Bug 16629: <canvas> does not support isPointInPath()
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Jan 2008 07:04:56 +0000 (07:04 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Jan 2008 07:04:56 +0000 (07:04 +0000)
Reviewed by Sam Weinig.

Relatively trivial change to implement pointInPath and add
it to the bindings.  Most of this patch is the addition of
GraphicsContext::getCTM() by pulling the various platform
implementations from CanvasRenderingContext2D::willDraw

Test: fast/canvas/pointInPath.html

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/canvas/pointInPath-expected.txt [new file with mode: 0644]
LayoutTests/fast/canvas/pointInPath.html [new file with mode: 0644]
LayoutTests/fast/canvas/pointInPath.js [new file with mode: 0644]
WebCore/ChangeLog
WebCore/html/CanvasRenderingContext2D.cpp
WebCore/html/CanvasRenderingContext2D.h
WebCore/html/CanvasRenderingContext2D.idl
WebCore/platform/graphics/AffineTransform.cpp
WebCore/platform/graphics/AffineTransform.h
WebCore/platform/graphics/GraphicsContext.h
WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
WebCore/platform/graphics/cg/GraphicsContextCG.cpp
WebCore/platform/graphics/qt/GraphicsContextQt.cpp

index 6f47a8e..ee97683 100644 (file)
@@ -1,3 +1,13 @@
+2008-01-27  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        Test case for canvas.pointInPath
+
+        * fast/canvas/pointInPath-expected.txt: Added.
+        * fast/canvas/pointInPath.html: Added.
+        * fast/canvas/pointInPath.js: Added.
+
 2008-01-27  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin.
diff --git a/LayoutTests/fast/canvas/pointInPath-expected.txt b/LayoutTests/fast/canvas/pointInPath-expected.txt
new file mode 100644 (file)
index 0000000..a95f045
--- /dev/null
@@ -0,0 +1,39 @@
+Series of tests for Canvas.isPointInPath
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Rectangle at (0,0) 20x20
+PASS ctx.isPointInPath(5, 5) is true
+PASS ctx.isPointInPath(10, 10) is true
+PASS ctx.isPointInPath(20, 20) is true
+PASS ctx.isPointInPath(30, 30) is false
+PASS ctx.isPointInPath(-1, 10) is false
+PASS ctx.isPointInPath(10, -1) is false
+Translate context (10,10)
+PASS ctx.isPointInPath(5, 5) is true
+PASS ctx.isPointInPath(10, 10) is true
+PASS ctx.isPointInPath(20, 20) is true
+PASS ctx.isPointInPath(30, 30) is false
+PASS ctx.isPointInPath(-1, 10) is false
+PASS ctx.isPointInPath(10, -1) is false
+Collapse ctm to non-invertible matrix
+PASS ctx.isPointInPath(5, 5) is false
+PASS ctx.isPointInPath(10, 10) is false
+PASS ctx.isPointInPath(20, 20) is false
+PASS ctx.isPointInPath(30, 30) is false
+PASS ctx.isPointInPath(-1, 10) is false
+PASS ctx.isPointInPath(10, -1) is false
+Resetting context to a clean state
+Translate context (10,10)
+Rectangle at (0,0) 20x20
+PASS ctx.isPointInPath(5, 5) is false
+PASS ctx.isPointInPath(10, 10) is true
+PASS ctx.isPointInPath(20, 20) is true
+PASS ctx.isPointInPath(30, 30) is true
+PASS ctx.isPointInPath(-1, 10) is false
+PASS ctx.isPointInPath(10, -1) is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/canvas/pointInPath.html b/LayoutTests/fast/canvas/pointInPath.html
new file mode 100644 (file)
index 0000000..5dd2b07
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../js/resources/js-test-style.css">
+<script src="../js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<canvas id="canvas"></canvas>
+<script src="pointInPath.js"></script>
+<script src="../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/canvas/pointInPath.js b/LayoutTests/fast/canvas/pointInPath.js
new file mode 100644 (file)
index 0000000..1629989
--- /dev/null
@@ -0,0 +1,43 @@
+description("Series of tests for Canvas.isPointInPath");
+
+ctx = document.getElementById("canvas").getContext("2d");
+ctx.save();
+debug("Rectangle at (0,0) 20x20");
+ctx.rect(0, 0, 20, 20);
+shouldBe("ctx.isPointInPath(5, 5)", "true");
+shouldBe("ctx.isPointInPath(10, 10)", "true");
+shouldBe("ctx.isPointInPath(20, 20)", "true");
+shouldBe("ctx.isPointInPath(30, 30)", "false");
+shouldBe("ctx.isPointInPath(-1, 10)", "false");
+shouldBe("ctx.isPointInPath(10, -1)", "false");
+debug("Translate context (10,10)");
+ctx.translate(10,10);
+shouldBe("ctx.isPointInPath(5, 5)", "true");
+shouldBe("ctx.isPointInPath(10, 10)", "true");
+shouldBe("ctx.isPointInPath(20, 20)", "true");
+shouldBe("ctx.isPointInPath(30, 30)", "false");
+shouldBe("ctx.isPointInPath(-1, 10)", "false");
+shouldBe("ctx.isPointInPath(10, -1)", "false");
+debug("Collapse ctm to non-invertible matrix");
+ctx.scale(0,0);
+shouldBe("ctx.isPointInPath(5, 5)", "false");
+shouldBe("ctx.isPointInPath(10, 10)", "false");
+shouldBe("ctx.isPointInPath(20, 20)", "false");
+shouldBe("ctx.isPointInPath(30, 30)", "false");
+shouldBe("ctx.isPointInPath(-1, 10)", "false");
+shouldBe("ctx.isPointInPath(10, -1)", "false");
+debug("Resetting context to a clean state");
+ctx.restore();
+ctx.beginPath();
+debug("Translate context (10,10)");
+ctx.translate(10,10);
+debug("Rectangle at (0,0) 20x20");
+ctx.rect(0, 0, 20, 20);
+shouldBe("ctx.isPointInPath(5, 5)", "false");
+shouldBe("ctx.isPointInPath(10, 10)", "true");
+shouldBe("ctx.isPointInPath(20, 20)", "true");
+shouldBe("ctx.isPointInPath(30, 30)", "true");
+shouldBe("ctx.isPointInPath(-1, 10)", "false");
+shouldBe("ctx.isPointInPath(10, -1)", "false");
+
+var successfullyParsed = true;
index 96954d2..eb75065 100644 (file)
@@ -1,3 +1,33 @@
+2008-01-27  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        Bug 16629: <canvas> does not support isPointInPath()
+
+        Relatively trivial change to implement pointInPath and add
+        it to the bindings.  Most of this patch is the addition of
+        GraphicsContext::getCTM() by pulling the various platform
+        implementations from CanvasRenderingContext2D::willDraw
+
+        Test: fast/canvas/pointInPath.html
+
+        * html/CanvasRenderingContext2D.cpp:
+        (WebCore::CanvasRenderingContext2D::isPointInPath):
+        (WebCore::CanvasRenderingContext2D::willDraw):
+        * html/CanvasRenderingContext2D.h:
+        * html/CanvasRenderingContext2D.idl:
+        * platform/graphics/AffineTransform.cpp:
+        (WebCore::AffineTransform::mapPoint):
+          Support mapping of FloatRects
+        * platform/graphics/AffineTransform.h:
+        * platform/graphics/GraphicsContext.h:
+        * platform/graphics/cairo/GraphicsContextCairo.cpp:
+        (WebCore::GraphicsContext::getCTM):
+        * platform/graphics/cg/GraphicsContextCG.cpp:
+        (WebCore::GraphicsContext::getCTM):
+        * platform/graphics/qt/GraphicsContextQt.cpp:
+        (WebCore::GraphicsContext::getCTM):
+
 2008-01-27  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin.
index dc857e6..b698be3 100644 (file)
@@ -575,6 +575,21 @@ void CanvasRenderingContext2D::clip()
     clearPathForDashboardBackwardCompatibilityMode();
 }
 
+bool CanvasRenderingContext2D::isPointInPath(const float x, const float y)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return false;
+    FloatPoint point(x, y);
+    // We have to invert the current transform to ensure we correctly handle the
+    // transforms applied to the current path.
+    AffineTransform ctm = c->getCTM();
+    if (!ctm.isInvertible())
+        return false;
+    FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
+    return state().m_path.contains(transformedPoint);
+}
+
 void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height, ExceptionCode& ec)
 {
     ec = 0;
@@ -1080,25 +1095,8 @@ void CanvasRenderingContext2D::willDraw(const FloatRect& r)
     GraphicsContext* c = drawingContext();
     if (!c)
         return;
-    
-    AffineTransform transform;
-#if PLATFORM(CG)
-    transform = CGContextGetCTM(c->platformContext());
-#elif PLATFORM(CAIRO)
-    cairo_t* cr = c->platformContext();
-    cairo_matrix_t m;
-    cairo_get_matrix(cr, &m);
-    transform = m;
-#elif PLATFORM(QT)
-    transform = c->platformContext()->combinedMatrix();
-#else
-    notImplemented();
-    FloatRect completeBounds(0, 0, m_canvas->width(), m_canvas->height());
-    m_canvas->willDraw(completeBounds);
-    return;
-#endif
-    
-    m_canvas->willDraw(transform.mapRect(r));
+
+    m_canvas->willDraw(c->getCTM().mapRect(r));
 }
 
 GraphicsContext* CanvasRenderingContext2D::drawingContext() const
index d26be4e..1de3549 100644 (file)
@@ -126,6 +126,8 @@ namespace WebCore {
         void stroke();
         void clip();
 
+        bool isPointInPath(const float x, const float y);
+
         void clearRect(float x, float y, float width, float height, ExceptionCode&);
         void fillRect(float x, float y, float width, float height, ExceptionCode&);
         void strokeRect(float x, float y, float width, float height, ExceptionCode&);
index c9da2c2..ff9213e 100644 (file)
@@ -77,6 +77,7 @@ module html {
         void fill();
         void stroke();
         void clip();
+        boolean isPointInPath(in float x, in float y);
 
         // other
 
index 55f17d4..664bf28 100644 (file)
@@ -92,4 +92,12 @@ IntPoint AffineTransform::mapPoint(const IntPoint& point) const
     return IntPoint(lround(x2), lround(y2));
 }
 
+FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
+{
+    double x2, y2;
+    map(point.x(), point.y(), &x2, &y2);
+
+    return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
+}
+
 }
index 0fba1df..2ba4ce7 100644 (file)
@@ -41,6 +41,7 @@ namespace WebCore {
 
 class IntPoint;
 class IntRect;
+class FloatPoint;
 class FloatRect;
 
 class AffineTransform {
@@ -60,6 +61,7 @@ public:
     void setMatrix(double a, double b, double c, double d, double e, double f);
     void map(double x, double y, double *x2, double *y2) const;
     IntPoint mapPoint(const IntPoint&) const;
+    FloatPoint mapPoint(const FloatPoint&) const;
     IntRect mapRect(const IntRect&) const;
     FloatRect mapRect(const FloatRect&) const;
     
index 25a6efc..e4a98e4 100644 (file)
@@ -216,6 +216,7 @@ namespace WebCore {
         void setURLForRect(const KURL&, const IntRect&);
 
         void concatCTM(const AffineTransform&);
+        AffineTransform getCTM() const;
 
         void setUseAntialiasing(bool = true);
 
index e2ef67c..51781b7 100644 (file)
@@ -128,6 +128,14 @@ GraphicsContext::~GraphicsContext()
     delete m_data;
 }
 
+AffineTransform GraphicsContext::getCTM() const
+{
+    cairo_t* cr = platformContext();
+    cairo_matrix_t m;
+    cairo_get_matrix(cr, &m);
+    return m;
+}
+
 cairo_t* GraphicsContext::platformContext() const
 {
     return m_data->cr;
index 177d727..eb967b9 100644 (file)
@@ -682,6 +682,11 @@ void GraphicsContext::concatCTM(const AffineTransform& transform)
     m_data->m_userToDeviceTransformKnownToBeIdentity = false;
 }
 
+AffineTransform GraphicsContext::getCTM() const
+{
+    return CGContextGetCTM(platformContext());
+}
+
 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
 {
     // It is not enough just to round to pixels in device space. The rotation part of the 
index b23bf0e..cf097c8 100644 (file)
@@ -259,6 +259,11 @@ PlatformGraphicsContext* GraphicsContext::platformContext() const
     return m_data->p();
 }
 
+AffineTransform GraphicsContext::getCTM() const
+{
+    return platformContext()->combinedMatrix();
+}
+
 void GraphicsContext::savePlatformState()
 {
     m_data->p()->save();