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);
}
Beispiel #3
0
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();
}
Beispiel #4
0
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);
}
Beispiel #5
0
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());
    }
}
Beispiel #7
0
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));
    }
}
Beispiel #9
0
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();
    }
}
Beispiel #11
0
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;
}
Beispiel #15
0
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
}
Beispiel #16
0
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);
}
Beispiel #17
0
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);
}
Beispiel #21
0
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>();
}
Beispiel #22
0
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));
}
Beispiel #23
0
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();
}
Beispiel #26
0
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();
}
Beispiel #27
0
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();
}
Beispiel #29
0
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();
}
Beispiel #30
0
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;
    }
}