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)); }
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 RenderSVGRect::createShape() { // Before creating a new object we need to clear the cached bounding box // to avoid using garbage. m_boundingBox = FloatRect(); m_innerStrokeRect = FloatRect(); m_outerStrokeRect = FloatRect(); SVGRectElement* rect = static_cast<SVGRectElement*>(node()); ASSERT(rect); bool nonScalingStroke = style()->svgStyle()->vectorEffect() == VE_NON_SCALING_STROKE; // Fallback to RenderSVGShape if rect has rounded corners. if (rect->hasAttribute(SVGNames::rxAttr) || rect->hasAttribute(SVGNames::ryAttr) || nonScalingStroke) { RenderSVGShape::createShape(); setIsPaintingFallback(true); return; } SVGLengthContext lengthContext(rect); FloatSize boundingBoxSize(rect->width().value(lengthContext), rect->height().value(lengthContext)); if (boundingBoxSize.isEmpty()) return; m_boundingBox = 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_boundingBox; m_outerStrokeRect = m_boundingBox; if (style()->svgStyle()->hasStroke()) { float strokeWidth = this->strokeWidth(); m_innerStrokeRect.inflate(-strokeWidth / 2); m_outerStrokeRect.inflate(strokeWidth / 2); } }