[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebCore / html / canvas / CanvasRenderingContext2DBase.cpp
1 /*
2  * Copyright (C) 2004-2017 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 Intel Corporation. All rights reserved.
9  * Copyright (C) 2013, 2014 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 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 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 "CanvasRenderingContext2DBase.h"
35
36 #include "BitmapImage.h"
37 #include "CSSFontSelector.h"
38 #include "CSSParser.h"
39 #include "CSSPropertyNames.h"
40 #include "CachedImage.h"
41 #include "CanvasGradient.h"
42 #include "CanvasPattern.h"
43 #include "DOMMatrix.h"
44 #include "DOMMatrix2DInit.h"
45 #include "DisplayListRecorder.h"
46 #include "DisplayListReplayer.h"
47 #include "FloatQuad.h"
48 #include "HTMLCanvasElement.h"
49 #include "HTMLImageElement.h"
50 #include "HTMLVideoElement.h"
51 #include "ImageBitmap.h"
52 #include "ImageBuffer.h"
53 #include "ImageData.h"
54 #include "Path2D.h"
55 #include "RenderElement.h"
56 #include "RenderImage.h"
57 #include "RenderLayer.h"
58 #include "RenderTheme.h"
59 #include "SecurityOrigin.h"
60 #include "StrokeStyleApplier.h"
61 #include "StyleProperties.h"
62 #include "StyleResolver.h"
63 #include "TextMetrics.h"
64 #include "TextRun.h"
65 #include "TypedOMCSSImageValue.h"
66 #include <wtf/CheckedArithmetic.h>
67 #include <wtf/IsoMallocInlines.h>
68 #include <wtf/MathExtras.h>
69 #include <wtf/NeverDestroyed.h>
70 #include <wtf/text/StringBuilder.h>
71 #include <wtf/text/TextStream.h>
72
73 namespace WebCore {
74
75 using namespace HTMLNames;
76
77 WTF_MAKE_ISO_ALLOCATED_IMPL(CanvasRenderingContext2DBase);
78
79 #if USE(CG)
80 const ImageSmoothingQuality defaultSmoothingQuality = ImageSmoothingQuality::Low;
81 #else
82 const ImageSmoothingQuality defaultSmoothingQuality = ImageSmoothingQuality::Medium;
83 #endif
84
85 const int CanvasRenderingContext2DBase::DefaultFontSize = 10;
86 const char* const CanvasRenderingContext2DBase::DefaultFontFamily = "sans-serif";
87 const char* const CanvasRenderingContext2DBase::DefaultFont = "10px sans-serif";
88
89 struct DisplayListDrawingContext {
90     WTF_MAKE_FAST_ALLOCATED;
91 public:
92     GraphicsContext context;
93     DisplayList::DisplayList displayList;
94     
95     DisplayListDrawingContext(GraphicsContext& context, const FloatRect& clip)
96         : DisplayListDrawingContext(context.state(), clip)
97     {
98     }
99
100     DisplayListDrawingContext(const GraphicsContextState& state, const FloatRect& clip)
101         : context([&](GraphicsContext& displayListContext) {
102             return makeUnique<DisplayList::Recorder>(displayListContext, displayList, state, clip, AffineTransform());
103         })
104     {
105     }
106 };
107
108 typedef HashMap<const CanvasRenderingContext2DBase*, std::unique_ptr<DisplayList::DisplayList>> ContextDisplayListHashMap;
109
110 static ContextDisplayListHashMap& contextDisplayListMap()
111 {
112     static NeverDestroyed<ContextDisplayListHashMap> sharedHashMap;
113     return sharedHashMap;
114 }
115
116 class CanvasStrokeStyleApplier : public StrokeStyleApplier {
117 public:
118     CanvasStrokeStyleApplier(CanvasRenderingContext2DBase* canvasContext)
119         : m_canvasContext(canvasContext)
120     {
121     }
122
123     void strokeStyle(GraphicsContext* c) override
124     {
125         c->setStrokeThickness(m_canvasContext->lineWidth());
126         c->setLineCap(m_canvasContext->getLineCap());
127         c->setLineJoin(m_canvasContext->getLineJoin());
128         c->setMiterLimit(m_canvasContext->miterLimit());
129         const Vector<float>& lineDash = m_canvasContext->getLineDash();
130         DashArray convertedLineDash(lineDash.size());
131         for (size_t i = 0; i < lineDash.size(); ++i)
132             convertedLineDash[i] = static_cast<DashArrayElement>(lineDash[i]);
133         c->setLineDash(convertedLineDash, m_canvasContext->lineDashOffset());
134     }
135
136 private:
137     CanvasRenderingContext2DBase* m_canvasContext;
138 };
139
140 CanvasRenderingContext2DBase::CanvasRenderingContext2DBase(CanvasBase& canvas, bool usesCSSCompatibilityParseMode)
141     : CanvasRenderingContext(canvas)
142     , m_stateStack(1)
143     , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
144 {
145 }
146
147 void CanvasRenderingContext2DBase::unwindStateStack()
148 {
149     // Ensure that the state stack in the ImageBuffer's context
150     // is cleared before destruction, to avoid assertions in the
151     // GraphicsContext dtor.
152     if (size_t stackSize = m_stateStack.size()) {
153         if (auto* context = canvasBase().existingDrawingContext()) {
154             while (--stackSize)
155                 context->restore();
156         }
157     }
158 }
159
160 CanvasRenderingContext2DBase::~CanvasRenderingContext2DBase()
161 {
162 #if !ASSERT_DISABLED
163     unwindStateStack();
164 #endif
165
166     if (UNLIKELY(tracksDisplayListReplay()))
167         contextDisplayListMap().remove(this);
168 }
169
170 bool CanvasRenderingContext2DBase::isAccelerated() const
171 {
172 #if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
173     auto* context = canvasBase().existingDrawingContext();
174     return context && context->isAcceleratedContext();
175 #else
176     return false;
177 #endif
178 }
179
180 void CanvasRenderingContext2DBase::reset()
181 {
182     unwindStateStack();
183     m_stateStack.resize(1);
184     m_stateStack.first() = State();
185     m_path.clear();
186     m_unrealizedSaveCount = 0;
187     
188     m_recordingContext = nullptr;
189 }
190
191 CanvasRenderingContext2DBase::State::State()
192     : strokeStyle(Color::black)
193     , fillStyle(Color::black)
194     , lineWidth(1)
195     , lineCap(ButtCap)
196     , lineJoin(MiterJoin)
197     , miterLimit(10)
198     , shadowBlur(0)
199     , shadowColor(Color::transparent)
200     , globalAlpha(1)
201     , globalComposite(CompositeSourceOver)
202     , globalBlend(BlendMode::Normal)
203     , hasInvertibleTransform(true)
204     , lineDashOffset(0)
205     , imageSmoothingEnabled(true)
206     , imageSmoothingQuality(defaultSmoothingQuality)
207     , textAlign(StartTextAlign)
208     , textBaseline(AlphabeticTextBaseline)
209     , direction(Direction::Inherit)
210     , unparsedFont(DefaultFont)
211 {
212 }
213
214 CanvasRenderingContext2DBase::State::State(const State& other)
215     : unparsedStrokeColor(other.unparsedStrokeColor)
216     , unparsedFillColor(other.unparsedFillColor)
217     , strokeStyle(other.strokeStyle)
218     , fillStyle(other.fillStyle)
219     , lineWidth(other.lineWidth)
220     , lineCap(other.lineCap)
221     , lineJoin(other.lineJoin)
222     , miterLimit(other.miterLimit)
223     , shadowOffset(other.shadowOffset)
224     , shadowBlur(other.shadowBlur)
225     , shadowColor(other.shadowColor)
226     , globalAlpha(other.globalAlpha)
227     , globalComposite(other.globalComposite)
228     , globalBlend(other.globalBlend)
229     , transform(other.transform)
230     , hasInvertibleTransform(other.hasInvertibleTransform)
231     , lineDashOffset(other.lineDashOffset)
232     , imageSmoothingEnabled(other.imageSmoothingEnabled)
233     , imageSmoothingQuality(other.imageSmoothingQuality)
234     , textAlign(other.textAlign)
235     , textBaseline(other.textBaseline)
236     , direction(other.direction)
237     , unparsedFont(other.unparsedFont)
238     , font(other.font)
239 {
240 }
241
242 CanvasRenderingContext2DBase::State& CanvasRenderingContext2DBase::State::operator=(const State& other)
243 {
244     if (this == &other)
245         return *this;
246
247     unparsedStrokeColor = other.unparsedStrokeColor;
248     unparsedFillColor = other.unparsedFillColor;
249     strokeStyle = other.strokeStyle;
250     fillStyle = other.fillStyle;
251     lineWidth = other.lineWidth;
252     lineCap = other.lineCap;
253     lineJoin = other.lineJoin;
254     miterLimit = other.miterLimit;
255     shadowOffset = other.shadowOffset;
256     shadowBlur = other.shadowBlur;
257     shadowColor = other.shadowColor;
258     globalAlpha = other.globalAlpha;
259     globalComposite = other.globalComposite;
260     globalBlend = other.globalBlend;
261     transform = other.transform;
262     hasInvertibleTransform = other.hasInvertibleTransform;
263     imageSmoothingEnabled = other.imageSmoothingEnabled;
264     imageSmoothingQuality = other.imageSmoothingQuality;
265     textAlign = other.textAlign;
266     textBaseline = other.textBaseline;
267     direction = other.direction;
268     unparsedFont = other.unparsedFont;
269     font = other.font;
270
271     return *this;
272 }
273
274 CanvasRenderingContext2DBase::FontProxy::~FontProxy()
275 {
276     if (realized())
277         m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
278 }
279
280 CanvasRenderingContext2DBase::FontProxy::FontProxy(const FontProxy& other)
281     : m_font(other.m_font)
282 {
283     if (realized())
284         m_font.fontSelector()->registerForInvalidationCallbacks(*this);
285 }
286
287 auto CanvasRenderingContext2DBase::FontProxy::operator=(const FontProxy& other) -> FontProxy&
288 {
289     if (realized())
290         m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
291
292     m_font = other.m_font;
293
294     if (realized())
295         m_font.fontSelector()->registerForInvalidationCallbacks(*this);
296
297     return *this;
298 }
299
300 inline void CanvasRenderingContext2DBase::FontProxy::update(FontSelector& selector)
301 {
302     ASSERT(&selector == m_font.fontSelector()); // This is an invariant. We should only ever be registered for callbacks on m_font.m_fonts.m_fontSelector.
303     if (realized())
304         m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
305     m_font.update(&selector);
306     if (realized())
307         m_font.fontSelector()->registerForInvalidationCallbacks(*this);
308     ASSERT(&selector == m_font.fontSelector());
309 }
310
311 void CanvasRenderingContext2DBase::FontProxy::fontsNeedUpdate(FontSelector& selector)
312 {
313     ASSERT_ARG(selector, &selector == m_font.fontSelector());
314     ASSERT(realized());
315
316     update(selector);
317 }
318
319 void CanvasRenderingContext2DBase::FontProxy::initialize(FontSelector& fontSelector, const RenderStyle& newStyle)
320 {
321     // Beware! m_font.fontSelector() might not point to document.fontSelector()!
322     ASSERT(newStyle.fontCascade().fontSelector() == &fontSelector);
323     if (realized())
324         m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
325     m_font = newStyle.fontCascade();
326     m_font.update(&fontSelector);
327     ASSERT(&fontSelector == m_font.fontSelector());
328     m_font.fontSelector()->registerForInvalidationCallbacks(*this);
329 }
330
331 const FontMetrics& CanvasRenderingContext2DBase::FontProxy::fontMetrics() const
332 {
333     return m_font.fontMetrics();
334 }
335
336 const FontCascadeDescription& CanvasRenderingContext2DBase::FontProxy::fontDescription() const
337 {
338     return m_font.fontDescription();
339 }
340
341 float CanvasRenderingContext2DBase::FontProxy::width(const TextRun& textRun, GlyphOverflow* overflow) const
342 {
343     return m_font.width(textRun, 0, overflow);
344 }
345
346 void CanvasRenderingContext2DBase::FontProxy::drawBidiText(GraphicsContext& context, const TextRun& run, const FloatPoint& point, FontCascade::CustomFontNotReadyAction action) const
347 {
348     context.drawBidiText(m_font, run, point, action);
349 }
350
351 void CanvasRenderingContext2DBase::realizeSaves()
352 {
353     if (m_unrealizedSaveCount)
354         realizeSavesLoop();
355
356     if (m_unrealizedSaveCount) {
357         static NeverDestroyed<String> consoleMessage(MAKE_STATIC_STRING_IMPL("CanvasRenderingContext2D.save() has been called without a matching restore() too many times. Ignoring save()."));
358
359         canvasBase().scriptExecutionContext()->addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, consoleMessage);
360     }
361 }
362
363 void CanvasRenderingContext2DBase::realizeSavesLoop()
364 {
365     ASSERT(m_unrealizedSaveCount);
366     ASSERT(m_stateStack.size() >= 1);
367     GraphicsContext* context = drawingContext();
368     do {
369         if (m_stateStack.size() > MaxSaveCount)
370             break;
371         m_stateStack.append(state());
372         if (context)
373             context->save();
374     } while (--m_unrealizedSaveCount);
375 }
376
377 void CanvasRenderingContext2DBase::restore()
378 {
379     if (m_unrealizedSaveCount) {
380         --m_unrealizedSaveCount;
381         return;
382     }
383     ASSERT(m_stateStack.size() >= 1);
384     if (m_stateStack.size() <= 1)
385         return;
386     m_path.transform(state().transform);
387     m_stateStack.removeLast();
388     if (Optional<AffineTransform> inverse = state().transform.inverse())
389         m_path.transform(inverse.value());
390     GraphicsContext* c = drawingContext();
391     if (!c)
392         return;
393     c->restore();
394 }
395
396 void CanvasRenderingContext2DBase::setStrokeStyle(CanvasStyle style)
397 {
398     if (!style.isValid())
399         return;
400
401     if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentColor(style))
402         return;
403
404     if (style.isCurrentColor() && is<HTMLCanvasElement>(canvasBase())) {
405         auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
406
407         if (style.hasOverrideAlpha()) {
408             // FIXME: Should not use RGBA32 here.
409             style = CanvasStyle(colorWithOverrideAlpha(currentColor(&canvas).rgb(), style.overrideAlpha()));
410         } else
411             style = CanvasStyle(currentColor(&canvas));
412     } else
413         checkOrigin(style.canvasPattern().get());
414
415     realizeSaves();
416     State& state = modifiableState();
417     state.strokeStyle = style;
418     GraphicsContext* c = drawingContext();
419     if (!c)
420         return;
421     state.strokeStyle.applyStrokeColor(*c);
422     state.unparsedStrokeColor = String();
423 }
424
425 void CanvasRenderingContext2DBase::setFillStyle(CanvasStyle style)
426 {
427     if (!style.isValid())
428         return;
429
430     if (state().fillStyle.isValid() && state().fillStyle.isEquivalentColor(style))
431         return;
432
433     if (style.isCurrentColor() && is<HTMLCanvasElement>(canvasBase())) {
434         auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
435
436         if (style.hasOverrideAlpha()) {
437             // FIXME: Should not use RGBA32 here.
438             style = CanvasStyle(colorWithOverrideAlpha(currentColor(&canvas).rgb(), style.overrideAlpha()));
439         } else
440             style = CanvasStyle(currentColor(&canvas));
441     } else
442         checkOrigin(style.canvasPattern().get());
443
444     realizeSaves();
445     State& state = modifiableState();
446     state.fillStyle = style;
447     GraphicsContext* c = drawingContext();
448     if (!c)
449         return;
450     state.fillStyle.applyFillColor(*c);
451     state.unparsedFillColor = String();
452 }
453
454 float CanvasRenderingContext2DBase::lineWidth() const
455 {
456     return state().lineWidth;
457 }
458
459 void CanvasRenderingContext2DBase::setLineWidth(float width)
460 {
461     if (!(std::isfinite(width) && width > 0))
462         return;
463     if (state().lineWidth == width)
464         return;
465     realizeSaves();
466     modifiableState().lineWidth = width;
467     GraphicsContext* c = drawingContext();
468     if (!c)
469         return;
470     c->setStrokeThickness(width);
471 }
472
473 static CanvasLineCap toCanvasLineCap(LineCap lineCap)
474 {
475     switch (lineCap) {
476     case ButtCap:
477         return CanvasLineCap::Butt;
478     case RoundCap:
479         return CanvasLineCap::Round;
480     case SquareCap:
481         return CanvasLineCap::Square;
482     }
483
484     ASSERT_NOT_REACHED();
485     return CanvasLineCap::Butt;
486 }
487
488 static LineCap fromCanvasLineCap(CanvasLineCap canvasLineCap)
489 {
490     switch (canvasLineCap) {
491     case CanvasLineCap::Butt:
492         return ButtCap;
493     case CanvasLineCap::Round:
494         return RoundCap;
495     case CanvasLineCap::Square:
496         return SquareCap;
497     }
498     
499     ASSERT_NOT_REACHED();
500     return ButtCap;
501 }
502
503 CanvasLineCap CanvasRenderingContext2DBase::lineCap() const
504 {
505     return toCanvasLineCap(state().lineCap);
506 }
507
508 void CanvasRenderingContext2DBase::setLineCap(CanvasLineCap canvasLineCap)
509 {
510     auto lineCap = fromCanvasLineCap(canvasLineCap);
511     if (state().lineCap == lineCap)
512         return;
513     realizeSaves();
514     modifiableState().lineCap = lineCap;
515     GraphicsContext* c = drawingContext();
516     if (!c)
517         return;
518     c->setLineCap(lineCap);
519 }
520
521 void CanvasRenderingContext2DBase::setLineCap(const String& stringValue)
522 {
523     CanvasLineCap cap;
524     if (stringValue == "butt")
525         cap = CanvasLineCap::Butt;
526     else if (stringValue == "round")
527         cap = CanvasLineCap::Round;
528     else if (stringValue == "square")
529         cap = CanvasLineCap::Square;
530     else
531         return;
532     
533     setLineCap(cap);
534 }
535
536 static CanvasLineJoin toCanvasLineJoin(LineJoin lineJoin)
537 {
538     switch (lineJoin) {
539     case RoundJoin:
540         return CanvasLineJoin::Round;
541     case BevelJoin:
542         return CanvasLineJoin::Bevel;
543     case MiterJoin:
544         return CanvasLineJoin::Miter;
545     }
546
547     ASSERT_NOT_REACHED();
548     return CanvasLineJoin::Round;
549 }
550
551 static LineJoin fromCanvasLineJoin(CanvasLineJoin canvasLineJoin)
552 {
553     switch (canvasLineJoin) {
554     case CanvasLineJoin::Round:
555         return RoundJoin;
556     case CanvasLineJoin::Bevel:
557         return BevelJoin;
558     case CanvasLineJoin::Miter:
559         return MiterJoin;
560     }
561     
562     ASSERT_NOT_REACHED();
563     return RoundJoin;
564 }
565
566 CanvasLineJoin CanvasRenderingContext2DBase::lineJoin() const
567 {
568     return toCanvasLineJoin(state().lineJoin);
569 }
570
571 void CanvasRenderingContext2DBase::setLineJoin(CanvasLineJoin canvasLineJoin)
572 {
573     auto lineJoin = fromCanvasLineJoin(canvasLineJoin);
574     if (state().lineJoin == lineJoin)
575         return;
576     realizeSaves();
577     modifiableState().lineJoin = lineJoin;
578     GraphicsContext* c = drawingContext();
579     if (!c)
580         return;
581     c->setLineJoin(lineJoin);
582 }
583
584 void CanvasRenderingContext2DBase::setLineJoin(const String& stringValue)
585 {
586     CanvasLineJoin join;
587     if (stringValue == "round")
588         join = CanvasLineJoin::Round;
589     else if (stringValue == "bevel")
590         join = CanvasLineJoin::Bevel;
591     else if (stringValue == "miter")
592         join = CanvasLineJoin::Miter;
593     else
594         return;
595
596     setLineJoin(join);
597 }
598
599 float CanvasRenderingContext2DBase::miterLimit() const
600 {
601     return state().miterLimit;
602 }
603
604 void CanvasRenderingContext2DBase::setMiterLimit(float limit)
605 {
606     if (!(std::isfinite(limit) && limit > 0))
607         return;
608     if (state().miterLimit == limit)
609         return;
610     realizeSaves();
611     modifiableState().miterLimit = limit;
612     GraphicsContext* c = drawingContext();
613     if (!c)
614         return;
615     c->setMiterLimit(limit);
616 }
617
618 float CanvasRenderingContext2DBase::shadowOffsetX() const
619 {
620     return state().shadowOffset.width();
621 }
622
623 void CanvasRenderingContext2DBase::setShadowOffsetX(float x)
624 {
625     if (!std::isfinite(x))
626         return;
627     if (state().shadowOffset.width() == x)
628         return;
629     realizeSaves();
630     modifiableState().shadowOffset.setWidth(x);
631     applyShadow();
632 }
633
634 float CanvasRenderingContext2DBase::shadowOffsetY() const
635 {
636     return state().shadowOffset.height();
637 }
638
639 void CanvasRenderingContext2DBase::setShadowOffsetY(float y)
640 {
641     if (!std::isfinite(y))
642         return;
643     if (state().shadowOffset.height() == y)
644         return;
645     realizeSaves();
646     modifiableState().shadowOffset.setHeight(y);
647     applyShadow();
648 }
649
650 float CanvasRenderingContext2DBase::shadowBlur() const
651 {
652     return state().shadowBlur;
653 }
654
655 void CanvasRenderingContext2DBase::setShadowBlur(float blur)
656 {
657     if (!(std::isfinite(blur) && blur >= 0))
658         return;
659     if (state().shadowBlur == blur)
660         return;
661     realizeSaves();
662     modifiableState().shadowBlur = blur;
663     applyShadow();
664 }
665
666 String CanvasRenderingContext2DBase::shadowColor() const
667 {
668     return Color(state().shadowColor).serialized();
669 }
670
671 void CanvasRenderingContext2DBase::setShadowColor(const String& colorString)
672 {
673     auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
674     Color color = parseColorOrCurrentColor(colorString, &canvas);
675     if (!color.isValid())
676         return;
677     if (state().shadowColor == color)
678         return;
679     realizeSaves();
680     modifiableState().shadowColor = color;
681     applyShadow();
682 }
683
684 const Vector<float>& CanvasRenderingContext2DBase::getLineDash() const
685 {
686     return state().lineDash;
687 }
688
689 static bool lineDashSequenceIsValid(const Vector<float>& dash)
690 {
691     for (size_t i = 0; i < dash.size(); i++) {
692         if (!std::isfinite(dash[i]) || dash[i] < 0)
693             return false;
694     }
695     return true;
696 }
697
698 void CanvasRenderingContext2DBase::setLineDash(const Vector<float>& dash)
699 {
700     if (!lineDashSequenceIsValid(dash))
701         return;
702
703     realizeSaves();
704     modifiableState().lineDash = dash;
705     // Spec requires the concatenation of two copies the dash list when the
706     // number of elements is odd
707     if (dash.size() % 2)
708         modifiableState().lineDash.appendVector(dash);
709
710     applyLineDash();
711 }
712
713 void CanvasRenderingContext2DBase::setWebkitLineDash(const Vector<float>& dash)
714 {
715     if (!lineDashSequenceIsValid(dash))
716         return;
717
718     realizeSaves();
719     modifiableState().lineDash = dash;
720
721     applyLineDash();
722 }
723
724 float CanvasRenderingContext2DBase::lineDashOffset() const
725 {
726     return state().lineDashOffset;
727 }
728
729 void CanvasRenderingContext2DBase::setLineDashOffset(float offset)
730 {
731     if (!std::isfinite(offset) || state().lineDashOffset == offset)
732         return;
733
734     realizeSaves();
735     modifiableState().lineDashOffset = offset;
736     applyLineDash();
737 }
738
739 void CanvasRenderingContext2DBase::applyLineDash() const
740 {
741     GraphicsContext* c = drawingContext();
742     if (!c)
743         return;
744     DashArray convertedLineDash(state().lineDash.size());
745     for (size_t i = 0; i < state().lineDash.size(); ++i)
746         convertedLineDash[i] = static_cast<DashArrayElement>(state().lineDash[i]);
747     c->setLineDash(convertedLineDash, state().lineDashOffset);
748 }
749
750 float CanvasRenderingContext2DBase::globalAlpha() const
751 {
752     return state().globalAlpha;
753 }
754
755 void CanvasRenderingContext2DBase::setGlobalAlpha(float alpha)
756 {
757     if (!(alpha >= 0 && alpha <= 1))
758         return;
759     if (state().globalAlpha == alpha)
760         return;
761     realizeSaves();
762     modifiableState().globalAlpha = alpha;
763     GraphicsContext* c = drawingContext();
764     if (!c)
765         return;
766     c->setAlpha(alpha);
767 }
768
769 String CanvasRenderingContext2DBase::globalCompositeOperation() const
770 {
771     return compositeOperatorName(state().globalComposite, state().globalBlend);
772 }
773
774 void CanvasRenderingContext2DBase::setGlobalCompositeOperation(const String& operation)
775 {
776     CompositeOperator op = CompositeSourceOver;
777     BlendMode blendMode = BlendMode::Normal;
778     if (!parseCompositeAndBlendOperator(operation, op, blendMode))
779         return;
780     if ((state().globalComposite == op) && (state().globalBlend == blendMode))
781         return;
782     realizeSaves();
783     modifiableState().globalComposite = op;
784     modifiableState().globalBlend = blendMode;
785     GraphicsContext* c = drawingContext();
786     if (!c)
787         return;
788     c->setCompositeOperation(op, blendMode);
789 }
790
791 void CanvasRenderingContext2DBase::scale(float sx, float sy)
792 {
793     GraphicsContext* c = drawingContext();
794     if (!c)
795         return;
796     if (!state().hasInvertibleTransform)
797         return;
798
799     if (!std::isfinite(sx) || !std::isfinite(sy))
800         return;
801
802     AffineTransform newTransform = state().transform;
803     newTransform.scaleNonUniform(sx, sy);
804     if (state().transform == newTransform)
805         return;
806
807     realizeSaves();
808
809     if (!sx || !sy) {
810         modifiableState().hasInvertibleTransform = false;
811         return;
812     }
813
814     modifiableState().transform = newTransform;
815     c->scale(FloatSize(sx, sy));
816     m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
817 }
818
819 void CanvasRenderingContext2DBase::rotate(float angleInRadians)
820 {
821     GraphicsContext* c = drawingContext();
822     if (!c)
823         return;
824     if (!state().hasInvertibleTransform)
825         return;
826
827     if (!std::isfinite(angleInRadians))
828         return;
829
830     AffineTransform newTransform = state().transform;
831     newTransform.rotate(angleInRadians / piDouble * 180.0);
832     if (state().transform == newTransform)
833         return;
834
835     realizeSaves();
836
837     modifiableState().transform = newTransform;
838     c->rotate(angleInRadians);
839     m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0));
840 }
841
842 void CanvasRenderingContext2DBase::translate(float tx, float ty)
843 {
844     GraphicsContext* c = drawingContext();
845     if (!c)
846         return;
847     if (!state().hasInvertibleTransform)
848         return;
849
850     if (!std::isfinite(tx) | !std::isfinite(ty))
851         return;
852
853     AffineTransform newTransform = state().transform;
854     newTransform.translate(tx, ty);
855     if (state().transform == newTransform)
856         return;
857
858     realizeSaves();
859
860     modifiableState().transform = newTransform;
861     c->translate(tx, ty);
862     m_path.transform(AffineTransform().translate(-tx, -ty));
863 }
864
865 void CanvasRenderingContext2DBase::transform(float m11, float m12, float m21, float m22, float dx, float dy)
866 {
867     GraphicsContext* c = drawingContext();
868     if (!c)
869         return;
870     if (!state().hasInvertibleTransform)
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     AffineTransform transform(m11, m12, m21, m22, dx, dy);
877     AffineTransform newTransform = state().transform * transform;
878     if (state().transform == newTransform)
879         return;
880
881     realizeSaves();
882
883     if (auto inverse = transform.inverse()) {
884         modifiableState().transform = newTransform;
885         c->concatCTM(transform);
886         m_path.transform(inverse.value());
887         return;
888     }
889     modifiableState().hasInvertibleTransform = false;
890 }
891
892 Ref<DOMMatrix> CanvasRenderingContext2DBase::getTransform() const
893 {
894     return DOMMatrix::create(state().transform.toTransformationMatrix(), DOMMatrixReadOnly::Is2D::Yes);
895 }
896
897 void CanvasRenderingContext2DBase::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
898 {
899     GraphicsContext* c = drawingContext();
900     if (!c)
901         return;
902
903     if (!std::isfinite(m11) | !std::isfinite(m21) | !std::isfinite(dx) | !std::isfinite(m12) | !std::isfinite(m22) | !std::isfinite(dy))
904         return;
905
906     resetTransform();
907     transform(m11, m12, m21, m22, dx, dy);
908 }
909
910 ExceptionOr<void> CanvasRenderingContext2DBase::setTransform(DOMMatrix2DInit&& matrixInit)
911 {
912     auto checkValid = DOMMatrixReadOnly::validateAndFixup(matrixInit);
913     if (checkValid.hasException())
914         return checkValid.releaseException();
915
916     setTransform(matrixInit.m11.value(), matrixInit.m12.value(), matrixInit.m21.value(), matrixInit.m22.value(), matrixInit.m41.value(), matrixInit.m42.value());
917     return { };
918 }
919
920 void CanvasRenderingContext2DBase::resetTransform()
921 {
922     GraphicsContext* c = drawingContext();
923     if (!c)
924         return;
925
926     AffineTransform ctm = state().transform;
927     bool hasInvertibleTransform = state().hasInvertibleTransform;
928
929     realizeSaves();
930
931     c->setCTM(canvasBase().baseTransform());
932     modifiableState().transform = AffineTransform();
933
934     if (hasInvertibleTransform)
935         m_path.transform(ctm);
936
937     modifiableState().hasInvertibleTransform = true;
938 }
939
940 void CanvasRenderingContext2DBase::setStrokeColor(const String& color, Optional<float> alpha)
941 {
942     if (alpha) {
943         setStrokeStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha.value()));
944         return;
945     }
946
947     if (color == state().unparsedStrokeColor)
948         return;
949
950     realizeSaves();
951     setStrokeStyle(CanvasStyle::createFromString(color));
952     modifiableState().unparsedStrokeColor = color;
953 }
954
955 void CanvasRenderingContext2DBase::setStrokeColor(float grayLevel, float alpha)
956 {
957     if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
958         return;
959     setStrokeStyle(CanvasStyle(grayLevel, alpha));
960 }
961
962 void CanvasRenderingContext2DBase::setStrokeColor(float r, float g, float b, float a)
963 {
964     if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentRGBA(r, g, b, a))
965         return;
966     setStrokeStyle(CanvasStyle(r, g, b, a));
967 }
968
969 void CanvasRenderingContext2DBase::setStrokeColor(float c, float m, float y, float k, float a)
970 {
971     if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentCMYKA(c, m, y, k, a))
972         return;
973     setStrokeStyle(CanvasStyle(c, m, y, k, a));
974 }
975
976 void CanvasRenderingContext2DBase::setFillColor(const String& color, Optional<float> alpha)
977 {
978     if (alpha) {
979         setFillStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha.value()));
980         return;
981     }
982
983     if (color == state().unparsedFillColor)
984         return;
985
986     realizeSaves();
987     setFillStyle(CanvasStyle::createFromString(color));
988     modifiableState().unparsedFillColor = color;
989 }
990
991 void CanvasRenderingContext2DBase::setFillColor(float grayLevel, float alpha)
992 {
993     if (state().fillStyle.isValid() && state().fillStyle.isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
994         return;
995     setFillStyle(CanvasStyle(grayLevel, alpha));
996 }
997
998 void CanvasRenderingContext2DBase::setFillColor(float r, float g, float b, float a)
999 {
1000     if (state().fillStyle.isValid() && state().fillStyle.isEquivalentRGBA(r, g, b, a))
1001         return;
1002     setFillStyle(CanvasStyle(r, g, b, a));
1003 }
1004
1005 void CanvasRenderingContext2DBase::setFillColor(float c, float m, float y, float k, float a)
1006 {
1007     if (state().fillStyle.isValid() && state().fillStyle.isEquivalentCMYKA(c, m, y, k, a))
1008         return;
1009     setFillStyle(CanvasStyle(c, m, y, k, a));
1010 }
1011
1012 void CanvasRenderingContext2DBase::beginPath()
1013 {
1014     m_path.clear();
1015 }
1016
1017 static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
1018 {
1019     if (!std::isfinite(x) | !std::isfinite(y) | !std::isfinite(width) | !std::isfinite(height))
1020         return false;
1021
1022     if (!width && !height)
1023         return false;
1024
1025     if (width < 0) {
1026         width = -width;
1027         x -= width;
1028     }
1029
1030     if (height < 0) {
1031         height = -height;
1032         y -= height;
1033     }
1034
1035     return true;
1036 }
1037
1038 bool CanvasRenderingContext2DBase::isFullCanvasCompositeMode(CompositeOperator op)
1039 {
1040     // See 4.8.11.1.3 Compositing
1041     // CompositeSourceAtop and CompositeDestinationOut are not listed here as the platforms already
1042     // implement the specification's behavior.
1043     return op == CompositeSourceIn || op == CompositeSourceOut || op == CompositeDestinationIn || op == CompositeDestinationAtop;
1044 }
1045
1046 static WindRule toWindRule(CanvasFillRule rule)
1047 {
1048     return rule == CanvasFillRule::Nonzero ? WindRule::NonZero : WindRule::EvenOdd;
1049 }
1050
1051 void CanvasRenderingContext2DBase::fill(CanvasFillRule windingRule)
1052 {
1053     fillInternal(m_path, windingRule);
1054 }
1055
1056 void CanvasRenderingContext2DBase::stroke()
1057 {
1058     strokeInternal(m_path);
1059 }
1060
1061 void CanvasRenderingContext2DBase::clip(CanvasFillRule windingRule)
1062 {
1063     clipInternal(m_path, windingRule);
1064 }
1065
1066 void CanvasRenderingContext2DBase::fill(Path2D& path, CanvasFillRule windingRule)
1067 {
1068     fillInternal(path.path(), windingRule);
1069 }
1070
1071 void CanvasRenderingContext2DBase::stroke(Path2D& path)
1072 {
1073     strokeInternal(path.path());
1074 }
1075
1076 void CanvasRenderingContext2DBase::clip(Path2D& path, CanvasFillRule windingRule)
1077 {
1078     clipInternal(path.path(), windingRule);
1079 }
1080
1081 void CanvasRenderingContext2DBase::fillInternal(const Path& path, CanvasFillRule windingRule)
1082 {
1083     auto* c = drawingContext();
1084     if (!c)
1085         return;
1086     if (!state().hasInvertibleTransform)
1087         return;
1088
1089     // If gradient size is zero, then paint nothing.
1090     auto gradient = c->fillGradient();
1091     if (gradient && gradient->isZeroSize())
1092         return;
1093
1094     if (!path.isEmpty()) {
1095         auto savedFillRule = c->fillRule();
1096         c->setFillRule(toWindRule(windingRule));
1097
1098         if (isFullCanvasCompositeMode(state().globalComposite)) {
1099             beginCompositeLayer();
1100             c->fillPath(path);
1101             endCompositeLayer();
1102             didDrawEntireCanvas();
1103         } else if (state().globalComposite == CompositeCopy) {
1104             clearCanvas();
1105             c->fillPath(path);
1106             didDrawEntireCanvas();
1107         } else {
1108             c->fillPath(path);
1109             didDraw(path.fastBoundingRect());
1110         }
1111         
1112         c->setFillRule(savedFillRule);
1113     }
1114 }
1115
1116 void CanvasRenderingContext2DBase::strokeInternal(const Path& path)
1117 {
1118     auto* c = drawingContext();
1119     if (!c)
1120         return;
1121     if (!state().hasInvertibleTransform)
1122         return;
1123
1124     // If gradient size is zero, then paint nothing.
1125     auto gradient = c->strokeGradient();
1126     if (gradient && gradient->isZeroSize())
1127         return;
1128
1129     if (!path.isEmpty()) {
1130         if (isFullCanvasCompositeMode(state().globalComposite)) {
1131             beginCompositeLayer();
1132             c->strokePath(path);
1133             endCompositeLayer();
1134             didDrawEntireCanvas();
1135         } else if (state().globalComposite == CompositeCopy) {
1136             clearCanvas();
1137             c->strokePath(path);
1138             didDrawEntireCanvas();
1139         } else {
1140             FloatRect dirtyRect = path.fastBoundingRect();
1141             inflateStrokeRect(dirtyRect);
1142             c->strokePath(path);
1143             didDraw(dirtyRect);
1144         }
1145     }
1146 }
1147
1148 void CanvasRenderingContext2DBase::clipInternal(const Path& path, CanvasFillRule windingRule)
1149 {
1150     auto* c = drawingContext();
1151     if (!c)
1152         return;
1153     if (!state().hasInvertibleTransform)
1154         return;
1155
1156     realizeSaves();
1157     c->canvasClip(path, toWindRule(windingRule));
1158 }
1159
1160 void CanvasRenderingContext2DBase::beginCompositeLayer()
1161 {
1162 #if !USE(CAIRO)
1163     drawingContext()->beginTransparencyLayer(1);
1164 #endif
1165 }
1166
1167 void CanvasRenderingContext2DBase::endCompositeLayer()
1168 {
1169 #if !USE(CAIRO)
1170     drawingContext()->endTransparencyLayer();    
1171 #endif
1172 }
1173
1174 bool CanvasRenderingContext2DBase::isPointInPath(float x, float y, CanvasFillRule windingRule)
1175 {
1176     return isPointInPathInternal(m_path, x, y, windingRule);
1177 }
1178
1179 bool CanvasRenderingContext2DBase::isPointInStroke(float x, float y)
1180 {
1181     return isPointInStrokeInternal(m_path, x, y);
1182 }
1183
1184 bool CanvasRenderingContext2DBase::isPointInPath(Path2D& path, float x, float y, CanvasFillRule windingRule)
1185 {
1186     return isPointInPathInternal(path.path(), x, y, windingRule);
1187 }
1188
1189 bool CanvasRenderingContext2DBase::isPointInStroke(Path2D& path, float x, float y)
1190 {
1191     return isPointInStrokeInternal(path.path(), x, y);
1192 }
1193
1194 bool CanvasRenderingContext2DBase::isPointInPathInternal(const Path& path, float x, float y, CanvasFillRule windingRule)
1195 {
1196     auto* c = drawingContext();
1197     if (!c)
1198         return false;
1199     if (!state().hasInvertibleTransform)
1200         return false;
1201
1202     auto transformedPoint = state().transform.inverse().valueOr(AffineTransform()).mapPoint(FloatPoint(x, y));
1203
1204     if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
1205         return false;
1206
1207     return path.contains(transformedPoint, toWindRule(windingRule));
1208 }
1209
1210 bool CanvasRenderingContext2DBase::isPointInStrokeInternal(const Path& path, float x, float y)
1211 {
1212     auto* c = drawingContext();
1213     if (!c)
1214         return false;
1215     if (!state().hasInvertibleTransform)
1216         return false;
1217
1218     auto transformedPoint = state().transform.inverse().valueOr(AffineTransform()).mapPoint(FloatPoint(x, y));
1219     if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
1220         return false;
1221
1222     CanvasStrokeStyleApplier applier(this);
1223     return path.strokeContains(&applier, transformedPoint);
1224 }
1225
1226 void CanvasRenderingContext2DBase::clearRect(float x, float y, float width, float height)
1227 {
1228     if (!validateRectForCanvas(x, y, width, height))
1229         return;
1230     auto* context = drawingContext();
1231     if (!context)
1232         return;
1233     if (!state().hasInvertibleTransform)
1234         return;
1235     FloatRect rect(x, y, width, height);
1236
1237     bool saved = false;
1238     if (shouldDrawShadows()) {
1239         context->save();
1240         saved = true;
1241         context->setLegacyShadow(FloatSize(), 0, Color::transparent);
1242     }
1243     if (state().globalAlpha != 1) {
1244         if (!saved) {
1245             context->save();
1246             saved = true;
1247         }
1248         context->setAlpha(1);
1249     }
1250     if (state().globalComposite != CompositeSourceOver) {
1251         if (!saved) {
1252             context->save();
1253             saved = true;
1254         }
1255         context->setCompositeOperation(CompositeSourceOver);
1256     }
1257     context->clearRect(rect);
1258     if (saved)
1259         context->restore();
1260     didDraw(rect);
1261 }
1262
1263 void CanvasRenderingContext2DBase::fillRect(float x, float y, float width, float height)
1264 {
1265     if (!validateRectForCanvas(x, y, width, height))
1266         return;
1267
1268     auto* c = drawingContext();
1269     if (!c)
1270         return;
1271     if (!state().hasInvertibleTransform)
1272         return;
1273
1274     // from the HTML5 Canvas spec:
1275     // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
1276     // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
1277     auto gradient = c->fillGradient();
1278     if (gradient && gradient->isZeroSize())
1279         return;
1280
1281     FloatRect rect(x, y, width, height);
1282
1283     if (rectContainsCanvas(rect)) {
1284         c->fillRect(rect);
1285         didDrawEntireCanvas();
1286     } else if (isFullCanvasCompositeMode(state().globalComposite)) {
1287         beginCompositeLayer();
1288         c->fillRect(rect);
1289         endCompositeLayer();
1290         didDrawEntireCanvas();
1291     } else if (state().globalComposite == CompositeCopy) {
1292         clearCanvas();
1293         c->fillRect(rect);
1294         didDrawEntireCanvas();
1295     } else {
1296         c->fillRect(rect);
1297         didDraw(rect);
1298     }
1299 }
1300
1301 void CanvasRenderingContext2DBase::strokeRect(float x, float y, float width, float height)
1302 {
1303     if (!validateRectForCanvas(x, y, width, height))
1304         return;
1305
1306     auto* c = drawingContext();
1307     if (!c)
1308         return;
1309     if (!state().hasInvertibleTransform)
1310         return;
1311     if (!(state().lineWidth >= 0))
1312         return;
1313
1314     // If gradient size is zero, then paint nothing.
1315     auto gradient = c->strokeGradient();
1316     if (gradient && gradient->isZeroSize())
1317         return;
1318
1319     FloatRect rect(x, y, width, height);
1320     if (isFullCanvasCompositeMode(state().globalComposite)) {
1321         beginCompositeLayer();
1322         c->strokeRect(rect, state().lineWidth);
1323         endCompositeLayer();
1324         didDrawEntireCanvas();
1325     } else if (state().globalComposite == CompositeCopy) {
1326         clearCanvas();
1327         c->strokeRect(rect, state().lineWidth);
1328         didDrawEntireCanvas();
1329     } else {
1330         FloatRect boundingRect = rect;
1331         boundingRect.inflate(state().lineWidth / 2);
1332         c->strokeRect(rect, state().lineWidth);
1333         didDraw(boundingRect);
1334     }
1335 }
1336
1337 void CanvasRenderingContext2DBase::setShadow(float width, float height, float blur, const String& colorString, Optional<float> alpha)
1338 {
1339     Color color = Color::transparent;
1340     if (!colorString.isNull()) {
1341         auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
1342         color = parseColorOrCurrentColor(colorString, &canvas);
1343         if (!color.isValid())
1344             return;
1345     }
1346     // FIXME: Should not use RGBA32 here.
1347     setShadow(FloatSize(width, height), blur, colorWithOverrideAlpha(color.rgb(), alpha));
1348 }
1349
1350 void CanvasRenderingContext2DBase::setShadow(float width, float height, float blur, float grayLevel, float alpha)
1351 {
1352     setShadow(FloatSize(width, height), blur, Color(grayLevel, grayLevel, grayLevel, alpha));
1353 }
1354
1355 void CanvasRenderingContext2DBase::setShadow(float width, float height, float blur, float r, float g, float b, float a)
1356 {
1357     setShadow(FloatSize(width, height), blur, Color(r, g, b, a));
1358 }
1359
1360 void CanvasRenderingContext2DBase::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
1361 {
1362     setShadow(FloatSize(width, height), blur, Color(c, m, y, k, a));
1363 }
1364
1365 void CanvasRenderingContext2DBase::clearShadow()
1366 {
1367     setShadow(FloatSize(), 0, Color::transparent);
1368 }
1369
1370 void CanvasRenderingContext2DBase::setShadow(const FloatSize& offset, float blur, const Color& color)
1371 {
1372     if (state().shadowOffset == offset && state().shadowBlur == blur && state().shadowColor == color)
1373         return;
1374     bool wasDrawingShadows = shouldDrawShadows();
1375     realizeSaves();
1376     modifiableState().shadowOffset = offset;
1377     modifiableState().shadowBlur = blur;
1378     modifiableState().shadowColor = color;
1379     if (!wasDrawingShadows && !shouldDrawShadows())
1380         return;
1381     applyShadow();
1382 }
1383
1384 void CanvasRenderingContext2DBase::applyShadow()
1385 {
1386     auto* c = drawingContext();
1387     if (!c)
1388         return;
1389
1390     if (shouldDrawShadows()) {
1391         float width = state().shadowOffset.width();
1392         float height = state().shadowOffset.height();
1393         c->setLegacyShadow(FloatSize(width, -height), state().shadowBlur, state().shadowColor);
1394     } else
1395         c->setLegacyShadow(FloatSize(), 0, Color::transparent);
1396 }
1397
1398 bool CanvasRenderingContext2DBase::shouldDrawShadows() const
1399 {
1400     return state().shadowColor.isVisible() && (state().shadowBlur || !state().shadowOffset.isZero());
1401 }
1402
1403 enum class ImageSizeType { AfterDevicePixelRatio, BeforeDevicePixelRatio };
1404 static LayoutSize size(HTMLImageElement& element, ImageSizeType sizeType = ImageSizeType::BeforeDevicePixelRatio)
1405 {
1406     LayoutSize size;
1407     if (auto* cachedImage = element.cachedImage()) {
1408         size = cachedImage->imageSizeForRenderer(element.renderer(), 1.0f); // FIXME: Not sure about this.
1409         if (sizeType == ImageSizeType::AfterDevicePixelRatio && is<RenderImage>(element.renderer()) && cachedImage->image() && !cachedImage->image()->hasRelativeWidth())
1410             size.scale(downcast<RenderImage>(*element.renderer()).imageDevicePixelRatio());
1411     }
1412     return size;
1413 }
1414
1415 static inline FloatSize size(HTMLCanvasElement& canvasElement)
1416 {
1417     return canvasElement.size();
1418 }
1419
1420 static inline FloatSize size(ImageBitmap& imageBitmap)
1421 {
1422     return FloatSize { static_cast<float>(imageBitmap.width()), static_cast<float>(imageBitmap.height()) };
1423 }
1424
1425 #if ENABLE(VIDEO)
1426
1427 static inline FloatSize size(HTMLVideoElement& video)
1428 {
1429     auto player = video.player();
1430     if (!player)
1431         return { };
1432     return player->naturalSize();
1433 }
1434
1435 #endif
1436
1437 #if ENABLE(CSS_TYPED_OM)
1438 static inline FloatSize size(TypedOMCSSImageValue& image)
1439 {
1440     auto* cachedImage = image.image();
1441     if (!cachedImage)
1442         return FloatSize();
1443
1444     return cachedImage->imageSizeForRenderer(nullptr, 1.0f);
1445 }
1446 #endif
1447
1448 static inline FloatRect normalizeRect(const FloatRect& rect)
1449 {
1450     return FloatRect(std::min(rect.x(), rect.maxX()),
1451         std::min(rect.y(), rect.maxY()),
1452         std::max(rect.width(), -rect.width()),
1453         std::max(rect.height(), -rect.height()));
1454 }
1455
1456 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(CanvasImageSource&& image, float dx, float dy)
1457 {
1458     return WTF::switchOn(image,
1459         [&] (RefPtr<HTMLImageElement>& imageElement) -> ExceptionOr<void> {
1460             LayoutSize destRectSize = size(*imageElement, ImageSizeType::AfterDevicePixelRatio);
1461             LayoutSize sourceRectSize = size(*imageElement, ImageSizeType::BeforeDevicePixelRatio);
1462             return this->drawImage(*imageElement, FloatRect { 0, 0, sourceRectSize.width(), sourceRectSize.height() }, FloatRect { dx, dy, destRectSize.width(), destRectSize.height() });
1463         },
1464         [&] (auto& element) -> ExceptionOr<void> {
1465             FloatSize elementSize = size(*element);
1466             return this->drawImage(*element, FloatRect { 0, 0, elementSize.width(), elementSize.height() }, FloatRect { dx, dy, elementSize.width(), elementSize.height() });
1467         }
1468     );
1469 }
1470
1471 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(CanvasImageSource&& image, float dx, float dy, float dw, float dh)
1472 {
1473     return WTF::switchOn(image,
1474         [&] (auto& element) -> ExceptionOr<void> {
1475             FloatSize elementSize = size(*element);
1476             return this->drawImage(*element, FloatRect { 0, 0, elementSize.width(), elementSize.height() }, FloatRect { dx, dy, dw, dh });
1477         }
1478     );
1479 }
1480
1481 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(CanvasImageSource&& image, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh)
1482 {
1483     return WTF::switchOn(image,
1484         [&] (auto& element) -> ExceptionOr<void> {
1485             return this->drawImage(*element, FloatRect { sx, sy, sw, sh }, FloatRect { dx, dy, dw, dh });
1486         }
1487     );
1488 }
1489
1490 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(HTMLImageElement& imageElement, const FloatRect& srcRect, const FloatRect& dstRect)
1491 {
1492     return drawImage(imageElement, srcRect, dstRect, state().globalComposite, state().globalBlend);
1493 }
1494
1495 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(HTMLImageElement& imageElement, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator& op, const BlendMode& blendMode)
1496 {
1497     if (!imageElement.complete())
1498         return { };
1499     FloatRect imageRect = FloatRect(FloatPoint(), size(imageElement, ImageSizeType::BeforeDevicePixelRatio));
1500
1501     auto result = drawImage(imageElement.document(), imageElement.cachedImage(), imageElement.renderer(), imageRect, srcRect, dstRect, op, blendMode);
1502
1503     if (!result.hasException())
1504         checkOrigin(&imageElement);
1505     return result;
1506 }
1507
1508 #if ENABLE(CSS_TYPED_OM)
1509 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(TypedOMCSSImageValue& image, const FloatRect& srcRect, const FloatRect& dstRect)
1510 {
1511     auto* cachedImage = image.image();
1512     if (!cachedImage || !image.document())
1513         return { };
1514     FloatRect imageRect = FloatRect(FloatPoint(), size(image));
1515
1516     auto result = drawImage(*image.document(), cachedImage, nullptr, imageRect, srcRect, dstRect, state().globalComposite, state().globalBlend);
1517
1518     if (!result.hasException())
1519         checkOrigin(image);
1520     return result;
1521 }
1522 #endif
1523
1524 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(Document& document, CachedImage* cachedImage, const RenderObject* renderer, const FloatRect& imageRect, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator& op, const BlendMode& blendMode)
1525 {
1526     if (!std::isfinite(dstRect.x()) || !std::isfinite(dstRect.y()) || !std::isfinite(dstRect.width()) || !std::isfinite(dstRect.height())
1527         || !std::isfinite(srcRect.x()) || !std::isfinite(srcRect.y()) || !std::isfinite(srcRect.width()) || !std::isfinite(srcRect.height()))
1528         return { };
1529
1530     if (!dstRect.width() || !dstRect.height())
1531         return { };
1532
1533     FloatRect normalizedSrcRect = normalizeRect(srcRect);
1534     FloatRect normalizedDstRect = normalizeRect(dstRect);
1535
1536     if (!srcRect.width() || !srcRect.height())
1537         return Exception { IndexSizeError };
1538
1539     // When the source rectangle is outside the source image, the source rectangle must be clipped
1540     // to the source image and the destination rectangle must be clipped in the same proportion.
1541     FloatRect originalNormalizedSrcRect = normalizedSrcRect;
1542     normalizedSrcRect.intersect(imageRect);
1543     if (normalizedSrcRect.isEmpty())
1544         return { };
1545
1546     if (normalizedSrcRect != originalNormalizedSrcRect) {
1547         normalizedDstRect.setWidth(normalizedDstRect.width() * normalizedSrcRect.width() / originalNormalizedSrcRect.width());
1548         normalizedDstRect.setHeight(normalizedDstRect.height() * normalizedSrcRect.height() / originalNormalizedSrcRect.height());
1549         if (normalizedDstRect.isEmpty())
1550             return { };
1551     }
1552
1553     GraphicsContext* c = drawingContext();
1554     if (!c)
1555         return { };
1556     if (!state().hasInvertibleTransform)
1557         return { };
1558
1559     if (!cachedImage)
1560         return { };
1561
1562     RefPtr<Image> image = cachedImage->imageForRenderer(renderer);
1563     if (!image)
1564         return { };
1565
1566     ImageObserver* observer = image->imageObserver();
1567
1568     if (image->isSVGImage()) {
1569         image->setImageObserver(nullptr);
1570         image->setContainerSize(imageRect.size());
1571     }
1572
1573     if (image->isBitmapImage())
1574         downcast<BitmapImage>(*image).updateFromSettings(document.settings());
1575
1576     if (rectContainsCanvas(normalizedDstRect)) {
1577         c->drawImage(*image, normalizedDstRect, normalizedSrcRect, ImagePaintingOptions(op, blendMode));
1578         didDrawEntireCanvas();
1579     } else if (isFullCanvasCompositeMode(op)) {
1580         fullCanvasCompositedDrawImage(*image, normalizedDstRect, normalizedSrcRect, op);
1581         didDrawEntireCanvas();
1582     } else if (op == CompositeCopy) {
1583         clearCanvas();
1584         c->drawImage(*image, normalizedDstRect, normalizedSrcRect, ImagePaintingOptions(op, blendMode));
1585         didDrawEntireCanvas();
1586     } else {
1587         c->drawImage(*image, normalizedDstRect, normalizedSrcRect, ImagePaintingOptions(op, blendMode));
1588         didDraw(normalizedDstRect);
1589     }
1590     
1591     if (image->isSVGImage())
1592         image->setImageObserver(observer);
1593
1594     return { };
1595 }
1596
1597 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(HTMLCanvasElement& sourceCanvas, const FloatRect& srcRect, const FloatRect& dstRect)
1598 {
1599     FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas.size());
1600
1601     if (!srcCanvasRect.width() || !srcCanvasRect.height())
1602         return Exception { InvalidStateError };
1603
1604     if (!srcRect.width() || !srcRect.height())
1605         return Exception { IndexSizeError };
1606
1607     if (!srcCanvasRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
1608         return { };
1609
1610     GraphicsContext* c = drawingContext();
1611     if (!c)
1612         return { };
1613     if (!state().hasInvertibleTransform)
1614         return { };
1615
1616     // FIXME: Do this through platform-independent GraphicsContext API.
1617     ImageBuffer* buffer = sourceCanvas.buffer();
1618     if (!buffer)
1619         return { };
1620
1621     checkOrigin(&sourceCanvas);
1622
1623 #if ENABLE(ACCELERATED_2D_CANVAS)
1624     // If we're drawing from one accelerated canvas 2d to another, avoid calling sourceCanvas.makeRenderingResultsAvailable()
1625     // as that will do a readback to software.
1626     RefPtr<CanvasRenderingContext> sourceContext = sourceCanvas.renderingContext();
1627     // FIXME: Implement an accelerated path for drawing from a WebGL canvas to a 2d canvas when possible.
1628     if (!isAccelerated() || !sourceContext || !sourceContext->isAccelerated() || !sourceContext->is2d())
1629         sourceCanvas.makeRenderingResultsAvailable();
1630 #else
1631     sourceCanvas.makeRenderingResultsAvailable();
1632 #endif
1633
1634     if (rectContainsCanvas(dstRect)) {
1635         c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
1636         didDrawEntireCanvas();
1637     } else if (isFullCanvasCompositeMode(state().globalComposite)) {
1638         fullCanvasCompositedDrawImage(*buffer, dstRect, srcRect, state().globalComposite);
1639         didDrawEntireCanvas();
1640     } else if (state().globalComposite == CompositeCopy) {
1641         if (&sourceCanvas == &canvasBase()) {
1642             if (auto copy = buffer->copyRectToBuffer(srcRect, ColorSpaceSRGB, *c)) {
1643                 clearCanvas();
1644                 c->drawImageBuffer(*copy, dstRect, { { }, srcRect.size() }, ImagePaintingOptions(state().globalComposite, state().globalBlend));
1645             }
1646         } else {
1647             clearCanvas();
1648             c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
1649         }
1650         didDrawEntireCanvas();
1651     } else {
1652         c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
1653         didDraw(dstRect);
1654     }
1655
1656     return { };
1657 }
1658
1659 #if ENABLE(VIDEO)
1660
1661 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(HTMLVideoElement& video, const FloatRect& srcRect, const FloatRect& dstRect)
1662 {
1663     if (video.readyState() == HTMLMediaElement::HAVE_NOTHING || video.readyState() == HTMLMediaElement::HAVE_METADATA)
1664         return { };
1665
1666     FloatRect videoRect = FloatRect(FloatPoint(), size(video));
1667     if (!srcRect.width() || !srcRect.height())
1668         return Exception { IndexSizeError };
1669
1670     if (!videoRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
1671         return { };
1672
1673     GraphicsContext* c = drawingContext();
1674     if (!c)
1675         return { };
1676     if (!state().hasInvertibleTransform)
1677         return { };
1678
1679     checkOrigin(&video);
1680
1681 #if USE(CG) || (ENABLE(ACCELERATED_2D_CANVAS) && USE(GSTREAMER_GL) && USE(CAIRO))
1682     if (NativeImagePtr image = video.nativeImageForCurrentTime()) {
1683         c->drawNativeImage(image, FloatSize(video.videoWidth(), video.videoHeight()), dstRect, srcRect);
1684         if (rectContainsCanvas(dstRect))
1685             didDrawEntireCanvas();
1686         else
1687             didDraw(dstRect);
1688
1689         return { };
1690     }
1691 #endif
1692
1693     GraphicsContextStateSaver stateSaver(*c);
1694     c->clip(dstRect);
1695     c->translate(dstRect.location());
1696     c->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height()));
1697     c->translate(-srcRect.location());
1698     video.paintCurrentFrameInContext(*c, FloatRect(FloatPoint(), size(video)));
1699     stateSaver.restore();
1700     didDraw(dstRect);
1701
1702     return { };
1703 }
1704
1705 #endif
1706
1707 ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(ImageBitmap& imageBitmap, const FloatRect& srcRect, const FloatRect& dstRect)
1708 {
1709     if (!imageBitmap.width() || !imageBitmap.height())
1710         return Exception { InvalidStateError };
1711
1712     if (!srcRect.width() || !srcRect.height())
1713         return Exception { IndexSizeError };
1714
1715     FloatRect srcBitmapRect = FloatRect(FloatPoint(), FloatSize(imageBitmap.width(), imageBitmap.height()));
1716
1717     if (!srcBitmapRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
1718         return { };
1719
1720     GraphicsContext* c = drawingContext();
1721     if (!c)
1722         return { };
1723     if (!state().hasInvertibleTransform)
1724         return { };
1725
1726     ImageBuffer* buffer = imageBitmap.buffer();
1727     if (!buffer)
1728         return { };
1729
1730     checkOrigin(&imageBitmap);
1731
1732     if (rectContainsCanvas(dstRect)) {
1733         c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
1734         didDrawEntireCanvas();
1735     } else if (isFullCanvasCompositeMode(state().globalComposite)) {
1736         fullCanvasCompositedDrawImage(*buffer, dstRect, srcRect, state().globalComposite);
1737         didDrawEntireCanvas();
1738     } else if (state().globalComposite == CompositeCopy) {
1739         clearCanvas();
1740         c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
1741         didDrawEntireCanvas();
1742     } else {
1743         c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
1744         didDraw(dstRect);
1745     }
1746
1747     return { };
1748 }
1749
1750 void CanvasRenderingContext2DBase::drawImageFromRect(HTMLImageElement& imageElement, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, const String& compositeOperation)
1751 {
1752     CompositeOperator op;
1753     auto blendOp = BlendMode::Normal;
1754     if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blendOp != BlendMode::Normal)
1755         op = CompositeSourceOver;
1756     drawImage(imageElement, FloatRect { sx, sy, sw, sh }, FloatRect { dx, dy, dw, dh }, op, BlendMode::Normal);
1757 }
1758
1759 void CanvasRenderingContext2DBase::clearCanvas()
1760 {
1761     auto* c = drawingContext();
1762     if (!c)
1763         return;
1764
1765     c->save();
1766     c->setCTM(canvasBase().baseTransform());
1767     c->clearRect(FloatRect(0, 0, canvasBase().width(), canvasBase().height()));
1768     c->restore();
1769 }
1770
1771 Path CanvasRenderingContext2DBase::transformAreaToDevice(const Path& path) const
1772 {
1773     Path transformed(path);
1774     transformed.transform(state().transform);
1775     transformed.transform(canvasBase().baseTransform());
1776     return transformed;
1777 }
1778
1779 Path CanvasRenderingContext2DBase::transformAreaToDevice(const FloatRect& rect) const
1780 {
1781     Path path;
1782     path.addRect(rect);
1783     return transformAreaToDevice(path);
1784 }
1785
1786 bool CanvasRenderingContext2DBase::rectContainsCanvas(const FloatRect& rect) const
1787 {
1788     FloatQuad quad(rect);
1789     FloatQuad canvasQuad(FloatRect(0, 0, canvasBase().width(), canvasBase().height()));
1790     return state().transform.mapQuad(quad).containsQuad(canvasQuad);
1791 }
1792
1793 template<class T> IntRect CanvasRenderingContext2DBase::calculateCompositingBufferRect(const T& area, IntSize* croppedOffset)
1794 {
1795     IntRect canvasRect(0, 0, canvasBase().width(), canvasBase().height());
1796     canvasRect = canvasBase().baseTransform().mapRect(canvasRect);
1797     Path path = transformAreaToDevice(area);
1798     IntRect bufferRect = enclosingIntRect(path.fastBoundingRect());
1799     IntPoint originalLocation = bufferRect.location();
1800     bufferRect.intersect(canvasRect);
1801     if (croppedOffset)
1802         *croppedOffset = originalLocation - bufferRect.location();
1803     return bufferRect;
1804 }
1805
1806 std::unique_ptr<ImageBuffer> CanvasRenderingContext2DBase::createCompositingBuffer(const IntRect& bufferRect)
1807 {
1808     return ImageBuffer::create(bufferRect.size(), isAccelerated() ? Accelerated : Unaccelerated);
1809 }
1810
1811 void CanvasRenderingContext2DBase::compositeBuffer(ImageBuffer& buffer, const IntRect& bufferRect, CompositeOperator op)
1812 {
1813     IntRect canvasRect(0, 0, canvasBase().width(), canvasBase().height());
1814     canvasRect = canvasBase().baseTransform().mapRect(canvasRect);
1815
1816     auto* c = drawingContext();
1817     if (!c)
1818         return;
1819
1820     c->save();
1821     c->setCTM(AffineTransform());
1822     c->setCompositeOperation(op);
1823
1824     c->save();
1825     c->clipOut(bufferRect);
1826     c->clearRect(canvasRect);
1827     c->restore();
1828     c->drawImageBuffer(buffer, bufferRect.location(), state().globalComposite);
1829     c->restore();
1830 }
1831
1832 static void drawImageToContext(Image& image, GraphicsContext& context, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1833 {
1834     context.drawImage(image, dest, src, op);
1835 }
1836
1837 static void drawImageToContext(ImageBuffer& imageBuffer, GraphicsContext& context, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1838 {
1839     context.drawImageBuffer(imageBuffer, dest, src, op);
1840 }
1841
1842 template<class T> void CanvasRenderingContext2DBase::fullCanvasCompositedDrawImage(T& image, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
1843 {
1844     ASSERT(isFullCanvasCompositeMode(op));
1845
1846     IntSize croppedOffset;
1847     auto bufferRect = calculateCompositingBufferRect(dest, &croppedOffset);
1848     if (bufferRect.isEmpty()) {
1849         clearCanvas();
1850         return;
1851     }
1852
1853     auto buffer = createCompositingBuffer(bufferRect);
1854     if (!buffer)
1855         return;
1856
1857     auto* c = drawingContext();
1858     if (!c)
1859         return;
1860
1861     FloatRect adjustedDest = dest;
1862     adjustedDest.setLocation(FloatPoint(0, 0));
1863     AffineTransform effectiveTransform = c->getCTM();
1864     IntRect transformedAdjustedRect = enclosingIntRect(effectiveTransform.mapRect(adjustedDest));
1865     buffer->context().translate(-transformedAdjustedRect.location());
1866     buffer->context().translate(croppedOffset);
1867     buffer->context().concatCTM(effectiveTransform);
1868     drawImageToContext(image, buffer->context(), adjustedDest, src, CompositeSourceOver);
1869
1870     compositeBuffer(*buffer, bufferRect, op);
1871 }
1872
1873 static CanvasRenderingContext2DBase::Style toStyle(const CanvasStyle& style)
1874 {
1875     if (auto gradient = style.canvasGradient())
1876         return gradient;
1877     if (auto pattern = style.canvasPattern())
1878         return pattern;
1879     return style.color();
1880 }
1881
1882 CanvasRenderingContext2DBase::Style CanvasRenderingContext2DBase::strokeStyle() const
1883 {
1884     return toStyle(state().strokeStyle);
1885 }
1886
1887 void CanvasRenderingContext2DBase::setStrokeStyle(CanvasRenderingContext2DBase::Style&& style)
1888 {
1889     WTF::switchOn(style,
1890         [this] (const String& string) { this->setStrokeColor(string); },
1891         [this] (const RefPtr<CanvasGradient>& gradient) { this->setStrokeStyle(CanvasStyle(*gradient)); },
1892         [this] (const RefPtr<CanvasPattern>& pattern) { this->setStrokeStyle(CanvasStyle(*pattern)); }
1893     );
1894 }
1895
1896 CanvasRenderingContext2DBase::Style CanvasRenderingContext2DBase::fillStyle() const
1897 {
1898     return toStyle(state().fillStyle);
1899 }
1900
1901 void CanvasRenderingContext2DBase::setFillStyle(CanvasRenderingContext2DBase::Style&& style)
1902 {
1903     WTF::switchOn(style,
1904         [this] (const String& string) { this->setFillColor(string); },
1905         [this] (const RefPtr<CanvasGradient>& gradient) { this->setFillStyle(CanvasStyle(*gradient)); },
1906         [this] (const RefPtr<CanvasPattern>& pattern) { this->setFillStyle(CanvasStyle(*pattern)); }
1907     );
1908 }
1909
1910 ExceptionOr<Ref<CanvasGradient>> CanvasRenderingContext2DBase::createLinearGradient(float x0, float y0, float x1, float y1)
1911 {
1912     if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(x1) || !std::isfinite(y1))
1913         return Exception { NotSupportedError };
1914
1915     return CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
1916 }
1917
1918 ExceptionOr<Ref<CanvasGradient>> CanvasRenderingContext2DBase::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1)
1919 {
1920     if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(r0) || !std::isfinite(x1) || !std::isfinite(y1) || !std::isfinite(r1))
1921         return Exception { NotSupportedError };
1922
1923     if (r0 < 0 || r1 < 0)
1924         return Exception { IndexSizeError };
1925
1926     return CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
1927 }
1928
1929 ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(CanvasImageSource&& image, const String& repetition)
1930 {
1931     bool repeatX, repeatY;
1932     if (!CanvasPattern::parseRepetitionType(repetition, repeatX, repeatY))
1933         return Exception { SyntaxError };
1934
1935     return WTF::switchOn(image,
1936         [&] (auto& element) -> ExceptionOr<RefPtr<CanvasPattern>> { return this->createPattern(*element, repeatX, repeatY); }
1937     );
1938 }
1939
1940 ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(HTMLImageElement& imageElement, bool repeatX, bool repeatY)
1941 {
1942     auto* cachedImage = imageElement.cachedImage();
1943
1944     // If the image loading hasn't started or the image is not complete, it is not fully decodable.
1945     if (!cachedImage || !imageElement.complete())
1946         return nullptr;
1947
1948     if (cachedImage->status() == CachedResource::LoadError)
1949         return Exception { InvalidStateError };
1950
1951     bool originClean = cachedImage->isOriginClean(canvasBase().securityOrigin());
1952
1953     // FIXME: SVG images with animations can switch between clean and dirty (leaking cross-origin
1954     // data). We should either:
1955     //   1) Take a fixed snapshot of an SVG image when creating a pattern and determine then whether
1956     //      the origin is clean.
1957     //   2) Dynamically verify the origin checks at draw time, and dirty the canvas accordingly.
1958     // To be on the safe side, taint the origin for all patterns containing SVG images for now.
1959     if (cachedImage->image()->isSVGImage())
1960         originClean = false;
1961
1962     return RefPtr<CanvasPattern> { CanvasPattern::create(*cachedImage->imageForRenderer(imageElement.renderer()), repeatX, repeatY, originClean) };
1963 }
1964
1965 ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(CanvasBase& canvas, bool repeatX, bool repeatY)
1966 {
1967     if (!canvas.width() || !canvas.height())
1968         return Exception { InvalidStateError };
1969     auto* copiedImage = canvas.copiedImage();
1970
1971     if (!copiedImage)
1972         return Exception { InvalidStateError };
1973
1974     return RefPtr<CanvasPattern> { CanvasPattern::create(*copiedImage, repeatX, repeatY, canvas.originClean()) };
1975 }
1976     
1977 #if ENABLE(VIDEO)
1978
1979 ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(HTMLVideoElement& videoElement, bool repeatX, bool repeatY)
1980 {
1981     if (videoElement.readyState() < HTMLMediaElement::HAVE_CURRENT_DATA)
1982         return nullptr;
1983     
1984     checkOrigin(&videoElement);
1985     bool originClean = canvasBase().originClean();
1986
1987 #if USE(CG) || (ENABLE(ACCELERATED_2D_CANVAS) && USE(GSTREAMER_GL) && USE(CAIRO))
1988     if (auto nativeImage = videoElement.nativeImageForCurrentTime())
1989         return RefPtr<CanvasPattern> { CanvasPattern::create(BitmapImage::create(WTFMove(nativeImage)), repeatX, repeatY, originClean) };
1990 #endif
1991
1992     auto imageBuffer = ImageBuffer::create(size(videoElement), drawingContext() ? drawingContext()->renderingMode() : Accelerated);
1993     if (!imageBuffer)
1994         return nullptr;
1995
1996     videoElement.paintCurrentFrameInContext(imageBuffer->context(), FloatRect(FloatPoint(), size(videoElement)));
1997     
1998     return RefPtr<CanvasPattern> { CanvasPattern::create(ImageBuffer::sinkIntoImage(WTFMove(imageBuffer), PreserveResolution::Yes).releaseNonNull(), repeatX, repeatY, originClean) };
1999 }
2000
2001 #endif
2002
2003 ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(ImageBitmap&, bool, bool)
2004 {
2005     // FIXME: Implement.
2006     return Exception { TypeError };
2007 }
2008
2009 #if ENABLE(CSS_TYPED_OM)
2010 ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(TypedOMCSSImageValue&, bool, bool)
2011 {
2012     // FIXME: Implement.
2013     return Exception { TypeError };
2014 }
2015 #endif
2016
2017 void CanvasRenderingContext2DBase::didDrawEntireCanvas()
2018 {
2019     didDraw(FloatRect(FloatPoint::zero(), canvasBase().size()), CanvasDidDrawApplyClip);
2020 }
2021
2022 void CanvasRenderingContext2DBase::didDraw(const FloatRect& r, unsigned options)
2023 {
2024     auto* c = drawingContext();
2025     if (!c)
2026         return;
2027     if (!state().hasInvertibleTransform)
2028         return;
2029
2030 #if ENABLE(ACCELERATED_2D_CANVAS)
2031     // If we are drawing to hardware and we have a composited layer, just call contentChanged().
2032     if (isAccelerated()) {
2033         auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
2034         RenderBox* renderBox = canvas.renderBox();
2035         if (renderBox && renderBox->hasAcceleratedCompositing()) {
2036             renderBox->contentChanged(CanvasPixelsChanged);
2037             canvas.clearCopiedImage();
2038             canvas.notifyObserversCanvasChanged(r);
2039             return;
2040         }
2041     }
2042 #endif
2043
2044     FloatRect dirtyRect = r;
2045     if (options & CanvasDidDrawApplyTransform) {
2046         AffineTransform ctm = state().transform;
2047         dirtyRect = ctm.mapRect(r);
2048     }
2049
2050     if (options & CanvasDidDrawApplyShadow && state().shadowColor.isVisible()) {
2051         // The shadow gets applied after transformation
2052         FloatRect shadowRect(dirtyRect);
2053         shadowRect.move(state().shadowOffset);
2054         shadowRect.inflate(state().shadowBlur);
2055         dirtyRect.unite(shadowRect);
2056     }
2057
2058     if (options & CanvasDidDrawApplyClip) {
2059         // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
2060         // back out of the GraphicsContext, so to take clip into account for incremental painting,
2061         // we'd have to keep the clip path around.
2062     }
2063
2064     canvasBase().didDraw(dirtyRect);
2065 }
2066
2067 void CanvasRenderingContext2DBase::setTracksDisplayListReplay(bool tracksDisplayListReplay)
2068 {
2069     if (tracksDisplayListReplay == m_tracksDisplayListReplay)
2070         return;
2071
2072     m_tracksDisplayListReplay = tracksDisplayListReplay;
2073     if (!m_tracksDisplayListReplay)
2074         contextDisplayListMap().remove(this);
2075 }
2076
2077 String CanvasRenderingContext2DBase::displayListAsText(DisplayList::AsTextFlags flags) const
2078 {
2079     if (!m_recordingContext)
2080         return { };
2081     return m_recordingContext->displayList.asText(flags);
2082 }
2083
2084 String CanvasRenderingContext2DBase::replayDisplayListAsText(DisplayList::AsTextFlags flags) const
2085 {
2086     auto* displayList = contextDisplayListMap().get(this);
2087     if (!displayList)
2088         return { };
2089     return displayList->asText(flags);
2090 }
2091
2092 const Vector<CanvasRenderingContext2DBase::State, 1>& CanvasRenderingContext2DBase::stateStack()
2093 {
2094     realizeSaves();
2095     return m_stateStack;
2096 }
2097
2098 void CanvasRenderingContext2DBase::paintRenderingResultsToCanvas()
2099 {
2100     if (UNLIKELY(m_usesDisplayListDrawing)) {
2101         if (!m_recordingContext)
2102             return;
2103
2104         FloatRect clip(FloatPoint::zero(), canvasBase().size());
2105         DisplayList::Replayer replayer(*canvasBase().drawingContext(), m_recordingContext->displayList);
2106
2107         if (UNLIKELY(m_tracksDisplayListReplay)) {
2108             auto replayList = replayer.replay(clip, m_tracksDisplayListReplay);
2109             contextDisplayListMap().add(this, WTFMove(replayList));
2110         } else
2111             replayer.replay(clip);
2112
2113         m_recordingContext->displayList.clear();
2114     }
2115 }
2116
2117 GraphicsContext* CanvasRenderingContext2DBase::drawingContext() const
2118 {
2119     if (UNLIKELY(m_usesDisplayListDrawing)) {
2120         if (!m_recordingContext)
2121             m_recordingContext = makeUnique<DisplayListDrawingContext>(GraphicsContextState(), FloatRect(FloatPoint::zero(), canvasBase().size()));
2122         return &m_recordingContext->context;
2123     }
2124
2125     return canvasBase().drawingContext();
2126 }
2127
2128 static RefPtr<ImageData> createEmptyImageData(const IntSize& size)
2129 {
2130     auto data = ImageData::create(size);
2131     if (data)
2132         data->data()->zeroFill();
2133     return data;
2134 }
2135
2136 RefPtr<ImageData> CanvasRenderingContext2DBase::createImageData(ImageData& imageData) const
2137 {
2138     return createEmptyImageData(imageData.size());
2139 }
2140
2141 ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2DBase::createImageData(float sw, float sh) const
2142 {
2143     if (!sw || !sh)
2144         return Exception { IndexSizeError };
2145
2146     FloatSize logicalSize(std::abs(sw), std::abs(sh));
2147     if (!logicalSize.isExpressibleAsIntSize())
2148         return nullptr;
2149
2150     IntSize size = expandedIntSize(logicalSize);
2151     if (size.width() < 1)
2152         size.setWidth(1);
2153     if (size.height() < 1)
2154         size.setHeight(1);
2155
2156     return createEmptyImageData(size);
2157 }
2158
2159 ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2DBase::getImageData(float sx, float sy, float sw, float sh) const
2160 {
2161     return getImageData(ImageBuffer::LogicalCoordinateSystem, sx, sy, sw, sh);
2162 }
2163
2164 ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2DBase::getImageData(ImageBuffer::CoordinateSystem coordinateSystem, float sx, float sy, float sw, float sh) const
2165 {
2166     if (!canvasBase().originClean()) {
2167         static NeverDestroyed<String> consoleMessage(MAKE_STATIC_STRING_IMPL("Unable to get image data from canvas because the canvas has been tainted by cross-origin data."));
2168         canvasBase().scriptExecutionContext()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, consoleMessage);
2169         return Exception { SecurityError };
2170     }
2171
2172     if (!sw || !sh)
2173         return Exception { IndexSizeError };
2174
2175     if (sw < 0) {
2176         sx += sw;
2177         sw = -sw;
2178     }    
2179     if (sh < 0) {
2180         sy += sh;
2181         sh = -sh;
2182     }
2183
2184     FloatRect logicalRect(sx, sy, sw, sh);
2185     if (logicalRect.width() < 1)
2186         logicalRect.setWidth(1);
2187     if (logicalRect.height() < 1)
2188         logicalRect.setHeight(1);
2189     if (!logicalRect.isExpressibleAsIntRect())
2190         return nullptr;
2191
2192     IntRect imageDataRect = enclosingIntRect(logicalRect);
2193     auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
2194
2195     ImageBuffer* buffer = canvas.buffer();
2196     if (!buffer)
2197         return createEmptyImageData(imageDataRect.size());
2198
2199     auto byteArray = buffer->getUnmultipliedImageData(imageDataRect, nullptr, coordinateSystem);
2200     if (!byteArray) {
2201         StringBuilder consoleMessage;
2202         consoleMessage.appendLiteral("Unable to get image data from canvas. Requested size was ");
2203         consoleMessage.appendNumber(imageDataRect.width());
2204         consoleMessage.appendLiteral(" x ");
2205         consoleMessage.appendNumber(imageDataRect.height());
2206
2207         canvasBase().scriptExecutionContext()->addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, consoleMessage.toString());
2208         return Exception { InvalidStateError };
2209     }
2210
2211     return ImageData::create(imageDataRect.size(), byteArray.releaseNonNull());
2212 }
2213
2214 void CanvasRenderingContext2DBase::putImageData(ImageData& data, float dx, float dy)
2215 {
2216     putImageData(data, dx, dy, 0, 0, data.width(), data.height());
2217 }
2218
2219 void CanvasRenderingContext2DBase::putImageData(ImageData& data, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight)
2220 {
2221     putImageData(data, ImageBuffer::LogicalCoordinateSystem, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2222 }
2223
2224 void CanvasRenderingContext2DBase::putImageData(ImageData& data, ImageBuffer::CoordinateSystem coordinateSystem, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight)
2225 {
2226     auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
2227
2228     ImageBuffer* buffer = canvas.buffer();
2229     if (!buffer)
2230         return;
2231
2232     if (!data.data())
2233         return;
2234
2235     if (dirtyWidth < 0) {
2236         dirtyX += dirtyWidth;
2237         dirtyWidth = -dirtyWidth;
2238     }
2239
2240     if (dirtyHeight < 0) {
2241         dirtyY += dirtyHeight;
2242         dirtyHeight = -dirtyHeight;
2243     }
2244
2245     FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2246     clipRect.intersect(IntRect(0, 0, data.width(), data.height()));
2247     IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
2248     IntRect destRect = enclosingIntRect(clipRect);
2249     destRect.move(destOffset);
2250     destRect.intersect(IntRect(IntPoint(), coordinateSystem == ImageBuffer::LogicalCoordinateSystem ? buffer->logicalSize() : buffer->internalSize()));
2251     if (destRect.isEmpty())
2252         return;
2253     IntRect sourceRect(destRect);
2254     sourceRect.move(-destOffset);
2255     sourceRect.intersect(IntRect(0, 0, data.width(), data.height()));
2256
2257     if (!sourceRect.isEmpty())
2258         buffer->putByteArray(*data.data(), AlphaPremultiplication::Unpremultiplied, IntSize(data.width(), data.height()), sourceRect, IntPoint(destOffset), coordinateSystem);
2259
2260     didDraw(destRect, CanvasDidDrawApplyNone); // ignore transform, shadow and clip
2261 }
2262
2263 void CanvasRenderingContext2DBase::inflateStrokeRect(FloatRect& rect) const
2264 {
2265     // Fast approximation of the stroke's bounding rect.
2266     // This yields a slightly oversized rect but is very fast
2267     // compared to Path::strokeBoundingRect().
2268     static const float root2 = sqrtf(2);
2269     float delta = state().lineWidth / 2;
2270     if (state().lineJoin == MiterJoin)
2271         delta *= state().miterLimit;
2272     else if (state().lineCap == SquareCap)
2273         delta *= root2;
2274     rect.inflate(delta);
2275 }
2276
2277 #if ENABLE(ACCELERATED_2D_CANVAS)
2278
2279 PlatformLayer* CanvasRenderingContext2DBase::platformLayer() const
2280 {
2281     auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
2282
2283     return canvas.buffer() ? canvas.buffer()->platformLayer() : nullptr;
2284 }
2285
2286 #endif
2287
2288 static inline InterpolationQuality smoothingToInterpolationQuality(ImageSmoothingQuality quality)
2289 {
2290     switch (quality) {
2291     case ImageSmoothingQuality::Low:
2292         return InterpolationLow;
2293     case ImageSmoothingQuality::Medium:
2294         return InterpolationMedium;
2295     case ImageSmoothingQuality::High:
2296         return InterpolationHigh;
2297     }
2298
2299     ASSERT_NOT_REACHED();
2300     return InterpolationLow;
2301 };
2302
2303 auto CanvasRenderingContext2DBase::imageSmoothingQuality() const -> ImageSmoothingQuality
2304 {
2305     return state().imageSmoothingQuality;
2306 }
2307
2308 void CanvasRenderingContext2DBase::setImageSmoothingQuality(ImageSmoothingQuality quality)
2309 {
2310     if (quality == state().imageSmoothingQuality)
2311         return;
2312
2313     realizeSaves();
2314     modifiableState().imageSmoothingQuality = quality;
2315
2316     if (!state().imageSmoothingEnabled)
2317         return;
2318
2319     if (auto* context = drawingContext())
2320         context->setImageInterpolationQuality(smoothingToInterpolationQuality(quality));
2321 }
2322
2323 bool CanvasRenderingContext2DBase::imageSmoothingEnabled() const
2324 {
2325     return state().imageSmoothingEnabled;
2326 }
2327
2328 void CanvasRenderingContext2DBase::setImageSmoothingEnabled(bool enabled)
2329 {
2330     if (enabled == state().imageSmoothingEnabled)
2331         return;
2332
2333     realizeSaves();
2334     modifiableState().imageSmoothingEnabled = enabled;
2335     auto* c = drawingContext();
2336     if (c)
2337         c->setImageInterpolationQuality(enabled ? smoothingToInterpolationQuality(state().imageSmoothingQuality) : InterpolationNone);
2338 }
2339
2340 void CanvasRenderingContext2DBase::setPath(Path2D& path)
2341 {
2342     m_path = path.path();
2343 }
2344
2345 Ref<Path2D> CanvasRenderingContext2DBase::getPath() const
2346 {
2347     return Path2D::create(m_path);
2348 }
2349
2350 } // namespace WebCore