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