void LayoutSVGRect::updateStrokeAndFillBoundingBoxes()
{
    SVGLengthContext lengthContext(toSVGRectElement(element()));
    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) {
        m_fillBoundingBox = FloatRect();
        m_strokeBoundingBox = FloatRect();
        return;
    }

    if (m_usePathFallback) {
        // Spec: "A value of zero disables rendering of the element." so we can skip
        // the path fallback and rely on the existing bounding box calculation.
        if (!boundingBoxSize.isEmpty()) {
            LayoutSVGShape::updateStrokeAndFillBoundingBoxes();
            return;
        }
        m_usePathFallback = false;
        clearPath();
    }

    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 #2
0
static void updatePathFromRectElement(SVGElement* element, Path& path)
{
    SVGRectElement* rect = toSVGRectElement(element);

    SVGLengthContext lengthContext(element);
    float width = rect->width().value(lengthContext);
    if (width <= 0)
        return;
    float height = rect->height().value(lengthContext);
    if (height <= 0)
        return;
    float x = rect->x().value(lengthContext);
    float y = rect->y().value(lengthContext);
    bool hasRx = rect->hasAttribute(SVGNames::rxAttr);
    bool hasRy = rect->hasAttribute(SVGNames::ryAttr);
    if (hasRx || hasRy) {
        float rx = rect->rx().value(lengthContext);
        float ry = rect->ry().value(lengthContext);
        if (!hasRx)
            rx = ry;
        else if (!hasRy)
            ry = rx;
        // FIXME: We currently enforce using beziers here, as at least on CoreGraphics/Lion, as
        // the native method uses a different line dash origin, causing svg/custom/dashOrigin.svg to fail.
        // See bug https://bugs.webkit.org/show_bug.cgi?id=79932 which tracks this issue.
        path.addRoundedRect(FloatRect(x, y, width, height), FloatSize(rx, ry), Path::PreferBezierRoundedRect);
        return;
    }

    path.addRect(FloatRect(x, y, width, height));
}
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 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;
}
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;
}
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);
}
static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape)
{
    writePositionAndStyle(ts, shape);

    SVGElement* svgElement = shape.element();
    SVGLengthContext lengthContext(svgElement);

    if (svgElement->hasTagName(SVGNames::rectTag)) {
        SVGRectElement* element = toSVGRectElement(svgElement);
        writeNameValuePair(ts, "x", element->xCurrentValue().value(lengthContext));
        writeNameValuePair(ts, "y", element->yCurrentValue().value(lengthContext));
        writeNameValuePair(ts, "width", element->widthCurrentValue().value(lengthContext));
        writeNameValuePair(ts, "height", element->heightCurrentValue().value(lengthContext));
    } else if (svgElement->hasTagName(SVGNames::lineTag)) {
        SVGLineElement* element = toSVGLineElement(svgElement);
        writeNameValuePair(ts, "x1", element->x1CurrentValue().value(lengthContext));
        writeNameValuePair(ts, "y1", element->y1CurrentValue().value(lengthContext));
        writeNameValuePair(ts, "x2", element->x2CurrentValue().value(lengthContext));
        writeNameValuePair(ts, "y2", element->y2CurrentValue().value(lengthContext));
    } else if (svgElement->hasTagName(SVGNames::ellipseTag)) {
        SVGEllipseElement* element = toSVGEllipseElement(svgElement);
        writeNameValuePair(ts, "cx", element->cxCurrentValue().value(lengthContext));
        writeNameValuePair(ts, "cy", element->cyCurrentValue().value(lengthContext));
        writeNameValuePair(ts, "rx", element->rxCurrentValue().value(lengthContext));
        writeNameValuePair(ts, "ry", element->ryCurrentValue().value(lengthContext));
    } else if (svgElement->hasTagName(SVGNames::circleTag)) {
        SVGCircleElement* element = toSVGCircleElement(svgElement);
        writeNameValuePair(ts, "cx", element->cxCurrentValue().value(lengthContext));
        writeNameValuePair(ts, "cy", element->cyCurrentValue().value(lengthContext));
        writeNameValuePair(ts, "r", element->rCurrentValue().value(lengthContext));
    } else if (svgElement->hasTagName(SVGNames::polygonTag) || svgElement->hasTagName(SVGNames::polylineTag)) {
        writeNameAndQuotedValue(ts, "points", toSVGPolyElement(svgElement)->pointList().valueAsString());
    } else if (svgElement->hasTagName(SVGNames::pathTag)) {
        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;
}
Beispiel #8
0
SVGRectElement& RenderSVGRect::rectElement() const
{
    return toSVGRectElement(RenderSVGShape::graphicsElement());
}