WebCore:
[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 "AffineTransform.h"
34 #include "CSSParser.h"
35 #include "CachedImage.h"
36 #include "CanvasGradient.h"
37 #include "CanvasPattern.h"
38 #include "CanvasPixelArray.h"
39 #include "CanvasStyle.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 "NotImplemented.h"
54 #include "Page.h"
55 #include "RenderHTMLCanvas.h"
56 #include "SecurityOrigin.h"
57 #include "Settings.h"
58 #include "StrokeStyleApplier.h"
59 #include "TextMetrics.h"
60 #include <stdio.h>
61 #include <wtf/MathExtras.h>
62
63 using namespace std;
64
65 namespace WebCore {
66
67 using namespace HTMLNames;
68
69 static const char* const defaultFont = "10px sans-serif";
70
71
72 class CanvasStrokeStyleApplier : public StrokeStyleApplier {
73 public:
74     CanvasStrokeStyleApplier(CanvasRenderingContext2D* canvasContext)
75         : m_canvasContext(canvasContext)
76     {
77     }
78     
79     virtual void strokeStyle(GraphicsContext* c)
80     {
81         c->setStrokeThickness(m_canvasContext->lineWidth());
82         c->setLineCap(m_canvasContext->getLineCap());
83         c->setLineJoin(m_canvasContext->getLineJoin());
84         c->setMiterLimit(m_canvasContext->miterLimit());
85     }
86
87 private:
88     CanvasRenderingContext2D* m_canvasContext;
89 };
90
91
92
93 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas)
94     : m_canvas(canvas)
95     , m_stateStack(1)
96 {
97 }
98
99 void CanvasRenderingContext2D::ref()
100 {
101     m_canvas->ref();
102 }
103
104 void CanvasRenderingContext2D::deref()
105 {
106     m_canvas->deref(); 
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     AffineTransform newTransform = state().m_transform;
359     newTransform.scale(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(AffineTransform().scale(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     AffineTransform 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(AffineTransform().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     AffineTransform 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(AffineTransform().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     AffineTransform transform(m11, m12, m21, m22, dx, dy);
424
425     AffineTransform newTransform = state().m_transform;
426     newTransform.multiply(transform);
427     if (!newTransform.isInvertible()) {
428         state().m_invertibleCTM = false;
429         return;
430     }
431
432     state().m_transform = newTransform;
433     c->concatCTM(transform);
434     m_path.transform(transform.inverse());
435 }
436
437 void CanvasRenderingContext2D::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
438 {
439     GraphicsContext* c = drawingContext();
440     if (!c)
441         return;
442     
443     // HTML5 3.14.11.1 -- ignore any calls that pass non-finite numbers
444     if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | 
445         !isfinite(m12) | !isfinite(m22) | !isfinite(dy))
446         return;
447
448     AffineTransform ctm = state().m_transform;
449     if (!ctm.isInvertible())
450         return;
451     c->concatCTM(c->getCTM().inverse());
452     c->concatCTM(m_canvas->baseTransform());
453     state().m_transform.multiply(ctm.inverse());
454     m_path.transform(ctm);
455
456     state().m_invertibleCTM = true;
457     transform(m11, m12, m21, m22, dx, dy);
458 }
459
460 void CanvasRenderingContext2D::setStrokeColor(const String& color)
461 {
462     setStrokeStyle(CanvasStyle::create(color));
463 }
464
465 void CanvasRenderingContext2D::setStrokeColor(float grayLevel)
466 {
467     setStrokeStyle(CanvasStyle::create(grayLevel, 1));
468 }
469
470 void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
471 {
472     setStrokeStyle(CanvasStyle::create(color, alpha));
473 }
474
475 void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
476 {
477     setStrokeStyle(CanvasStyle::create(grayLevel, alpha));
478 }
479
480 void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a)
481 {
482     setStrokeStyle(CanvasStyle::create(r, g, b, a));
483 }
484
485 void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a)
486 {
487     setStrokeStyle(CanvasStyle::create(c, m, y, k, a));
488 }
489
490 void CanvasRenderingContext2D::setFillColor(const String& color)
491 {
492     setFillStyle(CanvasStyle::create(color));
493 }
494
495 void CanvasRenderingContext2D::setFillColor(float grayLevel)
496 {
497     setFillStyle(CanvasStyle::create(grayLevel, 1));
498 }
499
500 void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
501 {
502     setFillStyle(CanvasStyle::create(color, alpha));
503 }
504
505 void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
506 {
507     setFillStyle(CanvasStyle::create(grayLevel, alpha));
508 }
509
510 void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
511 {
512     setFillStyle(CanvasStyle::create(r, g, b, a));
513 }
514
515 void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
516 {
517     setFillStyle(CanvasStyle::create(c, m, y, k, a));
518 }
519
520 void CanvasRenderingContext2D::beginPath()
521 {
522     m_path.clear();
523 }
524
525 void CanvasRenderingContext2D::closePath()
526 {
527     m_path.closeSubpath();
528 }
529
530 void CanvasRenderingContext2D::moveTo(float x, float y)
531 {
532     if (!isfinite(x) | !isfinite(y))
533         return;
534     if (!state().m_invertibleCTM)
535         return;
536     m_path.moveTo(FloatPoint(x, y));
537 }
538
539 void CanvasRenderingContext2D::lineTo(float x, float y)
540 {
541     if (!isfinite(x) | !isfinite(y))
542         return;
543     if (!state().m_invertibleCTM)
544         return;
545     m_path.addLineTo(FloatPoint(x, y));
546 }
547
548 void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, float y)
549 {
550     if (!isfinite(cpx) | !isfinite(cpy) | !isfinite(x) | !isfinite(y))
551         return;
552     if (!state().m_invertibleCTM)
553         return;
554     m_path.addQuadCurveTo(FloatPoint(cpx, cpy), FloatPoint(x, y));
555 }
556
557 void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
558 {
559     if (!isfinite(cp1x) | !isfinite(cp1y) | !isfinite(cp2x) | !isfinite(cp2y) | !isfinite(x) | !isfinite(y))
560         return;
561     if (!state().m_invertibleCTM)
562         return;
563     m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), FloatPoint(x, y));
564 }
565
566 void CanvasRenderingContext2D::arcTo(float x0, float y0, float x1, float y1, float r, ExceptionCode& ec)
567 {
568     ec = 0;
569     if (!isfinite(x0) | !isfinite(y0) | !isfinite(x1) | !isfinite(y1) | !isfinite(r))
570         return;
571     
572     if (r < 0) {
573         ec = INDEX_SIZE_ERR;
574         return;
575     }
576     if (!state().m_invertibleCTM)
577         return;
578     m_path.addArcTo(FloatPoint(x0, y0), FloatPoint(x1, y1), r);
579 }
580
581 void CanvasRenderingContext2D::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec)
582 {
583     ec = 0;
584     if (!isfinite(x) | !isfinite(y) | !isfinite(r) | !isfinite(sa) | !isfinite(ea))
585         return;
586     
587     if (r < 0) {
588         ec = INDEX_SIZE_ERR;
589         return;
590     }
591     if (!state().m_invertibleCTM)
592         return;
593     m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise);
594 }
595     
596 static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
597 {
598     if (!isfinite(x) | !isfinite(y) | !isfinite(width) | !isfinite(height))
599         return false;
600     
601     if (width < 0) {
602         width = -width;
603         x -= width;
604     }
605     
606     if (height < 0) {
607         height = -height;
608         y -= height;
609     }
610     
611     return true;
612 }
613
614 void CanvasRenderingContext2D::rect(float x, float y, float width, float height)
615 {
616     if (!validateRectForCanvas(x, y, width, height))
617         return;
618     if (!state().m_invertibleCTM)
619         return;
620     m_path.addRect(FloatRect(x, y, width, height));
621 }
622
623 #if ENABLE(DASHBOARD_SUPPORT)
624 void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode()
625 {
626     if (Settings* settings = m_canvas->document()->settings())
627         if (settings->usesDashboardBackwardCompatibilityMode())
628             m_path.clear();
629 }
630 #endif
631
632 void CanvasRenderingContext2D::fill()
633 {
634     GraphicsContext* c = drawingContext();
635     if (!c)
636         return;
637     if (!state().m_invertibleCTM)
638         return;
639
640     if (!m_path.isEmpty()) {
641         c->beginPath();
642         c->addPath(m_path);
643         willDraw(m_path.boundingRect());
644         c->fillPath();
645     }
646
647 #if ENABLE(DASHBOARD_SUPPORT)
648     clearPathForDashboardBackwardCompatibilityMode();
649 #endif
650 }
651
652 void CanvasRenderingContext2D::stroke()
653 {
654     GraphicsContext* c = drawingContext();
655     if (!c)
656         return;
657     if (!state().m_invertibleCTM)
658         return;
659
660     if (!m_path.isEmpty()) {
661         c->beginPath();
662         c->addPath(m_path);
663
664         CanvasStrokeStyleApplier strokeApplier(this);
665         FloatRect boundingRect = m_path.strokeBoundingRect(&strokeApplier);
666         willDraw(boundingRect);
667
668         c->strokePath();
669     }
670
671 #if ENABLE(DASHBOARD_SUPPORT)
672     clearPathForDashboardBackwardCompatibilityMode();
673 #endif
674 }
675
676 void CanvasRenderingContext2D::clip()
677 {
678     GraphicsContext* c = drawingContext();
679     if (!c)
680         return;
681     if (!state().m_invertibleCTM)
682         return;
683     c->clip(m_path);
684 #if ENABLE(DASHBOARD_SUPPORT)
685     clearPathForDashboardBackwardCompatibilityMode();
686 #endif
687 }
688
689 bool CanvasRenderingContext2D::isPointInPath(const float x, const float y)
690 {
691     GraphicsContext* c = drawingContext();
692     if (!c)
693         return false;
694     if (!state().m_invertibleCTM)
695         return false;
696
697     FloatPoint point(x, y);
698     AffineTransform ctm = state().m_transform;
699     FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
700     return m_path.contains(transformedPoint);
701 }
702
703 void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
704 {
705     if (!validateRectForCanvas(x, y, width, height))
706         return;
707     GraphicsContext* c = drawingContext();
708     if (!c)
709         return;
710     if (!state().m_invertibleCTM)
711         return;
712     FloatRect rect(x, y, width, height);
713     willDraw(rect);
714     c->clearRect(rect);
715 }
716
717 void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
718 {
719     if (!validateRectForCanvas(x, y, width, height))
720         return;
721
722     GraphicsContext* c = drawingContext();
723     if (!c)
724         return;
725     if (!state().m_invertibleCTM)
726         return;
727
728     FloatRect rect(x, y, width, height);
729     willDraw(rect);
730
731     c->save();
732     c->fillRect(rect);
733     c->restore();
734 }
735
736 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height)
737 {
738     if (!validateRectForCanvas(x, y, width, height))
739         return;
740     strokeRect(x, y, width, height, state().m_lineWidth);
741 }
742
743 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth)
744 {
745     if (!validateRectForCanvas(x, y, width, height))
746         return;
747     
748     if (!(lineWidth >= 0))
749         return;
750
751     GraphicsContext* c = drawingContext();
752     if (!c)
753         return;
754     if (!state().m_invertibleCTM)
755         return;
756
757     FloatRect rect(x, y, width, height);
758
759     FloatRect boundingRect = rect;
760     boundingRect.inflate(lineWidth / 2);
761     willDraw(boundingRect);
762
763     c->strokeRect(rect, lineWidth);
764 }
765
766 #if PLATFORM(CG)
767 static inline CGSize adjustedShadowSize(CGFloat width, CGFloat height)
768 {
769     // Work around <rdar://problem/5539388> by ensuring that shadow offsets will get truncated
770     // to the desired integer.
771     static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128);
772     if (width > 0)
773         width += extraShadowOffset;
774     else if (width < 0)
775         width -= extraShadowOffset;
776
777     if (height > 0)
778         height += extraShadowOffset;
779     else if (height < 0)
780         height -= extraShadowOffset;
781
782     return CGSizeMake(width, height);
783 }
784 #endif
785
786 void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
787 {
788     state().m_shadowOffset = FloatSize(width, height);
789     state().m_shadowBlur = blur;
790     state().m_shadowColor = "";
791     applyShadow();
792 }
793
794 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color)
795 {
796     state().m_shadowOffset = FloatSize(width, height);
797     state().m_shadowBlur = blur;
798     state().m_shadowColor = color;
799     applyShadow();
800 }
801
802 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
803 {
804     state().m_shadowOffset = FloatSize(width, height);
805     state().m_shadowBlur = blur;
806     state().m_shadowColor = "";
807
808     GraphicsContext* c = drawingContext();
809     if (!c)
810         return;
811
812     RGBA32 rgba = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1.0f);
813     c->setShadow(IntSize(width, -height), state().m_shadowBlur, Color(rgba));
814 }
815
816 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha)
817 {
818     state().m_shadowOffset = FloatSize(width, height);
819     state().m_shadowBlur = blur;
820     state().m_shadowColor = color;
821
822     GraphicsContext* c = drawingContext();
823     if (!c)
824         return;
825
826     RGBA32 rgba = 0; // default is transparent black
827     if (!state().m_shadowColor.isEmpty())
828         CSSParser::parseColor(rgba, state().m_shadowColor);
829     c->setShadow(IntSize(width, -height), state().m_shadowBlur, Color(colorWithOverrideAlpha(rgba, alpha)));
830 }
831
832 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
833 {
834     state().m_shadowOffset = FloatSize(width, height);
835     state().m_shadowBlur = blur;
836     state().m_shadowColor = "";
837
838     GraphicsContext* c = drawingContext();
839     if (!c)
840         return;
841
842     RGBA32 rgba = makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha);
843     c->setShadow(IntSize(width, -height), state().m_shadowBlur, Color(rgba));
844 }
845
846 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
847 {
848     state().m_shadowOffset = FloatSize(width, height);
849     state().m_shadowBlur = blur;
850     state().m_shadowColor = "";
851
852     GraphicsContext* c = drawingContext();
853     if (!c)
854         return;
855
856     RGBA32 rgba = makeRGBA32FromFloats(r, g, b, a); // default is transparent black
857     if (!state().m_shadowColor.isEmpty())
858         CSSParser::parseColor(rgba, state().m_shadowColor);
859     c->setShadow(IntSize(width, -height), state().m_shadowBlur, Color(rgba));
860 }
861
862 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
863 {
864     state().m_shadowOffset = FloatSize(width, height);
865     state().m_shadowBlur = blur;
866     state().m_shadowColor = "";
867
868     GraphicsContext* dc = drawingContext();
869     if (!dc)
870         return;
871     // FIXME: Do this through platform-independent GraphicsContext API.
872 #if PLATFORM(CG)
873     const CGFloat components[5] = { c, m, y, k, a };
874     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceCMYK();
875     CGColorRef shadowColor = CGColorCreate(colorSpace, components);
876     CGColorSpaceRelease(colorSpace);
877     CGContextSetShadowWithColor(dc->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor);
878     CGColorRelease(shadowColor);
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     KURL url(cachedImage->url());
1115     RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
1116     bool originClean = m_canvas->document()->securityOrigin()->canAccess(origin.get());
1117     return CanvasPattern::create(cachedImage->image(), repeatX, repeatY, originClean);
1118 }
1119
1120 PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas,
1121     const String& repetitionType, ExceptionCode& ec)
1122 {
1123     if (!canvas->width() || !canvas->height()) {
1124         ec = INVALID_STATE_ERR;
1125         return 0;
1126     }
1127     
1128     bool repeatX, repeatY;
1129     ec = 0;
1130     CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
1131     if (ec)
1132         return 0;
1133     return CanvasPattern::create(canvas->buffer()->image(), repeatX, repeatY, canvas->originClean());
1134 }
1135
1136 void CanvasRenderingContext2D::willDraw(const FloatRect& r, unsigned options)
1137 {
1138     GraphicsContext* c = drawingContext();
1139     if (!c)
1140         return;
1141     if (!state().m_invertibleCTM)
1142         return;
1143
1144     FloatRect dirtyRect = r;
1145     if (options & CanvasWillDrawApplyTransform) {
1146         AffineTransform ctm = state().m_transform;
1147         dirtyRect = ctm.mapRect(r);
1148     }
1149     
1150     if (options & CanvasWillDrawApplyShadow) {
1151         // The shadow gets applied after transformation
1152         FloatRect shadowRect(dirtyRect);
1153         shadowRect.move(state().m_shadowOffset);
1154         shadowRect.inflate(state().m_shadowBlur);
1155         dirtyRect.unite(shadowRect);
1156     }
1157     
1158     if (options & CanvasWillDrawApplyClip) {
1159         // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
1160         // back out of the GraphicsContext, so to take clip into account for incremental painting,
1161         // we'd have to keep the clip path around.
1162     }
1163     
1164     m_canvas->willDraw(dirtyRect);
1165 }
1166
1167 GraphicsContext* CanvasRenderingContext2D::drawingContext() const
1168 {
1169     return m_canvas->drawingContext();
1170 }
1171
1172 static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size)
1173 {
1174     PassRefPtr<ImageData> data = ImageData::create(size.width(), size.height());
1175     memset(data->data()->data().data(), 0, data->data()->length());
1176     return data;
1177 }
1178
1179 PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh) const
1180 {
1181     FloatSize unscaledSize(sw, sh);
1182     IntSize scaledSize = m_canvas->convertLogicalToDevice(unscaledSize);
1183     if (scaledSize.width() < 1)
1184         scaledSize.setWidth(1);
1185     if (scaledSize.height() < 1)
1186         scaledSize.setHeight(1);
1187     
1188     return createEmptyImageData(scaledSize);
1189 }
1190
1191 PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const
1192 {
1193     if (!m_canvas->originClean()) {
1194         ec = SECURITY_ERR;
1195         return 0;
1196     }
1197     
1198     FloatRect unscaledRect(sx, sy, sw, sh);
1199     IntRect scaledRect = m_canvas->convertLogicalToDevice(unscaledRect);
1200     if (scaledRect.width() < 1)
1201         scaledRect.setWidth(1);
1202     if (scaledRect.height() < 1)
1203         scaledRect.setHeight(1);
1204     ImageBuffer* buffer = m_canvas ? m_canvas->buffer() : 0;
1205     if (!buffer)
1206         return createEmptyImageData(scaledRect.size());
1207     return buffer->getImageData(scaledRect);
1208 }
1209
1210 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec)
1211 {
1212     if (!data) {
1213         ec = TYPE_MISMATCH_ERR;
1214         return;
1215     }
1216     putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec);
1217 }
1218
1219 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, 
1220                                             float dirtyWidth, float dirtyHeight, ExceptionCode& ec)
1221 {
1222     if (!data) {
1223         ec = TYPE_MISMATCH_ERR;
1224         return;
1225     }
1226     if (!isfinite(dx) || !isfinite(dy) || !isfinite(dirtyX) || 
1227         !isfinite(dirtyY) || !isfinite(dirtyWidth) || !isfinite(dirtyHeight)) {
1228         ec = INDEX_SIZE_ERR;
1229         return;
1230     }
1231
1232     ImageBuffer* buffer = m_canvas->buffer();
1233     if (!buffer)
1234         return;
1235
1236     if (dirtyWidth < 0) {
1237         dirtyX += dirtyWidth;
1238         dirtyWidth = -dirtyWidth;
1239     }
1240
1241     if (dirtyHeight < 0) {
1242         dirtyY += dirtyHeight;
1243         dirtyHeight = -dirtyHeight;
1244     }
1245
1246     FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
1247     clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
1248     IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
1249     IntRect sourceRect = enclosingIntRect(clipRect);
1250     sourceRect.move(destOffset);
1251     sourceRect.intersect(IntRect(IntPoint(), buffer->size()));
1252     if (sourceRect.isEmpty())
1253         return;
1254     willDraw(sourceRect, 0);  // ignore transform, shadow and clip
1255     sourceRect.move(-destOffset);
1256     IntPoint destPoint(destOffset.width(), destOffset.height());
1257     
1258     buffer->putImageData(data, sourceRect, destPoint);
1259 }
1260
1261 String CanvasRenderingContext2D::font() const
1262 {
1263     return state().m_unparsedFont;
1264 }
1265
1266 void CanvasRenderingContext2D::setFont(const String& newFont)
1267 {
1268     RefPtr<CSSMutableStyleDeclaration> tempDecl = CSSMutableStyleDeclaration::create();
1269     CSSParser parser(!m_canvas->document()->inCompatMode()); // Use the parse mode of the canvas' document when parsing CSS.
1270         
1271     String declarationText("font: ");
1272     declarationText += newFont;
1273     parser.parseDeclaration(tempDecl.get(), declarationText);
1274     if (!tempDecl->length())
1275         return;
1276             
1277     // The parse succeeded.
1278     state().m_unparsedFont = newFont;
1279     
1280     // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
1281     // relative to the canvas.
1282     RefPtr<RenderStyle> newStyle = RenderStyle::create();
1283     if (m_canvas->computedStyle())
1284         newStyle->setFontDescription(m_canvas->computedStyle()->fontDescription());
1285
1286     // Now map the font property into the style.
1287     CSSStyleSelector* styleSelector = m_canvas->document()->styleSelector();
1288     styleSelector->applyPropertyToStyle(CSSPropertyFont, tempDecl->getPropertyCSSValue(CSSPropertyFont).get(), newStyle.get());
1289     
1290     state().m_font = newStyle->font();
1291     state().m_font.update(styleSelector->fontSelector());
1292     state().m_realizedFont = true;
1293     
1294     // Set the font in the graphics context.
1295     GraphicsContext* c = drawingContext();
1296     if (!c)
1297         return;
1298     c->setFont(state().m_font);
1299 }
1300         
1301 String CanvasRenderingContext2D::textAlign() const
1302 {
1303     return textAlignName(state().m_textAlign);
1304 }
1305
1306 void CanvasRenderingContext2D::setTextAlign(const String& s)
1307 {
1308     TextAlign align;
1309     if (!parseTextAlign(s, align))
1310         return;
1311     state().m_textAlign = align;
1312 }
1313         
1314 String CanvasRenderingContext2D::textBaseline() const
1315 {
1316     return textBaselineName(state().m_textBaseline);
1317 }
1318
1319 void CanvasRenderingContext2D::setTextBaseline(const String& s)
1320 {
1321     TextBaseline baseline;
1322     if (!parseTextBaseline(s, baseline))
1323         return;
1324     state().m_textBaseline = baseline;
1325 }
1326
1327 void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
1328 {
1329     drawTextInternal(text, x, y, true);
1330 }
1331
1332 void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth)
1333 {
1334     drawTextInternal(text, x, y, true, maxWidth, true);
1335 }
1336
1337 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
1338 {
1339     drawTextInternal(text, x, y, false);
1340 }
1341
1342 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
1343 {
1344     drawTextInternal(text, x, y, false, maxWidth, true);
1345 }
1346
1347 PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
1348 {
1349     RefPtr<TextMetrics> metrics = TextMetrics::create();
1350     metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length())));
1351     return metrics;
1352 }
1353
1354 void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float maxWidth, bool useMaxWidth)
1355 {
1356     GraphicsContext* c = drawingContext();
1357     if (!c)
1358         return;
1359     if (!state().m_invertibleCTM)
1360         return;
1361     
1362     const Font& font = accessFont();
1363
1364     // FIXME: Handle maxWidth.
1365     // FIXME: Need to turn off font smoothing.
1366
1367     bool rtl = m_canvas->computedStyle() ? m_canvas->computedStyle()->direction() == RTL : false;
1368     bool override = m_canvas->computedStyle() ? m_canvas->computedStyle()->unicodeBidi() == Override : false;
1369
1370     unsigned length = text.length();
1371     const UChar* string = text.characters();
1372     TextRun textRun(string, length, 0, 0, 0, rtl, override, false, false);
1373
1374     // Draw the item text at the correct point.
1375     FloatPoint location(x, y);
1376     switch (state().m_textBaseline) {
1377         case TopTextBaseline:
1378         case HangingTextBaseline:
1379             location.setY(y + font.ascent());
1380             break;
1381         case BottomTextBaseline:
1382         case IdeographicTextBaseline:
1383             location.setY(y - font.descent());
1384             break;
1385         case MiddleTextBaseline:
1386             location.setY(y - font.descent() + font.height() / 2);
1387             break;
1388         case AlphabeticTextBaseline:
1389         default:
1390              // Do nothing.
1391             break;
1392     }
1393     
1394     float width = font.width(TextRun(text, false, 0, 0, rtl, override));
1395
1396     TextAlign align = state().m_textAlign;
1397     if (align == StartTextAlign)
1398          align = rtl ? RightTextAlign : LeftTextAlign;
1399     else if (align == EndTextAlign)
1400         align = rtl ? LeftTextAlign : RightTextAlign;
1401     
1402     switch (align) {
1403         case CenterTextAlign:
1404             location.setX(location.x() - width / 2);
1405             break;
1406         case RightTextAlign:
1407             location.setX(location.x() - width);
1408             break;
1409         default:
1410             break;
1411     }
1412     
1413     // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
1414     FloatRect textRect = FloatRect(location.x() - font.height() / 2, location.y() - font.ascent() - font.lineGap(),
1415                                    width + font.height(), font.lineSpacing());
1416     if (!fill)
1417         textRect.inflate(c->strokeThickness() / 2);
1418
1419     if (fill)
1420         m_canvas->willDraw(textRect);
1421     else {
1422         // When stroking text, pointy miters can extend outside of textRect, so we
1423         // punt and dirty the whole canvas.
1424         m_canvas->willDraw(FloatRect(0, 0, m_canvas->width(), m_canvas->height()));
1425     }
1426     
1427     CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get();
1428     if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) {
1429         // FIXME: The rect is not big enough for miters on stroked text.
1430         IntRect maskRect = enclosingIntRect(textRect);
1431
1432         auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false);
1433         
1434         GraphicsContext* maskImageContext = maskImage->context();
1435
1436         if (fill)
1437             maskImageContext->setFillColor(Color::black);
1438         else {
1439             maskImageContext->setStrokeColor(Color::black);
1440             maskImageContext->setStrokeThickness(c->strokeThickness());
1441         }
1442
1443         maskImageContext->setTextDrawingMode(fill ? cTextFill : cTextStroke);
1444         maskImageContext->translate(-maskRect.x(), -maskRect.y());
1445         
1446         maskImageContext->setFont(font);
1447         maskImageContext->drawBidiText(textRun, location);
1448         
1449         c->save();
1450         c->clipToImageBuffer(maskRect, maskImage.get());
1451         drawStyle->applyFillColor(c);
1452         c->fillRect(maskRect);
1453         c->restore();
1454
1455         return;
1456     }
1457
1458     c->setTextDrawingMode(fill ? cTextFill : cTextStroke);
1459     c->drawBidiText(textRun, location);
1460 }
1461
1462 const Font& CanvasRenderingContext2D::accessFont()
1463 {
1464     if (!state().m_realizedFont)
1465         setFont(state().m_unparsedFont);
1466     return state().m_font;
1467 }
1468
1469 } // namespace WebCore