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