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