Title: [99460] trunk
Revision
99460
Author
[email protected]
Date
2011-11-07 12:40:24 -0800 (Mon, 07 Nov 2011)

Log Message

getBBox() on a SVGPathElement with curves incorrectly includes control points
https://bugs.webkit.org/show_bug.cgi?id=53512
<rdar://problem/9861154>

Reviewed by Oliver Hunt.

Split Path::boundingRect() into two, adding Path::fastBoundingRect()
for a rough estimate of the bounding rect (always equal to or larger
than boundingRect()). fastBoundingRect() currently falls back to
boundingRect() for all ports besides CG, though in most cases
(on a port-by-port basis) the current implementation of boundingRect()
will need to become fastBoundingRect(), and a new, more accurate method will
be implemented for boundingRect().

All previous callers of boundingRect() are transitioned to using fastBoundingRect()
except SVGPathElement::getBBox, which wants an accurate bounding box.

The CoreGraphics implementation of Path::boundingRect() called
CGPathGetBoundingBox, which includes the path's control points in its
calculations. Snow Leopard added CGPathGetPathBoundingBox, which
finds the bounding box of only points within the path, and does not
include control points. On Snow Leopard and above, we now use the latter.

Test: svg/custom/getBBox-path.svg

* html/HTMLAreaElement.cpp:
* html/canvas/CanvasRenderingContext2D.cpp:
* platform/graphics/Path.cpp:
* platform/graphics/Path.h:
* platform/graphics/cg/GraphicsContextCG.cpp:
* platform/graphics/cg/PathCG.cpp:
(WebCore::Path::boundingRect):
* rendering/RenderObject.h:
* rendering/svg/RenderSVGPath.cpp:
* svg/SVGPathElement.cpp:
* svg/SVGPathElement.h:

Add a test that ensures that getBBox does not include control points in the rect it returns.

* platform/chromium/test_expectations.txt:
* svg/custom/getBBox-path-expected.txt: Added.
* svg/custom/getBBox-path.svg: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (99459 => 99460)


--- trunk/LayoutTests/ChangeLog	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/LayoutTests/ChangeLog	2011-11-07 20:40:24 UTC (rev 99460)
@@ -1,3 +1,17 @@
+2011-11-07  Tim Horton  <[email protected]>
+
+        getBBox() on a SVGPathElement with curves incorrectly includes control points
+        https://bugs.webkit.org/show_bug.cgi?id=53512
+        <rdar://problem/9861154>
+
+        Reviewed by Oliver Hunt.
+        
+        Add a test that ensures that getBBox does not include control points in the rect it returns.
+
+        * platform/chromium/test_expectations.txt:
+        * svg/custom/getBBox-path-expected.txt: Added.
+        * svg/custom/getBBox-path.svg: Added.
+
 2011-11-07  [email protected]  <[email protected]>
 
         Web Inspector: Suggest box should consume enter key pressed event.

Modified: trunk/LayoutTests/platform/chromium/test_expectations.txt (99459 => 99460)


--- trunk/LayoutTests/platform/chromium/test_expectations.txt	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/LayoutTests/platform/chromium/test_expectations.txt	2011-11-07 20:40:24 UTC (rev 99460)
@@ -3899,3 +3899,6 @@
 BUGWK59552 SNOWLEOPARD DEBUG : fast/frames/set-parent-src-synchronously.html = PASS CRASH
 
 BUGWK71658 MAC DEBUG : fast/frames/sandboxed-iframe-navigation-targetlink.html = PASS TIMEOUT
+
+// Introduced due to BUGWK53512, fails under Skia right now
+BUGWK65939 : svg/custom/getBBox-path.svg = TEXT

Added: trunk/LayoutTests/svg/custom/getBBox-path-expected.txt (0 => 99460)


--- trunk/LayoutTests/svg/custom/getBBox-path-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/svg/custom/getBBox-path-expected.txt	2011-11-07 20:40:24 UTC (rev 99460)
@@ -0,0 +1 @@
+100 37.5 PASS

Added: trunk/LayoutTests/svg/custom/getBBox-path.svg (0 => 99460)


--- trunk/LayoutTests/svg/custom/getBBox-path.svg	                        (rev 0)
+++ trunk/LayoutTests/svg/custom/getBBox-path.svg	2011-11-07 20:40:24 UTC (rev 99460)
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" _onload_="init()">
+  <script type="text/_javascript_">
+  <![CDATA[
+    function init()
+    {
+        if (window.layoutTestController)
+            layoutTestController.dumpAsText();
+        var txt = document.getElementById("text");
+        size = document.getElementById("shape").getBBox();
+        var passState = "FAIL";
+        if(size.width == 100 && size.height == 37.5)
+            passState = "PASS";
+        var textNode = document.createTextNode(size.width + " " + size.height + " " + passState);
+        txt.appendChild(textNode);
+    }
+  ]]>
+  </script>
+  <path id="shape" d="M100,100 C125,150 175,150 200,100 z" />
+  <text id="text" x="50" y="50" />
+</svg>

Modified: trunk/Source/WebCore/ChangeLog (99459 => 99460)


--- trunk/Source/WebCore/ChangeLog	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/ChangeLog	2011-11-07 20:40:24 UTC (rev 99460)
@@ -1,3 +1,42 @@
+2011-11-07  Tim Horton  <[email protected]>
+
+        getBBox() on a SVGPathElement with curves incorrectly includes control points
+        https://bugs.webkit.org/show_bug.cgi?id=53512
+        <rdar://problem/9861154>
+
+        Reviewed by Oliver Hunt.
+
+        Split Path::boundingRect() into two, adding Path::fastBoundingRect()
+        for a rough estimate of the bounding rect (always equal to or larger
+        than boundingRect()). fastBoundingRect() currently falls back to
+        boundingRect() for all ports besides CG, though in most cases
+        (on a port-by-port basis) the current implementation of boundingRect()
+        will need to become fastBoundingRect(), and a new, more accurate method will
+        be implemented for boundingRect().
+
+        All previous callers of boundingRect() are transitioned to using fastBoundingRect()
+        except SVGPathElement::getBBox, which wants an accurate bounding box.
+
+        The CoreGraphics implementation of Path::boundingRect() called
+        CGPathGetBoundingBox, which includes the path's control points in its
+        calculations. Snow Leopard added CGPathGetPathBoundingBox, which
+        finds the bounding box of only points within the path, and does not
+        include control points. On Snow Leopard and above, we now use the latter.
+
+        Test: svg/custom/getBBox-path.svg
+
+        * html/HTMLAreaElement.cpp:
+        * html/canvas/CanvasRenderingContext2D.cpp:
+        * platform/graphics/Path.cpp:
+        * platform/graphics/Path.h:
+        * platform/graphics/cg/GraphicsContextCG.cpp:
+        * platform/graphics/cg/PathCG.cpp:
+        (WebCore::Path::boundingRect):
+        * rendering/RenderObject.h:
+        * rendering/svg/RenderSVGPath.cpp:
+        * svg/SVGPathElement.cpp:
+        * svg/SVGPathElement.h:
+
 2011-11-07  Vsevolod Vlasov  <[email protected]>
 
         Web Inspector: Suggest box should be open immediately if forced by Ctrl+Space.

Modified: trunk/Source/WebCore/html/HTMLAreaElement.cpp (99459 => 99460)


--- trunk/Source/WebCore/html/HTMLAreaElement.cpp	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/html/HTMLAreaElement.cpp	2011-11-07 20:40:24 UTC (rev 99460)
@@ -120,7 +120,7 @@
     
 LayoutRect HTMLAreaElement::computeRect(RenderObject* obj) const
 {
-    return enclosingLayoutRect(computePath(obj).boundingRect());
+    return enclosingLayoutRect(computePath(obj).fastBoundingRect());
 }
 
 Path HTMLAreaElement::getRegion(const LayoutSize& size) const

Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp (99459 => 99460)


--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp	2011-11-07 20:40:24 UTC (rev 99460)
@@ -771,7 +771,7 @@
     if (m_path.isEmpty())
         return;
 
-    FloatRect boundRect = m_path.boundingRect();
+    FloatRect boundRect = m_path.fastBoundingRect();
     if (boundRect.width() || boundRect.height())
         m_path.closeSubpath();
 }
@@ -956,7 +956,7 @@
             didDrawEntireCanvas();
         } else {
             c->fillPath(m_path);
-            didDraw(m_path.boundingRect());
+            didDraw(m_path.fastBoundingRect());
         }
     }
 
@@ -974,7 +974,7 @@
         return;
 
     if (!m_path.isEmpty()) {
-        FloatRect dirtyRect = m_path.boundingRect();
+        FloatRect dirtyRect = m_path.fastBoundingRect();
         // Fast approximation of the stroke's bounding rect.
         // This yields a slightly oversized rect but is very fast
         // compared to Path::strokeBoundingRect().
@@ -1580,7 +1580,7 @@
     IntRect canvasRect(0, 0, canvas()->width(), canvas()->height());
     canvasRect = canvas()->baseTransform().mapRect(canvasRect);
     Path path = transformAreaToDevice(area);
-    IntRect bufferRect = enclosingIntRect(path.boundingRect());
+    IntRect bufferRect = enclosingIntRect(path.fastBoundingRect());
     IntPoint originalLocation = bufferRect.location();
     bufferRect.intersect(canvasRect);
     if (croppedOffset)

Modified: trunk/Source/WebCore/platform/graphics/Path.cpp (99459 => 99460)


--- trunk/Source/WebCore/platform/graphics/Path.cpp	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/platform/graphics/Path.cpp	2011-11-07 20:40:24 UTC (rev 99460)
@@ -163,4 +163,11 @@
     closeSubpath();
 }
 
+#if !USE(CG)
+FloatRect Path::fastBoundingRect() const
+{
+    return boundingRect();
 }
+#endif
+
+}

Modified: trunk/Source/WebCore/platform/graphics/Path.h (99459 => 99460)


--- trunk/Source/WebCore/platform/graphics/Path.h	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/platform/graphics/Path.h	2011-11-07 20:40:24 UTC (rev 99460)
@@ -105,7 +105,10 @@
 
         bool contains(const FloatPoint&, WindRule rule = RULE_NONZERO) const;
         bool strokeContains(StrokeStyleApplier*, const FloatPoint&) const;
+        // fastBoundingRect() should equal or contain boundingRect(); boundingRect()
+        // should perfectly bound the points within the path.
         FloatRect boundingRect() const;
+        FloatRect fastBoundingRect() const;
         FloatRect strokeBoundingRect(StrokeStyleApplier* = 0) const;
         
         float length() const;

Modified: trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp (99459 => 99460)


--- trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/platform/graphics/cg/GraphicsContextCG.cpp	2011-11-07 20:40:24 UTC (rev 99460)
@@ -627,7 +627,7 @@
 
     if (m_state.fillGradient) {
         if (hasShadow()) {
-            FloatRect rect = path.boundingRect();
+            FloatRect rect = path.fastBoundingRect();
             CGLayerRef layer = CGLayerCreateWithContext(context, CGSizeMake(rect.width(), rect.height()), 0);
             CGContextRef layerContext = CGLayerGetContext(layer);
 
@@ -682,7 +682,7 @@
 
     if (m_state.strokeGradient) {
         if (hasShadow()) {
-            FloatRect rect = path.boundingRect();
+            FloatRect rect = path.fastBoundingRect();
             float lineWidth = strokeThickness();
             float doubleLineWidth = lineWidth * 2;
             float layerWidth = ceilf(rect.width() + doubleLineWidth);

Modified: trunk/Source/WebCore/platform/graphics/cg/PathCG.cpp (99459 => 99460)


--- trunk/Source/WebCore/platform/graphics/cg/PathCG.cpp	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/platform/graphics/cg/PathCG.cpp	2011-11-07 20:40:24 UTC (rev 99460)
@@ -124,7 +124,7 @@
 
 bool Path::contains(const FloatPoint &point, WindRule rule) const
 {
-    if (!boundingRect().contains(point))
+    if (!fastBoundingRect().contains(point))
         return false;
 
     // CGPathContainsPoint returns false for non-closed paths, as a work-around, we copy and close the path first.  Radar 4758998 asks for a better CG API to use
@@ -163,9 +163,20 @@
 
 FloatRect Path::boundingRect() const
 {
+    // CGPathGetBoundingBox includes the path's control points, CGPathGetPathBoundingBox
+    // does not, but only exists on 10.6 and above.
+#if !defined(BUILDING_ON_LEOPARD)
+    return CGPathGetPathBoundingBox(m_path);
+#else
     return CGPathGetBoundingBox(m_path);
+#endif
 }
 
+FloatRect Path::fastBoundingRect() const
+{
+    return CGPathGetBoundingBox(m_path);
+}
+
 FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const
 {
     CGContextRef context = scratchContext();

Modified: trunk/Source/WebCore/rendering/RenderObject.h (99459 => 99460)


--- trunk/Source/WebCore/rendering/RenderObject.h	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/rendering/RenderObject.h	2011-11-07 20:40:24 UTC (rev 99460)
@@ -421,7 +421,7 @@
     virtual void setNeedsBoundariesUpdate();
 
     // Per SVG 1.1 objectBoundingBox ignores clipping, masking, filter effects, opacity and stroke-width.
-    // This is used for all computation of objectBoundingBox relative units and by SVGLocateable::getBBox().
+    // This is used for all computation of objectBoundingBox relative units and by SVGLocatable::getBBox().
     // NOTE: Markers are not specifically ignored here by SVG 1.1 spec, but we ignore them
     // since stroke-width is ignored (and marker size can depend on stroke-width).
     // objectBoundingBox is returned local coordinates.

Modified: trunk/Source/WebCore/rendering/svg/RenderSVGPath.cpp (99459 => 99460)


--- trunk/Source/WebCore/rendering/svg/RenderSVGPath.cpp	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGPath.cpp	2011-11-07 20:40:24 UTC (rev 99460)
@@ -357,7 +357,7 @@
     }
 
     // Cache _unclipped_ fill bounding box, used for calculations in resources
-    m_fillBoundingBox = m_path.boundingRect();
+    m_fillBoundingBox = m_path.fastBoundingRect();
 
     // Spec(11.4): Any zero length subpath shall not be stroked if the ‘stroke-linecap’ property has a value of butt
     // but shall be stroked if the ‘stroke-linecap’ property has a value of round or square

Modified: trunk/Source/WebCore/svg/SVGPathElement.cpp (99459 => 99460)


--- trunk/Source/WebCore/svg/SVGPathElement.cpp	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/svg/SVGPathElement.cpp	2011-11-07 20:40:24 UTC (rev 99460)
@@ -76,6 +76,7 @@
     : SVGStyledTransformableElement(tagName, document)
     , m_pathByteStream(SVGPathByteStream::create())
     , m_pathSegList(PathSegUnalteredRole)
+    , m_cachedBBoxRectIsValid(false)
 {
     ASSERT(hasTagName(SVGNames::pathTag));
     registerAnimatedPropertiesForSVGPathElement();
@@ -266,6 +267,7 @@
             SVGPathParserFactory* factory = SVGPathParserFactory::self();
             factory->buildSVGPathSegListFromByteStream(m_pathByteStream.get(), this, newList, UnalteredParsing);
             m_pathSegList.value = newList;
+            m_cachedBBoxRectIsValid = false;
         }
 
         if (renderer)
@@ -350,6 +352,8 @@
     }
 
     invalidateSVGAttributes();
+    
+    m_cachedBBoxRectIsValid = false;
 
     RenderSVGPath* renderer = static_cast<RenderSVGPath*>(this->renderer());
     if (!renderer)
@@ -359,6 +363,25 @@
     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
 }
 
+FloatRect SVGPathElement::getBBox(StyleUpdateStrategy styleUpdateStrategy)
+{
+    if (styleUpdateStrategy == AllowStyleUpdate)
+        this->document()->updateLayoutIgnorePendingStylesheets();
+
+    RenderSVGPath* renderer = static_cast<RenderSVGPath*>(this->renderer());
+
+    // FIXME: Eventually we should support getBBox for detached elements.
+    if (!renderer)
+        return FloatRect();
+
+    if (!m_cachedBBoxRectIsValid) {
+        m_cachedBBoxRect = renderer->path().boundingRect();
+        m_cachedBBoxRectIsValid = true;
+    }
+    
+    return m_cachedBBoxRect;
 }
 
+}
+
 #endif // ENABLE(SVG)

Modified: trunk/Source/WebCore/svg/SVGPathElement.h (99459 => 99460)


--- trunk/Source/WebCore/svg/SVGPathElement.h	2011-11-07 20:37:06 UTC (rev 99459)
+++ trunk/Source/WebCore/svg/SVGPathElement.h	2011-11-07 20:40:24 UTC (rev 99460)
@@ -97,6 +97,8 @@
 
     static const SVGPropertyInfo* dPropertyInfo();
 
+    virtual FloatRect getBBox(StyleUpdateStrategy = AllowStyleUpdate);
+
 private:
     SVGPathElement(const QualifiedName&, Document*);
 
@@ -126,6 +128,8 @@
     OwnPtr<SVGPathByteStream> m_pathByteStream;
     mutable SVGSynchronizableAnimatedProperty<SVGPathSegList> m_pathSegList;
     RefPtr<SVGAnimatedPathSegListPropertyTearOff> m_animatablePathSegList;
+    FloatRect m_cachedBBoxRect;
+    bool m_cachedBBoxRectIsValid;                       
 };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to