Refactor RenderSVGShape bounding box code
authorpdr@google.com <pdr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Jul 2012 08:10:23 +0000 (08:10 +0000)
committerpdr@google.com <pdr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Jul 2012 08:10:23 +0000 (08:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=90655

Reviewed by Nikolas Zimmermann.

RenderSVGShape::objectBoundingBox worked differently than RenderSVGShape::strokeBoundingBox by
not caching the object bounding box and instead computing it on each call. For consistency and
performance objectBoundingBox has been refactored to return a cached value.

createShape has been renamed updateShapeFromElement for understandability. updateShapeFromElement
now updates the internal state of the shape (bounding boxes, etc) from the associated element.
RenderSVGShape::inflateWithStrokeAndMarkerBounds has been merged into
RenderSVGShape::calculateStrokeBoundingBox which is called from updateShapeFromElement.

After this change all bounding box computation is now handled in updateShapeFromElement. Because
subclasses override updateShapeFromElement it will be easy for them to have custom bounding box
code there (as will happen for RenderSVGPath in a followup patch).

strokeBoundingBox and objectBoundingBox are now able to return their cached values immediately
in RenderSVGRect and RenderSVGEllipse instead of checking their fallback state on each call.

Additionally, to save space RenderSVGEllipse and RenderSVGRect now use the m_fillBoundingBox and
m_strokeBoundingBox of RenderSVGShape instead of having their own.

This patch also removes setStrokeAndMarkerBoundingBox that was previously dead code.

No new tests, just a refactoring.

* rendering/svg/RenderSVGEllipse.cpp:
(WebCore::RenderSVGEllipse::updateShapeFromElement):
(WebCore):
(WebCore::RenderSVGEllipse::fillShape):
(WebCore::RenderSVGEllipse::strokeShape):
(WebCore::RenderSVGEllipse::shapeDependentStrokeContains):
* rendering/svg/RenderSVGEllipse.h:
(RenderSVGEllipse):
(WebCore::RenderSVGEllipse::isEmpty):
* rendering/svg/RenderSVGRect.cpp:
(WebCore::RenderSVGRect::updateShapeFromElement):
(WebCore):
(WebCore::RenderSVGRect::fillShape):
(WebCore::RenderSVGRect::strokeShape):
(WebCore::RenderSVGRect::shapeDependentStrokeContains):
(WebCore::RenderSVGRect::shapeDependentFillContains):
* rendering/svg/RenderSVGRect.h:
(RenderSVGRect):
(WebCore::RenderSVGRect::isEmpty):
* rendering/svg/RenderSVGShape.cpp:
(WebCore::RenderSVGShape::updateShapeFromElement):
(WebCore):
(WebCore::RenderSVGShape::layout):
(WebCore::RenderSVGShape::calculateObjectBoundingBox):
(WebCore::RenderSVGShape::calculateStrokeBoundingBox):
(WebCore::RenderSVGShape::updateRepaintBoundingBox):
* rendering/svg/RenderSVGShape.h:
(RenderSVGShape):
(WebCore::RenderSVGShape::objectBoundingBox):
(WebCore::RenderSVGShape::strokeBoundingBox):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@122424 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/rendering/svg/RenderSVGEllipse.cpp
Source/WebCore/rendering/svg/RenderSVGEllipse.h
Source/WebCore/rendering/svg/RenderSVGRect.cpp
Source/WebCore/rendering/svg/RenderSVGRect.h
Source/WebCore/rendering/svg/RenderSVGShape.cpp
Source/WebCore/rendering/svg/RenderSVGShape.h

index 6ebce69..fa6711d 100644 (file)
@@ -1,3 +1,64 @@
+2012-07-12  Philip Rogers  <pdr@google.com>
+
+        Refactor RenderSVGShape bounding box code
+        https://bugs.webkit.org/show_bug.cgi?id=90655
+
+        Reviewed by Nikolas Zimmermann.
+
+        RenderSVGShape::objectBoundingBox worked differently than RenderSVGShape::strokeBoundingBox by
+        not caching the object bounding box and instead computing it on each call. For consistency and
+        performance objectBoundingBox has been refactored to return a cached value.
+
+        createShape has been renamed updateShapeFromElement for understandability. updateShapeFromElement
+        now updates the internal state of the shape (bounding boxes, etc) from the associated element.
+        RenderSVGShape::inflateWithStrokeAndMarkerBounds has been merged into
+        RenderSVGShape::calculateStrokeBoundingBox which is called from updateShapeFromElement.
+
+        After this change all bounding box computation is now handled in updateShapeFromElement. Because
+        subclasses override updateShapeFromElement it will be easy for them to have custom bounding box
+        code there (as will happen for RenderSVGPath in a followup patch).
+
+        strokeBoundingBox and objectBoundingBox are now able to return their cached values immediately
+        in RenderSVGRect and RenderSVGEllipse instead of checking their fallback state on each call.
+
+        Additionally, to save space RenderSVGEllipse and RenderSVGRect now use the m_fillBoundingBox and
+        m_strokeBoundingBox of RenderSVGShape instead of having their own.
+
+        This patch also removes setStrokeAndMarkerBoundingBox that was previously dead code.
+
+        No new tests, just a refactoring.
+
+        * rendering/svg/RenderSVGEllipse.cpp:
+        (WebCore::RenderSVGEllipse::updateShapeFromElement):
+        (WebCore):
+        (WebCore::RenderSVGEllipse::fillShape):
+        (WebCore::RenderSVGEllipse::strokeShape):
+        (WebCore::RenderSVGEllipse::shapeDependentStrokeContains):
+        * rendering/svg/RenderSVGEllipse.h:
+        (RenderSVGEllipse):
+        (WebCore::RenderSVGEllipse::isEmpty):
+        * rendering/svg/RenderSVGRect.cpp:
+        (WebCore::RenderSVGRect::updateShapeFromElement):
+        (WebCore):
+        (WebCore::RenderSVGRect::fillShape):
+        (WebCore::RenderSVGRect::strokeShape):
+        (WebCore::RenderSVGRect::shapeDependentStrokeContains):
+        (WebCore::RenderSVGRect::shapeDependentFillContains):
+        * rendering/svg/RenderSVGRect.h:
+        (RenderSVGRect):
+        (WebCore::RenderSVGRect::isEmpty):
+        * rendering/svg/RenderSVGShape.cpp:
+        (WebCore::RenderSVGShape::updateShapeFromElement):
+        (WebCore):
+        (WebCore::RenderSVGShape::layout):
+        (WebCore::RenderSVGShape::calculateObjectBoundingBox):
+        (WebCore::RenderSVGShape::calculateStrokeBoundingBox):
+        (WebCore::RenderSVGShape::updateRepaintBoundingBox):
+        * rendering/svg/RenderSVGShape.h:
+        (RenderSVGShape):
+        (WebCore::RenderSVGShape::objectBoundingBox):
+        (WebCore::RenderSVGShape::strokeBoundingBox):
+
 2012-07-12  Kent Tamura  <tkent@chromium.org>
 
         Do not save the form state signature if nothing is saved
index b14f8ac..b4a7653 100644 (file)
@@ -46,18 +46,18 @@ RenderSVGEllipse::~RenderSVGEllipse()
 {
 }
 
-void RenderSVGEllipse::createShape()
+void RenderSVGEllipse::updateShapeFromElement()
 {
     // Before creating a new object we need to clear the cached bounding box
     // to avoid using garbage.
-    m_boundingBox = FloatRect();
-    m_outerStrokeRect = FloatRect();
+    m_fillBoundingBox = FloatRect();
+    m_strokeBoundingBox = FloatRect();
     m_center = FloatPoint();
     m_radii = FloatSize();
 
     // Fallback to RenderSVGShape if shape has a non-scaling stroke.
     if (hasNonScalingStroke()) {
-        RenderSVGShape::createShape();
+        RenderSVGShape::updateShapeFromElement();
         m_usePathFallback = true;
         return;
     } else
@@ -69,10 +69,10 @@ void RenderSVGEllipse::createShape()
     if (m_radii.width() <= 0 || m_radii.height() <= 0)
         return;
 
-    m_boundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height());
-    m_outerStrokeRect = m_boundingBox;
+    m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height());
+    m_strokeBoundingBox = m_fillBoundingBox;
     if (style()->svgStyle()->hasStroke())
-        m_outerStrokeRect.inflate(strokeWidth() / 2);
+        m_strokeBoundingBox.inflate(strokeWidth() / 2);
 }
 
 void RenderSVGEllipse::calculateRadiiAndCenter()
@@ -97,27 +97,13 @@ void RenderSVGEllipse::calculateRadiiAndCenter()
     m_center = FloatPoint(ellipse->cx().value(lengthContext), ellipse->cy().value(lengthContext));
 }
 
-FloatRect RenderSVGEllipse::objectBoundingBox() const
-{
-    if (m_usePathFallback)
-        return RenderSVGShape::objectBoundingBox();
-    return m_boundingBox;
-}
-
-FloatRect RenderSVGEllipse::strokeBoundingBox() const
-{
-    if (m_usePathFallback)
-        return RenderSVGShape::strokeBoundingBox();
-    return m_outerStrokeRect;
-}
-
 void RenderSVGEllipse::fillShape(GraphicsContext* context) const
 {
     if (m_usePathFallback) {
         RenderSVGShape::fillShape(context);
         return;
     }
-    context->fillEllipse(m_boundingBox);
+    context->fillEllipse(m_fillBoundingBox);
 }
 
 void RenderSVGEllipse::strokeShape(GraphicsContext* context) const
@@ -128,7 +114,7 @@ void RenderSVGEllipse::strokeShape(GraphicsContext* context) const
         RenderSVGShape::strokeShape(context);
         return;
     }
-    context->strokeEllipse(m_boundingBox);
+    context->strokeEllipse(m_fillBoundingBox);
 }
 
 bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point)
@@ -137,7 +123,7 @@ bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point)
     // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cases.
     if (m_usePathFallback || !hasSmoothStroke()) {
         if (!hasPath())
-            RenderSVGShape::createShape();
+            RenderSVGShape::updateShapeFromElement();
         return RenderSVGShape::shapeDependentStrokeContains(point);
     }
 
index 9e88dee..f5129df 100644 (file)
@@ -41,19 +41,15 @@ public:
 private:
     virtual const char* renderName() const { return "RenderSVGEllipse"; }
 
-    virtual void createShape();
-    virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_boundingBox.isEmpty(); };
+    virtual void updateShapeFromElement();
+    virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); };
     virtual void fillShape(GraphicsContext*) const;
     virtual void strokeShape(GraphicsContext*) const;
-    virtual FloatRect objectBoundingBox() const;
-    virtual FloatRect strokeBoundingBox() const;
     virtual bool shapeDependentStrokeContains(const FloatPoint&);
     virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const;
     void calculateRadiiAndCenter();
 
 private:
-    FloatRect m_boundingBox;
-    FloatRect m_outerStrokeRect;
     FloatPoint m_center;
     FloatSize m_radii;
     bool m_usePathFallback;
index 120c132..c7f9c5b 100755 (executable)
@@ -46,11 +46,11 @@ RenderSVGRect::~RenderSVGRect()
 {
 }
 
-void RenderSVGRect::createShape()
+void RenderSVGRect::updateShapeFromElement()
 {
     // Before creating a new object we need to clear the cached bounding box
     // to avoid using garbage.
-    m_boundingBox = FloatRect();
+    m_fillBoundingBox = FloatRect();
     m_innerStrokeRect = FloatRect();
     m_outerStrokeRect = FloatRect();
     SVGRectElement* rect = static_cast<SVGRectElement*>(node());
@@ -58,7 +58,7 @@ void RenderSVGRect::createShape()
 
     // Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke.
     if (rect->hasAttribute(SVGNames::rxAttr) || rect->hasAttribute(SVGNames::ryAttr) || hasNonScalingStroke()) {
-        RenderSVGShape::createShape();
+        RenderSVGShape::updateShapeFromElement();
         m_usePathFallback = true;
         return;
     } else
@@ -69,12 +69,12 @@ void RenderSVGRect::createShape()
     if (boundingBoxSize.isEmpty())
         return;
 
-    m_boundingBox = FloatRect(FloatPoint(rect->x().value(lengthContext), rect->y().value(lengthContext)), boundingBoxSize);
+    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_boundingBox;
-    m_outerStrokeRect = m_boundingBox;
+    m_innerStrokeRect = m_fillBoundingBox;
+    m_outerStrokeRect = m_fillBoundingBox;
 
     if (style()->svgStyle()->hasStroke()) {
         float strokeWidth = this->strokeWidth();
@@ -82,29 +82,15 @@ void RenderSVGRect::createShape()
         m_outerStrokeRect.inflate(strokeWidth / 2);
     }
 
-    m_strokeBoundingRect = m_outerStrokeRect;
+    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_strokeBoundingRect.inflate(1);
+        m_strokeBoundingBox.inflate(1);
 #endif
 }
 
-FloatRect RenderSVGRect::objectBoundingBox() const
-{
-    if (m_usePathFallback)
-        return RenderSVGShape::objectBoundingBox();
-    return m_boundingBox;
-}
-
-FloatRect RenderSVGRect::strokeBoundingBox() const
-{
-    if (m_usePathFallback)
-        return RenderSVGShape::strokeBoundingBox();
-    return m_strokeBoundingRect;
-}
-
 void RenderSVGRect::fillShape(GraphicsContext* context) const
 {
     if (m_usePathFallback) {
@@ -120,12 +106,12 @@ void RenderSVGRect::fillShape(GraphicsContext* context) const
     if (context->hasShadow()) {
         GraphicsContextStateSaver stateSaver(*context);
         context->clearShadow();
-        context->fillRect(m_boundingBox);
+        context->fillRect(m_fillBoundingBox);
         return;
     }
 #endif
 
-    context->fillRect(m_boundingBox);
+    context->fillRect(m_fillBoundingBox);
 }
 
 void RenderSVGRect::strokeShape(GraphicsContext* context) const
@@ -138,7 +124,7 @@ void RenderSVGRect::strokeShape(GraphicsContext* context) const
         return;
     }
 
-    context->strokeRect(m_boundingBox, strokeWidth());
+    context->strokeRect(m_fillBoundingBox, strokeWidth());
 }
 
 bool RenderSVGRect::shapeDependentStrokeContains(const FloatPoint& point)
@@ -147,7 +133,7 @@ bool RenderSVGRect::shapeDependentStrokeContains(const FloatPoint& point)
     // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cases.
     if (m_usePathFallback || !hasSmoothStroke()) {
         if (!hasPath())
-            RenderSVGShape::createShape();
+            RenderSVGShape::updateShapeFromElement();
         return RenderSVGShape::shapeDependentStrokeContains(point);
     }
 
@@ -158,7 +144,7 @@ bool RenderSVGRect::shapeDependentFillContains(const FloatPoint& point, const Wi
 {
     if (m_usePathFallback)
         return RenderSVGShape::shapeDependentFillContains(point, fillRule);
-    return m_boundingBox.contains(point.x(), point.y());
+    return m_fillBoundingBox.contains(point.x(), point.y());
 }
 
 }
index 36837f7..6305579 100644 (file)
@@ -42,20 +42,16 @@ public:
 private:
     virtual const char* renderName() const { return "RenderSVGRect"; }
 
-    virtual void createShape();
-    virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_boundingBox.isEmpty(); };
+    virtual void updateShapeFromElement();
+    virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); };
     virtual void fillShape(GraphicsContext*) const;
     virtual void strokeShape(GraphicsContext*) const;
-    virtual FloatRect objectBoundingBox() const;
-    virtual FloatRect strokeBoundingBox() const;
     virtual bool shapeDependentStrokeContains(const FloatPoint&);
     virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const;
 
 private:
-    FloatRect m_boundingBox;
     FloatRect m_innerStrokeRect;
     FloatRect m_outerStrokeRect;
-    FloatRect m_strokeBoundingRect;
     bool m_usePathFallback;
 };
 
index 92d7c28..282c50a 100755 (executable)
@@ -64,9 +64,9 @@ RenderSVGShape::~RenderSVGShape()
 {
 }
 
-void RenderSVGShape::createShape()
+void RenderSVGShape::updateShapeFromElement()
 {
-    ASSERT(!m_path);
+    m_path.clear();
     m_path = adoptPtr(new Path);
     ASSERT(RenderSVGShape::isEmpty());
 
@@ -74,6 +74,9 @@ void RenderSVGShape::createShape()
     updatePathFromGraphicsElement(element, path());
     processZeroLengthSubpaths();
     processMarkerPositions();
+
+    m_fillBoundingBox = calculateObjectBoundingBox();
+    m_strokeBoundingBox = calculateStrokeBoundingBox();
 }
 
 bool RenderSVGShape::isEmpty() const
@@ -86,11 +89,6 @@ void RenderSVGShape::fillShape(GraphicsContext* context) const
     context->fillPath(path());
 }
 
-FloatRect RenderSVGShape::objectBoundingBox() const
-{
-    return path().fastBoundingRect();
-}
-
 void RenderSVGShape::strokeShape(GraphicsContext* context) const
 {
     if (style()->svgStyle()->hasVisibleStroke())
@@ -162,11 +160,11 @@ void RenderSVGShape::layout()
 
     bool updateCachedBoundariesInParents = false;
 
-    bool needsShapeUpdate = m_needsShapeUpdate;
-    if (needsShapeUpdate || m_needsBoundariesUpdate) {
-        m_path.clear();
-        createShape();
+    if (m_needsShapeUpdate || m_needsBoundariesUpdate) {
+        updateShapeFromElement();
         m_needsShapeUpdate = false;
+        updateRepaintBoundingBox();
+        m_needsBoundariesUpdate = false;
         updateCachedBoundariesInParents = true;
     }
 
@@ -180,13 +178,6 @@ void RenderSVGShape::layout()
     if (everHadLayout() && selfNeedsLayout())
         SVGResourcesCache::clientLayoutChanged(this);
 
-    // At this point LayoutRepainter already grabbed the old bounds,
-    // recalculate them now so repaintAfterLayout() uses the new bounds.
-    if (needsShapeUpdate || m_needsBoundariesUpdate) {
-        updateCachedBoundaries();
-        m_needsBoundariesUpdate = false;
-    }
-
     // If our bounds changed, notify the parents.
     if (updateCachedBoundariesInParents)
         RenderSVGModelObject::setNeedsBoundariesUpdate();
@@ -439,29 +430,44 @@ FloatRect RenderSVGShape::markerRect(float strokeWidth) const
     return boundaries;
 }
 
-void RenderSVGShape::updateCachedBoundaries()
+FloatRect RenderSVGShape::calculateObjectBoundingBox() const
 {
-    if (isEmpty()) {
-        m_fillBoundingBox = FloatRect();
-        m_strokeAndMarkerBoundingBox = FloatRect();
-        m_repaintBoundingBox = FloatRect();
-        return;
+    return path().fastBoundingRect();
+}
+
+FloatRect RenderSVGShape::calculateStrokeBoundingBox() const
+{
+    ASSERT(m_path);
+    FloatRect strokeBoundingBox = m_fillBoundingBox;
+
+    const SVGRenderStyle* svgStyle = style()->svgStyle();
+    if (svgStyle->hasStroke()) {
+        BoundingRectStrokeStyleApplier strokeStyle(this, style());
+        if (hasNonScalingStroke()) {
+            AffineTransform nonScalingTransform = nonScalingStrokeTransform();
+            if (nonScalingTransform.isInvertible()) {
+                Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);
+                FloatRect strokeBoundingRect = usePath->strokeBoundingRect(&strokeStyle);
+                strokeBoundingRect = nonScalingTransform.inverse().mapRect(strokeBoundingRect);
+                strokeBoundingBox.unite(strokeBoundingRect);
+            }
+        } else
+            strokeBoundingBox.unite(path().strokeBoundingRect(&strokeStyle));
+
+        // FIXME: zero-length subpaths do not respect vector-effect = non-scaling-stroke.
+        float strokeWidth = this->strokeWidth();
+        for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i)
+            strokeBoundingBox.unite(zeroLengthSubpathRect(m_zeroLengthLinecapLocations[i], strokeWidth));
     }
 
-    // Cache _unclipped_ fill bounding box, used for calculations in resources
-    m_fillBoundingBox = objectBoundingBox();
+    if (!m_markerPositions.isEmpty())
+        strokeBoundingBox.unite(markerRect(strokeWidth()));
 
-    // Add zero-length sub-path linecaps to the fill box
-    // FIXME: zero-length subpaths do not respect vector-effect = non-scaling-stroke.
-    float strokeWidth = this->strokeWidth();
-    for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i)
-        m_fillBoundingBox.unite(zeroLengthSubpathRect(m_zeroLengthLinecapLocations[i], strokeWidth));
-
-    // Cache _unclipped_ stroke bounding box, used for calculations in resources (includes marker boundaries)
-    m_strokeAndMarkerBoundingBox = m_fillBoundingBox;
-    if (hasPath())
-        inflateWithStrokeAndMarkerBounds();
-    // Cache smallest possible repaint rectangle
+    return strokeBoundingBox;
+}
+
+void RenderSVGShape::updateRepaintBoundingBox()
+{
     m_repaintBoundingBox = strokeBoundingBox();
     SVGRenderSupport::intersectRepaintRectWithResources(this, m_repaintBoundingBox);
 }
@@ -482,28 +488,6 @@ bool RenderSVGShape::hasSmoothStroke() const
         && svgStyle->capStyle() == svgStyle->initialCapStyle();
 }
 
-void RenderSVGShape::inflateWithStrokeAndMarkerBounds()
-{
-    const SVGRenderStyle* svgStyle = style()->svgStyle();
-    if (svgStyle->hasStroke()) {
-        BoundingRectStrokeStyleApplier strokeStyle(this, style());
-
-        // SVG1.2 Tiny only defines non scaling stroke for the stroke but not markers.
-        if (hasNonScalingStroke()) {
-            AffineTransform nonScalingTransform = nonScalingStrokeTransform();
-            if (nonScalingTransform.isInvertible()) {
-                Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform);
-                FloatRect strokeBoundingRect = usePath->strokeBoundingRect(&strokeStyle);
-                strokeBoundingRect = nonScalingTransform.inverse().mapRect(strokeBoundingRect);
-                m_strokeAndMarkerBoundingBox.unite(strokeBoundingRect);
-            }
-        } else
-            m_strokeAndMarkerBoundingBox.unite(path().strokeBoundingRect(&strokeStyle));
-    }
-    if (!m_markerPositions.isEmpty())
-        m_strokeAndMarkerBoundingBox.unite(markerRect(strokeWidth()));
-}
-
 void RenderSVGShape::drawMarkers(PaintInfo& paintInfo)
 {
     ASSERT(!m_markerPositions.isEmpty());
index f6c22db..81c6b37 100644 (file)
@@ -83,11 +83,8 @@ public:
     }
 
 protected:
-    virtual void createShape();
+    virtual void updateShapeFromElement();
     virtual bool isEmpty() const;
-    virtual FloatRect objectBoundingBox() const;
-    virtual FloatRect strokeBoundingBox() const { return m_strokeAndMarkerBoundingBox; }
-    void setStrokeAndMarkerBoundingBox(FloatRect rect) { m_strokeAndMarkerBoundingBox = rect; }
     virtual bool shapeDependentStrokeContains(const FloatPoint&);
     virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const;
     float strokeWidth() const;
@@ -95,6 +92,9 @@ protected:
     bool hasNonScalingStroke() const { return style()->svgStyle()->vectorEffect() == VE_NON_SCALING_STROKE; }
     bool hasSmoothStroke() const;
 
+    FloatRect m_fillBoundingBox;
+    FloatRect m_strokeBoundingBox;
+
 private:
     // Hit-detection separated for the fill and the stroke
     bool fillContains(const FloatPoint&, bool requiresFill = true, const WindRule fillRule = RULE_NONZERO);
@@ -113,7 +113,12 @@ private:
 
     virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction);
 
-    void updateCachedBoundaries();
+    virtual FloatRect objectBoundingBox() const { return m_fillBoundingBox; }
+    virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; }
+
+    FloatRect calculateObjectBoundingBox() const;
+    FloatRect calculateStrokeBoundingBox() const;
+    void updateRepaintBoundingBox();
 
     AffineTransform nonScalingStrokeTransform() const;
     bool setupNonScalingStrokeContext(AffineTransform&, GraphicsContextStateSaver&);
@@ -132,12 +137,9 @@ private:
     void strokePath(RenderStyle*, GraphicsContext*, Path*, RenderSVGResource*,
                     const Color&, int);
     void fillAndStrokePath(GraphicsContext*);
-    void inflateWithStrokeAndMarkerBounds();
     void drawMarkers(PaintInfo&);
 
 private:
-    FloatRect m_fillBoundingBox;
-    FloatRect m_strokeAndMarkerBoundingBox;
     FloatRect m_repaintBoundingBox;
     AffineTransform m_localTransform;
     OwnPtr<Path> m_path;