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