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