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); }
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(); SVGLengthContext lengthContext(&rectElement()); FloatSize boundingBoxSize(lengthContext.valueForLength(style().width(), LengthModeWidth), lengthContext.valueForLength(style().height(), LengthModeHeight)); // Element is invalid if either dimension is negative. if (boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0) return; // Rendering enabled? Spec: "A value of zero disables rendering of the element." if (!boundingBoxSize.isEmpty()) { if (rectElement().rx().value(lengthContext) > 0 || rectElement().ry().value(lengthContext) > 0 || hasNonScalingStroke()) { // Fall back to RenderSVGShape RenderSVGShape::updateShapeFromElement(); m_usePathFallback = true; return; } m_usePathFallback = false; } m_fillBoundingBox = FloatRect(FloatPoint(lengthContext.valueForLength(style().svgStyle().x(), LengthModeWidth), lengthContext.valueForLength(style().svgStyle().y(), LengthModeHeight)), 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::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 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); }
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); } }