[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-10851-g50815da

mrobinson at webkit.org mrobinson at webkit.org
Wed Dec 22 18:48:13 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 9529365294875d086a8053883720988b0d27bdc3
Author: mrobinson at webkit.org <mrobinson at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Sat Dec 18 18:44:48 2010 +0000

    2010-12-18  Helder Correia  <helder at sencha.com> and Martin Robinson  <mrobinson at igalia.com>
    
            Reviewed by Ariya Hidayat.
    
            [Qt] Canvas shadow offset should not be affected by any transformation
            https://bugs.webkit.org/show_bug.cgi?id=50422
    
            On a canvas context, shadows are currently affected by all
            transformations except scaling. According to the spec:
            http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#shadows
    
            "The shadowOffsetX and shadowOffsetY attributes specify the distance
            that the shadow will be offset in the positive horizontal and positive
            vertical distance respectively. Their values are in coordinate space
            units. They are not affected by the current transformation matrix."
    
            NOTE: this applies only to canvas, not to box shadows.
    
            Add new test to ensure that shadows are correctly transformed keeping
            the relative offset to the shape.
    
            * fast/canvas/canvas-scale-strokePath-shadow-expected.txt: See strokePath below.
            * fast/canvas/canvas-transforms-fillRect-shadow-expected.txt: Added.
            * fast/canvas/canvas-transforms-fillRect-shadow.html: Added.
            * fast/canvas/script-tests/canvas-scale-fillPath-shadow.js:
            * fast/canvas/script-tests/canvas-scale-fillRect-shadow.js:
            * fast/canvas/script-tests/canvas-scale-strokePath-shadow.js: Now using
              a lineWidth > 1 to make it easier to test and more fair among all
              ports, since there can be different transformation smoothness or
              aliasing settings.
            * fast/canvas/script-tests/canvas-transforms-fillRect-shadow.js: Added.
            * platform/gtk/Skipped: GTK port needs to implement this feature.
            * platform/gtk/fast/canvas/canvas-scale-fillPath-shadow-expected.txt: Removed.
            * platform/gtk/fast/canvas/canvas-scale-fillRect-shadow-expected.txt: Removed.
            * platform/gtk/fast/canvas/canvas-scale-strokePath-shadow-expected.txt: Removed.
    2010-12-18  Helder Correia  <helder at sencha.com> and Martin Robinson  <mrobinson at igalia.com>
    
            Reviewed by Ariya Hidayat.
    
            [Qt] Canvas shadow offset should not be affected by any transformation
            https://bugs.webkit.org/show_bug.cgi?id=50422
    
            On a canvas context, shadows are currently affected by all
            transformations except scaling. According to the spec:
            http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#shadows
    
            "The shadowOffsetX and shadowOffsetY attributes specify the distance
            that the shadow will be offset in the positive horizontal and positive
            vertical distance respectively. Their values are in coordinate space
            units. They are not affected by the current transformation matrix."
    
            NOTE: this applies only to canvas, not to box shadows.
    
            Test: fast/canvas/canvas-transforms-fillRect-shadow.html
    
            * platform/graphics/ContextShadow.cpp:
            (WebCore::ContextShadow::ContextShadow):
            (WebCore::ContextShadow::calculateLayerBoundingRect):
            * platform/graphics/ContextShadow.h:
            (WebCore::ContextShadow::setShadowsIgnoreTransforms):
            (WebCore::ContextShadow::shadowsIgnoreTransforms):
            (WebCore::ContextShadow::offset):
            * platform/graphics/qt/ContextShadowQt.cpp:
            (WebCore::ContextShadow::beginShadowLayer):
            (WebCore::ContextShadow::endShadowLayer):
            * platform/graphics/qt/GraphicsContextQt.cpp:
            (WebCore::mustUseContextShadow):
            (WebCore::GraphicsContext::fillPath):
            (WebCore::GraphicsContext::strokePath):
            (WebCore::GraphicsContext::fillRect):
            (WebCore::GraphicsContext::fillRoundedRect):
            (WebCore::GraphicsContext::setPlatformShadow):
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@74317 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 2328f34..94aa894 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,39 @@
+2010-12-18  Helder Correia  <helder at sencha.com> and Martin Robinson  <mrobinson at igalia.com>
+
+        Reviewed by Ariya Hidayat.
+
+        [Qt] Canvas shadow offset should not be affected by any transformation
+        https://bugs.webkit.org/show_bug.cgi?id=50422
+
+        On a canvas context, shadows are currently affected by all
+        transformations except scaling. According to the spec:
+        http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#shadows
+
+        "The shadowOffsetX and shadowOffsetY attributes specify the distance
+        that the shadow will be offset in the positive horizontal and positive
+        vertical distance respectively. Their values are in coordinate space
+        units. They are not affected by the current transformation matrix."
+
+        NOTE: this applies only to canvas, not to box shadows.
+
+        Add new test to ensure that shadows are correctly transformed keeping
+        the relative offset to the shape.
+
+        * fast/canvas/canvas-scale-strokePath-shadow-expected.txt: See strokePath below.
+        * fast/canvas/canvas-transforms-fillRect-shadow-expected.txt: Added.
+        * fast/canvas/canvas-transforms-fillRect-shadow.html: Added.
+        * fast/canvas/script-tests/canvas-scale-fillPath-shadow.js:
+        * fast/canvas/script-tests/canvas-scale-fillRect-shadow.js:
+        * fast/canvas/script-tests/canvas-scale-strokePath-shadow.js: Now using
+          a lineWidth > 1 to make it easier to test and more fair among all
+          ports, since there can be different transformation smoothness or
+          aliasing settings.
+        * fast/canvas/script-tests/canvas-transforms-fillRect-shadow.js: Added.
+        * platform/gtk/Skipped: GTK port needs to implement this feature.
+        * platform/gtk/fast/canvas/canvas-scale-fillPath-shadow-expected.txt: Removed.
+        * platform/gtk/fast/canvas/canvas-scale-fillRect-shadow-expected.txt: Removed.
+        * platform/gtk/fast/canvas/canvas-scale-strokePath-shadow-expected.txt: Removed.
+
 2010-12-18  Tony Gentilcore  <tonyg at chromium.org>
 
         Reviewed by Laszlo Gombos.
diff --git a/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow-expected.txt b/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
index e56201f..a337c4b 100644
--- a/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
+++ b/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
@@ -30,27 +30,27 @@ PASS d[3] is around 76
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-PASS d[3] is around 20
+PASS d[3] is around 149
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-PASS d[3] is around 22
+PASS d[3] is around 116
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-PASS d[3] is around 28
+PASS d[3] is around 115
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-PASS d[3] is around 22
+PASS d[3] is around 70
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-PASS d[3] is around 15
+PASS d[3] is around 70
 PASS d[0] is 255
 PASS d[1] is 0
 PASS d[2] is 0
-PASS d[3] is around 17
+PASS d[3] is around 69
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/fast/canvas/canvas-transforms-fillRect-shadow-expected.txt b/LayoutTests/fast/canvas/canvas-transforms-fillRect-shadow-expected.txt
new file mode 100644
index 0000000..013b891
--- /dev/null
+++ b/LayoutTests/fast/canvas/canvas-transforms-fillRect-shadow-expected.txt
@@ -0,0 +1,57 @@
+Ensure correct behavior of canvas with fillRect+shadow after translation+rotation+scaling. A blue and red checkered pattern should be displayed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is 255
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 127
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 127
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 127
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 106
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 106
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 83
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 36
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 36
+PASS d[0] is 255
+PASS d[1] is 0
+PASS d[2] is 0
+PASS d[3] is around 36
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/canvas/canvas-transforms-fillRect-shadow.html b/LayoutTests/fast/canvas/canvas-transforms-fillRect-shadow.html
new file mode 100644
index 0000000..2fc4e9a
--- /dev/null
+++ b/LayoutTests/fast/canvas/canvas-transforms-fillRect-shadow.html
@@ -0,0 +1,13 @@
+<!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>
+<script src="script-tests/canvas-transforms-fillRect-shadow.js"></script>
+<script src="../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/canvas/script-tests/canvas-scale-fillPath-shadow.js b/LayoutTests/fast/canvas/script-tests/canvas-scale-fillPath-shadow.js
index 05286f5..8b05f3c 100644
--- a/LayoutTests/fast/canvas/script-tests/canvas-scale-fillPath-shadow.js
+++ b/LayoutTests/fast/canvas/script-tests/canvas-scale-fillPath-shadow.js
@@ -19,7 +19,7 @@ function shouldBeAround(a, b)
         evalA = e;
     }
 
-    if (Math.abs(evalA - b) < 10)
+    if (Math.abs(evalA - b) < 20)
         print("PASS " + a + " is around " + b , "green")
     else
         print("FAIL " + a + " is not around " + b + " (actual: " + evalA + ")", "red");
@@ -35,7 +35,6 @@ ctx.scale(2, 2);
 ctx.shadowOffsetX = 100;
 ctx.shadowOffsetY = 100;
 ctx.fillStyle = 'rgba(0, 0, 255, 1)';
-//ctx.lineWidth = 30;
 
 ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
 ctx.beginPath();
@@ -73,38 +72,38 @@ ctx.fill();
 var d; // imageData.data
 
 // Verify solid shadow.
-d = ctx.getImageData(200, 205, 1, 1).data;
+d = ctx.getImageData(201, 205, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBe('d[3]', '255');
 
-d = ctx.getImageData(299, 295, 1, 1).data;
+d = ctx.getImageData(298, 295, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBe('d[3]', '255');
 
-d = ctx.getImageData(200, 299, 1, 1).data;
+d = ctx.getImageData(201, 298, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBe('d[3]', '255');
 
 // Verify solid alpha shadow.
-d = ctx.getImageData(200, 405, 1, 1).data;
+d = ctx.getImageData(201, 405, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBeAround('d[3]', '76');
 
-d = ctx.getImageData(299, 405, 1, 1).data;
+d = ctx.getImageData(298, 405, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBeAround('d[3]', '76');
 
-d = ctx.getImageData(205, 499, 1, 1).data;
+d = ctx.getImageData(205, 498, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
diff --git a/LayoutTests/fast/canvas/script-tests/canvas-scale-fillRect-shadow.js b/LayoutTests/fast/canvas/script-tests/canvas-scale-fillRect-shadow.js
index 99a1e59..56d4a34 100644
--- a/LayoutTests/fast/canvas/script-tests/canvas-scale-fillRect-shadow.js
+++ b/LayoutTests/fast/canvas/script-tests/canvas-scale-fillRect-shadow.js
@@ -19,7 +19,7 @@ function shouldBeAround(a, b)
         evalA = e;
     }
 
-    if (Math.abs(evalA - b) < 10)
+    if (Math.abs(evalA - b) < 20)
         print("PASS " + a + " is around " + b , "green")
     else
         print("FAIL " + a + " is not around " + b + " (actual: " + evalA + ")", "red");
@@ -52,38 +52,38 @@ ctx.fillRect(150, 150, 50, 50);
 var d; // imageData.data
 
 // Verify solid shadow.
-d = ctx.getImageData(200, 205, 1, 1).data;
+d = ctx.getImageData(201, 205, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBe('d[3]', '255');
 
-d = ctx.getImageData(299, 295, 1, 1).data;
+d = ctx.getImageData(298, 298, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBe('d[3]', '255');
 
-d = ctx.getImageData(200, 299, 1, 1).data;
+d = ctx.getImageData(201, 298, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBe('d[3]', '255');
 
 // Verify solid alpha shadow.
-d = ctx.getImageData(200, 405, 1, 1).data;
+d = ctx.getImageData(201, 405, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBeAround('d[3]', '76');
 
-d = ctx.getImageData(299, 405, 1, 1).data;
+d = ctx.getImageData(298, 405, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBeAround('d[3]', '76');
 
-d = ctx.getImageData(205, 499, 1, 1).data;
+d = ctx.getImageData(205, 498, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
diff --git a/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js b/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js
index 5198d94..6002175 100644
--- a/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js
+++ b/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js
@@ -19,7 +19,7 @@ function shouldBeAround(a, b)
         evalA = e;
     }
 
-    if (Math.abs(evalA - b) < 10)
+    if (Math.abs(evalA - b) < 20)
         print("PASS " + a + " is around " + b , "green")
     else
         print("FAIL " + a + " is not around " + b + " (actual: " + evalA + ")", "red");
@@ -35,6 +35,7 @@ ctx.scale(2, 2);
 ctx.shadowOffsetX = 100;
 ctx.shadowOffsetY = 100;
 ctx.strokeStyle = 'rgba(0, 0, 255, 1)';
+ctx.lineWidth = 5;
 
 ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
 ctx.beginPath();
@@ -76,79 +77,79 @@ ctx.stroke();
 var d; // imageData.data
 
 // Verify solid shadow.
-d = ctx.getImageData(200, 205, 1, 1).data;
+d = ctx.getImageData(250, 200, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBe('d[3]', '255');
 
-d = ctx.getImageData(299, 295, 1, 1).data;
+d = ctx.getImageData(300, 290, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBe('d[3]', '255');
 
-d = ctx.getImageData(201, 299, 1, 1).data;
+d = ctx.getImageData(200, 250, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBe('d[3]', '255');
 
 // Verify solid alpha shadow.
-d = ctx.getImageData(200, 405, 1, 1).data;
+d = ctx.getImageData(201, 405, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBeAround('d[3]', '76');
 
-d = ctx.getImageData(299, 405, 1, 1).data;
+d = ctx.getImageData(201, 500, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBeAround('d[3]', '76');
 
-d = ctx.getImageData(205, 499, 1, 1).data;
+d = ctx.getImageData(300, 499, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
 shouldBeAround('d[3]', '76');
 
 // Verify blurry shadow.
-d = ctx.getImageData(394, 208, 1, 1).data;
+d = ctx.getImageData(404, 210, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '20');
+shouldBeAround('d[3]', '149');
 
-d = ctx.getImageData(503, 301, 1, 1).data;
+d = ctx.getImageData(505, 250, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '22');
+shouldBeAround('d[3]', '116');
 
-d = ctx.getImageData(504, 250, 1, 1).data;
+d = ctx.getImageData(450, 205, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '28');
+shouldBeAround('d[3]', '115');
 
 // Verify blurry alpha shadow.
-d = ctx.getImageData(405, 405, 1, 1).data;
+d = ctx.getImageData(505, 450, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '22');
+shouldBeAround('d[3]', '70');
 
-d = ctx.getImageData(415, 495, 1, 1).data;
+d = ctx.getImageData(505, 450, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '15');
+shouldBeAround('d[3]', '70');
 
-d = ctx.getImageData(450, 504, 1, 1).data;
+d = ctx.getImageData(450, 405, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
-shouldBeAround('d[3]', '17');
+shouldBeAround('d[3]', '69');
 
 var successfullyParsed = true;
diff --git a/LayoutTests/fast/canvas/script-tests/canvas-transforms-fillRect-shadow.js b/LayoutTests/fast/canvas/script-tests/canvas-transforms-fillRect-shadow.js
new file mode 100644
index 0000000..a090b47
--- /dev/null
+++ b/LayoutTests/fast/canvas/script-tests/canvas-transforms-fillRect-shadow.js
@@ -0,0 +1,133 @@
+description("Ensure correct behavior of canvas with fillRect+shadow after translation+rotation+scaling. A blue and red checkered pattern should be displayed.");
+
+function print(message, color)
+{
+    var paragraph = document.createElement("div");
+    paragraph.appendChild(document.createTextNode(message));
+    paragraph.style.fontFamily = "monospace";
+    if (color)
+        paragraph.style.color = color;
+    document.getElementById("console").appendChild(paragraph);
+}
+
+function shouldBeAround(a, b)
+{
+    var evalA;
+    try {
+        evalA = eval(a);
+    } catch(e) {
+        evalA = e;
+    }
+
+    if (Math.abs(evalA - b) < 10)
+        print("PASS " + a + " is around " + b , "green")
+    else
+        print("FAIL " + a + " is not around " + b + " (actual: " + evalA + ")", "red");
+}
+
+var canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+canvas.setAttribute('width', '600');
+canvas.setAttribute('height', '600');
+var ctx = canvas.getContext('2d');
+
+ctx.fillStyle = 'rgba(0, 0, 255, 1.0)';
+ctx.shadowOffsetX = 100;
+ctx.shadowOffsetY = 100;
+
+ctx.translate(-100, -100);
+ctx.rotate(Math.PI/2);
+ctx.scale(2, 2);
+
+ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
+ctx.fillRect(100, -150, 50, 50);
+
+ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
+ctx.fillRect(200, -150, 50, 50);
+
+ctx.shadowBlur = 5;
+ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
+ctx.fillRect(100, -250, 50, 50);
+
+ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
+ctx.fillRect(200, -250, 50, 50);
+
+var d; // imageData.data
+
+// Verify solid shadow.
+d = ctx.getImageData(201, 205, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBe('d[3]', '255');
+
+d = ctx.getImageData(298, 298, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBe('d[3]', '255');
+
+d = ctx.getImageData(201, 298, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBe('d[3]', '255');
+
+// Verify solid alpha shadow.
+d = ctx.getImageData(201, 401, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBeAround('d[3]', '127');
+
+d = ctx.getImageData(298, 450, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBeAround('d[3]', '127');
+
+d = ctx.getImageData(205, 498, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBeAround('d[3]', '127');
+
+// Verify blurry shadow.
+d = ctx.getImageData(399, 205, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBeAround('d[3]', '106');
+
+d = ctx.getImageData(500, 205, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBeAround('d[3]', '106');
+
+d = ctx.getImageData(499, 299, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBeAround('d[3]', '83');
+
+// Verify blurry alpha shadow.
+d = ctx.getImageData(398, 405, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBeAround('d[3]', '36');
+
+d = ctx.getImageData(405, 501, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBeAround('d[3]', '36');
+
+d = ctx.getImageData(405, 501, 1, 1).data;
+shouldBe('d[0]', '255');
+shouldBe('d[1]', '0');
+shouldBe('d[2]', '0');
+shouldBeAround('d[3]', '36');
+
+var successfullyParsed = true;
diff --git a/LayoutTests/platform/gtk/Skipped b/LayoutTests/platform/gtk/Skipped
index e715a37..0b09405 100644
--- a/LayoutTests/platform/gtk/Skipped
+++ b/LayoutTests/platform/gtk/Skipped
@@ -1025,6 +1025,7 @@ editing/unsupported-content/table-type-before.html
 fast/canvas/canvas-bg-zoom.html
 fast/canvas/canvas-getImageData.html
 fast/canvas/canvas-gradient-addStop-error.html
+fast/canvas/canvas-transforms-fillRect-shadow.html
 fast/canvas/canvas-zoom.html
 fast/css/css1_forward_compatible_parsing.html
 fast/css/invalid-percentage-property.html
diff --git a/LayoutTests/platform/gtk/fast/canvas/canvas-scale-fillPath-shadow-expected.txt b/LayoutTests/platform/gtk/fast/canvas/canvas-scale-fillPath-shadow-expected.txt
deleted file mode 100644
index 8572178..0000000
--- a/LayoutTests/platform/gtk/fast/canvas/canvas-scale-fillPath-shadow-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-Ensure correct behavior of canvas with path fill + shadow after scaling. A blue and red checkered pattern should be displayed.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] should be 255. Was 191.
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] should be 255. Was 191.
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] should be 255. Was 143.
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 57)
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 57)
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 57)
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 83
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 83
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 53
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 24
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 24
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 24
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/LayoutTests/platform/gtk/fast/canvas/canvas-scale-fillRect-shadow-expected.txt b/LayoutTests/platform/gtk/fast/canvas/canvas-scale-fillRect-shadow-expected.txt
deleted file mode 100644
index 228d5fc..0000000
--- a/LayoutTests/platform/gtk/fast/canvas/canvas-scale-fillRect-shadow-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-Ensure correct behavior of canvas with fillRect+shadow after scaling. A blue and red checkered pattern should be displayed.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] should be 255. Was 191.
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] should be 255. Was 191.
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] should be 255. Was 143.
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 57)
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 57)
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 57)
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 83
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 83
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 53
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 24
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 24
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 24
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/LayoutTests/platform/gtk/fast/canvas/canvas-scale-strokePath-shadow-expected.txt b/LayoutTests/platform/gtk/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
deleted file mode 100644
index afddb09..0000000
--- a/LayoutTests/platform/gtk/fast/canvas/canvas-scale-strokePath-shadow-expected.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-Ensure correct behavior of canvas with path stroke + shadow after scaling. A blue and red checkered pattern should be displayed.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] should be 255. Was 123.
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] should be 255. Was 90.
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] should be 255. Was 162.
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 37)
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 27)
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-FAIL d[3] is not around 76 (actual: 27)
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 20
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 22
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 28
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 22
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 15
-PASS d[0] is 255
-PASS d[1] is 0
-PASS d[2] is 0
-PASS d[3] is around 17
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 7275d7d..3b08fc5 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,41 @@
+2010-12-18  Helder Correia  <helder at sencha.com> and Martin Robinson  <mrobinson at igalia.com>
+
+        Reviewed by Ariya Hidayat.
+
+        [Qt] Canvas shadow offset should not be affected by any transformation
+        https://bugs.webkit.org/show_bug.cgi?id=50422
+
+        On a canvas context, shadows are currently affected by all
+        transformations except scaling. According to the spec:
+        http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#shadows
+
+        "The shadowOffsetX and shadowOffsetY attributes specify the distance
+        that the shadow will be offset in the positive horizontal and positive
+        vertical distance respectively. Their values are in coordinate space
+        units. They are not affected by the current transformation matrix."
+
+        NOTE: this applies only to canvas, not to box shadows.
+
+        Test: fast/canvas/canvas-transforms-fillRect-shadow.html
+
+        * platform/graphics/ContextShadow.cpp:
+        (WebCore::ContextShadow::ContextShadow):
+        (WebCore::ContextShadow::calculateLayerBoundingRect):
+        * platform/graphics/ContextShadow.h:
+        (WebCore::ContextShadow::setShadowsIgnoreTransforms):
+        (WebCore::ContextShadow::shadowsIgnoreTransforms):
+        (WebCore::ContextShadow::offset):
+        * platform/graphics/qt/ContextShadowQt.cpp:
+        (WebCore::ContextShadow::beginShadowLayer):
+        (WebCore::ContextShadow::endShadowLayer):
+        * platform/graphics/qt/GraphicsContextQt.cpp:
+        (WebCore::mustUseContextShadow):
+        (WebCore::GraphicsContext::fillPath):
+        (WebCore::GraphicsContext::strokePath):
+        (WebCore::GraphicsContext::fillRect):
+        (WebCore::GraphicsContext::fillRoundedRect):
+        (WebCore::GraphicsContext::setPlatformShadow):
+
 2010-12-18  Ariya Hidayat  <ariya at sencha.com>
 
         Reviewed by Andreas Kling.
diff --git a/WebCore/platform/graphics/ContextShadow.cpp b/WebCore/platform/graphics/ContextShadow.cpp
index 87a1c5c..5e7a7a0 100644
--- a/WebCore/platform/graphics/ContextShadow.cpp
+++ b/WebCore/platform/graphics/ContextShadow.cpp
@@ -29,6 +29,7 @@
 #include "config.h"
 #include "ContextShadow.h"
 
+#include "FloatQuad.h"
 #include <wtf/MathExtras.h>
 #include <wtf/Noncopyable.h>
 
@@ -41,6 +42,7 @@ ContextShadow::ContextShadow()
     : m_type(NoShadow)
     , m_blurDistance(0)
     , m_layerContext(0)
+    , m_shadowsIgnoreTransforms(false)
 {
 }
 
@@ -49,6 +51,7 @@ ContextShadow::ContextShadow(const Color& color, float radius, const FloatSize&
     , m_blurDistance(round(radius))
     , m_offset(offset)
     , m_layerContext(0)
+    , m_shadowsIgnoreTransforms(false)
 {
     // See comments in http://webkit.org/b/40793, it seems sensible
     // to follow Skia's limit of 128 pixels of blur radius
@@ -77,6 +80,23 @@ void ContextShadow::clear()
     m_offset = FloatSize();
 }
 
+bool ContextShadow::mustUseContextShadow(PlatformContext context)
+{
+    // We can't avoid ContextShadow, since the shadow has blur.
+    if (m_type == ContextShadow::BlurShadow)
+        return true;
+    // We can avoid ContextShadow and optimize, since we're not drawing on a
+    // canvas and box shadows are affected by the transformation matrix.
+    if (!shadowsIgnoreTransforms())
+        return false;
+    // We can avoid ContextShadow, since there are no transformations to apply to the canvas.
+    const TransformationMatrix transform(getTransformationMatrixFromContext(context));
+    if (transform.isIdentity())
+        return false;
+    // Otherwise, no chance avoiding ContextShadow.
+    return true;
+}
+
 // Instead of integer division, we use 17.15 for fixed-point division.
 static const int BlurSumShift = 15;
 
@@ -149,29 +169,61 @@ void ContextShadow::blurLayerImage(unsigned char* imageData, const IntSize& size
     }
 }
 
-void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect)
+IntRect ContextShadow::calculateLayerBoundingRect(const PlatformContext context, const FloatRect& layerArea, const IntRect& clipRect)
 {
-    // Calculate the destination of the blurred layer.
-    FloatRect destinationRect(layerArea);
-    destinationRect.move(m_offset);
-    m_layerRect = enclosingIntRect(destinationRect);
+    // Calculate the destination of the blurred and/or transformed layer.
+    FloatRect layerFloatRect;
+    float inflation = 0;
+
+    const TransformationMatrix transform(getTransformationMatrixFromContext(context));
+    if (m_shadowsIgnoreTransforms && !transform.isIdentity()) {
+        FloatQuad transformedPolygon = transform.mapQuad(FloatQuad(layerArea));
+        transformedPolygon.move(m_offset);
+        layerFloatRect = transform.inverse().mapQuad(transformedPolygon).boundingBox();
+    } else {
+        layerFloatRect = layerArea;
+        layerFloatRect.move(m_offset);
+    }
 
     // We expand the area by the blur radius to give extra space for the blur transition.
-    m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0);
+    if (m_type == BlurShadow) {
+        layerFloatRect.inflate(m_blurDistance);
+        inflation += m_blurDistance;
+    }
 
-    if (!clipRect.contains(m_layerRect)) {
+    FloatRect unclippedLayerRect = layerFloatRect;
+
+    if (!clipRect.contains(enclosingIntRect(layerFloatRect))) {
         // No need to have the buffer larger than the clip.
-        m_layerRect.intersect(clipRect);
+        layerFloatRect.intersect(clipRect);
 
         // If we are totally outside the clip region, we aren't painting at all.
-        if (m_layerRect.isEmpty())
-            return;
+        if (layerFloatRect.isEmpty())
+            return IntRect(0, 0, 0, 0);
 
         // We adjust again because the pixels at the borders are still
         // potentially affected by the pixels outside the buffer.
-        if (m_type == BlurShadow)
-            m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0);
+        if (m_type == BlurShadow) {
+            layerFloatRect.inflate(m_blurDistance);
+            unclippedLayerRect.inflate(m_blurDistance);
+            inflation += m_blurDistance;
+        }
     }
+
+    const int frameSize = inflation * 2;
+    m_sourceRect = IntRect(0, 0, layerArea.width() + frameSize, layerArea.height() + frameSize);
+    m_layerOrigin = FloatPoint(layerFloatRect.x(), layerFloatRect.y());
+
+    const FloatPoint m_unclippedLayerOrigin = FloatPoint(unclippedLayerRect.x(), unclippedLayerRect.y());
+    const FloatSize clippedOut = m_unclippedLayerOrigin - m_layerOrigin;
+
+    // Set the origin as the top left corner of the scratch image, or, in case there's a clipped
+    // out region, set the origin accordingly to the full bounding rect's top-left corner.
+    const float translationX = -layerArea.x() + inflation - fabsf(clippedOut.width());
+    const float translationY = -layerArea.y() + inflation - fabsf(clippedOut.height());
+    m_layerContextTranslation = FloatPoint(translationX, translationY);
+
+    return enclosingIntRect(layerFloatRect);
 }
 
 } // namespace WebCore
diff --git a/WebCore/platform/graphics/ContextShadow.h b/WebCore/platform/graphics/ContextShadow.h
index fa778af..d13d321 100644
--- a/WebCore/platform/graphics/ContextShadow.h
+++ b/WebCore/platform/graphics/ContextShadow.h
@@ -79,6 +79,7 @@ public:
     ContextShadow();
     ContextShadow(const Color&, float radius, const FloatSize& offset);
 
+    bool mustUseContextShadow(PlatformContext);
     void clear();
 
     // The pair beginShadowLayer and endShadowLayer creates a temporary image
@@ -106,25 +107,28 @@ public:
     PlatformContext beginShadowLayer(PlatformContext, const FloatRect& layerArea);
     void endShadowLayer(PlatformContext);
     static void purgeScratchBuffer();
+    static TransformationMatrix getTransformationMatrixFromContext(PlatformContext);
+
+    void setShadowsIgnoreTransforms(bool enable) { m_shadowsIgnoreTransforms = enable; }
+    bool shadowsIgnoreTransforms() const { return m_shadowsIgnoreTransforms; }
 #if PLATFORM(CAIRO)
     void drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius = IntSize(), const IntSize& topRightRadius = IntSize(), const IntSize& bottomLeftRadius = IntSize(), const IntSize& bottomRightRadius = IntSize());
 #endif
-
 #if PLATFORM(QT)
-    QPointF offset() { return QPointF(m_offset.width(), m_offset.height()); }
+    QPointF offset() const { return QPointF(m_offset.width(), m_offset.height()); }
 #endif
 
-
 private:
-    IntRect m_layerRect;
-    PlatformImage m_layerImage;
-    PlatformContext m_layerContext;
-
-    // Used for reference when canvas scale(x,y) was called.
-    FloatRect m_unscaledLayerRect;
+    PlatformImage m_layerImage; // Buffer to where the temporary shadow will be drawn to.
+    PlatformContext m_layerContext; // Context used to paint the shadow to the layer image.
+    FloatRect m_sourceRect; // Sub-rect of m_layerImage that contains the shadow pixels.
+    FloatPoint m_layerOrigin; // Top-left corner of the (possibly clipped) bounding rect to draw the shadow to.
+    FloatPoint m_layerContextTranslation; // Translation to apply to m_layerContext for the shadow to be correctly clipped.
+    bool m_shadowsIgnoreTransforms;
 
     void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride);
-    void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect);
+    IntRect calculateLayerBoundingRect(const PlatformContext, const FloatRect& layerArea, const IntRect& clipRect);
+
 #if PLATFORM(CAIRO)
     void drawRectShadowWithoutTiling(PlatformContext context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha);
 #endif
diff --git a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
index 699edf7..6801269 100644
--- a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp
@@ -82,19 +82,25 @@ static cairo_surface_t* getScratchBuffer(const IntSize& size)
     return scratchBuffer;
 }
 
-PlatformContext ContextShadow::beginShadowLayer(PlatformContext context, const FloatRect& layerArea)
+TransformationMatrix ContextShadow::getTransformationMatrixFromContext(PlatformContext context)
 {
-    m_unscaledLayerRect = layerArea;
+    cairo_matrix_t transform;
+    cairo_get_matrix(context, &transform);
+    return TransformationMatrix(transform.xx, transform.yx, transform.xy,
+                                transform.yy, transform.x0, transform.y0);
+}
 
+PlatformContext ContextShadow::beginShadowLayer(PlatformContext context, const FloatRect& layerArea)
+{
     double x1, x2, y1, y2;
     cairo_clip_extents(context, &x1, &y1, &x2, &y2);
-    calculateLayerBoundingRect(layerArea, IntRect(x1, y1, x2 - x1, y2 - y1));
+    IntRect layerRect = calculateLayerBoundingRect(context, layerArea, IntRect(x1, y1, x2 - x1, y2 - y1));
 
     // Don't paint if we are totally outside the clip region.
-    if (m_layerRect.isEmpty())
+    if (layerRect.isEmpty())
         return 0;
 
-    m_layerImage = getScratchBuffer(m_layerRect.size());
+    m_layerImage = getScratchBuffer(layerRect.size());
     m_layerContext = cairo_create(m_layerImage);
 
     // Always clear the surface first.
@@ -102,8 +108,7 @@ PlatformContext ContextShadow::beginShadowLayer(PlatformContext context, const F
     cairo_paint(m_layerContext);
     cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER);
 
-    cairo_translate(m_layerContext, m_offset.width(), m_offset.height());
-    cairo_translate(m_layerContext, -m_layerRect.x(), -m_layerRect.y());
+    cairo_translate(m_layerContext, m_layerContextTranslation.x(), m_layerContextTranslation.y());
     return m_layerContext;
 }
 
@@ -122,19 +127,7 @@ void ContextShadow::endShadowLayer(cairo_t* cr)
 
     cairo_save(cr);
     setSourceRGBAFromColor(cr, m_color);
-
-    cairo_matrix_t transform;
-    cairo_get_matrix(cr, &transform);
-    double x = m_layerRect.x();
-    double y = m_layerRect.y();
-
-    double xScale = sqrt(transform.xx * transform.xx + transform.yx * transform.yx);
-    double yScale = sqrt(transform.xy * transform.xy + transform.yy * transform.yy);
-    if (xScale != 1 || yScale != 1) {
-        x = m_unscaledLayerRect.x() + m_offset.width()  / transform.xx - m_blurDistance;
-        y = m_unscaledLayerRect.y() + m_offset.height() / transform.yy - m_blurDistance;
-    }
-    cairo_mask_surface(cr, m_layerImage, x, y);
+    cairo_mask_surface(cr, m_layerImage, m_layerOrigin.x(), m_layerOrigin.y());
     cairo_restore(cr);
 
     // Schedule a purge of the scratch buffer. We do not need to destroy the surface.
@@ -235,9 +228,9 @@ void ContextShadow::drawRectShadow(GraphicsContext* context, const IntRect& rect
     // Reduce the size of what we have to draw with the clip area.
     double x1, x2, y1, y2;
     cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
-    calculateLayerBoundingRect(shadowRect, IntRect(x1, y1, x2 - x1, y2 - y1));
+    calculateLayerBoundingRect(cr, shadowRect, IntRect(x1, y1, x2 - x1, y2 - y1));
 
-    if ((shadowTemplateSize.width() * shadowTemplateSize.height() > m_layerRect.width() * m_layerRect.height())) {
+    if ((shadowTemplateSize.width() * shadowTemplateSize.height() > m_sourceRect.width() * m_sourceRect.height())) {
         drawRectShadowWithoutTiling(cr, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha());
         return;
     }
diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp
index 4b11756..0d92ada 100644
--- a/WebCore/platform/graphics/cairo/FontCairo.cpp
+++ b/WebCore/platform/graphics/cairo/FontCairo.cpp
@@ -72,7 +72,7 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context,
     if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow->m_type == ContextShadow::NoShadow)
         return;
 
-    if (shadow->m_type == ContextShadow::SolidShadow) {
+    if (!shadow->mustUseContextShadow(context)) {
         // Optimize non-blurry shadows, by just drawing text without the ContextShadow.
         cairo_save(context);
         cairo_translate(context, shadow->m_offset.width(), shadow->m_offset.height());
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index 5032f97..a6edaf7 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -871,6 +871,8 @@ void GraphicsContext::setPlatformShadow(FloatSize const& size, float blur, Color
         m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
     } else
         m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
+
+    m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
 }
 
 ContextShadow* GraphicsContext::contextShadow()
diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp
index a0d5c62..eabd913 100644
--- a/WebCore/platform/graphics/gtk/FontGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontGtk.cpp
@@ -225,7 +225,7 @@ static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context,
     FloatPoint totalOffset(point + shadow->m_offset);
 
     // Optimize non-blurry shadows, by just drawing text without the ContextShadow.
-    if (shadow->m_type == ContextShadow::SolidShadow) {
+    if (!shadow->mustUseContextShadow(context)) {
         cairo_save(context);
         cairo_translate(context, totalOffset.x(), totalOffset.y());
 
diff --git a/WebCore/platform/graphics/qt/ContextShadowQt.cpp b/WebCore/platform/graphics/qt/ContextShadowQt.cpp
index f7c70f6..48f7976 100644
--- a/WebCore/platform/graphics/qt/ContextShadowQt.cpp
+++ b/WebCore/platform/graphics/qt/ContextShadowQt.cpp
@@ -100,6 +100,13 @@ void ShadowBuffer::timerEvent(QTimerEvent* event)
     QObject::timerEvent(event);
 }
 
+TransformationMatrix ContextShadow::getTransformationMatrixFromContext(PlatformContext context)
+{
+    const QTransform& transform = context->transform();
+    return TransformationMatrix(transform.m11(), transform.m12(), transform.m21(),
+                                transform.m22(), transform.dx(), transform.dy());
+}
+
 Q_GLOBAL_STATIC(ShadowBuffer, scratchShadowBuffer)
 
 PlatformContext ContextShadow::beginShadowLayer(PlatformContext p, const FloatRect& layerArea)
@@ -114,25 +121,22 @@ PlatformContext ContextShadow::beginShadowLayer(PlatformContext p, const FloatRe
     else
         clipRect = p->transform().inverted().mapRect(p->window());
 
-    m_unscaledLayerRect = layerArea;
-    calculateLayerBoundingRect(layerArea, IntRect(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height()));
+    // Set m_layerOrigin, m_layerContextTranslation, m_sourceRect.
+    IntRect clip(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
+    IntRect layerRect = calculateLayerBoundingRect(p, layerArea, clip);
 
     // Don't paint if we are totally outside the clip region.
-    if (m_layerRect.isEmpty())
+    if (layerRect.isEmpty())
         return 0;
 
     ShadowBuffer* shadowBuffer = scratchShadowBuffer();
-    QImage* shadowImage = shadowBuffer->scratchImage(m_layerRect.size());
+    QImage* shadowImage = shadowBuffer->scratchImage(layerRect.size());
     m_layerImage = QImage(*shadowImage);
 
     m_layerContext = new QPainter;
     m_layerContext->begin(&m_layerImage);
     m_layerContext->setFont(p->font());
-    m_layerContext->translate(m_offset.width(), m_offset.height());
-
-    // The origin is now the top left corner of the scratch image.
-    m_layerContext->translate(-m_layerRect.x(), -m_layerRect.y());
-
+    m_layerContext->translate(m_layerContextTranslation);
     return m_layerContext;
 }
 
@@ -155,13 +159,7 @@ void ContextShadow::endShadowLayer(PlatformContext p)
         p.end();
     }
 
-    const QTransform transform = p->transform();
-    if (transform.isScaling()) {
-        qreal x = m_unscaledLayerRect.x() + m_offset.width()  / transform.m11() - m_blurDistance;
-        qreal y = m_unscaledLayerRect.y() + m_offset.height() / transform.m22() - m_blurDistance;
-        p->drawImage(QPointF(x, y), m_layerImage);
-    } else
-        p->drawImage(m_layerRect.topLeft(), m_layerImage);
+    p->drawImage(m_layerOrigin, m_layerImage, m_sourceRect);
 
     scratchShadowBuffer()->schedulePurge();
 }
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index e89d330..131ae93 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -146,7 +146,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float
 
             if (ctxShadow->m_type != ContextShadow::NoShadow) {
                 ContextShadow* ctxShadow = ctx->contextShadow();
-                if (ctxShadow->m_type != ContextShadow::BlurShadow) {
+                if (!ctxShadow->mustUseContextShadow(p)) {
                     p->save();
                     p->setPen(ctxShadow->m_color);
                     p->translate(ctxShadow->offset());
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index b94c934..9dd38aa 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -53,7 +53,6 @@
 #include "TransparencyLayer.h"
 
 #include <QBrush>
-#include <QDebug>
 #include <QGradient>
 #include <QPaintDevice>
 #include <QPaintEngine>
@@ -511,33 +510,20 @@ void GraphicsContext::fillPath(const Path& path)
 
     if (m_data->hasShadow()) {
         ContextShadow* shadow = contextShadow();
-        if (shadow->m_type != ContextShadow::BlurShadow
-            && !m_state.fillPattern && !m_state.fillGradient)
+        if (shadow->mustUseContextShadow(p) || m_state.fillPattern || m_state.fillGradient)
         {
-            QPointF offset = shadow->offset();
-            const QTransform& transform = p->transform();
-            if (transform.isScaling()) {
-                // If scaling is required, find the new coord for shadow origin,
-                // so that the relative offset to its shape is kept.
-                QPointF translatedOffset(offset.x() / transform.m11(),
-                                         offset.y() / transform.m22());
-                platformPath.translate(translatedOffset);
-                p->fillPath(platformPath, QColor(shadow->m_color));
-                platformPath.translate(-translatedOffset);
-            } else {
-                p->translate(offset);
-                p->fillPath(platformPath, QColor(shadow->m_color));
-                p->translate(-offset);
-            }
-        } else {
             QPainter* shadowPainter = shadow->beginShadowLayer(p, platformPath.controlPointRect());
             if (shadowPainter) {
                 shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
                 shadowPainter->fillPath(platformPath, QColor(m_data->shadow.m_color));
                 shadow->endShadowLayer(p);
             }
+        } else {
+            QPointF offset = shadow->offset();
+            p->translate(offset);
+            p->fillPath(platformPath, QColor(shadow->m_color));
+            p->translate(-offset);
         }
-
     }
     if (m_state.fillPattern) {
         AffineTransform affine;
@@ -562,28 +548,8 @@ void GraphicsContext::strokePath(const Path& path)
 
     if (m_data->hasShadow()) {
         ContextShadow* shadow = contextShadow();
-
-        if (shadow->m_type != ContextShadow::BlurShadow
-            && !m_state.strokePattern && !m_state.strokeGradient)
+        if (shadow->mustUseContextShadow(p) || m_state.strokePattern || m_state.strokeGradient)
         {
-            QPen shadowPen(pen);
-            shadowPen.setColor(m_data->shadow.m_color);
-            QPointF offset = shadow->offset();
-            const QTransform& transform = p->transform();
-            if (transform.isScaling()) {
-                // If scaling is required, find the new coord for shadow origin,
-                // so that the relative offset to its shape is kept.
-                QPointF translatedOffset(offset.x() / transform.m11(),
-                                         offset.y() / transform.m22());
-                platformPath.translate(translatedOffset);
-                p->strokePath(platformPath, shadowPen);
-                platformPath.translate(-translatedOffset);
-            } else {
-                p->translate(offset);
-                p->strokePath(platformPath, shadowPen);
-                p->translate(-offset);
-            }
-        } else {
             FloatRect boundingRect = platformPath.controlPointRect();
             boundingRect.inflate(pen.miterLimit() + pen.widthF());
             QPainter* shadowPainter = shadow->beginShadowLayer(p, boundingRect);
@@ -592,6 +558,13 @@ void GraphicsContext::strokePath(const Path& path)
                 shadowPainter->strokePath(platformPath, pen);
                 shadow->endShadowLayer(p);
             }
+        } else {
+            QPen shadowPen(pen);
+            shadowPen.setColor(m_data->shadow.m_color);
+            QPointF offset = shadow->offset();
+            p->translate(offset);
+            p->strokePath(platformPath, shadowPen);
+            p->translate(-offset);
         }
     }
 
@@ -711,7 +684,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
         p->fillRect(normalizedRect, brush);
     } else {
         if (m_data->hasShadow()) {
-            if (shadow->m_type == ContextShadow::BlurShadow) {
+            if (shadow->mustUseContextShadow(p)) {
                 QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect);
                 if (shadowPainter) {
                     shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255);
@@ -719,17 +692,11 @@ void GraphicsContext::fillRect(const FloatRect& rect)
                     shadow->endShadowLayer(p);
                 }
             } else {
-                // Solid rectangle fill with no blur shadow can be done faster
-                // without using the shadow layer at all.
+                // Solid rectangle fill with no blur shadow or transformations applied can be done
+                // faster without using the shadow layer at all.
                 QColor shadowColor = shadow->m_color;
                 shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF());
-                const QTransform& transform = p->transform();
-                if (transform.isScaling()) {
-                    p->fillRect(normalizedRect.translated(static_cast<qreal>(shadow->offset().x()) / transform.m11(),
-                                                          static_cast<qreal>(shadow->offset().y()  / transform.m22())),
-                                shadowColor);
-                } else
-                    p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor);
+                p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor);
             }
         }
 
@@ -749,18 +716,15 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS
 
     if (m_data->hasShadow()) {
         ContextShadow* shadow = contextShadow();
-
-        if (shadow->m_type != ContextShadow::BlurShadow) {
-            // We do not need any layer for simple shadow.
-            p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color);
-        } else {
+        if (shadow->mustUseContextShadow(p)) {
             QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect);
             if (shadowPainter) {
                 shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
                 shadowPainter->fillRect(normalizedRect, shadow->m_color);
                 shadow->endShadowLayer(p);
             }
-        }
+        } else
+            p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color);
     }
 
     p->fillRect(normalizedRect, m_data->solidColor);
@@ -776,19 +740,17 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
     QPainter* p = m_data->p();
     if (m_data->hasShadow()) {
         ContextShadow* shadow = contextShadow();
-
-        if (shadow->m_type != ContextShadow::BlurShadow) {
-            // We do not need any layer for simple shadow.
-            p->translate(m_data->shadow.offset());
-            p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
-            p->translate(-m_data->shadow.offset());
-        } else {
+        if (shadow->mustUseContextShadow(p)) {
             QPainter* shadowPainter = shadow->beginShadowLayer(p, rect);
             if (shadowPainter) {
                 shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
                 shadowPainter->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
                 shadow->endShadowLayer(p);
             }
+        } else {
+            p->translate(m_data->shadow.offset());
+            p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
+            p->translate(-m_data->shadow.offset());
         }
     }
     p->fillPath(path.platformPath(), QColor(color));
@@ -958,9 +920,10 @@ void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const
         // We flip the height since CG and HTML5 Canvas have opposite Y axis
         m_state.shadowOffset = FloatSize(size.width(), -size.height());
         m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
-    } else {
+    } else
         m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
-    }
+
+    m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
 }
 
 void GraphicsContext::clearPlatformShadow()

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list