void SVGLengthTearOff::setValue(float value, ExceptionState& exceptionState) { if (isImmutable()) { exceptionState.throwDOMException(NoModificationAllowedError, "The attribute is read-only."); return; } if (target()->isRelative() && !canResolveRelativeUnits(contextElement())) { exceptionState.throwDOMException(NotSupportedError, "Could not resolve relative length."); return; } SVGLengthContext lengthContext(contextElement()); target()->setValue(value, lengthContext); commitChange(); }
void SVGAnimatedLengthListAnimator::addAnimatedTypes(SVGAnimatedType* from, SVGAnimatedType* to) { ASSERT(from->type() == AnimatedLengthList); ASSERT(from->type() == to->type()); const SVGLengthList& fromLengthList = from->lengthList(); SVGLengthList& toLengthList = to->lengthList(); unsigned fromLengthListSize = fromLengthList.size(); if (!fromLengthListSize || fromLengthListSize != toLengthList.size()) return; SVGLengthContext lengthContext(m_contextElement); for (unsigned i = 0; i < fromLengthListSize; ++i) toLengthList[i].setValue(toLengthList[i].value(lengthContext) + fromLengthList[i].value(lengthContext), lengthContext, ASSERT_NO_EXCEPTION); }
void SVGLengthTearOff::convertToSpecifiedUnits(unsigned short unitType, ExceptionState& exceptionState) { if (isImmutable()) { exceptionState.throwDOMException(NoModificationAllowedError, "The object is read-only."); return; } if (unitType == LengthTypeUnknown || unitType > LengthTypePC) { exceptionState.throwDOMException(NotSupportedError, "Cannot convert to unknown or invalid units (" + String::number(unitType) + ")."); return; } SVGLengthContext lengthContext(contextElement()); target()->convertToSpecifiedUnits(toSVGLengthType(unitType), lengthContext, exceptionState); commitChange(); }
void FEImage::platformApplySoftware() { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; SVGFilter* svgFilter = static_cast<SVGFilter*>(filter()); FloatRect destRect = svgFilter->absoluteTransform().mapRect(filterPrimitiveSubregion()); FloatRect srcRect; if (renderer) srcRect = svgFilter->absoluteTransform().mapRect(renderer->repaintRectInLocalCoordinates()); else { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio.transformRect(destRect, srcRect); } IntPoint paintLocation = absolutePaintRect().location(); destRect.move(-paintLocation.x(), -paintLocation.y()); if (renderer) { const AffineTransform& absoluteTransform = svgFilter->absoluteTransform(); resultImage->context()->concatCTM(absoluteTransform); SVGElement* contextNode = static_cast<SVGElement*>(renderer->node()); if (contextNode->isStyled() && static_cast<SVGStyledElement*>(contextNode)->hasRelativeLengths()) { SVGLengthContext lengthContext(contextNode); float width = 0; float height = 0; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(width, height)) resultImage->context()->concatCTM(makeMapBetweenRects(FloatRect(0, 0, width, height), destRect)); } AffineTransform contentTransformation; SVGRenderingContext::renderSubtreeToImageBuffer(resultImage, renderer, contentTransformation); return; } resultImage->context()->drawImage(m_image.get(), ColorSpaceDeviceRGB, destRect, srcRect); }
void SVGLengthTearOff::setValue(float value, ExceptionState& exceptionState) { if (isImmutable()) { throwReadOnly(exceptionState); return; } if (target()->isRelative() && !canResolveRelativeUnits(contextElement())) { exceptionState.throwDOMException(NotSupportedError, "Could not resolve relative length."); return; } SVGLengthContext lengthContext(contextElement()); if (target()->isCalculated()) target()->setValueAsNumber(value); else target()->setValue(value, lengthContext); commitChange(); }
void SVGUseElement::toClipPath(Path& path) const { ASSERT(path.isEmpty()); const SVGGraphicsElement* element = targetGraphicsElementForClipping(); if (!element) return; if (element->isSVGGeometryElement()) { toSVGGeometryElement(*element).toClipPath(path); // FIXME: Avoid manual resolution of x/y here. Its potentially harmful. SVGLengthContext lengthContext(this); path.translate(FloatSize(m_x->currentValue()->value(lengthContext), m_y->currentValue()->value(lengthContext))); path.transform(calculateAnimatedLocalTransform()); } }
void RenderSVGEllipse::calculateRadiiAndCenter() { SVGLengthContext lengthContext(&graphicsElement()); m_center = FloatPoint( lengthContext.valueForLength(style().svgStyle().cx(), LengthModeWidth), lengthContext.valueForLength(style().svgStyle().cy(), LengthModeHeight)); if (is<SVGCircleElement>(graphicsElement())) { float radius = lengthContext.valueForLength(style().svgStyle().r()); m_radii = FloatSize(radius, radius); return; } ASSERT(is<SVGEllipseElement>(graphicsElement())); m_radii = FloatSize( lengthContext.valueForLength(style().svgStyle().rx(), LengthModeWidth), lengthContext.valueForLength(style().svgStyle().ry(), LengthModeHeight)); }
void LayoutSVGEllipse::calculateRadiiAndCenter() { ASSERT(element()); SVGLengthContext lengthContext(element()); m_center = FloatPoint( lengthContext.valueForLength(style()->svgStyle().cx(), styleRef(), SVGLengthMode::Width), lengthContext.valueForLength(style()->svgStyle().cy(), styleRef(), SVGLengthMode::Height)); if (isSVGCircleElement(*element())) { float radius = lengthContext.valueForLength(style()->svgStyle().r(), styleRef(), SVGLengthMode::Other); m_radii = FloatSize(radius, radius); } else { m_radii = FloatSize( lengthContext.valueForLength(style()->svgStyle().rx(), styleRef(), SVGLengthMode::Width), lengthContext.valueForLength(style()->svgStyle().ry(), styleRef(), SVGLengthMode::Height)); } }
void RenderSVGForeignObject::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; ASSERT(needsLayout()); ASSERT(!view()->layoutStateEnabled()); // RenderSVGRoot disables layoutState for the SVG rendering tree. LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); SVGForeignObjectElement* foreign = static_cast<SVGForeignObjectElement*>(node()); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { m_localTransform = foreign->animatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } FloatRect oldViewport = m_viewport; // Cache viewport boundaries SVGLengthContext lengthContext(foreign); FloatPoint viewportLocation(foreign->x().value(lengthContext), foreign->y().value(lengthContext)); m_viewport = FloatRect(viewportLocation, FloatSize(foreign->width().value(lengthContext), foreign->height().value(lengthContext))); if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldViewport != m_viewport; // Set box origin to the foreignObject x/y translation, so positioned objects in XHTML content get correct // positions. A regular RenderBoxModelObject would pull this information from RenderStyle - in SVG those // properties are ignored for non <svg> elements, so we mimic what happens when specifying them through CSS. // FIXME: Investigate in location rounding issues - only affects RenderSVGForeignObject & RenderSVGText setLocation(roundedIntPoint(viewportLocation)); bool layoutChanged = everHadLayout() && selfNeedsLayout(); RenderBlock::layout(); ASSERT(!needsLayout()); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) RenderSVGBlock::setNeedsBoundariesUpdate(); // Invalidate all resources of this client if our layout changed. if (layoutChanged) SVGResourcesCache::clientLayoutChanged(this); repainter.repaintAfterLayout(); }
void LayoutSVGViewportContainer::calcViewport() { SVGElement* element = this->element(); ASSERT(element); if (!isSVGSVGElement(*element)) return; SVGSVGElement* svg = toSVGSVGElement(element); FloatRect oldViewport = m_viewport; SVGLengthContext lengthContext(element); m_viewport = FloatRect(svg->x()->currentValue()->value(lengthContext), svg->y()->currentValue()->value(lengthContext), svg->width()->currentValue()->value(lengthContext), svg->height()->currentValue()->value(lengthContext)); if (oldViewport != m_viewport) { setNeedsBoundariesUpdate(); setNeedsTransformUpdate(); } }
AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const { AffineTransform viewBoxTransform; if (hasAttribute(SVGNames::viewBoxAttr)) { FloatSize size = currentViewportSize(); viewBoxTransform = viewBoxToViewTransform(size.width(), size.height()); } AffineTransform transform; if (!isOutermostSVGSVGElement()) { SVGLengthContext lengthContext(this); transform.translate(x().value(lengthContext), y().value(lengthContext)); } else if (mode == SVGLocatable::ScreenScope) { if (RenderObject* renderer = this->renderer()) { FloatPoint location; float zoomFactor = 1; // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. // RenderSVGRoot's localToAbsolute method expects CSS box coordinates. // We also need to adjust for the zoom level factored into CSS coordinates (bug #96361). if (renderer->isSVGRoot()) { location = toRenderSVGRoot(renderer)->localToBorderBoxTransform().mapPoint(location); zoomFactor = 1 / renderer->style()->effectiveZoom(); } // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. location = renderer->localToAbsolute(location, UseTransforms); location.scale(zoomFactor, zoomFactor); // Be careful here! localToBorderBoxTransform() included the x/y offset coming from the viewBoxToViewTransform(), // so we have to subtract it here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document()->view()) { LayoutSize scrollOffset = view->scrollOffset(); scrollOffset.scale(zoomFactor); transform.translate(-scrollOffset.width(), -scrollOffset.height()); } } } return transform.multiply(viewBoxTransform); }
void LayoutSVGForeignObject::layout() { ASSERT(needsLayout()); SVGForeignObjectElement* foreign = toSVGForeignObjectElement(node()); bool updateCachedBoundariesInParents = false; if (m_needsTransformUpdate) { m_localTransform = foreign->calculateAnimatedLocalTransform(); m_needsTransformUpdate = false; updateCachedBoundariesInParents = true; } FloatRect oldViewport = m_viewport; // Cache viewport boundaries SVGLengthContext lengthContext(foreign); FloatPoint viewportLocation( lengthContext.valueForLength(styleRef().svgStyle().x(), styleRef(), SVGLengthMode::Width), lengthContext.valueForLength(styleRef().svgStyle().y(), styleRef(), SVGLengthMode::Height)); m_viewport = FloatRect(viewportLocation, FloatSize( lengthContext.valueForLength(styleRef().width(), styleRef(), SVGLengthMode::Width), lengthContext.valueForLength(styleRef().height(), styleRef(), SVGLengthMode::Height))); if (!updateCachedBoundariesInParents) updateCachedBoundariesInParents = oldViewport != m_viewport; // Set box origin to the foreignObject x/y translation, so positioned objects in XHTML content get correct // positions. A regular LayoutBoxModelObject would pull this information from ComputedStyle - in SVG those // properties are ignored for non <svg> elements, so we mimic what happens when specifying them through CSS. // FIXME: Investigate in location rounding issues - only affects LayoutSVGForeignObject & LayoutSVGText setLocation(roundedIntPoint(viewportLocation)); bool layoutChanged = everHadLayout() && selfNeedsLayout(); LayoutBlock::layout(); ASSERT(!needsLayout()); // If our bounds changed, notify the parents. if (updateCachedBoundariesInParents) LayoutSVGBlock::setNeedsBoundariesUpdate(); // Invalidate all resources of this client if our layout changed. if (layoutChanged) SVGResourcesCache::clientLayoutChanged(this); }
void LayoutSVGRect::updateShapeFromElement() { m_usePathFallback = false; // Fallback to LayoutSVGShape and path-based hit detection if the rect // has rounded corners or a non-scaling or non-simple stroke. SVGLengthContext lengthContext(toSVGRectElement(element())); if (lengthContext.valueForLength(styleRef().svgStyle().rx(), styleRef(), SVGLengthMode::Width) > 0 || lengthContext.valueForLength(styleRef().svgStyle().ry(), styleRef(), SVGLengthMode::Height) > 0 || hasNonScalingStroke() || !definitelyHasSimpleStroke(style()->svgStyle())) { LayoutSVGShape::updateShapeFromElement(); m_usePathFallback = true; return; } clearPath(); }
static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape) { writePositionAndStyle(ts, shape); ASSERT(shape.node()->isSVGElement()); SVGElement* svgElement = toSVGElement(shape.node()); SVGLengthContext lengthContext(svgElement); if (svgElement->hasTagName(SVGNames::rectTag)) { SVGRectElement* element = static_cast<SVGRectElement*>(svgElement); writeNameValuePair(ts, "x", element->x().value(lengthContext)); writeNameValuePair(ts, "y", element->y().value(lengthContext)); writeNameValuePair(ts, "width", element->width().value(lengthContext)); writeNameValuePair(ts, "height", element->height().value(lengthContext)); } else if (svgElement->hasTagName(SVGNames::lineTag)) { SVGLineElement* element = static_cast<SVGLineElement*>(svgElement); writeNameValuePair(ts, "x1", element->x1().value(lengthContext)); writeNameValuePair(ts, "y1", element->y1().value(lengthContext)); writeNameValuePair(ts, "x2", element->x2().value(lengthContext)); writeNameValuePair(ts, "y2", element->y2().value(lengthContext)); } else if (svgElement->hasTagName(SVGNames::ellipseTag)) { SVGEllipseElement* element = static_cast<SVGEllipseElement*>(svgElement); writeNameValuePair(ts, "cx", element->cx().value(lengthContext)); writeNameValuePair(ts, "cy", element->cy().value(lengthContext)); writeNameValuePair(ts, "rx", element->rx().value(lengthContext)); writeNameValuePair(ts, "ry", element->ry().value(lengthContext)); } else if (svgElement->hasTagName(SVGNames::circleTag)) { SVGCircleElement* element = static_cast<SVGCircleElement*>(svgElement); writeNameValuePair(ts, "cx", element->cx().value(lengthContext)); writeNameValuePair(ts, "cy", element->cy().value(lengthContext)); writeNameValuePair(ts, "r", element->r().value(lengthContext)); } else if (svgElement->hasTagName(SVGNames::polygonTag) || svgElement->hasTagName(SVGNames::polylineTag)) { SVGPolyElement* element = static_cast<SVGPolyElement*>(svgElement); writeNameAndQuotedValue(ts, "points", element->pointList().valueAsString()); } else if (svgElement->hasTagName(SVGNames::pathTag)) { SVGPathElement* element = toSVGPathElement(svgElement); String pathString; // FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests. buildStringFromByteStream(element->pathByteStream(), pathString, NormalizedParsing); writeNameAndQuotedValue(ts, "data", pathString); } else ASSERT_NOT_REACHED(); return ts; }
void RenderSVGRect::updateShapeFromElement() { // Before creating a new object we need to clear the cached bounding box // to avoid using garbage. m_fillBoundingBox = FloatRect(); m_innerStrokeRect = FloatRect(); m_outerStrokeRect = FloatRect(); SVGRectElement* rect = static_cast<SVGRectElement*>(node()); ASSERT(rect); // Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke. if (rect->hasAttribute(SVGNames::rxAttr) || rect->hasAttribute(SVGNames::ryAttr) || hasNonScalingStroke()) { RenderSVGShape::updateShapeFromElement(); m_usePathFallback = true; return; } else m_usePathFallback = false; SVGLengthContext lengthContext(rect); FloatSize boundingBoxSize(rect->width().value(lengthContext), rect->height().value(lengthContext)); if (boundingBoxSize.isEmpty()) return; m_fillBoundingBox = FloatRect(FloatPoint(rect->x().value(lengthContext), rect->y().value(lengthContext)), boundingBoxSize); // To decide if the stroke contains a point we create two rects which represent the inner and // the outer stroke borders. A stroke contains the point, if the point is between them. m_innerStrokeRect = m_fillBoundingBox; m_outerStrokeRect = m_fillBoundingBox; if (style()->svgStyle()->hasStroke()) { float strokeWidth = this->strokeWidth(); m_innerStrokeRect.inflate(-strokeWidth / 2); m_outerStrokeRect.inflate(strokeWidth / 2); } m_strokeBoundingBox = m_outerStrokeRect; #if USE(CG) // CoreGraphics can inflate the stroke by 1px when drawing a rectangle with antialiasing disabled at non-integer coordinates, we need to compensate. if (style()->svgStyle()->shapeRendering() == SR_CRISPEDGES) m_strokeBoundingBox.inflate(1); #endif }
void FEImage::applySoftware() { RenderObject* renderer = referencedRenderer(); if (!m_image && !renderer) return; ImageBuffer* resultImage = createImageBufferResult(); if (!resultImage) return; IntPoint paintLocation = absolutePaintRect().location(); resultImage->context()->translate(-paintLocation.x(), -paintLocation.y()); // FEImage results are always in ColorSpaceDeviceRGB setResultColorSpace(ColorSpaceDeviceRGB); FloatRect destRect = filter()->mapLocalRectToAbsoluteRect(filterPrimitiveSubregion()); FloatRect srcRect; if (!renderer) { srcRect = FloatRect(FloatPoint(), m_image->size()); m_preserveAspectRatio->transformRect(destRect, srcRect); resultImage->context()->drawImage(m_image.get(), destRect, srcRect); return; } SVGElement* contextNode = toSVGElement(renderer->node()); if (contextNode->hasRelativeLengths()) { // FIXME: This fixes relative lengths but breaks non-relative ones (see crbug/260709). SVGLengthContext lengthContext(contextNode); FloatSize viewportSize; // If we're referencing an element with percentage units, eg. <rect with="30%"> those values were resolved against the viewport. // Build up a transformation that maps from the viewport space to the filter primitive subregion. if (lengthContext.determineViewport(viewportSize)) resultImage->context()->concatCTM(makeMapBetweenRects(FloatRect(FloatPoint(), viewportSize), destRect)); } else { resultImage->context()->translate(destRect.x(), destRect.y()); resultImage->context()->concatCTM(filter()->absoluteTransform()); } AffineTransform contentTransformation; SVGRenderingContext::renderSubtree(resultImage->context(), renderer, contentTransformation); }
bool SVGTextLayoutEngine::parentDefinesTextLength(RenderObject* parent) const { RenderObject* currentParent = parent; while (currentParent) { if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(currentParent)) { SVGLengthContext lengthContext(textContentElement); if (textContentElement->lengthAdjust() == SVGLengthAdjustSpacing && textContentElement->specifiedTextLength().value(lengthContext) > 0) return true; } if (currentParent->isSVGText()) return false; currentParent = currentParent->parent(); } ASSERT_NOT_REACHED(); return false; }
static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape) { writePositionAndStyle(ts, shape); SVGGraphicsElement& svgElement = shape.graphicsElement(); SVGLengthContext lengthContext(&svgElement); if (isSVGRectElement(svgElement)) { const SVGRectElement& element = toSVGRectElement(svgElement); writeNameValuePair(ts, "x", element.x().value(lengthContext)); writeNameValuePair(ts, "y", element.y().value(lengthContext)); writeNameValuePair(ts, "width", element.width().value(lengthContext)); writeNameValuePair(ts, "height", element.height().value(lengthContext)); } else if (isSVGLineElement(svgElement)) { const SVGLineElement& element = toSVGLineElement(svgElement); writeNameValuePair(ts, "x1", element.x1().value(lengthContext)); writeNameValuePair(ts, "y1", element.y1().value(lengthContext)); writeNameValuePair(ts, "x2", element.x2().value(lengthContext)); writeNameValuePair(ts, "y2", element.y2().value(lengthContext)); } else if (isSVGEllipseElement(svgElement)) { const SVGEllipseElement& element = toSVGEllipseElement(svgElement); writeNameValuePair(ts, "cx", element.cx().value(lengthContext)); writeNameValuePair(ts, "cy", element.cy().value(lengthContext)); writeNameValuePair(ts, "rx", element.rx().value(lengthContext)); writeNameValuePair(ts, "ry", element.ry().value(lengthContext)); } else if (isSVGCircleElement(svgElement)) { const SVGCircleElement& element = toSVGCircleElement(svgElement); writeNameValuePair(ts, "cx", element.cx().value(lengthContext)); writeNameValuePair(ts, "cy", element.cy().value(lengthContext)); writeNameValuePair(ts, "r", element.r().value(lengthContext)); } else if (svgElement.hasTagName(SVGNames::polygonTag) || svgElement.hasTagName(SVGNames::polylineTag)) { const SVGPolyElement& element = toSVGPolyElement(svgElement); writeNameAndQuotedValue(ts, "points", element.pointList().valueAsString()); } else if (isSVGPathElement(svgElement)) { const SVGPathElement& element = toSVGPathElement(svgElement); String pathString; // FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests. buildStringFromByteStream(element.pathByteStream(), pathString, NormalizedParsing); writeNameAndQuotedValue(ts, "data", pathString); } else ASSERT_NOT_REACHED(); return ts; }
static TextStream& operator<<(TextStream& ts, const LayoutSVGShape& shape) { writePositionAndStyle(ts, shape); SVGElement* svgElement = shape.element(); ASSERT(svgElement); SVGLengthContext lengthContext(svgElement); if (isSVGRectElement(*svgElement)) { SVGRectElement& element = toSVGRectElement(*svgElement); writeNameValuePair(ts, "x", element.x()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "y", element.y()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "width", element.width()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "height", element.height()->currentValue()->value(lengthContext)); } else if (isSVGLineElement(*svgElement)) { SVGLineElement& element = toSVGLineElement(*svgElement); writeNameValuePair(ts, "x1", element.x1()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "y1", element.y1()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "x2", element.x2()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "y2", element.y2()->currentValue()->value(lengthContext)); } else if (isSVGEllipseElement(*svgElement)) { SVGEllipseElement& element = toSVGEllipseElement(*svgElement); writeNameValuePair(ts, "cx", element.cx()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "cy", element.cy()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "rx", element.rx()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "ry", element.ry()->currentValue()->value(lengthContext)); } else if (isSVGCircleElement(*svgElement)) { SVGCircleElement& element = toSVGCircleElement(*svgElement); writeNameValuePair(ts, "cx", element.cx()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "cy", element.cy()->currentValue()->value(lengthContext)); writeNameValuePair(ts, "r", element.r()->currentValue()->value(lengthContext)); } else if (isSVGPolyElement(*svgElement)) { writeNameAndQuotedValue(ts, "points", toSVGPolyElement(*svgElement).points()->currentValue()->valueAsString()); } else if (isSVGPathElement(*svgElement)) { String pathString; // FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests. buildStringFromByteStream(*toSVGPathElement(*svgElement).pathByteStream(), pathString, NormalizedParsing); writeNameAndQuotedValue(ts, "data", pathString); } else { ASSERT_NOT_REACHED(); } return ts; }
void LayoutSVGRect::updateShapeFromElement() { // Before creating a new object we need to clear the cached bounding box // to avoid using garbage. m_fillBoundingBox = FloatRect(); m_strokeBoundingBox = FloatRect(); m_usePathFallback = false; SVGRectElement* rect = toSVGRectElement(element()); ASSERT(rect); SVGLengthContext lengthContext(rect); FloatSize boundingBoxSize( lengthContext.valueForLength(styleRef().width(), styleRef(), SVGLengthMode::Width), lengthContext.valueForLength(styleRef().height(), styleRef(), SVGLengthMode::Height)); // Spec: "A negative value is an error." if (boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0) return; // Spec: "A value of zero disables rendering of the element." if (!boundingBoxSize.isEmpty()) { // Fallback to LayoutSVGShape and path-based hit detection if the rect // has rounded corners or a non-scaling or non-simple stroke. if (lengthContext.valueForLength(styleRef().svgStyle().rx(), styleRef(), SVGLengthMode::Width) > 0 || lengthContext.valueForLength(styleRef().svgStyle().ry(), styleRef(), SVGLengthMode::Height) > 0 || hasNonScalingStroke() || !definitelyHasSimpleStroke()) { LayoutSVGShape::updateShapeFromElement(); m_usePathFallback = true; return; } } m_fillBoundingBox = FloatRect( FloatPoint( lengthContext.valueForLength(styleRef().svgStyle().x(), styleRef(), SVGLengthMode::Width), lengthContext.valueForLength(styleRef().svgStyle().y(), styleRef(), SVGLengthMode::Height)), boundingBoxSize); m_strokeBoundingBox = m_fillBoundingBox; if (style()->svgStyle().hasStroke()) m_strokeBoundingBox.inflate(strokeWidth() / 2); }
v8::Handle<v8::Value> V8SVGLength::convertToSpecifiedUnitsCallback(const v8::Arguments& args) { INC_STATS("DOM.SVGLength.convertToSpecifiedUnits"); SVGPropertyTearOff<SVGLength>* wrapper = V8SVGLength::toNative(args.Holder()); if (wrapper->role() == AnimValRole) return V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR, args.GetIsolate()); if (args.Length() < 1) return V8Proxy::throwNotEnoughArgumentsError(args.GetIsolate()); SVGLength& imp = wrapper->propertyReference(); ExceptionCode ec = 0; EXCEPTION_BLOCK(int, unitType, toUInt32(args[0])); SVGLengthContext lengthContext(wrapper->contextElement()); imp.convertToSpecifiedUnits(unitType, lengthContext, ec); if (UNLIKELY(ec)) return V8Proxy::setDOMException(ec, args.GetIsolate()); wrapper->commitChange(); return v8::Handle<v8::Value>(); }
FloatRect SVGLengthContext::resolveRectangle(const SVGElement* context, SVGUnitTypes::SVGUnitType type, const FloatRect& viewport, const SVGLength& x, const SVGLength& y, const SVGLength& width, const SVGLength& height) { DCHECK_NE(SVGUnitTypes::kSvgUnitTypeUnknown, type); if (type != SVGUnitTypes::kSvgUnitTypeUserspaceonuse) { const FloatSize& viewportSize = viewport.size(); return FloatRect( convertValueFromPercentageToUserUnits(x, viewportSize) + viewport.x(), convertValueFromPercentageToUserUnits(y, viewportSize) + viewport.y(), convertValueFromPercentageToUserUnits(width, viewportSize), convertValueFromPercentageToUserUnits(height, viewportSize)); } SVGLengthContext lengthContext(context); return FloatRect(x.value(lengthContext), y.value(lengthContext), width.value(lengthContext), height.value(lengthContext)); }
void SVGUseElement::toClipPath(Path& path) { ASSERT(path.isEmpty()); Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0; if (!n) return; if (n->isSVGElement() && toSVGElement(*n).isSVGGraphicsElement()) { if (!isDirectReference(toSVGElement(*n))) { // Spec: Indirect references are an error (14.3.5) document().accessSVGExtensions()->reportError("Not allowed to use indirect reference in <clip-path>"); } else { toSVGGraphicsElement(*n).toClipPath(path); // FIXME: Avoid manual resolution of x/y here. Its potentially harmful. SVGLengthContext lengthContext(this); path.translate(FloatSize(x().value(lengthContext), y().value(lengthContext))); path.transform(animatedLocalTransform()); } } }
void V8SVGLength::valueAttrSetterCustom(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) { SVGPropertyTearOff<SVGLength>* wrapper = V8SVGLength::toNative(info.Holder()); if (wrapper->isReadOnly()) { setDOMException(NoModificationAllowedError, info.GetIsolate()); return; } if (!isUndefinedOrNull(value) && !value->IsNumber() && !value->IsBoolean()) { throwTypeError(info.GetIsolate()); return; } SVGLength& imp = wrapper->propertyReference(); ExceptionState es(info.GetIsolate()); SVGLengthContext lengthContext(wrapper->contextElement()); imp.setValue(static_cast<float>(value->NumberValue()), lengthContext, es); if (es.throwIfNeeded()) return; wrapper->commitChange(); }
void SVGLengthTearOff::convertToSpecifiedUnits(unsigned short unitType, ExceptionState& exceptionState) { if (isImmutable()) { exceptionState.throwDOMException(NoModificationAllowedError, "The object is read-only."); return; } if (!isValidLengthUnit(unitType)) { exceptionState.throwDOMException(NotSupportedError, "Cannot convert to unknown or invalid units (" + String::number(unitType) + ")."); return; } if ((target()->isRelative() || SVGLength::isRelativeUnit(toCSSUnitType(unitType))) && !canResolveRelativeUnits(contextElement())) { exceptionState.throwDOMException(NotSupportedError, "Could not resolve relative length."); return; } SVGLengthContext lengthContext(contextElement()); target()->convertToSpecifiedUnits(toCSSUnitType(unitType), lengthContext); commitChange(); }
void V8SVGLength::convertToSpecifiedUnitsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) { SVGPropertyTearOff<SVGLength>* wrapper = V8SVGLength::toNative(info.Holder()); if (wrapper->isReadOnly()) { setDOMException(NoModificationAllowedError, info.GetIsolate()); return; } if (info.Length() < 1) { throwTypeError(ExceptionMessages::failedToExecute("convertToSpecifiedUnits", "SVGLength", ExceptionMessages::notEnoughArguments(1, info.Length())), info.GetIsolate()); return; } SVGLength& imp = wrapper->propertyReference(); ExceptionState exceptionState(info.Holder(), info.GetIsolate()); V8TRYCATCH_VOID(int, unitType, toUInt32(info[0])); SVGLengthContext lengthContext(wrapper->contextElement()); imp.convertToSpecifiedUnits(unitType, lengthContext, exceptionState); if (exceptionState.throwIfNeeded()) return; wrapper->commitChange(); }
void SVGAnimatedLengthListAnimator::calculateFromAndByValues(OwnPtr<SVGAnimatedType>& from, OwnPtr<SVGAnimatedType>& to, const String& fromString, const String& byString) { ASSERT(m_contextElement); ASSERT(m_animationElement); SVGAnimateElement* animationElement = static_cast<SVGAnimateElement*>(m_animationElement); animationElement->determinePropertyValueTypes(fromString, byString); from = constructFromString(fromString); to = constructFromString(byString); SVGLengthList& fromLengthList = from->lengthList(); SVGLengthList& toLengthList = to->lengthList(); unsigned itemsCount = fromLengthList.size(); if (itemsCount != toLengthList.size()) return; SVGLengthContext lengthContext(m_contextElement); ExceptionCode ec = 0; for (unsigned i = 0; i < itemsCount; ++i) { toLengthList[i].setValue(toLengthList[i].value(lengthContext) + fromLengthList[i].value(lengthContext), lengthContext, ec); ASSERT(!ec); } }
void V8SVGLength::convertToSpecifiedUnitsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) { SVGPropertyTearOff<SVGLength>* wrapper = V8SVGLength::toNative(args.Holder()); if (wrapper->isReadOnly()) { setDOMException(NoModificationAllowedError, args.GetIsolate()); return; } if (args.Length() < 1) { throwNotEnoughArgumentsError(args.GetIsolate()); return; } SVGLength& imp = wrapper->propertyReference(); ExceptionState es(args.GetIsolate()); V8TRYCATCH_VOID(int, unitType, toUInt32(args[0])); SVGLengthContext lengthContext(wrapper->contextElement()); imp.convertToSpecifiedUnits(unitType, lengthContext, es); if (es.throwIfNeeded()) return; wrapper->commitChange(); }
void V8SVGLength::valueAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info) { INC_STATS("DOM.SVGLength.value._set"); SVGPropertyTearOff<SVGLength>* wrapper = V8SVGLength::toNative(info.Holder()); if (wrapper->role() == AnimValRole) { V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR, info.GetIsolate()); return; } if (!isUndefinedOrNull(value) && !value->IsNumber() && !value->IsBoolean()) { V8Proxy::throwTypeError(0, info.GetIsolate()); return; } SVGLength& imp = wrapper->propertyReference(); ExceptionCode ec = 0; SVGLengthContext lengthContext(wrapper->contextElement()); imp.setValue(static_cast<float>(value->NumberValue()), lengthContext, ec); if (UNLIKELY(ec)) V8Proxy::setDOMException(ec, info.GetIsolate()); else wrapper->commitChange(); }
float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle* style, SVGElement* contextElement) const { if (style->baselineShift() == BS_LENGTH) { SVGLength baselineShiftValueLength = style->baselineShiftValue(); if (baselineShiftValueLength.unitType() == LengthTypePercentage) return baselineShiftValueLength.valueAsPercentage() * m_font.pixelSize(); SVGLengthContext lengthContext(contextElement); return baselineShiftValueLength.value(lengthContext); } switch (style->baselineShift()) { case BS_BASELINE: return 0; case BS_SUB: return -m_font.fontMetrics().floatHeight() / 2; case BS_SUPER: return m_font.fontMetrics().floatHeight() / 2; default: ASSERT_NOT_REACHED(); return 0; } }