2009-09-19 Adam Barth <abarth@webkit.org>
[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     if (m_canvas->document()->securityOrigin()->taintsCanvas(url))
939         m_canvas->setOriginTainted();
940 }
941
942 void CanvasRenderingContext2D::checkOrigin(const String& url)
943 {
944     checkOrigin(KURL(KURL(), url));
945 }
946
947 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y)
948 {
949     ASSERT(image);
950     IntSize s = size(image);
951     ExceptionCode ec;
952     drawImage(image, x, y, s.width(), s.height(), ec);
953 }
954
955 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
956     float x, float y, float width, float height, ExceptionCode& ec)
957 {
958     ASSERT(image);
959     IntSize s = size(image);
960     drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
961 }
962
963 void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect,
964     ExceptionCode& ec)
965 {
966     ASSERT(image);
967
968     ec = 0;
969
970     FloatRect imageRect = FloatRect(FloatPoint(), size(image));
971     if (!imageRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
972         ec = INDEX_SIZE_ERR;
973         return;
974     }
975
976     if (!dstRect.width() || !dstRect.height())
977         return;
978
979     GraphicsContext* c = drawingContext();
980     if (!c)
981         return;
982     if (!state().m_invertibleCTM)
983         return;
984
985     CachedImage* cachedImage = image->cachedImage();
986     if (!cachedImage)
987         return;
988
989     if (m_canvas->originClean())
990         checkOrigin(cachedImage->response().url());
991
992     if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigin())
993         m_canvas->setOriginTainted();
994
995     FloatRect sourceRect = c->roundToDevicePixels(srcRect);
996     FloatRect destRect = c->roundToDevicePixels(dstRect);
997     willDraw(destRect);
998     c->drawImage(cachedImage->image(), destRect, sourceRect, state().m_globalComposite);
999 }
1000
1001 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, float y)
1002 {
1003     ASSERT(canvas);
1004     ExceptionCode ec;
1005     drawImage(canvas, x, y, canvas->width(), canvas->height(), ec);
1006 }
1007
1008 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas,
1009     float x, float y, float width, float height, ExceptionCode& ec)
1010 {
1011     ASSERT(canvas);
1012     drawImage(canvas, FloatRect(0, 0, canvas->width(), canvas->height()), FloatRect(x, y, width, height), ec);
1013 }
1014
1015 void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, const FloatRect& srcRect,
1016     const FloatRect& dstRect, ExceptionCode& ec)
1017 {
1018     ASSERT(canvas);
1019
1020     ec = 0;
1021
1022     FloatRect srcCanvasRect = FloatRect(FloatPoint(), canvas->size());
1023     if (!srcCanvasRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
1024         ec = INDEX_SIZE_ERR;
1025         return;
1026     }
1027
1028     if (!dstRect.width() || !dstRect.height())
1029         return;
1030
1031     GraphicsContext* c = drawingContext();
1032     if (!c)
1033         return;
1034     if (!state().m_invertibleCTM)
1035         return;
1036         
1037     FloatRect sourceRect = c->roundToDevicePixels(srcRect);
1038     FloatRect destRect = c->roundToDevicePixels(dstRect);
1039         
1040     // FIXME: Do this through platform-independent GraphicsContext API.
1041     ImageBuffer* buffer = canvas->buffer();
1042     if (!buffer)
1043         return;
1044
1045     if (!canvas->originClean())
1046         m_canvas->setOriginTainted();
1047
1048     c->drawImage(buffer->image(), destRect, sourceRect, state().m_globalComposite);
1049     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.
1050                         // FIXME: Arguably willDraw should become didDraw and occur after drawing calls and not before them to avoid problems like this.
1051 }
1052
1053 #if ENABLE(VIDEO)
1054 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y)
1055 {
1056     ASSERT(video);
1057     IntSize s = size(video);
1058     ExceptionCode ec;
1059     drawImage(video, x, y, s.width(), s.height(), ec);
1060 }
1061
1062 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video,
1063                                          float x, float y, float width, float height, ExceptionCode& ec)
1064 {
1065     ASSERT(video);
1066     IntSize s = size(video);
1067     drawImage(video, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec);
1068 }
1069
1070 void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRect& srcRect, const FloatRect& dstRect,
1071                                          ExceptionCode& ec)
1072 {
1073     ASSERT(video);
1074     
1075     ec = 0;
1076     FloatRect videoRect = FloatRect(FloatPoint(), size(video));
1077     if (!videoRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
1078         ec = INDEX_SIZE_ERR;
1079         return;
1080     }
1081     
1082     if (!dstRect.width() || !dstRect.height())
1083         return;
1084     
1085     GraphicsContext* c = drawingContext();
1086     if (!c)
1087         return;
1088     if (!state().m_invertibleCTM)
1089         return;
1090
1091     if (m_canvas->originClean())
1092         checkOrigin(video->currentSrc());
1093
1094     if (m_canvas->originClean() && !video->hasSingleSecurityOrigin())
1095         m_canvas->setOriginTainted();
1096
1097     FloatRect sourceRect = c->roundToDevicePixels(srcRect);
1098     FloatRect destRect = c->roundToDevicePixels(dstRect);
1099     willDraw(destRect);
1100
1101     c->save();
1102     c->clip(destRect);
1103     c->translate(destRect.x(), destRect.y());
1104     c->scale(FloatSize(destRect.width()/sourceRect.width(), destRect.height()/sourceRect.height()));
1105     c->translate(-sourceRect.x(), -sourceRect.y());
1106     video->paintCurrentFrameInContext(c, IntRect(IntPoint(), size(video)));
1107     c->restore();
1108 }
1109 #endif
1110
1111 // FIXME: Why isn't this just another overload of drawImage? Why have a different name?
1112 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
1113     float sx, float sy, float sw, float sh,
1114     float dx, float dy, float dw, float dh,
1115     const String& compositeOperation)
1116 {
1117     if (!image)
1118         return;
1119
1120     CachedImage* cachedImage = image->cachedImage();
1121     if (!cachedImage)
1122         return;
1123
1124     if (m_canvas->originClean())
1125         checkOrigin(cachedImage->response().url());
1126
1127     if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigin())
1128         m_canvas->setOriginTainted();
1129
1130     GraphicsContext* c = drawingContext();
1131     if (!c)
1132         return;
1133     if (!state().m_invertibleCTM)
1134         return;
1135
1136     CompositeOperator op;
1137     if (!parseCompositeOperator(compositeOperation, op))
1138         op = CompositeSourceOver;
1139
1140     FloatRect destRect = FloatRect(dx, dy, dw, dh);
1141     willDraw(destRect);
1142     c->drawImage(cachedImage->image(), destRect, FloatRect(sx, sy, sw, sh), op);
1143 }
1144
1145 void CanvasRenderingContext2D::setAlpha(float alpha)
1146 {
1147     setGlobalAlpha(alpha);
1148 }
1149
1150 void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
1151 {
1152     setGlobalCompositeOperation(operation);
1153 }
1154
1155 void CanvasRenderingContext2D::prepareGradientForDashboard(CanvasGradient* gradient) const
1156 {
1157 #if ENABLE(DASHBOARD_SUPPORT)
1158     if (Settings* settings = m_canvas->document()->settings())
1159         if (settings->usesDashboardBackwardCompatibilityMode())
1160             gradient->setDashboardCompatibilityMode();
1161 #else
1162     UNUSED_PARAM(gradient);
1163 #endif
1164 }
1165
1166 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1, ExceptionCode& ec)
1167 {
1168     if (!isfinite(x0) || !isfinite(y0) || !isfinite(x1) || !isfinite(y1)) {
1169         ec = NOT_SUPPORTED_ERR;
1170         return 0;
1171     }
1172
1173     PassRefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
1174     prepareGradientForDashboard(gradient.get());
1175     return gradient;
1176 }
1177
1178 PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode& ec)
1179 {
1180     if (!isfinite(x0) || !isfinite(y0) || !isfinite(r0) || 
1181         !isfinite(x1) || !isfinite(y1) || !isfinite(r1)) {
1182         ec = NOT_SUPPORTED_ERR;
1183         return 0;
1184     }
1185     PassRefPtr<CanvasGradient> gradient =  CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
1186     prepareGradientForDashboard(gradient.get());
1187     return gradient;
1188 }
1189
1190 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image,
1191     const String& repetitionType, ExceptionCode& ec)
1192 {
1193     bool repeatX, repeatY;
1194     ec = 0;
1195     CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1196     if (ec)
1197         return 0;
1198
1199     if (!image->complete()) {
1200         ec = INVALID_STATE_ERR;
1201         return 0;
1202     }
1203
1204     CachedImage* cachedImage = image->cachedImage();
1205     if (!cachedImage || !image->cachedImage()->image())
1206         return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true);
1207
1208     bool originClean = !m_canvas->document()->securityOrigin()->taintsCanvas(KURL(KURL(), cachedImage->url()));
1209     return CanvasPattern::create(cachedImage->image(), repeatX, repeatY, originClean);
1210 }
1211
1212 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas,
1213     const String& repetitionType, ExceptionCode& ec)
1214 {
1215     if (!canvas->width() || !canvas->height()) {
1216         ec = INVALID_STATE_ERR;
1217         return 0;
1218     }
1219     
1220     bool repeatX, repeatY;
1221     ec = 0;
1222     CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1223     if (ec)
1224         return 0;
1225     return CanvasPattern::create(canvas->buffer()->image(), repeatX, repeatY, canvas->originClean());
1226 }
1227
1228 void CanvasRenderingContext2D::willDraw(const FloatRect& r, unsigned options)
1229 {
1230     GraphicsContext* c = drawingContext();
1231     if (!c)
1232         return;
1233     if (!state().m_invertibleCTM)
1234         return;
1235
1236     FloatRect dirtyRect = r;
1237     if (options & CanvasWillDrawApplyTransform) {
1238         TransformationMatrix ctm = state().m_transform;
1239         dirtyRect = ctm.mapRect(r);
1240     }
1241     
1242     if (options & CanvasWillDrawApplyShadow) {
1243         // The shadow gets applied after transformation
1244         FloatRect shadowRect(dirtyRect);
1245         shadowRect.move(state().m_shadowOffset);
1246         shadowRect.inflate(state().m_shadowBlur);
1247         dirtyRect.unite(shadowRect);
1248     }
1249     
1250     if (options & CanvasWillDrawApplyClip) {
1251         // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
1252         // back out of the GraphicsContext, so to take clip into account for incremental painting,
1253         // we'd have to keep the clip path around.
1254     }
1255     
1256     m_canvas->willDraw(dirtyRect);
1257 }
1258
1259 GraphicsContext* CanvasRenderingContext2D::drawingContext() const
1260 {
1261     return m_canvas->drawingContext();
1262 }
1263
1264 static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size)
1265 {
1266     RefPtr<ImageData> data = ImageData::create(size.width(), size.height());
1267     memset(data->data()->data()->data(), 0, data->data()->data()->length());
1268     return data.get();
1269 }
1270
1271 PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh, ExceptionCode& ec) const
1272 {
1273     ec = 0;
1274     if (!isfinite(sw) || !isfinite(sh)) {
1275         ec = NOT_SUPPORTED_ERR;
1276         return 0;
1277     }
1278     FloatSize unscaledSize(sw, sh);
1279     IntSize scaledSize = m_canvas->convertLogicalToDevice(unscaledSize);
1280     if (scaledSize.width() < 1)
1281         scaledSize.setWidth(1);
1282     if (scaledSize.height() < 1)
1283         scaledSize.setHeight(1);
1284     
1285     return createEmptyImageData(scaledSize);
1286 }
1287
1288 PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const
1289 {
1290     if (!m_canvas->originClean()) {
1291         ec = SECURITY_ERR;
1292         return 0;
1293     }
1294     
1295     FloatRect unscaledRect(sx, sy, sw, sh);
1296     IntRect scaledRect = m_canvas->convertLogicalToDevice(unscaledRect);
1297     if (scaledRect.width() < 1)
1298         scaledRect.setWidth(1);
1299     if (scaledRect.height() < 1)
1300         scaledRect.setHeight(1);
1301     ImageBuffer* buffer = m_canvas ? m_canvas->buffer() : 0;
1302     if (!buffer)
1303         return createEmptyImageData(scaledRect.size());
1304     return buffer->getUnmultipliedImageData(scaledRect);
1305 }
1306
1307 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec)
1308 {
1309     if (!data) {
1310         ec = TYPE_MISMATCH_ERR;
1311         return;
1312     }
1313     putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec);
1314 }
1315
1316 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, 
1317                                             float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
1318 {
1319     if (!data) {
1320         ec = TYPE_MISMATCH_ERR;
1321         return;
1322     }
1323     if (!isfinite(dx) || !isfinite(dy) || !isfinite(dirtyX) || 
1324         !isfinite(dirtyY) || !isfinite(dirtyWidth) || !isfinite(dirtyHeight)) {
1325         ec = INDEX_SIZE_ERR;
1326         return;
1327     }
1328
1329     ImageBuffer* buffer = m_canvas->buffer();
1330     if (!buffer)
1331         return;
1332
1333     if (dirtyWidth < 0) {
1334         dirtyX += dirtyWidth;
1335         dirtyWidth = -dirtyWidth;
1336     }
1337
1338     if (dirtyHeight < 0) {
1339         dirtyY += dirtyHeight;
1340         dirtyHeight = -dirtyHeight;
1341     }
1342
1343     FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
1344     clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
1345     IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
1346     IntRect sourceRect = enclosingIntRect(clipRect);
1347     sourceRect.move(destOffset);
1348     sourceRect.intersect(IntRect(IntPoint(), buffer->size()));
1349     if (sourceRect.isEmpty())
1350         return;
1351     willDraw(sourceRect, 0);  // ignore transform, shadow and clip
1352     sourceRect.move(-destOffset);
1353     IntPoint destPoint(destOffset.width(), destOffset.height());
1354     
1355     buffer->putUnmultipliedImageData(data, sourceRect, destPoint);
1356 }
1357
1358 String CanvasRenderingContext2D::font() const
1359 {
1360     return state().m_unparsedFont;
1361 }
1362
1363 void CanvasRenderingContext2D::setFont(const String& newFont)
1364 {
1365     RefPtr<CSSMutableStyleDeclaration> tempDecl = CSSMutableStyleDeclaration::create();
1366     CSSParser parser(!m_canvas->document()->inCompatMode()); // Use the parse mode of the canvas' document when parsing CSS.
1367         
1368     String declarationText("font: ");
1369     declarationText += newFont;
1370     parser.parseDeclaration(tempDecl.get(), declarationText);
1371     if (!tempDecl->length())
1372         return;
1373             
1374     // The parse succeeded.
1375     state().m_unparsedFont = newFont;
1376     
1377     // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
1378     // relative to the canvas.
1379     RefPtr<RenderStyle> newStyle = RenderStyle::create();
1380     if (m_canvas->computedStyle())
1381         newStyle->setFontDescription(m_canvas->computedStyle()->fontDescription());
1382
1383     // Now map the font property into the style.
1384     CSSStyleSelector* styleSelector = m_canvas->document()->styleSelector();
1385     styleSelector->applyPropertyToStyle(CSSPropertyFont, tempDecl->getPropertyCSSValue(CSSPropertyFont).get(), newStyle.get());
1386     
1387     state().m_font = newStyle->font();
1388     state().m_font.update(styleSelector->fontSelector());
1389     state().m_realizedFont = true;
1390 }
1391         
1392 String CanvasRenderingContext2D::textAlign() const
1393 {
1394     return textAlignName(state().m_textAlign);
1395 }
1396
1397 void CanvasRenderingContext2D::setTextAlign(const String& s)
1398 {
1399     TextAlign align;
1400     if (!parseTextAlign(s, align))
1401         return;
1402     state().m_textAlign = align;
1403 }
1404         
1405 String CanvasRenderingContext2D::textBaseline() const
1406 {
1407     return textBaselineName(state().m_textBaseline);
1408 }
1409
1410 void CanvasRenderingContext2D::setTextBaseline(const String& s)
1411 {
1412     TextBaseline baseline;
1413     if (!parseTextBaseline(s, baseline))
1414         return;
1415     state().m_textBaseline = baseline;
1416 }
1417
1418 void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
1419 {
1420     drawTextInternal(text, x, y, true);
1421 }
1422
1423 void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth)
1424 {
1425     drawTextInternal(text, x, y, true, maxWidth, true);
1426 }
1427
1428 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
1429 {
1430     drawTextInternal(text, x, y, false);
1431 }
1432
1433 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
1434 {
1435     drawTextInternal(text, x, y, false, maxWidth, true);
1436 }
1437
1438 PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
1439 {
1440     RefPtr<TextMetrics> metrics = TextMetrics::create();
1441     metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length())));
1442     return metrics;
1443 }
1444
1445 void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float /*maxWidth*/, bool /*useMaxWidth*/)
1446 {
1447     GraphicsContext* c = drawingContext();
1448     if (!c)
1449         return;
1450     if (!state().m_invertibleCTM)
1451         return;
1452     
1453     const Font& font = accessFont();
1454
1455     // FIXME: Handle maxWidth.
1456     // FIXME: Need to turn off font smoothing.
1457
1458     bool rtl = m_canvas->computedStyle() ? m_canvas->computedStyle()->direction() == RTL : false;
1459     bool override = m_canvas->computedStyle() ? m_canvas->computedStyle()->unicodeBidi() == Override : false;
1460
1461     unsigned length = text.length();
1462     const UChar* string = text.characters();
1463     TextRun textRun(string, length, 0, 0, 0, rtl, override, false, false);
1464
1465     // Draw the item text at the correct point.
1466     FloatPoint location(x, y);
1467     switch (state().m_textBaseline) {
1468         case TopTextBaseline:
1469         case HangingTextBaseline:
1470             location.setY(y + font.ascent());
1471             break;
1472         case BottomTextBaseline:
1473         case IdeographicTextBaseline:
1474             location.setY(y - font.descent());
1475             break;
1476         case MiddleTextBaseline:
1477             location.setY(y - font.descent() + font.height() / 2);
1478             break;
1479         case AlphabeticTextBaseline:
1480         default:
1481              // Do nothing.
1482             break;
1483     }
1484     
1485     float width = font.width(TextRun(text, false, 0, 0, rtl, override));
1486
1487     TextAlign align = state().m_textAlign;
1488     if (align == StartTextAlign)
1489          align = rtl ? RightTextAlign : LeftTextAlign;
1490     else if (align == EndTextAlign)
1491         align = rtl ? LeftTextAlign : RightTextAlign;
1492     
1493     switch (align) {
1494         case CenterTextAlign:
1495             location.setX(location.x() - width / 2);
1496             break;
1497         case RightTextAlign:
1498             location.setX(location.x() - width);
1499             break;
1500         default:
1501             break;
1502     }
1503     
1504     // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
1505     FloatRect textRect = FloatRect(location.x() - font.height() / 2, location.y() - font.ascent() - font.lineGap(),
1506                                    width + font.height(), font.lineSpacing());
1507     if (!fill)
1508         textRect.inflate(c->strokeThickness() / 2);
1509
1510     if (fill)
1511         m_canvas->willDraw(textRect);
1512     else {
1513         // When stroking text, pointy miters can extend outside of textRect, so we
1514         // punt and dirty the whole canvas.
1515         m_canvas->willDraw(FloatRect(0, 0, m_canvas->width(), m_canvas->height()));
1516     }
1517     
1518 #if PLATFORM(CG)
1519     CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get();
1520     if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) {
1521         // FIXME: The rect is not big enough for miters on stroked text.
1522         IntRect maskRect = enclosingIntRect(textRect);
1523
1524         OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size());
1525
1526         GraphicsContext* maskImageContext = maskImage->context();
1527
1528         if (fill)
1529             maskImageContext->setFillColor(Color::black);
1530         else {
1531             maskImageContext->setStrokeColor(Color::black);
1532             maskImageContext->setStrokeThickness(c->strokeThickness());
1533         }
1534
1535         maskImageContext->setTextDrawingMode(fill ? cTextFill : cTextStroke);
1536         maskImageContext->translate(-maskRect.x(), -maskRect.y());
1537         
1538         maskImageContext->drawBidiText(font, textRun, location);
1539         
1540         c->save();
1541         c->clipToImageBuffer(maskRect, maskImage.get());
1542         drawStyle->applyFillColor(c);
1543         c->fillRect(maskRect);
1544         c->restore();
1545
1546         return;
1547     }
1548 #endif
1549
1550     c->setTextDrawingMode(fill ? cTextFill : cTextStroke);
1551     c->drawBidiText(font, textRun, location);
1552 }
1553
1554 const Font& CanvasRenderingContext2D::accessFont()
1555 {
1556     if (!state().m_realizedFont)
1557         setFont(state().m_unparsedFont);
1558     return state().m_font;
1559 }
1560
1561 } // namespace WebCore