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

commit-queue at webkit.org commit-queue at webkit.org
Wed Dec 22 18:37:00 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 09a30e329c5bd53b768d237d05cdcad4ced60d27
Author: commit-queue at webkit.org <commit-queue at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Dec 14 18:30:34 2010 +0000

    2010-12-14  Helder Correia  <helder at sencha.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:
            * 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.
    2010-12-14  Helder Correia  <helder at sencha.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@74040 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index ac2e6e4..5f1c566 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,35 @@
+2010-12-14  Helder Correia  <helder at sencha.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:
+        * 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.
+
 2010-12-14  Pavel Feldman  <pfeldman at chromium.org>
 
         Not reviewed. Removed obsolete chromium expectations.
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..3ca3321 100644
--- a/LayoutTests/fast/canvas/script-tests/canvas-scale-fillPath-shadow.js
+++ b/LayoutTests/fast/canvas/script-tests/canvas-scale-fillPath-shadow.js
@@ -79,13 +79,13 @@ 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(200, 298, 1, 1).data;
 shouldBe('d[0]', '255');
 shouldBe('d[1]', '0');
 shouldBe('d[2]', '0');
@@ -98,13 +98,13 @@ 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..f495c91 100644
--- a/LayoutTests/fast/canvas/script-tests/canvas-scale-fillRect-shadow.js
+++ b/LayoutTests/fast/canvas/script-tests/canvas-scale-fillRect-shadow.js
@@ -58,13 +58,13 @@ 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');
@@ -77,13 +77,13 @@ 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..91b927f 100644
--- a/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js
+++ b/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js
@@ -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..b67f244
--- /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(200, 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(299, 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/WebCore/ChangeLog b/WebCore/ChangeLog
index 4d79928..bcdab61 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,41 @@
+2010-12-14  Helder Correia  <helder at sencha.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-14  Alexander Pavlov  <apavlov at chromium.org>
 
         Reviewed by Yury Semikhatsky.
diff --git a/WebCore/platform/graphics/ContextShadow.cpp b/WebCore/platform/graphics/ContextShadow.cpp
index 87a1c5c..ebffd98 100644
--- a/WebCore/platform/graphics/ContextShadow.cpp
+++ b/WebCore/platform/graphics/ContextShadow.cpp
@@ -41,6 +41,7 @@ ContextShadow::ContextShadow()
     : m_type(NoShadow)
     , m_blurDistance(0)
     , m_layerContext(0)
+    , m_shadowsIgnoreTransforms(false)
 {
 }
 
@@ -49,6 +50,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
@@ -149,6 +151,53 @@ void ContextShadow::blurLayerImage(unsigned char* imageData, const IntSize& size
     }
 }
 
+#if PLATFORM(QT)
+IntRect ContextShadow::calculateLayerBoundingRect(const PlatformContext p, const FloatRect& layerArea, const IntRect& clipRect)
+{
+    // Calculate the destination of the blurred and/or transformed layer.
+    FloatRect layerFloatRect;
+    float inflation = 0;
+
+    const QTransform transform = p->transform();
+    if (m_shadowsIgnoreTransforms && !transform.isIdentity()) {
+        QPolygonF transformedPolygon = transform.map(QPolygonF(layerArea));
+        transformedPolygon.translate(offset());
+        layerFloatRect = transform.inverted().map(transformedPolygon).boundingRect();
+    } else {
+        layerFloatRect = layerArea;
+        layerFloatRect.move(m_offset);
+    }
+
+    // We expand the area by the blur radius to give extra space for the blur transition.
+    if (m_type == BlurShadow) {
+        layerFloatRect.inflate(m_blurDistance);
+        inflation += m_blurDistance;
+    }
+
+    if (!clipRect.contains(enclosingIntRect(layerFloatRect))) {
+        // No need to have the buffer larger than the clip.
+        layerFloatRect.intersect(clipRect);
+
+        // If we are totally outside the clip region, we aren't painting at all.
+        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) {
+            layerFloatRect.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());
+    return enclosingIntRect(layerFloatRect);
+}
+#endif
+
+#if PLATFORM(CAIRO)
 void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect)
 {
     // Calculate the destination of the blurred layer.
@@ -173,5 +222,6 @@ void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const
             m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0);
     }
 }
+#endif
 
 } // namespace WebCore
diff --git a/WebCore/platform/graphics/ContextShadow.h b/WebCore/platform/graphics/ContextShadow.h
index fa778af..c0776bb 100644
--- a/WebCore/platform/graphics/ContextShadow.h
+++ b/WebCore/platform/graphics/ContextShadow.h
@@ -106,27 +106,41 @@ public:
     PlatformContext beginShadowLayer(PlatformContext, const FloatRect& layerArea);
     void endShadowLayer(PlatformContext);
     static void purgeScratchBuffer();
+    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;
+    // Buffer to where the temporary shadow will be drawn to.
     PlatformImage m_layerImage;
+    // Context used to paint the shadow to the layer image.
     PlatformContext m_layerContext;
-
+#if PLATFORM(QT)
+    // Sub-rect of m_layerImage that contains the shadow pixels.
+    FloatRect m_sourceRect;
+    // Top-left corner of the bounding rect where the shadow image needs to be drawn.
+    FloatPoint m_layerOrigin;
+#endif
+#if PLATFORM(CAIRO)
+    // Enclosing int rect where shadow needs to be drawn to using the layer context.
+    IntRect m_layerRect;
     // Used for reference when canvas scale(x,y) was called.
     FloatRect m_unscaledLayerRect;
+#endif
+    bool m_shadowsIgnoreTransforms;
 
     void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride);
-    void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect);
 #if PLATFORM(CAIRO)
+    void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect);
     void drawRectShadowWithoutTiling(PlatformContext context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha);
+#else
+    IntRect calculateLayerBoundingRect(const PlatformContext, const FloatRect& layerArea, const IntRect& clipRect);
 #endif
 };
 
diff --git a/WebCore/platform/graphics/qt/ContextShadowQt.cpp b/WebCore/platform/graphics/qt/ContextShadowQt.cpp
index f7c70f6..56e0673 100644
--- a/WebCore/platform/graphics/qt/ContextShadowQt.cpp
+++ b/WebCore/platform/graphics/qt/ContextShadowQt.cpp
@@ -114,24 +114,25 @@ 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 and 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());
+    // Set the origin as the top left corner of the scratch image.
+    const int frameSize = (m_sourceRect.width() - layerArea.width()) / 2;
+    m_layerContext->translate(-layerArea.x() + frameSize, -layerArea.y() + frameSize);
 
     return m_layerContext;
 }
@@ -155,13 +156,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/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 254235e..42e5618 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>
@@ -175,6 +174,22 @@ static inline Qt::FillRule toQtFillRule(WindRule rule)
     return Qt::OddEvenFill;
 }
 
+static inline bool mustUseContextShadow(QPainter* painter, ContextShadow* shadow)
+{
+    if (shadow->m_type == ContextShadow::BlurShadow)
+        // We can't avoid ContextShadow, since the shadow has blur.
+        return true;
+    if (!shadow->shadowsIgnoreTransforms())
+        // We can avoid ContextShadow and optimize, since we're not drawing on a canvas and box
+        // shadows are affected by the transformation matrix.
+        return false;
+    if (painter->transform().isIdentity())
+        // We can avoid ContextShadow, since there are no transformations to apply to the canvas.
+        return false;
+    // Otherwise, no chance avoiding ContextShadow.
+    return true;
+}
+
 class GraphicsContextPlatformPrivate : public Noncopyable {
 public:
     GraphicsContextPlatformPrivate(QPainter*, const QColor& initialSolidColor);
@@ -506,33 +521,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 (mustUseContextShadow(p, shadow) || 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;
@@ -557,28 +559,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 (mustUseContextShadow(p, shadow) || 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);
@@ -587,6 +569,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);
         }
     }
 
@@ -706,7 +695,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
         p->fillRect(normalizedRect, brush);
     } else {
         if (m_data->hasShadow()) {
-            if (shadow->m_type == ContextShadow::BlurShadow) {
+            if (mustUseContextShadow(p, shadow)) {
                 QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect);
                 if (shadowPainter) {
                     shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255);
@@ -714,17 +703,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);
             }
         }
 
@@ -744,18 +727,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 (mustUseContextShadow(p, shadow)) {
             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);
@@ -771,19 +751,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 (mustUseContextShadow(p, shadow)) {
             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));
@@ -971,9 +949,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