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