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