CanvasRenderingContext2D.cpp revision 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00
1/*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "CanvasRenderingContext2D.h"
33
34#include "AffineTransform.h"
35#include "CSSMutableStyleDeclaration.h"
36#include "CSSParser.h"
37#include "CSSPropertyNames.h"
38#include "CSSStyleSelector.h"
39#include "CachedImage.h"
40#include "CanvasGradient.h"
41#include "CanvasPattern.h"
42#include "CanvasStyle.h"
43#include "ExceptionCode.h"
44#include "FloatConversion.h"
45#include "GraphicsContext.h"
46#include "HTMLCanvasElement.h"
47#include "HTMLImageElement.h"
48#include "HTMLMediaElement.h"
49#include "HTMLNames.h"
50#include "HTMLVideoElement.h"
51#include "ImageBuffer.h"
52#include "ImageData.h"
53#include "KURL.h"
54#include "Page.h"
55#include "RenderHTMLCanvas.h"
56#include "SecurityOrigin.h"
57#include "Settings.h"
58#include "StrokeStyleApplier.h"
59#include "TextMetrics.h"
60#include "TextRun.h"
61
62#if ENABLE(ACCELERATED_2D_CANVAS)
63#include "Chrome.h"
64#include "ChromeClient.h"
65#include "DrawingBuffer.h"
66#include "FrameView.h"
67#include "GraphicsContext3D.h"
68#include "SharedGraphicsContext3D.h"
69#if USE(ACCELERATED_COMPOSITING)
70#include "RenderLayer.h"
71#endif
72#endif
73
74#include <wtf/ByteArray.h>
75#include <wtf/MathExtras.h>
76#include <wtf/OwnPtr.h>
77#include <wtf/UnusedParam.h>
78
79using namespace std;
80
81namespace WebCore {
82
83using namespace HTMLNames;
84
85static const char* const defaultFont = "10px sans-serif";
86
87
88class CanvasStrokeStyleApplier : public StrokeStyleApplier {
89public:
90    CanvasStrokeStyleApplier(CanvasRenderingContext2D* canvasContext)
91        : m_canvasContext(canvasContext)
92    {
93    }
94
95    virtual void strokeStyle(GraphicsContext* c)
96    {
97        c->setStrokeThickness(m_canvasContext->lineWidth());
98        c->setLineCap(m_canvasContext->getLineCap());
99        c->setLineJoin(m_canvasContext->getLineJoin());
100        c->setMiterLimit(m_canvasContext->miterLimit());
101    }
102
103private:
104    CanvasRenderingContext2D* m_canvasContext;
105};
106
107CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode)
108    : CanvasRenderingContext(canvas)
109    , m_stateStack(1)
110    , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
111#if ENABLE(DASHBOARD_SUPPORT)
112    , m_usesDashboardCompatibilityMode(usesDashboardCompatibilityMode)
113#endif
114#if ENABLE(ACCELERATED_2D_CANVAS)
115    , m_context3D(0)
116#endif
117{
118#if !ENABLE(DASHBOARD_SUPPORT)
119    ASSERT_UNUSED(usesDashboardCompatibilityMode, !usesDashboardCompatibilityMode);
120#endif
121
122    // Make sure that even if the drawingContext() has a different default
123    // thickness, it is in sync with the canvas thickness.
124    setLineWidth(lineWidth());
125
126#if ENABLE(ACCELERATED_2D_CANVAS)
127    Page* p = canvas->document()->page();
128    if (!p)
129        return;
130    if (!p->settings()->accelerated2dCanvasEnabled())
131        return;
132    if (GraphicsContext* c = drawingContext()) {
133        m_context3D = p->sharedGraphicsContext3D();
134        if (m_context3D) {
135            m_drawingBuffer = m_context3D->graphicsContext3D()->createDrawingBuffer(IntSize(canvas->width(), canvas->height()));
136            if (!m_drawingBuffer) {
137                c->setSharedGraphicsContext3D(0, 0, IntSize());
138                m_context3D.clear();
139            } else
140                c->setSharedGraphicsContext3D(m_context3D.get(), m_drawingBuffer.get(), IntSize(canvas->width(), canvas->height()));
141        }
142    }
143#endif
144}
145
146CanvasRenderingContext2D::~CanvasRenderingContext2D()
147{
148}
149
150bool CanvasRenderingContext2D::isAccelerated() const
151{
152#if USE(IOSURFACE_CANVAS_BACKING_STORE)
153    ImageBuffer* buffer = canvas()->buffer();
154    return buffer ? buffer->isAccelerated() : false;
155#elif ENABLE(ACCELERATED_2D_CANVAS)
156    return m_context3D;
157#else
158    return false;
159#endif
160}
161
162bool CanvasRenderingContext2D::paintsIntoCanvasBuffer() const
163{
164#if ENABLE(ACCELERATED_2D_CANVAS)
165    if (m_context3D)
166        return m_context3D->paintsIntoCanvasBuffer();
167#endif
168    return true;
169}
170
171
172void CanvasRenderingContext2D::reset()
173{
174    m_stateStack.resize(1);
175    m_stateStack.first() = State();
176    m_path.clear();
177#if ENABLE(ACCELERATED_2D_CANVAS)
178    if (GraphicsContext* c = drawingContext()) {
179        if (m_context3D && m_drawingBuffer) {
180            if (m_drawingBuffer->reset(IntSize(canvas()->width(), canvas()->height()))) {
181                c->setSharedGraphicsContext3D(m_context3D.get(), m_drawingBuffer.get(), IntSize(canvas()->width(), canvas()->height()));
182#if USE(ACCELERATED_COMPOSITING)
183                RenderBox* renderBox = canvas()->renderBox();
184                if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing())
185                    renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
186#endif
187            } else {
188                c->setSharedGraphicsContext3D(0, 0, IntSize());
189                m_drawingBuffer.clear();
190                m_context3D.clear();
191            }
192        }
193    }
194#endif
195}
196
197CanvasRenderingContext2D::State::State()
198    : m_strokeStyle(CanvasStyle::createFromRGBA(Color::black))
199    , m_fillStyle(CanvasStyle::createFromRGBA(Color::black))
200    , m_lineWidth(1)
201    , m_lineCap(ButtCap)
202    , m_lineJoin(MiterJoin)
203    , m_miterLimit(10)
204    , m_shadowBlur(0)
205    , m_shadowColor(Color::transparent)
206    , m_globalAlpha(1)
207    , m_globalComposite(CompositeSourceOver)
208    , m_invertibleCTM(true)
209    , m_textAlign(StartTextAlign)
210    , m_textBaseline(AlphabeticTextBaseline)
211    , m_unparsedFont(defaultFont)
212    , m_realizedFont(false)
213{
214}
215
216CanvasRenderingContext2D::State::State(const State& other)
217    : FontSelectorClient()
218{
219    m_unparsedStrokeColor = other.m_unparsedStrokeColor;
220    m_unparsedFillColor = other.m_unparsedFillColor;
221    m_strokeStyle = other.m_strokeStyle;
222    m_fillStyle = other.m_fillStyle;
223    m_lineWidth = other.m_lineWidth;
224    m_lineCap = other.m_lineCap;
225    m_lineJoin = other.m_lineJoin;
226    m_miterLimit = other.m_miterLimit;
227    m_shadowOffset = other.m_shadowOffset;
228    m_shadowBlur = other.m_shadowBlur;
229    m_shadowColor = other.m_shadowColor;
230    m_globalAlpha = other.m_globalAlpha;
231    m_globalComposite = other.m_globalComposite;
232    m_transform = other.m_transform;
233    m_invertibleCTM = other.m_invertibleCTM;
234    m_textAlign = other.m_textAlign;
235    m_textBaseline = other.m_textBaseline;
236    m_unparsedFont = other.m_unparsedFont;
237    m_font = other.m_font;
238    m_realizedFont = other.m_realizedFont;
239
240    if (m_realizedFont)
241        m_font.fontSelector()->registerForInvalidationCallbacks(this);
242}
243
244CanvasRenderingContext2D::State& CanvasRenderingContext2D::State::operator=(const State& other)
245{
246    if (this == &other)
247        return *this;
248
249    if (m_realizedFont)
250        m_font.fontSelector()->unregisterForInvalidationCallbacks(this);
251
252    m_unparsedStrokeColor = other.m_unparsedStrokeColor;
253    m_unparsedFillColor = other.m_unparsedFillColor;
254    m_strokeStyle = other.m_strokeStyle;
255    m_fillStyle = other.m_fillStyle;
256    m_lineWidth = other.m_lineWidth;
257    m_lineCap = other.m_lineCap;
258    m_lineJoin = other.m_lineJoin;
259    m_miterLimit = other.m_miterLimit;
260    m_shadowOffset = other.m_shadowOffset;
261    m_shadowBlur = other.m_shadowBlur;
262    m_shadowColor = other.m_shadowColor;
263    m_globalAlpha = other.m_globalAlpha;
264    m_globalComposite = other.m_globalComposite;
265    m_transform = other.m_transform;
266    m_invertibleCTM = other.m_invertibleCTM;
267    m_textAlign = other.m_textAlign;
268    m_textBaseline = other.m_textBaseline;
269    m_unparsedFont = other.m_unparsedFont;
270    m_font = other.m_font;
271    m_realizedFont = other.m_realizedFont;
272
273    if (m_realizedFont)
274        m_font.fontSelector()->registerForInvalidationCallbacks(this);
275
276    return *this;
277}
278
279CanvasRenderingContext2D::State::~State()
280{
281    if (m_realizedFont)
282        m_font.fontSelector()->unregisterForInvalidationCallbacks(this);
283}
284
285void CanvasRenderingContext2D::State::fontsNeedUpdate(FontSelector* fontSelector)
286{
287    ASSERT_ARG(fontSelector, fontSelector == m_font.fontSelector());
288    ASSERT(m_realizedFont);
289
290    m_font.update(fontSelector);
291}
292
293void CanvasRenderingContext2D::save()
294{
295    ASSERT(m_stateStack.size() >= 1);
296    m_stateStack.append(state());
297    GraphicsContext* c = drawingContext();
298    if (!c)
299        return;
300    c->save();
301}
302
303void CanvasRenderingContext2D::restore()
304{
305    ASSERT(m_stateStack.size() >= 1);
306    if (m_stateStack.size() <= 1)
307        return;
308    m_path.transform(state().m_transform);
309    m_stateStack.removeLast();
310    m_path.transform(state().m_transform.inverse());
311    GraphicsContext* c = drawingContext();
312    if (!c)
313        return;
314    c->restore();
315}
316
317void CanvasRenderingContext2D::setAllAttributesToDefault()
318{
319    state().m_globalAlpha = 1;
320    state().m_shadowOffset = FloatSize();
321    state().m_shadowBlur = 0;
322    state().m_shadowColor = Color::transparent;
323    state().m_globalComposite = CompositeSourceOver;
324
325    GraphicsContext* context = drawingContext();
326    if (!context)
327        return;
328
329    context->setLegacyShadow(FloatSize(), 0, Color::transparent, ColorSpaceDeviceRGB);
330    context->setAlpha(1);
331    context->setCompositeOperation(CompositeSourceOver);
332}
333
334CanvasStyle* CanvasRenderingContext2D::strokeStyle() const
335{
336    return state().m_strokeStyle.get();
337}
338
339void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> style)
340{
341    if (!style)
342        return;
343
344    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style))
345        return;
346
347    if (style->isCurrentColor()) {
348        if (style->hasOverrideAlpha())
349            style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha()));
350        else
351            style = CanvasStyle::createFromRGBA(currentColor(canvas()));
352    } else
353        checkOrigin(style->canvasPattern());
354
355    state().m_strokeStyle = style;
356    GraphicsContext* c = drawingContext();
357    if (!c)
358        return;
359    state().m_strokeStyle->applyStrokeColor(c);
360    state().m_unparsedStrokeColor = String();
361}
362
363CanvasStyle* CanvasRenderingContext2D::fillStyle() const
364{
365    return state().m_fillStyle.get();
366}
367
368void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> style)
369{
370    if (!style)
371        return;
372
373    if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style))
374        return;
375
376    if (style->isCurrentColor()) {
377        if (style->hasOverrideAlpha())
378            style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha()));
379        else
380            style = CanvasStyle::createFromRGBA(currentColor(canvas()));
381    } else
382        checkOrigin(style->canvasPattern());
383
384    state().m_fillStyle = style;
385    GraphicsContext* c = drawingContext();
386    if (!c)
387        return;
388    state().m_fillStyle->applyFillColor(c);
389    state().m_unparsedFillColor = String();
390}
391
392float CanvasRenderingContext2D::lineWidth() const
393{
394    return state().m_lineWidth;
395}
396
397void CanvasRenderingContext2D::setLineWidth(float width)
398{
399    if (!(isfinite(width) && width > 0))
400        return;
401    state().m_lineWidth = width;
402    GraphicsContext* c = drawingContext();
403    if (!c)
404        return;
405    c->setStrokeThickness(width);
406}
407
408String CanvasRenderingContext2D::lineCap() const
409{
410    return lineCapName(state().m_lineCap);
411}
412
413void CanvasRenderingContext2D::setLineCap(const String& s)
414{
415    LineCap cap;
416    if (!parseLineCap(s, cap))
417        return;
418    state().m_lineCap = cap;
419    GraphicsContext* c = drawingContext();
420    if (!c)
421        return;
422    c->setLineCap(cap);
423}
424
425String CanvasRenderingContext2D::lineJoin() const
426{
427    return lineJoinName(state().m_lineJoin);
428}
429
430void CanvasRenderingContext2D::setLineJoin(const String& s)
431{
432    LineJoin join;
433    if (!parseLineJoin(s, join))
434        return;
435    state().m_lineJoin = join;
436    GraphicsContext* c = drawingContext();
437    if (!c)
438        return;
439    c->setLineJoin(join);
440}
441
442float CanvasRenderingContext2D::miterLimit() const
443{
444    return state().m_miterLimit;
445}
446
447void CanvasRenderingContext2D::setMiterLimit(float limit)
448{
449    if (!(isfinite(limit) && limit > 0))
450        return;
451    state().m_miterLimit = limit;
452    GraphicsContext* c = drawingContext();
453    if (!c)
454        return;
455    c->setMiterLimit(limit);
456}
457
458float CanvasRenderingContext2D::shadowOffsetX() const
459{
460    return state().m_shadowOffset.width();
461}
462
463void CanvasRenderingContext2D::setShadowOffsetX(float x)
464{
465    if (!isfinite(x))
466        return;
467    state().m_shadowOffset.setWidth(x);
468    applyShadow();
469}
470
471float CanvasRenderingContext2D::shadowOffsetY() const
472{
473    return state().m_shadowOffset.height();
474}
475
476void CanvasRenderingContext2D::setShadowOffsetY(float y)
477{
478    if (!isfinite(y))
479        return;
480    state().m_shadowOffset.setHeight(y);
481    applyShadow();
482}
483
484float CanvasRenderingContext2D::shadowBlur() const
485{
486    return state().m_shadowBlur;
487}
488
489void CanvasRenderingContext2D::setShadowBlur(float blur)
490{
491    if (!(isfinite(blur) && blur >= 0))
492        return;
493    state().m_shadowBlur = blur;
494    applyShadow();
495}
496
497String CanvasRenderingContext2D::shadowColor() const
498{
499    return Color(state().m_shadowColor).serialized();
500}
501
502void CanvasRenderingContext2D::setShadowColor(const String& color)
503{
504    if (!parseColorOrCurrentColor(state().m_shadowColor, color, canvas()))
505        return;
506
507    applyShadow();
508}
509
510float CanvasRenderingContext2D::globalAlpha() const
511{
512    return state().m_globalAlpha;
513}
514
515void CanvasRenderingContext2D::setGlobalAlpha(float alpha)
516{
517    if (!(alpha >= 0 && alpha <= 1))
518        return;
519    state().m_globalAlpha = alpha;
520    GraphicsContext* c = drawingContext();
521    if (!c)
522        return;
523    c->setAlpha(alpha);
524}
525
526String CanvasRenderingContext2D::globalCompositeOperation() const
527{
528    return compositeOperatorName(state().m_globalComposite);
529}
530
531void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation)
532{
533    CompositeOperator op;
534    if (!parseCompositeOperator(operation, op))
535        return;
536    state().m_globalComposite = op;
537    GraphicsContext* c = drawingContext();
538    if (!c)
539        return;
540    c->setCompositeOperation(op);
541#if ENABLE(ACCELERATED_2D_CANVAS) && !ENABLE(SKIA_GPU)
542    if (isAccelerated() && op != CompositeSourceOver) {
543        c->setSharedGraphicsContext3D(0, 0, IntSize());
544        m_drawingBuffer.clear();
545        m_context3D.clear();
546        // Mark as needing a style recalc so our compositing layer can be removed.
547        canvas()->setNeedsStyleRecalc(SyntheticStyleChange);
548    }
549#endif
550}
551
552void CanvasRenderingContext2D::scale(float sx, float sy)
553{
554    GraphicsContext* c = drawingContext();
555    if (!c)
556        return;
557    if (!state().m_invertibleCTM)
558        return;
559
560    if (!isfinite(sx) | !isfinite(sy))
561        return;
562
563    AffineTransform newTransform = state().m_transform;
564    newTransform.scaleNonUniform(sx, sy);
565    if (!newTransform.isInvertible()) {
566        state().m_invertibleCTM = false;
567        return;
568    }
569
570    state().m_transform = newTransform;
571    c->scale(FloatSize(sx, sy));
572    m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
573}
574
575void CanvasRenderingContext2D::rotate(float angleInRadians)
576{
577    GraphicsContext* c = drawingContext();
578    if (!c)
579        return;
580    if (!state().m_invertibleCTM)
581        return;
582
583    if (!isfinite(angleInRadians))
584        return;
585
586    AffineTransform newTransform = state().m_transform;
587    newTransform.rotate(angleInRadians / piDouble * 180.0);
588    if (!newTransform.isInvertible()) {
589        state().m_invertibleCTM = false;
590        return;
591    }
592
593    state().m_transform = newTransform;
594    c->rotate(angleInRadians);
595    m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0));
596}
597
598void CanvasRenderingContext2D::translate(float tx, float ty)
599{
600    GraphicsContext* c = drawingContext();
601    if (!c)
602        return;
603    if (!state().m_invertibleCTM)
604        return;
605
606    if (!isfinite(tx) | !isfinite(ty))
607        return;
608
609    AffineTransform newTransform = state().m_transform;
610    newTransform.translate(tx, ty);
611    if (!newTransform.isInvertible()) {
612        state().m_invertibleCTM = false;
613        return;
614    }
615
616    state().m_transform = newTransform;
617    c->translate(tx, ty);
618    m_path.transform(AffineTransform().translate(-tx, -ty));
619}
620
621void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy)
622{
623    GraphicsContext* c = drawingContext();
624    if (!c)
625        return;
626    if (!state().m_invertibleCTM)
627        return;
628
629    if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
630        return;
631
632    AffineTransform transform(m11, m12, m21, m22, dx, dy);
633    AffineTransform newTransform = state().m_transform * transform;
634    if (!newTransform.isInvertible()) {
635        state().m_invertibleCTM = false;
636        return;
637    }
638
639    state().m_transform = newTransform;
640    c->concatCTM(transform);
641    m_path.transform(transform.inverse());
642}
643
644void CanvasRenderingContext2D::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
645{
646    GraphicsContext* c = drawingContext();
647    if (!c)
648        return;
649
650    if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
651        return;
652
653    AffineTransform ctm = state().m_transform;
654    if (!ctm.isInvertible())
655        return;
656    c->concatCTM(c->getCTM().inverse());
657    c->concatCTM(canvas()->baseTransform());
658    state().m_transform = ctm.inverse() * state().m_transform;
659    m_path.transform(ctm);
660
661    state().m_invertibleCTM = true;
662    transform(m11, m12, m21, m22, dx, dy);
663}
664
665void CanvasRenderingContext2D::setStrokeColor(const String& color)
666{
667    if (color == state().m_unparsedStrokeColor)
668        return;
669    setStrokeStyle(CanvasStyle::createFromString(color, canvas()->document()));
670    state().m_unparsedStrokeColor = color;
671}
672
673void CanvasRenderingContext2D::setStrokeColor(float grayLevel)
674{
675    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
676        return;
677    setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
678}
679
680void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
681{
682    setStrokeStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
683}
684
685void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
686{
687    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
688        return;
689    setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
690}
691
692void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a)
693{
694    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(r, g, b, a))
695        return;
696    setStrokeStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
697}
698
699void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a)
700{
701    if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentCMYKA(c, m, y, k, a))
702        return;
703    setStrokeStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
704}
705
706void CanvasRenderingContext2D::setFillColor(const String& color)
707{
708    if (color == state().m_unparsedFillColor)
709        return;
710    setFillStyle(CanvasStyle::createFromString(color, canvas()->document()));
711    state().m_unparsedFillColor = color;
712}
713
714void CanvasRenderingContext2D::setFillColor(float grayLevel)
715{
716    if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
717        return;
718    setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
719}
720
721void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
722{
723    setFillStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
724}
725
726void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
727{
728    if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
729        return;
730    setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
731}
732
733void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
734{
735    if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(r, g, b, a))
736        return;
737    setFillStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
738}
739
740void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
741{
742    if (state().m_fillStyle && state().m_fillStyle->isEquivalentCMYKA(c, m, y, k, a))
743        return;
744    setFillStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
745}
746
747void CanvasRenderingContext2D::beginPath()
748{
749    m_path.clear();
750}
751
752void CanvasRenderingContext2D::closePath()
753{
754    if (m_path.isEmpty())
755        return;
756
757    FloatRect boundRect = m_path.boundingRect();
758    if (boundRect.width() || boundRect.height())
759        m_path.closeSubpath();
760}
761
762void CanvasRenderingContext2D::moveTo(float x, float y)
763{
764    if (!isfinite(x) | !isfinite(y))
765        return;
766    if (!state().m_invertibleCTM)
767        return;
768    m_path.moveTo(FloatPoint(x, y));
769}
770
771void CanvasRenderingContext2D::lineTo(float x, float y)
772{
773    if (!isfinite(x) | !isfinite(y))
774        return;
775    if (!state().m_invertibleCTM)
776        return;
777
778    FloatPoint p1 = FloatPoint(x, y);
779    if (!m_path.hasCurrentPoint())
780        m_path.moveTo(p1);
781    else if (p1 != m_path.currentPoint())
782        m_path.addLineTo(FloatPoint(x, y));
783}
784
785void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, float y)
786{
787    if (!isfinite(cpx) | !isfinite(cpy) | !isfinite(x) | !isfinite(y))
788        return;
789    if (!state().m_invertibleCTM)
790        return;
791    if (!m_path.hasCurrentPoint())
792        m_path.moveTo(FloatPoint(cpx, cpy));
793
794    FloatPoint p1 = FloatPoint(x, y);
795    if (p1 != m_path.currentPoint())
796        m_path.addQuadCurveTo(FloatPoint(cpx, cpy), p1);
797}
798
799void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
800{
801    if (!isfinite(cp1x) | !isfinite(cp1y) | !isfinite(cp2x) | !isfinite(cp2y) | !isfinite(x) | !isfinite(y))
802        return;
803    if (!state().m_invertibleCTM)
804        return;
805    if (!m_path.hasCurrentPoint())
806        m_path.moveTo(FloatPoint(cp1x, cp1y));
807
808    FloatPoint p1 = FloatPoint(x, y);
809    if (p1 != m_path.currentPoint())
810        m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), p1);
811}
812
813void CanvasRenderingContext2D::arcTo(float x1, float y1, float x2, float y2, float r, ExceptionCode& ec)
814{
815    ec = 0;
816    if (!isfinite(x1) | !isfinite(y1) | !isfinite(x2) | !isfinite(y2) | !isfinite(r))
817        return;
818
819    if (r < 0) {
820        ec = INDEX_SIZE_ERR;
821        return;
822    }
823
824    if (!state().m_invertibleCTM)
825        return;
826
827    FloatPoint p1 = FloatPoint(x1, y1);
828    FloatPoint p2 = FloatPoint(x2, y2);
829
830    if (!m_path.hasCurrentPoint())
831        m_path.moveTo(p1);
832    else if (p1 == m_path.currentPoint() || p1 == p2 || !r)
833        lineTo(x1, y1);
834    else
835        m_path.addArcTo(p1, p2, r);
836}
837
838void CanvasRenderingContext2D::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec)
839{
840    ec = 0;
841    if (!isfinite(x) | !isfinite(y) | !isfinite(r) | !isfinite(sa) | !isfinite(ea))
842        return;
843
844    if (r < 0) {
845        ec = INDEX_SIZE_ERR;
846        return;
847    }
848
849    if (sa == ea)
850        return;
851
852    if (!state().m_invertibleCTM)
853        return;
854    m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise);
855}
856
857static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
858{
859    if (!isfinite(x) | !isfinite(y) | !isfinite(width) | !isfinite(height))
860        return false;
861
862    if (!width && !height)
863        return false;
864
865    if (width < 0) {
866        width = -width;
867        x -= width;
868    }
869
870    if (height < 0) {
871        height = -height;
872        y -= height;
873    }
874
875    return true;
876}
877
878void CanvasRenderingContext2D::rect(float x, float y, float width, float height)
879{
880    if (!state().m_invertibleCTM)
881        return;
882
883    if (!isfinite(x) || !isfinite(y) || !isfinite(width) || !isfinite(height))
884        return;
885
886    if (!width && !height) {
887        m_path.moveTo(FloatPoint(x, y));
888        return;
889    }
890
891    m_path.addRect(FloatRect(x, y, width, height));
892}
893
894#if ENABLE(DASHBOARD_SUPPORT)
895void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode()
896{
897    if (m_usesDashboardCompatibilityMode)
898        m_path.clear();
899}
900#endif
901
902void CanvasRenderingContext2D::fill()
903{
904    GraphicsContext* c = drawingContext();
905    if (!c)
906        return;
907    if (!state().m_invertibleCTM)
908        return;
909
910    if (!m_path.isEmpty()) {
911        c->fillPath(m_path);
912        didDraw(m_path.boundingRect());
913    }
914
915#if ENABLE(DASHBOARD_SUPPORT)
916    clearPathForDashboardBackwardCompatibilityMode();
917#endif
918}
919
920void CanvasRenderingContext2D::stroke()
921{
922    GraphicsContext* c = drawingContext();
923    if (!c)
924        return;
925    if (!state().m_invertibleCTM)
926        return;
927
928    if (!m_path.isEmpty()) {
929#if PLATFORM(QT)
930        // Fast approximation of the stroke's bounding rect.
931        // This yields a slightly oversized rect but is very fast
932        // compared to Path::strokeBoundingRect().
933        FloatRect boundingRect = m_path.platformPath().controlPointRect();
934        boundingRect.inflate(state().m_miterLimit + state().m_lineWidth);
935#else
936        CanvasStrokeStyleApplier strokeApplier(this);
937        FloatRect boundingRect = m_path.strokeBoundingRect(&strokeApplier);
938#endif
939        c->strokePath(m_path);
940        didDraw(boundingRect);
941    }
942
943#if ENABLE(DASHBOARD_SUPPORT)
944    clearPathForDashboardBackwardCompatibilityMode();
945#endif
946}
947
948void CanvasRenderingContext2D::clip()
949{
950    GraphicsContext* c = drawingContext();
951    if (!c)
952        return;
953    if (!state().m_invertibleCTM)
954        return;
955    c->canvasClip(m_path);
956#if ENABLE(DASHBOARD_SUPPORT)
957    clearPathForDashboardBackwardCompatibilityMode();
958#endif
959}
960
961bool CanvasRenderingContext2D::isPointInPath(const float x, const float y)
962{
963    GraphicsContext* c = drawingContext();
964    if (!c)
965        return false;
966    if (!state().m_invertibleCTM)
967        return false;
968
969    FloatPoint point(x, y);
970    AffineTransform ctm = state().m_transform;
971    FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
972    if (!isfinite(transformedPoint.x()) || !isfinite(transformedPoint.y()))
973        return false;
974    return m_path.contains(transformedPoint);
975}
976
977void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
978{
979    if (!validateRectForCanvas(x, y, width, height))
980        return;
981    GraphicsContext* context = drawingContext();
982    if (!context)
983        return;
984    if (!state().m_invertibleCTM)
985        return;
986    FloatRect rect(x, y, width, height);
987
988    save();
989    setAllAttributesToDefault();
990    context->clearRect(rect);
991    didDraw(rect);
992    restore();
993}
994
995void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
996{
997    if (!validateRectForCanvas(x, y, width, height))
998        return;
999
1000    GraphicsContext* c = drawingContext();
1001    if (!c)
1002        return;
1003    if (!state().m_invertibleCTM)
1004        return;
1005
1006    // from the HTML5 Canvas spec:
1007    // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
1008    // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
1009    Gradient* gradient = c->fillGradient();
1010    if (gradient && gradient->isZeroSize())
1011        return;
1012
1013    FloatRect rect(x, y, width, height);
1014
1015    c->fillRect(rect);
1016    didDraw(rect);
1017}
1018
1019void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height)
1020{
1021    if (!validateRectForCanvas(x, y, width, height))
1022        return;
1023    strokeRect(x, y, width, height, state().m_lineWidth);
1024}
1025
1026void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth)
1027{
1028    if (!validateRectForCanvas(x, y, width, height))
1029        return;
1030
1031    if (!(lineWidth >= 0))
1032        return;
1033
1034    GraphicsContext* c = drawingContext();
1035    if (!c)
1036        return;
1037    if (!state().m_invertibleCTM)
1038        return;
1039
1040    FloatRect rect(x, y, width, height);
1041
1042    FloatRect boundingRect = rect;
1043    boundingRect.inflate(lineWidth / 2);
1044
1045    c->strokeRect(rect, lineWidth);
1046    didDraw(boundingRect);
1047}
1048
1049#if USE(CG)
1050static inline CGSize adjustedShadowSize(CGFloat width, CGFloat height)
1051{
1052    // Work around <rdar://problem/5539388> by ensuring that shadow offsets will get truncated
1053    // to the desired integer.
1054    static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128);
1055    if (width > 0)
1056        width += extraShadowOffset;
1057    else if (width < 0)
1058        width -= extraShadowOffset;
1059
1060    if (height > 0)
1061        height += extraShadowOffset;
1062    else if (height < 0)
1063        height -= extraShadowOffset;
1064
1065    return CGSizeMake(width, height);
1066}
1067#endif
1068
1069void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
1070{
1071    state().m_shadowOffset = FloatSize(width, height);
1072    state().m_shadowBlur = blur;
1073    state().m_shadowColor = Color::transparent;
1074    applyShadow();
1075}
1076
1077void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color)
1078{
1079    if (!parseColorOrCurrentColor(state().m_shadowColor, color, canvas()))
1080        return;
1081
1082    state().m_shadowOffset = FloatSize(width, height);
1083    state().m_shadowBlur = blur;
1084    applyShadow();
1085}
1086
1087void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
1088{
1089    state().m_shadowOffset = FloatSize(width, height);
1090    state().m_shadowBlur = blur;
1091    state().m_shadowColor = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1.0f);
1092
1093    GraphicsContext* c = drawingContext();
1094    if (!c)
1095        return;
1096
1097    c->setLegacyShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB);
1098}
1099
1100void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha)
1101{
1102    RGBA32 rgba;
1103
1104    if (!parseColorOrCurrentColor(rgba, color, canvas()))
1105        return;
1106
1107    state().m_shadowColor = colorWithOverrideAlpha(rgba, alpha);
1108    state().m_shadowOffset = FloatSize(width, height);
1109    state().m_shadowBlur = blur;
1110
1111    GraphicsContext* c = drawingContext();
1112    if (!c)
1113        return;
1114
1115    c->setLegacyShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB);
1116}
1117
1118void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
1119{
1120    state().m_shadowOffset = FloatSize(width, height);
1121    state().m_shadowBlur = blur;
1122    state().m_shadowColor = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha);
1123
1124    GraphicsContext* c = drawingContext();
1125    if (!c)
1126        return;
1127
1128    c->setLegacyShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB);
1129}
1130
1131void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
1132{
1133    state().m_shadowOffset = FloatSize(width, height);
1134    state().m_shadowBlur = blur;
1135    state().m_shadowColor = makeRGBA32FromFloats(r, g, b, a);
1136
1137    GraphicsContext* c = drawingContext();
1138    if (!c)
1139        return;
1140
1141    c->setLegacyShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB);
1142}
1143
1144void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
1145{
1146    state().m_shadowOffset = FloatSize(width, height);
1147    state().m_shadowBlur = blur;
1148    state().m_shadowColor = makeRGBAFromCMYKA(c, m, y, k, a);
1149
1150    GraphicsContext* dc = drawingContext();
1151    if (!dc)
1152        return;
1153#if USE(CG)
1154    const CGFloat components[5] = { c, m, y, k, a };
1155    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceCMYK();
1156    CGColorRef shadowColor = CGColorCreate(colorSpace, components);
1157    CGColorSpaceRelease(colorSpace);
1158    CGContextSetShadowWithColor(dc->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor);
1159    CGColorRelease(shadowColor);
1160#else
1161    dc->setLegacyShadow(FloatSize(width, -height), blur, state().m_shadowColor, ColorSpaceDeviceRGB);
1162#endif
1163}
1164
1165void CanvasRenderingContext2D::clearShadow()
1166{
1167    state().m_shadowOffset = FloatSize();
1168    state().m_shadowBlur = 0;
1169    state().m_shadowColor = Color::transparent;
1170    applyShadow();
1171}
1172
1173void CanvasRenderingContext2D::applyShadow()
1174{
1175    GraphicsContext* c = drawingContext();
1176    if (!c)
1177        return;
1178
1179    float width = state().m_shadowOffset.width();
1180    float height = state().m_shadowOffset.height();
1181    c->setLegacyShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB);
1182}
1183
1184static IntSize size(HTMLImageElement* image)
1185{
1186    if (CachedImage* cachedImage = image->cachedImage())
1187        return cachedImage->imageSize(1.0f); // FIXME: Not sure about this.
1188    return IntSize();
1189}
1190
1191#if ENABLE(VIDEO)
1192static IntSize size(HTMLVideoElement* video)
1193{
1194    if (MediaPlayer* player = video->player())
1195        return player->naturalSize();
1196    return IntSize();
1197}
1198#endif
1199
1200static inline FloatRect normalizeRect(const FloatRect& rect)
1201{
1202    return FloatRect(min(rect.x(), rect.maxX()),
1203        min(rect.y(), rect.maxY()),
1204        max(rect.width(), -rect.width()),
1205        max(rect.height(), -rect.height()));
1206}
1207
1208void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y, ExceptionCode& ec)
1209{
1210    if (!image) {
1211        ec = TYPE_MISMATCH_ERR;
1212        return;
1213    }
1214    IntSize s = size(image);
1215    drawImage(image, x, y, s.width(), s.height(), ec);
1216}
1217
1218void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
1219    float x, float y, float width, float height, ExceptionCode& ec)
1220{
1221    if (!image) {
1222        ec = TYPE_MISMATCH_ERR;
1223        return;
1224    }
1225    IntSize s = size(image);
1226    drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
1227}
1228
1229void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
1230    float sx, float sy, float sw, float sh,
1231    float dx, float dy, float dw, float dh, ExceptionCode& ec)
1232{
1233    if (!image) {
1234        ec = TYPE_MISMATCH_ERR;
1235        return;
1236    }
1237    drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
1238}
1239
1240void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec)
1241{
1242    drawImage(image, srcRect, dstRect, state().m_globalComposite, ec);
1243}
1244
1245void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator& op, ExceptionCode& ec)
1246{
1247    if (!image) {
1248        ec = TYPE_MISMATCH_ERR;
1249        return;
1250    }
1251
1252    ec = 0;
1253
1254    if (!isfinite(dstRect.x()) || !isfinite(dstRect.y()) || !isfinite(dstRect.width()) || !isfinite(dstRect.height())
1255        || !isfinite(srcRect.x()) || !isfinite(srcRect.y()) || !isfinite(srcRect.width()) || !isfinite(srcRect.height()))
1256        return;
1257
1258    if (!dstRect.width() || !dstRect.height())
1259        return;
1260
1261    if (!image->complete())
1262        return;
1263
1264    FloatRect normalizedSrcRect = normalizeRect(srcRect);
1265    FloatRect normalizedDstRect = normalizeRect(dstRect);
1266
1267    FloatRect imageRect = FloatRect(FloatPoint(), size(image));
1268    if (!imageRect.contains(normalizedSrcRect) || !srcRect.width() || !srcRect.height()) {
1269        ec = INDEX_SIZE_ERR;
1270        return;
1271    }
1272
1273    GraphicsContext* c = drawingContext();
1274    if (!c)
1275        return;
1276    if (!state().m_invertibleCTM)
1277        return;
1278
1279    CachedImage* cachedImage = image->cachedImage();
1280    if (!cachedImage)
1281        return;
1282
1283    checkOrigin(image);
1284
1285    FloatRect sourceRect = c->roundToDevicePixels(normalizedSrcRect);
1286    FloatRect destRect = c->roundToDevicePixels(normalizedDstRect);
1287    c->drawImage(cachedImage->image(), ColorSpaceDeviceRGB, destRect, sourceRect, op);
1288    didDraw(destRect);
1289}
1290
1291void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, float y, ExceptionCode& ec)
1292{
1293    if (!canvas) {
1294        ec = TYPE_MISMATCH_ERR;
1295        return;
1296    }
1297    drawImage(canvas, x, y, canvas->width(), canvas->height(), ec);
1298}
1299
1300void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
1301    float x, float y, float width, float height, ExceptionCode& ec)
1302{
1303    if (!canvas) {
1304        ec = TYPE_MISMATCH_ERR;
1305        return;
1306    }
1307    drawImage(canvas, FloatRect(0, 0, canvas->width(), canvas->height()), FloatRect(x, y, width, height), ec);
1308}
1309
1310void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
1311    float sx, float sy, float sw, float sh,
1312    float dx, float dy, float dw, float dh, ExceptionCode& ec)
1313{
1314    drawImage(canvas, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
1315}
1316
1317void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const FloatRect& srcRect,
1318    const FloatRect& dstRect, ExceptionCode& ec)
1319{
1320    if (!sourceCanvas) {
1321        ec = TYPE_MISMATCH_ERR;
1322        return;
1323    }
1324
1325    FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas->size());
1326
1327    if (!srcCanvasRect.width() || !srcCanvasRect.height()) {
1328        ec = INVALID_STATE_ERR;
1329        return;
1330    }
1331
1332    if (!srcCanvasRect.contains(normalizeRect(srcRect)) || !srcRect.width() || !srcRect.height()) {
1333        ec = INDEX_SIZE_ERR;
1334        return;
1335    }
1336
1337    ec = 0;
1338
1339    if (!dstRect.width() || !dstRect.height())
1340        return;
1341
1342    GraphicsContext* c = drawingContext();
1343    if (!c)
1344        return;
1345    if (!state().m_invertibleCTM)
1346        return;
1347
1348    FloatRect sourceRect = c->roundToDevicePixels(srcRect);
1349    FloatRect destRect = c->roundToDevicePixels(dstRect);
1350
1351    // FIXME: Do this through platform-independent GraphicsContext API.
1352    ImageBuffer* buffer = sourceCanvas->buffer();
1353    if (!buffer)
1354        return;
1355
1356    checkOrigin(sourceCanvas);
1357
1358#if ENABLE(ACCELERATED_2D_CANVAS)
1359    // If we're drawing from one accelerated canvas 2d to another, avoid calling sourceCanvas->makeRenderingResultsAvailable()
1360    // as that will do a readback to software.
1361    CanvasRenderingContext* sourceContext = sourceCanvas->renderingContext();
1362    // FIXME: Implement an accelerated path for drawing from a WebGL canvas to a 2d canvas when possible.
1363    if (!isAccelerated() || !sourceContext || !sourceContext->isAccelerated() || !sourceContext->is2d())
1364        sourceCanvas->makeRenderingResultsAvailable();
1365#else
1366    sourceCanvas->makeRenderingResultsAvailable();
1367#endif
1368
1369    c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, destRect, sourceRect, state().m_globalComposite);
1370    didDraw(destRect);
1371}
1372
1373#if ENABLE(VIDEO)
1374void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y, ExceptionCode& ec)
1375{
1376    if (!video) {
1377        ec = TYPE_MISMATCH_ERR;
1378        return;
1379    }
1380    IntSize s = size(video);
1381    drawImage(video, x, y, s.width(), s.height(), ec);
1382}
1383
1384void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
1385                                         float x, float y, float width, float height, ExceptionCode& ec)
1386{
1387    if (!video) {
1388        ec = TYPE_MISMATCH_ERR;
1389        return;
1390    }
1391    IntSize s = size(video);
1392    drawImage(video, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
1393}
1394
1395void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
1396    float sx, float sy, float sw, float sh,
1397    float dx, float dy, float dw, float dh, ExceptionCode& ec)
1398{
1399    drawImage(video, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec);
1400}
1401
1402void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRect& srcRect, const FloatRect& dstRect,
1403                                         ExceptionCode& ec)
1404{
1405    if (!video) {
1406        ec = TYPE_MISMATCH_ERR;
1407        return;
1408    }
1409
1410    ec = 0;
1411
1412    if (video->readyState() == HTMLMediaElement::HAVE_NOTHING || video->readyState() == HTMLMediaElement::HAVE_METADATA)
1413        return;
1414
1415    FloatRect videoRect = FloatRect(FloatPoint(), size(video));
1416    if (!videoRect.contains(normalizeRect(srcRect)) || !srcRect.width() || !srcRect.height()) {
1417        ec = INDEX_SIZE_ERR;
1418        return;
1419    }
1420
1421    if (!dstRect.width() || !dstRect.height())
1422        return;
1423
1424    GraphicsContext* c = drawingContext();
1425    if (!c)
1426        return;
1427    if (!state().m_invertibleCTM)
1428        return;
1429
1430    checkOrigin(video);
1431
1432    FloatRect sourceRect = c->roundToDevicePixels(srcRect);
1433    FloatRect destRect = c->roundToDevicePixels(dstRect);
1434
1435    c->save();
1436    c->clip(destRect);
1437    c->translate(destRect.x(), destRect.y());
1438    c->scale(FloatSize(destRect.width() / sourceRect.width(), destRect.height() / sourceRect.height()));
1439    c->translate(-sourceRect.x(), -sourceRect.y());
1440    video->paintCurrentFrameInContext(c, IntRect(IntPoint(), size(video)));
1441    c->restore();
1442    didDraw(destRect);
1443}
1444#endif
1445
1446void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
1447    float sx, float sy, float sw, float sh,
1448    float dx, float dy, float dw, float dh,
1449    const String& compositeOperation)
1450{
1451    CompositeOperator op;
1452    if (!parseCompositeOperator(compositeOperation, op))
1453        op = CompositeSourceOver;
1454
1455    ExceptionCode ec;
1456    drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), op, ec);
1457}
1458
1459void CanvasRenderingContext2D::setAlpha(float alpha)
1460{
1461    setGlobalAlpha(alpha);
1462}
1463
1464void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
1465{
1466    setGlobalCompositeOperation(operation);
1467}
1468
1469void CanvasRenderingContext2D::prepareGradientForDashboard(CanvasGradient* gradient) const
1470{
1471#if ENABLE(DASHBOARD_SUPPORT)
1472    if (m_usesDashboardCompatibilityMode)
1473        gradient->setDashboardCompatibilityMode();
1474#else
1475    UNUSED_PARAM(gradient);
1476#endif
1477}
1478
1479PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1, ExceptionCode& ec)
1480{
1481    if (!isfinite(x0) || !isfinite(y0) || !isfinite(x1) || !isfinite(y1)) {
1482        ec = NOT_SUPPORTED_ERR;
1483        return 0;
1484    }
1485
1486    RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
1487    prepareGradientForDashboard(gradient.get());
1488    return gradient.release();
1489}
1490
1491PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode& ec)
1492{
1493    if (!isfinite(x0) || !isfinite(y0) || !isfinite(r0) || !isfinite(x1) || !isfinite(y1) || !isfinite(r1)) {
1494        ec = NOT_SUPPORTED_ERR;
1495        return 0;
1496    }
1497
1498    if (r0 < 0 || r1 < 0) {
1499        ec = INDEX_SIZE_ERR;
1500        return 0;
1501    }
1502
1503    RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
1504    prepareGradientForDashboard(gradient.get());
1505    return gradient.release();
1506}
1507
1508PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image,
1509    const String& repetitionType, ExceptionCode& ec)
1510{
1511    if (!image) {
1512        ec = TYPE_MISMATCH_ERR;
1513        return 0;
1514    }
1515    bool repeatX, repeatY;
1516    ec = 0;
1517    CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1518    if (ec)
1519        return 0;
1520
1521    if (!image->complete())
1522        return 0;
1523
1524    CachedImage* cachedImage = image->cachedImage();
1525    if (!cachedImage || !image->cachedImage()->image())
1526        return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true);
1527
1528    bool originClean = !canvas()->securityOrigin().taintsCanvas(KURL(KURL(), cachedImage->response().url())) && cachedImage->image()->hasSingleSecurityOrigin();
1529    return CanvasPattern::create(cachedImage->image(), repeatX, repeatY, originClean);
1530}
1531
1532PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas,
1533    const String& repetitionType, ExceptionCode& ec)
1534{
1535    if (!canvas) {
1536        ec = TYPE_MISMATCH_ERR;
1537        return 0;
1538    }
1539    if (!canvas->width() || !canvas->height()) {
1540        ec = INVALID_STATE_ERR;
1541        return 0;
1542    }
1543
1544    bool repeatX, repeatY;
1545    ec = 0;
1546    CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1547    if (ec)
1548        return 0;
1549    return CanvasPattern::create(canvas->copiedImage(), repeatX, repeatY, canvas->originClean());
1550}
1551
1552void CanvasRenderingContext2D::didDraw(const FloatRect& r, unsigned options)
1553{
1554    GraphicsContext* c = drawingContext();
1555    if (!c)
1556        return;
1557    if (!state().m_invertibleCTM)
1558        return;
1559
1560    FloatRect dirtyRect = r;
1561    if (options & CanvasDidDrawApplyTransform) {
1562        AffineTransform ctm = state().m_transform;
1563        dirtyRect = ctm.mapRect(r);
1564    }
1565
1566    if (options & CanvasDidDrawApplyShadow && alphaChannel(state().m_shadowColor)) {
1567        // The shadow gets applied after transformation
1568        FloatRect shadowRect(dirtyRect);
1569        shadowRect.move(state().m_shadowOffset);
1570        shadowRect.inflate(state().m_shadowBlur);
1571        dirtyRect.unite(shadowRect);
1572    }
1573
1574    if (options & CanvasDidDrawApplyClip) {
1575        // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
1576        // back out of the GraphicsContext, so to take clip into account for incremental painting,
1577        // we'd have to keep the clip path around.
1578    }
1579
1580#if ENABLE(ACCELERATED_2D_CANVAS)
1581    if (isAccelerated())
1582        drawingContext()->markDirtyRect(enclosingIntRect(dirtyRect));
1583#endif
1584#if ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING)
1585    // If we are drawing to hardware and we have a composited layer, just call contentChanged().
1586    RenderBox* renderBox = canvas()->renderBox();
1587    if (isAccelerated() && renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing())
1588        renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
1589    else
1590#endif
1591        canvas()->didDraw(dirtyRect);
1592}
1593
1594GraphicsContext* CanvasRenderingContext2D::drawingContext() const
1595{
1596    return canvas()->drawingContext();
1597}
1598
1599static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size)
1600{
1601    RefPtr<ImageData> data = ImageData::create(size);
1602    memset(data->data()->data()->data(), 0, data->data()->data()->length());
1603    return data.release();
1604}
1605
1606PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(PassRefPtr<ImageData> imageData, ExceptionCode& ec) const
1607{
1608    if (!imageData) {
1609        ec = NOT_SUPPORTED_ERR;
1610        return 0;
1611    }
1612
1613    return createEmptyImageData(imageData->size());
1614}
1615
1616PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh, ExceptionCode& ec) const
1617{
1618    ec = 0;
1619    if (!sw || !sh) {
1620        ec = INDEX_SIZE_ERR;
1621        return 0;
1622    }
1623    if (!isfinite(sw) || !isfinite(sh)) {
1624        ec = NOT_SUPPORTED_ERR;
1625        return 0;
1626    }
1627
1628    FloatSize unscaledSize(fabs(sw), fabs(sh));
1629    IntSize scaledSize = canvas()->convertLogicalToDevice(unscaledSize);
1630    if (scaledSize.width() < 1)
1631        scaledSize.setWidth(1);
1632    if (scaledSize.height() < 1)
1633        scaledSize.setHeight(1);
1634
1635    return createEmptyImageData(scaledSize);
1636}
1637
1638PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const
1639{
1640    if (!canvas()->originClean()) {
1641        ec = SECURITY_ERR;
1642        return 0;
1643    }
1644    if (!sw || !sh) {
1645        ec = INDEX_SIZE_ERR;
1646        return 0;
1647    }
1648    if (!isfinite(sx) || !isfinite(sy) || !isfinite(sw) || !isfinite(sh)) {
1649        ec = NOT_SUPPORTED_ERR;
1650        return 0;
1651    }
1652
1653    if (sw < 0) {
1654        sx += sw;
1655        sw = -sw;
1656    }
1657    if (sh < 0) {
1658        sy += sh;
1659        sh = -sh;
1660    }
1661
1662    FloatRect unscaledRect(sx, sy, sw, sh);
1663    IntRect scaledRect = canvas()->convertLogicalToDevice(unscaledRect);
1664    if (scaledRect.width() < 1)
1665        scaledRect.setWidth(1);
1666    if (scaledRect.height() < 1)
1667        scaledRect.setHeight(1);
1668    ImageBuffer* buffer = canvas()->buffer();
1669    if (!buffer)
1670        return createEmptyImageData(scaledRect.size());
1671    return ImageData::create(scaledRect.size(), buffer->getUnmultipliedImageData(scaledRect));
1672}
1673
1674void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec)
1675{
1676    if (!data) {
1677        ec = TYPE_MISMATCH_ERR;
1678        return;
1679    }
1680    putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec);
1681}
1682
1683void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY,
1684                                            float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
1685{
1686    if (!data) {
1687        ec = TYPE_MISMATCH_ERR;
1688        return;
1689    }
1690    if (!isfinite(dx) || !isfinite(dy) || !isfinite(dirtyX) || !isfinite(dirtyY) || !isfinite(dirtyWidth) || !isfinite(dirtyHeight)) {
1691        ec = NOT_SUPPORTED_ERR;
1692        return;
1693    }
1694
1695    ImageBuffer* buffer = canvas()->buffer();
1696    if (!buffer)
1697        return;
1698
1699    if (dirtyWidth < 0) {
1700        dirtyX += dirtyWidth;
1701        dirtyWidth = -dirtyWidth;
1702    }
1703
1704    if (dirtyHeight < 0) {
1705        dirtyY += dirtyHeight;
1706        dirtyHeight = -dirtyHeight;
1707    }
1708
1709    FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
1710    clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
1711    IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
1712    IntRect destRect = enclosingIntRect(clipRect);
1713    destRect.move(destOffset);
1714    destRect.intersect(IntRect(IntPoint(), buffer->size()));
1715    if (destRect.isEmpty())
1716        return;
1717    IntRect sourceRect(destRect);
1718    sourceRect.move(-destOffset);
1719
1720    buffer->putUnmultipliedImageData(data->data()->data(), IntSize(data->width(), data->height()), sourceRect, IntPoint(destOffset));
1721    didDraw(destRect, CanvasDidDrawApplyNone); // ignore transform, shadow and clip
1722}
1723
1724String CanvasRenderingContext2D::font() const
1725{
1726    return state().m_unparsedFont;
1727}
1728
1729void CanvasRenderingContext2D::setFont(const String& newFont)
1730{
1731    RefPtr<CSSMutableStyleDeclaration> tempDecl = CSSMutableStyleDeclaration::create();
1732    CSSParser parser(!m_usesCSSCompatibilityParseMode);
1733
1734    String declarationText("font: ");
1735    declarationText += newFont;
1736    parser.parseDeclaration(tempDecl.get(), declarationText);
1737    if (!tempDecl->length())
1738        return;
1739
1740    // The parse succeeded.
1741    state().m_unparsedFont = newFont;
1742
1743    // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
1744    // relative to the canvas.
1745    RefPtr<RenderStyle> newStyle = RenderStyle::create();
1746    if (RenderStyle* computedStyle = canvas()->computedStyle())
1747        newStyle->setFontDescription(computedStyle->fontDescription());
1748    newStyle->font().update(newStyle->font().fontSelector());
1749
1750    // Now map the font property into the style.
1751    CSSStyleSelector* styleSelector = canvas()->styleSelector();
1752    styleSelector->applyPropertyToStyle(CSSPropertyFont, tempDecl->getPropertyCSSValue(CSSPropertyFont).get(), newStyle.get());
1753
1754    state().m_font = newStyle->font();
1755    state().m_font.update(styleSelector->fontSelector());
1756    state().m_realizedFont = true;
1757    styleSelector->fontSelector()->registerForInvalidationCallbacks(&state());
1758}
1759
1760String CanvasRenderingContext2D::textAlign() const
1761{
1762    return textAlignName(state().m_textAlign);
1763}
1764
1765void CanvasRenderingContext2D::setTextAlign(const String& s)
1766{
1767    TextAlign align;
1768    if (!parseTextAlign(s, align))
1769        return;
1770    state().m_textAlign = align;
1771}
1772
1773String CanvasRenderingContext2D::textBaseline() const
1774{
1775    return textBaselineName(state().m_textBaseline);
1776}
1777
1778void CanvasRenderingContext2D::setTextBaseline(const String& s)
1779{
1780    TextBaseline baseline;
1781    if (!parseTextBaseline(s, baseline))
1782        return;
1783    state().m_textBaseline = baseline;
1784}
1785
1786void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
1787{
1788    drawTextInternal(text, x, y, true);
1789}
1790
1791void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth)
1792{
1793    drawTextInternal(text, x, y, true, maxWidth, true);
1794}
1795
1796void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
1797{
1798    drawTextInternal(text, x, y, false);
1799}
1800
1801void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
1802{
1803    drawTextInternal(text, x, y, false, maxWidth, true);
1804}
1805
1806PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
1807{
1808    RefPtr<TextMetrics> metrics = TextMetrics::create();
1809
1810#if PLATFORM(QT)
1811    // We always use complex text shaping since it can't be turned off for QPainterPath::addText().
1812    Font::CodePath oldCodePath = Font::codePath();
1813    Font::setCodePath(Font::Complex);
1814#endif
1815
1816    metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length())));
1817
1818#if PLATFORM(QT)
1819    Font::setCodePath(oldCodePath);
1820#endif
1821
1822    return metrics.release();
1823}
1824
1825void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float /*maxWidth*/, bool /*useMaxWidth*/)
1826{
1827    GraphicsContext* c = drawingContext();
1828    if (!c)
1829        return;
1830    if (!state().m_invertibleCTM)
1831        return;
1832    if (!isfinite(x) | !isfinite(y))
1833        return;
1834
1835    const Font& font = accessFont();
1836    const FontMetrics& fontMetrics = font.fontMetrics();
1837
1838    // FIXME: Handle maxWidth.
1839    // FIXME: Need to turn off font smoothing.
1840
1841    RenderStyle* computedStyle = canvas()->computedStyle();
1842    bool rtl = computedStyle ? !computedStyle->isLeftToRightDirection() : false;
1843    bool override = computedStyle ? computedStyle->unicodeBidi() == Override : false;
1844
1845    unsigned length = text.length();
1846    const UChar* string = text.characters();
1847    TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, rtl, override);
1848
1849    // Draw the item text at the correct point.
1850    FloatPoint location(x, y);
1851    switch (state().m_textBaseline) {
1852    case TopTextBaseline:
1853    case HangingTextBaseline:
1854        location.setY(y + fontMetrics.ascent());
1855        break;
1856    case BottomTextBaseline:
1857    case IdeographicTextBaseline:
1858        location.setY(y - fontMetrics.descent());
1859        break;
1860    case MiddleTextBaseline:
1861        location.setY(y - fontMetrics.descent() + fontMetrics.height() / 2);
1862        break;
1863    case AlphabeticTextBaseline:
1864    default:
1865         // Do nothing.
1866        break;
1867    }
1868
1869    float width = font.width(TextRun(text, false, 0, 0, TextRun::AllowTrailingExpansion, rtl, override));
1870
1871    TextAlign align = state().m_textAlign;
1872    if (align == StartTextAlign)
1873         align = rtl ? RightTextAlign : LeftTextAlign;
1874    else if (align == EndTextAlign)
1875        align = rtl ? LeftTextAlign : RightTextAlign;
1876
1877    switch (align) {
1878    case CenterTextAlign:
1879        location.setX(location.x() - width / 2);
1880        break;
1881    case RightTextAlign:
1882        location.setX(location.x() - width);
1883        break;
1884    default:
1885        break;
1886    }
1887
1888    // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
1889    FloatRect textRect = FloatRect(location.x() - fontMetrics.height() / 2, location.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
1890                                   width + fontMetrics.height(), fontMetrics.lineSpacing());
1891    if (!fill)
1892        textRect.inflate(c->strokeThickness() / 2);
1893
1894#if USE(CG)
1895    CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get();
1896    if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) {
1897        // FIXME: The rect is not big enough for miters on stroked text.
1898        IntRect maskRect = enclosingIntRect(textRect);
1899
1900#if USE(IOSURFACE_CANVAS_BACKING_STORE)
1901        OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), ColorSpaceDeviceRGB, Accelerated);
1902#else
1903        OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size());
1904#endif
1905
1906        GraphicsContext* maskImageContext = maskImage->context();
1907
1908        if (fill)
1909            maskImageContext->setFillColor(Color::black, ColorSpaceDeviceRGB);
1910        else {
1911            maskImageContext->setStrokeColor(Color::black, ColorSpaceDeviceRGB);
1912            maskImageContext->setStrokeThickness(c->strokeThickness());
1913        }
1914
1915        maskImageContext->setTextDrawingMode(fill ? TextModeFill : TextModeStroke);
1916        maskImageContext->translate(-maskRect.x(), -maskRect.y());
1917
1918        maskImageContext->drawBidiText(font, textRun, location);
1919
1920        c->save();
1921        c->clipToImageBuffer(maskImage.get(), maskRect);
1922        drawStyle->applyFillColor(c);
1923        c->fillRect(maskRect);
1924        c->restore();
1925
1926        return;
1927    }
1928#endif
1929
1930    c->setTextDrawingMode(fill ? TextModeFill : TextModeStroke);
1931
1932#if PLATFORM(QT)
1933    // We always use complex text shaping since it can't be turned off for QPainterPath::addText().
1934    Font::CodePath oldCodePath = Font::codePath();
1935    Font::setCodePath(Font::Complex);
1936#endif
1937
1938    c->drawBidiText(font, textRun, location);
1939
1940    if (fill)
1941        didDraw(textRect);
1942    else {
1943        // When stroking text, pointy miters can extend outside of textRect, so we
1944        // punt and dirty the whole canvas.
1945        didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
1946    }
1947
1948#if PLATFORM(QT)
1949    Font::setCodePath(oldCodePath);
1950#endif
1951}
1952
1953const Font& CanvasRenderingContext2D::accessFont()
1954{
1955    canvas()->document()->updateStyleIfNeeded();
1956
1957    if (!state().m_realizedFont)
1958        setFont(state().m_unparsedFont);
1959    return state().m_font;
1960}
1961
1962void CanvasRenderingContext2D::paintRenderingResultsToCanvas()
1963{
1964#if ENABLE(ACCELERATED_2D_CANVAS)
1965    if (GraphicsContext* c = drawingContext())
1966        c->syncSoftwareCanvas();
1967#endif
1968}
1969
1970#if ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING)
1971PlatformLayer* CanvasRenderingContext2D::platformLayer() const
1972{
1973    return m_drawingBuffer ? m_drawingBuffer->platformLayer() : 0;
1974}
1975#endif
1976
1977} // namespace WebCore
1978