1e3faa37400b4efcb88df05d4b317057cd3f51d2
[WebKit-https.git] / WebCore / html / canvas / CanvasRenderingContext2D.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 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  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
28  */
29
30 #include "config.h"
31 #include "CanvasRenderingContext2D.h"
32
33 #include "TransformationMatrix.h"
34 #include "CSSParser.h"
35 #include "CachedImage.h"
36 #include "CanvasGradient.h"
37 #include "CanvasPattern.h"
38 #include "CanvasStyle.h"
39 #include "CSSMutableStyleDeclaration.h"
40 #include "CSSPropertyNames.h"
41 #include "CSSStyleSelector.h"
42 #include "Document.h"
43 #include "ExceptionCode.h"
44 #include "FloatConversion.h"
45 #include "Frame.h"
46 #include "GraphicsContext.h"
47 #include "HTMLCanvasElement.h"
48 #include "HTMLImageElement.h"
49 #include "HTMLNames.h"
50 #include "ImageBuffer.h"
51 #include "ImageData.h"
52 #include "KURL.h"
53 #include "Page.h"
54 #include "RenderHTMLCanvas.h"
55 #include "SecurityOrigin.h"
56 #include "Settings.h"
57 #include "StrokeStyleApplier.h"
58 #include "TextMetrics.h"
59 #include "HTMLVideoElement.h"
60 #include <stdio.h>
61 #include <wtf/ByteArray.h>
62 #include <wtf/MathExtras.h>
63 #include <wtf/OwnPtr.h>
64 #include <wtf/UnusedParam.h>
65
66 using namespace std;
67
68 namespace WebCore {
69
70 using namespace HTMLNames;
71
72 static const char* const defaultFont = "10px sans-serif";
73
74
75 class CanvasStrokeStyleApplier : public StrokeStyleApplier {
76 public:
77     CanvasStrokeStyleApplier(CanvasRenderingContext2D* canvasContext)
78         : m_canvasContext(canvasContext)
79     {
80     }
81     
82     virtual void strokeStyle(GraphicsContext* c)
83     {
84         c->setStrokeThickness(m_canvasContext->lineWidth());
85         c->setLineCap(m_canvasContext->getLineCap());
86         c->setLineJoin(m_canvasContext->getLineJoin());
87         c->setMiterLimit(m_canvasContext->miterLimit());
88     }
89
90 private:
91     CanvasRenderingContext2D* m_canvasContext;
92 };
93
94
95
96 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas)
97     : CanvasRenderingContext(canvas)
98     , m_stateStack(1)
99 {
100     // Make sure that even if the drawingContext() has a different default
101     // thickness, it is in sync with the canvas thickness.
102     setLineWidth(lineWidth());
103 }
104
105 CanvasRenderingContext2D::~CanvasRenderingContext2D()
106 {
107 }
108
109 void CanvasRenderingContext2D::reset()
110 {
111     m_stateStack.resize(1);
112     m_stateStack.first() = State();
113 }
114
115 CanvasRenderingContext2D::State::State()
116     : m_strokeStyle(CanvasStyle::create("black"))
117     , m_fillStyle(CanvasStyle::create("black"))
118     , m_lineWidth(1)
119     , m_lineCap(ButtCap)
120     , m_lineJoin(MiterJoin)
121     , m_miterLimit(10)
122     , m_shadowBlur(0)
123     , m_shadowColor("black")
124     , m_globalAlpha(1)
125     , m_globalComposite(CompositeSourceOver)
126     , m_invertibleCTM(true)
127     , m_textAlign(StartTextAlign)
128     , m_textBaseline(AlphabeticTextBaseline)
129     , m_unparsedFont(defaultFont)
130     , m_realizedFont(false)
131 {
132 }
133
134 void CanvasRenderingContext2D::save()
135 {
136     ASSERT(m_stateStack.size() >= 1);
137     m_stateStack.append(state());
138     GraphicsContext* c = drawingContext();
139     if (!c)
140         return;
141     c->save();
142 }
143
144 void CanvasRenderingContext2D::restore()
145 {
146     ASSERT(m_stateStack.size() >= 1);
147     if (m_stateStack.size() <= 1)
148         return;
149     m_path.transform(state().m_transform);
150     m_stateStack.removeLast();
151     m_path.transform(state().m_transform.inverse());
152     GraphicsContext* c = drawingContext();
153     if (!c)
154         return;
155     c->restore();
156 }
157
158 CanvasStyle* CanvasRenderingContext2D::strokeStyle() const
159 {
160     return state().m_strokeStyle.get();
161 }
162
163 void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> style)
164 {
165     if (!style)
166         return;
167
168     if (m_canvas->originClean()) {
169         if (CanvasPattern* pattern = style->canvasPattern()) {
170             if (!pattern->originClean())
171                 m_canvas->setOriginTainted();
172         }
173     }
174
175     state().m_strokeStyle = style;
176     GraphicsContext* c = drawingContext();
177     if (!c)
178         return;
179     state().m_strokeStyle->applyStrokeColor(c);
180 }
181
182 CanvasStyle* CanvasRenderingContext2D::fillStyle() const
183 {
184     return state().m_fillStyle.get();
185 }
186
187 void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> style)
188 {
189     if (!style)
190         return;
191  
192     if (m_canvas->originClean()) {
193         if (CanvasPattern* pattern = style->canvasPattern()) {
194             if (!pattern->originClean())
195                 m_canvas->setOriginTainted();
196         }
197     }
198
199     state().m_fillStyle = style;
200     GraphicsContext* c = drawingContext();
201     if (!c)
202         return;
203     state().m_fillStyle->applyFillColor(c);
204 }
205
206 float CanvasRenderingContext2D::lineWidth() const
207 {
208     return state().m_lineWidth;
209 }
210
211 void CanvasRenderingContext2D::setLineWidth(float width)
212 {
213     if (!(width > 0))
214         return;
215     state().m_lineWidth = width;
216     GraphicsContext* c = drawingContext();
217     if (!c)
218         return;
219     c->setStrokeThickness(width);
220 }
221
222 String CanvasRenderingContext2D::lineCap() const
223 {
224     return lineCapName(state().m_lineCap);
225 }
226
227 void CanvasRenderingContext2D::setLineCap(const String& s)
228 {
229     LineCap cap;
230     if (!parseLineCap(s, cap))
231         return;
232     state().m_lineCap = cap;
233     GraphicsContext* c = drawingContext();
234     if (!c)
235         return;
236     c->setLineCap(cap);
237 }
238
239 String CanvasRenderingContext2D::lineJoin() const
240 {
241     return lineJoinName(state().m_lineJoin);
242 }
243
244 void CanvasRenderingContext2D::setLineJoin(const String& s)
245 {
246     LineJoin join;
247     if (!parseLineJoin(s, join))
248         return;
249     state().m_lineJoin = join;
250     GraphicsContext* c = drawingContext();
251     if (!c)
252         return;
253     c->setLineJoin(join);
254 }
255
256 float CanvasRenderingContext2D::miterLimit() const
257 {
258     return state().m_miterLimit;
259 }
260
261 void CanvasRenderingContext2D::setMiterLimit(float limit)
262 {
263     if (!(limit > 0))
264         return;
265     state().m_miterLimit = limit;
266     GraphicsContext* c = drawingContext();
267     if (!c)
268         return;
269     c->setMiterLimit(limit);
270 }
271
272 float CanvasRenderingContext2D::shadowOffsetX() const
273 {
274     return state().m_shadowOffset.width();
275 }
276
277 void CanvasRenderingContext2D::setShadowOffsetX(float x)
278 {
279     state().m_shadowOffset.setWidth(x);
280     applyShadow();
281 }
282
283 float CanvasRenderingContext2D::shadowOffsetY() const
284 {
285     return state().m_shadowOffset.height();
286 }
287
288 void CanvasRenderingContext2D::setShadowOffsetY(float y)
289 {
290     state().m_shadowOffset.setHeight(y);
291     applyShadow();
292 }
293
294 float CanvasRenderingContext2D::shadowBlur() const
295 {
296     return state().m_shadowBlur;
297 }
298
299 void CanvasRenderingContext2D::setShadowBlur(float blur)
300 {
301     state().m_shadowBlur = blur;
302     applyShadow();
303 }
304
305 String CanvasRenderingContext2D::shadowColor() const
306 {
307     // FIXME: What should this return if you called setShadow with a non-string color?
308     return state().m_shadowColor;
309 }
310
311 void CanvasRenderingContext2D::setShadowColor(const String& color)
312 {
313     state().m_shadowColor = color;
314     applyShadow();
315 }
316
317 float CanvasRenderingContext2D::globalAlpha() const
318 {
319     return state().m_globalAlpha;
320 }
321
322 void CanvasRenderingContext2D::setGlobalAlpha(float alpha)
323 {
324     if (!(alpha >= 0 && alpha <= 1))
325         return;
326     state().m_globalAlpha = alpha;
327     GraphicsContext* c = drawingContext();
328     if (!c)
329         return;
330     c->setAlpha(alpha);
331 }
332
333 String CanvasRenderingContext2D::globalCompositeOperation() const
334 {
335     return compositeOperatorName(state().m_globalComposite);
336 }
337
338 void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation)
339 {
340     CompositeOperator op;
341     if (!parseCompositeOperator(operation, op))
342         return;
343     state().m_globalComposite = op;
344     GraphicsContext* c = drawingContext();
345     if (!c)
346         return;
347     c->setCompositeOperation(op);
348 }
349
350 void CanvasRenderingContext2D::scale(float sx, float sy)
351 {
352     GraphicsContext* c = drawingContext();
353     if (!c)
354         return;
355     if (!state().m_invertibleCTM)
356         return;
357
358     TransformationMatrix newTransform = state().m_transform;
359     newTransform.scaleNonUniform(sx, sy);
360     if (!newTransform.isInvertible()) {
361         state().m_invertibleCTM = false;
362         return;
363     }
364
365     state().m_transform = newTransform;
366     c->scale(FloatSize(sx, sy));
367     m_path.transform(TransformationMatrix().scaleNonUniform(1.0/sx, 1.0/sy));
368 }
369
370 void CanvasRenderingContext2D::rotate(float angleInRadians)
371 {
372     GraphicsContext* c = drawingContext();
373     if (!c)
374         return;
375     if (!state().m_invertibleCTM)
376         return;
377
378     TransformationMatrix newTransform = state().m_transform;
379     newTransform.rotate(angleInRadians / piDouble * 180.0);
380     if (!newTransform.isInvertible()) {
381         state().m_invertibleCTM = false;
382         return;
383     }
384
385     state().m_transform = newTransform;
386     c->rotate(angleInRadians);
387     m_path.transform(TransformationMatrix().rotate(-angleInRadians / piDouble * 180.0));
388 }
389
390 void CanvasRenderingContext2D::translate(float tx, float ty)
391 {
392     GraphicsContext* c = drawingContext();
393     if (!c)
394         return;
395     if (!state().m_invertibleCTM)
396         return;
397
398     TransformationMatrix newTransform = state().m_transform;
399     newTransform.translate(tx, ty);
400     if (!newTransform.isInvertible()) {
401         state().m_invertibleCTM = false;
402         return;
403     }
404
405     state().m_transform = newTransform;
406     c->translate(tx, ty);
407     m_path.transform(TransformationMatrix().translate(-tx, -ty));
408 }
409
410 void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy)
411 {
412     GraphicsContext* c = drawingContext();
413     if (!c)
414         return;
415     if (!state().m_invertibleCTM)
416         return;
417     
418     // HTML5 3.14.11.1 -- ignore any calls that pass non-finite numbers
419     if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | 
420         !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
421         return;
422
423     TransformationMatrix transform(m11, m12, m21, m22, dx, dy);
424     TransformationMatrix newTransform = transform * state().m_transform;
425     if (!newTransform.isInvertible()) {
426         state().m_invertibleCTM = false;
427         return;
428     }
429
430     state().m_transform = newTransform;
431     c->concatCTM(transform);
432     m_path.transform(transform.inverse());
433 }
434
435 void CanvasRenderingContext2D::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
436 {
437     GraphicsContext* c = drawingContext();
438     if (!c)
439         return;
440     
441     // HTML5 3.14.11.1 -- ignore any calls that pass non-finite numbers
442     if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | 
443         !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
444         return;
445
446     TransformationMatrix ctm = state().m_transform;
447     if (!ctm.isInvertible())
448         return;
449     c->concatCTM(c->getCTM().inverse());
450     c->concatCTM(m_canvas->baseTransform());
451     state().m_transform.multiply(ctm.inverse());
452     m_path.transform(ctm);
453
454     state().m_invertibleCTM = true;
455     transform(m11, m12, m21, m22, dx, dy);
456 }
457
458 void CanvasRenderingContext2D::setStrokeColor(const String& color)
459 {
460     setStrokeStyle(CanvasStyle::create(color));
461 }
462
463 void CanvasRenderingContext2D::setStrokeColor(float grayLevel)
464 {
465     setStrokeStyle(CanvasStyle::create(grayLevel, 1));
466 }
467
468 void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
469 {
470     setStrokeStyle(CanvasStyle::create(color, alpha));
471 }
472
473 void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
474 {
475     setStrokeStyle(CanvasStyle::create(grayLevel, alpha));
476 }
477
478 void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a)
479 {
480     setStrokeStyle(CanvasStyle::create(r, g, b, a));
481 }
482
483 void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a)
484 {
485     setStrokeStyle(CanvasStyle::create(c, m, y, k, a));
486 }
487
488 void CanvasRenderingContext2D::setFillColor(const String& color)
489 {
490     setFillStyle(CanvasStyle::create(color));
491 }
492
493 void CanvasRenderingContext2D::setFillColor(float grayLevel)
494 {
495     setFillStyle(CanvasStyle::create(grayLevel, 1));
496 }
497
498 void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
499 {
500     setFillStyle(CanvasStyle::create(color, alpha));
501 }
502
503 void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
504 {
505     setFillStyle(CanvasStyle::create(grayLevel, alpha));
506 }
507
508 void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
509 {
510     setFillStyle(CanvasStyle::create(r, g, b, a));
511 }
512
513 void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
514 {
515     setFillStyle(CanvasStyle::create(c, m, y, k, a));
516 }
517
518 void CanvasRenderingContext2D::beginPath()
519 {
520     m_path.clear();
521 }
522
523 void CanvasRenderingContext2D::closePath()
524 {
525     m_path.closeSubpath();
526 }
527
528 void CanvasRenderingContext2D::moveTo(float x, float y)
529 {
530     if (!isfinite(x) | !isfinite(y))
531         return;
532     if (!state().m_invertibleCTM)
533         return;
534     m_path.moveTo(FloatPoint(x, y));
535 }
536
537 void CanvasRenderingContext2D::lineTo(float x, float y)
538 {
539     if (!isfinite(x) | !isfinite(y))
540         return;
541     if (!state().m_invertibleCTM)
542         return;
543     if (!m_path.hasCurrentPoint())
544         m_path.moveTo(FloatPoint(x, y));
545     else
546         m_path.addLineTo(FloatPoint(x, y));
547 }
548
549 void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, float y)
550 {
551     if (!isfinite(cpx) | !isfinite(cpy) | !isfinite(x) | !isfinite(y))
552         return;
553     if (!state().m_invertibleCTM)
554         return;
555     if (!m_path.hasCurrentPoint())
556         m_path.moveTo(FloatPoint(x, y));
557     else
558         m_path.addQuadCurveTo(FloatPoint(cpx, cpy), FloatPoint(x, y));
559 }
560
561 void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
562 {
563     if (!isfinite(cp1x) | !isfinite(cp1y) | !isfinite(cp2x) | !isfinite(cp2y) | !isfinite(x) | !isfinite(y))
564         return;
565     if (!state().m_invertibleCTM)
566         return;
567     if (!m_path.hasCurrentPoint())
568         m_path.moveTo(FloatPoint(x, y));
569     else
570         m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), FloatPoint(x, y));
571 }
572
573 void CanvasRenderingContext2D::arcTo(float x0, float y0, float x1, float y1, float r, ExceptionCode& ec)
574 {
575     ec = 0;
576     if (!isfinite(x0) | !isfinite(y0) | !isfinite(x1) | !isfinite(y1) | !isfinite(r))
577         return;
578     
579     if (r < 0) {
580         ec = INDEX_SIZE_ERR;
581         return;
582     }
583     if (!state().m_invertibleCTM)
584         return;
585     m_path.addArcTo(FloatPoint(x0, y0), FloatPoint(x1, y1), r);
586 }
587
588 void CanvasRenderingContext2D::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec)
589 {
590     ec = 0;
591     if (!isfinite(x) | !isfinite(y) | !isfinite(r) | !isfinite(sa) | !isfinite(ea))
592         return;
593     
594     if (r < 0) {
595         ec = INDEX_SIZE_ERR;
596         return;
597     }
598     if (!state().m_invertibleCTM)
599         return;
600     m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise);
601 }
602     
603 static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
604 {
605     if (!isfinite(x) | !isfinite(y) | !isfinite(width) | !isfinite(height))
606         return false;
607     
608     if (width < 0) {
609         width = -width;
610         x -= width;
611     }
612     
613     if (height < 0) {
614         height = -height;
615         y -= height;
616     }
617     
618     return true;
619 }
620
621 void CanvasRenderingContext2D::rect(float x, float y, float width, float height)
622 {
623     if (!validateRectForCanvas(x, y, width, height))
624         return;
625     if (!state().m_invertibleCTM)
626         return;
627     m_path.addRect(FloatRect(x, y, width, height));
628 }
629
630 #if ENABLE(DASHBOARD_SUPPORT)
631 void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode()
632 {
633     if (Settings* settings = m_canvas->document()->settings())
634         if (settings->usesDashboardBackwardCompatibilityMode())
635             m_path.clear();
636 }
637 #endif
638
639 void CanvasRenderingContext2D::fill()
640 {
641     GraphicsContext* c = drawingContext();
642     if (!c)
643         return;
644     if (!state().m_invertibleCTM)
645         return;
646
647     if (!m_path.isEmpty()) {
648         c->beginPath();
649         c->addPath(m_path);
650         willDraw(m_path.boundingRect());
651         c->fillPath();
652     }
653
654 #if ENABLE(DASHBOARD_SUPPORT)
655     clearPathForDashboardBackwardCompatibilityMode();
656 #endif
657 }
658
659 void CanvasRenderingContext2D::stroke()
660 {
661     GraphicsContext* c = drawingContext();
662     if (!c)
663         return;
664     if (!state().m_invertibleCTM)
665         return;
666
667     if (!m_path.isEmpty()) {
668         c->beginPath();
669         c->addPath(m_path);
670
671         CanvasStrokeStyleApplier strokeApplier(this);
672         FloatRect boundingRect = m_path.strokeBoundingRect(&strokeApplier);
673         willDraw(boundingRect);
674
675         c->strokePath();
676     }
677
678 #if ENABLE(DASHBOARD_SUPPORT)
679     clearPathForDashboardBackwardCompatibilityMode();
680 #endif
681 }
682
683 void CanvasRenderingContext2D::clip()
684 {
685     GraphicsContext* c = drawingContext();
686     if (!c)
687         return;
688     if (!state().m_invertibleCTM)
689         return;
690     c->clip(m_path);
691 #if ENABLE(DASHBOARD_SUPPORT)
692     clearPathForDashboardBackwardCompatibilityMode();
693 #endif
694 }
695
696 bool CanvasRenderingContext2D::isPointInPath(const float x, const float y)
697 {
698     GraphicsContext* c = drawingContext();
699     if (!c)
700         return false;
701     if (!state().m_invertibleCTM)
702         return false;
703
704     FloatPoint point(x, y);
705     TransformationMatrix ctm = state().m_transform;
706     FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
707     return m_path.contains(transformedPoint);
708 }
709
710 void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
711 {
712     if (!validateRectForCanvas(x, y, width, height))
713         return;
714     GraphicsContext* c = drawingContext();
715     if (!c)
716         return;
717     if (!state().m_invertibleCTM)
718         return;
719     FloatRect rect(x, y, width, height);
720     willDraw(rect);
721     c->clearRect(rect);
722 }
723
724 void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
725 {
726     if (!validateRectForCanvas(x, y, width, height))
727         return;
728
729     GraphicsContext* c = drawingContext();
730     if (!c)
731         return;
732     if (!state().m_invertibleCTM)
733         return;
734
735     FloatRect rect(x, y, width, height);
736     willDraw(rect);
737
738     c->save();
739     c->fillRect(rect);
740     c->restore();
741 }
742
743 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height)
744 {
745     if (!validateRectForCanvas(x, y, width, height))
746         return;
747     strokeRect(x, y, width, height, state().m_lineWidth);
748 }
749
750 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth)
751 {
752     if (!validateRectForCanvas(x, y, width, height))
753         return;
754     
755     if (!(lineWidth >= 0))
756         return;
757
758     GraphicsContext* c = drawingContext();
759     if (!c)
760         return;
761     if (!state().m_invertibleCTM)
762         return;
763
764     FloatRect rect(x, y, width, height);
765
766     FloatRect boundingRect = rect;
767     boundingRect.inflate(lineWidth / 2);
768     willDraw(boundingRect);
769
770     c->strokeRect(rect, lineWidth);
771 }
772
773 #if PLATFORM(CG)
774 static inline CGSize adjustedShadowSize(CGFloat width, CGFloat height)
775 {
776     // Work around <rdar://problem/5539388> by ensuring that shadow offsets will get truncated
777     // to the desired integer.
778     static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128);
779     if (width > 0)
780         width += extraShadowOffset;
781     else if (width < 0)
782         width -= extraShadowOffset;
783
784     if (height > 0)
785         height += extraShadowOffset;
786     else if (height < 0)
787         height -= extraShadowOffset;
788
789     return CGSizeMake(width, height);
790 }
791 #endif
792
793 void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
794 {
795     state().m_shadowOffset = FloatSize(width, height);
796     state().m_shadowBlur = blur;
797     state().m_shadowColor = "";
798     applyShadow();
799 }
800
801 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color)
802 {
803     state().m_shadowOffset = FloatSize(width, height);
804     state().m_shadowBlur = blur;
805     state().m_shadowColor = color;
806     applyShadow();
807 }
808
809 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
810 {
811     state().m_shadowOffset = FloatSize(width, height);
812     state().m_shadowBlur = blur;
813     state().m_shadowColor = "";
814
815     GraphicsContext* c = drawingContext();
816     if (!c)
817         return;
818
819     RGBA32 rgba = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1.0f);
820     c->setShadow(IntSize(width, -height), state().m_shadowBlur, Color(rgba));
821 }
822
823 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha)
824 {
825     state().m_shadowOffset = FloatSize(width, height);
826     state().m_shadowBlur = blur;
827     state().m_shadowColor = color;
828
829     GraphicsContext* c = drawingContext();
830     if (!c)
831         return;
832
833     RGBA32 rgba = 0; // default is transparent black
834     if (!state().m_shadowColor.isEmpty())
835         CSSParser::parseColor(rgba, state().m_shadowColor);
836     c->setShadow(IntSize(width, -height), state().m_shadowBlur, Color(colorWithOverrideAlpha(rgba, alpha)));
837 }
838
839 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
840 {
841     state().m_shadowOffset = FloatSize(width, height);
842     state().m_shadowBlur = blur;
843     state().m_shadowColor = "";
844
845     GraphicsContext* c = drawingContext();
846     if (!c)
847         return;
848
849     RGBA32 rgba = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha);
850     c->setShadow(IntSize(width, -height), state().m_shadowBlur, Color(rgba));
851 }
852
853 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
854 {
855     state().m_shadowOffset = FloatSize(width, height);
856     state().m_shadowBlur = blur;
857     state().m_shadowColor = "";
858
859     GraphicsContext* c = drawingContext();
860     if (!c)
861         return;
862
863     RGBA32 rgba = makeRGBA32FromFloats(r, g, b, a); // default is transparent black
864     if (!state().m_shadowColor.isEmpty())
865         CSSParser::parseColor(rgba, state().m_shadowColor);
866     c->setShadow(IntSize(width, -height), state().m_shadowBlur, Color(rgba));
867 }
868
869 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
870 {
871     state().m_shadowOffset = FloatSize(width, height);
872     state().m_shadowBlur = blur;
873     state().m_shadowColor = "";
874
875     GraphicsContext* dc = drawingContext();
876     if (!dc)
877         return;
878 #if PLATFORM(CG)
879     const CGFloat components[5] = { c, m, y, k, a };
880     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceCMYK();
881     CGColorRef shadowColor = CGColorCreate(colorSpace, components);
882     CGColorSpaceRelease(colorSpace);
883     CGContextSetShadowWithColor(dc->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor);
884     CGColorRelease(shadowColor);
885 #else
886     dc->setShadow(IntSize(width, -height), blur, Color(c, m, y, k, a));
887 #endif
888 }
889
890 void CanvasRenderingContext2D::clearShadow()
891 {
892     state().m_shadowOffset = FloatSize();
893     state().m_shadowBlur = 0;
894     state().m_shadowColor = "";
895     applyShadow();
896 }
897
898 void CanvasRenderingContext2D::applyShadow()
899 {
900     GraphicsContext* c = drawingContext();
901     if (!c)
902         return;
903
904     RGBA32 rgba = 0; // default is transparent black
905     if (!state().m_shadowColor.isEmpty())
906         CSSParser::parseColor(rgba, state().m_shadowColor);
907     float width = state().m_shadowOffset.width();
908     float height = state().m_shadowOffset.height();
909     c->setShadow(IntSize(width, -height), state().m_shadowBlur, Color(rgba));
910 }
911
912 static IntSize size(HTMLImageElement* image)
913 {
914     if (CachedImage* cachedImage = image->cachedImage())
915         return cachedImage->imageSize(1.0f); // FIXME: Not sure about this.
916     return IntSize();
917 }
918
919 #if ENABLE(VIDEO)
920 static IntSize size(HTMLVideoElement* video)
921 {
922     if (MediaPlayer* player = video->player())
923         return player->naturalSize();
924     return IntSize();
925 }
926 #endif
927
928 static inline FloatRect normalizeRect(const FloatRect& rect)
929 {
930     return FloatRect(min(rect.x(), rect.right()),
931         min(rect.y(), rect.bottom()),
932         max(rect.width(), -rect.width()),
933         max(rect.height(), -rect.height()));
934 }
935
936 void CanvasRenderingContext2D::checkOrigin(const KURL& url)
937 {
938     RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
939     if (!m_canvas->document()->securityOrigin()->canAccess(origin.get()))
940         m_canvas->setOriginTainted();
941 }
942
943 void CanvasRenderingContext2D::checkOrigin(const String& url)
944 {
945     RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromString(url);
946     if (!m_canvas->document()->securityOrigin()->canAccess(origin.get()))
947         m_canvas->setOriginTainted();
948 }
949
950 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y)
951 {
952     ASSERT(image);
953     IntSize s = size(image);
954     ExceptionCode ec;
955     drawImage(image, x, y, s.width(), s.height(), ec);
956 }
957
958 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
959     float x, float y, float width, float height, ExceptionCode& ec)
960 {
961     ASSERT(image);
962     IntSize s = size(image);
963     drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
964 }
965
966 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect,
967     ExceptionCode& ec)
968 {
969     ASSERT(image);
970
971     ec = 0;
972
973     FloatRect imageRect = FloatRect(FloatPoint(), size(image));
974     if (!imageRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
975         ec = INDEX_SIZE_ERR;
976         return;
977     }
978
979     if (!dstRect.width() || !dstRect.height())
980         return;
981
982     GraphicsContext* c = drawingContext();
983     if (!c)
984         return;
985     if (!state().m_invertibleCTM)
986         return;
987
988     CachedImage* cachedImage = image->cachedImage();
989     if (!cachedImage)
990         return;
991
992     if (m_canvas->originClean())
993         checkOrigin(cachedImage->response().url());
994
995     if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigin())
996         m_canvas->setOriginTainted();
997
998     FloatRect sourceRect = c->roundToDevicePixels(srcRect);
999     FloatRect destRect = c->roundToDevicePixels(dstRect);
1000     willDraw(destRect);
1001     c->drawImage(cachedImage->image(), destRect, sourceRect, state().m_globalComposite);
1002 }
1003
1004 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, float y)
1005 {
1006     ASSERT(canvas);
1007     ExceptionCode ec;
1008     drawImage(canvas, x, y, canvas->width(), canvas->height(), ec);
1009 }
1010
1011 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
1012     float x, float y, float width, float height, ExceptionCode& ec)
1013 {
1014     ASSERT(canvas);
1015     drawImage(canvas, FloatRect(0, 0, canvas->width(), canvas->height()), FloatRect(x, y, width, height), ec);
1016 }
1017
1018 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, const FloatRect& srcRect,
1019     const FloatRect& dstRect, ExceptionCode& ec)
1020 {
1021     ASSERT(canvas);
1022
1023     ec = 0;
1024
1025     FloatRect srcCanvasRect = FloatRect(FloatPoint(), canvas->size());
1026     if (!srcCanvasRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
1027         ec = INDEX_SIZE_ERR;
1028         return;
1029     }
1030
1031     if (!dstRect.width() || !dstRect.height())
1032         return;
1033
1034     GraphicsContext* c = drawingContext();
1035     if (!c)
1036         return;
1037     if (!state().m_invertibleCTM)
1038         return;
1039         
1040     FloatRect sourceRect = c->roundToDevicePixels(srcRect);
1041     FloatRect destRect = c->roundToDevicePixels(dstRect);
1042         
1043     // FIXME: Do this through platform-independent GraphicsContext API.
1044     ImageBuffer* buffer = canvas->buffer();
1045     if (!buffer)
1046         return;
1047
1048     if (!canvas->originClean())
1049         m_canvas->setOriginTainted();
1050
1051     c->drawImage(buffer->image(), destRect, sourceRect, state().m_globalComposite);
1052     willDraw(destRect); // This call comes after drawImage, since the buffer we draw into may be our own, and we need to make sure it is dirty.
1053                         // FIXME: Arguably willDraw should become didDraw and occur after drawing calls and not before them to avoid problems like this.
1054 }
1055
1056 #if ENABLE(VIDEO)
1057 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y)
1058 {
1059     ASSERT(video);
1060     IntSize s = size(video);
1061     ExceptionCode ec;
1062     drawImage(video, x, y, s.width(), s.height(), ec);
1063 }
1064
1065 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
1066                                          float x, float y, float width, float height, ExceptionCode& ec)
1067 {
1068     ASSERT(video);
1069     IntSize s = size(video);
1070     drawImage(video, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
1071 }
1072
1073 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRect& srcRect, const FloatRect& dstRect,
1074                                          ExceptionCode& ec)
1075 {
1076     ASSERT(video);
1077     
1078     ec = 0;
1079     FloatRect videoRect = FloatRect(FloatPoint(), size(video));
1080     if (!videoRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
1081         ec = INDEX_SIZE_ERR;
1082         return;
1083     }
1084     
1085     if (!dstRect.width() || !dstRect.height())
1086         return;
1087     
1088     GraphicsContext* c = drawingContext();
1089     if (!c)
1090         return;
1091     if (!state().m_invertibleCTM)
1092         return;
1093
1094     if (m_canvas->originClean())
1095         checkOrigin(video->currentSrc());
1096
1097     if (m_canvas->originClean() && !video->hasSingleSecurityOrigin())
1098         m_canvas->setOriginTainted();
1099
1100     FloatRect sourceRect = c->roundToDevicePixels(srcRect);
1101     FloatRect destRect = c->roundToDevicePixels(dstRect);
1102     willDraw(destRect);
1103
1104     c->save();
1105     c->clip(destRect);
1106     c->translate(destRect.x(), destRect.y());
1107     c->scale(FloatSize(destRect.width()/sourceRect.width(), destRect.height()/sourceRect.height()));
1108     c->translate(-sourceRect.x(), -sourceRect.y());
1109     video->paintCurrentFrameInContext(c, IntRect(IntPoint(), size(video)));
1110     c->restore();
1111 }
1112 #endif
1113
1114 // FIXME: Why isn't this just another overload of drawImage? Why have a different name?
1115 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
1116     float sx, float sy, float sw, float sh,
1117     float dx, float dy, float dw, float dh,
1118     const String& compositeOperation)
1119 {
1120     if (!image)
1121         return;
1122
1123     CachedImage* cachedImage = image->cachedImage();
1124     if (!cachedImage)
1125         return;
1126
1127     if (m_canvas->originClean())
1128         checkOrigin(cachedImage->response().url());
1129
1130     if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigin())
1131         m_canvas->setOriginTainted();
1132
1133     GraphicsContext* c = drawingContext();
1134     if (!c)
1135         return;
1136     if (!state().m_invertibleCTM)
1137         return;
1138
1139     CompositeOperator op;
1140     if (!parseCompositeOperator(compositeOperation, op))
1141         op = CompositeSourceOver;
1142
1143     FloatRect destRect = FloatRect(dx, dy, dw, dh);
1144     willDraw(destRect);
1145     c->drawImage(cachedImage->image(), destRect, FloatRect(sx, sy, sw, sh), op);
1146 }
1147
1148 void CanvasRenderingContext2D::setAlpha(float alpha)
1149 {
1150     setGlobalAlpha(alpha);
1151 }
1152
1153 void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
1154 {
1155     setGlobalCompositeOperation(operation);
1156 }
1157
1158 void CanvasRenderingContext2D::prepareGradientForDashboard(CanvasGradient* gradient) const
1159 {
1160 #if ENABLE(DASHBOARD_SUPPORT)
1161     if (Settings* settings = m_canvas->document()->settings())
1162         if (settings->usesDashboardBackwardCompatibilityMode())
1163             gradient->setDashboardCompatibilityMode();
1164 #else
1165     UNUSED_PARAM(gradient);
1166 #endif
1167 }
1168
1169 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1, ExceptionCode& ec)
1170 {
1171     if (!isfinite(x0) || !isfinite(y0) || !isfinite(x1) || !isfinite(y1)) {
1172         ec = NOT_SUPPORTED_ERR;
1173         return 0;
1174     }
1175
1176     PassRefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
1177     prepareGradientForDashboard(gradient.get());
1178     return gradient;
1179 }
1180
1181 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode& ec)
1182 {
1183     if (!isfinite(x0) || !isfinite(y0) || !isfinite(r0) || 
1184         !isfinite(x1) || !isfinite(y1) || !isfinite(r1)) {
1185         ec = NOT_SUPPORTED_ERR;
1186         return 0;
1187     }
1188     PassRefPtr<CanvasGradient> gradient =  CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
1189     prepareGradientForDashboard(gradient.get());
1190     return gradient;
1191 }
1192
1193 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image,
1194     const String& repetitionType, ExceptionCode& ec)
1195 {
1196     bool repeatX, repeatY;
1197     ec = 0;
1198     CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1199     if (ec)
1200         return 0;
1201
1202     if (!image->complete()) {
1203         ec = INVALID_STATE_ERR;
1204         return 0;
1205     }
1206
1207     CachedImage* cachedImage = image->cachedImage();
1208     if (!cachedImage || !image->cachedImage()->image())
1209         return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true);
1210
1211     RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromString(cachedImage->url());
1212     bool originClean = m_canvas->document()->securityOrigin()->canAccess(origin.get());
1213     return CanvasPattern::create(cachedImage->image(), repeatX, repeatY, originClean);
1214 }
1215
1216 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas,
1217     const String& repetitionType, ExceptionCode& ec)
1218 {
1219     if (!canvas->width() || !canvas->height()) {
1220         ec = INVALID_STATE_ERR;
1221         return 0;
1222     }
1223     
1224     bool repeatX, repeatY;
1225     ec = 0;
1226     CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1227     if (ec)
1228         return 0;
1229     return CanvasPattern::create(canvas->buffer()->image(), repeatX, repeatY, canvas->originClean());
1230 }
1231
1232 void CanvasRenderingContext2D::willDraw(const FloatRect& r, unsigned options)
1233 {
1234     GraphicsContext* c = drawingContext();
1235     if (!c)
1236         return;
1237     if (!state().m_invertibleCTM)
1238         return;
1239
1240     FloatRect dirtyRect = r;
1241     if (options & CanvasWillDrawApplyTransform) {
1242         TransformationMatrix ctm = state().m_transform;
1243         dirtyRect = ctm.mapRect(r);
1244     }
1245     
1246     if (options & CanvasWillDrawApplyShadow) {
1247         // The shadow gets applied after transformation
1248         FloatRect shadowRect(dirtyRect);
1249         shadowRect.move(state().m_shadowOffset);
1250         shadowRect.inflate(state().m_shadowBlur);
1251         dirtyRect.unite(shadowRect);
1252     }
1253     
1254     if (options & CanvasWillDrawApplyClip) {
1255         // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
1256         // back out of the GraphicsContext, so to take clip into account for incremental painting,
1257         // we'd have to keep the clip path around.
1258     }
1259     
1260     m_canvas->willDraw(dirtyRect);
1261 }
1262
1263 GraphicsContext* CanvasRenderingContext2D::drawingContext() const
1264 {
1265     return m_canvas->drawingContext();
1266 }
1267
1268 static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size)
1269 {
1270     RefPtr<ImageData> data = ImageData::create(size.width(), size.height());
1271     memset(data->data()->data()->data(), 0, data->data()->data()->length());
1272     return data.get();
1273 }
1274
1275 PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh, ExceptionCode& ec) const
1276 {
1277     ec = 0;
1278     if (!isfinite(sw) || !isfinite(sh)) {
1279         ec = NOT_SUPPORTED_ERR;
1280         return 0;
1281     }
1282     FloatSize unscaledSize(sw, sh);
1283     IntSize scaledSize = m_canvas->convertLogicalToDevice(unscaledSize);
1284     if (scaledSize.width() < 1)
1285         scaledSize.setWidth(1);
1286     if (scaledSize.height() < 1)
1287         scaledSize.setHeight(1);
1288     
1289     return createEmptyImageData(scaledSize);
1290 }
1291
1292 PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const
1293 {
1294     if (!m_canvas->originClean()) {
1295         ec = SECURITY_ERR;
1296         return 0;
1297     }
1298     
1299     FloatRect unscaledRect(sx, sy, sw, sh);
1300     IntRect scaledRect = m_canvas->convertLogicalToDevice(unscaledRect);
1301     if (scaledRect.width() < 1)
1302         scaledRect.setWidth(1);
1303     if (scaledRect.height() < 1)
1304         scaledRect.setHeight(1);
1305     ImageBuffer* buffer = m_canvas ? m_canvas->buffer() : 0;
1306     if (!buffer)
1307         return createEmptyImageData(scaledRect.size());
1308     return buffer->getUnmultipliedImageData(scaledRect);
1309 }
1310
1311 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec)
1312 {
1313     if (!data) {
1314         ec = TYPE_MISMATCH_ERR;
1315         return;
1316     }
1317     putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec);
1318 }
1319
1320 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, 
1321                                             float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
1322 {
1323     if (!data) {
1324         ec = TYPE_MISMATCH_ERR;
1325         return;
1326     }
1327     if (!isfinite(dx) || !isfinite(dy) || !isfinite(dirtyX) || 
1328         !isfinite(dirtyY) || !isfinite(dirtyWidth) || !isfinite(dirtyHeight)) {
1329         ec = INDEX_SIZE_ERR;
1330         return;
1331     }
1332
1333     ImageBuffer* buffer = m_canvas->buffer();
1334     if (!buffer)
1335         return;
1336
1337     if (dirtyWidth < 0) {
1338         dirtyX += dirtyWidth;
1339         dirtyWidth = -dirtyWidth;
1340     }
1341
1342     if (dirtyHeight < 0) {
1343         dirtyY += dirtyHeight;
1344         dirtyHeight = -dirtyHeight;
1345     }
1346
1347     FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
1348     clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
1349     IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
1350     IntRect sourceRect = enclosingIntRect(clipRect);
1351     sourceRect.move(destOffset);
1352     sourceRect.intersect(IntRect(IntPoint(), buffer->size()));
1353     if (sourceRect.isEmpty())
1354         return;
1355     willDraw(sourceRect, 0);  // ignore transform, shadow and clip
1356     sourceRect.move(-destOffset);
1357     IntPoint destPoint(destOffset.width(), destOffset.height());
1358     
1359     buffer->putUnmultipliedImageData(data, sourceRect, destPoint);
1360 }
1361
1362 String CanvasRenderingContext2D::font() const
1363 {
1364     return state().m_unparsedFont;
1365 }
1366
1367 void CanvasRenderingContext2D::setFont(const String& newFont)
1368 {
1369     RefPtr<CSSMutableStyleDeclaration> tempDecl = CSSMutableStyleDeclaration::create();
1370     CSSParser parser(!m_canvas->document()->inCompatMode()); // Use the parse mode of the canvas' document when parsing CSS.
1371         
1372     String declarationText("font: ");
1373     declarationText += newFont;
1374     parser.parseDeclaration(tempDecl.get(), declarationText);
1375     if (!tempDecl->length())
1376         return;
1377             
1378     // The parse succeeded.
1379     state().m_unparsedFont = newFont;
1380     
1381     // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
1382     // relative to the canvas.
1383     RefPtr<RenderStyle> newStyle = RenderStyle::create();
1384     if (m_canvas->computedStyle())
1385         newStyle->setFontDescription(m_canvas->computedStyle()->fontDescription());
1386
1387     // Now map the font property into the style.
1388     CSSStyleSelector* styleSelector = m_canvas->document()->styleSelector();
1389     styleSelector->applyPropertyToStyle(CSSPropertyFont, tempDecl->getPropertyCSSValue(CSSPropertyFont).get(), newStyle.get());
1390     
1391     state().m_font = newStyle->font();
1392     state().m_font.update(styleSelector->fontSelector());
1393     state().m_realizedFont = true;
1394 }
1395         
1396 String CanvasRenderingContext2D::textAlign() const
1397 {
1398     return textAlignName(state().m_textAlign);
1399 }
1400
1401 void CanvasRenderingContext2D::setTextAlign(const String& s)
1402 {
1403     TextAlign align;
1404     if (!parseTextAlign(s, align))
1405         return;
1406     state().m_textAlign = align;
1407 }
1408         
1409 String CanvasRenderingContext2D::textBaseline() const
1410 {
1411     return textBaselineName(state().m_textBaseline);
1412 }
1413
1414 void CanvasRenderingContext2D::setTextBaseline(const String& s)
1415 {
1416     TextBaseline baseline;
1417     if (!parseTextBaseline(s, baseline))
1418         return;
1419     state().m_textBaseline = baseline;
1420 }
1421
1422 void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
1423 {
1424     drawTextInternal(text, x, y, true);
1425 }
1426
1427 void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth)
1428 {
1429     drawTextInternal(text, x, y, true, maxWidth, true);
1430 }
1431
1432 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
1433 {
1434     drawTextInternal(text, x, y, false);
1435 }
1436
1437 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
1438 {
1439     drawTextInternal(text, x, y, false, maxWidth, true);
1440 }
1441
1442 PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
1443 {
1444     RefPtr<TextMetrics> metrics = TextMetrics::create();
1445     metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length())));
1446     return metrics;
1447 }
1448
1449 void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float /*maxWidth*/, bool /*useMaxWidth*/)
1450 {
1451     GraphicsContext* c = drawingContext();
1452     if (!c)
1453         return;
1454     if (!state().m_invertibleCTM)
1455         return;
1456     
1457     const Font& font = accessFont();
1458
1459     // FIXME: Handle maxWidth.
1460     // FIXME: Need to turn off font smoothing.
1461
1462     bool rtl = m_canvas->computedStyle() ? m_canvas->computedStyle()->direction() == RTL : false;
1463     bool override = m_canvas->computedStyle() ? m_canvas->computedStyle()->unicodeBidi() == Override : false;
1464
1465     unsigned length = text.length();
1466     const UChar* string = text.characters();
1467     TextRun textRun(string, length, 0, 0, 0, rtl, override, false, false);
1468
1469     // Draw the item text at the correct point.
1470     FloatPoint location(x, y);
1471     switch (state().m_textBaseline) {
1472         case TopTextBaseline:
1473         case HangingTextBaseline:
1474             location.setY(y + font.ascent());
1475             break;
1476         case BottomTextBaseline:
1477         case IdeographicTextBaseline:
1478             location.setY(y - font.descent());
1479             break;
1480         case MiddleTextBaseline:
1481             location.setY(y - font.descent() + font.height() / 2);
1482             break;
1483         case AlphabeticTextBaseline:
1484         default:
1485              // Do nothing.
1486             break;
1487     }
1488     
1489     float width = font.width(TextRun(text, false, 0, 0, rtl, override));
1490
1491     TextAlign align = state().m_textAlign;
1492     if (align == StartTextAlign)
1493          align = rtl ? RightTextAlign : LeftTextAlign;
1494     else if (align == EndTextAlign)
1495         align = rtl ? LeftTextAlign : RightTextAlign;
1496     
1497     switch (align) {
1498         case CenterTextAlign:
1499             location.setX(location.x() - width / 2);
1500             break;
1501         case RightTextAlign:
1502             location.setX(location.x() - width);
1503             break;
1504         default:
1505             break;
1506     }
1507     
1508     // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
1509     FloatRect textRect = FloatRect(location.x() - font.height() / 2, location.y() - font.ascent() - font.lineGap(),
1510                                    width + font.height(), font.lineSpacing());
1511     if (!fill)
1512         textRect.inflate(c->strokeThickness() / 2);
1513
1514     if (fill)
1515         m_canvas->willDraw(textRect);
1516     else {
1517         // When stroking text, pointy miters can extend outside of textRect, so we
1518         // punt and dirty the whole canvas.
1519         m_canvas->willDraw(FloatRect(0, 0, m_canvas->width(), m_canvas->height()));
1520     }
1521     
1522 #if PLATFORM(CG)
1523     CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get();
1524     if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) {
1525         // FIXME: The rect is not big enough for miters on stroked text.
1526         IntRect maskRect = enclosingIntRect(textRect);
1527
1528         OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size());
1529
1530         GraphicsContext* maskImageContext = maskImage->context();
1531
1532         if (fill)
1533             maskImageContext->setFillColor(Color::black);
1534         else {
1535             maskImageContext->setStrokeColor(Color::black);
1536             maskImageContext->setStrokeThickness(c->strokeThickness());
1537         }
1538
1539         maskImageContext->setTextDrawingMode(fill ? cTextFill : cTextStroke);
1540         maskImageContext->translate(-maskRect.x(), -maskRect.y());
1541         
1542         maskImageContext->drawBidiText(font, textRun, location);
1543         
1544         c->save();
1545         c->clipToImageBuffer(maskRect, maskImage.get());
1546         drawStyle->applyFillColor(c);
1547         c->fillRect(maskRect);
1548         c->restore();
1549
1550         return;
1551     }
1552 #endif
1553
1554     c->setTextDrawingMode(fill ? cTextFill : cTextStroke);
1555     c->drawBidiText(font, textRun, location);
1556 }
1557
1558 const Font& CanvasRenderingContext2D::accessFont()
1559 {
1560     if (!state().m_realizedFont)
1561         setFont(state().m_unparsedFont);
1562     return state().m_font;
1563 }
1564
1565 } // namespace WebCore