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