Changeset 93275 in webkit


Ignore:
Timestamp:
Aug 17, 2011 7:14:14 PM (13 years ago)
Author:
commit-queue@webkit.org
Message:

Canvas fill and fillRect with SourceIn, DestinationIn, SourceOut, DestinationAtop and Copy have errors
https://bugs.webkit.org/show_bug.cgi?id=66036

Source/WebCore:

These modes cannot be passed straight through to the underlying graphics context as the graphics context
and the HTML5 canvas spec have different interpretations to them. In the graphics context, the compositing
modes are applied just over the area being filled. In the HTML5 spec, the compositing modes are applied over
the entire canvas.

The SourceIn, DestinationIn, SourceOut, DestinationAtop and Copy modes all need some kind of extra action
to just performing the composited fill on the canvas, as they need t he canvas to be cleared outside of the
area being filled.

Previous to this change the Copy mode did not do this clearing at all. The other modes did but if the
transformed path being filled contained anti-aliasing at its edges artifacts were introduced.

With this change, Copy now does a complete erase of the canvas before performing a fill as per normal.
The other modes use a temporary buffer just big enough for the transformed path (in device coordinates).
The fill is first done there in SourceOver mode. Then this is drawn into the canvas context using the
appropriate mode, with any areas outside the draw area being cleared.

Patch by Ben Wells <benwells@chromium.org> on 2011-08-17
Reviewed by James Robinson.

Test: fast/canvas/canvas-composite-transformclip.html

  • html/HTMLCanvasElement.h:
  • html/canvas/CanvasRenderingContext2D.cpp:

(WebCore::CanvasRenderingContext2D::fill):
(WebCore::CanvasRenderingContext2D::fillRect):
(WebCore::CanvasRenderingContext2D::clearCanvas):
(WebCore::CanvasRenderingContext2D::transformAreaToDevice):
(WebCore::CanvasRenderingContext2D::fillAndDisplayTransparencyElsewhere):

  • html/canvas/CanvasRenderingContext2D.h:
  • platform/graphics/skia/ImageBufferSkia.cpp:

(WebCore::ImageBuffer::ImageBuffer):

LayoutTests:

Patch by Ben Wells <benwells@chromium.org> on 2011-08-17
Reviewed by James Robinson.

  • fast/canvas/canvas-composite-alpha.html:
  • fast/canvas/canvas-composite-transformclip-expected.txt: Added.
  • fast/canvas/canvas-composite-transformclip.html: Added.
  • platform/chromium-linux/fast/canvas/canvas-composite-expected.png:
  • platform/chromium-linux/fast/canvas/canvas-composite-transformclip-expected.png: Added.
  • platform/chromium/test_expectations.txt:
  • platform/mac/fast/canvas/canvas-composite-expected.png:
  • platform/mac/fast/canvas/canvas-composite-transformclip-expected.png: Added.
Location:
trunk
Files:
4 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r93251 r93275  
     12011-08-17  Ben Wells  <benwells@chromium.org>
     2
     3        Canvas fill and fillRect with SourceIn, DestinationIn, SourceOut, DestinationAtop and Copy have errors
     4        https://bugs.webkit.org/show_bug.cgi?id=66036
     5
     6        Reviewed by James Robinson.
     7
     8        * fast/canvas/canvas-composite-alpha.html:
     9        * fast/canvas/canvas-composite-transformclip-expected.txt: Added.
     10        * fast/canvas/canvas-composite-transformclip.html: Added.
     11        * platform/chromium-linux/fast/canvas/canvas-composite-expected.png:
     12        * platform/chromium-linux/fast/canvas/canvas-composite-transformclip-expected.png: Added.
     13        * platform/chromium/test_expectations.txt:
     14        * platform/mac/fast/canvas/canvas-composite-expected.png:
     15        * platform/mac/fast/canvas/canvas-composite-transformclip-expected.png: Added.
     16
    1172011-08-17  Tony Chang  <tony@chromium.org>
    218
  • trunk/LayoutTests/fast/canvas/canvas-composite-alpha.html

    r90723 r93275  
    186186          ],
    187187          [
    188               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 255, 0, 255] },
    189               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
    190               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 255, 0, 1] },
    191               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [255, 0, 0, 255] },
    192               { source: [0, 255, 0, 1], composition: [0, 255, 0, 1], destination: [255, 0, 0, 255] },
    193               { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 255, 0, 255] },
    194               { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [0, 255, 0, 127] },
    195               { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 255, 0, 127] },
    196               { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [0, 255, 0, 255] },
    197               { source: [127, 0, 0, 255], composition: [127, 0, 0, 255], destination: [0, 126, 0, 127] },
    198               { source: [126, 0, 0, 127], composition: [126, 0, 0, 127], destination: [0, 127, 0, 255] },
    199               { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [255, 0, 0, 63] },
    200               { source: [255, 127, 0, 32], composition: [255, 127, 0, 32], destination: [255, 64, 0, 63] },
    201               { source: [255, 0, 0, 191], composition: [255, 0, 0, 191], destination: [0, 255, 0, 127] },
    202               { source: [255, 0, 255, 191], composition: [255, 0, 255, 191], destination: [0, 255, 255, 127] }
     188              { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
     189              { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
     190              { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
     191              { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
     192              { source: [0, 255, 0, 1], composition: [0, 255, 0, 1], destination: [0, 0, 0, 0] },
     193              { source: [0, 0, 0, 0], composition: [0, 0, 0, 0], destination: [0, 0, 0, 0] },
     194              { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [0, 0, 0, 0] },
     195              { source: [255, 0, 0, 255], composition: [255, 0, 0, 255], destination: [0, 0, 0, 0] },
     196              { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [0, 0, 0, 0] },
     197              { source: [127, 0, 0, 255], composition: [127, 0, 0, 255], destination: [0, 0, 0, 0] },
     198              { source: [126, 0, 0, 127], composition: [126, 0, 0, 127], destination: [0, 0, 0, 0] },
     199              { source: [255, 0, 0, 127], composition: [255, 0, 0, 127], destination: [0, 0, 0, 0] },
     200              { source: [255, 127, 0, 32], composition: [255, 127, 0, 32], destination: [0, 0, 0, 0] },
     201              { source: [255, 0, 0, 191], composition: [255, 0, 0, 191], destination: [0, 0, 0, 0] },
     202              { source: [255, 0, 255, 191], composition: [255, 0, 255, 191], destination: [0, 0, 0, 0] }
    203203          ],
    204204          [
  • trunk/LayoutTests/platform/chromium/test_expectations.txt

    r93251 r93275  
    18881888BUGWK48288 : canvas/philip/tests/2d.composite.operation.clear.html = TEXT
    18891889BUGWK48289 : canvas/philip/tests/2d.composite.operation.darker.html = TEXT
    1890 BUGWK39177 : canvas/philip/tests/2d.composite.uncovered.fill.copy.html = TEXT
    18911890BUGWK39177 : canvas/philip/tests/2d.composite.uncovered.image.copy.html = TEXT
    18921891BUGWK39177 : canvas/philip/tests/2d.composite.uncovered.image.destination-atop.html = TEXT
     
    36473646BUGWK58013 LINUX GPU : compositing/scaling/tiled-layer-recursion.html = IMAGE
    36483647
     3648// Need rebaselining after canvas composite mode fixes
     3649BUGWK66036 MAC WIN GPU : fast/canvas/canvas-composite.html = IMAGE
     3650BUGWK66036 MAC WIN GPU : fast/canvas/canvas-composite-transformclip.html = IMAGE
    36493651
    36503652// Might need rebaseline.
  • trunk/Source/WebCore/ChangeLog

    r93274 r93275  
     12011-08-17  Ben Wells  <benwells@chromium.org>
     2
     3        Canvas fill and fillRect with SourceIn, DestinationIn, SourceOut, DestinationAtop and Copy have errors
     4        https://bugs.webkit.org/show_bug.cgi?id=66036
     5
     6        These modes cannot be passed straight through to the underlying graphics context as the graphics context
     7        and the HTML5 canvas spec have different interpretations to them. In the graphics context, the compositing
     8        modes are applied just over the area being filled. In the HTML5 spec, the compositing modes are applied over
     9        the entire canvas.
     10
     11        The SourceIn, DestinationIn, SourceOut, DestinationAtop and Copy modes all need some kind of extra action
     12        to just performing the composited fill on the canvas, as they need t he canvas to be cleared outside of the
     13        area being filled.
     14
     15        Previous to this change the Copy mode did not do this clearing at all. The other modes did but if the
     16        transformed path being filled contained anti-aliasing at its edges artifacts were introduced.
     17
     18        With this change, Copy now does a complete erase of the canvas before performing a fill as per normal.
     19        The other modes use a temporary buffer just big enough for the transformed path (in device coordinates).
     20        The fill is first done there in SourceOver mode. Then this is drawn into the canvas context using the
     21        appropriate mode, with any areas outside the draw area being cleared.
     22
     23        Reviewed by James Robinson.
     24
     25        Test: fast/canvas/canvas-composite-transformclip.html
     26
     27        * html/HTMLCanvasElement.h:
     28        * html/canvas/CanvasRenderingContext2D.cpp:
     29        (WebCore::CanvasRenderingContext2D::fill):
     30        (WebCore::CanvasRenderingContext2D::fillRect):
     31        (WebCore::CanvasRenderingContext2D::clearCanvas):
     32        (WebCore::CanvasRenderingContext2D::transformAreaToDevice):
     33        (WebCore::CanvasRenderingContext2D::fillAndDisplayTransparencyElsewhere):
     34        * html/canvas/CanvasRenderingContext2D.h:
     35        * platform/graphics/skia/ImageBufferSkia.cpp:
     36        (WebCore::ImageBuffer::ImageBuffer):
     37
    1382011-08-17  Emil A Eklund  <eae@chromium.org>
    239
  • trunk/Source/WebCore/html/HTMLCanvasElement.h

    r93157 r93275  
    131131    bool hasCreatedImageBuffer() const { return m_hasCreatedImageBuffer; }
    132132
     133    bool shouldAccelerate(const IntSize&) const;
     134
    133135private:
    134136    HTMLCanvasElement(const QualifiedName&, Document*);
     
    139141    void reset();
    140142
    141     bool shouldAccelerate(const IntSize&) const;
    142143    void createImageBuffer() const;
    143144
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp

    r93157 r93275  
    902902    if (!m_path.isEmpty()) {
    903903        if (shouldDisplayTransparencyElsewhere())
    904             displayTransparencyElsewhere<Path>(m_path);
    905 
    906         c->fillPath(m_path);
     904            fillAndDisplayTransparencyElsewhere(m_path);
     905        else if (state().m_globalComposite == CompositeCopy) {
     906            clearCanvas();
     907            c->fillPath(m_path);
     908        } else
     909            c->fillPath(m_path);
    907910        didDraw(m_path.boundingRect());
    908911    }
     
    10091012
    10101013    if (shouldDisplayTransparencyElsewhere())
    1011         displayTransparencyElsewhere<IntRect>(enclosingIntRect(rect));
    1012 
    1013     c->fillRect(rect);
     1014        fillAndDisplayTransparencyElsewhere(rect);
     1015    else if (state().m_globalComposite == CompositeCopy) {
     1016        clearCanvas();
     1017        c->fillRect(rect);
     1018    } else
     1019        c->fillRect(rect);
    10141020    didDraw(rect);
    10151021}
     
    14571463}
    14581464
     1465void CanvasRenderingContext2D::clearCanvas()
     1466{
     1467    FloatRect canvasRect(0, 0, canvas()->width(), canvas()->height());
     1468    GraphicsContext* c = drawingContext();
     1469
     1470    c->save();
     1471    c->setCTM(canvas()->baseTransform());
     1472    c->clearRect(canvasRect);
     1473    c->restore();
     1474}
     1475
    14591476bool CanvasRenderingContext2D::shouldDisplayTransparencyElsewhere() const
    14601477{
     
    14661483}
    14671484
    1468 template<class T> void CanvasRenderingContext2D::displayTransparencyElsewhere(const T& area)
     1485Path CanvasRenderingContext2D::transformAreaToDevice(const Path& path) const
     1486{
     1487    Path transformed(path);
     1488    transformed.transform(state().m_transform);
     1489    transformed.transform(canvas()->baseTransform());
     1490    return transformed;
     1491}
     1492
     1493Path CanvasRenderingContext2D::transformAreaToDevice(const FloatRect& rect) const
     1494{
     1495    Path path;
     1496    path.addRect(rect);
     1497    return transformAreaToDevice(path);
     1498}
     1499
     1500template<class T> void CanvasRenderingContext2D::fillAndDisplayTransparencyElsewhere(const T& area)
    14691501{
    14701502    ASSERT(shouldDisplayTransparencyElsewhere());
    14711503
     1504    Path path = transformAreaToDevice(area);
     1505    IntRect bufferRect = enclosingIntRect(path.boundingRect());
     1506    path.translate(FloatSize(-bufferRect.x(), -bufferRect.y()));
     1507
     1508    RenderingMode renderMode = canvas()->buffer()->isAccelerated() ? Accelerated : Unaccelerated;
     1509    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(bufferRect.size(), ColorSpaceDeviceRGB, renderMode);
     1510    buffer->context()->setCompositeOperation(CompositeSourceOver);
     1511    state().m_fillStyle->applyFillColor(buffer->context());
     1512    buffer->context()->fillPath(path);
     1513
    14721514    FloatRect canvasRect(0, 0, canvas()->width(), canvas()->height());
    1473     canvasRect = state().m_transform.inverse().mapRect(canvasRect);
     1515    canvasRect = canvas()->baseTransform().mapRect(canvasRect);
    14741516
    14751517    GraphicsContext* c = drawingContext();
    14761518    c->save();
    1477     c->clipOut(area);
    1478     c->setCompositeOperation(CompositeClear);
    1479     c->fillRect(canvasRect);
     1519    c->setCTM(AffineTransform());
     1520
     1521    c->save();
     1522    c->clipOut(bufferRect);
     1523    c->clearRect(canvasRect);
     1524    c->restore();
     1525
     1526    c->drawImageBuffer(buffer.get(), ColorSpaceDeviceRGB, bufferRect.location(), state().m_globalComposite);
    14801527    c->restore();
    14811528}
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h

    r93157 r93275  
    285285#endif
    286286
     287    void clearCanvas();
     288    Path transformAreaToDevice(const Path&) const;
     289    Path transformAreaToDevice(const FloatRect&) const;
    287290    bool shouldDisplayTransparencyElsewhere() const;
    288     template<class T> void displayTransparencyElsewhere(const T& area);
     291    template<class T> void fillAndDisplayTransparencyElsewhere(const T& area);
    289292
    290293    void prepareGradientForDashboard(CanvasGradient* gradient) const;
  • trunk/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp

    r93157 r93275  
    6666    : m_data(size)
    6767    , m_size(size)
     68    , m_accelerateRendering(false)
    6869{
    6970    OwnPtr<SkCanvas> canvas = adoptPtr(skia::CreateBitmapCanvas(size.width(), size.height(), false));
     
    8384    m_data.m_canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
    8485    if (renderingMode == Accelerated) {
     86        m_accelerateRendering = true;
    8587        GraphicsContext3D* context3D = SharedGraphicsContext3D::create(0);
    8688        if (context3D) {
Note: See TracChangeset for help on using the changeset viewer.