Bug 17173: HTML5 Canvas API requires us to ignore certain operations
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Apr 2008 07:41:28 +0000 (07:41 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Apr 2008 07:41:28 +0000 (07:41 +0000)
<https://bugs.webkit.org/show_bug.cgi?id=17173>

Reviewed by Maciej

This fixes the semantics of a number of Canvas functions to match
the new HTML5 non-throwing semantics.

Test: fast/canvas/canvas-path-with-inf-nan-dimensions.html

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

LayoutTests/ChangeLog
LayoutTests/fast/canvas/canvas-path-with-inf-nan-dimensions.html [new file with mode: 0644]
LayoutTests/fast/canvas/canvas-with-incorrect-args-expected.txt
LayoutTests/fast/canvas/canvas-with-incorrect-args.html
WebCore/ChangeLog
WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp
WebCore/html/CanvasRenderingContext2D.cpp
WebCore/html/CanvasRenderingContext2D.h
WebCore/html/CanvasRenderingContext2D.idl

index cc22f7b..8cdf290 100644 (file)
@@ -1,3 +1,17 @@
+2008-04-27  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Maciej.
+
+        Bug 17173: HTML5 Canvas API requires us to ignore certain operations
+        <https://bugs.webkit.org/show_bug.cgi?id=17173>
+
+        Correct old test case now that undefined behaviour is defined.  Add
+        additional tests for non-path related cases that are also now defined.
+
+        * fast/canvas/canvas-path-with-inf-nan-dimensions.html: Added.
+        * fast/canvas/canvas-with-incorrect-args-expected.txt:
+        * fast/canvas/canvas-with-incorrect-args.html:
+
 2008-04-27  Rob Buis  <buis@kde.org>
 
         Reviewed by Adele.
diff --git a/LayoutTests/fast/canvas/canvas-path-with-inf-nan-dimensions.html b/LayoutTests/fast/canvas/canvas-path-with-inf-nan-dimensions.html
new file mode 100644 (file)
index 0000000..cfb9294
--- /dev/null
@@ -0,0 +1,98 @@
+<canvas width="200" height="200" id="canvas">FAIL: no canvas support</canvas>
+<div id="log"></div>
+<script>
+if (window.layoutTestController)
+    layoutTestController.dumpAsText();
+
+var canvas = document.getElementById("canvas").getContext("2d");
+//four tests
+// 1. Infinite dimensions to fillRect
+canvas.fillStyle = "green";
+canvas.fillRect(0, 0, 100, 100);
+canvas.fillStyle = "red";
+try {
+    canvas.fillRect(0, 0, Infinity, Infinity);
+} catch (e) {
+    canvas.fillRect(0, 0, 100, 100);
+}
+
+// 2. Infinite dimensions to rect
+canvas.fillStyle = "green";
+canvas.fillRect(100, 0, 100, 100);
+canvas.fillStyle = "red";
+try {
+    canvas.rect(100, 0, Infinity, Infinity);
+    canvas.fill();
+} catch (e) {
+    canvas.fillRect(100, 0, 100, 100);
+}
+
+// 3. Infinite argument to moveTo
+canvas.translate(0, 100);
+canvas.fillStyle = "red";
+canvas.fillRect(0, 0, 100, 100);
+canvas.fillStyle = "green";
+try {
+    canvas.beginPath();
+    canvas.moveTo(Infinity, Infinity);
+    canvas.rect(0, 0, 100, 100);
+    canvas.fill();
+} catch (e) {
+    alert(e);
+}
+
+// 4. Infinite argument to lineTo
+canvas.translate(100, 0);
+canvas.fillStyle = "red";
+canvas.fillRect(0, 0, 100, 100);
+canvas.fillStyle = "green";
+try {
+    canvas.beginPath();
+    canvas.moveTo(0,0);
+    canvas.lineTo(100, 0);
+    canvas.lineTo(100, 100);
+    canvas.lineTo(0, 100);
+    canvas.lineTo(Infinity, 100);
+    canvas.fill();
+} catch (e) {
+}
+
+function log(msg){
+    document.getElementById("log").innerHTML += msg + "<br/>";
+}
+
+function dataToArray(data) {
+    var result = new Array(data.length)
+    for (var i = 0; i < data.length; i++)
+        result[i] = data[i];
+    return result;
+}
+
+function getPixel(ctx, x, y) {
+    var data = ctx.getImageData(x,y,1,1);
+    if (!data) // getImageData failed, which should never happen
+        return [-1,-1,-1,-1];
+    return dataToArray(data.data);
+}
+
+function pixelShouldBe(ctx, x, y, colour) {
+    var ctxColour = getPixel(ctx, x, y);
+    var correct = true;
+    for (var i = 0; i < 4; i++)
+        if (colour[i] != ctxColour[i]) {
+            correct = false;
+            break;
+        }
+    if (correct)
+        log("PASS: pixel at ("+[x,y]+") was ["+colour+"]");
+    else
+        log("FAIL: pixel at ("+[x,y]+") was ["+ctxColour+"], expected ["+colour+"]");
+}
+
+var points = [25, 50, 75, 125, 150, 175];
+for (var x = 0; x < points.length; x++) {
+    for (var y = 0; y < points.length; y++) {
+        pixelShouldBe(canvas, points[x], points[y], [0, 128, 0, 255]);
+    }
+}
+</script>
index cafb28c..f03057e 100644 (file)
@@ -1,37 +1,59 @@
 
 This tests the behaviour of a number of the DOM Canvas drawing methods when
-given 0, inf, or NaN as parameters.
-A number of the Canvas methods do not have defined behaviour when given inf
-or nan and so we use UNDEFINED to indicate this.
+given 0, Infinity, or NaN as parameters.
 
 PASS called fillRect 0*0 fillRect without throwing an exception.
-UNDEFINED called fillRect with inf*inf fillRect without throwing an exception.
-UNDEFINED threw exception code 1 on nan*nan fillRect.
+PASS called fillRect with Infinity*Infinity fillRect without throwing an exception.
+PASS did not throw exception with NaN*NaN fillRect.
 PASS called clearRect 0*0 clearRect without throwing an exception.
-UNDEFINED called clearRect with inf*inf clearRect without throwing an exception.
-UNDEFINED threw exception code 1 on nan*nan clearRect.
+PASS called clearRect with Infinity*Infinity clearRect without throwing an exception.
+PASS did not throw exception with NaN*NaN clearRect.
 PASS called rect 0*0 rect without throwing an exception.
-UNDEFINED called rect with inf*inf rect without throwing an exception.
-UNDEFINED threw exception code 1 on nan*nan rect.
+PASS called rect with Infinity*Infinity rect without throwing an exception.
+PASS did not throw exception with NaN*NaN rect.
 PASS called fill with an empty path without throwing an exception.
 PASS did not throw exception on arc with zero-length radius
 PASS threw exception code 1 on arc with negative-length radius
-UNDEFINED did not throw exception on arc with infinite radius
-UNDEFINED threw exception code 1 on arc with nan-length radius
-PASS threw exception code 1 on arcTo with zero-length radius
+PASS did not throw exception on arc with infinite radius
+PASS did not throw exception on arc with NaN-length radius
+PASS did not throw exception on arcTo with zero-length radius
 PASS threw exception code 1 on arcTo with negative-length radius
-UNDEFINED did not throw exception on arcTo with infinite radius
-UNDEFINED threw exception code 1 on arcTo with nan-length radius
-UNDEFINED did not throw exception on lineTo(inf, inf).
-UNDEFINED did not throw exception on lineTo(nan, nan).
-UNDEFINED did not throw exception on quadraticCurveTo(20, 20, inf, inf).
-UNDEFINED did not throw exception on quadraticCurveTo(inf, inf, 20, 20).
-UNDEFINED did not throw exception on quadraticCurveTo(20, 20, nan, nan).
-UNDEFINED did not throw exception on quadraticCurveTo(nan, nan, 20, 20).
-UNDEFINED did not throw exception on bezierCurveTo(20, 20, 30, 30, inf, inf).
-UNDEFINED did not throw exception on bezierCurveTo(20, 20, inf, inf, 30, 30).
-UNDEFINED did not throw exception on bezierCurveTo(inf, inf, 20, 20, 30, 30).
-UNDEFINED did not throw exception on bezierCurveTo(20, 20, 30, 30, nan, nan).
-UNDEFINED did not throw exception on bezierCurveTo(20, 20, nan, nan, 30, 30).
-UNDEFINED did not throw exception on bezierCurveTo(nan, nan, 20, 20, 30, 30).
+PASS did not throw exception on arcTo with infinite radius
+PASS did not throw exception on arcTo with NaN-length radius
+PASS did not throw exception on lineTo(Infinity, Infinity).
+PASS did not throw exception on lineTo(Infinity, 20).
+PASS did not throw exception on lineTo(20, Infinity).
+PASS did not throw exception on lineTo(NaN, NaN).
+PASS did not throw exception on lineTo(20, NaN).
+PASS did not throw exception on lineTo(NaN, 20).
+PASS did not throw exception on quadraticCurveTo(20, 20, Infinity, Infinity).
+PASS did not throw exception on quadraticCurveTo(Infinity, Infinity, 20, 20).
+PASS did not throw exception on quadraticCurveTo(Infinity, 20, 20, 20).
+PASS did not throw exception on quadraticCurveTo(20, Infinity, 20, 20).
+PASS did not throw exception on quadraticCurveTo(20, 20, Infinity, 20).
+PASS did not throw exception on quadraticCurveTo(20, 20, 20, Infinity).
+PASS did not throw exception on quadraticCurveTo(20, 20, NaN, NaN).
+PASS did not throw exception on quadraticCurveTo(NaN, NaN, 20, 20).
+PASS did not throw exception on quadraticCurveTo(NaN, 20, 20, 20).
+PASS did not throw exception on quadraticCurveTo(20, NaN, 20, 20).
+PASS did not throw exception on quadraticCurveTo(20, 20, Nan, 20).
+PASS did not throw exception on quadraticCurveTo(20, 20, 20, NaN).
+PASS did not throw exception on bezierCurveTo(20, 20, 30, 30, Infinity, Infinity).
+PASS did not throw exception on bezierCurveTo(20, 20, 30, 30, 30, Infinity).
+PASS did not throw exception on bezierCurveTo(20, 20, 30, 30, Infinity, 30).
+PASS did not throw exception on bezierCurveTo(20, 20, Infinity, Infinity, 30, 30).
+PASS did not throw exception on bezierCurveTo(20, 20, 30, Infinity, 30, 30).
+PASS did not throw exception on bezierCurveTo(20, 20, Infinity, 30, 30, 30).
+PASS did not throw exception on bezierCurveTo(Infinity, Infinity, 20, 20, 30, 30).
+PASS did not throw exception on bezierCurveTo(30, Infinity, 20, 20, 30, 30).
+PASS did not throw exception on bezierCurveTo(Infinity, 30, 20, 20, 30, 30).
+PASS did not throw exception on bezierCurveTo(20, 20, 30, 30, NaN, NaN).
+PASS did not throw exception on bezierCurveTo(20, 20, 30, 30, 0, NaN).
+PASS did not throw exception on bezierCurveTo(20, 20, 30, 30, NaN, 0).
+PASS did not throw exception on bezierCurveTo(20, 20, NaN, NaN, 30, 30).
+PASS did not throw exception on bezierCurveTo(20, 20, 30, NaN, 30, 30).
+PASS did not throw exception on bezierCurveTo(20, 20, NaN, 30, 30, 30).
+PASS did not throw exception on bezierCurveTo(NaN, NaN, 20, 20, 30, 30).
+PASS did not throw exception on bezierCurveTo(20, NaN, 20, 20, 30, 30).
+PASS did not throw exception on bezierCurveTo(NaN, 20, 20, 20, 30, 30).
 
index 1edf49a..1f808b1 100644 (file)
@@ -3,7 +3,6 @@
 <style>
 .fail { color: red; font-weight: bold;}
 .pass { color: green; font-weight: bold;}
-.undefined { color: blue; font-weight: bold;}
 </style>
 <script type="text/javascript">
 failed = false;
@@ -23,10 +22,6 @@ function fail(msg) {
     failed = true;
 }
 
-function undefined(msg) {
-    debug('<span class="undefined">UNDEFINED</span> ' + msg + '</span>');
-}
-
 function runTest() {
     var canvas = document.getElementById("test");
     var context = canvas.getContext("2d");
@@ -40,15 +35,15 @@ function runTest() {
     }
     try {
         context.fillRect(0, 0, 0.0/1.0, 0.0/1.0);
-        undefined("called fillRect with inf*inf fillRect without throwing an exception.");
+        pass("called fillRect with Infinity*Infinity fillRect without throwing an exception.");
     } catch (e) {
-        undefined("threw exception code " + e.code + " with inf*inf fillRect");       
+        fail("threw exception code " + e.code + " with Infinity*Infinity fillRect");       
     }
     try {
-        context.fillRect(0, 0, 0.0/0.0, 0.0/0.0);
-        undefined("did not throw exception with nan*nan fillRect.");
+        context.fillRect(0, 0, NaN, NaN);
+        pass("did not throw exception with NaN*NaN fillRect.");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on nan*nan fillRect.");       
+        fail("threw exception code " + e.code + " on NaN*NaN fillRect.");       
     }
     try {
         context.clearRect(0, 0, 0, 0);
@@ -58,15 +53,15 @@ function runTest() {
     }
     try {
         context.clearRect(0, 0, 0.0/1.0, 0.0/1.0);
-        undefined("called clearRect with inf*inf clearRect without throwing an exception.");
+        pass("called clearRect with Infinity*Infinity clearRect without throwing an exception.");
     } catch (e) {
-        undefined("threw exception code " + e.code + " with inf*inf clearRect.");       
+        fail("threw exception code " + e.code + " with Infinity*Infinity clearRect.");       
     }
     try {
-        context.clearRect(0, 0, 0.0/0.0, 0.0/0.0);
-        undefined("did not throw exception with nan*nan clearRect.");
+        context.clearRect(0, 0, NaN, NaN);
+        pass("did not throw exception with NaN*NaN clearRect.");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on nan*nan clearRect.");       
+        fail("threw exception code " + e.code + " on NaN*NaN clearRect.");       
     }
     try {
         context.rect(0, 0, 0, 0);
@@ -76,15 +71,15 @@ function runTest() {
     }
     try {
         context.rect(0, 0, 0.0/1.0, 0.0/1.0);
-        undefined("called rect with inf*inf rect without throwing an exception.");
+        pass("called rect with Infinity*Infinity rect without throwing an exception.");
     } catch (e) {
-        undefined("threw exception code " + e.code + " with inf*inf rect.");       
+        fail("threw exception code " + e.code + " with Infinity*Infinity rect.");       
     }
     try {
-        context.rect(0, 0, 0.0/0.0, 0.0/0.0);
-        undefined("did not throw exception with nan*nan rect.");
+        context.rect(0, 0, NaN, NaN);
+        pass("did not throw exception with NaN*NaN rect.");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on nan*nan rect.");       
+        fail("threw exception code " + e.code + " on NaN*NaN rect.");       
     }
     try {
         context.fill();
@@ -105,24 +100,24 @@ function runTest() {
         pass("threw exception code " + e.code + " on arc with negative-length radius");    
     }
     try {
-        context.arc(2, 2, 1.0/0.0, 0, 90, true);
-        undefined("did not throw exception on arc with infinite radius");
+        context.arc(2, 2, Infinity, 0, 90, true);
+        pass("did not throw exception on arc with infinite radius");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on arc with infinite radius");    
+        fail("threw exception code " + e.code + " on arc with infinite radius");    
     }
     try {
-        context.arc(2, 2, 0.0/0.0, 0, 90, true);
-        undefined("did not throw exception on arc with nan-length radius");
+        context.arc(2, 2, NaN, 0, 90, true);
+        pass("did not throw exception on arc with NaN-length radius");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on arc with nan-length radius");    
+        fail("threw exception code " + e.code + " on arc with NaN-length radius");    
     }
     context.beginPath();
     try {
         context.moveTo(10, 10);
         context.arcTo(2, 2, 4, 4, 0);
-        fail("did not throw exception on arcTo with zero-length radius");
+        pass("did not throw exception on arcTo with zero-length radius");
     } catch (e) {
-        pass("threw exception code " + e.code + " on arcTo with zero-length radius");    
+        fail("threw exception code " + e.code + " on arcTo with zero-length radius");    
     }
     context.closePath();
     context.beginPath();
@@ -137,127 +132,343 @@ function runTest() {
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.arcTo(2, 2, 4, 4, 1.0/0.0);
-        undefined("did not throw exception on arcTo with infinite radius");
+        context.arcTo(2, 2, 4, 4, Infinity);
+        pass("did not throw exception on arcTo with infinite radius");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on arcTo with infinite radius");    
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.arcTo(2, 2, 4, 4, NaN);
+        pass("did not throw exception on arcTo with NaN-length radius");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on arcTo with NaN-length radius");    
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.lineTo(Infinity, Infinity);
+        pass("did not throw exception on lineTo(Infinity, Infinity).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on lineTo(Infinity, Infinity).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.lineTo(Infinity, 20);
+        pass("did not throw exception on lineTo(Infinity, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on lineTo(Infinity, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.lineTo(20, Infinity);
+        pass("did not throw exception on lineTo(20, Infinity).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on lineTo(20, Infinity).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.lineTo(NaN, NaN);
+        pass("did not throw exception on lineTo(NaN, NaN).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on lineTo(NaN, NaN).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.lineTo(20, NaN);
+        pass("did not throw exception on lineTo(20, NaN).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on lineTo(20, NaN).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.lineTo(NaN, 20);
+        pass("did not throw exception on lineTo(NaN, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on lineTo(NaN, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(20, 20, Infinity, Infinity);
+        pass("did not throw exception on quadraticCurveTo(20, 20, Infinity, Infinity).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(20, 20, Infinity, Infinity).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(Infinity, Infinity, 20, 20);
+        pass("did not throw exception on quadraticCurveTo(Infinity, Infinity, 20, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(Infinity, Infinity, 20, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(Infinity, 20, 20, 20);
+        pass("did not throw exception on quadraticCurveTo(Infinity, 20, 20, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(Infinity, 20, 20, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(20, Infinity, 20, 20);
+        pass("did not throw exception on quadraticCurveTo(20, Infinity, 20, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(20, Infinity, 20, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(20, 20, Infinity, 20);
+        pass("did not throw exception on quadraticCurveTo(20, 20, Infinity, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(20, 20, Infinity, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(20, 20, 20, Infinity);
+        pass("did not throw exception on quadraticCurveTo(20, 20, 20, Infinity).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(20, 20, 20, Infinity).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(20, 20, NaN, NaN);
+        pass("did not throw exception on quadraticCurveTo(20, 20, NaN, NaN).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(20, 20, NaN, NaN).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(NaN, NaN, 20, 20);
+        pass("did not throw exception on quadraticCurveTo(NaN, NaN, 20, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(NaN, NaN, 20, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(NaN, 20, 20, 20);
+        pass("did not throw exception on quadraticCurveTo(NaN, 20, 20, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(NaN, 20, 20, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(20, NaN, 20, 20);
+        pass("did not throw exception on quadraticCurveTo(20, NaN, 20, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(20, NaN, 20, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(20, 20, NaN, 20);
+        pass("did not throw exception on quadraticCurveTo(20, 20, Nan, 20).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(20, 20, NaN, 20).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.quadraticCurveTo(20, 20, 20, NaN);
+        pass("did not throw exception on quadraticCurveTo(20, 20, 20, NaN).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on quadraticCurveTo(20, 20, 20, NaN).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.bezierCurveTo(20, 20, 30, 30, Infinity, Infinity);
+        pass("did not throw exception on bezierCurveTo(20, 20, 30, 30, Infinity, Infinity).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, 30, Infinity, Infinity).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.bezierCurveTo(20, 20, 30, 30, 30, Infinity);
+        pass("did not throw exception on bezierCurveTo(20, 20, 30, 30, 30, Infinity).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, 30, 30, Infinity).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.bezierCurveTo(20, 20, 30, 30, Infinity, 30);
+        pass("did not throw exception on bezierCurveTo(20, 20, 30, 30, Infinity, 30).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, 30, Infinity, 30).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.bezierCurveTo(20, 20, Infinity, Infinity, 30, 30);
+        pass("did not throw exception on bezierCurveTo(20, 20, Infinity, Infinity, 30, 30).");
+    } catch (e) {
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, Infinity, Infinity, 30, 30).");       
+    }
+    context.closePath();
+    context.beginPath();
+    try {
+        context.moveTo(10, 10);
+        context.bezierCurveTo(20, 20, 30, Infinity, 30, 30);
+        pass("did not throw exception on bezierCurveTo(20, 20, 30, Infinity, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on arcTo with infinite radius");    
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, Infinity, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.arcTo(2, 2, 4, 4, 0.0/0.0);
-        undefined("did not throw exception on arcTo with nan-length radius");
+        context.bezierCurveTo(20, 20, Infinity, 30, 30, 30);
+        pass("did not throw exception on bezierCurveTo(20, 20, Infinity, 30, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on arcTo with nan-length radius");    
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, Infinity, 30, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.lineTo(1.0/0.0, 1.0/0.0);
-        undefined("did not throw exception on lineTo(inf, inf).");
+        context.bezierCurveTo(Infinity, Infinity, 20, 20, 30, 30);
+        pass("did not throw exception on bezierCurveTo(Infinity, Infinity, 20, 20, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on lineTo(inf, inf).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(Infinity, Infinity, 20, 20, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.lineTo(0.0/0.0, 0.0/0.0);
-        undefined("did not throw exception on lineTo(nan, nan).");
+        context.bezierCurveTo(30, Infinity, 20, 20, 30, 30);
+        pass("did not throw exception on bezierCurveTo(30, Infinity, 20, 20, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on lineTo(nan, nan).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(30, Infinity, 20, 20, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.quadraticCurveTo(20, 20, 1.0/0.0, 1.0/0.0);
-        undefined("did not throw exception on quadraticCurveTo(20, 20, inf, inf).");
+        context.bezierCurveTo(Infinity, 30, 20, 20, 30, 30);
+        pass("did not throw exception on bezierCurveTo(Infinity, 30, 20, 20, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on quadraticCurveTo(20, 20, inf, inf).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(Infinity, 30, 20, 20, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.quadraticCurveTo(1.0/0.0, 1.0/0.0, 20, 20);
-        undefined("did not throw exception on quadraticCurveTo(inf, inf, 20, 20).");
+        context.bezierCurveTo(20, 20, 30, 30, NaN, NaN);
+        pass("did not throw exception on bezierCurveTo(20, 20, 30, 30, NaN, NaN).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on quadraticCurveTo(inf, inf, 20, 20).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, 30, NaN, NaN).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.quadraticCurveTo(20, 20, 0.0/0.0, 0.0/0.0);
-        undefined("did not throw exception on quadraticCurveTo(20, 20, nan, nan).");
+        context.bezierCurveTo(20, 20, 30, 30, 0, NaN);
+        pass("did not throw exception on bezierCurveTo(20, 20, 30, 30, 0, NaN).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on quadraticCurveTo(20, 20, nan, nan).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, 30, 0, NaN).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.quadraticCurveTo(0.0/0.0, 0.0/0.0, 20, 20);
-        undefined("did not throw exception on quadraticCurveTo(nan, nan, 20, 20).");
+        context.bezierCurveTo(20, 20, 30, 30, NaN, 0);
+        pass("did not throw exception on bezierCurveTo(20, 20, 30, 30, NaN, 0).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on quadraticCurveTo(nan, nan, 20, 20).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, 30, NaN, 0).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.bezierCurveTo(20, 20, 30, 30, 1.0/0.0, 1.0/0.0);
-        undefined("did not throw exception on bezierCurveTo(20, 20, 30, 30, inf, inf).");
+        context.bezierCurveTo(20, 20, NaN, NaN, 30, 30);
+        pass("did not throw exception on bezierCurveTo(20, 20, NaN, NaN, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, 30, inf, inf).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, NaN, NaN, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.bezierCurveTo(20, 20, 1.0/0.0, 1.0/0.0, 30, 30);
-        undefined("did not throw exception on bezierCurveTo(20, 20, inf, inf, 30, 30).");
+        context.bezierCurveTo(20, 20, 30, NaN, 30, 30);
+        pass("did not throw exception on bezierCurveTo(20, 20, 30, NaN, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on bezierCurveTo(20, 20, inf, inf, 30, 30).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, NaN, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.bezierCurveTo(1.0/0.0, 1.0/0.0, 20, 20, 30, 30);
-        undefined("did not throw exception on bezierCurveTo(inf, inf, 20, 20, 30, 30).");
+        context.bezierCurveTo(20, 20, NaN, 30, 30, 30);
+        pass("did not throw exception on bezierCurveTo(20, 20, NaN, 30, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on bezierCurveTo(inf, inf, 20, 20, 30, 30).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, 20, NaN, 30, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.bezierCurveTo(20, 20, 30, 30, 0.0/0.0, 0.0/0.0);
-        undefined("did not throw exception on bezierCurveTo(20, 20, 30, 30, nan, nan).");
+        context.bezierCurveTo(NaN, NaN, 20, 20, 30, 30);
+        pass("did not throw exception on bezierCurveTo(NaN, NaN, 20, 20, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on bezierCurveTo(20, 20, 30, 30, nan, nan).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(NaN, NaN, 20, 20, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.bezierCurveTo(20, 20, 0.0/0.0, 0.0/0.0, 30, 30);
-        undefined("did not throw exception on bezierCurveTo(20, 20, nan, nan, 30, 30).");
+        context.bezierCurveTo(20, NaN, 20, 20, 30, 30);
+        pass("did not throw exception on bezierCurveTo(20, NaN, 20, 20, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on bezierCurveTo(20, 20, nan, nan, 30, 30).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(20, NaN, 20, 20, 30, 30).");       
     }
     context.closePath();
     context.beginPath();
     try {
         context.moveTo(10, 10);
-        context.bezierCurveTo(0.0/0.0, 0.0/0.0, 20, 20, 30, 30);
-        undefined("did not throw exception on bezierCurveTo(nan, nan, 20, 20, 30, 30).");
+        context.bezierCurveTo(NaN, 20, 20, 20, 30, 30);
+        pass("did not throw exception on bezierCurveTo(NaN, 20, 20, 20, 30, 30).");
     } catch (e) {
-        undefined("threw exception code " + e.code + " on bezierCurveTo(nan, nan, 20, 20, 30, 30).");       
+        fail("threw exception code " + e.code + " on bezierCurveTo(NaN, 20, 20, 20, 30, 30).");       
     }
     context.closePath();
 
@@ -266,7 +477,7 @@ function runTest() {
         context.fillRect(0, 0, canvas.width, canvas.height);
     }
 
-    if (layoutTestController)
+    if (window.layoutTestController)
         layoutTestController.dumpAsText();
 }
 </script>
@@ -276,9 +487,7 @@ function runTest() {
 <canvas id="test" width="100" height="100"></canvas><br />
 <pre id="console">
 This tests the behaviour of a number of the DOM Canvas drawing methods when
-given 0, inf, or NaN as parameters.
-A number of the Canvas methods do not have defined behaviour when given inf
-or nan and so we use <span class="undefined">UNDEFINED</span> to indicate this.
+given 0, Infinity, or NaN as parameters.
 
 </pre>
 
index fb4688a..0f3f3f5 100644 (file)
@@ -1,3 +1,32 @@
+2008-04-27  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Maciej.
+
+        Bug 17173: HTML5 Canvas API requires us to ignore certain operations
+        <https://bugs.webkit.org/show_bug.cgi?id=17173>
+
+        This fixes the semantics of a number of Canvas functions to match
+        the new HTML5 non-throwing semantics.
+
+        Test: fast/canvas/canvas-path-with-inf-nan-dimensions.html
+
+        * bindings/js/JSCanvasRenderingContext2DCustom.cpp:
+        (WebCore::JSCanvasRenderingContext2D::strokeRect):
+        * html/CanvasRenderingContext2D.cpp:
+        (WebCore::CanvasRenderingContext2D::moveTo):
+        (WebCore::CanvasRenderingContext2D::lineTo):
+        (WebCore::CanvasRenderingContext2D::quadraticCurveTo):
+        (WebCore::CanvasRenderingContext2D::bezierCurveTo):
+        (WebCore::CanvasRenderingContext2D::arcTo):
+        (WebCore::CanvasRenderingContext2D::arc):
+        (WebCore::validateRectForCanvas):
+        (WebCore::CanvasRenderingContext2D::rect):
+        (WebCore::CanvasRenderingContext2D::clearRect):
+        (WebCore::CanvasRenderingContext2D::fillRect):
+        (WebCore::CanvasRenderingContext2D::strokeRect):
+        * html/CanvasRenderingContext2D.h:
+        * html/CanvasRenderingContext2D.idl:
+
 2008-04-27  Rob Buis  <buis@kde.org>
 
         Reviewed by Adele.
index a3675aa..e952302 100644 (file)
@@ -160,17 +160,15 @@ JSValue* JSCanvasRenderingContext2D::setStrokeColor(ExecState* exec, const List&
 
 JSValue* JSCanvasRenderingContext2D::strokeRect(ExecState* exec, const List& args)
 { 
-    CanvasRenderingContext2D* context = impl();    
-    ExceptionCode ec;
+    CanvasRenderingContext2D* context = impl();
     
     if (args.size() <= 4)
         context->strokeRect(args[0]->toFloat(exec), args[1]->toFloat(exec),
-                            args[2]->toFloat(exec), args[3]->toFloat(exec), ec);
+                            args[2]->toFloat(exec), args[3]->toFloat(exec));
     else
         context->strokeRect(args[0]->toFloat(exec), args[1]->toFloat(exec),
-                            args[2]->toFloat(exec), args[3]->toFloat(exec), args[4]->toFloat(exec), ec);
-    setDOMException(exec, ec);
-    
+                            args[2]->toFloat(exec), args[3]->toFloat(exec), args[4]->toFloat(exec));
+
     return jsUndefined();    
 }
 
index 9102144..4c32c51 100644 (file)
@@ -356,8 +356,8 @@ void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float
         return;
     
     // HTML5 3.14.11.1 -- ignore any calls that pass non-finite numbers
-    if (!isfinite(m11) || !isfinite(m21) || !isfinite(dx) |
-        !isfinite(m12) || !isfinite(m22) || !isfinite(dy))
+    if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) 
+        !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
         return;
     AffineTransform transform(m11, m12, m21, m22, dx, dy);
     c->concatCTM(transform);
@@ -437,51 +437,83 @@ void CanvasRenderingContext2D::closePath()
 
 void CanvasRenderingContext2D::moveTo(float x, float y)
 {
+    if (!isfinite(x) | !isfinite(y))
+        return;
     m_path.moveTo(FloatPoint(x, y));
 }
 
 void CanvasRenderingContext2D::lineTo(float x, float y)
 {
+    if (!isfinite(x) | !isfinite(y))
+        return;
     m_path.addLineTo(FloatPoint(x, y));
 }
 
 void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, float y)
 {
+    if (!isfinite(cpx) | !isfinite(cpy) | !isfinite(x) | !isfinite(y))
+        return;
     m_path.addQuadCurveTo(FloatPoint(cpx, cpy), FloatPoint(x, y));
 }
 
 void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
 {
+    if (!isfinite(cp1x) | !isfinite(cp1y) | !isfinite(cp2x) | !isfinite(cp2y) | !isfinite(x) | !isfinite(y))
+        return;
     m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), FloatPoint(x, y));
 }
 
 void CanvasRenderingContext2D::arcTo(float x0, float y0, float x1, float y1, float r, ExceptionCode& ec)
 {
     ec = 0;
-    if (!(r > 0)) {
+    if (!isfinite(x0) | !isfinite(y0) | !isfinite(x1) | !isfinite(y1) | !isfinite(r))
+        return;
+    
+    if (r < 0) {
         ec = INDEX_SIZE_ERR;
         return;
     }
+    
     m_path.addArcTo(FloatPoint(x0, y0), FloatPoint(x1, y1), r);
 }
 
 void CanvasRenderingContext2D::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec)
 {
     ec = 0;
-    if (!(r >= 0)) {
+    if (!isfinite(x) | !isfinite(y) | !isfinite(r) | !isfinite(sa) | !isfinite(ea))
+        return;
+    
+    if (r < 0) {
         ec = INDEX_SIZE_ERR;
         return;
     }
+    
     m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise);
 }
+    
+static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
+{
+    if (!isfinite(x) | !isfinite(y) | !isfinite(width) | !isfinite(height))
+        return false;
+    
+    if (width < 0) {
+        width = -width;
+        x -= width;
+    }
+    
+    if (height < 0) {
+        height = -height;
+        y -= height;
+    }
+    
+    return true;
+}
 
-void CanvasRenderingContext2D::rect(float x, float y, float width, float height, ExceptionCode& ec)
+void CanvasRenderingContext2D::rect(float x, float y, float width, float height)
 {
-    ec = 0;
-    if (!(width >= 0 && height >= 0)) {
-        ec = INDEX_SIZE_ERR;
+    if (!validateRectForCanvas(x, y, width, height))
         return;
-    }
+        
     m_path.addRect(FloatRect(x, y, width, height));
 }
 
@@ -631,13 +663,10 @@ bool CanvasRenderingContext2D::isPointInPath(const float x, const float y)
     return m_path.contains(transformedPoint);
 }
 
-void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height, ExceptionCode& ec)
+void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
 {
-    ec = 0;
-    if (!(width >= 0 && height >= 0)) {
-        ec = INDEX_SIZE_ERR;
+    if (!validateRectForCanvas(x, y, width, height))
         return;
-    }
     GraphicsContext* c = drawingContext();
     if (!c)
         return;
@@ -646,14 +675,10 @@ void CanvasRenderingContext2D::clearRect(float x, float y, float width, float he
     c->clearRect(rect);
 }
 
-void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height, ExceptionCode& ec)
+void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
 {
-    ec = 0;
-
-    if (!(width >= 0 && height >= 0)) {
-        ec = INDEX_SIZE_ERR;
+    if (!validateRectForCanvas(x, y, width, height))
         return;
-    }
 
     GraphicsContext* c = drawingContext();
     if (!c)
@@ -699,19 +724,20 @@ void CanvasRenderingContext2D::fillRect(float x, float y, float width, float hei
 #endif
 }
 
-void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, ExceptionCode& ec)
+void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height)
 {
-    strokeRect(x, y, width, height, state().m_lineWidth, ec);
+    if (!validateRectForCanvas(x, y, width, height))
+        return;
+    strokeRect(x, y, width, height, state().m_lineWidth);
 }
 
-void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth, ExceptionCode& ec)
+void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth)
 {
-    ec = 0;
-
-    if (!(width >= 0 && height >= 0 && lineWidth >= 0)) {
-        ec = INDEX_SIZE_ERR;
+    if (!validateRectForCanvas(x, y, width, height))
+        return;
+    
+    if (!(lineWidth >= 0))
         return;
-    }
 
     GraphicsContext* c = drawingContext();
     if (!c)
index b45b522..fc18208 100644 (file)
@@ -124,7 +124,7 @@ namespace WebCore {
         void bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y);
         void arcTo(float x0, float y0, float x1, float y1, float radius, ExceptionCode&);
         void arc(float x, float y, float r, float sa, float ea, bool clockwise, ExceptionCode&);
-        void rect(float x, float y, float width, float height, ExceptionCode&);
+        void rect(float x, float y, float width, float height);
 
         void fill();
         void stroke();
@@ -132,10 +132,10 @@ namespace WebCore {
 
         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&);
-        void strokeRect(float x, float y, float width, float height, float lineWidth, ExceptionCode&);
+        void clearRect(float x, float y, float width, float height);
+        void fillRect(float x, float y, float width, float height);
+        void strokeRect(float x, float y, float width, float height);
+        void strokeRect(float x, float y, float width, float height, float lineWidth);
 
         void setShadow(float width, float height, float blur);
         void setShadow(float width, float height, float blur, const String& color);
index 5a16971..281b6c2 100644 (file)
@@ -59,10 +59,8 @@ module html {
         attribute float shadowBlur;
         attribute [ConvertNullToNullString] DOMString shadowColor;
 
-        void clearRect(in float x, in float y, in float width, in float height)
-            raises (DOMException);
-        void fillRect(in float x, in float y, in float width, in float height)
-            raises (DOMException);
+        void clearRect(in float x, in float y, in float width, in float height);
+        void fillRect(in float x, in float y, in float width, in float height);
 
         void beginPath();
         void closePath();
@@ -72,8 +70,7 @@ module html {
         void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y);
         void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius)
             raises (DOMException);
-        void rect(in float x, in float y, in float width, in float height)
-            raises (DOMException);
+        void rect(in float x, in float y, in float width, in float height);
         void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise)
             raises (DOMException);
         void fill();