Changeset 74154 in webkit


Ignore:
Timestamp:
Dec 15, 2010 3:48:29 PM (13 years ago)
Author:
commit-queue@webkit.org
Message:

2010-12-15 Helder Correia <helder@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-15 Helder Correia <helder@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):
Location:
trunk
Files:
1 added
10 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r74146 r74154  
     12010-12-15  Helder Correia  <helder@sencha.com>
     2
     3        Reviewed by Ariya Hidayat.
     4
     5        [Qt] Canvas shadow offset should not be affected by any transformation
     6        https://bugs.webkit.org/show_bug.cgi?id=50422
     7
     8        On a canvas context, shadows are currently affected by all
     9        transformations except scaling. According to the spec:
     10        http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#shadows
     11
     12        "The shadowOffsetX and shadowOffsetY attributes specify the distance
     13        that the shadow will be offset in the positive horizontal and positive
     14        vertical distance respectively. Their values are in coordinate space
     15        units. They are not affected by the current transformation matrix."
     16
     17        NOTE: this applies only to canvas, not to box shadows.
     18
     19        Add new test to ensure that shadows are correctly transformed keeping
     20        the relative offset to the shape.
     21
     22        * fast/canvas/canvas-scale-strokePath-shadow-expected.txt:
     23        * fast/canvas/canvas-transforms-fillRect-shadow-expected.txt: Added.
     24        * fast/canvas/canvas-transforms-fillRect-shadow.html: Added.
     25        * fast/canvas/script-tests/canvas-scale-fillPath-shadow.js:
     26        * fast/canvas/script-tests/canvas-scale-fillRect-shadow.js:
     27        * fast/canvas/script-tests/canvas-scale-strokePath-shadow.js: Now using
     28          a lineWidth > 1 to make it easier to test and more fair among all
     29          ports, since there can be different transformation smoothness or
     30          aliasing settings.
     31        * fast/canvas/script-tests/canvas-transforms-fillRect-shadow.js: Added.
     32
    1332010-12-15  Kenji Imasaki  <imasaki@chromium.org>
    234
  • trunk/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow-expected.txt

    r74054 r74154  
    3131PASS d[1] is 0
    3232PASS d[2] is 0
    33 PASS d[3] is around 20
     33PASS d[3] is around 149
    3434PASS d[0] is 255
    3535PASS d[1] is 0
    3636PASS d[2] is 0
    37 PASS d[3] is around 22
     37PASS d[3] is around 116
    3838PASS d[0] is 255
    3939PASS d[1] is 0
    4040PASS d[2] is 0
    41 PASS d[3] is around 28
     41PASS d[3] is around 115
    4242PASS d[0] is 255
    4343PASS d[1] is 0
    4444PASS d[2] is 0
    45 PASS d[3] is around 22
     45PASS d[3] is around 70
    4646PASS d[0] is 255
    4747PASS d[1] is 0
    4848PASS d[2] is 0
    49 PASS d[3] is around 15
     49PASS d[3] is around 70
    5050PASS d[0] is 255
    5151PASS d[1] is 0
    5252PASS d[2] is 0
    53 PASS d[3] is around 17
     53PASS d[3] is around 69
    5454PASS successfullyParsed is true
    5555
  • trunk/LayoutTests/fast/canvas/canvas-transforms-fillRect-shadow-expected.txt

    r74153 r74154  
    1 Ensure correct behavior of canvas with path stroke + shadow after scaling. A blue and red checkered pattern should be displayed.
     1Ensure correct behavior of canvas with fillRect+shadow after translation+rotation+scaling. A blue and red checkered pattern should be displayed.
    22
    33On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
     
    1919PASS d[1] is 0
    2020PASS d[2] is 0
    21 PASS d[3] is around 76
     21PASS d[3] is around 127
    2222PASS d[0] is 255
    2323PASS d[1] is 0
    2424PASS d[2] is 0
    25 PASS d[3] is around 76
     25PASS d[3] is around 127
    2626PASS d[0] is 255
    2727PASS d[1] is 0
    2828PASS d[2] is 0
    29 PASS d[3] is around 76
     29PASS d[3] is around 127
    3030PASS d[0] is 255
    3131PASS d[1] is 0
    3232PASS d[2] is 0
    33 PASS d[3] is around 20
     33PASS d[3] is around 106
    3434PASS d[0] is 255
    3535PASS d[1] is 0
    3636PASS d[2] is 0
    37 PASS d[3] is around 22
     37PASS d[3] is around 106
    3838PASS d[0] is 255
    3939PASS d[1] is 0
    4040PASS d[2] is 0
    41 PASS d[3] is around 28
     41PASS d[3] is around 83
    4242PASS d[0] is 255
    4343PASS d[1] is 0
    4444PASS d[2] is 0
    45 PASS d[3] is around 22
     45PASS d[3] is around 36
    4646PASS d[0] is 255
    4747PASS d[1] is 0
    4848PASS d[2] is 0
    49 PASS d[3] is around 15
     49PASS d[3] is around 36
    5050PASS d[0] is 255
    5151PASS d[1] is 0
    5252PASS d[2] is 0
    53 PASS d[3] is around 17
     53PASS d[3] is around 36
    5454PASS successfullyParsed is true
    5555
  • trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-fillPath-shadow.js

    r74054 r74154  
    8080shouldBe('d[3]', '255');
    8181
    82 d = ctx.getImageData(299, 295, 1, 1).data;
     82d = ctx.getImageData(298, 295, 1, 1).data;
    8383shouldBe('d[0]', '255');
    8484shouldBe('d[1]', '0');
     
    8686shouldBe('d[3]', '255');
    8787
    88 d = ctx.getImageData(200, 299, 1, 1).data;
     88d = ctx.getImageData(200, 298, 1, 1).data;
    8989shouldBe('d[0]', '255');
    9090shouldBe('d[1]', '0');
     
    9999shouldBeAround('d[3]', '76');
    100100
    101 d = ctx.getImageData(299, 405, 1, 1).data;
     101d = ctx.getImageData(298, 405, 1, 1).data;
    102102shouldBe('d[0]', '255');
    103103shouldBe('d[1]', '0');
     
    105105shouldBeAround('d[3]', '76');
    106106
    107 d = ctx.getImageData(205, 499, 1, 1).data;
     107d = ctx.getImageData(205, 498, 1, 1).data;
    108108shouldBe('d[0]', '255');
    109109shouldBe('d[1]', '0');
  • trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-fillRect-shadow.js

    r74054 r74154  
    5959shouldBe('d[3]', '255');
    6060
    61 d = ctx.getImageData(299, 295, 1, 1).data;
     61d = ctx.getImageData(298, 298, 1, 1).data;
    6262shouldBe('d[0]', '255');
    6363shouldBe('d[1]', '0');
     
    6565shouldBe('d[3]', '255');
    6666
    67 d = ctx.getImageData(200, 299, 1, 1).data;
     67d = ctx.getImageData(201, 298, 1, 1).data;
    6868shouldBe('d[0]', '255');
    6969shouldBe('d[1]', '0');
     
    7878shouldBeAround('d[3]', '76');
    7979
    80 d = ctx.getImageData(299, 405, 1, 1).data;
     80d = ctx.getImageData(298, 405, 1, 1).data;
    8181shouldBe('d[0]', '255');
    8282shouldBe('d[1]', '0');
     
    8484shouldBeAround('d[3]', '76');
    8585
    86 d = ctx.getImageData(205, 499, 1, 1).data;
     86d = ctx.getImageData(205, 498, 1, 1).data;
    8787shouldBe('d[0]', '255');
    8888shouldBe('d[1]', '0');
  • trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js

    r74054 r74154  
    3636ctx.shadowOffsetY = 100;
    3737ctx.strokeStyle = 'rgba(0, 0, 255, 1)';
     38ctx.lineWidth = 5;
    3839
    3940ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
     
    7778
    7879// Verify solid shadow.
    79 d = ctx.getImageData(200, 205, 1, 1).data;
     80d = ctx.getImageData(250, 200, 1, 1).data;
    8081shouldBe('d[0]', '255');
    8182shouldBe('d[1]', '0');
     
    8384shouldBe('d[3]', '255');
    8485
    85 d = ctx.getImageData(299, 295, 1, 1).data;
     86d = ctx.getImageData(300, 290, 1, 1).data;
    8687shouldBe('d[0]', '255');
    8788shouldBe('d[1]', '0');
     
    8990shouldBe('d[3]', '255');
    9091
    91 d = ctx.getImageData(201, 299, 1, 1).data;
     92d = ctx.getImageData(200, 250, 1, 1).data;
    9293shouldBe('d[0]', '255');
    9394shouldBe('d[1]', '0');
     
    9697
    9798// Verify solid alpha shadow.
    98 d = ctx.getImageData(200, 405, 1, 1).data;
     99d = ctx.getImageData(201, 405, 1, 1).data;
    99100shouldBe('d[0]', '255');
    100101shouldBe('d[1]', '0');
     
    102103shouldBeAround('d[3]', '76');
    103104
    104 d = ctx.getImageData(299, 405, 1, 1).data;
     105d = ctx.getImageData(201, 500, 1, 1).data;
    105106shouldBe('d[0]', '255');
    106107shouldBe('d[1]', '0');
     
    108109shouldBeAround('d[3]', '76');
    109110
    110 d = ctx.getImageData(205, 499, 1, 1).data;
     111d = ctx.getImageData(300, 499, 1, 1).data;
    111112shouldBe('d[0]', '255');
    112113shouldBe('d[1]', '0');
     
    115116
    116117// Verify blurry shadow.
    117 d = ctx.getImageData(394, 208, 1, 1).data;
     118d = ctx.getImageData(404, 210, 1, 1).data;
    118119shouldBe('d[0]', '255');
    119120shouldBe('d[1]', '0');
    120121shouldBe('d[2]', '0');
    121 shouldBeAround('d[3]', '20');
     122shouldBeAround('d[3]', '149');
    122123
    123 d = ctx.getImageData(503, 301, 1, 1).data;
     124d = ctx.getImageData(505, 250, 1, 1).data;
    124125shouldBe('d[0]', '255');
    125126shouldBe('d[1]', '0');
    126127shouldBe('d[2]', '0');
    127 shouldBeAround('d[3]', '22');
     128shouldBeAround('d[3]', '116');
    128129
    129 d = ctx.getImageData(504, 250, 1, 1).data;
     130d = ctx.getImageData(450, 205, 1, 1).data;
    130131shouldBe('d[0]', '255');
    131132shouldBe('d[1]', '0');
    132133shouldBe('d[2]', '0');
    133 shouldBeAround('d[3]', '28');
     134shouldBeAround('d[3]', '115');
    134135
    135136// Verify blurry alpha shadow.
    136 d = ctx.getImageData(405, 405, 1, 1).data;
     137d = ctx.getImageData(505, 450, 1, 1).data;
    137138shouldBe('d[0]', '255');
    138139shouldBe('d[1]', '0');
    139140shouldBe('d[2]', '0');
    140 shouldBeAround('d[3]', '22');
     141shouldBeAround('d[3]', '70');
    141142
    142 d = ctx.getImageData(415, 495, 1, 1).data;
     143d = ctx.getImageData(505, 450, 1, 1).data;
    143144shouldBe('d[0]', '255');
    144145shouldBe('d[1]', '0');
    145146shouldBe('d[2]', '0');
    146 shouldBeAround('d[3]', '15');
     147shouldBeAround('d[3]', '70');
    147148
    148 d = ctx.getImageData(450, 504, 1, 1).data;
     149d = ctx.getImageData(450, 405, 1, 1).data;
    149150shouldBe('d[0]', '255');
    150151shouldBe('d[1]', '0');
    151152shouldBe('d[2]', '0');
    152 shouldBeAround('d[3]', '17');
     153shouldBeAround('d[3]', '69');
    153154
    154155var successfullyParsed = true;
  • trunk/LayoutTests/fast/canvas/script-tests/canvas-transforms-fillRect-shadow.js

    r74153 r74154  
    1 description("Ensure correct behavior of canvas with fillRect+shadow after scaling. A blue and red checkered pattern should be displayed.");
     1description("Ensure correct behavior of canvas with fillRect+shadow after translation+rotation+scaling. A blue and red checkered pattern should be displayed.");
    22
    33function print(message, color)
     
    2828var canvas = document.createElement('canvas');
    2929document.body.appendChild(canvas);
    30 canvas.setAttribute('width', '1000');
    31 canvas.setAttribute('height', '1000');
     30canvas.setAttribute('width', '600');
     31canvas.setAttribute('height', '600');
    3232var ctx = canvas.getContext('2d');
    3333
    34 ctx.scale(2, 2);
     34ctx.fillStyle = 'rgba(0, 0, 255, 1.0)';
    3535ctx.shadowOffsetX = 100;
    3636ctx.shadowOffsetY = 100;
    37 ctx.fillStyle = 'rgba(0, 0, 255, 1)';
     37
     38ctx.translate(-100, -100);
     39ctx.rotate(Math.PI/2);
     40ctx.scale(2, 2);
    3841
    3942ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
    40 ctx.fillRect(50, 50, 50, 50);
     43ctx.fillRect(100, -150, 50, 50);
    4144
    42 ctx.shadowColor = 'rgba(255, 0, 0, 0.3)';
    43 ctx.fillRect(50, 150, 50, 50);
     45ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
     46ctx.fillRect(200, -150, 50, 50);
    4447
     48ctx.shadowBlur = 5;
    4549ctx.shadowColor = 'rgba(255, 0, 0, 1.0)';
    46 ctx.shadowBlur = 10;
    47 ctx.fillRect(150, 50, 50, 50);
     50ctx.fillRect(100, -250, 50, 50);
    4851
    49 ctx.shadowColor = 'rgba(255, 0, 0, 0.3)';
    50 ctx.fillRect(150, 150, 50, 50);
     52ctx.shadowColor = 'rgba(255, 0, 0, 0.5)';
     53ctx.fillRect(200, -250, 50, 50);
    5154
    5255var d; // imageData.data
     
    5962shouldBe('d[3]', '255');
    6063
    61 d = ctx.getImageData(299, 295, 1, 1).data;
     64d = ctx.getImageData(298, 298, 1, 1).data;
    6265shouldBe('d[0]', '255');
    6366shouldBe('d[1]', '0');
     
    6568shouldBe('d[3]', '255');
    6669
    67 d = ctx.getImageData(200, 299, 1, 1).data;
     70d = ctx.getImageData(201, 298, 1, 1).data;
    6871shouldBe('d[0]', '255');
    6972shouldBe('d[1]', '0');
     
    7275
    7376// Verify solid alpha shadow.
    74 d = ctx.getImageData(200, 405, 1, 1).data;
     77d = ctx.getImageData(201, 401, 1, 1).data;
    7578shouldBe('d[0]', '255');
    7679shouldBe('d[1]', '0');
    7780shouldBe('d[2]', '0');
    78 shouldBeAround('d[3]', '76');
     81shouldBeAround('d[3]', '127');
    7982
    80 d = ctx.getImageData(299, 405, 1, 1).data;
     83d = ctx.getImageData(299, 450, 1, 1).data;
    8184shouldBe('d[0]', '255');
    8285shouldBe('d[1]', '0');
    8386shouldBe('d[2]', '0');
    84 shouldBeAround('d[3]', '76');
     87shouldBeAround('d[3]', '127');
    8588
    86 d = ctx.getImageData(205, 499, 1, 1).data;
     89d = ctx.getImageData(205, 498, 1, 1).data;
    8790shouldBe('d[0]', '255');
    8891shouldBe('d[1]', '0');
    8992shouldBe('d[2]', '0');
    90 shouldBeAround('d[3]', '76');
     93shouldBeAround('d[3]', '127');
    9194
    9295// Verify blurry shadow.
    93 d = ctx.getImageData(398, 205, 1, 1).data;
     96d = ctx.getImageData(399, 205, 1, 1).data;
     97shouldBe('d[0]', '255');
     98shouldBe('d[1]', '0');
     99shouldBe('d[2]', '0');
     100shouldBeAround('d[3]', '106');
     101
     102d = ctx.getImageData(500, 205, 1, 1).data;
     103shouldBe('d[0]', '255');
     104shouldBe('d[1]', '0');
     105shouldBe('d[2]', '0');
     106shouldBeAround('d[3]', '106');
     107
     108d = ctx.getImageData(499, 299, 1, 1).data;
    94109shouldBe('d[0]', '255');
    95110shouldBe('d[1]', '0');
    96111shouldBe('d[2]', '0');
    97112shouldBeAround('d[3]', '83');
    98 
    99 d = ctx.getImageData(501, 205, 1, 1).data;
    100 shouldBe('d[0]', '255');
    101 shouldBe('d[1]', '0');
    102 shouldBe('d[2]', '0');
    103 shouldBeAround('d[3]', '83');
    104 
    105 d = ctx.getImageData(500, 300, 1, 1).data;
    106 shouldBe('d[0]', '255');
    107 shouldBe('d[1]', '0');
    108 shouldBe('d[2]', '0');
    109 shouldBeAround('d[3]', '53');
    110113
    111114// Verify blurry alpha shadow.
     
    114117shouldBe('d[1]', '0');
    115118shouldBe('d[2]', '0');
    116 shouldBeAround('d[3]', '24');
     119shouldBeAround('d[3]', '36');
    117120
    118121d = ctx.getImageData(405, 501, 1, 1).data;
     
    120123shouldBe('d[1]', '0');
    121124shouldBe('d[2]', '0');
    122 shouldBeAround('d[3]', '24');
     125shouldBeAround('d[3]', '36');
    123126
    124127d = ctx.getImageData(405, 501, 1, 1).data;
     
    126129shouldBe('d[1]', '0');
    127130shouldBe('d[2]', '0');
    128 shouldBeAround('d[3]', '24');
     131shouldBeAround('d[3]', '36');
    129132
    130133var successfullyParsed = true;
  • trunk/WebCore/ChangeLog

    r74153 r74154  
     12010-12-15  Helder Correia  <helder@sencha.com>
     2
     3        Reviewed by Ariya Hidayat.
     4
     5        [Qt] Canvas shadow offset should not be affected by any transformation
     6        https://bugs.webkit.org/show_bug.cgi?id=50422
     7
     8        On a canvas context, shadows are currently affected by all
     9        transformations except scaling. According to the spec:
     10        http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#shadows
     11
     12        "The shadowOffsetX and shadowOffsetY attributes specify the distance
     13        that the shadow will be offset in the positive horizontal and positive
     14        vertical distance respectively. Their values are in coordinate space
     15        units. They are not affected by the current transformation matrix."
     16
     17        NOTE: this applies only to canvas, not to box shadows.
     18
     19        Test: fast/canvas/canvas-transforms-fillRect-shadow.html
     20
     21        * platform/graphics/ContextShadow.cpp:
     22        (WebCore::ContextShadow::ContextShadow):
     23        (WebCore::ContextShadow::calculateLayerBoundingRect):
     24        * platform/graphics/ContextShadow.h:
     25        (WebCore::ContextShadow::setShadowsIgnoreTransforms):
     26        (WebCore::ContextShadow::shadowsIgnoreTransforms):
     27        (WebCore::ContextShadow::offset):
     28        * platform/graphics/qt/ContextShadowQt.cpp:
     29        (WebCore::ContextShadow::beginShadowLayer):
     30        (WebCore::ContextShadow::endShadowLayer):
     31        * platform/graphics/qt/GraphicsContextQt.cpp:
     32        (WebCore::mustUseContextShadow):
     33        (WebCore::GraphicsContext::fillPath):
     34        (WebCore::GraphicsContext::strokePath):
     35        (WebCore::GraphicsContext::fillRect):
     36        (WebCore::GraphicsContext::fillRoundedRect):
     37        (WebCore::GraphicsContext::setPlatformShadow):
     38
    1392010-12-15  Timothy Hatcher  <timothy@apple.com>
    240
  • trunk/WebCore/platform/graphics/ContextShadow.cpp

    r74054 r74154  
    4242    , m_blurDistance(0)
    4343    , m_layerContext(0)
     44    , m_shadowsIgnoreTransforms(false)
    4445{
    4546}
     
    5051    , m_offset(offset)
    5152    , m_layerContext(0)
     53    , m_shadowsIgnoreTransforms(false)
    5254{
    5355    // See comments in http://webkit.org/b/40793, it seems sensible
     
    150152}
    151153
     154#if PLATFORM(QT)
     155IntRect ContextShadow::calculateLayerBoundingRect(const PlatformContext p, const FloatRect& layerArea, const IntRect& clipRect)
     156{
     157    // Calculate the destination of the blurred and/or transformed layer.
     158    FloatRect layerFloatRect;
     159    float inflation = 0;
     160
     161    const QTransform transform = p->transform();
     162    if (m_shadowsIgnoreTransforms && !transform.isIdentity()) {
     163        QPolygonF transformedPolygon = transform.map(QPolygonF(layerArea));
     164        transformedPolygon.translate(offset());
     165        layerFloatRect = transform.inverted().map(transformedPolygon).boundingRect();
     166    } else {
     167        layerFloatRect = layerArea;
     168        layerFloatRect.move(m_offset);
     169    }
     170
     171    // We expand the area by the blur radius to give extra space for the blur transition.
     172    if (m_type == BlurShadow) {
     173        layerFloatRect.inflate(m_blurDistance);
     174        inflation += m_blurDistance;
     175    }
     176
     177    FloatRect unclippedLayerRect = layerFloatRect;
     178
     179    if (!clipRect.contains(enclosingIntRect(layerFloatRect))) {
     180        // No need to have the buffer larger than the clip.
     181        layerFloatRect.intersect(clipRect);
     182
     183        // If we are totally outside the clip region, we aren't painting at all.
     184        if (layerFloatRect.isEmpty())
     185            return IntRect(0, 0, 0, 0);
     186
     187        // We adjust again because the pixels at the borders are still
     188        // potentially affected by the pixels outside the buffer.
     189        if (m_type == BlurShadow) {
     190            layerFloatRect.inflate(m_blurDistance);
     191            unclippedLayerRect.inflate(m_blurDistance);
     192            inflation += m_blurDistance;
     193        }
     194    }
     195
     196    const int frameSize = inflation * 2;
     197    m_sourceRect = IntRect(0, 0, layerArea.width() + frameSize, layerArea.height() + frameSize);
     198
     199    m_layerOrigin = FloatPoint(layerFloatRect.x(), layerFloatRect.y());
     200
     201    const FloatPoint m_unclippedLayerOrigin = FloatPoint(unclippedLayerRect.x(), unclippedLayerRect.y());
     202    const FloatSize clippedOut = m_unclippedLayerOrigin - m_layerOrigin;
     203
     204    // Set the origin as the top left corner of the scratch image, or, in case there's a clipped
     205    // out region, set the origin accordingly to the full bounding rect's top-left corner.
     206    const float translationX = -layerArea.x() + inflation - fabsf(clippedOut.width());
     207    const float translationY = -layerArea.y() + inflation - fabsf(clippedOut.height());
     208    m_layerContextTranslation = FloatPoint(translationX, translationY);
     209
     210    return enclosingIntRect(layerFloatRect);
     211}
     212#endif
     213
     214#if PLATFORM(CAIRO)
    152215void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect)
    153216{
     
    174237    }
    175238}
     239#endif
    176240
    177241} // namespace WebCore
  • trunk/WebCore/platform/graphics/ContextShadow.h

    r74054 r74154  
    107107    void endShadowLayer(PlatformContext);
    108108    static void purgeScratchBuffer();
     109    void setShadowsIgnoreTransforms(bool enable) { m_shadowsIgnoreTransforms = enable; }
     110    bool shadowsIgnoreTransforms() const { return m_shadowsIgnoreTransforms; }
    109111#if PLATFORM(CAIRO)
    110112    void drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius = IntSize(), const IntSize& topRightRadius = IntSize(), const IntSize& bottomLeftRadius = IntSize(), const IntSize& bottomRightRadius = IntSize());
    111113#endif
    112 
    113114#if PLATFORM(QT)
    114     QPointF offset() { return QPointF(m_offset.width(), m_offset.height()); }
     115    QPointF offset() const { return QPointF(m_offset.width(), m_offset.height()); }
    115116#endif
    116117
    117118
    118119private:
     120    // Buffer to where the temporary shadow will be drawn to.
     121    PlatformImage m_layerImage;
     122    // Context used to paint the shadow to the layer image.
     123    PlatformContext m_layerContext;
     124#if PLATFORM(QT)
     125    // Sub-rect of m_layerImage that contains the shadow pixels.
     126    FloatRect m_sourceRect;
     127    // Top-left corner of the (possibly clipped) bounding rect to draw the shadow to.
     128    FloatPoint m_layerOrigin;
     129    // Translation to apply to m_layerContext for the shadow to be correctly clipped.
     130    FloatPoint m_layerContextTranslation;
     131#endif
     132#if PLATFORM(CAIRO)
     133    // Enclosing int rect where shadow needs to be drawn to using the layer context.
    119134    IntRect m_layerRect;
    120     PlatformImage m_layerImage;
    121     PlatformContext m_layerContext;
    122 
    123135    // Used for reference when canvas scale(x,y) was called.
    124136    FloatRect m_unscaledLayerRect;
     137#endif
     138    bool m_shadowsIgnoreTransforms;
    125139
    126140    void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride);
     141#if PLATFORM(CAIRO)
    127142    void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect);
    128 #if PLATFORM(CAIRO)
    129143    void drawRectShadowWithoutTiling(PlatformContext context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha);
     144#else
     145    IntRect calculateLayerBoundingRect(const PlatformContext, const FloatRect& layerArea, const IntRect& clipRect);
    130146#endif
    131147};
  • trunk/WebCore/platform/graphics/qt/ContextShadowQt.cpp

    r74054 r74154  
    115115        clipRect = p->transform().inverted().mapRect(p->window());
    116116
    117     m_unscaledLayerRect = layerArea;
    118     calculateLayerBoundingRect(layerArea, IntRect(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height()));
     117    // Set m_layerOrigin, m_layerContextTranslation, m_sourceRect.
     118    IntRect clip(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
     119    IntRect layerRect = calculateLayerBoundingRect(p, layerArea, clip);
    119120
    120121    // Don't paint if we are totally outside the clip region.
    121     if (m_layerRect.isEmpty())
     122    if (layerRect.isEmpty())
    122123        return 0;
    123124
    124125    ShadowBuffer* shadowBuffer = scratchShadowBuffer();
    125     QImage* shadowImage = shadowBuffer->scratchImage(m_layerRect.size());
     126    QImage* shadowImage = shadowBuffer->scratchImage(layerRect.size());
    126127    m_layerImage = QImage(*shadowImage);
    127128
     
    129130    m_layerContext->begin(&m_layerImage);
    130131    m_layerContext->setFont(p->font());
    131     m_layerContext->translate(m_offset.width(), m_offset.height());
    132 
    133     // The origin is now the top left corner of the scratch image.
    134     m_layerContext->translate(-m_layerRect.x(), -m_layerRect.y());
    135 
     132    m_layerContext->translate(m_layerContextTranslation);
    136133    return m_layerContext;
    137134}
     
    156153    }
    157154
    158     const QTransform transform = p->transform();
    159     if (transform.isScaling()) {
    160         qreal x = m_unscaledLayerRect.x() + m_offset.width()  / transform.m11() - m_blurDistance;
    161         qreal y = m_unscaledLayerRect.y() + m_offset.height() / transform.m22() - m_blurDistance;
    162         p->drawImage(QPointF(x, y), m_layerImage);
    163     } else
    164         p->drawImage(m_layerRect.topLeft(), m_layerImage);
     155    p->drawImage(m_layerOrigin, m_layerImage, m_sourceRect);
    165156
    166157    scratchShadowBuffer()->schedulePurge();
  • trunk/WebCore/platform/graphics/qt/GraphicsContextQt.cpp

    r74069 r74154  
    5454
    5555#include <QBrush>
    56 #include <QDebug>
    5756#include <QGradient>
    5857#include <QPaintDevice>
     
    176175}
    177176
     177static inline bool mustUseContextShadow(QPainter* painter, ContextShadow* shadow)
     178{
     179    if (shadow->m_type == ContextShadow::BlurShadow)
     180        // We can't avoid ContextShadow, since the shadow has blur.
     181        return true;
     182    if (!shadow->shadowsIgnoreTransforms())
     183        // We can avoid ContextShadow and optimize, since we're not drawing on a canvas and box
     184        // shadows are affected by the transformation matrix.
     185        return false;
     186    if (painter->transform().isIdentity())
     187        // We can avoid ContextShadow, since there are no transformations to apply to the canvas.
     188        return false;
     189    // Otherwise, no chance avoiding ContextShadow.
     190    return true;
     191}
     192
    178193class GraphicsContextPlatformPrivate : public Noncopyable {
    179194public:
     
    507522    if (m_data->hasShadow()) {
    508523        ContextShadow* shadow = contextShadow();
    509         if (shadow->m_type != ContextShadow::BlurShadow
    510             && !m_state.fillPattern && !m_state.fillGradient)
     524        if (mustUseContextShadow(p, shadow) || m_state.fillPattern || m_state.fillGradient)
    511525        {
    512             QPointF offset = shadow->offset();
    513             const QTransform& transform = p->transform();
    514             if (transform.isScaling()) {
    515                 // If scaling is required, find the new coord for shadow origin,
    516                 // so that the relative offset to its shape is kept.
    517                 QPointF translatedOffset(offset.x() / transform.m11(),
    518                                          offset.y() / transform.m22());
    519                 platformPath.translate(translatedOffset);
    520                 p->fillPath(platformPath, QColor(shadow->m_color));
    521                 platformPath.translate(-translatedOffset);
    522             } else {
    523                 p->translate(offset);
    524                 p->fillPath(platformPath, QColor(shadow->m_color));
    525                 p->translate(-offset);
    526             }
    527         } else {
    528526            QPainter* shadowPainter = shadow->beginShadowLayer(p, platformPath.controlPointRect());
    529527            if (shadowPainter) {
     
    532530                shadow->endShadowLayer(p);
    533531            }
     532        } else {
     533            QPointF offset = shadow->offset();
     534            p->translate(offset);
     535            p->fillPath(platformPath, QColor(shadow->m_color));
     536            p->translate(-offset);
    534537        }
    535 
    536538    }
    537539    if (m_state.fillPattern) {
     
    558560    if (m_data->hasShadow()) {
    559561        ContextShadow* shadow = contextShadow();
    560 
    561         if (shadow->m_type != ContextShadow::BlurShadow
    562             && !m_state.strokePattern && !m_state.strokeGradient)
     562        if (mustUseContextShadow(p, shadow) || m_state.strokePattern || m_state.strokeGradient)
    563563        {
    564             QPen shadowPen(pen);
    565             shadowPen.setColor(m_data->shadow.m_color);
    566             QPointF offset = shadow->offset();
    567             const QTransform& transform = p->transform();
    568             if (transform.isScaling()) {
    569                 // If scaling is required, find the new coord for shadow origin,
    570                 // so that the relative offset to its shape is kept.
    571                 QPointF translatedOffset(offset.x() / transform.m11(),
    572                                          offset.y() / transform.m22());
    573                 platformPath.translate(translatedOffset);
    574                 p->strokePath(platformPath, shadowPen);
    575                 platformPath.translate(-translatedOffset);
    576             } else {
    577                 p->translate(offset);
    578                 p->strokePath(platformPath, shadowPen);
    579                 p->translate(-offset);
    580             }
    581         } else {
    582564            FloatRect boundingRect = platformPath.controlPointRect();
    583565            boundingRect.inflate(pen.miterLimit() + pen.widthF());
     
    588570                shadow->endShadowLayer(p);
    589571            }
     572        } else {
     573            QPen shadowPen(pen);
     574            shadowPen.setColor(m_data->shadow.m_color);
     575            QPointF offset = shadow->offset();
     576            p->translate(offset);
     577            p->strokePath(platformPath, shadowPen);
     578            p->translate(-offset);
    590579        }
    591580    }
     
    707696    } else {
    708697        if (m_data->hasShadow()) {
    709             if (shadow->m_type == ContextShadow::BlurShadow) {
     698            if (mustUseContextShadow(p, shadow)) {
    710699                QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect);
    711700                if (shadowPainter) {
     
    715704                }
    716705            } else {
    717                 // Solid rectangle fill with no blur shadow can be done faster
    718                 // without using the shadow layer at all.
     706                // Solid rectangle fill with no blur shadow or transformations applied can be done
     707                // faster without using the shadow layer at all.
    719708                QColor shadowColor = shadow->m_color;
    720709                shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF());
    721                 const QTransform& transform = p->transform();
    722                 if (transform.isScaling()) {
    723                     p->fillRect(normalizedRect.translated(static_cast<qreal>(shadow->offset().x()) / transform.m11(),
    724                                                           static_cast<qreal>(shadow->offset().y()  / transform.m22())),
    725                                 shadowColor);
    726                 } else
    727                     p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor);
     710                p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor);
    728711            }
    729712        }
     
    745728    if (m_data->hasShadow()) {
    746729        ContextShadow* shadow = contextShadow();
    747 
    748         if (shadow->m_type != ContextShadow::BlurShadow) {
    749             // We do not need any layer for simple shadow.
    750             p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color);
    751         } else {
     730        if (mustUseContextShadow(p, shadow)) {
    752731            QPainter* shadowPainter = shadow->beginShadowLayer(p, normalizedRect);
    753732            if (shadowPainter) {
     
    756735                shadow->endShadowLayer(p);
    757736            }
    758         }
     737        } else
     738            p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color);
    759739    }
    760740
     
    772752    if (m_data->hasShadow()) {
    773753        ContextShadow* shadow = contextShadow();
    774 
    775         if (shadow->m_type != ContextShadow::BlurShadow) {
    776             // We do not need any layer for simple shadow.
    777             p->translate(m_data->shadow.offset());
    778             p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
    779             p->translate(-m_data->shadow.offset());
    780         } else {
     754        if (mustUseContextShadow(p, shadow)) {
    781755            QPainter* shadowPainter = shadow->beginShadowLayer(p, rect);
    782756            if (shadowPainter) {
     
    785759                shadow->endShadowLayer(p);
    786760            }
     761        } else {
     762            p->translate(m_data->shadow.offset());
     763            p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
     764            p->translate(-m_data->shadow.offset());
    787765        }
    788766    }
     
    954932        m_state.shadowOffset = FloatSize(size.width(), -size.height());
    955933        m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
    956     } else {
     934    } else
    957935        m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
    958     }
     936
     937    m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
    959938}
    960939
Note: See TracChangeset for help on using the changeset viewer.