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