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