Changeset 74040 in webkit


Ignore:
Timestamp:
Dec 14, 2010 10:30:34 AM (13 years ago)
Author:
commit-queue@webkit.org
Message:

2010-12-14 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-14 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

    r74039 r74040  
     12010-12-14  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-14  Pavel Feldman  <pfeldman@chromium.org>
    234
  • trunk/LayoutTests/fast/canvas/canvas-scale-strokePath-shadow-expected.txt

    r72900 r74040  
    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

    r74039 r74040  
    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

    r72898 r74040  
    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

    r72784 r74040  
    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

    r72900 r74040  
    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

    r74039 r74040  
    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

    r74038 r74040  
     12010-12-14  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-14  Alexander Pavlov  <apavlov@chromium.org>
    240
  • trunk/WebCore/platform/graphics/ContextShadow.cpp

    r69701 r74040  
    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    if (!clipRect.contains(enclosingIntRect(layerFloatRect))) {
     178        // No need to have the buffer larger than the clip.
     179        layerFloatRect.intersect(clipRect);
     180
     181        // If we are totally outside the clip region, we aren't painting at all.
     182        if (layerFloatRect.isEmpty())
     183            return IntRect(0, 0, 0, 0);
     184
     185        // We adjust again because the pixels at the borders are still
     186        // potentially affected by the pixels outside the buffer.
     187        if (m_type == BlurShadow) {
     188            layerFloatRect.inflate(m_blurDistance);
     189            inflation += m_blurDistance;
     190        }
     191    }
     192
     193    const int frameSize = inflation * 2;
     194    m_sourceRect = IntRect(0, 0, layerArea.width() + frameSize, layerArea.height() + frameSize);
     195    m_layerOrigin = FloatPoint(layerFloatRect.x(), layerFloatRect.y());
     196    return enclosingIntRect(layerFloatRect);
     197}
     198#endif
     199
     200#if PLATFORM(CAIRO)
    152201void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect)
    153202{
     
    174223    }
    175224}
     225#endif
    176226
    177227} // namespace WebCore
  • trunk/WebCore/platform/graphics/ContextShadow.h

    r72987 r74040  
    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 bounding rect where the shadow image needs to be drawn.
     128    FloatPoint m_layerOrigin;
     129#endif
     130#if PLATFORM(CAIRO)
     131    // Enclosing int rect where shadow needs to be drawn to using the layer context.
    119132    IntRect m_layerRect;
    120     PlatformImage m_layerImage;
    121     PlatformContext m_layerContext;
    122 
    123133    // Used for reference when canvas scale(x,y) was called.
    124134    FloatRect m_unscaledLayerRect;
     135#endif
     136    bool m_shadowsIgnoreTransforms;
    125137
    126138    void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride);
     139#if PLATFORM(CAIRO)
    127140    void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect);
    128 #if PLATFORM(CAIRO)
    129141    void drawRectShadowWithoutTiling(PlatformContext context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha);
     142#else
     143    IntRect calculateLayerBoundingRect(const PlatformContext, const FloatRect& layerArea, const IntRect& clipRect);
    130144#endif
    131145};
  • trunk/WebCore/platform/graphics/qt/ContextShadowQt.cpp

    r72784 r74040  
    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 and 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());
    132132
    133     // The origin is now the top left corner of the scratch image.
    134     m_layerContext->translate(-m_layerRect.x(), -m_layerRect.y());
     133    // Set the origin as the top left corner of the scratch image.
     134    const int frameSize = (m_sourceRect.width() - layerArea.width()) / 2;
     135    m_layerContext->translate(-layerArea.x() + frameSize, -layerArea.y() + frameSize);
    135136
    136137    return m_layerContext;
     
    156157    }
    157158
    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);
     159    p->drawImage(m_layerOrigin, m_layerImage, m_sourceRect);
    165160
    166161    scratchShadowBuffer()->schedulePurge();
  • trunk/WebCore/platform/graphics/qt/GraphicsContextQt.cpp

    r73729 r74040  
    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    }
     
    972950        m_state.shadowOffset = FloatSize(size.width(), -size.height());
    973951        m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
    974     } else {
     952    } else
    975953        m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
    976     }
     954
     955    m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
    977956}
    978957
Note: See TracChangeset for help on using the changeset viewer.