Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / canvas / CanvasRenderingContext2D.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
3  * Copyright (C) 2008, 2010 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  * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
8  * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved.
9  * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34 #include "core/html/canvas/CanvasRenderingContext2D.h"
35
36 #include "bindings/core/v8/ExceptionMessages.h"
37 #include "bindings/core/v8/ExceptionState.h"
38 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
39 #include "core/CSSPropertyNames.h"
40 #include "core/css/CSSFontSelector.h"
41 #include "core/css/StylePropertySet.h"
42 #include "core/css/parser/CSSParser.h"
43 #include "core/css/resolver/StyleResolver.h"
44 #include "core/dom/ExceptionCode.h"
45 #include "core/dom/StyleEngine.h"
46 #include "core/events/Event.h"
47 #include "core/fetch/ImageResource.h"
48 #include "core/frame/ImageBitmap.h"
49 #include "core/html/HTMLCanvasElement.h"
50 #include "core/html/HTMLImageElement.h"
51 #include "core/html/HTMLMediaElement.h"
52 #include "core/html/HTMLVideoElement.h"
53 #include "core/html/ImageData.h"
54 #include "core/html/TextMetrics.h"
55 #include "core/html/canvas/CanvasGradient.h"
56 #include "core/html/canvas/CanvasPattern.h"
57 #include "core/html/canvas/CanvasStyle.h"
58 #include "core/html/canvas/HitRegionOptions.h"
59 #include "core/html/canvas/Path2D.h"
60 #include "core/rendering/RenderImage.h"
61 #include "core/rendering/RenderLayer.h"
62 #include "core/rendering/RenderTheme.h"
63 #include "platform/fonts/FontCache.h"
64 #include "platform/geometry/FloatQuad.h"
65 #include "platform/graphics/DrawLooperBuilder.h"
66 #include "platform/graphics/GraphicsContextStateSaver.h"
67 #include "platform/text/TextRun.h"
68 #include "wtf/CheckedArithmetic.h"
69 #include "wtf/MathExtras.h"
70 #include "wtf/OwnPtr.h"
71 #include "wtf/Uint8ClampedArray.h"
72 #include "wtf/text/StringBuilder.h"
73
74 namespace blink {
75
76 static const int defaultFontSize = 10;
77 static const char defaultFontFamily[] = "sans-serif";
78 static const char defaultFont[] = "10px sans-serif";
79 static const char inherit[] = "inherit";
80 static const char rtl[] = "rtl";
81 static const char ltr[] = "ltr";
82 static const double TryRestoreContextInterval = 0.5;
83 static const unsigned MaxTryRestoreContextAttempts = 4;
84
85 static bool contextLostRestoredEventsEnabled()
86 {
87     return RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled();
88 }
89
90 CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, const Canvas2DContextAttributes* attrs, bool usesCSSCompatibilityParseMode)
91     : CanvasRenderingContext(canvas)
92     , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
93     , m_hasAlpha(!attrs || attrs->alpha())
94     , m_isContextLost(false)
95     , m_contextRestorable(true)
96     , m_storageMode(!attrs ? PersistentStorage : attrs->parsedStorage())
97     , m_tryRestoreContextAttemptCount(0)
98     , m_dispatchContextLostEventTimer(this, &CanvasRenderingContext2D::dispatchContextLostEvent)
99     , m_dispatchContextRestoredEventTimer(this, &CanvasRenderingContext2D::dispatchContextRestoredEvent)
100     , m_tryRestoreContextEventTimer(this, &CanvasRenderingContext2D::tryRestoreContextEvent)
101 {
102     m_stateStack.append(adoptPtrWillBeNoop(new State()));
103 }
104
105 void CanvasRenderingContext2D::unwindStateStack()
106 {
107     if (size_t stackSize = m_stateStack.size()) {
108         if (GraphicsContext* context = canvas()->existingDrawingContext()) {
109             while (--stackSize)
110                 context->restore();
111         }
112     }
113 }
114
115 CanvasRenderingContext2D::~CanvasRenderingContext2D()
116 {
117 }
118
119 void CanvasRenderingContext2D::validateStateStack()
120 {
121 #if ENABLE(ASSERT)
122     GraphicsContext* context = canvas()->existingDrawingContext();
123     if (context && !context->contextDisabled())
124         ASSERT(context->saveCount() == m_stateStack.size());
125 #endif
126 }
127
128 bool CanvasRenderingContext2D::isAccelerated() const
129 {
130     if (!canvas()->hasImageBuffer())
131         return false;
132     GraphicsContext* context = drawingContext();
133     return context && context->isAccelerated();
134 }
135
136 bool CanvasRenderingContext2D::isContextLost() const
137 {
138     return m_isContextLost;
139 }
140
141 void CanvasRenderingContext2D::loseContext()
142 {
143     if (m_isContextLost)
144         return;
145     m_isContextLost = true;
146     m_dispatchContextLostEventTimer.startOneShot(0, FROM_HERE);
147 }
148
149 void CanvasRenderingContext2D::restoreContext()
150 {
151     if (!m_contextRestorable)
152         return;
153     // This code path is for restoring from an eviction
154     // Restoring from surface failure is handled internally
155     ASSERT(m_isContextLost && !canvas()->hasImageBuffer());
156
157     if (canvas()->buffer()) {
158         if (contextLostRestoredEventsEnabled()) {
159             m_dispatchContextRestoredEventTimer.startOneShot(0, FROM_HERE);
160         } else {
161             // legacy synchronous context restoration.
162             reset();
163             m_isContextLost = false;
164         }
165     }
166 }
167
168 void CanvasRenderingContext2D::trace(Visitor* visitor)
169 {
170 #if ENABLE(OILPAN)
171     visitor->trace(m_stateStack);
172     visitor->trace(m_fetchedFonts);
173     visitor->trace(m_hitRegionManager);
174 #endif
175     CanvasRenderingContext::trace(visitor);
176 }
177
178 void CanvasRenderingContext2D::dispatchContextLostEvent(Timer<CanvasRenderingContext2D>*)
179 {
180     if (contextLostRestoredEventsEnabled()) {
181         RefPtrWillBeRawPtr<Event> event = Event::createCancelable(EventTypeNames::contextlost);
182         canvas()->dispatchEvent(event);
183         if (event->defaultPrevented()) {
184             m_contextRestorable = false;
185         }
186     }
187
188     // If an image buffer is present, it means the context was not lost due to
189     // an eviction, but rather due to a surface failure (gpu context lost?)
190     if (m_contextRestorable && canvas()->hasImageBuffer()) {
191         m_tryRestoreContextAttemptCount = 0;
192         m_tryRestoreContextEventTimer.startRepeating(TryRestoreContextInterval, FROM_HERE);
193     }
194 }
195
196 void CanvasRenderingContext2D::tryRestoreContextEvent(Timer<CanvasRenderingContext2D>* timer)
197 {
198     if (!m_isContextLost) {
199         // Canvas was already restored (possibly thanks to a resize), so stop trying.
200         m_tryRestoreContextEventTimer.stop();
201         return;
202     }
203     if (canvas()->hasImageBuffer() && canvas()->buffer()->restoreSurface()) {
204         m_tryRestoreContextEventTimer.stop();
205         dispatchContextRestoredEvent(0);
206     }
207
208     if (++m_tryRestoreContextAttemptCount > MaxTryRestoreContextAttempts)
209         canvas()->discardImageBuffer();
210
211     if (!canvas()->hasImageBuffer()) {
212         // final attempt: allocate a brand new image buffer instead of restoring
213         timer->stop();
214         if (canvas()->buffer())
215             dispatchContextRestoredEvent(0);
216     }
217 }
218
219 void CanvasRenderingContext2D::dispatchContextRestoredEvent(Timer<CanvasRenderingContext2D>*)
220 {
221     if (!m_isContextLost)
222         return;
223     reset();
224     m_isContextLost = false;
225     if (contextLostRestoredEventsEnabled()) {
226         RefPtrWillBeRawPtr<Event> event(Event::create(EventTypeNames::contextrestored));
227         canvas()->dispatchEvent(event);
228     }
229 }
230
231 void CanvasRenderingContext2D::reset()
232 {
233     validateStateStack();
234     unwindStateStack();
235     m_stateStack.resize(1);
236     m_stateStack.first() = adoptPtrWillBeNoop(new State());
237     m_path.clear();
238     validateStateStack();
239 }
240
241 // Important: Several of these properties are also stored in GraphicsContext's
242 // StrokeData. The default values that StrokeData uses may not the same values
243 // that the canvas 2d spec specifies. Make sure to sync the initial state of the
244 // GraphicsContext in HTMLCanvasElement::createImageBuffer()!
245 CanvasRenderingContext2D::State::State()
246     : m_unrealizedSaveCount(0)
247     , m_strokeStyle(CanvasStyle::createFromRGBA(Color::black))
248     , m_fillStyle(CanvasStyle::createFromRGBA(Color::black))
249     , m_lineWidth(1)
250     , m_lineCap(ButtCap)
251     , m_lineJoin(MiterJoin)
252     , m_miterLimit(10)
253     , m_shadowBlur(0)
254     , m_shadowColor(Color::transparent)
255     , m_globalAlpha(1)
256     , m_globalComposite(CompositeSourceOver)
257     , m_globalBlend(blink::WebBlendModeNormal)
258     , m_invertibleCTM(true)
259     , m_lineDashOffset(0)
260     , m_imageSmoothingEnabled(true)
261     , m_textAlign(StartTextAlign)
262     , m_textBaseline(AlphabeticTextBaseline)
263     , m_direction(DirectionInherit)
264     , m_unparsedFont(defaultFont)
265     , m_realizedFont(false)
266     , m_hasClip(false)
267 {
268 }
269
270 CanvasRenderingContext2D::State::State(const State& other)
271     : CSSFontSelectorClient()
272     , m_unrealizedSaveCount(other.m_unrealizedSaveCount)
273     , m_unparsedStrokeColor(other.m_unparsedStrokeColor)
274     , m_unparsedFillColor(other.m_unparsedFillColor)
275     , m_strokeStyle(other.m_strokeStyle)
276     , m_fillStyle(other.m_fillStyle)
277     , m_lineWidth(other.m_lineWidth)
278     , m_lineCap(other.m_lineCap)
279     , m_lineJoin(other.m_lineJoin)
280     , m_miterLimit(other.m_miterLimit)
281     , m_shadowOffset(other.m_shadowOffset)
282     , m_shadowBlur(other.m_shadowBlur)
283     , m_shadowColor(other.m_shadowColor)
284     , m_globalAlpha(other.m_globalAlpha)
285     , m_globalComposite(other.m_globalComposite)
286     , m_globalBlend(other.m_globalBlend)
287     , m_transform(other.m_transform)
288     , m_invertibleCTM(other.m_invertibleCTM)
289     , m_lineDashOffset(other.m_lineDashOffset)
290     , m_imageSmoothingEnabled(other.m_imageSmoothingEnabled)
291     , m_textAlign(other.m_textAlign)
292     , m_textBaseline(other.m_textBaseline)
293     , m_direction(other.m_direction)
294     , m_unparsedFont(other.m_unparsedFont)
295     , m_font(other.m_font)
296     , m_realizedFont(other.m_realizedFont)
297     , m_hasClip(other.m_hasClip)
298 {
299     if (m_realizedFont)
300         static_cast<CSSFontSelector*>(m_font.fontSelector())->registerForInvalidationCallbacks(this);
301 }
302
303 CanvasRenderingContext2D::State& CanvasRenderingContext2D::State::operator=(const State& other)
304 {
305     if (this == &other)
306         return *this;
307
308 #if !ENABLE(OILPAN)
309     if (m_realizedFont)
310         static_cast<CSSFontSelector*>(m_font.fontSelector())->unregisterForInvalidationCallbacks(this);
311 #endif
312
313     m_unrealizedSaveCount = other.m_unrealizedSaveCount;
314     m_unparsedStrokeColor = other.m_unparsedStrokeColor;
315     m_unparsedFillColor = other.m_unparsedFillColor;
316     m_strokeStyle = other.m_strokeStyle;
317     m_fillStyle = other.m_fillStyle;
318     m_lineWidth = other.m_lineWidth;
319     m_lineCap = other.m_lineCap;
320     m_lineJoin = other.m_lineJoin;
321     m_miterLimit = other.m_miterLimit;
322     m_shadowOffset = other.m_shadowOffset;
323     m_shadowBlur = other.m_shadowBlur;
324     m_shadowColor = other.m_shadowColor;
325     m_globalAlpha = other.m_globalAlpha;
326     m_globalComposite = other.m_globalComposite;
327     m_globalBlend = other.m_globalBlend;
328     m_transform = other.m_transform;
329     m_invertibleCTM = other.m_invertibleCTM;
330     m_imageSmoothingEnabled = other.m_imageSmoothingEnabled;
331     m_textAlign = other.m_textAlign;
332     m_textBaseline = other.m_textBaseline;
333     m_direction = other.m_direction;
334     m_unparsedFont = other.m_unparsedFont;
335     m_font = other.m_font;
336     m_realizedFont = other.m_realizedFont;
337     m_hasClip = other.m_hasClip;
338
339     if (m_realizedFont)
340         static_cast<CSSFontSelector*>(m_font.fontSelector())->registerForInvalidationCallbacks(this);
341
342     return *this;
343 }
344
345 CanvasRenderingContext2D::State::~State()
346 {
347 #if !ENABLE(OILPAN)
348     if (m_realizedFont)
349         static_cast<CSSFontSelector*>(m_font.fontSelector())->unregisterForInvalidationCallbacks(this);
350 #endif
351 }
352
353 void CanvasRenderingContext2D::State::fontsNeedUpdate(CSSFontSelector* fontSelector)
354 {
355     ASSERT_ARG(fontSelector, fontSelector == m_font.fontSelector());
356     ASSERT(m_realizedFont);
357
358     m_font.update(fontSelector);
359 }
360
361 void CanvasRenderingContext2D::State::trace(Visitor* visitor)
362 {
363     visitor->trace(m_strokeStyle);
364     visitor->trace(m_fillStyle);
365     CSSFontSelectorClient::trace(visitor);
366 }
367
368 void CanvasRenderingContext2D::realizeSaves(GraphicsContext* context)
369 {
370     validateStateStack();
371     if (state().m_unrealizedSaveCount) {
372         ASSERT(m_stateStack.size() >= 1);
373         // Reduce the current state's unrealized count by one now,
374         // to reflect the fact we are saving one state.
375         m_stateStack.last()->m_unrealizedSaveCount--;
376         m_stateStack.append(adoptPtrWillBeNoop(new State(state())));
377         // Set the new state's unrealized count to 0, because it has no outstanding saves.
378         // We need to do this explicitly because the copy constructor and operator= used
379         // by the Vector operations copy the unrealized count from the previous state (in
380         // turn necessary to support correct resizing and unwinding of the stack).
381         m_stateStack.last()->m_unrealizedSaveCount = 0;
382         if (!context)
383             context = drawingContext();
384         if (context)
385             context->save();
386         validateStateStack();
387     }
388 }
389
390 void CanvasRenderingContext2D::restore()
391 {
392     validateStateStack();
393     if (state().m_unrealizedSaveCount) {
394         // We never realized the save, so just record that it was unnecessary.
395         --m_stateStack.last()->m_unrealizedSaveCount;
396         return;
397     }
398     ASSERT(m_stateStack.size() >= 1);
399     if (m_stateStack.size() <= 1)
400         return;
401     m_path.transform(state().m_transform);
402     m_stateStack.removeLast();
403     m_path.transform(state().m_transform.inverse());
404     GraphicsContext* c = drawingContext();
405     if (c)
406         c->restore();
407     validateStateStack();
408 }
409
410 CanvasStyle* CanvasRenderingContext2D::strokeStyle() const
411 {
412     return state().m_strokeStyle.get();
413 }
414
415 void CanvasRenderingContext2D::setStrokeStyle(PassRefPtrWillBeRawPtr<CanvasStyle> prpStyle)
416 {
417     RefPtrWillBeRawPtr<CanvasStyle> style = prpStyle;
418
419     if (!style)
420         return;
421
422     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style))
423         return;
424
425     if (style->isCurrentColor()) {
426         if (style->hasOverrideAlpha())
427             style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha()));
428         else
429             style = CanvasStyle::createFromRGBA(currentColor(canvas()));
430     } else if (canvas()->originClean() && style->canvasPattern() && !style->canvasPattern()->originClean()) {
431         canvas()->setOriginTainted();
432     }
433
434     GraphicsContext* c = drawingContext();
435     realizeSaves(c);
436     modifiableState().m_strokeStyle = style.release();
437     if (!c)
438         return;
439     state().m_strokeStyle->applyStrokeColor(c);
440     modifiableState().m_unparsedStrokeColor = String();
441 }
442
443 CanvasStyle* CanvasRenderingContext2D::fillStyle() const
444 {
445     return state().m_fillStyle.get();
446 }
447
448 void CanvasRenderingContext2D::setFillStyle(PassRefPtrWillBeRawPtr<CanvasStyle> prpStyle)
449 {
450     RefPtrWillBeRawPtr<CanvasStyle> style = prpStyle;
451
452     if (!style)
453         return;
454
455     if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style))
456         return;
457
458     if (style->isCurrentColor()) {
459         if (style->hasOverrideAlpha())
460             style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha()));
461         else
462             style = CanvasStyle::createFromRGBA(currentColor(canvas()));
463     } else if (canvas()->originClean() && style->canvasPattern() && !style->canvasPattern()->originClean()) {
464         canvas()->setOriginTainted();
465     }
466
467     GraphicsContext* c = drawingContext();
468     realizeSaves(c);
469     modifiableState().m_fillStyle = style.release();
470     if (!c)
471         return;
472     state().m_fillStyle->applyFillColor(c);
473     modifiableState().m_unparsedFillColor = String();
474 }
475
476 float CanvasRenderingContext2D::lineWidth() const
477 {
478     return state().m_lineWidth;
479 }
480
481 void CanvasRenderingContext2D::setLineWidth(float width)
482 {
483     if (!(std::isfinite(width) && width > 0))
484         return;
485     if (state().m_lineWidth == width)
486         return;
487     GraphicsContext* c = drawingContext();
488     realizeSaves(c);
489     modifiableState().m_lineWidth = width;
490     if (!c)
491         return;
492     c->setStrokeThickness(width);
493 }
494
495 String CanvasRenderingContext2D::lineCap() const
496 {
497     return lineCapName(state().m_lineCap);
498 }
499
500 void CanvasRenderingContext2D::setLineCap(const String& s)
501 {
502     LineCap cap;
503     if (!parseLineCap(s, cap))
504         return;
505     if (state().m_lineCap == cap)
506         return;
507     GraphicsContext* c = drawingContext();
508     realizeSaves(c);
509     modifiableState().m_lineCap = cap;
510     if (!c)
511         return;
512     c->setLineCap(cap);
513 }
514
515 String CanvasRenderingContext2D::lineJoin() const
516 {
517     return lineJoinName(state().m_lineJoin);
518 }
519
520 void CanvasRenderingContext2D::setLineJoin(const String& s)
521 {
522     LineJoin join;
523     if (!parseLineJoin(s, join))
524         return;
525     if (state().m_lineJoin == join)
526         return;
527     GraphicsContext* c = drawingContext();
528     realizeSaves(c);
529     modifiableState().m_lineJoin = join;
530     if (!c)
531         return;
532     c->setLineJoin(join);
533 }
534
535 float CanvasRenderingContext2D::miterLimit() const
536 {
537     return state().m_miterLimit;
538 }
539
540 void CanvasRenderingContext2D::setMiterLimit(float limit)
541 {
542     if (!(std::isfinite(limit) && limit > 0))
543         return;
544     if (state().m_miterLimit == limit)
545         return;
546     GraphicsContext* c = drawingContext();
547     realizeSaves(c);
548     modifiableState().m_miterLimit = limit;
549     if (!c)
550         return;
551     c->setMiterLimit(limit);
552 }
553
554 float CanvasRenderingContext2D::shadowOffsetX() const
555 {
556     return state().m_shadowOffset.width();
557 }
558
559 void CanvasRenderingContext2D::setShadowOffsetX(float x)
560 {
561     if (!std::isfinite(x))
562         return;
563     if (state().m_shadowOffset.width() == x)
564         return;
565     realizeSaves(0);
566     modifiableState().m_shadowOffset.setWidth(x);
567     applyShadow();
568 }
569
570 float CanvasRenderingContext2D::shadowOffsetY() const
571 {
572     return state().m_shadowOffset.height();
573 }
574
575 void CanvasRenderingContext2D::setShadowOffsetY(float y)
576 {
577     if (!std::isfinite(y))
578         return;
579     if (state().m_shadowOffset.height() == y)
580         return;
581     realizeSaves(0);
582     modifiableState().m_shadowOffset.setHeight(y);
583     applyShadow();
584 }
585
586 float CanvasRenderingContext2D::shadowBlur() const
587 {
588     return state().m_shadowBlur;
589 }
590
591 void CanvasRenderingContext2D::setShadowBlur(float blur)
592 {
593     if (!(std::isfinite(blur) && blur >= 0))
594         return;
595     if (state().m_shadowBlur == blur)
596         return;
597     realizeSaves(0);
598     modifiableState().m_shadowBlur = blur;
599     applyShadow();
600 }
601
602 String CanvasRenderingContext2D::shadowColor() const
603 {
604     return Color(state().m_shadowColor).serialized();
605 }
606
607 void CanvasRenderingContext2D::setShadowColor(const String& color)
608 {
609     RGBA32 rgba;
610     if (!parseColorOrCurrentColor(rgba, color, canvas()))
611         return;
612     if (state().m_shadowColor == rgba)
613         return;
614     realizeSaves(0);
615     modifiableState().m_shadowColor = rgba;
616     applyShadow();
617 }
618
619 const Vector<float>& CanvasRenderingContext2D::getLineDash() const
620 {
621     return state().m_lineDash;
622 }
623
624 static bool lineDashSequenceIsValid(const Vector<float>& dash)
625 {
626     for (size_t i = 0; i < dash.size(); i++) {
627         if (!std::isfinite(dash[i]) || dash[i] < 0)
628             return false;
629     }
630     return true;
631 }
632
633 void CanvasRenderingContext2D::setLineDash(const Vector<float>& dash)
634 {
635     if (!lineDashSequenceIsValid(dash))
636         return;
637
638     realizeSaves(0);
639     modifiableState().m_lineDash = dash;
640     // Spec requires the concatenation of two copies the dash list when the
641     // number of elements is odd
642     if (dash.size() % 2)
643         modifiableState().m_lineDash.appendVector(dash);
644
645     applyLineDash();
646 }
647
648 float CanvasRenderingContext2D::lineDashOffset() const
649 {
650     return state().m_lineDashOffset;
651 }
652
653 void CanvasRenderingContext2D::setLineDashOffset(float offset)
654 {
655     if (!std::isfinite(offset) || state().m_lineDashOffset == offset)
656         return;
657
658     realizeSaves(0);
659     modifiableState().m_lineDashOffset = offset;
660     applyLineDash();
661 }
662
663 void CanvasRenderingContext2D::applyLineDash() const
664 {
665     GraphicsContext* c = drawingContext();
666     if (!c)
667         return;
668     DashArray convertedLineDash(state().m_lineDash.size());
669     for (size_t i = 0; i < state().m_lineDash.size(); ++i)
670         convertedLineDash[i] = static_cast<DashArrayElement>(state().m_lineDash[i]);
671     c->setLineDash(convertedLineDash, state().m_lineDashOffset);
672 }
673
674 float CanvasRenderingContext2D::globalAlpha() const
675 {
676     return state().m_globalAlpha;
677 }
678
679 void CanvasRenderingContext2D::setGlobalAlpha(float alpha)
680 {
681     if (!(alpha >= 0 && alpha <= 1))
682         return;
683     if (state().m_globalAlpha == alpha)
684         return;
685     GraphicsContext* c = drawingContext();
686     realizeSaves(c);
687     modifiableState().m_globalAlpha = alpha;
688     if (!c)
689         return;
690     c->setAlphaAsFloat(alpha);
691 }
692
693 String CanvasRenderingContext2D::globalCompositeOperation() const
694 {
695     return compositeOperatorName(state().m_globalComposite, state().m_globalBlend);
696 }
697
698 void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation)
699 {
700     CompositeOperator op = CompositeSourceOver;
701     blink::WebBlendMode blendMode = blink::WebBlendModeNormal;
702     if (!parseCompositeAndBlendOperator(operation, op, blendMode))
703         return;
704     if ((state().m_globalComposite == op) && (state().m_globalBlend == blendMode))
705         return;
706     GraphicsContext* c = drawingContext();
707     realizeSaves(c);
708     modifiableState().m_globalComposite = op;
709     modifiableState().m_globalBlend = blendMode;
710     if (!c)
711         return;
712     c->setCompositeOperation(op, blendMode);
713 }
714
715 void CanvasRenderingContext2D::setCurrentTransform(PassRefPtr<SVGMatrixTearOff> passMatrixTearOff)
716 {
717     RefPtr<SVGMatrixTearOff> matrixTearOff = passMatrixTearOff;
718     const AffineTransform& transform = matrixTearOff->value();
719     setTransform(transform.a(), transform.b(), transform.c(), transform.d(), transform.e(), transform.f());
720 }
721
722 void CanvasRenderingContext2D::scale(float sx, float sy)
723 {
724     GraphicsContext* c = drawingContext();
725     if (!c)
726         return;
727     if (!state().m_invertibleCTM)
728         return;
729
730     if (!std::isfinite(sx) | !std::isfinite(sy))
731         return;
732
733     AffineTransform newTransform = state().m_transform;
734     newTransform.scaleNonUniform(sx, sy);
735     if (state().m_transform == newTransform)
736         return;
737
738     realizeSaves(c);
739
740     if (!newTransform.isInvertible()) {
741         modifiableState().m_invertibleCTM = false;
742         return;
743     }
744
745     modifiableState().m_transform = newTransform;
746     c->scale(sx, sy);
747     m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
748 }
749
750 void CanvasRenderingContext2D::rotate(float angleInRadians)
751 {
752     GraphicsContext* c = drawingContext();
753     if (!c)
754         return;
755     if (!state().m_invertibleCTM)
756         return;
757
758     if (!std::isfinite(angleInRadians))
759         return;
760
761     AffineTransform newTransform = state().m_transform;
762     newTransform.rotateRadians(angleInRadians);
763     if (state().m_transform == newTransform)
764         return;
765
766     realizeSaves(c);
767
768     if (!newTransform.isInvertible()) {
769         modifiableState().m_invertibleCTM = false;
770         return;
771     }
772
773     modifiableState().m_transform = newTransform;
774     c->rotate(angleInRadians);
775     m_path.transform(AffineTransform().rotateRadians(-angleInRadians));
776 }
777
778 void CanvasRenderingContext2D::translate(float tx, float ty)
779 {
780     GraphicsContext* c = drawingContext();
781     if (!c)
782         return;
783     if (!state().m_invertibleCTM)
784         return;
785
786     if (!std::isfinite(tx) | !std::isfinite(ty))
787         return;
788
789     AffineTransform newTransform = state().m_transform;
790     newTransform.translate(tx, ty);
791     if (state().m_transform == newTransform)
792         return;
793
794     realizeSaves(c);
795
796     if (!newTransform.isInvertible()) {
797         modifiableState().m_invertibleCTM = false;
798         return;
799     }
800
801     modifiableState().m_transform = newTransform;
802     c->translate(tx, ty);
803     m_path.transform(AffineTransform().translate(-tx, -ty));
804 }
805
806 void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy)
807 {
808     GraphicsContext* c = drawingContext();
809     if (!c)
810         return;
811     if (!state().m_invertibleCTM)
812         return;
813
814     if (!std::isfinite(m11) | !std::isfinite(m21) | !std::isfinite(dx) | !std::isfinite(m12) | !std::isfinite(m22) | !std::isfinite(dy))
815         return;
816
817     AffineTransform transform(m11, m12, m21, m22, dx, dy);
818     AffineTransform newTransform = state().m_transform * transform;
819     if (state().m_transform == newTransform)
820         return;
821
822     realizeSaves(c);
823
824     modifiableState().m_transform = newTransform;
825     if (!newTransform.isInvertible()) {
826         modifiableState().m_invertibleCTM = false;
827         return;
828     }
829
830     c->concatCTM(transform);
831     m_path.transform(transform.inverse());
832 }
833
834 void CanvasRenderingContext2D::resetTransform()
835 {
836     GraphicsContext* c = drawingContext();
837     if (!c)
838         return;
839
840     AffineTransform ctm = state().m_transform;
841     bool invertibleCTM = state().m_invertibleCTM;
842     // It is possible that CTM is identity while CTM is not invertible.
843     // When CTM becomes non-invertible, realizeSaves() can make CTM identity.
844     if (ctm.isIdentity() && invertibleCTM)
845         return;
846
847     realizeSaves(c);
848     // resetTransform() resolves the non-invertible CTM state.
849     modifiableState().m_transform.makeIdentity();
850     modifiableState().m_invertibleCTM = true;
851     c->setCTM(canvas()->baseTransform());
852
853     if (invertibleCTM)
854         m_path.transform(ctm);
855     // When else, do nothing because all transform methods didn't update m_path when CTM became non-invertible.
856     // It means that resetTransform() restores m_path just before CTM became non-invertible.
857 }
858
859 void CanvasRenderingContext2D::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
860 {
861     GraphicsContext* c = drawingContext();
862     if (!c)
863         return;
864
865     if (!std::isfinite(m11) | !std::isfinite(m21) | !std::isfinite(dx) | !std::isfinite(m12) | !std::isfinite(m22) | !std::isfinite(dy))
866         return;
867
868     resetTransform();
869     transform(m11, m12, m21, m22, dx, dy);
870 }
871
872 void CanvasRenderingContext2D::setStrokeColor(const String& color)
873 {
874     if (color == state().m_unparsedStrokeColor)
875         return;
876     realizeSaves(0);
877     setStrokeStyle(CanvasStyle::createFromString(color));
878     modifiableState().m_unparsedStrokeColor = color;
879 }
880
881 void CanvasRenderingContext2D::setStrokeColor(float grayLevel)
882 {
883     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
884         return;
885     setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
886 }
887
888 void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
889 {
890     setStrokeStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
891 }
892
893 void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
894 {
895     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
896         return;
897     setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
898 }
899
900 void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a)
901 {
902     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(r, g, b, a))
903         return;
904     setStrokeStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
905 }
906
907 void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a)
908 {
909     if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentCMYKA(c, m, y, k, a))
910         return;
911     setStrokeStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
912 }
913
914 void CanvasRenderingContext2D::setFillColor(const String& color)
915 {
916     if (color == state().m_unparsedFillColor)
917         return;
918     realizeSaves(0);
919     setFillStyle(CanvasStyle::createFromString(color));
920     modifiableState().m_unparsedFillColor = color;
921 }
922
923 void CanvasRenderingContext2D::setFillColor(float grayLevel)
924 {
925     if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
926         return;
927     setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
928 }
929
930 void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
931 {
932     setFillStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
933 }
934
935 void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
936 {
937     if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
938         return;
939     setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
940 }
941
942 void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
943 {
944     if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(r, g, b, a))
945         return;
946     setFillStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
947 }
948
949 void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
950 {
951     if (state().m_fillStyle && state().m_fillStyle->isEquivalentCMYKA(c, m, y, k, a))
952         return;
953     setFillStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
954 }
955
956 void CanvasRenderingContext2D::beginPath()
957 {
958     m_path.clear();
959 }
960
961 static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
962 {
963     if (!std::isfinite(x) | !std::isfinite(y) | !std::isfinite(width) | !std::isfinite(height))
964         return false;
965
966     if (!width && !height)
967         return false;
968
969     if (width < 0) {
970         width = -width;
971         x -= width;
972     }
973
974     if (height < 0) {
975         height = -height;
976         y -= height;
977     }
978
979     return true;
980 }
981
982 static bool isFullCanvasCompositeMode(CompositeOperator op)
983 {
984     // See 4.8.11.1.3 Compositing
985     // CompositeSourceAtop and CompositeDestinationOut are not listed here as the platforms already
986     // implement the specification's behavior.
987     return op == CompositeSourceIn || op == CompositeSourceOut || op == CompositeDestinationIn || op == CompositeDestinationAtop;
988 }
989
990 static WindRule parseWinding(const String& windingRuleString)
991 {
992     if (windingRuleString == "nonzero")
993         return RULE_NONZERO;
994     if (windingRuleString == "evenodd")
995         return RULE_EVENODD;
996
997     ASSERT_NOT_REACHED();
998     return RULE_EVENODD;
999 }
1000
1001 void CanvasRenderingContext2D::fillInternal(const Path& path, const String& windingRuleString)
1002 {
1003     if (path.isEmpty()) {
1004         return;
1005     }
1006     GraphicsContext* c = drawingContext();
1007     if (!c) {
1008         return;
1009     }
1010     if (!state().m_invertibleCTM) {
1011         return;
1012     }
1013     FloatRect clipBounds;
1014     if (!c->getTransformedClipBounds(&clipBounds)) {
1015         return;
1016     }
1017
1018     // If gradient size is zero, then paint nothing.
1019     Gradient* gradient = c->fillGradient();
1020     if (gradient && gradient->isZeroSize()) {
1021         return;
1022     }
1023
1024     WindRule windRule = c->fillRule();
1025     c->setFillRule(parseWinding(windingRuleString));
1026
1027     if (isFullCanvasCompositeMode(state().m_globalComposite)) {
1028         fullCanvasCompositedFill(path);
1029         didDraw(clipBounds);
1030     } else if (state().m_globalComposite == CompositeCopy) {
1031         clearCanvas();
1032         c->fillPath(path);
1033         didDraw(clipBounds);
1034     } else {
1035         FloatRect dirtyRect;
1036         if (computeDirtyRect(path.boundingRect(), clipBounds, &dirtyRect)) {
1037             c->fillPath(path);
1038             didDraw(dirtyRect);
1039         }
1040     }
1041
1042     c->setFillRule(windRule);
1043 }
1044
1045 void CanvasRenderingContext2D::fill(const String& windingRuleString)
1046 {
1047     fillInternal(m_path, windingRuleString);
1048 }
1049
1050 void CanvasRenderingContext2D::fill(Path2D* domPath, const String& windingRuleString)
1051 {
1052     fillInternal(domPath->path(), windingRuleString);
1053 }
1054
1055 void CanvasRenderingContext2D::strokeInternal(const Path& path)
1056 {
1057     if (path.isEmpty()) {
1058         return;
1059     }
1060     GraphicsContext* c = drawingContext();
1061     if (!c) {
1062         return;
1063     }
1064     if (!state().m_invertibleCTM) {
1065         return;
1066     }
1067     FloatRect clipBounds;
1068     if (!c->getTransformedClipBounds(&clipBounds))
1069         return;
1070
1071     // If gradient size is zero, then paint nothing.
1072     Gradient* gradient = c->strokeGradient();
1073     if (gradient && gradient->isZeroSize()) {
1074         return;
1075     }
1076
1077     if (isFullCanvasCompositeMode(state().m_globalComposite)) {
1078         fullCanvasCompositedStroke(path);
1079         didDraw(clipBounds);
1080     } else if (state().m_globalComposite == CompositeCopy) {
1081         clearCanvas();
1082         c->strokePath(path);
1083         didDraw(clipBounds);
1084     } else {
1085         FloatRect bounds = path.boundingRect();
1086         inflateStrokeRect(bounds);
1087         FloatRect dirtyRect;
1088         if (computeDirtyRect(bounds, clipBounds, &dirtyRect)) {
1089             c->strokePath(path);
1090             didDraw(dirtyRect);
1091         }
1092     }
1093 }
1094
1095 void CanvasRenderingContext2D::stroke()
1096 {
1097     strokeInternal(m_path);
1098 }
1099
1100 void CanvasRenderingContext2D::stroke(Path2D* domPath)
1101 {
1102     strokeInternal(domPath->path());
1103 }
1104
1105 void CanvasRenderingContext2D::clipInternal(const Path& path, const String& windingRuleString)
1106 {
1107     GraphicsContext* c = drawingContext();
1108     if (!c) {
1109         return;
1110     }
1111     if (!state().m_invertibleCTM) {
1112         return;
1113     }
1114
1115     realizeSaves(c);
1116     c->canvasClip(path, parseWinding(windingRuleString));
1117     modifiableState().m_hasClip = true;
1118 }
1119
1120 void CanvasRenderingContext2D::clip(const String& windingRuleString)
1121 {
1122     clipInternal(m_path, windingRuleString);
1123 }
1124
1125 void CanvasRenderingContext2D::clip(Path2D* domPath, const String& windingRuleString)
1126 {
1127     clipInternal(domPath->path(), windingRuleString);
1128 }
1129
1130 bool CanvasRenderingContext2D::isPointInPath(const float x, const float y, const String& windingRuleString)
1131 {
1132     return isPointInPathInternal(m_path, x, y, windingRuleString);
1133 }
1134
1135 bool CanvasRenderingContext2D::isPointInPath(Path2D* domPath, const float x, const float y, const String& windingRuleString)
1136 {
1137     return isPointInPathInternal(domPath->path(), x, y, windingRuleString);
1138 }
1139
1140 bool CanvasRenderingContext2D::isPointInPathInternal(const Path& path, const float x, const float y, const String& windingRuleString)
1141 {
1142     GraphicsContext* c = drawingContext();
1143     if (!c)
1144         return false;
1145     if (!state().m_invertibleCTM)
1146         return false;
1147
1148     FloatPoint point(x, y);
1149     AffineTransform ctm = state().m_transform;
1150     FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
1151     if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
1152         return false;
1153
1154     return path.contains(transformedPoint, parseWinding(windingRuleString));
1155 }
1156
1157 bool CanvasRenderingContext2D::isPointInStroke(const float x, const float y)
1158 {
1159     return isPointInStrokeInternal(m_path, x, y);
1160 }
1161
1162 bool CanvasRenderingContext2D::isPointInStroke(Path2D* domPath, const float x, const float y)
1163 {
1164     return isPointInStrokeInternal(domPath->path(), x, y);
1165 }
1166
1167 bool CanvasRenderingContext2D::isPointInStrokeInternal(const Path& path, const float x, const float y)
1168 {
1169     GraphicsContext* c = drawingContext();
1170     if (!c)
1171         return false;
1172     if (!state().m_invertibleCTM)
1173         return false;
1174
1175     FloatPoint point(x, y);
1176     AffineTransform ctm = state().m_transform;
1177     FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
1178     if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
1179         return false;
1180
1181     StrokeData strokeData;
1182     strokeData.setThickness(lineWidth());
1183     strokeData.setLineCap(getLineCap());
1184     strokeData.setLineJoin(getLineJoin());
1185     strokeData.setMiterLimit(miterLimit());
1186     strokeData.setLineDash(getLineDash(), lineDashOffset());
1187     return path.strokeContains(transformedPoint, strokeData);
1188 }
1189
1190 void CanvasRenderingContext2D::scrollPathIntoView()
1191 {
1192     scrollPathIntoViewInternal(m_path);
1193 }
1194
1195 void CanvasRenderingContext2D::scrollPathIntoView(Path2D* path2d)
1196 {
1197     scrollPathIntoViewInternal(path2d->path());
1198 }
1199
1200 void CanvasRenderingContext2D::scrollPathIntoViewInternal(const Path& path)
1201 {
1202     RenderObject* renderer = canvas()->renderer();
1203     RenderBox* renderBox = canvas()->renderBox();
1204     if (!renderer || !renderBox || !state().m_invertibleCTM || path.isEmpty())
1205         return;
1206
1207     canvas()->document().updateLayoutIgnorePendingStylesheets();
1208
1209     // Apply transformation and get the bounding rect
1210     Path transformedPath = path;
1211     transformedPath.transform(state().m_transform);
1212     FloatRect boundingRect = transformedPath.boundingRect();
1213
1214     // Offset by the canvas rect
1215     LayoutRect pathRect(boundingRect);
1216     IntRect canvasRect = renderBox->absoluteContentBox();
1217     pathRect.move(canvasRect.x(), canvasRect.y());
1218
1219     renderer->scrollRectToVisible(
1220         pathRect, ScrollAlignment::alignCenterAlways, ScrollAlignment::alignTopAlways);
1221
1222     // TODO: should implement "inform the user" that the caret and/or
1223     // selection the specified rectangle of the canvas. See http://crbug.com/357987
1224 }
1225
1226 void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
1227 {
1228     if (!validateRectForCanvas(x, y, width, height))
1229         return;
1230     GraphicsContext* context = drawingContext();
1231     if (!context)
1232         return;
1233     if (!state().m_invertibleCTM)
1234         return;
1235     FloatRect rect(x, y, width, height);
1236
1237     FloatRect dirtyRect;
1238     if (!computeDirtyRect(rect, &dirtyRect))
1239         return;
1240
1241     bool saved = false;
1242     if (shouldDrawShadows()) {
1243         context->save();
1244         saved = true;
1245         context->clearShadow();
1246     }
1247     if (state().m_globalAlpha != 1) {
1248         if (!saved) {
1249             context->save();
1250             saved = true;
1251         }
1252         context->setAlphaAsFloat(1);
1253     }
1254     if (state().m_globalComposite != CompositeSourceOver) {
1255         if (!saved) {
1256             context->save();
1257             saved = true;
1258         }
1259         context->setCompositeOperation(CompositeSourceOver);
1260     }
1261     context->clearRect(rect);
1262     if (m_hitRegionManager)
1263         m_hitRegionManager->removeHitRegionsInRect(rect, state().m_transform);
1264     if (saved)
1265         context->restore();
1266
1267     validateStateStack();
1268     didDraw(dirtyRect);
1269 }
1270
1271 void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
1272 {
1273     if (!validateRectForCanvas(x, y, width, height))
1274         return;
1275
1276     GraphicsContext* c = drawingContext();
1277     if (!c)
1278         return;
1279     if (!state().m_invertibleCTM)
1280         return;
1281     FloatRect clipBounds;
1282     if (!c->getTransformedClipBounds(&clipBounds))
1283         return;
1284
1285     // from the HTML5 Canvas spec:
1286     // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
1287     // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
1288     Gradient* gradient = c->fillGradient();
1289     if (gradient && gradient->isZeroSize())
1290         return;
1291
1292     FloatRect rect(x, y, width, height);
1293     if (rectContainsTransformedRect(rect, clipBounds)) {
1294         c->fillRect(rect);
1295         didDraw(clipBounds);
1296     } else if (isFullCanvasCompositeMode(state().m_globalComposite)) {
1297         fullCanvasCompositedFill(rect);
1298         didDraw(clipBounds);
1299     } else if (state().m_globalComposite == CompositeCopy) {
1300         clearCanvas();
1301         c->fillRect(rect);
1302         didDraw(clipBounds);
1303     } else {
1304         FloatRect dirtyRect;
1305         if (computeDirtyRect(rect, clipBounds, &dirtyRect)) {
1306             c->fillRect(rect);
1307             didDraw(dirtyRect);
1308         }
1309     }
1310 }
1311
1312 void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height)
1313 {
1314     if (!validateRectForCanvas(x, y, width, height))
1315         return;
1316
1317     if (!(state().m_lineWidth >= 0))
1318         return;
1319
1320     GraphicsContext* c = drawingContext();
1321     if (!c)
1322         return;
1323     if (!state().m_invertibleCTM)
1324         return;
1325     FloatRect clipBounds;
1326     if (!c->getTransformedClipBounds(&clipBounds))
1327         return;
1328
1329     // If gradient size is zero, then paint nothing.
1330     Gradient* gradient = c->strokeGradient();
1331     if (gradient && gradient->isZeroSize())
1332         return;
1333
1334     FloatRect rect(x, y, width, height);
1335
1336     if (isFullCanvasCompositeMode(state().m_globalComposite)) {
1337         fullCanvasCompositedStroke(rect);
1338         didDraw(clipBounds);
1339     } else if (state().m_globalComposite == CompositeCopy) {
1340         clearCanvas();
1341         c->strokeRect(rect);
1342         didDraw(clipBounds);
1343     } else {
1344         FloatRect boundingRect = rect;
1345         boundingRect.inflate(state().m_lineWidth / 2);
1346         FloatRect dirtyRect;
1347         if (computeDirtyRect(boundingRect, clipBounds, &dirtyRect)) {
1348             c->strokeRect(rect);
1349             didDraw(dirtyRect);
1350         }
1351     }
1352 }
1353
1354 void CanvasRenderingContext2D::setShadow(float width, float height, float blur)
1355 {
1356     setShadow(FloatSize(width, height), blur, Color::transparent);
1357 }
1358
1359 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color)
1360 {
1361     RGBA32 rgba;
1362     if (!parseColorOrCurrentColor(rgba, color, canvas()))
1363         return;
1364     setShadow(FloatSize(width, height), blur, rgba);
1365 }
1366
1367 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel)
1368 {
1369     setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1));
1370 }
1371
1372 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha)
1373 {
1374     RGBA32 rgba;
1375     if (!parseColorOrCurrentColor(rgba, color, canvas()))
1376         return;
1377     setShadow(FloatSize(width, height), blur, colorWithOverrideAlpha(rgba, alpha));
1378 }
1379
1380 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
1381 {
1382     setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha));
1383 }
1384
1385 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
1386 {
1387     setShadow(FloatSize(width, height), blur, makeRGBA32FromFloats(r, g, b, a));
1388 }
1389
1390 void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
1391 {
1392     setShadow(FloatSize(width, height), blur, makeRGBAFromCMYKA(c, m, y, k, a));
1393 }
1394
1395 void CanvasRenderingContext2D::clearShadow()
1396 {
1397     setShadow(FloatSize(), 0, Color::transparent);
1398 }
1399
1400 void CanvasRenderingContext2D::setShadow(const FloatSize& offset, float blur, RGBA32 color)
1401 {
1402     if (state().m_shadowOffset == offset && state().m_shadowBlur == blur && state().m_shadowColor == color)
1403         return;
1404     bool wasDrawingShadows = shouldDrawShadows();
1405     realizeSaves(0);
1406     modifiableState().m_shadowOffset = offset;
1407     modifiableState().m_shadowBlur = blur;
1408     modifiableState().m_shadowColor = color;
1409     if (!wasDrawingShadows && !shouldDrawShadows())
1410         return;
1411     applyShadow();
1412 }
1413
1414 void CanvasRenderingContext2D::applyShadow()
1415 {
1416     GraphicsContext* c = drawingContext();
1417     if (!c)
1418         return;
1419
1420     if (shouldDrawShadows()) {
1421         c->setShadow(state().m_shadowOffset, state().m_shadowBlur, state().m_shadowColor,
1422             DrawLooperBuilder::ShadowIgnoresTransforms);
1423     } else {
1424         c->clearShadow();
1425     }
1426 }
1427
1428 bool CanvasRenderingContext2D::shouldDrawShadows() const
1429 {
1430     return alphaChannel(state().m_shadowColor) && (state().m_shadowBlur || !state().m_shadowOffset.isZero());
1431 }
1432
1433 static inline FloatRect normalizeRect(const FloatRect& rect)
1434 {
1435     return FloatRect(std::min(rect.x(), rect.maxX()),
1436         std::min(rect.y(), rect.maxY()),
1437         std::max(rect.width(), -rect.width()),
1438         std::max(rect.height(), -rect.height()));
1439 }
1440
1441 static inline void clipRectsToImageRect(const FloatRect& imageRect, FloatRect* srcRect, FloatRect* dstRect)
1442 {
1443     if (imageRect.contains(*srcRect))
1444         return;
1445
1446     // Compute the src to dst transform
1447     FloatSize scale(dstRect->size().width() / srcRect->size().width(), dstRect->size().height() / srcRect->size().height());
1448     FloatPoint scaledSrcLocation = srcRect->location();
1449     scaledSrcLocation.scale(scale.width(), scale.height());
1450     FloatSize offset = dstRect->location() - scaledSrcLocation;
1451
1452     srcRect->intersect(imageRect);
1453
1454     // To clip the destination rectangle in the same proportion, transform the clipped src rect
1455     *dstRect = *srcRect;
1456     dstRect->scale(scale.width(), scale.height());
1457     dstRect->move(offset);
1458 }
1459
1460 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource, float x, float y, ExceptionState& exceptionState)
1461 {
1462     FloatSize destRectSize = imageSource->defaultDestinationSize();
1463     drawImage(imageSource, x, y, destRectSize.width(), destRectSize.height(), exceptionState);
1464 }
1465
1466 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource,
1467     float x, float y, float width, float height, ExceptionState& exceptionState)
1468 {
1469     FloatSize sourceRectSize = imageSource->sourceSize();
1470     drawImage(imageSource, 0, 0, sourceRectSize.width(), sourceRectSize.height(), x, y, width, height, exceptionState);
1471 }
1472
1473 void CanvasRenderingContext2D::drawImage(CanvasImageSource* imageSource,
1474     float sx, float sy, float sw, float sh,
1475     float dx, float dy, float dw, float dh, ExceptionState& exceptionState)
1476 {
1477     GraphicsContext* c = drawingContext(); // Do not exit yet if !c because we may need to throw exceptions first
1478     CompositeOperator op = c ? c->compositeOperation() : CompositeSourceOver;
1479     blink::WebBlendMode blendMode = c ? c->blendModeOperation() : blink::WebBlendModeNormal;
1480     drawImageInternal(imageSource, sx, sy, sw, sh, dx, dy, dw, dh, exceptionState, op, blendMode, c);
1481 }
1482
1483 void CanvasRenderingContext2D::drawImageInternal(CanvasImageSource* imageSource,
1484     float sx, float sy, float sw, float sh,
1485     float dx, float dy, float dw, float dh, ExceptionState& exceptionState,
1486     CompositeOperator op, blink::WebBlendMode blendMode, GraphicsContext* c)
1487 {
1488     RefPtr<Image> image;
1489     SourceImageStatus sourceImageStatus = InvalidSourceImageStatus;
1490     if (!imageSource->isVideoElement()) {
1491         SourceImageMode mode = canvas() == imageSource ? CopySourceImageIfVolatile : DontCopySourceImage; // Thunking for ==
1492         image = imageSource->getSourceImageForCanvas(mode, &sourceImageStatus);
1493         if (sourceImageStatus == UndecodableSourceImageStatus)
1494             exceptionState.throwDOMException(InvalidStateError, "The HTMLImageElement provided is in the 'broken' state.");
1495         if (!image || !image->width() || !image->height())
1496             return;
1497     }
1498
1499     if (!c)
1500         c = drawingContext();
1501     if (!c)
1502         return;
1503
1504     if (!state().m_invertibleCTM)
1505         return;
1506
1507     if (!std::isfinite(dx) || !std::isfinite(dy) || !std::isfinite(dw) || !std::isfinite(dh)
1508         || !std::isfinite(sx) || !std::isfinite(sy) || !std::isfinite(sw) || !std::isfinite(sh)
1509         || !dw || !dh || !sw || !sh)
1510         return;
1511
1512     FloatRect clipBounds;
1513     if (!c->getTransformedClipBounds(&clipBounds))
1514         return;
1515
1516     FloatRect srcRect = normalizeRect(FloatRect(sx, sy, sw, sh));
1517     FloatRect dstRect = normalizeRect(FloatRect(dx, dy, dw, dh));
1518
1519     clipRectsToImageRect(FloatRect(FloatPoint(), imageSource->sourceSize()), &srcRect, &dstRect);
1520
1521     imageSource->adjustDrawRects(&srcRect, &dstRect);
1522
1523     if (srcRect.isEmpty())
1524         return;
1525
1526     FloatRect dirtyRect = clipBounds;
1527     if (imageSource->isVideoElement()) {
1528         // TODO(dshwang): unify video code into below code to composite correctly; crbug.com/407079
1529         drawVideo(static_cast<HTMLVideoElement*>(imageSource), srcRect, dstRect);
1530         computeDirtyRect(dstRect, clipBounds, &dirtyRect);
1531     } else {
1532         if (rectContainsTransformedRect(dstRect, clipBounds)) {
1533             c->drawImage(image.get(), dstRect, srcRect, op, blendMode);
1534         } else if (isFullCanvasCompositeMode(op)) {
1535             fullCanvasCompositedDrawImage(image.get(), dstRect, srcRect, op);
1536         } else if (op == CompositeCopy) {
1537             clearCanvas();
1538             c->drawImage(image.get(), dstRect, srcRect, op, blendMode);
1539         } else {
1540             FloatRect dirtyRect;
1541             computeDirtyRect(dstRect, clipBounds, &dirtyRect);
1542             c->drawImage(image.get(), dstRect, srcRect, op, blendMode);
1543         }
1544
1545         if (sourceImageStatus == ExternalSourceImageStatus && isAccelerated() && canvas()->buffer())
1546             canvas()->buffer()->flush();
1547     }
1548
1549     if (canvas()->originClean() && wouldTaintOrigin(imageSource))
1550         canvas()->setOriginTainted();
1551
1552     didDraw(dirtyRect);
1553 }
1554
1555 void CanvasRenderingContext2D::drawVideo(HTMLVideoElement* video, FloatRect srcRect, FloatRect dstRect)
1556 {
1557     GraphicsContext* c = drawingContext();
1558     GraphicsContextStateSaver stateSaver(*c);
1559     c->clip(dstRect);
1560     c->translate(dstRect.x(), dstRect.y());
1561     c->scale(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height());
1562     c->translate(-srcRect.x(), -srcRect.y());
1563     video->paintCurrentFrameInContext(c, IntRect(IntPoint(), IntSize(video->videoWidth(), video->videoHeight())));
1564     stateSaver.restore();
1565     validateStateStack();
1566 }
1567
1568 void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image,
1569     float sx, float sy, float sw, float sh,
1570     float dx, float dy, float dw, float dh,
1571     const String& compositeOperation)
1572 {
1573     if (!image)
1574         return;
1575     CompositeOperator op;
1576     blink::WebBlendMode blendOp = blink::WebBlendModeNormal;
1577     if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blendOp != blink::WebBlendModeNormal)
1578         op = CompositeSourceOver;
1579
1580     drawImageInternal(image, sx, sy, sw, sh, dx, dy, dw, dh, IGNORE_EXCEPTION, op, blendOp);
1581 }
1582
1583 void CanvasRenderingContext2D::setAlpha(float alpha)
1584 {
1585     setGlobalAlpha(alpha);
1586 }
1587
1588 void CanvasRenderingContext2D::setCompositeOperation(const String& operation)
1589 {
1590     setGlobalCompositeOperation(operation);
1591 }
1592
1593 void CanvasRenderingContext2D::clearCanvas()
1594 {
1595     FloatRect canvasRect(0, 0, canvas()->width(), canvas()->height());
1596     GraphicsContext* c = drawingContext();
1597     if (!c)
1598         return;
1599
1600     c->save();
1601     c->setCTM(canvas()->baseTransform());
1602     c->clearRect(canvasRect);
1603     c->restore();
1604 }
1605
1606 bool CanvasRenderingContext2D::rectContainsTransformedRect(const FloatRect& rect, const FloatRect& transformedRect) const
1607 {
1608     FloatQuad quad(rect);
1609     FloatQuad transformedQuad(transformedRect);
1610     return state().m_transform.mapQuad(quad).containsQuad(transformedQuad);
1611 }
1612
1613 static void drawImageToContext(Image* image, GraphicsContext* context, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1614 {
1615     context->drawImage(image, dest, src, op);
1616 }
1617
1618 template<class T> void  CanvasRenderingContext2D::fullCanvasCompositedDrawImage(T* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1619 {
1620     ASSERT(isFullCanvasCompositeMode(op));
1621
1622     GraphicsContext* c = drawingContext();
1623     c->beginLayer(1, op);
1624     drawImageToContext(image, c, dest, src, CompositeSourceOver);
1625     c->endLayer();
1626 }
1627
1628 static void fillPrimitive(const FloatRect& rect, GraphicsContext* context)
1629 {
1630     context->fillRect(rect);
1631 }
1632
1633 static void fillPrimitive(const Path& path, GraphicsContext* context)
1634 {
1635     context->fillPath(path);
1636 }
1637
1638 template<class T> void CanvasRenderingContext2D::fullCanvasCompositedFill(const T& area)
1639 {
1640     ASSERT(isFullCanvasCompositeMode(state().m_globalComposite));
1641
1642     GraphicsContext* c = drawingContext();
1643     ASSERT(c);
1644     c->beginLayer(1, state().m_globalComposite);
1645     CompositeOperator previousOperator = c->compositeOperation();
1646     c->setCompositeOperation(CompositeSourceOver);
1647     fillPrimitive(area, c);
1648     c->setCompositeOperation(previousOperator);
1649     c->endLayer();
1650 }
1651
1652 static void strokePrimitive(const FloatRect& rect, GraphicsContext* context)
1653 {
1654     context->strokeRect(rect);
1655 }
1656
1657 static void strokePrimitive(const Path& path, GraphicsContext* context)
1658 {
1659     context->strokePath(path);
1660 }
1661
1662 template<class T> void CanvasRenderingContext2D::fullCanvasCompositedStroke(const T& area)
1663 {
1664     ASSERT(isFullCanvasCompositeMode(state().m_globalComposite));
1665
1666     GraphicsContext* c = drawingContext();
1667     ASSERT(c);
1668     c->beginLayer(1, state().m_globalComposite);
1669     CompositeOperator previousOperator = c->compositeOperation();
1670     c->setCompositeOperation(CompositeSourceOver);
1671     strokePrimitive(area, c);
1672     c->setCompositeOperation(previousOperator);
1673     c->endLayer();
1674 }
1675
1676 PassRefPtrWillBeRawPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1)
1677 {
1678     RefPtrWillBeRawPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
1679     return gradient.release();
1680 }
1681
1682 PassRefPtrWillBeRawPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionState& exceptionState)
1683 {
1684     if (r0 < 0 || r1 < 0) {
1685         exceptionState.throwDOMException(IndexSizeError, String::format("The %s provided is less than 0.", r0 < 0 ? "r0" : "r1"));
1686         return nullptr;
1687     }
1688
1689     RefPtrWillBeRawPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
1690     return gradient.release();
1691 }
1692
1693 PassRefPtrWillBeRawPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(CanvasImageSource* imageSource,
1694     const String& repetitionType, ExceptionState& exceptionState)
1695 {
1696     Pattern::RepeatMode repeatMode = CanvasPattern::parseRepetitionType(repetitionType, exceptionState);
1697     if (exceptionState.hadException())
1698         return nullptr;
1699
1700     SourceImageStatus status;
1701     RefPtr<Image> imageForRendering = imageSource->getSourceImageForCanvas(CopySourceImageIfVolatile, &status);
1702
1703     switch (status) {
1704     case NormalSourceImageStatus:
1705         break;
1706     case ZeroSizeCanvasSourceImageStatus:
1707         exceptionState.throwDOMException(InvalidStateError, String::format("The canvas %s is 0.", imageSource->sourceSize().width() ? "height" : "width"));
1708         return nullptr;
1709     case UndecodableSourceImageStatus:
1710         exceptionState.throwDOMException(InvalidStateError, "Source image is in the 'broken' state.");
1711         return nullptr;
1712     case InvalidSourceImageStatus:
1713         imageForRendering = Image::nullImage();
1714         break;
1715     case IncompleteSourceImageStatus:
1716         return nullptr;
1717     default:
1718     case ExternalSourceImageStatus: // should not happen when mode is CopySourceImageIfVolatile
1719         ASSERT_NOT_REACHED();
1720         return nullptr;
1721     }
1722     ASSERT(imageForRendering);
1723
1724     bool originClean = !wouldTaintOrigin(imageSource);
1725
1726     return CanvasPattern::create(imageForRendering.release(), repeatMode, originClean);
1727 }
1728
1729 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, FloatRect* dirtyRect)
1730 {
1731     FloatRect clipBounds;
1732     if (!drawingContext()->getTransformedClipBounds(&clipBounds))
1733         return false;
1734     return computeDirtyRect(localRect, clipBounds, dirtyRect);
1735 }
1736
1737 bool CanvasRenderingContext2D::computeDirtyRect(const FloatRect& localRect, const FloatRect& transformedClipBounds, FloatRect* dirtyRect)
1738 {
1739     FloatRect canvasRect = state().m_transform.mapRect(localRect);
1740
1741     if (alphaChannel(state().m_shadowColor)) {
1742         FloatRect shadowRect(canvasRect);
1743         shadowRect.move(state().m_shadowOffset);
1744         shadowRect.inflate(state().m_shadowBlur);
1745         canvasRect.unite(shadowRect);
1746     }
1747
1748     canvasRect.intersect(transformedClipBounds);
1749     if (canvasRect.isEmpty())
1750         return false;
1751
1752     if (dirtyRect)
1753         *dirtyRect = canvasRect;
1754
1755     return true;
1756 }
1757
1758 void CanvasRenderingContext2D::didDraw(const FloatRect& dirtyRect)
1759 {
1760     if (dirtyRect.isEmpty())
1761         return;
1762
1763     canvas()->didDraw(dirtyRect);
1764 }
1765
1766 GraphicsContext* CanvasRenderingContext2D::drawingContext() const
1767 {
1768     if (isContextLost())
1769         return 0;
1770     return canvas()->drawingContext();
1771 }
1772
1773 static PassRefPtrWillBeRawPtr<ImageData> createEmptyImageData(const IntSize& size)
1774 {
1775     if (RefPtrWillBeRawPtr<ImageData> data = ImageData::create(size)) {
1776         data->data()->zeroFill();
1777         return data.release();
1778     }
1779
1780     return nullptr;
1781 }
1782
1783 PassRefPtrWillBeRawPtr<ImageData> CanvasRenderingContext2D::createImageData(PassRefPtrWillBeRawPtr<ImageData> imageData) const
1784 {
1785     return createEmptyImageData(imageData->size());
1786 }
1787
1788 PassRefPtrWillBeRawPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh, ExceptionState& exceptionState) const
1789 {
1790     if (!sw || !sh) {
1791         exceptionState.throwDOMException(IndexSizeError, String::format("The source %s is 0.", sw ? "height" : "width"));
1792         return nullptr;
1793     }
1794
1795     FloatSize logicalSize(fabs(sw), fabs(sh));
1796     if (!logicalSize.isExpressibleAsIntSize())
1797         return nullptr;
1798
1799     IntSize size = expandedIntSize(logicalSize);
1800     if (size.width() < 1)
1801         size.setWidth(1);
1802     if (size.height() < 1)
1803         size.setHeight(1);
1804
1805     return createEmptyImageData(size);
1806 }
1807
1808 PassRefPtrWillBeRawPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionState& exceptionState) const
1809 {
1810     if (!canvas()->originClean())
1811         exceptionState.throwSecurityError("The canvas has been tainted by cross-origin data.");
1812     else if (!sw || !sh)
1813         exceptionState.throwDOMException(IndexSizeError, String::format("The source %s is 0.", sw ? "height" : "width"));
1814
1815     if (exceptionState.hadException())
1816         return nullptr;
1817
1818     if (sw < 0) {
1819         sx += sw;
1820         sw = -sw;
1821     }
1822     if (sh < 0) {
1823         sy += sh;
1824         sh = -sh;
1825     }
1826
1827     FloatRect logicalRect(sx, sy, sw, sh);
1828     if (logicalRect.width() < 1)
1829         logicalRect.setWidth(1);
1830     if (logicalRect.height() < 1)
1831         logicalRect.setHeight(1);
1832     if (!logicalRect.isExpressibleAsIntRect())
1833         return nullptr;
1834
1835     IntRect imageDataRect = enclosingIntRect(logicalRect);
1836     ImageBuffer* buffer = canvas()->buffer();
1837     if (!buffer || isContextLost())
1838         return createEmptyImageData(imageDataRect.size());
1839
1840     RefPtr<Uint8ClampedArray> byteArray = buffer->getImageData(Unmultiplied, imageDataRect);
1841     if (!byteArray)
1842         return nullptr;
1843
1844     return ImageData::create(imageDataRect.size(), byteArray.release());
1845 }
1846
1847 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy)
1848 {
1849     putImageData(data, dx, dy, 0, 0, data->width(), data->height());
1850 }
1851
1852 void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight)
1853 {
1854     ImageBuffer* buffer = canvas()->buffer();
1855     if (!buffer)
1856         return;
1857
1858     if (dirtyWidth < 0) {
1859         dirtyX += dirtyWidth;
1860         dirtyWidth = -dirtyWidth;
1861     }
1862
1863     if (dirtyHeight < 0) {
1864         dirtyY += dirtyHeight;
1865         dirtyHeight = -dirtyHeight;
1866     }
1867
1868     FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
1869     clipRect.intersect(IntRect(0, 0, data->width(), data->height()));
1870     IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
1871     IntRect destRect = enclosingIntRect(clipRect);
1872     destRect.move(destOffset);
1873     destRect.intersect(IntRect(IntPoint(), buffer->size()));
1874     if (destRect.isEmpty())
1875         return;
1876     IntRect sourceRect(destRect);
1877     sourceRect.move(-destOffset);
1878
1879     buffer->putByteArray(Unmultiplied, data->data(), IntSize(data->width(), data->height()), sourceRect, IntPoint(destOffset));
1880
1881     didDraw(destRect);
1882 }
1883
1884 String CanvasRenderingContext2D::font() const
1885 {
1886     if (!state().m_realizedFont)
1887         return defaultFont;
1888
1889     StringBuilder serializedFont;
1890     const FontDescription& fontDescription = state().m_font.fontDescription();
1891
1892     if (fontDescription.style() == FontStyleItalic)
1893         serializedFont.appendLiteral("italic ");
1894     if (fontDescription.weight() == FontWeightBold)
1895         serializedFont.appendLiteral("bold ");
1896     if (fontDescription.variant() == FontVariantSmallCaps)
1897         serializedFont.appendLiteral("small-caps ");
1898
1899     serializedFont.appendNumber(fontDescription.computedPixelSize());
1900     serializedFont.appendLiteral("px");
1901
1902     const FontFamily& firstFontFamily = fontDescription.family();
1903     for (const FontFamily* fontFamily = &firstFontFamily; fontFamily; fontFamily = fontFamily->next()) {
1904         if (fontFamily != &firstFontFamily)
1905             serializedFont.append(',');
1906
1907         // FIXME: We should append family directly to serializedFont rather than building a temporary string.
1908         String family = fontFamily->family();
1909         if (family.startsWith("-webkit-"))
1910             family = family.substring(8);
1911         if (family.contains(' '))
1912             family = "\"" + family + "\"";
1913
1914         serializedFont.append(' ');
1915         serializedFont.append(family);
1916     }
1917
1918     return serializedFont.toString();
1919 }
1920
1921 void CanvasRenderingContext2D::setFont(const String& newFont)
1922 {
1923     // The style resolution required for rendering text is not available in frame-less documents.
1924     if (!canvas()->document().frame())
1925         return;
1926
1927     MutableStylePropertyMap::iterator i = m_fetchedFonts.find(newFont);
1928     RefPtrWillBeRawPtr<MutableStylePropertySet> parsedStyle = i != m_fetchedFonts.end() ? i->value : nullptr;
1929
1930     if (!parsedStyle) {
1931         parsedStyle = MutableStylePropertySet::create();
1932         CSSParserMode mode = m_usesCSSCompatibilityParseMode ? HTMLQuirksMode : HTMLStandardMode;
1933         CSSParser::parseValue(parsedStyle.get(), CSSPropertyFont, newFont, true, mode, 0);
1934         m_fetchedFonts.add(newFont, parsedStyle);
1935     }
1936     if (parsedStyle->isEmpty())
1937         return;
1938
1939     String fontValue = parsedStyle->getPropertyValue(CSSPropertyFont);
1940
1941     // According to http://lists.w3.org/Archives/Public/public-html/2009Jul/0947.html,
1942     // the "inherit" and "initial" values must be ignored.
1943     if (fontValue == "inherit" || fontValue == "initial")
1944         return;
1945
1946     // The parse succeeded.
1947     String newFontSafeCopy(newFont); // Create a string copy since newFont can be deleted inside realizeSaves.
1948     realizeSaves(0);
1949     modifiableState().m_unparsedFont = newFontSafeCopy;
1950
1951     // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work
1952     // relative to the canvas.
1953     RefPtr<RenderStyle> newStyle = RenderStyle::create();
1954     canvas()->document().updateRenderTreeIfNeeded();
1955     if (RenderStyle* computedStyle = canvas()->computedStyle()) {
1956         FontDescription elementFontDescription(computedStyle->fontDescription());
1957         // Reset the computed size to avoid inheriting the zoom factor from the <canvas> element.
1958         elementFontDescription.setComputedSize(elementFontDescription.specifiedSize());
1959         newStyle->setFontDescription(elementFontDescription);
1960     } else {
1961         FontFamily fontFamily;
1962         fontFamily.setFamily(defaultFontFamily);
1963
1964         FontDescription defaultFontDescription;
1965         defaultFontDescription.setFamily(fontFamily);
1966         defaultFontDescription.setSpecifiedSize(defaultFontSize);
1967         defaultFontDescription.setComputedSize(defaultFontSize);
1968
1969         newStyle->setFontDescription(defaultFontDescription);
1970     }
1971
1972     newStyle->font().update(newStyle->font().fontSelector());
1973
1974     // Now map the font property longhands into the style.
1975     CSSPropertyValue properties[] = {
1976         CSSPropertyValue(CSSPropertyFontFamily, *parsedStyle),
1977         CSSPropertyValue(CSSPropertyFontStyle, *parsedStyle),
1978         CSSPropertyValue(CSSPropertyFontVariant, *parsedStyle),
1979         CSSPropertyValue(CSSPropertyFontWeight, *parsedStyle),
1980         CSSPropertyValue(CSSPropertyFontSize, *parsedStyle),
1981         CSSPropertyValue(CSSPropertyLineHeight, *parsedStyle),
1982     };
1983
1984     StyleResolver& styleResolver = canvas()->document().ensureStyleResolver();
1985     styleResolver.applyPropertiesToStyle(properties, WTF_ARRAY_LENGTH(properties), newStyle.get());
1986
1987 #if !ENABLE(OILPAN)
1988     if (state().m_realizedFont)
1989         static_cast<CSSFontSelector*>(state().m_font.fontSelector())->unregisterForInvalidationCallbacks(&modifiableState());
1990 #endif
1991     modifiableState().m_font = newStyle->font();
1992     modifiableState().m_font.update(canvas()->document().styleEngine()->fontSelector());
1993     modifiableState().m_realizedFont = true;
1994     canvas()->document().styleEngine()->fontSelector()->registerForInvalidationCallbacks(&modifiableState());
1995 }
1996
1997 String CanvasRenderingContext2D::textAlign() const
1998 {
1999     return textAlignName(state().m_textAlign);
2000 }
2001
2002 void CanvasRenderingContext2D::setTextAlign(const String& s)
2003 {
2004     TextAlign align;
2005     if (!parseTextAlign(s, align))
2006         return;
2007     if (state().m_textAlign == align)
2008         return;
2009     realizeSaves(0);
2010     modifiableState().m_textAlign = align;
2011 }
2012
2013 String CanvasRenderingContext2D::textBaseline() const
2014 {
2015     return textBaselineName(state().m_textBaseline);
2016 }
2017
2018 void CanvasRenderingContext2D::setTextBaseline(const String& s)
2019 {
2020     TextBaseline baseline;
2021     if (!parseTextBaseline(s, baseline))
2022         return;
2023     if (state().m_textBaseline == baseline)
2024         return;
2025     realizeSaves(0);
2026     modifiableState().m_textBaseline = baseline;
2027 }
2028
2029 inline TextDirection CanvasRenderingContext2D::toTextDirection(Direction direction, RenderStyle** computedStyle) const
2030 {
2031     RenderStyle* style = (computedStyle || direction == DirectionInherit) ? canvas()->computedStyle() : nullptr;
2032     if (computedStyle)
2033         *computedStyle = style;
2034     switch (direction) {
2035     case DirectionInherit:
2036         return style ? style->direction() : LTR;
2037     case DirectionRTL:
2038         return RTL;
2039     case DirectionLTR:
2040         return LTR;
2041     }
2042     ASSERT_NOT_REACHED();
2043     return LTR;
2044 }
2045
2046 String CanvasRenderingContext2D::direction() const
2047 {
2048     if (state().m_direction == DirectionInherit)
2049         canvas()->document().updateRenderTreeIfNeeded();
2050     return toTextDirection(state().m_direction) == RTL ? rtl : ltr;
2051 }
2052
2053 void CanvasRenderingContext2D::setDirection(const String& directionString)
2054 {
2055     Direction direction;
2056     if (directionString == inherit)
2057         direction = DirectionInherit;
2058     else if (directionString == rtl)
2059         direction = DirectionRTL;
2060     else if (directionString == ltr)
2061         direction = DirectionLTR;
2062     else
2063         return;
2064
2065     if (state().m_direction == direction)
2066         return;
2067
2068     realizeSaves(0);
2069     modifiableState().m_direction = direction;
2070 }
2071
2072 void CanvasRenderingContext2D::fillText(const String& text, float x, float y)
2073 {
2074     drawTextInternal(text, x, y, true);
2075 }
2076
2077 void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth)
2078 {
2079     drawTextInternal(text, x, y, true, maxWidth, true);
2080 }
2081
2082 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y)
2083 {
2084     drawTextInternal(text, x, y, false);
2085 }
2086
2087 void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth)
2088 {
2089     drawTextInternal(text, x, y, false, maxWidth, true);
2090 }
2091
2092 PassRefPtrWillBeRawPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text)
2093 {
2094     RefPtrWillBeRawPtr<TextMetrics> metrics = TextMetrics::create();
2095
2096     // The style resolution required for rendering text is not available in frame-less documents.
2097     if (!canvas()->document().frame())
2098         return metrics.release();
2099
2100     FontCachePurgePreventer fontCachePurgePreventer;
2101     canvas()->document().updateRenderTreeIfNeeded();
2102     const Font& font = accessFont();
2103     const TextRun textRun(text, 0, 0, TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, LTR, false, true, true);
2104     FloatRect textBounds = font.selectionRectForText(textRun, FloatPoint(), font.fontDescription().computedSize(), 0, -1, true);
2105
2106     // x direction
2107     metrics->setWidth(font.width(textRun));
2108     metrics->setActualBoundingBoxLeft(-textBounds.x());
2109     metrics->setActualBoundingBoxRight(textBounds.maxX());
2110
2111     // y direction
2112     const FontMetrics& fontMetrics = font.fontMetrics();
2113     const float ascent = fontMetrics.floatAscent();
2114     const float descent = fontMetrics.floatDescent();
2115     const float baselineY = getFontBaseline(fontMetrics);
2116
2117     metrics->setFontBoundingBoxAscent(ascent - baselineY);
2118     metrics->setFontBoundingBoxDescent(descent + baselineY);
2119     metrics->setActualBoundingBoxAscent(-textBounds.y() - baselineY);
2120     metrics->setActualBoundingBoxDescent(textBounds.maxY() + baselineY);
2121
2122     // Note : top/bottom and ascend/descend are currently the same, so there's no difference
2123     //        between the EM box's top and bottom and the font's ascend and descend
2124     metrics->setEmHeightAscent(0);
2125     metrics->setEmHeightDescent(0);
2126
2127     metrics->setHangingBaseline(-0.8f * ascent + baselineY);
2128     metrics->setAlphabeticBaseline(baselineY);
2129     metrics->setIdeographicBaseline(descent + baselineY);
2130     return metrics.release();
2131 }
2132
2133 void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float maxWidth, bool useMaxWidth)
2134 {
2135     // The style resolution required for rendering text is not available in frame-less documents.
2136     if (!canvas()->document().frame())
2137         return;
2138
2139     // accessFont needs the style to be up to date, but updating style can cause script to run,
2140     // (e.g. due to autofocus) which can free the GraphicsContext, so update style before grabbing
2141     // the GraphicsContext.
2142     canvas()->document().updateRenderTreeIfNeeded();
2143
2144     GraphicsContext* c = drawingContext();
2145     if (!c)
2146         return;
2147     if (!state().m_invertibleCTM)
2148         return;
2149     if (!std::isfinite(x) | !std::isfinite(y))
2150         return;
2151     if (useMaxWidth && (!std::isfinite(maxWidth) || maxWidth <= 0))
2152         return;
2153
2154     // If gradient size is zero, then paint nothing.
2155     Gradient* gradient = c->strokeGradient();
2156     if (!fill && gradient && gradient->isZeroSize())
2157         return;
2158
2159     gradient = c->fillGradient();
2160     if (fill && gradient && gradient->isZeroSize())
2161         return;
2162
2163     FontCachePurgePreventer fontCachePurgePreventer;
2164
2165     const Font& font = accessFont();
2166     const FontMetrics& fontMetrics = font.fontMetrics();
2167
2168     // FIXME: Need to turn off font smoothing.
2169
2170     RenderStyle* computedStyle;
2171     TextDirection direction = toTextDirection(state().m_direction, &computedStyle);
2172     bool isRTL = direction == RTL;
2173     bool override = computedStyle ? isOverride(computedStyle->unicodeBidi()) : false;
2174
2175     TextRun textRun(text, 0, 0, TextRun::AllowTrailingExpansion, direction, override, true, true);
2176     // Draw the item text at the correct point.
2177     FloatPoint location(x, y + getFontBaseline(fontMetrics));
2178     float fontWidth = font.width(textRun);
2179
2180     useMaxWidth = (useMaxWidth && maxWidth < fontWidth);
2181     float width = useMaxWidth ? maxWidth : fontWidth;
2182
2183     TextAlign align = state().m_textAlign;
2184     if (align == StartTextAlign)
2185         align = isRTL ? RightTextAlign : LeftTextAlign;
2186     else if (align == EndTextAlign)
2187         align = isRTL ? LeftTextAlign : RightTextAlign;
2188
2189     switch (align) {
2190     case CenterTextAlign:
2191         location.setX(location.x() - width / 2);
2192         break;
2193     case RightTextAlign:
2194         location.setX(location.x() - width);
2195         break;
2196     default:
2197         break;
2198     }
2199
2200     // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text.
2201     TextRunPaintInfo textRunPaintInfo(textRun);
2202     textRunPaintInfo.bounds = FloatRect(location.x() - fontMetrics.height() / 2,
2203                                         location.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
2204                                         width + fontMetrics.height(),
2205                                         fontMetrics.lineSpacing());
2206     if (!fill)
2207         inflateStrokeRect(textRunPaintInfo.bounds);
2208
2209     c->setTextDrawingMode(fill ? TextModeFill : TextModeStroke);
2210
2211     GraphicsContextStateSaver stateSaver(*c);
2212     if (useMaxWidth) {
2213         c->translate(location.x(), location.y());
2214         // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) still work.
2215         c->scale((fontWidth > 0 ? (width / fontWidth) : 0), 1);
2216         location = FloatPoint();
2217     }
2218
2219     FloatRect clipBounds;
2220     if (!c->getTransformedClipBounds(&clipBounds)) {
2221         return;
2222     }
2223
2224     if (isFullCanvasCompositeMode(state().m_globalComposite)) {
2225         c->beginLayer(1, state().m_globalComposite);
2226         CompositeOperator previousOperator = c->compositeOperation();
2227         c->setCompositeOperation(CompositeSourceOver);
2228         c->drawBidiText(font, textRunPaintInfo, location, Font::UseFallbackIfFontNotReady);
2229         c->setCompositeOperation(previousOperator);
2230         c->endLayer();
2231         didDraw(clipBounds);
2232     } else if (state().m_globalComposite == CompositeCopy) {
2233         clearCanvas();
2234         c->drawBidiText(font, textRunPaintInfo, location, Font::UseFallbackIfFontNotReady);
2235         didDraw(clipBounds);
2236     } else {
2237         FloatRect dirtyRect;
2238         if (computeDirtyRect(textRunPaintInfo.bounds, clipBounds, &dirtyRect)) {
2239             c->drawBidiText(font, textRunPaintInfo, location, Font::UseFallbackIfFontNotReady);
2240             didDraw(dirtyRect);
2241         }
2242     }
2243 }
2244
2245 void CanvasRenderingContext2D::inflateStrokeRect(FloatRect& rect) const
2246 {
2247     // Fast approximation of the stroke's bounding rect.
2248     // This yields a slightly oversized rect but is very fast
2249     // compared to Path::strokeBoundingRect().
2250     static const float root2 = sqrtf(2);
2251     float delta = state().m_lineWidth / 2;
2252     if (state().m_lineJoin == MiterJoin)
2253         delta *= state().m_miterLimit;
2254     else if (state().m_lineCap == SquareCap)
2255         delta *= root2;
2256
2257     rect.inflate(delta);
2258 }
2259
2260 const Font& CanvasRenderingContext2D::accessFont()
2261 {
2262     // This needs style to be up to date, but can't assert so because drawTextInternal
2263     // can invalidate style before this is called (e.g. drawingContext invalidates style).
2264     if (!state().m_realizedFont)
2265         setFont(state().m_unparsedFont);
2266     return state().m_font;
2267 }
2268
2269 int CanvasRenderingContext2D::getFontBaseline(const FontMetrics& fontMetrics) const
2270 {
2271     switch (state().m_textBaseline) {
2272     case TopTextBaseline:
2273         return fontMetrics.ascent();
2274     case HangingTextBaseline:
2275         // According to http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
2276         // "FOP (Formatting Objects Processor) puts the hanging baseline at 80% of the ascender height"
2277         return (fontMetrics.ascent() * 4) / 5;
2278     case BottomTextBaseline:
2279     case IdeographicTextBaseline:
2280         return -fontMetrics.descent();
2281     case MiddleTextBaseline:
2282         return -fontMetrics.descent() + fontMetrics.height() / 2;
2283     case AlphabeticTextBaseline:
2284     default:
2285         // Do nothing.
2286         break;
2287     }
2288     return 0;
2289 }
2290
2291 void CanvasRenderingContext2D::setIsHidden(bool hidden)
2292 {
2293     ImageBuffer* buffer = canvas()->buffer();
2294     if (buffer)
2295         buffer->setIsHidden(hidden);
2296 }
2297
2298 blink::WebLayer* CanvasRenderingContext2D::platformLayer() const
2299 {
2300     return canvas()->buffer() ? canvas()->buffer()->platformLayer() : 0;
2301 }
2302
2303 bool CanvasRenderingContext2D::imageSmoothingEnabled() const
2304 {
2305     return state().m_imageSmoothingEnabled;
2306 }
2307
2308 void CanvasRenderingContext2D::setImageSmoothingEnabled(bool enabled)
2309 {
2310     if (enabled == state().m_imageSmoothingEnabled)
2311         return;
2312
2313     GraphicsContext* c = drawingContext();
2314     realizeSaves(c);
2315     modifiableState().m_imageSmoothingEnabled = enabled;
2316     if (c)
2317         c->setImageInterpolationQuality(enabled ? CanvasDefaultInterpolationQuality : InterpolationNone);
2318 }
2319
2320 PassRefPtrWillBeRawPtr<Canvas2DContextAttributes> CanvasRenderingContext2D::getContextAttributes() const
2321 {
2322     RefPtrWillBeRawPtr<Canvas2DContextAttributes> attributes = Canvas2DContextAttributes::create();
2323     attributes->setAlpha(m_hasAlpha);
2324     return attributes.release();
2325 }
2326
2327 void CanvasRenderingContext2D::drawFocusIfNeeded(Element* element)
2328 {
2329     drawFocusIfNeededInternal(m_path, element);
2330 }
2331
2332 void CanvasRenderingContext2D::drawFocusIfNeeded(Path2D* path2d, Element* element)
2333 {
2334     drawFocusIfNeededInternal(path2d->path(), element);
2335 }
2336
2337 void CanvasRenderingContext2D::drawFocusIfNeededInternal(const Path& path, Element* element)
2338 {
2339     if (!focusRingCallIsValid(path, element))
2340         return;
2341
2342     // Note: we need to check document->focusedElement() rather than just calling
2343     // element->focused(), because element->focused() isn't updated until after
2344     // focus events fire.
2345     if (element->document().focusedElement() == element)
2346         drawFocusRing(path);
2347 }
2348
2349 bool CanvasRenderingContext2D::focusRingCallIsValid(const Path& path, Element* element)
2350 {
2351     ASSERT(element);
2352     if (!state().m_invertibleCTM)
2353         return false;
2354     if (path.isEmpty())
2355         return false;
2356     if (!element->isDescendantOf(canvas()))
2357         return false;
2358
2359     return true;
2360 }
2361
2362 void CanvasRenderingContext2D::drawFocusRing(const Path& path)
2363 {
2364     GraphicsContext* c = drawingContext();
2365     if (!c)
2366         return;
2367
2368     // These should match the style defined in html.css.
2369     Color focusRingColor = RenderTheme::theme().focusRingColor();
2370     const int focusRingWidth = 5;
2371     const int focusRingOutline = 0;
2372
2373     // We need to add focusRingWidth to dirtyRect.
2374     StrokeData strokeData;
2375     strokeData.setThickness(focusRingWidth);
2376
2377     FloatRect dirtyRect;
2378     if (!computeDirtyRect(path.strokeBoundingRect(strokeData), &dirtyRect))
2379         return;
2380
2381     c->save();
2382     c->setAlphaAsFloat(1.0);
2383     c->clearShadow();
2384     c->setCompositeOperation(CompositeSourceOver, blink::WebBlendModeNormal);
2385     c->drawFocusRing(path, focusRingWidth, focusRingOutline, focusRingColor);
2386     c->restore();
2387     validateStateStack();
2388     didDraw(dirtyRect);
2389 }
2390
2391 void CanvasRenderingContext2D::addHitRegion(const HitRegionOptions& options, ExceptionState& exceptionState)
2392 {
2393     HitRegionOptionsInternal passOptions;
2394     passOptions.id = options.id();
2395     passOptions.control = options.control();
2396     if (passOptions.id.isEmpty() && !passOptions.control) {
2397         exceptionState.throwDOMException(NotSupportedError, "Both id and control are null.");
2398         return;
2399     }
2400
2401     Path hitRegionPath = options.hasPath() ? options.path()->path() : m_path;
2402
2403     FloatRect clipBounds;
2404     GraphicsContext* context = drawingContext();
2405
2406     if (hitRegionPath.isEmpty() || !context || !state().m_invertibleCTM
2407         || !context->getTransformedClipBounds(&clipBounds)) {
2408         exceptionState.throwDOMException(NotSupportedError, "The specified path has no pixels.");
2409         return;
2410     }
2411
2412     hitRegionPath.transform(state().m_transform);
2413
2414     if (hasClip()) {
2415         // FIXME: The hit regions should take clipping region into account.
2416         // However, we have no way to get the region from canvas state stack by now.
2417         // See http://crbug.com/387057
2418         exceptionState.throwDOMException(NotSupportedError, "The specified path has no pixels.");
2419         return;
2420     }
2421
2422     passOptions.path = hitRegionPath;
2423
2424     if (options.fillRule() != "evenodd")
2425         passOptions.fillRule = RULE_NONZERO;
2426     else
2427         passOptions.fillRule = RULE_EVENODD;
2428
2429     addHitRegionInternal(passOptions, exceptionState);
2430 }
2431
2432 void CanvasRenderingContext2D::addHitRegionInternal(const HitRegionOptionsInternal& options, ExceptionState& exceptionState)
2433 {
2434     if (!m_hitRegionManager)
2435         m_hitRegionManager = HitRegionManager::create();
2436
2437     // Remove previous region (with id or control)
2438     m_hitRegionManager->removeHitRegionById(options.id);
2439     m_hitRegionManager->removeHitRegionByControl(options.control.get());
2440
2441     RefPtrWillBeRawPtr<HitRegion> hitRegion = HitRegion::create(options);
2442     hitRegion->updateAccessibility(canvas());
2443     m_hitRegionManager->addHitRegion(hitRegion.release());
2444 }
2445
2446 void CanvasRenderingContext2D::removeHitRegion(const String& id)
2447 {
2448     if (m_hitRegionManager)
2449         m_hitRegionManager->removeHitRegionById(id);
2450 }
2451
2452 void CanvasRenderingContext2D::clearHitRegions()
2453 {
2454     if (m_hitRegionManager)
2455         m_hitRegionManager->removeAllHitRegions();
2456 }
2457
2458 HitRegion* CanvasRenderingContext2D::hitRegionAtPoint(const LayoutPoint& point)
2459 {
2460     if (m_hitRegionManager)
2461         return m_hitRegionManager->getHitRegionAtPoint(point);
2462
2463     return 0;
2464 }
2465
2466 unsigned CanvasRenderingContext2D::hitRegionsCount() const
2467 {
2468     if (m_hitRegionManager)
2469         return m_hitRegionManager->getHitRegionsCount();
2470
2471     return 0;
2472 }
2473
2474 } // namespace blink