void RenderSVGShape::strokeShape(GraphicsContext* context) const { ASSERT(m_path); Path* usePath = m_path.get(); if (hasNonScalingStroke()) usePath = nonScalingStrokePath(usePath, nonScalingStrokeTransform()); context->strokePath(*usePath); }
void RenderSVGShape::strokeShape(GraphicsContext& context) { if (!style().svgStyle().hasVisibleStroke()) return; GraphicsContextStateSaver stateSaver(context, false); if (hasNonScalingStroke()) { AffineTransform nonScalingTransform = nonScalingStrokeTransform(); if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver)) return; } strokeShape(style(), context); }
bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point) { ASSERT(m_path); BoundingRectStrokeStyleApplier applier(this, style()); if (hasNonScalingStroke()) { AffineTransform nonScalingTransform = nonScalingStrokeTransform(); Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform); return usePath->strokeContains(&applier, nonScalingTransform.mapPoint(point)); } return m_path->strokeContains(&applier, point); }
bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point) { ASSERT(m_path); StrokeData strokeData; SVGRenderSupport::applyStrokeStyleToStrokeData(&strokeData, style(), this); if (hasNonScalingStroke()) { AffineTransform nonScalingTransform = nonScalingStrokeTransform(); Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform); return usePath->strokeContains(nonScalingTransform.mapPoint(point), strokeData); } return m_path->strokeContains(point, strokeData); }
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(); }
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); }
FloatRect LayoutSVGShape::calculateStrokeBoundingBox() const { ASSERT(m_path); FloatRect strokeBoundingBox = m_fillBoundingBox; if (style()->svgStyle().hasStroke()) { StrokeData strokeData; SVGLayoutSupport::applyStrokeStyleToStrokeData(strokeData, styleRef(), *this); if (hasNonScalingStroke()) { AffineTransform nonScalingTransform = nonScalingStrokeTransform(); if (nonScalingTransform.isInvertible()) { Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform); FloatRect strokeBoundingRect = usePath->strokeBoundingRect(strokeData); strokeBoundingRect = nonScalingTransform.inverse().mapRect(strokeBoundingRect); strokeBoundingBox.unite(strokeBoundingRect); } } else { strokeBoundingBox.unite(path().strokeBoundingRect(strokeData)); } } return strokeBoundingBox; }
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(); // Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke. if (rectElement().hasAttribute(SVGNames::rxAttr) || rectElement().hasAttribute(SVGNames::ryAttr) || hasNonScalingStroke()) { RenderSVGShape::updateShapeFromElement(); m_usePathFallback = true; return; } else m_usePathFallback = false; SVGLengthContext lengthContext(&rectElement()); FloatSize boundingBoxSize(rectElement().width().value(lengthContext), rectElement().height().value(lengthContext)); if (boundingBoxSize.isEmpty()) return; m_fillBoundingBox = FloatRect(FloatPoint(rectElement().x().value(lengthContext), rectElement().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::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 }