Title: [122079] trunk/Source/WebCore
Revision
122079
Author
[email protected]
Date
2012-07-08 20:57:03 -0700 (Sun, 08 Jul 2012)

Log Message

Refactor RenderSVGShape to not contain fallback code
https://bugs.webkit.org/show_bug.cgi?id=90514

Reviewed by Nikolas Zimmermann.

The interaction between RenderSVGShape and {RenderSVGEllipse, RenderSVGRect}
was too coupled and it was not clear when a path existed or who controlled
falling back to path codepaths in RenderSVGShape.

This patch cleans up RenderSVGShape so that it does not track fallback state
and does not have special handling for creating a shape in strokeContains. Because
some functions of RenderSVGShape can be called without a path existing, each
of these functions has switched to using the path() function which asserts that
a path exists.

There is only one remaining use of hasPath() in RenderSVGShape which I plan
to remove in a followup patch.

This patch also cleans up RenderSVGRect and RenderSVGEllipse. These classes
now handle fallback tracking themselves and choose when to use their optimized
strokeContains codepaths.

No new tests as this is just a refactoring.

* rendering/svg/RenderSVGEllipse.cpp:
(WebCore::RenderSVGEllipse::RenderSVGEllipse):
(WebCore::RenderSVGEllipse::createShape):
(WebCore::RenderSVGEllipse::objectBoundingBox):
(WebCore::RenderSVGEllipse::strokeBoundingBox):
(WebCore::RenderSVGEllipse::fillShape):
(WebCore::RenderSVGEllipse::strokeShape):
(WebCore::RenderSVGEllipse::shapeDependentStrokeContains):
(WebCore::RenderSVGEllipse::shapeDependentFillContains):
* rendering/svg/RenderSVGEllipse.h:
(WebCore::RenderSVGEllipse::isEmpty):
(RenderSVGEllipse):
* rendering/svg/RenderSVGRect.cpp:
(WebCore::RenderSVGRect::RenderSVGRect):
(WebCore::RenderSVGRect::createShape):
(WebCore::RenderSVGRect::objectBoundingBox):
(WebCore::RenderSVGRect::strokeBoundingBox):
(WebCore::RenderSVGRect::fillShape):
(WebCore::RenderSVGRect::strokeShape):
(WebCore::RenderSVGRect::shapeDependentStrokeContains):
(WebCore::RenderSVGRect::shapeDependentFillContains):
* rendering/svg/RenderSVGRect.h:
(WebCore::RenderSVGRect::isEmpty):
(RenderSVGRect):
* rendering/svg/RenderSVGShape.cpp:
(WebCore::RenderSVGShape::RenderSVGShape):
(WebCore::RenderSVGShape::createShape):
(WebCore::RenderSVGShape::isEmpty):
(WebCore::RenderSVGShape::objectBoundingBox):
(WebCore::RenderSVGShape::shapeDependentStrokeContains):
(WebCore::RenderSVGShape::shapeDependentFillContains):
(WebCore::RenderSVGShape::strokeContains):
(WebCore::RenderSVGShape::layout):
(WebCore::RenderSVGShape::hasSmoothStroke):
(WebCore):
* rendering/svg/RenderSVGShape.h:
(RenderSVGShape):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (122078 => 122079)


--- trunk/Source/WebCore/ChangeLog	2012-07-09 03:51:26 UTC (rev 122078)
+++ trunk/Source/WebCore/ChangeLog	2012-07-09 03:57:03 UTC (rev 122079)
@@ -1,3 +1,67 @@
+2012-07-08  Philip Rogers  <[email protected]>
+
+        Refactor RenderSVGShape to not contain fallback code
+        https://bugs.webkit.org/show_bug.cgi?id=90514
+
+        Reviewed by Nikolas Zimmermann.
+
+        The interaction between RenderSVGShape and {RenderSVGEllipse, RenderSVGRect}
+        was too coupled and it was not clear when a path existed or who controlled
+        falling back to path codepaths in RenderSVGShape.
+
+        This patch cleans up RenderSVGShape so that it does not track fallback state
+        and does not have special handling for creating a shape in strokeContains. Because
+        some functions of RenderSVGShape can be called without a path existing, each
+        of these functions has switched to using the path() function which asserts that
+        a path exists.
+
+        There is only one remaining use of hasPath() in RenderSVGShape which I plan
+        to remove in a followup patch.
+
+        This patch also cleans up RenderSVGRect and RenderSVGEllipse. These classes
+        now handle fallback tracking themselves and choose when to use their optimized
+        strokeContains codepaths.
+
+        No new tests as this is just a refactoring.
+
+        * rendering/svg/RenderSVGEllipse.cpp:
+        (WebCore::RenderSVGEllipse::RenderSVGEllipse):
+        (WebCore::RenderSVGEllipse::createShape):
+        (WebCore::RenderSVGEllipse::objectBoundingBox):
+        (WebCore::RenderSVGEllipse::strokeBoundingBox):
+        (WebCore::RenderSVGEllipse::fillShape):
+        (WebCore::RenderSVGEllipse::strokeShape):
+        (WebCore::RenderSVGEllipse::shapeDependentStrokeContains):
+        (WebCore::RenderSVGEllipse::shapeDependentFillContains):
+        * rendering/svg/RenderSVGEllipse.h:
+        (WebCore::RenderSVGEllipse::isEmpty):
+        (RenderSVGEllipse):
+        * rendering/svg/RenderSVGRect.cpp:
+        (WebCore::RenderSVGRect::RenderSVGRect):
+        (WebCore::RenderSVGRect::createShape):
+        (WebCore::RenderSVGRect::objectBoundingBox):
+        (WebCore::RenderSVGRect::strokeBoundingBox):
+        (WebCore::RenderSVGRect::fillShape):
+        (WebCore::RenderSVGRect::strokeShape):
+        (WebCore::RenderSVGRect::shapeDependentStrokeContains):
+        (WebCore::RenderSVGRect::shapeDependentFillContains):
+        * rendering/svg/RenderSVGRect.h:
+        (WebCore::RenderSVGRect::isEmpty):
+        (RenderSVGRect):
+        * rendering/svg/RenderSVGShape.cpp:
+        (WebCore::RenderSVGShape::RenderSVGShape):
+        (WebCore::RenderSVGShape::createShape):
+        (WebCore::RenderSVGShape::isEmpty):
+        (WebCore::RenderSVGShape::objectBoundingBox):
+        (WebCore::RenderSVGShape::shapeDependentStrokeContains):
+        (WebCore::RenderSVGShape::shapeDependentFillContains):
+        (WebCore::RenderSVGShape::strokeContains):
+        (WebCore::RenderSVGShape::layout):
+        (WebCore::RenderSVGShape::hasSmoothStroke):
+        (WebCore):
+        * rendering/svg/RenderSVGShape.h:
+        (RenderSVGShape):
+
 2012-07-08  Kinuko Yasuda  <[email protected]>
 
         XHR.send should support ArrayBufferView

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp (122078 => 122079)


--- trunk/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp	2012-07-09 03:51:26 UTC (rev 122078)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp	2012-07-09 03:57:03 UTC (rev 122079)
@@ -38,6 +38,7 @@
 
 RenderSVGEllipse::RenderSVGEllipse(SVGStyledTransformableElement* node)
     : RenderSVGShape(node)
+    , m_usePathFallback(false)
 {
 }
 
@@ -54,12 +55,13 @@
     m_center = FloatPoint();
     m_radii = FloatSize();
 
-    // Fallback to RenderSVGShape if shape has a non scaling stroke.
+    // Fallback to RenderSVGShape if shape has a non-scaling stroke.
     if (hasNonScalingStroke()) {
         RenderSVGShape::createShape();
-        setIsPaintingFallback(true);
+        m_usePathFallback = true;
         return;
-    }
+    } else
+        m_usePathFallback = false;
 
     calculateRadiiAndCenter();
 
@@ -97,21 +99,21 @@
 
 FloatRect RenderSVGEllipse::objectBoundingBox() const
 {
-    if (isPaintingFallback())
+    if (m_usePathFallback)
         return RenderSVGShape::objectBoundingBox();
     return m_boundingBox;
 }
 
 FloatRect RenderSVGEllipse::strokeBoundingBox() const
 {
-    if (isPaintingFallback())
+    if (m_usePathFallback)
         return RenderSVGShape::strokeBoundingBox();
     return m_outerStrokeRect;
 }
 
 void RenderSVGEllipse::fillShape(GraphicsContext* context) const
 {
-    if (isPaintingFallback()) {
+    if (m_usePathFallback) {
         RenderSVGShape::fillShape(context);
         return;
     }
@@ -122,17 +124,22 @@
 {
     if (!style()->svgStyle()->hasVisibleStroke())
         return;
-    if (isPaintingFallback()) {
+    if (m_usePathFallback) {
         RenderSVGShape::strokeShape(context);
         return;
     }
     context->strokeEllipse(m_boundingBox);
 }
 
-bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point) const
+bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point)
 {
-    if (isPaintingFallback())
+    // The optimized contains code below does not support non-smooth strokes so we need
+    // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cases.
+    if (m_usePathFallback || !hasSmoothStroke()) {
+        if (!hasPath())
+            RenderSVGShape::createShape();
         return RenderSVGShape::shapeDependentStrokeContains(point);
+    }
 
     float halfStrokeWidth = strokeWidth() / 2;
     FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());
@@ -151,7 +158,7 @@
 
 bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
 {
-    if (isPaintingFallback())
+    if (m_usePathFallback)
         return RenderSVGShape::shapeDependentFillContains(point, fillRule);
 
     FloatPoint center = FloatPoint(m_center.x() - point.x(), m_center.y() - point.y());

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGEllipse.h (122078 => 122079)


--- trunk/Source/WebCore/rendering/svg/RenderSVGEllipse.h	2012-07-09 03:51:26 UTC (rev 122078)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGEllipse.h	2012-07-09 03:57:03 UTC (rev 122079)
@@ -42,12 +42,12 @@
     virtual const char* renderName() const { return "RenderSVGEllipse"; }
 
     virtual void createShape();
-    virtual bool isEmpty() const { return hasPath() ? RenderSVGShape::isEmpty() : m_boundingBox.isEmpty(); };
+    virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_boundingBox.isEmpty(); };
     virtual void fillShape(GraphicsContext*) const;
     virtual void strokeShape(GraphicsContext*) const;
     virtual FloatRect objectBoundingBox() const;
     virtual FloatRect strokeBoundingBox() const;
-    virtual bool shapeDependentStrokeContains(const FloatPoint&) const;
+    virtual bool shapeDependentStrokeContains(const FloatPoint&);
     virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const;
     void calculateRadiiAndCenter();
 
@@ -56,6 +56,7 @@
     FloatRect m_outerStrokeRect;
     FloatPoint m_center;
     FloatSize m_radii;
+    bool m_usePathFallback;
 };
 
 }

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGRect.cpp (122078 => 122079)


--- trunk/Source/WebCore/rendering/svg/RenderSVGRect.cpp	2012-07-09 03:51:26 UTC (rev 122078)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGRect.cpp	2012-07-09 03:57:03 UTC (rev 122079)
@@ -38,6 +38,7 @@
 
 RenderSVGRect::RenderSVGRect(SVGRectElement* node)
     : RenderSVGShape(node)
+    , m_usePathFallback(false)
 {
 }
 
@@ -55,12 +56,13 @@
     SVGRectElement* rect = static_cast<SVGRectElement*>(node());
     ASSERT(rect);
 
-    // Fallback to RenderSVGShape if rect has rounded corners.
+    // 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();
-       setIsPaintingFallback(true);
-       return;
-    }
+        RenderSVGShape::createShape();
+        m_usePathFallback = true;
+        return;
+    } else
+        m_usePathFallback = false;
 
     SVGLengthContext lengthContext(rect);
     FloatSize boundingBoxSize(rect->width().value(lengthContext), rect->height().value(lengthContext));
@@ -91,61 +93,70 @@
 
 FloatRect RenderSVGRect::objectBoundingBox() const
 {
-    if (isPaintingFallback())
+    if (m_usePathFallback)
         return RenderSVGShape::objectBoundingBox();
     return m_boundingBox;
 }
 
 FloatRect RenderSVGRect::strokeBoundingBox() const
 {
-    if (isPaintingFallback())
+    if (m_usePathFallback)
         return RenderSVGShape::strokeBoundingBox();
     return m_strokeBoundingRect;
 }
 
 void RenderSVGRect::fillShape(GraphicsContext* context) const
 {
-    if (!isPaintingFallback()) {
+    if (m_usePathFallback) {
+        RenderSVGShape::fillShape(context);
+        return;
+    }
+
 #if USE(CG)
-        // FIXME: CG implementation of GraphicsContextCG::fillRect has an own
-        // shadow drawing method, which draws an extra shadow.
-        // This is a workaround for switching off the extra shadow.
-        // https://bugs.webkit.org/show_bug.cgi?id=68899
-        if (context->hasShadow()) {
-            GraphicsContextStateSaver stateSaver(*context);
-            context->clearShadow();
-            context->fillRect(m_boundingBox);
-            return;
-        }
-#endif
+    // FIXME: CG implementation of GraphicsContextCG::fillRect has an own
+    // shadow drawing method, which draws an extra shadow.
+    // This is a workaround for switching off the extra shadow.
+    // https://bugs.webkit.org/show_bug.cgi?id=68899
+    if (context->hasShadow()) {
+        GraphicsContextStateSaver stateSaver(*context);
+        context->clearShadow();
         context->fillRect(m_boundingBox);
         return;
     }
-    RenderSVGShape::fillShape(context);
+#endif
+
+    context->fillRect(m_boundingBox);
 }
 
 void RenderSVGRect::strokeShape(GraphicsContext* context) const
 {
     if (!style()->svgStyle()->hasVisibleStroke())
         return;
-    if (!isPaintingFallback()) {
-        context->strokeRect(m_boundingBox, strokeWidth());
+
+    if (m_usePathFallback) {
+        RenderSVGShape::strokeShape(context);
         return;
     }
-    RenderSVGShape::strokeShape(context);
+
+    context->strokeRect(m_boundingBox, strokeWidth());
 }
 
-bool RenderSVGRect::shapeDependentStrokeContains(const FloatPoint& point) const
+bool RenderSVGRect::shapeDependentStrokeContains(const FloatPoint& point)
 {
-    if (isPaintingFallback())
+    // The optimized contains code below does not support non-smooth strokes so we need
+    // to fall back to RenderSVGShape::shapeDependentStrokeContains in these cases.
+    if (m_usePathFallback || !hasSmoothStroke()) {
+        if (!hasPath())
+            RenderSVGShape::createShape();
         return RenderSVGShape::shapeDependentStrokeContains(point);
+    }
 
     return m_outerStrokeRect.contains(point, FloatRect::InsideOrOnStroke) && !m_innerStrokeRect.contains(point, FloatRect::InsideButNotOnStroke);
 }
 
 bool RenderSVGRect::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
 {
-    if (isPaintingFallback())
+    if (m_usePathFallback)
         return RenderSVGShape::shapeDependentFillContains(point, fillRule);
     return m_boundingBox.contains(point.x(), point.y());
 }

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGRect.h (122078 => 122079)


--- trunk/Source/WebCore/rendering/svg/RenderSVGRect.h	2012-07-09 03:51:26 UTC (rev 122078)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGRect.h	2012-07-09 03:57:03 UTC (rev 122079)
@@ -43,12 +43,12 @@
     virtual const char* renderName() const { return "RenderSVGRect"; }
 
     virtual void createShape();
-    virtual bool isEmpty() const { return hasPath() ? RenderSVGShape::isEmpty() : m_boundingBox.isEmpty(); };
+    virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_boundingBox.isEmpty(); };
     virtual void fillShape(GraphicsContext*) const;
     virtual void strokeShape(GraphicsContext*) const;
     virtual FloatRect objectBoundingBox() const;
     virtual FloatRect strokeBoundingBox() const;
-    virtual bool shapeDependentStrokeContains(const FloatPoint&) const;
+    virtual bool shapeDependentStrokeContains(const FloatPoint&);
     virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const;
 
 private:
@@ -56,6 +56,7 @@
     FloatRect m_innerStrokeRect;
     FloatRect m_outerStrokeRect;
     FloatRect m_strokeBoundingRect;
+    bool m_usePathFallback;
 };
 
 }

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGShape.cpp (122078 => 122079)


--- trunk/Source/WebCore/rendering/svg/RenderSVGShape.cpp	2012-07-09 03:51:26 UTC (rev 122078)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGShape.cpp	2012-07-09 03:57:03 UTC (rev 122079)
@@ -57,7 +57,6 @@
     , m_needsBoundariesUpdate(false) // Default is false, the cached rects are empty from the beginning.
     , m_needsShapeUpdate(true) // Default is true, so we grab a Path object once from SVGStyledTransformableElement.
     , m_needsTransformUpdate(true) // Default is true, so we grab a AffineTransform object once from SVGStyledTransformableElement.
-    , m_fillFallback(false)
 {
 }
 
@@ -69,7 +68,7 @@
 {
     ASSERT(!m_path);
     m_path = adoptPtr(new Path);
-    ASSERT(isEmpty());
+    ASSERT(RenderSVGShape::isEmpty());
 
     SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(node());
     updatePathFromGraphicsElement(element, path());
@@ -79,7 +78,7 @@
 
 bool RenderSVGShape::isEmpty() const
 {
-    return m_path->isEmpty();
+    return path().isEmpty();
 }
 
 void RenderSVGShape::fillShape(GraphicsContext* context) const
@@ -89,7 +88,7 @@
 
 FloatRect RenderSVGShape::objectBoundingBox() const
 {
-    return m_path->fastBoundingRect();
+    return path().fastBoundingRect();
 }
 
 void RenderSVGShape::strokeShape(GraphicsContext* context) const
@@ -98,7 +97,7 @@
         context->strokePath(path());
 }
 
-bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point) const
+bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point)
 {
     ASSERT(m_path);
     BoundingRectStrokeStyleApplier applier(this, style());
@@ -115,8 +114,7 @@
 
 bool RenderSVGShape::shapeDependentFillContains(const FloatPoint& point, const WindRule fillRule) const
 {
-    ASSERT(m_path);
-    return m_path->contains(point, fillRule);
+    return path().contains(point, fillRule);
 }
 
 bool RenderSVGShape::fillContains(const FloatPoint& point, bool requiresFill, const WindRule fillRule)
@@ -140,7 +138,6 @@
     if (requiresStroke && !RenderSVGResource::strokePaintingResource(this, style(), fallbackColor))
         return false;
 
-    const SVGRenderStyle* svgStyle = style()->svgStyle();
     for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i) {
         ASSERT(style()->svgStyle()->hasStroke());
         float strokeWidth = this->strokeWidth();
@@ -155,12 +152,6 @@
         }
     }
 
-    if (!svgStyle->strokeDashArray().isEmpty() || svgStyle->strokeMiterLimit() != svgStyle->initialStrokeMiterLimit()
-        || svgStyle->joinStyle() != svgStyle->initialJoinStyle() || svgStyle->capStyle() != svgStyle->initialCapStyle()) {
-        if (!m_path)
-            RenderSVGShape::createShape();
-        return RenderSVGShape::shapeDependentStrokeContains(point);
-    }
     return shapeDependentStrokeContains(point);
 }
 
@@ -173,7 +164,6 @@
 
     bool needsShapeUpdate = m_needsShapeUpdate;
     if (needsShapeUpdate || m_needsBoundariesUpdate) {
-        setIsPaintingFallback(false);
         m_path.clear();
         createShape();
         m_needsShapeUpdate = false;
@@ -483,6 +473,15 @@
     return style()->svgStyle()->strokeWidth().value(lengthContext);
 }
 
+bool RenderSVGShape::hasSmoothStroke() const
+{
+    const SVGRenderStyle* svgStyle = style()->svgStyle();
+    return svgStyle->strokeDashArray().isEmpty()
+        && svgStyle->strokeMiterLimit() == svgStyle->initialStrokeMiterLimit()
+        && svgStyle->joinStyle() == svgStyle->initialJoinStyle()
+        && svgStyle->capStyle() == svgStyle->initialCapStyle();
+}
+
 void RenderSVGShape::inflateWithStrokeAndMarkerBounds()
 {
     const SVGRenderStyle* svgStyle = style()->svgStyle();

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGShape.h (122078 => 122079)


--- trunk/Source/WebCore/rendering/svg/RenderSVGShape.h	2012-07-09 03:51:26 UTC (rev 122078)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGShape.h	2012-07-09 03:57:03 UTC (rev 122079)
@@ -75,7 +75,6 @@
     virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
     virtual void fillShape(GraphicsContext*) const;
     virtual void strokeShape(GraphicsContext*) const;
-    bool isPaintingFallback() const { return m_fillFallback; }
 
     Path& path() const
     {
@@ -89,12 +88,12 @@
     virtual FloatRect objectBoundingBox() const;
     virtual FloatRect strokeBoundingBox() const { return m_strokeAndMarkerBoundingBox; }
     void setStrokeAndMarkerBoundingBox(FloatRect rect) { m_strokeAndMarkerBoundingBox = rect; }
-    virtual bool shapeDependentStrokeContains(const FloatPoint&) const;
+    virtual bool shapeDependentStrokeContains(const FloatPoint&);
     virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const;
     float strokeWidth() const;
-    void setIsPaintingFallback(bool isFallback) { m_fillFallback = isFallback; }
     bool hasPath() const { return m_path.get(); }
     bool hasNonScalingStroke() const { return style()->svgStyle()->vectorEffect() == VE_NON_SCALING_STROKE; }
+    bool hasSmoothStroke() const;
 
 private:
     // Hit-detection separated for the fill and the stroke
@@ -148,7 +147,6 @@
     bool m_needsBoundariesUpdate : 1;
     bool m_needsShapeUpdate : 1;
     bool m_needsTransformUpdate : 1;
-    bool m_fillFallback : 1;
 };
 
 inline RenderSVGShape* toRenderSVGShape(RenderObject* object)
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to