<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[225816] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/225816">225816</a></dd>
<dt>Author</dt> <dd>dino@apple.com</dd>
<dt>Date</dt> <dd>2017-12-12 15:35:51 -0800 (Tue, 12 Dec 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add CanvasRenderingContext2DBase class and OffscreenCanvasRenderingContext2D
https://bugs.webkit.org/show_bug.cgi?id=180718
<rdar://problem/36004015>

Reviewed by Sam Weinig.

Add an OffscreenCanvasRenderingContext2D class, and in the process create a shared
base class for it and CanvasRenderingContext2D, called CanvasRenderingContext2DBase.
The base class has nearly all the functionality, with the exception of the text
and focus rendering APIs, which are only exposed on CanvasRenderingContext2D.

At the moment CanvasRenderingContext2DBase's implementation still expects the attached
canvas to be an HTMLCanvasElement, but that's ok since you can't yet create an
OffscreenCanvasRenderingContext2D. A subsequent patch will do the right thing.

No change in functionality at the moment, so covered by the existing tests.

* DerivedSources.make: Add the new IDL file.

* Sources.txt: Add all the new files to compile.
* WebCore.xcodeproj/project.pbxproj:

* bindings/js/JSCanvasRenderingContext2DCustom.cpp: Removed some unnecessary headers, and
added JSC:: where appropriate.
(WebCore::JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
(WebCore::JSCanvasRenderingContext2D::visitAdditionalChildren):

* bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp: Copied from Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp.
(WebCore::root): New root function that just returns the address of the OffscreenCanvas.
(WebCore::JSOffscreenCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
(WebCore::JSOffscreenCanvasRenderingContext2D::visitAdditionalChildren):

* bindings/js/JSWorkerNavigatorCustom.cpp: Add JSC:: to fix a compilation error.
(WebCore::JSWorkerNavigator::visitAdditionalChildren):

* bindings/js/WebCoreBuiltinNames.h: New IDL types.

* html/OffscreenCanvas.idl: Explicitly generates an IsReachable.

* html/canvas/CanvasRenderingContext.h:
(WebCore::CanvasRenderingContext::isOffscreen2d const): Helper for is<> trait.

* html/canvas/CanvasRenderingContext2D.cpp: Nearly everything has been moved to the Base class.
* html/canvas/CanvasRenderingContext2D.h:
* html/canvas/CanvasRenderingContext2DBase.cpp: Copied from Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp.
* html/canvas/CanvasRenderingContext2DBase.h: Copied from Source/WebCore/html/canvas/CanvasRenderingContext2D.h.

* html/canvas/OffscreenCanvasRenderingContext2D.cpp: Added. Basic implementation that
just uses the Base class.
(WebCore::OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D):
* html/canvas/OffscreenCanvasRenderingContext2D.h: Added.
* html/canvas/OffscreenCanvasRenderingContext2D.idl: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreCMakeListstxt">trunk/Source/WebCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreDerivedSourcesmake">trunk/Source/WebCore/DerivedSources.make</a></li>
<li><a href="#trunkSourceWebCoreSourcestxt">trunk/Source/WebCore/Sources.txt</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCorebindingsjsJSCanvasRenderingContext2DCustomcpp">trunk/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp</a></li>
<li><a href="#trunkSourceWebCorebindingsjsJSWorkerNavigatorCustomcpp">trunk/Source/WebCore/bindings/js/JSWorkerNavigatorCustom.cpp</a></li>
<li><a href="#trunkSourceWebCorebindingsjsWebCoreBuiltinNamesh">trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h</a></li>
<li><a href="#trunkSourceWebCorehtmlOffscreenCanvasidl">trunk/Source/WebCore/html/OffscreenCanvas.idl</a></li>
<li><a href="#trunkSourceWebCorehtmlcanvasCanvasRenderingContexth">trunk/Source/WebCore/html/canvas/CanvasRenderingContext.h</a></li>
<li><a href="#trunkSourceWebCorehtmlcanvasCanvasRenderingContext2Dcpp">trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlcanvasCanvasRenderingContext2Dh">trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebCorebindingsjsJSOffscreenCanvasRenderingContext2DCustomcpp">trunk/Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlcanvasCanvasRenderingContext2DBasecpp">trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlcanvasCanvasRenderingContext2DBaseh">trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.h</a></li>
<li><a href="#trunkSourceWebCorehtmlcanvasOffscreenCanvasRenderingContext2Dcpp">trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlcanvasOffscreenCanvasRenderingContext2Dh">trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.h</a></li>
<li><a href="#trunkSourceWebCorehtmlcanvasOffscreenCanvasRenderingContext2Didl">trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.idl</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/CMakeLists.txt (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/CMakeLists.txt      2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/CMakeLists.txt 2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -729,6 +729,7 @@
</span><span class="cx">     html/canvas/CanvasUserInterface.idl
</span><span class="cx">     html/canvas/ImageBitmapRenderingContext.idl
</span><span class="cx">     html/canvas/ImageSmoothingQuality.idl
</span><ins>+    html/canvas/OffscreenCanvasRenderingContext2D.idl
</ins><span class="cx">     html/canvas/Path2D.idl
</span><span class="cx">     html/canvas/WebGPUBuffer.idl
</span><span class="cx">     html/canvas/WebGPUCommandBuffer.idl
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/ChangeLog      2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -1,3 +1,58 @@
</span><ins>+2017-12-12  Dean Jackson  <dino@apple.com>
+
+        Add CanvasRenderingContext2DBase class and OffscreenCanvasRenderingContext2D
+        https://bugs.webkit.org/show_bug.cgi?id=180718
+        <rdar://problem/36004015>
+
+        Reviewed by Sam Weinig.
+
+        Add an OffscreenCanvasRenderingContext2D class, and in the process create a shared
+        base class for it and CanvasRenderingContext2D, called CanvasRenderingContext2DBase.
+        The base class has nearly all the functionality, with the exception of the text
+        and focus rendering APIs, which are only exposed on CanvasRenderingContext2D.
+
+        At the moment CanvasRenderingContext2DBase's implementation still expects the attached
+        canvas to be an HTMLCanvasElement, but that's ok since you can't yet create an
+        OffscreenCanvasRenderingContext2D. A subsequent patch will do the right thing.
+
+        No change in functionality at the moment, so covered by the existing tests.
+
+        * DerivedSources.make: Add the new IDL file.
+
+        * Sources.txt: Add all the new files to compile.
+        * WebCore.xcodeproj/project.pbxproj:
+
+        * bindings/js/JSCanvasRenderingContext2DCustom.cpp: Removed some unnecessary headers, and
+        added JSC:: where appropriate.
+        (WebCore::JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
+        (WebCore::JSCanvasRenderingContext2D::visitAdditionalChildren):
+
+        * bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp: Copied from Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp.
+        (WebCore::root): New root function that just returns the address of the OffscreenCanvas.
+        (WebCore::JSOffscreenCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
+        (WebCore::JSOffscreenCanvasRenderingContext2D::visitAdditionalChildren):
+
+        * bindings/js/JSWorkerNavigatorCustom.cpp: Add JSC:: to fix a compilation error.
+        (WebCore::JSWorkerNavigator::visitAdditionalChildren):
+
+        * bindings/js/WebCoreBuiltinNames.h: New IDL types.
+
+        * html/OffscreenCanvas.idl: Explicitly generates an IsReachable.
+
+        * html/canvas/CanvasRenderingContext.h:
+        (WebCore::CanvasRenderingContext::isOffscreen2d const): Helper for is<> trait.
+
+        * html/canvas/CanvasRenderingContext2D.cpp: Nearly everything has been moved to the Base class.
+        * html/canvas/CanvasRenderingContext2D.h:
+        * html/canvas/CanvasRenderingContext2DBase.cpp: Copied from Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp.
+        * html/canvas/CanvasRenderingContext2DBase.h: Copied from Source/WebCore/html/canvas/CanvasRenderingContext2D.h.
+
+        * html/canvas/OffscreenCanvasRenderingContext2D.cpp: Added. Basic implementation that
+        just uses the Base class.
+        (WebCore::OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D):
+        * html/canvas/OffscreenCanvasRenderingContext2D.h: Added.
+        * html/canvas/OffscreenCanvasRenderingContext2D.idl: Added.
+
</ins><span class="cx"> 2017-12-12  Jer Noble  <jer.noble@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [EME] Support FPS-over-HLS in the Modern EME API
</span></span></pre></div>
<a id="trunkSourceWebCoreDerivedSourcesmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/DerivedSources.make (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/DerivedSources.make 2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/DerivedSources.make    2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -659,6 +659,7 @@
</span><span class="cx">     $(WebCore)/html/canvas/OESTextureHalfFloat.idl \
</span><span class="cx">     $(WebCore)/html/canvas/OESTextureHalfFloatLinear.idl \
</span><span class="cx">     $(WebCore)/html/canvas/OESVertexArrayObject.idl \
</span><ins>+    $(WebCore)/html/canvas/OffscreenCanvasRenderingContext2D.idl \
</ins><span class="cx">     $(WebCore)/html/canvas/Path2D.idl \
</span><span class="cx">     $(WebCore)/html/canvas/WebGL2RenderingContext.idl \
</span><span class="cx">     $(WebCore)/html/canvas/WebGLActiveInfo.idl \
</span></span></pre></div>
<a id="trunkSourceWebCoreSourcestxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Sources.txt (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Sources.txt 2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/Sources.txt    2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -408,6 +408,7 @@
</span><span class="cx"> bindings/js/JSNodeCustom.cpp
</span><span class="cx"> bindings/js/JSNodeIteratorCustom.cpp
</span><span class="cx"> bindings/js/JSNodeListCustom.cpp
</span><ins>+bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp
</ins><span class="cx"> bindings/js/JSPerformanceEntryCustom.cpp
</span><span class="cx"> bindings/js/JSPluginElementFunctions.cpp
</span><span class="cx"> bindings/js/JSPopStateEventCustom.cpp
</span><span class="lines">@@ -1058,8 +1059,10 @@
</span><span class="cx"> html/canvas/CanvasPattern.cpp
</span><span class="cx"> html/canvas/CanvasRenderingContext.cpp
</span><span class="cx"> html/canvas/CanvasRenderingContext2D.cpp
</span><ins>+html/canvas/CanvasRenderingContext2DBase.cpp
</ins><span class="cx"> html/canvas/CanvasStyle.cpp
</span><span class="cx"> html/canvas/ImageBitmapRenderingContext.cpp
</span><ins>+html/canvas/OffscreenCanvasRenderingContext2D.cpp
</ins><span class="cx"> html/canvas/Path2D.cpp
</span><span class="cx"> html/canvas/PlaceholderRenderingContext.cpp
</span><span class="cx"> html/canvas/WebGPUBuffer.cpp
</span><span class="lines">@@ -2666,6 +2669,7 @@
</span><span class="cx"> JSOfflineAudioCompletionEvent.cpp
</span><span class="cx"> JSOfflineAudioContext.cpp
</span><span class="cx"> JSOffscreenCanvas.cpp
</span><ins>+JSOffscreenCanvasRenderingContext2D.cpp
</ins><span class="cx"> JSOscillatorNode.cpp
</span><span class="cx"> JSOverconstrainedError.cpp
</span><span class="cx"> JSOverconstrainedErrorEvent.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj   2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj      2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -825,6 +825,9 @@
</span><span class="cx">          3135910B1E7DDC7300F30630 /* RTCSignalingState.h in Headers */ = {isa = PBXBuildFile; fileRef = 313591051E7DDC6000F30630 /* RTCSignalingState.h */; };
</span><span class="cx">          3140379B124BEA7F00AF40E4 /* WebCoreMotionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 31403797124BEA7F00AF40E4 /* WebCoreMotionManager.h */; };
</span><span class="cx">          3140379D124BEA7F00AF40E4 /* DeviceOrientationClientIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 31403799124BEA7F00AF40E4 /* DeviceOrientationClientIOS.h */; };
</span><ins>+               3140C5201FDF151A00D2A873 /* OffscreenCanvasRenderingContext2D.h in Headers */ = {isa = PBXBuildFile; fileRef = 3140C51E1FDF151A00D2A873 /* OffscreenCanvasRenderingContext2D.h */; };
+               3140C5241FDF318700D2A873 /* CanvasRenderingContext2DBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 3140C5221FDF318600D2A873 /* CanvasRenderingContext2DBase.h */; };
+               3140C5271FDF558200D2A873 /* JSOffscreenCanvasRenderingContext2D.h in Headers */ = {isa = PBXBuildFile; fileRef = 3140C5251FDF557F00D2A873 /* JSOffscreenCanvasRenderingContext2D.h */; };
</ins><span class="cx">           3146FE6E184420A8001A937C /* OESTextureFloatLinear.h in Headers */ = {isa = PBXBuildFile; fileRef = 3146FE6618442087001A937C /* OESTextureFloatLinear.h */; };
</span><span class="cx">          3146FE6F184420AA001A937C /* OESTextureFloatLinear.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3146FE6518442087001A937C /* OESTextureFloatLinear.cpp */; };
</span><span class="cx">          3146FE7518442370001A937C /* JSOESTextureFloatLinear.h in Headers */ = {isa = PBXBuildFile; fileRef = 3146FE7118442367001A937C /* JSOESTextureFloatLinear.h */; };
</span><span class="lines">@@ -6505,6 +6508,14 @@
</span><span class="cx">          31403798124BEA7F00AF40E4 /* WebCoreMotionManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebCoreMotionManager.mm; sourceTree = "<group>"; };
</span><span class="cx">          31403799124BEA7F00AF40E4 /* DeviceOrientationClientIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceOrientationClientIOS.h; sourceTree = "<group>"; };
</span><span class="cx">          3140379A124BEA7F00AF40E4 /* DeviceOrientationClientIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DeviceOrientationClientIOS.mm; sourceTree = "<group>"; };
</span><ins>+               3140C51B1FDF13D200D2A873 /* OffscreenCanvasRenderingContext2D.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = OffscreenCanvasRenderingContext2D.idl; sourceTree = "<group>"; };
+               3140C51D1FDF151A00D2A873 /* OffscreenCanvasRenderingContext2D.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = OffscreenCanvasRenderingContext2D.cpp; sourceTree = "<group>"; };
+               3140C51E1FDF151A00D2A873 /* OffscreenCanvasRenderingContext2D.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OffscreenCanvasRenderingContext2D.h; sourceTree = "<group>"; };
+               3140C5211FDF318400D2A873 /* CanvasRenderingContext2DBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CanvasRenderingContext2DBase.cpp; sourceTree = "<group>"; };
+               3140C5221FDF318600D2A873 /* CanvasRenderingContext2DBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasRenderingContext2DBase.h; sourceTree = "<group>"; };
+               3140C5251FDF557F00D2A873 /* JSOffscreenCanvasRenderingContext2D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSOffscreenCanvasRenderingContext2D.h; sourceTree = "<group>"; };
+               3140C5261FDF558100D2A873 /* JSOffscreenCanvasRenderingContext2D.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSOffscreenCanvasRenderingContext2D.cpp; sourceTree = "<group>"; };
+               3140C52B1FE06B4900D2A873 /* JSOffscreenCanvasRenderingContext2DCustom.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSOffscreenCanvasRenderingContext2DCustom.cpp; sourceTree = "<group>"; };
</ins><span class="cx">           3146FE6518442087001A937C /* OESTextureFloatLinear.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OESTextureFloatLinear.cpp; sourceTree = "<group>"; };
</span><span class="cx">          3146FE6618442087001A937C /* OESTextureFloatLinear.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OESTextureFloatLinear.h; sourceTree = "<group>"; };
</span><span class="cx">          3146FE6718442087001A937C /* OESTextureFloatLinear.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OESTextureFloatLinear.idl; sourceTree = "<group>"; };
</span><span class="lines">@@ -16602,6 +16613,8 @@
</span><span class="cx">                          49484FBC102CF23C00187DD3 /* CanvasRenderingContext2D.cpp */,
</span><span class="cx">                          49484FBD102CF23C00187DD3 /* CanvasRenderingContext2D.h */,
</span><span class="cx">                          49484FBE102CF23C00187DD3 /* CanvasRenderingContext2D.idl */,
</span><ins>+                               3140C5211FDF318400D2A873 /* CanvasRenderingContext2DBase.cpp */,
+                               3140C5221FDF318600D2A873 /* CanvasRenderingContext2DBase.h */,
</ins><span class="cx">                           7C193BAD1F5E0EB30088F3E6 /* CanvasShadowStyles.idl */,
</span><span class="cx">                          7C193BB21F5E0EB60088F3E6 /* CanvasState.idl */,
</span><span class="cx">                          49484FBF102CF23C00187DD3 /* CanvasStyle.cpp */,
</span><span class="lines">@@ -16658,6 +16671,9 @@
</span><span class="cx">                          77A17A6E12F28182004E02F6 /* OESVertexArrayObject.cpp */,
</span><span class="cx">                          77A17A6F12F28182004E02F6 /* OESVertexArrayObject.h */,
</span><span class="cx">                          77A17A7012F28182004E02F6 /* OESVertexArrayObject.idl */,
</span><ins>+                               3140C51D1FDF151A00D2A873 /* OffscreenCanvasRenderingContext2D.cpp */,
+                               3140C51E1FDF151A00D2A873 /* OffscreenCanvasRenderingContext2D.h */,
+                               3140C51B1FDF13D200D2A873 /* OffscreenCanvasRenderingContext2D.idl */,
</ins><span class="cx">                           7C193BA71F5E0EAF0088F3E6 /* Path2D.cpp */,
</span><span class="cx">                          7C193BAB1F5E0EB10088F3E6 /* Path2D.h */,
</span><span class="cx">                          7C193BB41F5E0EB70088F3E6 /* Path2D.idl */,
</span><span class="lines">@@ -19016,6 +19032,7 @@
</span><span class="cx">                          1A750DD30A90E729000FF215 /* JSNodeIteratorCustom.cpp */,
</span><span class="cx">                          BCD9C2610C17AA67005C90A2 /* JSNodeListCustom.cpp */,
</span><span class="cx">                          AD20B18C18E9D216005A8083 /* JSNodeListCustom.h */,
</span><ins>+                               3140C52B1FE06B4900D2A873 /* JSOffscreenCanvasRenderingContext2DCustom.cpp */,
</ins><span class="cx">                           CB38FD551CD21D5B00592A3F /* JSPerformanceEntryCustom.cpp */,
</span><span class="cx">                          83F572941FA1066F003837BE /* JSServiceWorkerClientCustom.cpp */,
</span><span class="cx">                          460D19441FCE21DD00C3DB85 /* JSServiceWorkerGlobalScopeCustom.cpp */,
</span><span class="lines">@@ -21052,6 +21069,8 @@
</span><span class="cx">                          77A17AA312F28B2A004E02F6 /* JSOESVertexArrayObject.h */,
</span><span class="cx">                          314877E51FAAB02400C05759 /* JSOffscreenCanvas.cpp */,
</span><span class="cx">                          314877E41FAAB02200C05759 /* JSOffscreenCanvas.h */,
</span><ins>+                               3140C5261FDF558100D2A873 /* JSOffscreenCanvasRenderingContext2D.cpp */,
+                               3140C5251FDF557F00D2A873 /* JSOffscreenCanvasRenderingContext2D.h */,
</ins><span class="cx">                           7C193BFD1F5E10D60088F3E6 /* JSPath2D.cpp */,
</span><span class="cx">                          7C193BFE1F5E10D70088F3E6 /* JSPath2D.h */,
</span><span class="cx">                          B658FF9F1522EF3A00DD5595 /* JSRadioNodeList.cpp */,
</span><span class="lines">@@ -26316,6 +26335,7 @@
</span><span class="cx">                          49484FC5102CF23C00187DD3 /* CanvasPattern.h in Headers */,
</span><span class="cx">                          49C7B9DD1042D32F0009D447 /* CanvasRenderingContext.h in Headers */,
</span><span class="cx">                          49484FCB102CF23C00187DD3 /* CanvasRenderingContext2D.h in Headers */,
</span><ins>+                               3140C5241FDF318700D2A873 /* CanvasRenderingContext2DBase.h in Headers */,
</ins><span class="cx">                           49484FCE102CF23C00187DD3 /* CanvasStyle.h in Headers */,
</span><span class="cx">                          7C193BBF1F5E0EED0088F3E6 /* CanvasTextAlign.h in Headers */,
</span><span class="cx">                          7C193BC01F5E0EED0088F3E6 /* CanvasTextBaseline.h in Headers */,
</span><span class="lines">@@ -27799,6 +27819,7 @@
</span><span class="cx">                          FDF6BAF9134A4C9800822920 /* JSOfflineAudioCompletionEvent.h in Headers */,
</span><span class="cx">                          FDA9326716703BA9008982DC /* JSOfflineAudioContext.h in Headers */,
</span><span class="cx">                          314877E61FAAB02500C05759 /* JSOffscreenCanvas.h in Headers */,
</span><ins>+                               3140C5271FDF558200D2A873 /* JSOffscreenCanvasRenderingContext2D.h in Headers */,
</ins><span class="cx">                           57E233651DC7DB1F00F28D01 /* JsonWebKey.h in Headers */,
</span><span class="cx">                          FDEA6243152102E200479DF0 /* JSOscillatorNode.h in Headers */,
</span><span class="cx">                          0704A40C1D6DFC690086DCDB /* JSOverconstrainedError.h in Headers */,
</span><span class="lines">@@ -28490,6 +28511,7 @@
</span><span class="cx">                          FDA9325E16703B2A008982DC /* OfflineAudioContext.h in Headers */,
</span><span class="cx">                          FDA3E95C134A49EF008D4B5A /* OfflineAudioDestinationNode.h in Headers */,
</span><span class="cx">                          314877E31FAA8FE900C05759 /* OffscreenCanvas.h in Headers */,
</span><ins>+                               3140C5201FDF151A00D2A873 /* OffscreenCanvasRenderingContext2D.h in Headers */,
</ins><span class="cx">                           B2D3DA650D006CD600EF6F3A /* OpenTypeCG.h in Headers */,
</span><span class="cx">                          B2D3DA650D006CD600EF6F27 /* OpenTypeMathData.h in Headers */,
</span><span class="cx">                          B2D3EA650D006CD600EF6F28 /* OpenTypeTypes.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsJSCanvasRenderingContext2DCustomcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp    2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp       2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -20,24 +20,9 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "JSCanvasRenderingContext2D.h"
</span><span class="cx"> 
</span><del>-#include "CanvasGradient.h"
-#include "CanvasPattern.h"
-#include "CanvasRenderingContext2D.h"
-#include "CanvasStyle.h"
-#include "HTMLCanvasElement.h"
-#include "HTMLImageElement.h"
-#include "ImageData.h"
-#include "JSCanvasGradient.h"
-#include "JSCanvasPattern.h"
-#include "JSHTMLCanvasElement.h"
-#include "JSHTMLImageElement.h"
-#include "JSImageData.h"
-
-
</del><span class="cx"> namespace WebCore {
</span><del>-using namespace JSC;
</del><span class="cx"> 
</span><del>-bool JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
</del><ins>+bool JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
</ins><span class="cx"> {
</span><span class="cx">     JSCanvasRenderingContext2D* jsCanvasRenderingContext = jsCast<JSCanvasRenderingContext2D*>(handle.slot()->asCell());
</span><span class="cx">     void* root = WebCore::root(jsCanvasRenderingContext->wrapped().canvas());
</span><span class="lines">@@ -44,7 +29,7 @@
</span><span class="cx">     return visitor.containsOpaqueRoot(root);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void JSCanvasRenderingContext2D::visitAdditionalChildren(SlotVisitor& visitor)
</del><ins>+void JSCanvasRenderingContext2D::visitAdditionalChildren(JSC::SlotVisitor& visitor)
</ins><span class="cx"> {
</span><span class="cx">     visitor.addOpaqueRoot(root(wrapped().canvas()));
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsJSOffscreenCanvasRenderingContext2DCustomcppfromrev225815trunkSourceWebCorebindingsjsJSCanvasRenderingContext2DCustomcpp"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp (from rev 225815, trunk/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp) (0 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp                           (rev 0)
+++ trunk/Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp      2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "JSOffscreenCanvasRenderingContext2D.h"
+
+namespace WebCore {
+using namespace JSC;
+
+inline void* root(OffscreenCanvas* canvas)
+{
+    return canvas;
+}
+
+bool JSOffscreenCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+{
+    JSOffscreenCanvasRenderingContext2D* jsOffscreenCanvasRenderingContext = jsCast<JSOffscreenCanvasRenderingContext2D*>(handle.slot()->asCell());
+    void* root = WebCore::root(&jsOffscreenCanvasRenderingContext->wrapped().canvas());
+    return visitor.containsOpaqueRoot(root);
+}
+
+void JSOffscreenCanvasRenderingContext2D::visitAdditionalChildren(SlotVisitor& visitor)
+{
+    visitor.addOpaqueRoot(root(&wrapped().canvas()));
+}
+
+} // namespace WebCore
+
</ins></span></pre></div>
<a id="trunkSourceWebCorebindingsjsJSWorkerNavigatorCustomcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/JSWorkerNavigatorCustom.cpp (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/JSWorkerNavigatorCustom.cpp     2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/bindings/js/JSWorkerNavigatorCustom.cpp        2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -28,7 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-void JSWorkerNavigator::visitAdditionalChildren(SlotVisitor& visitor)
</del><ins>+void JSWorkerNavigator::visitAdditionalChildren(JSC::SlotVisitor& visitor)
</ins><span class="cx"> {
</span><span class="cx"> #if ENABLE(SERVICE_WORKER)
</span><span class="cx">     visitor.addOpaqueRoot(&wrapped().serviceWorker());
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsWebCoreBuiltinNamesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h   2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/bindings/js/WebCoreBuiltinNames.h      2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -98,6 +98,7 @@
</span><span class="cx">     macro(NavigatorMediaDevices) \
</span><span class="cx">     macro(NavigatorUserMedia) \
</span><span class="cx">     macro(OffscreenCanvas) \
</span><ins>+    macro(OffscreenCanvasRenderingContext2D) \
</ins><span class="cx">     macro(PasswordCredential) \
</span><span class="cx">     macro(PaymentAddress) \
</span><span class="cx">     macro(PaymentRequest) \
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlOffscreenCanvasidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/OffscreenCanvas.idl (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/OffscreenCanvas.idl    2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/html/OffscreenCanvas.idl       2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -40,6 +40,7 @@
</span><span class="cx"> [
</span><span class="cx">     ConstructorCallWith=ScriptExecutionContext,
</span><span class="cx">     Constructor([EnforceRange] unsigned long width, [EnforceRange] unsigned long height),
</span><ins>+    GenerateIsReachable=Impl,
</ins><span class="cx">     EnabledAtRuntime=ImageBitmapOffscreenCanvas,
</span><span class="cx">     Exposed=(Window)
</span><span class="cx"> ] interface OffscreenCanvas : EventTarget {
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlcanvasCanvasRenderingContexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext.h (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext.h        2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext.h   2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -62,6 +62,7 @@
</span><span class="cx">     virtual bool isAccelerated() const { return false; }
</span><span class="cx">     virtual bool isBitmapRenderer() const { return false; }
</span><span class="cx">     virtual bool isPlaceholder() const { return false; }
</span><ins>+    virtual bool isOffscreen2d() const { return false; }
</ins><span class="cx"> 
</span><span class="cx">     virtual void paintRenderingResultsToCanvas() {}
</span><span class="cx">     virtual PlatformLayer* platformLayer() const { return 0; }
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlcanvasCanvasRenderingContext2Dcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp    2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp       2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -33,17 +33,9 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "CanvasRenderingContext2D.h"
</span><span class="cx"> 
</span><del>-#include "BitmapImage.h"
</del><span class="cx"> #include "CSSFontSelector.h"
</span><span class="cx"> #include "CSSParser.h"
</span><span class="cx"> #include "CSSPropertyNames.h"
</span><del>-#include "CachedImage.h"
-#include "CanvasGradient.h"
-#include "CanvasPattern.h"
-#include "DOMMatrix.h"
-#include "DOMMatrix2DInit.h"
-#include "DisplayListRecorder.h"
-#include "DisplayListReplayer.h"
</del><span class="cx"> #include "FloatQuad.h"
</span><span class="cx"> #include "HTMLImageElement.h"
</span><span class="cx"> #include "HTMLVideoElement.h"
</span><span class="lines">@@ -75,2111 +67,13 @@
</span><span class="cx"> 
</span><span class="cx"> using namespace HTMLNames;
</span><span class="cx"> 
</span><del>-#if USE(CG)
-const ImageSmoothingQuality defaultSmoothingQuality = ImageSmoothingQuality::Low;
-#else
-const ImageSmoothingQuality defaultSmoothingQuality = ImageSmoothingQuality::Medium;
-#endif
-
-static const int defaultFontSize = 10;
-static const char* const defaultFontFamily = "sans-serif";
-static const char* const defaultFont = "10px sans-serif";
-
-struct DisplayListDrawingContext {
-    WTF_MAKE_FAST_ALLOCATED;
-public:
-    GraphicsContext context;
-    DisplayList::DisplayList displayList;
-    
-    DisplayListDrawingContext(const FloatRect& clip)
-        : context([&](GraphicsContext& context) {
-            return std::make_unique<DisplayList::Recorder>(context, displayList, clip, AffineTransform());
-        })
-    {
-    }
-};
-
-typedef HashMap<const CanvasRenderingContext2D*, std::unique_ptr<DisplayList::DisplayList>> ContextDisplayListHashMap;
-
-static ContextDisplayListHashMap& contextDisplayListMap()
-{
-    static NeverDestroyed<ContextDisplayListHashMap> sharedHashMap;
-    return sharedHashMap;
-}
-
-class CanvasStrokeStyleApplier : public StrokeStyleApplier {
-public:
-    CanvasStrokeStyleApplier(CanvasRenderingContext2D* canvasContext)
-        : m_canvasContext(canvasContext)
-    {
-    }
-
-    void strokeStyle(GraphicsContext* c) override
-    {
-        c->setStrokeThickness(m_canvasContext->lineWidth());
-        c->setLineCap(m_canvasContext->getLineCap());
-        c->setLineJoin(m_canvasContext->getLineJoin());
-        c->setMiterLimit(m_canvasContext->miterLimit());
-        const Vector<float>& lineDash = m_canvasContext->getLineDash();
-        DashArray convertedLineDash(lineDash.size());
-        for (size_t i = 0; i < lineDash.size(); ++i)
-            convertedLineDash[i] = static_cast<DashArrayElement>(lineDash[i]);
-        c->setLineDash(convertedLineDash, m_canvasContext->lineDashOffset());
-    }
-
-private:
-    CanvasRenderingContext2D* m_canvasContext;
-};
-
</del><span class="cx"> CanvasRenderingContext2D::CanvasRenderingContext2D(CanvasBase& canvas, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode)
</span><del>-    : CanvasRenderingContext(canvas)
-    , m_stateStack(1)
-    , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
-#if ENABLE(DASHBOARD_SUPPORT)
-    , m_usesDashboardCompatibilityMode(usesDashboardCompatibilityMode)
-#endif
</del><ins>+    : CanvasRenderingContext2DBase(canvas, usesCSSCompatibilityParseMode, usesDashboardCompatibilityMode)
</ins><span class="cx"> {
</span><del>-#if !ENABLE(DASHBOARD_SUPPORT)
-    ASSERT_UNUSED(usesDashboardCompatibilityMode, !usesDashboardCompatibilityMode);
-#endif
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CanvasRenderingContext2D::unwindStateStack()
-{
-    // Ensure that the state stack in the ImageBuffer's context
-    // is cleared before destruction, to avoid assertions in the
-    // GraphicsContext dtor.
-    if (size_t stackSize = m_stateStack.size()) {
-        if (GraphicsContext* context = canvas().existingDrawingContext()) {
-            while (--stackSize)
-                context->restore();
-        }
-    }
-}
</del><ins>+CanvasRenderingContext2D::~CanvasRenderingContext2D() = default;
</ins><span class="cx"> 
</span><del>-CanvasRenderingContext2D::~CanvasRenderingContext2D()
-{
-#if !ASSERT_DISABLED
-    unwindStateStack();
-#endif
-
-    if (UNLIKELY(tracksDisplayListReplay()))
-        contextDisplayListMap().remove(this);
-}
-
-bool CanvasRenderingContext2D::isAccelerated() const
-{
-#if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
-    if (!canvas().hasCreatedImageBuffer())
-        return false;
-    auto* context = drawingContext();
-    return context && context->isAcceleratedContext();
-#else
-    return false;
-#endif
-}
-
-void CanvasRenderingContext2D::reset()
-{
-    unwindStateStack();
-    m_stateStack.resize(1);
-    m_stateStack.first() = State();
-    m_path.clear();
-    m_unrealizedSaveCount = 0;
-    
-    m_recordingContext = nullptr;
-}
-
-CanvasRenderingContext2D::State::State()
-    : strokeStyle(Color::black)
-    , fillStyle(Color::black)
-    , lineWidth(1)
-    , lineCap(ButtCap)
-    , lineJoin(MiterJoin)
-    , miterLimit(10)
-    , shadowBlur(0)
-    , shadowColor(Color::transparent)
-    , globalAlpha(1)
-    , globalComposite(CompositeSourceOver)
-    , globalBlend(BlendModeNormal)
-    , hasInvertibleTransform(true)
-    , lineDashOffset(0)
-    , imageSmoothingEnabled(true)
-    , imageSmoothingQuality(defaultSmoothingQuality)
-    , textAlign(StartTextAlign)
-    , textBaseline(AlphabeticTextBaseline)
-    , direction(Direction::Inherit)
-    , unparsedFont(defaultFont)
-{
-}
-
-CanvasRenderingContext2D::State::State(const State& other)
-    : unparsedStrokeColor(other.unparsedStrokeColor)
-    , unparsedFillColor(other.unparsedFillColor)
-    , strokeStyle(other.strokeStyle)
-    , fillStyle(other.fillStyle)
-    , lineWidth(other.lineWidth)
-    , lineCap(other.lineCap)
-    , lineJoin(other.lineJoin)
-    , miterLimit(other.miterLimit)
-    , shadowOffset(other.shadowOffset)
-    , shadowBlur(other.shadowBlur)
-    , shadowColor(other.shadowColor)
-    , globalAlpha(other.globalAlpha)
-    , globalComposite(other.globalComposite)
-    , globalBlend(other.globalBlend)
-    , transform(other.transform)
-    , hasInvertibleTransform(other.hasInvertibleTransform)
-    , lineDashOffset(other.lineDashOffset)
-    , imageSmoothingEnabled(other.imageSmoothingEnabled)
-    , imageSmoothingQuality(other.imageSmoothingQuality)
-    , textAlign(other.textAlign)
-    , textBaseline(other.textBaseline)
-    , direction(other.direction)
-    , unparsedFont(other.unparsedFont)
-    , font(other.font)
-{
-}
-
-CanvasRenderingContext2D::State& CanvasRenderingContext2D::State::operator=(const State& other)
-{
-    if (this == &other)
-        return *this;
-
-    unparsedStrokeColor = other.unparsedStrokeColor;
-    unparsedFillColor = other.unparsedFillColor;
-    strokeStyle = other.strokeStyle;
-    fillStyle = other.fillStyle;
-    lineWidth = other.lineWidth;
-    lineCap = other.lineCap;
-    lineJoin = other.lineJoin;
-    miterLimit = other.miterLimit;
-    shadowOffset = other.shadowOffset;
-    shadowBlur = other.shadowBlur;
-    shadowColor = other.shadowColor;
-    globalAlpha = other.globalAlpha;
-    globalComposite = other.globalComposite;
-    globalBlend = other.globalBlend;
-    transform = other.transform;
-    hasInvertibleTransform = other.hasInvertibleTransform;
-    imageSmoothingEnabled = other.imageSmoothingEnabled;
-    imageSmoothingQuality = other.imageSmoothingQuality;
-    textAlign = other.textAlign;
-    textBaseline = other.textBaseline;
-    direction = other.direction;
-    unparsedFont = other.unparsedFont;
-    font = other.font;
-
-    return *this;
-}
-
-CanvasRenderingContext2D::FontProxy::~FontProxy()
-{
-    if (realized())
-        m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
-}
-
-CanvasRenderingContext2D::FontProxy::FontProxy(const FontProxy& other)
-    : m_font(other.m_font)
-{
-    if (realized())
-        m_font.fontSelector()->registerForInvalidationCallbacks(*this);
-}
-
-auto CanvasRenderingContext2D::FontProxy::operator=(const FontProxy& other) -> FontProxy&
-{
-    if (realized())
-        m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
-
-    m_font = other.m_font;
-
-    if (realized())
-        m_font.fontSelector()->registerForInvalidationCallbacks(*this);
-
-    return *this;
-}
-
-inline void CanvasRenderingContext2D::FontProxy::update(FontSelector& selector)
-{
-    ASSERT(&selector == m_font.fontSelector()); // This is an invariant. We should only ever be registered for callbacks on m_font.m_fonts.m_fontSelector.
-    if (realized())
-        m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
-    m_font.update(&selector);
-    if (realized())
-        m_font.fontSelector()->registerForInvalidationCallbacks(*this);
-    ASSERT(&selector == m_font.fontSelector());
-}
-
-void CanvasRenderingContext2D::FontProxy::fontsNeedUpdate(FontSelector& selector)
-{
-    ASSERT_ARG(selector, &selector == m_font.fontSelector());
-    ASSERT(realized());
-
-    update(selector);
-}
-
-inline void CanvasRenderingContext2D::FontProxy::initialize(FontSelector& fontSelector, const RenderStyle& newStyle)
-{
-    // Beware! m_font.fontSelector() might not point to document.fontSelector()!
-    ASSERT(newStyle.fontCascade().fontSelector() == &fontSelector);
-    if (realized())
-        m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
-    m_font = newStyle.fontCascade();
-    m_font.update(&fontSelector);
-    ASSERT(&fontSelector == m_font.fontSelector());
-    m_font.fontSelector()->registerForInvalidationCallbacks(*this);
-}
-
-inline const FontMetrics& CanvasRenderingContext2D::FontProxy::fontMetrics() const
-{
-    return m_font.fontMetrics();
-}
-
-inline const FontCascadeDescription& CanvasRenderingContext2D::FontProxy::fontDescription() const
-{
-    return m_font.fontDescription();
-}
-
-inline float CanvasRenderingContext2D::FontProxy::width(const TextRun& textRun, GlyphOverflow* overflow) const
-{
-    return m_font.width(textRun, 0, overflow);
-}
-
-inline void CanvasRenderingContext2D::FontProxy::drawBidiText(GraphicsContext& context, const TextRun& run, const FloatPoint& point, FontCascade::CustomFontNotReadyAction action) const
-{
-    context.drawBidiText(m_font, run, point, action);
-}
-
-void CanvasRenderingContext2D::realizeSaves()
-{
-    if (m_unrealizedSaveCount)
-        realizeSavesLoop();
-
-    if (m_unrealizedSaveCount) {
-        static NeverDestroyed<String> consoleMessage(MAKE_STATIC_STRING_IMPL("CanvasRenderingContext2D.save() has been called without a matching restore() too many times. Ignoring save()."));
-        canvas().document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, consoleMessage);
-    }
-}
-
-void CanvasRenderingContext2D::realizeSavesLoop()
-{
-    ASSERT(m_unrealizedSaveCount);
-    ASSERT(m_stateStack.size() >= 1);
-    GraphicsContext* context = drawingContext();
-    do {
-        if (m_stateStack.size() > MaxSaveCount)
-            break;
-        m_stateStack.append(state());
-        if (context)
-            context->save();
-    } while (--m_unrealizedSaveCount);
-}
-
-void CanvasRenderingContext2D::restore()
-{
-    if (m_unrealizedSaveCount) {
-        --m_unrealizedSaveCount;
-        return;
-    }
-    ASSERT(m_stateStack.size() >= 1);
-    if (m_stateStack.size() <= 1)
-        return;
-    m_path.transform(state().transform);
-    m_stateStack.removeLast();
-    if (std::optional<AffineTransform> inverse = state().transform.inverse())
-        m_path.transform(inverse.value());
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    c->restore();
-}
-
-void CanvasRenderingContext2D::setStrokeStyle(CanvasStyle style)
-{
-    if (!style.isValid())
-        return;
-
-    if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentColor(style))
-        return;
-
-    if (style.isCurrentColor()) {
-        if (style.hasOverrideAlpha()) {
-            // FIXME: Should not use RGBA32 here.
-            style = CanvasStyle(colorWithOverrideAlpha(currentColor(&canvas()).rgb(), style.overrideAlpha()));
-        } else
-            style = CanvasStyle(currentColor(&canvas()));
-    } else
-        checkOrigin(style.canvasPattern().get());
-
-    realizeSaves();
-    State& state = modifiableState();
-    state.strokeStyle = style;
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    state.strokeStyle.applyStrokeColor(*c);
-    state.unparsedStrokeColor = String();
-}
-
-void CanvasRenderingContext2D::setFillStyle(CanvasStyle style)
-{
-    if (!style.isValid())
-        return;
-
-    if (state().fillStyle.isValid() && state().fillStyle.isEquivalentColor(style))
-        return;
-
-    if (style.isCurrentColor()) {
-        if (style.hasOverrideAlpha()) {
-            // FIXME: Should not use RGBA32 here.
-            style = CanvasStyle(colorWithOverrideAlpha(currentColor(&canvas()).rgb(), style.overrideAlpha()));
-        } else
-            style = CanvasStyle(currentColor(&canvas()));
-    } else
-        checkOrigin(style.canvasPattern().get());
-
-    realizeSaves();
-    State& state = modifiableState();
-    state.fillStyle = style;
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    state.fillStyle.applyFillColor(*c);
-    state.unparsedFillColor = String();
-}
-
-float CanvasRenderingContext2D::lineWidth() const
-{
-    return state().lineWidth;
-}
-
-void CanvasRenderingContext2D::setLineWidth(float width)
-{
-    if (!(std::isfinite(width) && width > 0))
-        return;
-    if (state().lineWidth == width)
-        return;
-    realizeSaves();
-    modifiableState().lineWidth = width;
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    c->setStrokeThickness(width);
-}
-
-static CanvasLineCap toCanvasLineCap(LineCap lineCap)
-{
-    switch (lineCap) {
-    case ButtCap:
-        return CanvasLineCap::Butt;
-    case RoundCap:
-        return CanvasLineCap::Round;
-    case SquareCap:
-        return CanvasLineCap::Square;
-    }
-
-    ASSERT_NOT_REACHED();
-    return CanvasLineCap::Butt;
-}
-
-static LineCap fromCanvasLineCap(CanvasLineCap canvasLineCap)
-{
-    switch (canvasLineCap) {
-    case CanvasLineCap::Butt:
-        return ButtCap;
-    case CanvasLineCap::Round:
-        return RoundCap;
-    case CanvasLineCap::Square:
-        return SquareCap;
-    }
-    
-    ASSERT_NOT_REACHED();
-    return ButtCap;
-}
-
-CanvasLineCap CanvasRenderingContext2D::lineCap() const
-{
-    return toCanvasLineCap(state().lineCap);
-}
-
-void CanvasRenderingContext2D::setLineCap(CanvasLineCap canvasLineCap)
-{
-    auto lineCap = fromCanvasLineCap(canvasLineCap);
-    if (state().lineCap == lineCap)
-        return;
-    realizeSaves();
-    modifiableState().lineCap = lineCap;
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    c->setLineCap(lineCap);
-}
-
-void CanvasRenderingContext2D::setLineCap(const String& stringValue)
-{
-    CanvasLineCap cap;
-    if (stringValue == "butt")
-        cap = CanvasLineCap::Butt;
-    else if (stringValue == "round")
-        cap = CanvasLineCap::Round;
-    else if (stringValue == "square")
-        cap = CanvasLineCap::Square;
-    else
-        return;
-    
-    setLineCap(cap);
-}
-
-static CanvasLineJoin toCanvasLineJoin(LineJoin lineJoin)
-{
-    switch (lineJoin) {
-    case RoundJoin:
-        return CanvasLineJoin::Round;
-    case BevelJoin:
-        return CanvasLineJoin::Bevel;
-    case MiterJoin:
-        return CanvasLineJoin::Miter;
-    }
-
-    ASSERT_NOT_REACHED();
-    return CanvasLineJoin::Round;
-}
-
-static LineJoin fromCanvasLineJoin(CanvasLineJoin canvasLineJoin)
-{
-    switch (canvasLineJoin) {
-    case CanvasLineJoin::Round:
-        return RoundJoin;
-    case CanvasLineJoin::Bevel:
-        return BevelJoin;
-    case CanvasLineJoin::Miter:
-        return MiterJoin;
-    }
-    
-    ASSERT_NOT_REACHED();
-    return RoundJoin;
-}
-
-CanvasLineJoin CanvasRenderingContext2D::lineJoin() const
-{
-    return toCanvasLineJoin(state().lineJoin);
-}
-
-void CanvasRenderingContext2D::setLineJoin(CanvasLineJoin canvasLineJoin)
-{
-    auto lineJoin = fromCanvasLineJoin(canvasLineJoin);
-    if (state().lineJoin == lineJoin)
-        return;
-    realizeSaves();
-    modifiableState().lineJoin = lineJoin;
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    c->setLineJoin(lineJoin);
-}
-
-void CanvasRenderingContext2D::setLineJoin(const String& stringValue)
-{
-    CanvasLineJoin join;
-    if (stringValue == "round")
-        join = CanvasLineJoin::Round;
-    else if (stringValue == "bevel")
-        join = CanvasLineJoin::Bevel;
-    else if (stringValue == "miter")
-        join = CanvasLineJoin::Miter;
-    else
-        return;
-
-    setLineJoin(join);
-}
-
-float CanvasRenderingContext2D::miterLimit() const
-{
-    return state().miterLimit;
-}
-
-void CanvasRenderingContext2D::setMiterLimit(float limit)
-{
-    if (!(std::isfinite(limit) && limit > 0))
-        return;
-    if (state().miterLimit == limit)
-        return;
-    realizeSaves();
-    modifiableState().miterLimit = limit;
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    c->setMiterLimit(limit);
-}
-
-float CanvasRenderingContext2D::shadowOffsetX() const
-{
-    return state().shadowOffset.width();
-}
-
-void CanvasRenderingContext2D::setShadowOffsetX(float x)
-{
-    if (!std::isfinite(x))
-        return;
-    if (state().shadowOffset.width() == x)
-        return;
-    realizeSaves();
-    modifiableState().shadowOffset.setWidth(x);
-    applyShadow();
-}
-
-float CanvasRenderingContext2D::shadowOffsetY() const
-{
-    return state().shadowOffset.height();
-}
-
-void CanvasRenderingContext2D::setShadowOffsetY(float y)
-{
-    if (!std::isfinite(y))
-        return;
-    if (state().shadowOffset.height() == y)
-        return;
-    realizeSaves();
-    modifiableState().shadowOffset.setHeight(y);
-    applyShadow();
-}
-
-float CanvasRenderingContext2D::shadowBlur() const
-{
-    return state().shadowBlur;
-}
-
-void CanvasRenderingContext2D::setShadowBlur(float blur)
-{
-    if (!(std::isfinite(blur) && blur >= 0))
-        return;
-    if (state().shadowBlur == blur)
-        return;
-    realizeSaves();
-    modifiableState().shadowBlur = blur;
-    applyShadow();
-}
-
-String CanvasRenderingContext2D::shadowColor() const
-{
-    return Color(state().shadowColor).serialized();
-}
-
-void CanvasRenderingContext2D::setShadowColor(const String& colorString)
-{
-    Color color = parseColorOrCurrentColor(colorString, &canvas());
-    if (!color.isValid())
-        return;
-    if (state().shadowColor == color)
-        return;
-    realizeSaves();
-    modifiableState().shadowColor = color;
-    applyShadow();
-}
-
-const Vector<float>& CanvasRenderingContext2D::getLineDash() const
-{
-    return state().lineDash;
-}
-
-static bool lineDashSequenceIsValid(const Vector<float>& dash)
-{
-    for (size_t i = 0; i < dash.size(); i++) {
-        if (!std::isfinite(dash[i]) || dash[i] < 0)
-            return false;
-    }
-    return true;
-}
-
-void CanvasRenderingContext2D::setLineDash(const Vector<float>& dash)
-{
-    if (!lineDashSequenceIsValid(dash))
-        return;
-
-    realizeSaves();
-    modifiableState().lineDash = dash;
-    // Spec requires the concatenation of two copies the dash list when the
-    // number of elements is odd
-    if (dash.size() % 2)
-        modifiableState().lineDash.appendVector(dash);
-
-    applyLineDash();
-}
-
-void CanvasRenderingContext2D::setWebkitLineDash(const Vector<float>& dash)
-{
-    if (!lineDashSequenceIsValid(dash))
-        return;
-
-    realizeSaves();
-    modifiableState().lineDash = dash;
-
-    applyLineDash();
-}
-
-float CanvasRenderingContext2D::lineDashOffset() const
-{
-    return state().lineDashOffset;
-}
-
-void CanvasRenderingContext2D::setLineDashOffset(float offset)
-{
-    if (!std::isfinite(offset) || state().lineDashOffset == offset)
-        return;
-
-    realizeSaves();
-    modifiableState().lineDashOffset = offset;
-    applyLineDash();
-}
-
-void CanvasRenderingContext2D::applyLineDash() const
-{
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    DashArray convertedLineDash(state().lineDash.size());
-    for (size_t i = 0; i < state().lineDash.size(); ++i)
-        convertedLineDash[i] = static_cast<DashArrayElement>(state().lineDash[i]);
-    c->setLineDash(convertedLineDash, state().lineDashOffset);
-}
-
-float CanvasRenderingContext2D::globalAlpha() const
-{
-    return state().globalAlpha;
-}
-
-void CanvasRenderingContext2D::setGlobalAlpha(float alpha)
-{
-    if (!(alpha >= 0 && alpha <= 1))
-        return;
-    if (state().globalAlpha == alpha)
-        return;
-    realizeSaves();
-    modifiableState().globalAlpha = alpha;
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    c->setAlpha(alpha);
-}
-
-String CanvasRenderingContext2D::globalCompositeOperation() const
-{
-    return compositeOperatorName(state().globalComposite, state().globalBlend);
-}
-
-void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation)
-{
-    CompositeOperator op = CompositeSourceOver;
-    BlendMode blendMode = BlendModeNormal;
-    if (!parseCompositeAndBlendOperator(operation, op, blendMode))
-        return;
-    if ((state().globalComposite == op) && (state().globalBlend == blendMode))
-        return;
-    realizeSaves();
-    modifiableState().globalComposite = op;
-    modifiableState().globalBlend = blendMode;
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    c->setCompositeOperation(op, blendMode);
-}
-
-void CanvasRenderingContext2D::scale(float sx, float sy)
-{
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-
-    if (!std::isfinite(sx) || !std::isfinite(sy))
-        return;
-
-    AffineTransform newTransform = state().transform;
-    newTransform.scaleNonUniform(sx, sy);
-    if (state().transform == newTransform)
-        return;
-
-    realizeSaves();
-
-    if (!sx || !sy) {
-        modifiableState().hasInvertibleTransform = false;
-        return;
-    }
-
-    modifiableState().transform = newTransform;
-    c->scale(FloatSize(sx, sy));
-    m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
-}
-
-void CanvasRenderingContext2D::rotate(float angleInRadians)
-{
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-
-    if (!std::isfinite(angleInRadians))
-        return;
-
-    AffineTransform newTransform = state().transform;
-    newTransform.rotate(angleInRadians / piDouble * 180.0);
-    if (state().transform == newTransform)
-        return;
-
-    realizeSaves();
-
-    modifiableState().transform = newTransform;
-    c->rotate(angleInRadians);
-    m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0));
-}
-
-void CanvasRenderingContext2D::translate(float tx, float ty)
-{
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-
-    if (!std::isfinite(tx) | !std::isfinite(ty))
-        return;
-
-    AffineTransform newTransform = state().transform;
-    newTransform.translate(tx, ty);
-    if (state().transform == newTransform)
-        return;
-
-    realizeSaves();
-
-    modifiableState().transform = newTransform;
-    c->translate(tx, ty);
-    m_path.transform(AffineTransform().translate(-tx, -ty));
-}
-
-void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy)
-{
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-
-    if (!std::isfinite(m11) | !std::isfinite(m21) | !std::isfinite(dx) | !std::isfinite(m12) | !std::isfinite(m22) | !std::isfinite(dy))
-        return;
-
-    AffineTransform transform(m11, m12, m21, m22, dx, dy);
-    AffineTransform newTransform = state().transform * transform;
-    if (state().transform == newTransform)
-        return;
-
-    realizeSaves();
-
-    if (auto inverse = transform.inverse()) {
-        modifiableState().transform = newTransform;
-        c->concatCTM(transform);
-        m_path.transform(inverse.value());
-        return;
-    }
-    modifiableState().hasInvertibleTransform = false;
-}
-
-Ref<DOMMatrix> CanvasRenderingContext2D::getTransform() const
-{
-    return DOMMatrix::create(state().transform.toTransformationMatrix(), DOMMatrixReadOnly::Is2D::Yes);
-}
-
-void CanvasRenderingContext2D::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
-{
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-
-    if (!std::isfinite(m11) | !std::isfinite(m21) | !std::isfinite(dx) | !std::isfinite(m12) | !std::isfinite(m22) | !std::isfinite(dy))
-        return;
-
-    resetTransform();
-    transform(m11, m12, m21, m22, dx, dy);
-}
-
-ExceptionOr<void> CanvasRenderingContext2D::setTransform(DOMMatrix2DInit&& matrixInit)
-{
-    auto checkValid = DOMMatrixReadOnly::validateAndFixup(matrixInit);
-    if (checkValid.hasException())
-        return checkValid.releaseException();
-
-    setTransform(matrixInit.a.value_or(1), matrixInit.b.value_or(0), matrixInit.c.value_or(0), matrixInit.d.value_or(1), matrixInit.e.value_or(0), matrixInit.f.value_or(0));
-    return { };
-}
-
-void CanvasRenderingContext2D::resetTransform()
-{
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return;
-
-    AffineTransform ctm = state().transform;
-    bool hasInvertibleTransform = state().hasInvertibleTransform;
-
-    realizeSaves();
-
-    c->setCTM(canvas().baseTransform());
-    modifiableState().transform = AffineTransform();
-
-    if (hasInvertibleTransform)
-        m_path.transform(ctm);
-
-    modifiableState().hasInvertibleTransform = true;
-}
-
-void CanvasRenderingContext2D::setStrokeColor(const String& color, std::optional<float> alpha)
-{
-    if (alpha) {
-        setStrokeStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha.value()));
-        return;
-    }
-
-    if (color == state().unparsedStrokeColor)
-        return;
-
-    realizeSaves();
-    setStrokeStyle(CanvasStyle::createFromString(color));
-    modifiableState().unparsedStrokeColor = color;
-}
-
-void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
-{
-    if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
-        return;
-    setStrokeStyle(CanvasStyle(grayLevel, alpha));
-}
-
-void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a)
-{
-    if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentRGBA(r, g, b, a))
-        return;
-    setStrokeStyle(CanvasStyle(r, g, b, a));
-}
-
-void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a)
-{
-    if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentCMYKA(c, m, y, k, a))
-        return;
-    setStrokeStyle(CanvasStyle(c, m, y, k, a));
-}
-
-void CanvasRenderingContext2D::setFillColor(const String& color, std::optional<float> alpha)
-{
-    if (alpha) {
-        setFillStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha.value()));
-        return;
-    }
-
-    if (color == state().unparsedFillColor)
-        return;
-
-    realizeSaves();
-    setFillStyle(CanvasStyle::createFromString(color));
-    modifiableState().unparsedFillColor = color;
-}
-
-void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
-{
-    if (state().fillStyle.isValid() && state().fillStyle.isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
-        return;
-    setFillStyle(CanvasStyle(grayLevel, alpha));
-}
-
-void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
-{
-    if (state().fillStyle.isValid() && state().fillStyle.isEquivalentRGBA(r, g, b, a))
-        return;
-    setFillStyle(CanvasStyle(r, g, b, a));
-}
-
-void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
-{
-    if (state().fillStyle.isValid() && state().fillStyle.isEquivalentCMYKA(c, m, y, k, a))
-        return;
-    setFillStyle(CanvasStyle(c, m, y, k, a));
-}
-
-void CanvasRenderingContext2D::beginPath()
-{
-    m_path.clear();
-}
-
-static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
-{
-    if (!std::isfinite(x) | !std::isfinite(y) | !std::isfinite(width) | !std::isfinite(height))
-        return false;
-
-    if (!width && !height)
-        return false;
-
-    if (width < 0) {
-        width = -width;
-        x -= width;
-    }
-
-    if (height < 0) {
-        height = -height;
-        y -= height;
-    }
-
-    return true;
-}
-
-inline void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode()
-{
-#if ENABLE(DASHBOARD_SUPPORT)
-    if (m_usesDashboardCompatibilityMode)
-        m_path.clear();
-#endif
-}
-
-static bool isFullCanvasCompositeMode(CompositeOperator op)
-{
-    // See 4.8.11.1.3 Compositing
-    // CompositeSourceAtop and CompositeDestinationOut are not listed here as the platforms already
-    // implement the specification's behavior.
-    return op == CompositeSourceIn || op == CompositeSourceOut || op == CompositeDestinationIn || op == CompositeDestinationAtop;
-}
-
-static WindRule toWindRule(CanvasFillRule rule)
-{
-    return rule == CanvasFillRule::Nonzero ? RULE_NONZERO : RULE_EVENODD;
-}
-
-void CanvasRenderingContext2D::fill(CanvasFillRule windingRule)
-{
-    fillInternal(m_path, windingRule);
-    clearPathForDashboardBackwardCompatibilityMode();
-}
-
-void CanvasRenderingContext2D::stroke()
-{
-    strokeInternal(m_path);
-    clearPathForDashboardBackwardCompatibilityMode();
-}
-
-void CanvasRenderingContext2D::clip(CanvasFillRule windingRule)
-{
-    clipInternal(m_path, windingRule);
-    clearPathForDashboardBackwardCompatibilityMode();
-}
-
-void CanvasRenderingContext2D::fill(Path2D& path, CanvasFillRule windingRule)
-{
-    fillInternal(path.path(), windingRule);
-}
-
-void CanvasRenderingContext2D::stroke(Path2D& path)
-{
-    strokeInternal(path.path());
-}
-
-void CanvasRenderingContext2D::clip(Path2D& path, CanvasFillRule windingRule)
-{
-    clipInternal(path.path(), windingRule);
-}
-
-void CanvasRenderingContext2D::fillInternal(const Path& path, CanvasFillRule windingRule)
-{
-    auto* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-
-    // If gradient size is zero, then paint nothing.
-    auto gradient = c->fillGradient();
-    if (gradient && gradient->isZeroSize())
-        return;
-
-    if (!path.isEmpty()) {
-        auto savedFillRule = c->fillRule();
-        c->setFillRule(toWindRule(windingRule));
-
-        if (isFullCanvasCompositeMode(state().globalComposite)) {
-            beginCompositeLayer();
-            c->fillPath(path);
-            endCompositeLayer();
-            didDrawEntireCanvas();
-        } else if (state().globalComposite == CompositeCopy) {
-            clearCanvas();
-            c->fillPath(path);
-            didDrawEntireCanvas();
-        } else {
-            c->fillPath(path);
-            didDraw(path.fastBoundingRect());
-        }
-        
-        c->setFillRule(savedFillRule);
-    }
-}
-
-void CanvasRenderingContext2D::strokeInternal(const Path& path)
-{
-    auto* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-
-    // If gradient size is zero, then paint nothing.
-    auto gradient = c->strokeGradient();
-    if (gradient && gradient->isZeroSize())
-        return;
-
-    if (!path.isEmpty()) {
-        if (isFullCanvasCompositeMode(state().globalComposite)) {
-            beginCompositeLayer();
-            c->strokePath(path);
-            endCompositeLayer();
-            didDrawEntireCanvas();
-        } else if (state().globalComposite == CompositeCopy) {
-            clearCanvas();
-            c->strokePath(path);
-            didDrawEntireCanvas();
-        } else {
-            FloatRect dirtyRect = path.fastBoundingRect();
-            inflateStrokeRect(dirtyRect);
-            c->strokePath(path);
-            didDraw(dirtyRect);
-        }
-    }
-}
-
-void CanvasRenderingContext2D::clipInternal(const Path& path, CanvasFillRule windingRule)
-{
-    auto* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-
-    realizeSaves();
-    c->canvasClip(path, toWindRule(windingRule));
-}
-
-inline void CanvasRenderingContext2D::beginCompositeLayer()
-{
-#if !USE(CAIRO)
-    drawingContext()->beginTransparencyLayer(1);
-#endif
-}
-
-inline void CanvasRenderingContext2D::endCompositeLayer()
-{
-#if !USE(CAIRO)
-    drawingContext()->endTransparencyLayer();    
-#endif
-}
-
-bool CanvasRenderingContext2D::isPointInPath(float x, float y, CanvasFillRule windingRule)
-{
-    return isPointInPathInternal(m_path, x, y, windingRule);
-}
-
-bool CanvasRenderingContext2D::isPointInStroke(float x, float y)
-{
-    return isPointInStrokeInternal(m_path, x, y);
-}
-
-bool CanvasRenderingContext2D::isPointInPath(Path2D& path, float x, float y, CanvasFillRule windingRule)
-{
-    return isPointInPathInternal(path.path(), x, y, windingRule);
-}
-
-bool CanvasRenderingContext2D::isPointInStroke(Path2D& path, float x, float y)
-{
-    return isPointInStrokeInternal(path.path(), x, y);
-}
-
-bool CanvasRenderingContext2D::isPointInPathInternal(const Path& path, float x, float y, CanvasFillRule windingRule)
-{
-    auto* c = drawingContext();
-    if (!c)
-        return false;
-    if (!state().hasInvertibleTransform)
-        return false;
-
-    auto transformedPoint = state().transform.inverse().value_or(AffineTransform()).mapPoint(FloatPoint(x, y));
-
-    if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
-        return false;
-
-    return path.contains(transformedPoint, toWindRule(windingRule));
-}
-
-bool CanvasRenderingContext2D::isPointInStrokeInternal(const Path& path, float x, float y)
-{
-    auto* c = drawingContext();
-    if (!c)
-        return false;
-    if (!state().hasInvertibleTransform)
-        return false;
-
-    auto transformedPoint = state().transform.inverse().value_or(AffineTransform()).mapPoint(FloatPoint(x, y));
-    if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
-        return false;
-
-    CanvasStrokeStyleApplier applier(this);
-    return path.strokeContains(&applier, transformedPoint);
-}
-
-void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
-{
-    if (!validateRectForCanvas(x, y, width, height))
-        return;
-    auto* context = drawingContext();
-    if (!context)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-    FloatRect rect(x, y, width, height);
-
-    bool saved = false;
-    if (shouldDrawShadows()) {
-        context->save();
-        saved = true;
-        context->setLegacyShadow(FloatSize(), 0, Color::transparent);
-    }
-    if (state().globalAlpha != 1) {
-        if (!saved) {
-            context->save();
-            saved = true;
-        }
-        context->setAlpha(1);
-    }
-    if (state().globalComposite != CompositeSourceOver) {
-        if (!saved) {
-            context->save();
-            saved = true;
-        }
-        context->setCompositeOperation(CompositeSourceOver);
-    }
-    context->clearRect(rect);
-    if (saved)
-        context->restore();
-    didDraw(rect);
-}
-
-void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
-{
-    if (!validateRectForCanvas(x, y, width, height))
-        return;
-
-    auto* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-
-    // from the HTML5 Canvas spec:
-    // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
-    // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
-    auto gradient = c->fillGradient();
-    if (gradient && gradient->isZeroSize())
-        return;
-
-    FloatRect rect(x, y, width, height);
-
-    if (rectContainsCanvas(rect)) {
-        c->fillRect(rect);
-        didDrawEntireCanvas();
-    } else if (isFullCanvasCompositeMode(state().globalComposite)) {
-        beginCompositeLayer();
-        c->fillRect(rect);
-        endCompositeLayer();
-        didDrawEntireCanvas();
-    } else if (state().globalComposite == CompositeCopy) {
-        clearCanvas();
-        c->fillRect(rect);
-        didDrawEntireCanvas();
-    } else {
-        c->fillRect(rect);
-        didDraw(rect);
-    }
-}
-
-void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height)
-{
-    if (!validateRectForCanvas(x, y, width, height))
-        return;
-
-    auto* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-    if (!(state().lineWidth >= 0))
-        return;
-
-    // If gradient size is zero, then paint nothing.
-    auto gradient = c->strokeGradient();
-    if (gradient && gradient->isZeroSize())
-        return;
-
-    FloatRect rect(x, y, width, height);
-    if (isFullCanvasCompositeMode(state().globalComposite)) {
-        beginCompositeLayer();
-        c->strokeRect(rect, state().lineWidth);
-        endCompositeLayer();
-        didDrawEntireCanvas();
-    } else if (state().globalComposite == CompositeCopy) {
-        clearCanvas();
-        c->strokeRect(rect, state().lineWidth);
-        didDrawEntireCanvas();
-    } else {
-        FloatRect boundingRect = rect;
-        boundingRect.inflate(state().lineWidth / 2);
-        c->strokeRect(rect, state().lineWidth);
-        didDraw(boundingRect);
-    }
-}
-
-void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& colorString, std::optional<float> alpha)
-{
-    Color color = Color::transparent;
-    if (!colorString.isNull()) {
-        color = parseColorOrCurrentColor(colorString, &canvas());
-        if (!color.isValid())
-            return;
-    }
-    // FIXME: Should not use RGBA32 here.
-    setShadow(FloatSize(width, height), blur, colorWithOverrideAlpha(color.rgb(), alpha));
-}
-
-void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha)
-{
-    setShadow(FloatSize(width, height), blur, Color(grayLevel, grayLevel, grayLevel, alpha));
-}
-
-void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a)
-{
-    setShadow(FloatSize(width, height), blur, Color(r, g, b, a));
-}
-
-void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
-{
-    setShadow(FloatSize(width, height), blur, Color(c, m, y, k, a));
-}
-
-void CanvasRenderingContext2D::clearShadow()
-{
-    setShadow(FloatSize(), 0, Color::transparent);
-}
-
-void CanvasRenderingContext2D::setShadow(const FloatSize& offset, float blur, const Color& color)
-{
-    if (state().shadowOffset == offset && state().shadowBlur == blur && state().shadowColor == color)
-        return;
-    bool wasDrawingShadows = shouldDrawShadows();
-    realizeSaves();
-    modifiableState().shadowOffset = offset;
-    modifiableState().shadowBlur = blur;
-    modifiableState().shadowColor = color;
-    if (!wasDrawingShadows && !shouldDrawShadows())
-        return;
-    applyShadow();
-}
-
-void CanvasRenderingContext2D::applyShadow()
-{
-    auto* c = drawingContext();
-    if (!c)
-        return;
-
-    if (shouldDrawShadows()) {
-        float width = state().shadowOffset.width();
-        float height = state().shadowOffset.height();
-        c->setLegacyShadow(FloatSize(width, -height), state().shadowBlur, state().shadowColor);
-    } else
-        c->setLegacyShadow(FloatSize(), 0, Color::transparent);
-}
-
-bool CanvasRenderingContext2D::shouldDrawShadows() const
-{
-    return state().shadowColor.isVisible() && (state().shadowBlur || !state().shadowOffset.isZero());
-}
-
-enum class ImageSizeType { AfterDevicePixelRatio, BeforeDevicePixelRatio };
-static LayoutSize size(HTMLImageElement& element, ImageSizeType sizeType = ImageSizeType::BeforeDevicePixelRatio)
-{
-    LayoutSize size;
-    if (auto* cachedImage = element.cachedImage()) {
-        size = cachedImage->imageSizeForRenderer(element.renderer(), 1.0f); // FIXME: Not sure about this.
-        if (sizeType == ImageSizeType::AfterDevicePixelRatio && is<RenderImage>(element.renderer()) && cachedImage->image() && !cachedImage->image()->hasRelativeWidth())
-            size.scale(downcast<RenderImage>(*element.renderer()).imageDevicePixelRatio());
-    }
-    return size;
-}
-
-static inline FloatSize size(HTMLCanvasElement& canvasElement)
-{
-    return canvasElement.size();
-}
-
-static inline FloatSize size(ImageBitmap& imageBitmap)
-{
-    return FloatSize { static_cast<float>(imageBitmap.width()), static_cast<float>(imageBitmap.height()) };
-}
-
-#if ENABLE(VIDEO)
-
-static inline FloatSize size(HTMLVideoElement& video)
-{
-    auto player = video.player();
-    if (!player)
-        return { };
-    return player->naturalSize();
-}
-
-#endif
-
-static inline FloatRect normalizeRect(const FloatRect& rect)
-{
-    return FloatRect(std::min(rect.x(), rect.maxX()),
-        std::min(rect.y(), rect.maxY()),
-        std::max(rect.width(), -rect.width()),
-        std::max(rect.height(), -rect.height()));
-}
-
-ExceptionOr<void> CanvasRenderingContext2D::drawImage(CanvasImageSource&& image, float dx, float dy)
-{
-    return WTF::switchOn(image,
-        [&] (RefPtr<HTMLImageElement>& imageElement) -> ExceptionOr<void> {
-            LayoutSize destRectSize = size(*imageElement, ImageSizeType::AfterDevicePixelRatio);
-            LayoutSize sourceRectSize = size(*imageElement, ImageSizeType::BeforeDevicePixelRatio);
-            return this->drawImage(*imageElement, FloatRect { 0, 0, sourceRectSize.width(), sourceRectSize.height() }, FloatRect { dx, dy, destRectSize.width(), destRectSize.height() });
-        },
-        [&] (auto& element) -> ExceptionOr<void> {
-            FloatSize elementSize = size(*element);
-            return this->drawImage(*element, FloatRect { 0, 0, elementSize.width(), elementSize.height() }, FloatRect { dx, dy, elementSize.width(), elementSize.height() });
-        }
-    );
-}
-
-ExceptionOr<void> CanvasRenderingContext2D::drawImage(CanvasImageSource&& image, float dx, float dy, float dw, float dh)
-{
-    return WTF::switchOn(image,
-        [&] (auto& element) -> ExceptionOr<void> {
-            FloatSize elementSize = size(*element);
-            return this->drawImage(*element, FloatRect { 0, 0, elementSize.width(), elementSize.height() }, FloatRect { dx, dy, dw, dh });
-        }
-    );
-}
-
-ExceptionOr<void> CanvasRenderingContext2D::drawImage(CanvasImageSource&& image, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh)
-{
-    return WTF::switchOn(image,
-        [&] (auto& element) -> ExceptionOr<void> {
-            return this->drawImage(*element, FloatRect { sx, sy, sw, sh }, FloatRect { dx, dy, dw, dh });
-        }
-    );
-}
-
-ExceptionOr<void> CanvasRenderingContext2D::drawImage(HTMLImageElement& imageElement, const FloatRect& srcRect, const FloatRect& dstRect)
-{
-    return drawImage(imageElement, srcRect, dstRect, state().globalComposite, state().globalBlend);
-}
-
-ExceptionOr<void> CanvasRenderingContext2D::drawImage(HTMLImageElement& imageElement, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator& op, const BlendMode& blendMode)
-{
-    if (!std::isfinite(dstRect.x()) || !std::isfinite(dstRect.y()) || !std::isfinite(dstRect.width()) || !std::isfinite(dstRect.height())
-        || !std::isfinite(srcRect.x()) || !std::isfinite(srcRect.y()) || !std::isfinite(srcRect.width()) || !std::isfinite(srcRect.height()))
-        return { };
-
-    if (!dstRect.width() || !dstRect.height())
-        return { };
-
-    if (!imageElement.complete())
-        return { };
-
-    FloatRect normalizedSrcRect = normalizeRect(srcRect);
-    FloatRect normalizedDstRect = normalizeRect(dstRect);
-
-    FloatRect imageRect = FloatRect(FloatPoint(), size(imageElement, ImageSizeType::BeforeDevicePixelRatio));
-    if (!srcRect.width() || !srcRect.height())
-        return Exception { IndexSizeError };
-
-    // When the source rectangle is outside the source image, the source rectangle must be clipped
-    // to the source image and the destination rectangle must be clipped in the same proportion.
-    FloatRect originalNormalizedSrcRect = normalizedSrcRect;
-    normalizedSrcRect.intersect(imageRect);
-    if (normalizedSrcRect.isEmpty())
-        return { };
-
-    if (normalizedSrcRect != originalNormalizedSrcRect) {
-        normalizedDstRect.setWidth(normalizedDstRect.width() * normalizedSrcRect.width() / originalNormalizedSrcRect.width());
-        normalizedDstRect.setHeight(normalizedDstRect.height() * normalizedSrcRect.height() / originalNormalizedSrcRect.height());
-        if (normalizedDstRect.isEmpty())
-            return { };
-    }
-
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return { };
-    if (!state().hasInvertibleTransform)
-        return { };
-
-    CachedImage* cachedImage = imageElement.cachedImage();
-    if (!cachedImage)
-        return { };
-
-    RefPtr<Image> image = cachedImage->imageForRenderer(imageElement.renderer());
-    if (!image)
-        return { };
-
-    ImageObserver* observer = image->imageObserver();
-
-    if (image->isSVGImage()) {
-        image->setImageObserver(nullptr);
-        image->setContainerSize(imageRect.size());
-    }
-
-    if (image->isBitmapImage())
-        downcast<BitmapImage>(*image).updateFromSettings(imageElement.document().settings());
-
-    if (rectContainsCanvas(normalizedDstRect)) {
-        c->drawImage(*image, normalizedDstRect, normalizedSrcRect, ImagePaintingOptions(op, blendMode));
-        didDrawEntireCanvas();
-    } else if (isFullCanvasCompositeMode(op)) {
-        fullCanvasCompositedDrawImage(*image, normalizedDstRect, normalizedSrcRect, op);
-        didDrawEntireCanvas();
-    } else if (op == CompositeCopy) {
-        clearCanvas();
-        c->drawImage(*image, normalizedDstRect, normalizedSrcRect, ImagePaintingOptions(op, blendMode));
-        didDrawEntireCanvas();
-    } else {
-        c->drawImage(*image, normalizedDstRect, normalizedSrcRect, ImagePaintingOptions(op, blendMode));
-        didDraw(normalizedDstRect);
-    }
-    
-    if (image->isSVGImage())
-        image->setImageObserver(observer);
-
-    checkOrigin(&imageElement);
-
-    return { };
-}
-
-ExceptionOr<void> CanvasRenderingContext2D::drawImage(HTMLCanvasElement& sourceCanvas, const FloatRect& srcRect, const FloatRect& dstRect)
-{
-    FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas.size());
-
-    if (!srcCanvasRect.width() || !srcCanvasRect.height())
-        return Exception { InvalidStateError };
-
-    if (!srcRect.width() || !srcRect.height())
-        return Exception { IndexSizeError };
-
-    if (!srcCanvasRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
-        return { };
-
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return { };
-    if (!state().hasInvertibleTransform)
-        return { };
-
-    // FIXME: Do this through platform-independent GraphicsContext API.
-    ImageBuffer* buffer = sourceCanvas.buffer();
-    if (!buffer)
-        return { };
-
-    checkOrigin(&sourceCanvas);
-
-#if ENABLE(ACCELERATED_2D_CANVAS)
-    // If we're drawing from one accelerated canvas 2d to another, avoid calling sourceCanvas.makeRenderingResultsAvailable()
-    // as that will do a readback to software.
-    RefPtr<CanvasRenderingContext> sourceContext = sourceCanvas.renderingContext();
-    // FIXME: Implement an accelerated path for drawing from a WebGL canvas to a 2d canvas when possible.
-    if (!isAccelerated() || !sourceContext || !sourceContext->isAccelerated() || !sourceContext->is2d())
-        sourceCanvas.makeRenderingResultsAvailable();
-#else
-    sourceCanvas.makeRenderingResultsAvailable();
-#endif
-
-    if (rectContainsCanvas(dstRect)) {
-        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
-        didDrawEntireCanvas();
-    } else if (isFullCanvasCompositeMode(state().globalComposite)) {
-        fullCanvasCompositedDrawImage(*buffer, dstRect, srcRect, state().globalComposite);
-        didDrawEntireCanvas();
-    } else if (state().globalComposite == CompositeCopy) {
-        clearCanvas();
-        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
-        didDrawEntireCanvas();
-    } else {
-        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
-        didDraw(dstRect);
-    }
-
-    return { };
-}
-
-#if ENABLE(VIDEO)
-
-ExceptionOr<void> CanvasRenderingContext2D::drawImage(HTMLVideoElement& video, const FloatRect& srcRect, const FloatRect& dstRect)
-{
-    if (video.readyState() == HTMLMediaElement::HAVE_NOTHING || video.readyState() == HTMLMediaElement::HAVE_METADATA)
-        return { };
-
-    FloatRect videoRect = FloatRect(FloatPoint(), size(video));
-    if (!srcRect.width() || !srcRect.height())
-        return Exception { IndexSizeError };
-
-    if (!videoRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
-        return { };
-
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return { };
-    if (!state().hasInvertibleTransform)
-        return { };
-
-    checkOrigin(&video);
-
-#if USE(CG) || (ENABLE(ACCELERATED_2D_CANVAS) && USE(GSTREAMER_GL) && USE(CAIRO))
-    if (NativeImagePtr image = video.nativeImageForCurrentTime()) {
-        c->drawNativeImage(image, FloatSize(video.videoWidth(), video.videoHeight()), dstRect, srcRect);
-        if (rectContainsCanvas(dstRect))
-            didDrawEntireCanvas();
-        else
-            didDraw(dstRect);
-
-        return { };
-    }
-#endif
-
-    GraphicsContextStateSaver stateSaver(*c);
-    c->clip(dstRect);
-    c->translate(dstRect.location());
-    c->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height()));
-    c->translate(-srcRect.location());
-    video.paintCurrentFrameInContext(*c, FloatRect(FloatPoint(), size(video)));
-    stateSaver.restore();
-    didDraw(dstRect);
-
-    return { };
-}
-
-#endif
-
-ExceptionOr<void> CanvasRenderingContext2D::drawImage(ImageBitmap& imageBitmap, const FloatRect& srcRect, const FloatRect& dstRect)
-{
-    if (!imageBitmap.width() || !imageBitmap.height())
-        return Exception { InvalidStateError };
-
-    if (!srcRect.width() || !srcRect.height())
-        return Exception { IndexSizeError };
-
-    FloatRect srcBitmapRect = FloatRect(FloatPoint(), FloatSize(imageBitmap.width(), imageBitmap.height()));
-
-    if (!srcBitmapRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
-        return { };
-
-    GraphicsContext* c = drawingContext();
-    if (!c)
-        return { };
-    if (!state().hasInvertibleTransform)
-        return { };
-
-    ImageBuffer* buffer = imageBitmap.buffer();
-    if (!buffer)
-        return { };
-
-    checkOrigin(&imageBitmap);
-
-    if (rectContainsCanvas(dstRect)) {
-        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
-        didDrawEntireCanvas();
-    } else if (isFullCanvasCompositeMode(state().globalComposite)) {
-        fullCanvasCompositedDrawImage(*buffer, dstRect, srcRect, state().globalComposite);
-        didDrawEntireCanvas();
-    } else if (state().globalComposite == CompositeCopy) {
-        clearCanvas();
-        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
-        didDrawEntireCanvas();
-    } else {
-        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
-        didDraw(dstRect);
-    }
-
-    return { };
-}
-
-void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement& imageElement, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, const String& compositeOperation)
-{
-    CompositeOperator op;
-    auto blendOp = BlendModeNormal;
-    if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blendOp != BlendModeNormal)
-        op = CompositeSourceOver;
-    drawImage(imageElement, FloatRect { sx, sy, sw, sh }, FloatRect { dx, dy, dw, dh }, op, BlendModeNormal);
-}
-
-void CanvasRenderingContext2D::clearCanvas()
-{
-    auto* c = drawingContext();
-    if (!c)
-        return;
-
-    c->save();
-    c->setCTM(canvas().baseTransform());
-    c->clearRect(FloatRect(0, 0, canvas().width(), canvas().height()));
-    c->restore();
-}
-
-Path CanvasRenderingContext2D::transformAreaToDevice(const Path& path) const
-{
-    Path transformed(path);
-    transformed.transform(state().transform);
-    transformed.transform(canvas().baseTransform());
-    return transformed;
-}
-
-Path CanvasRenderingContext2D::transformAreaToDevice(const FloatRect& rect) const
-{
-    Path path;
-    path.addRect(rect);
-    return transformAreaToDevice(path);
-}
-
-bool CanvasRenderingContext2D::rectContainsCanvas(const FloatRect& rect) const
-{
-    FloatQuad quad(rect);
-    FloatQuad canvasQuad(FloatRect(0, 0, canvas().width(), canvas().height()));
-    return state().transform.mapQuad(quad).containsQuad(canvasQuad);
-}
-
-template<class T> IntRect CanvasRenderingContext2D::calculateCompositingBufferRect(const T& area, IntSize* croppedOffset)
-{
-    IntRect canvasRect(0, 0, canvas().width(), canvas().height());
-    canvasRect = canvas().baseTransform().mapRect(canvasRect);
-    Path path = transformAreaToDevice(area);
-    IntRect bufferRect = enclosingIntRect(path.fastBoundingRect());
-    IntPoint originalLocation = bufferRect.location();
-    bufferRect.intersect(canvasRect);
-    if (croppedOffset)
-        *croppedOffset = originalLocation - bufferRect.location();
-    return bufferRect;
-}
-
-std::unique_ptr<ImageBuffer> CanvasRenderingContext2D::createCompositingBuffer(const IntRect& bufferRect)
-{
-    return ImageBuffer::create(bufferRect.size(), isAccelerated() ? Accelerated : Unaccelerated);
-}
-
-void CanvasRenderingContext2D::compositeBuffer(ImageBuffer& buffer, const IntRect& bufferRect, CompositeOperator op)
-{
-    IntRect canvasRect(0, 0, canvas().width(), canvas().height());
-    canvasRect = canvas().baseTransform().mapRect(canvasRect);
-
-    auto* c = drawingContext();
-    if (!c)
-        return;
-
-    c->save();
-    c->setCTM(AffineTransform());
-    c->setCompositeOperation(op);
-
-    c->save();
-    c->clipOut(bufferRect);
-    c->clearRect(canvasRect);
-    c->restore();
-    c->drawImageBuffer(buffer, bufferRect.location(), state().globalComposite);
-    c->restore();
-}
-
-static void drawImageToContext(Image& image, GraphicsContext& context, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
-{
-    context.drawImage(image, dest, src, op);
-}
-
-static void drawImageToContext(ImageBuffer& imageBuffer, GraphicsContext& context, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
-{
-    context.drawImageBuffer(imageBuffer, dest, src, op);
-}
-
-template<class T> void CanvasRenderingContext2D::fullCanvasCompositedDrawImage(T& image, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
-{
-    ASSERT(isFullCanvasCompositeMode(op));
-
-    IntSize croppedOffset;
-    auto bufferRect = calculateCompositingBufferRect(dest, &croppedOffset);
-    if (bufferRect.isEmpty()) {
-        clearCanvas();
-        return;
-    }
-
-    auto buffer = createCompositingBuffer(bufferRect);
-    if (!buffer)
-        return;
-
-    auto* c = drawingContext();
-    if (!c)
-        return;
-
-    FloatRect adjustedDest = dest;
-    adjustedDest.setLocation(FloatPoint(0, 0));
-    AffineTransform effectiveTransform = c->getCTM();
-    IntRect transformedAdjustedRect = enclosingIntRect(effectiveTransform.mapRect(adjustedDest));
-    buffer->context().translate(-transformedAdjustedRect.location());
-    buffer->context().translate(croppedOffset);
-    buffer->context().concatCTM(effectiveTransform);
-    drawImageToContext(image, buffer->context(), adjustedDest, src, CompositeSourceOver);
-
-    compositeBuffer(*buffer, bufferRect, op);
-}
-
-void CanvasRenderingContext2D::prepareGradientForDashboard(CanvasGradient& gradient) const
-{
-#if ENABLE(DASHBOARD_SUPPORT)
-    if (m_usesDashboardCompatibilityMode)
-        gradient.setDashboardCompatibilityMode();
-#else
-    UNUSED_PARAM(gradient);
-#endif
-}
-
-static CanvasRenderingContext2D::Style toStyle(const CanvasStyle& style)
-{
-    if (auto gradient = style.canvasGradient())
-        return gradient;
-    if (auto pattern = style.canvasPattern())
-        return pattern;
-    return style.color();
-}
-
-CanvasRenderingContext2D::Style CanvasRenderingContext2D::strokeStyle() const
-{
-    return toStyle(state().strokeStyle);
-}
-
-void CanvasRenderingContext2D::setStrokeStyle(CanvasRenderingContext2D::Style&& style)
-{
-    WTF::switchOn(style,
-        [this] (const String& string) { this->setStrokeColor(string); },
-        [this] (const RefPtr<CanvasGradient>& gradient) { this->setStrokeStyle(CanvasStyle(*gradient)); },
-        [this] (const RefPtr<CanvasPattern>& pattern) { this->setStrokeStyle(CanvasStyle(*pattern)); }
-    );
-}
-
-CanvasRenderingContext2D::Style CanvasRenderingContext2D::fillStyle() const
-{
-    return toStyle(state().fillStyle);
-}
-
-void CanvasRenderingContext2D::setFillStyle(CanvasRenderingContext2D::Style&& style)
-{
-    WTF::switchOn(style,
-        [this] (const String& string) { this->setFillColor(string); },
-        [this] (const RefPtr<CanvasGradient>& gradient) { this->setFillStyle(CanvasStyle(*gradient)); },
-        [this] (const RefPtr<CanvasPattern>& pattern) { this->setFillStyle(CanvasStyle(*pattern)); }
-    );
-}
-
-ExceptionOr<Ref<CanvasGradient>> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1)
-{
-    if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(x1) || !std::isfinite(y1))
-        return Exception { NotSupportedError };
-
-    auto gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
-    prepareGradientForDashboard(gradient.get());
-    return WTFMove(gradient);
-}
-
-ExceptionOr<Ref<CanvasGradient>> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1)
-{
-    if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(r0) || !std::isfinite(x1) || !std::isfinite(y1) || !std::isfinite(r1))
-        return Exception { NotSupportedError };
-
-    if (r0 < 0 || r1 < 0)
-        return Exception { IndexSizeError };
-
-    auto gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
-    prepareGradientForDashboard(gradient.get());
-    return WTFMove(gradient);
-}
-
-ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2D::createPattern(CanvasImageSource&& image, const String& repetition)
-{
-    bool repeatX, repeatY;
-    if (!CanvasPattern::parseRepetitionType(repetition, repeatX, repeatY))
-        return Exception { SyntaxError };
-
-    return WTF::switchOn(image,
-        [&] (auto& element) -> ExceptionOr<RefPtr<CanvasPattern>> { return this->createPattern(*element, repeatX, repeatY); }
-    );
-}
-
-ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2D::createPattern(HTMLImageElement& imageElement, bool repeatX, bool repeatY)
-{
-    auto* cachedImage = imageElement.cachedImage();
-
-    // If the image loading hasn't started or the image is not complete, it is not fully decodable.
-    if (!cachedImage || !imageElement.complete())
-        return nullptr;
-
-    if (cachedImage->status() == CachedResource::LoadError)
-        return Exception { InvalidStateError };
-
-    bool originClean = cachedImage->isOriginClean(canvas().securityOrigin());
-
-    // FIXME: SVG images with animations can switch between clean and dirty (leaking cross-origin
-    // data). We should either:
-    //   1) Take a fixed snapshot of an SVG image when creating a pattern and determine then whether
-    //      the origin is clean.
-    //   2) Dynamically verify the origin checks at draw time, and dirty the canvas accordingly.
-    // To be on the safe side, taint the origin for all patterns containing SVG images for now.
-    if (cachedImage->image()->isSVGImage())
-        originClean = false;
-
-    return RefPtr<CanvasPattern> { CanvasPattern::create(*cachedImage->imageForRenderer(imageElement.renderer()), repeatX, repeatY, originClean) };
-}
-
-ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2D::createPattern(HTMLCanvasElement& canvas, bool repeatX, bool repeatY)
-{
-    if (!canvas.width() || !canvas.height() || !canvas.buffer())
-        return Exception { InvalidStateError };
-
-    return RefPtr<CanvasPattern> { CanvasPattern::create(*canvas.copiedImage(), repeatX, repeatY, canvas.originClean()) };
-}
-    
-#if ENABLE(VIDEO)
-
-ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2D::createPattern(HTMLVideoElement& videoElement, bool repeatX, bool repeatY)
-{
-    if (videoElement.readyState() < HTMLMediaElement::HAVE_CURRENT_DATA)
-        return nullptr;
-    
-    checkOrigin(&videoElement);
-    bool originClean = canvas().originClean();
-
-#if USE(CG) || (ENABLE(ACCELERATED_2D_CANVAS) && USE(GSTREAMER_GL) && USE(CAIRO))
-    if (auto nativeImage = videoElement.nativeImageForCurrentTime())
-        return RefPtr<CanvasPattern> { CanvasPattern::create(BitmapImage::create(WTFMove(nativeImage)), repeatX, repeatY, originClean) };
-#endif
-
-    auto imageBuffer = ImageBuffer::create(size(videoElement), drawingContext() ? drawingContext()->renderingMode() : Accelerated);
-    videoElement.paintCurrentFrameInContext(imageBuffer->context(), FloatRect(FloatPoint(), size(videoElement)));
-    
-    return RefPtr<CanvasPattern> { CanvasPattern::create(ImageBuffer::sinkIntoImage(WTFMove(imageBuffer), Unscaled).releaseNonNull(), repeatX, repeatY, originClean) };
-}
-
-#endif
-
-ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2D::createPattern(ImageBitmap&, bool, bool)
-{
-    // FIXME: Implement.
-    return Exception { TypeError };
-}
-
-void CanvasRenderingContext2D::didDrawEntireCanvas()
-{
-    didDraw(FloatRect(FloatPoint::zero(), canvas().size()), CanvasDidDrawApplyClip);
-}
-
-void CanvasRenderingContext2D::didDraw(const FloatRect& r, unsigned options)
-{
-    auto* c = drawingContext();
-    if (!c)
-        return;
-    if (!state().hasInvertibleTransform)
-        return;
-
-#if ENABLE(ACCELERATED_2D_CANVAS)
-    // If we are drawing to hardware and we have a composited layer, just call contentChanged().
-    if (isAccelerated()) {
-        RenderBox* renderBox = canvas().renderBox();
-        if (renderBox && renderBox->hasAcceleratedCompositing()) {
-            renderBox->contentChanged(CanvasPixelsChanged);
-            canvas().clearCopiedImage();
-            canvas().notifyObserversCanvasChanged(r);
-            return;
-        }
-    }
-#endif
-
-    FloatRect dirtyRect = r;
-    if (options & CanvasDidDrawApplyTransform) {
-        AffineTransform ctm = state().transform;
-        dirtyRect = ctm.mapRect(r);
-    }
-
-    if (options & CanvasDidDrawApplyShadow && state().shadowColor.isVisible()) {
-        // The shadow gets applied after transformation
-        FloatRect shadowRect(dirtyRect);
-        shadowRect.move(state().shadowOffset);
-        shadowRect.inflate(state().shadowBlur);
-        dirtyRect.unite(shadowRect);
-    }
-
-    if (options & CanvasDidDrawApplyClip) {
-        // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
-        // back out of the GraphicsContext, so to take clip into account for incremental painting,
-        // we'd have to keep the clip path around.
-    }
-
-    canvas().didDraw(dirtyRect);
-}
-
-void CanvasRenderingContext2D::setTracksDisplayListReplay(bool tracksDisplayListReplay)
-{
-    if (tracksDisplayListReplay == m_tracksDisplayListReplay)
-        return;
-
-    m_tracksDisplayListReplay = tracksDisplayListReplay;
-    if (!m_tracksDisplayListReplay)
-        contextDisplayListMap().remove(this);
-}
-
-String CanvasRenderingContext2D::displayListAsText(DisplayList::AsTextFlags flags) const
-{
-    if (!m_recordingContext)
-        return { };
-    return m_recordingContext->displayList.asText(flags);
-}
-
-String CanvasRenderingContext2D::replayDisplayListAsText(DisplayList::AsTextFlags flags) const
-{
-    auto* displayList = contextDisplayListMap().get(this);
-    if (!displayList)
-        return { };
-    return displayList->asText(flags);
-}
-
-void CanvasRenderingContext2D::paintRenderingResultsToCanvas()
-{
-    if (UNLIKELY(m_usesDisplayListDrawing)) {
-        if (!m_recordingContext)
-            return;
-
-        FloatRect clip(FloatPoint::zero(), canvas().size());
-        DisplayList::Replayer replayer(*canvas().drawingContext(), m_recordingContext->displayList);
-
-        if (UNLIKELY(m_tracksDisplayListReplay)) {
-            auto replayList = replayer.replay(clip, m_tracksDisplayListReplay);
-            contextDisplayListMap().add(this, WTFMove(replayList));
-        } else
-            replayer.replay(clip);
-
-        m_recordingContext->displayList.clear();
-    }
-}
-
-GraphicsContext* CanvasRenderingContext2D::drawingContext() const
-{
-    if (UNLIKELY(m_usesDisplayListDrawing)) {
-        if (!m_recordingContext)
-            m_recordingContext = std::make_unique<DisplayListDrawingContext>(FloatRect(FloatPoint::zero(), canvas().size()));
-        return &m_recordingContext->context;
-    }
-
-    return canvas().drawingContext();
-}
-
-static RefPtr<ImageData> createEmptyImageData(const IntSize& size)
-{
-    auto data = ImageData::create(size);
-    if (data)
-        data->data()->zeroFill();
-    return data;
-}
-
-ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2D::createImageData(ImageData* imageData) const
-{
-    if (!imageData)
-        return Exception { NotSupportedError };
-
-    return createEmptyImageData(imageData->size());
-}
-
-ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2D::createImageData(float sw, float sh) const
-{
-    if (!sw || !sh)
-        return Exception { IndexSizeError };
-
-    FloatSize logicalSize(std::abs(sw), std::abs(sh));
-    if (!logicalSize.isExpressibleAsIntSize())
-        return nullptr;
-
-    IntSize size = expandedIntSize(logicalSize);
-    if (size.width() < 1)
-        size.setWidth(1);
-    if (size.height() < 1)
-        size.setHeight(1);
-
-    return createEmptyImageData(size);
-}
-
-ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh) const
-{
-    return getImageData(ImageBuffer::LogicalCoordinateSystem, sx, sy, sw, sh);
-}
-
-ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2D::getImageData(ImageBuffer::CoordinateSystem coordinateSystem, float sx, float sy, float sw, float sh) const
-{
-    if (!canvas().originClean()) {
-        static NeverDestroyed<String> consoleMessage(MAKE_STATIC_STRING_IMPL("Unable to get image data from canvas because the canvas has been tainted by cross-origin data."));
-        canvas().document().addConsoleMessage(MessageSource::Security, MessageLevel::Error, consoleMessage);
-        return Exception { SecurityError };
-    }
-
-    if (!sw || !sh)
-        return Exception { IndexSizeError };
-
-    if (sw < 0) {
-        sx += sw;
-        sw = -sw;
-    }    
-    if (sh < 0) {
-        sy += sh;
-        sh = -sh;
-    }
-
-    FloatRect logicalRect(sx, sy, sw, sh);
-    if (logicalRect.width() < 1)
-        logicalRect.setWidth(1);
-    if (logicalRect.height() < 1)
-        logicalRect.setHeight(1);
-    if (!logicalRect.isExpressibleAsIntRect())
-        return nullptr;
-
-    IntRect imageDataRect = enclosingIntRect(logicalRect);
-    ImageBuffer* buffer = canvas().buffer();
-    if (!buffer)
-        return createEmptyImageData(imageDataRect.size());
-
-    auto byteArray = buffer->getUnmultipliedImageData(imageDataRect, nullptr, coordinateSystem);
-    if (!byteArray) {
-        StringBuilder consoleMessage;
-        consoleMessage.appendLiteral("Unable to get image data from canvas. Requested size was ");
-        consoleMessage.appendNumber(imageDataRect.width());
-        consoleMessage.appendLiteral(" x ");
-        consoleMessage.appendNumber(imageDataRect.height());
-
-        canvas().document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, consoleMessage.toString());
-        return Exception { InvalidStateError };
-    }
-
-    return ImageData::create(imageDataRect.size(), byteArray.releaseNonNull());
-}
-
-void CanvasRenderingContext2D::putImageData(ImageData& data, float dx, float dy)
-{
-    putImageData(data, dx, dy, 0, 0, data.width(), data.height());
-}
-
-void CanvasRenderingContext2D::putImageData(ImageData& data, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight)
-{
-    putImageData(data, ImageBuffer::LogicalCoordinateSystem, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
-}
-
</del><span class="cx"> void CanvasRenderingContext2D::drawFocusIfNeeded(Element& element)
</span><span class="cx"> {
</span><span class="cx">     drawFocusIfNeededInternal(m_path, element);
</span><span class="lines">@@ -2198,47 +92,10 @@
</span><span class="cx">     context->drawFocusRing(path, 1, 1, RenderTheme::focusRingColor());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CanvasRenderingContext2D::putImageData(ImageData& data, ImageBuffer::CoordinateSystem coordinateSystem, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight)
-{
-    ImageBuffer* buffer = canvas().buffer();
-    if (!buffer)
-        return;
-
-    if (!data.data())
-        return;
-
-    if (dirtyWidth < 0) {
-        dirtyX += dirtyWidth;
-        dirtyWidth = -dirtyWidth;
-    }
-
-    if (dirtyHeight < 0) {
-        dirtyY += dirtyHeight;
-        dirtyHeight = -dirtyHeight;
-    }
-
-    FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
-    clipRect.intersect(IntRect(0, 0, data.width(), data.height()));
-    IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
-    IntRect destRect = enclosingIntRect(clipRect);
-    destRect.move(destOffset);
-    destRect.intersect(IntRect(IntPoint(), coordinateSystem == ImageBuffer::LogicalCoordinateSystem ? buffer->logicalSize() : buffer->internalSize()));
-    if (destRect.isEmpty())
-        return;
-    IntRect sourceRect(destRect);
-    sourceRect.move(-destOffset);
-    sourceRect.intersect(IntRect(0, 0, data.width(), data.height()));
-
-    if (!sourceRect.isEmpty())
-        buffer->putByteArray(*data.data(), AlphaPremultiplication::Unpremultiplied, IntSize(data.width(), data.height()), sourceRect, IntPoint(destOffset), coordinateSystem);
-
-    didDraw(destRect, CanvasDidDrawApplyNone); // ignore transform, shadow and clip
-}
-
</del><span class="cx"> String CanvasRenderingContext2D::font() const
</span><span class="cx"> {
</span><span class="cx">     if (!state().font.realized())
</span><del>-        return defaultFont;
</del><ins>+        return DefaultFont;
</ins><span class="cx"> 
</span><span class="cx">     StringBuilder serializedFont;
</span><span class="cx">     const auto& fontDescription = state().font.fontDescription();
</span><span class="lines">@@ -2301,9 +158,9 @@
</span><span class="cx">         newStyle->setFontDescription(computedStyle->fontDescription());
</span><span class="cx">     else {
</span><span class="cx">         FontCascadeDescription defaultFontDescription;
</span><del>-        defaultFontDescription.setOneFamily(defaultFontFamily);
-        defaultFontDescription.setSpecifiedSize(defaultFontSize);
-        defaultFontDescription.setComputedSize(defaultFontSize);
</del><ins>+        defaultFontDescription.setOneFamily(DefaultFontFamily);
+        defaultFontDescription.setSpecifiedSize(DefaultFontSize);
+        defaultFontDescription.setComputedSize(DefaultFontSize);
</ins><span class="cx"> 
</span><span class="cx">         newStyle->setFontDescription(defaultFontDescription);
</span><span class="cx">     }
</span><span class="lines">@@ -2547,6 +404,14 @@
</span><span class="cx">     return metrics;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+auto CanvasRenderingContext2D::fontProxy() -> const FontProxy& {
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    canvas.document().updateStyleIfNeeded();
+    if (!state().font.realized())
+        setFont(state().unparsedFont);
+    return state().font;
+}
+
</ins><span class="cx"> FloatPoint CanvasRenderingContext2D::textOffset(float width, TextDirection direction)
</span><span class="cx"> {
</span><span class="cx">     auto& fontMetrics = fontProxy().fontMetrics();
</span><span class="lines">@@ -2728,97 +593,4 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CanvasRenderingContext2D::inflateStrokeRect(FloatRect& rect) const
-{
-    // Fast approximation of the stroke's bounding rect.
-    // This yields a slightly oversized rect but is very fast
-    // compared to Path::strokeBoundingRect().
-    static const float root2 = sqrtf(2);
-    float delta = state().lineWidth / 2;
-    if (state().lineJoin == MiterJoin)
-        delta *= state().miterLimit;
-    else if (state().lineCap == SquareCap)
-        delta *= root2;
-    rect.inflate(delta);
-}
-
-auto CanvasRenderingContext2D::fontProxy() -> const FontProxy&
-{
-    canvas().document().updateStyleIfNeeded();
-    if (!state().font.realized())
-        setFont(state().unparsedFont);
-    return state().font;
-}
-
-#if ENABLE(ACCELERATED_2D_CANVAS)
-
-PlatformLayer* CanvasRenderingContext2D::platformLayer() const
-{
-    return canvas().buffer() ? canvas().buffer()->platformLayer() : nullptr;
-}
-
-#endif
-
-static inline InterpolationQuality smoothingToInterpolationQuality(ImageSmoothingQuality quality)
-{
-    switch (quality) {
-    case ImageSmoothingQuality::Low:
-        return InterpolationLow;
-    case ImageSmoothingQuality::Medium:
-        return InterpolationMedium;
-    case ImageSmoothingQuality::High:
-        return InterpolationHigh;
-    }
-
-    ASSERT_NOT_REACHED();
-    return InterpolationLow;
-};
-
-auto CanvasRenderingContext2D::imageSmoothingQuality() const -> ImageSmoothingQuality
-{
-    return state().imageSmoothingQuality;
-}
-
-void CanvasRenderingContext2D::setImageSmoothingQuality(ImageSmoothingQuality quality)
-{
-    if (quality == state().imageSmoothingQuality)
-        return;
-
-    realizeSaves();
-    modifiableState().imageSmoothingQuality = quality;
-
-    if (!state().imageSmoothingEnabled)
-        return;
-
-    if (auto* context = drawingContext())
-        context->setImageInterpolationQuality(smoothingToInterpolationQuality(quality));
-}
-
-bool CanvasRenderingContext2D::imageSmoothingEnabled() const
-{
-    return state().imageSmoothingEnabled;
-}
-
-void CanvasRenderingContext2D::setImageSmoothingEnabled(bool enabled)
-{
-    if (enabled == state().imageSmoothingEnabled)
-        return;
-
-    realizeSaves();
-    modifiableState().imageSmoothingEnabled = enabled;
-    auto* c = drawingContext();
-    if (c)
-        c->setImageInterpolationQuality(enabled ? smoothingToInterpolationQuality(state().imageSmoothingQuality) : InterpolationNone);
-}
-
-void CanvasRenderingContext2D::setPath(Path2D& path)
-{
-    m_path = path.path();
-}
-
-Ref<Path2D> CanvasRenderingContext2D::getPath() const
-{
-    return Path2D::create(m_path);
-}
-
</del><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlcanvasCanvasRenderingContext2Dh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h (225815 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h      2017-12-12 23:13:37 UTC (rev 225815)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h 2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -25,53 +25,17 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><del>-#include "AffineTransform.h"
-#include "CanvasDirection.h"
-#include "CanvasFillRule.h"
-#include "CanvasLineCap.h"
-#include "CanvasLineJoin.h"
-#include "CanvasPath.h"
-#include "CanvasRenderingContext.h"
-#include "CanvasStyle.h"
</del><ins>+#include "CanvasRenderingContext2DBase.h"
</ins><span class="cx"> #include "CanvasTextAlign.h"
</span><span class="cx"> #include "CanvasTextBaseline.h"
</span><del>-#include "Color.h"
-#include "FloatSize.h"
</del><span class="cx"> #include "FontCascade.h"
</span><span class="cx"> #include "FontSelectorClient.h"
</span><del>-#include "GraphicsContext.h"
-#include "GraphicsTypes.h"
-#include "ImageBuffer.h"
-#include "ImageSmoothingQuality.h"
-#include "Path.h"
-#include "PlatformLayer.h"
-#include <wtf/Vector.h>
-#include <wtf/text/WTFString.h>
</del><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-class CanvasBase;
-class CanvasGradient;
-class CanvasPattern;
-class DOMMatrix;
-class FloatRect;
-class GraphicsContext;
-class HTMLImageElement;
-class HTMLVideoElement;
-class ImageBitmap;
-class ImageData;
-class Path2D;
</del><span class="cx"> class TextMetrics;
</span><span class="cx"> 
</span><del>-struct DOMMatrix2DInit;
-
-#if ENABLE(VIDEO)
-using CanvasImageSource = Variant<RefPtr<HTMLImageElement>, RefPtr<HTMLVideoElement>, RefPtr<HTMLCanvasElement>, RefPtr<ImageBitmap>>;
-#else
-using CanvasImageSource = Variant<RefPtr<HTMLImageElement>, RefPtr<HTMLCanvasElement>, RefPtr<ImageBitmap>>;
-#endif
-
-class CanvasRenderingContext2D final : public CanvasRenderingContext, public CanvasPath {
</del><ins>+class CanvasRenderingContext2D final : public CanvasRenderingContext2DBase {
</ins><span class="cx"> public:
</span><span class="cx">     CanvasRenderingContext2D(CanvasBase&, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode);
</span><span class="cx">     virtual ~CanvasRenderingContext2D();
</span><span class="lines">@@ -78,125 +42,11 @@
</span><span class="cx"> 
</span><span class="cx">     HTMLCanvasElement& canvas() const { return downcast<HTMLCanvasElement>(canvasBase()); }
</span><span class="cx"> 
</span><del>-    float lineWidth() const;
-    void setLineWidth(float);
-
-    CanvasLineCap lineCap() const;
-    void setLineCap(CanvasLineCap);
-    void setLineCap(const String&);
-
-    CanvasLineJoin lineJoin() const;
-    void setLineJoin(CanvasLineJoin);
-    void setLineJoin(const String&);
-
-    float miterLimit() const;
-    void setMiterLimit(float);
-
-    const Vector<float>& getLineDash() const;
-    void setLineDash(const Vector<float>&);
-    const Vector<float>& webkitLineDash() const { return getLineDash(); }
-    void setWebkitLineDash(const Vector<float>&);
-
-    float lineDashOffset() const;
-    void setLineDashOffset(float);
-
-    float shadowOffsetX() const;
-    void setShadowOffsetX(float);
-
-    float shadowOffsetY() const;
-    void setShadowOffsetY(float);
-
-    float shadowBlur() const;
-    void setShadowBlur(float);
-
-    String shadowColor() const;
-    void setShadowColor(const String&);
-
-    float globalAlpha() const;
-    void setGlobalAlpha(float);
-
-    String globalCompositeOperation() const;
-    void setGlobalCompositeOperation(const String&);
-
-    void save() { ++m_unrealizedSaveCount; }
-    void restore();
-
-    void scale(float sx, float sy);
-    void rotate(float angleInRadians);
-    void translate(float tx, float ty);
-    void transform(float m11, float m12, float m21, float m22, float dx, float dy);
-
-    Ref<DOMMatrix> getTransform() const;
-    void setTransform(float m11, float m12, float m21, float m22, float dx, float dy);
-    ExceptionOr<void> setTransform(DOMMatrix2DInit&&);
-    void resetTransform();
-
-    void setStrokeColor(const String& color, std::optional<float> alpha = std::nullopt);
-    void setStrokeColor(float grayLevel, float alpha = 1.0);
-    void setStrokeColor(float r, float g, float b, float a);
-    void setStrokeColor(float c, float m, float y, float k, float a);
-
-    void setFillColor(const String& color, std::optional<float> alpha = std::nullopt);
-    void setFillColor(float grayLevel, float alpha = 1.0f);
-    void setFillColor(float r, float g, float b, float a);
-    void setFillColor(float c, float m, float y, float k, float a);
-
-    void beginPath();
-
-    void fill(CanvasFillRule = CanvasFillRule::Nonzero);
-    void stroke();
-    void clip(CanvasFillRule = CanvasFillRule::Nonzero);
-
-    void fill(Path2D&, CanvasFillRule = CanvasFillRule::Nonzero);
-    void stroke(Path2D&);
-    void clip(Path2D&, CanvasFillRule = CanvasFillRule::Nonzero);
-
-    bool isPointInPath(float x, float y, CanvasFillRule = CanvasFillRule::Nonzero);
-    bool isPointInStroke(float x, float y);
-
-    bool isPointInPath(Path2D&, float x, float y, CanvasFillRule = CanvasFillRule::Nonzero);
-    bool isPointInStroke(Path2D&, float x, float y);
-
-    void clearRect(float x, float y, float width, float height);
-    void fillRect(float x, float y, float width, float height);
-    void strokeRect(float x, float y, float width, float height);
-
-    void setShadow(float width, float height, float blur, const String& color = String(), std::optional<float> alpha = std::nullopt);
-    void setShadow(float width, float height, float blur, float grayLevel, float alpha = 1.0);
-    void setShadow(float width, float height, float blur, float r, float g, float b, float a);
-    void setShadow(float width, float height, float blur, float c, float m, float y, float k, float a);
-
-    void clearShadow();
-
-    ExceptionOr<void> drawImage(CanvasImageSource&&, float dx, float dy);
-    ExceptionOr<void> drawImage(CanvasImageSource&&, float dx, float dy, float dw, float dh);
-    ExceptionOr<void> drawImage(CanvasImageSource&&, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh);
-
-    void drawImageFromRect(HTMLImageElement&, float sx = 0, float sy = 0, float sw = 0, float sh = 0, float dx = 0, float dy = 0, float dw = 0, float dh = 0, const String& compositeOperation = emptyString());
-
-    using Style = Variant<String, RefPtr<CanvasGradient>, RefPtr<CanvasPattern>>;
-    Style strokeStyle() const;
-    void setStrokeStyle(Style&&);
-    Style fillStyle() const;
-    void setFillStyle(Style&&);
-
-    ExceptionOr<Ref<CanvasGradient>> createLinearGradient(float x0, float y0, float x1, float y1);
-    ExceptionOr<Ref<CanvasGradient>> createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1);
-    ExceptionOr<RefPtr<CanvasPattern>> createPattern(CanvasImageSource&&, const String& repetition);
-
-    ExceptionOr<RefPtr<ImageData>> createImageData(ImageData*) const;
-    ExceptionOr<RefPtr<ImageData>> createImageData(float width, float height) const;
-    ExceptionOr<RefPtr<ImageData>> getImageData(float sx, float sy, float sw, float sh) const;
-    void putImageData(ImageData&, float dx, float dy);
-    void putImageData(ImageData&, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight);
-
</del><span class="cx">     void drawFocusIfNeeded(Element&);
</span><span class="cx">     void drawFocusIfNeeded(Path2D&, Element&);
</span><span class="cx"> 
</span><span class="cx">     float webkitBackingStorePixelRatio() const { return 1; }
</span><span class="cx"> 
</span><del>-    void reset();
-
</del><span class="cx">     String font() const;
</span><span class="cx">     void setFont(const String&);
</span><span class="cx"> 
</span><span class="lines">@@ -213,196 +63,22 @@
</span><span class="cx">     void strokeText(const String& text, float x, float y, std::optional<float> maxWidth = std::nullopt);
</span><span class="cx">     Ref<TextMetrics> measureText(const String& text);
</span><span class="cx"> 
</span><del>-    LineCap getLineCap() const { return state().lineCap; }
-    LineJoin getLineJoin() const { return state().lineJoin; }
</del><ins>+    bool is2d() const override { return true; }
</ins><span class="cx"> 
</span><del>-    bool imageSmoothingEnabled() const;
-    void setImageSmoothingEnabled(bool);
-
-    ImageSmoothingQuality imageSmoothingQuality() const;
-    void setImageSmoothingQuality(ImageSmoothingQuality);
-
-    void setPath(Path2D&);
-    Ref<Path2D> getPath() const;
-
-    bool usesDisplayListDrawing() const { return m_usesDisplayListDrawing; };
-    void setUsesDisplayListDrawing(bool flag) { m_usesDisplayListDrawing = flag; };
-
-    bool tracksDisplayListReplay() const { return m_tracksDisplayListReplay; }
-    void setTracksDisplayListReplay(bool);
-
-    String displayListAsText(DisplayList::AsTextFlags) const;
-    String replayDisplayListAsText(DisplayList::AsTextFlags) const;
-
-    using Direction = CanvasDirection;
-
-    class FontProxy : public FontSelectorClient {
-    public:
-        FontProxy() = default;
-        virtual ~FontProxy();
-        FontProxy(const FontProxy&);
-        FontProxy& operator=(const FontProxy&);
-
-        bool realized() const { return m_font.fontSelector(); }
-        void initialize(FontSelector&, const RenderStyle&);
-        const FontMetrics& fontMetrics() const;
-        const FontCascadeDescription& fontDescription() const;
-        float width(const TextRun&, GlyphOverflow* = 0) const;
-        void drawBidiText(GraphicsContext&, const TextRun&, const FloatPoint&, FontCascade::CustomFontNotReadyAction) const;
-
-    private:
-        void update(FontSelector&);
-        void fontsNeedUpdate(FontSelector&) override;
-
-        FontCascade m_font;
-    };
-
-    struct State final {
-        State();
-
-        State(const State&);
-        State& operator=(const State&);
-
-        String unparsedStrokeColor;
-        String unparsedFillColor;
-        CanvasStyle strokeStyle;
-        CanvasStyle fillStyle;
-        float lineWidth;
-        LineCap lineCap;
-        LineJoin lineJoin;
-        float miterLimit;
-        FloatSize shadowOffset;
-        float shadowBlur;
-        Color shadowColor;
-        float globalAlpha;
-        CompositeOperator globalComposite;
-        BlendMode globalBlend;
-        AffineTransform transform;
-        bool hasInvertibleTransform;
-        Vector<float> lineDash;
-        float lineDashOffset;
-        bool imageSmoothingEnabled;
-        ImageSmoothingQuality imageSmoothingQuality;
-
-        // Text state.
-        TextAlign textAlign;
-        TextBaseline textBaseline;
-        Direction direction;
-
-        String unparsedFont;
-        FontProxy font;
-    };
-
-    const State& state() const { return m_stateStack.last(); }
-
</del><span class="cx"> private:
</span><del>-    enum CanvasDidDrawOption {
-        CanvasDidDrawApplyNone = 0,
-        CanvasDidDrawApplyTransform = 1,
-        CanvasDidDrawApplyShadow = 1 << 1,
-        CanvasDidDrawApplyClip = 1 << 2,
-        CanvasDidDrawApplyAll = 0xffffffff
-    };
-
-    State& modifiableState() { ASSERT(!m_unrealizedSaveCount || m_stateStack.size() >= MaxSaveCount); return m_stateStack.last(); }
-
-    void applyLineDash() const;
-    void setShadow(const FloatSize& offset, float blur, const Color&);
-    void applyShadow();
-    bool shouldDrawShadows() const;
-
-    void didDraw(const FloatRect&, unsigned options = CanvasDidDrawApplyAll);
-    void didDrawEntireCanvas();
-
-    void paintRenderingResultsToCanvas() override;
-
-    GraphicsContext* drawingContext() const;
-
-    void unwindStateStack();
-    void realizeSaves();
-    void realizeSavesLoop();
-
-    void applyStrokePattern();
-    void applyFillPattern();
-
-    void setStrokeStyle(CanvasStyle);
-    void setFillStyle(CanvasStyle);
-
-    ExceptionOr<RefPtr<CanvasPattern>> createPattern(HTMLImageElement&, bool repeatX, bool repeatY);
-    ExceptionOr<RefPtr<CanvasPattern>> createPattern(HTMLCanvasElement&, bool repeatX, bool repeatY);
-#if ENABLE(VIDEO)
-    ExceptionOr<RefPtr<CanvasPattern>> createPattern(HTMLVideoElement&, bool repeatX, bool repeatY);
-#endif
-    ExceptionOr<RefPtr<CanvasPattern>> createPattern(ImageBitmap&, bool repeatX, bool repeatY);
-
-    ExceptionOr<void> drawImage(HTMLImageElement&, const FloatRect& srcRect, const FloatRect& dstRect);
-    ExceptionOr<void> drawImage(HTMLImageElement&, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator&, const BlendMode&);
-    ExceptionOr<void> drawImage(HTMLCanvasElement&, const FloatRect& srcRect, const FloatRect& dstRect);
-#if ENABLE(VIDEO)
-    ExceptionOr<void> drawImage(HTMLVideoElement&, const FloatRect& srcRect, const FloatRect& dstRect);
-#endif
-    ExceptionOr<void> drawImage(ImageBitmap&, const FloatRect& srcRect, const FloatRect& dstRect);
-
-    void drawTextInternal(const String& text, float x, float y, bool fill, std::optional<float> maxWidth = std::nullopt);
-
</del><span class="cx">     // The relationship between FontCascade and CanvasRenderingContext2D::FontProxy must hold certain invariants.
</span><span class="cx">     // Therefore, all font operations must pass through the State.
</span><span class="cx">     const FontProxy& fontProxy();
</span><span class="cx"> 
</span><del>-    void clearPathForDashboardBackwardCompatibilityMode();
</del><ins>+    void drawTextInternal(const String& text, float x, float y, bool fill, std::optional<float> maxWidth = std::nullopt);
</ins><span class="cx"> 
</span><del>-    void beginCompositeLayer();
-    void endCompositeLayer();
-
-    void fillInternal(const Path&, CanvasFillRule);
-    void strokeInternal(const Path&);
-    void clipInternal(const Path&, CanvasFillRule);
-
-    bool isPointInPathInternal(const Path&, float x, float y, CanvasFillRule);
-    bool isPointInStrokeInternal(const Path&, float x, float y);
-
</del><span class="cx">     void drawFocusIfNeededInternal(const Path&, Element&);
</span><span class="cx"> 
</span><del>-    void clearCanvas();
-    Path transformAreaToDevice(const Path&) const;
-    Path transformAreaToDevice(const FloatRect&) const;
-    bool rectContainsCanvas(const FloatRect&) const;
-
-    template<class T> IntRect calculateCompositingBufferRect(const T&, IntSize*);
-    std::unique_ptr<ImageBuffer> createCompositingBuffer(const IntRect&);
-    void compositeBuffer(ImageBuffer&, const IntRect&, CompositeOperator);
-
-    void inflateStrokeRect(FloatRect&) const;
-
-    template<class T> void fullCanvasCompositedDrawImage(T&, const FloatRect&, const FloatRect&, CompositeOperator);
-
</del><span class="cx">     void prepareGradientForDashboard(CanvasGradient& gradient) const;
</span><span class="cx"> 
</span><del>-    ExceptionOr<RefPtr<ImageData>> getImageData(ImageBuffer::CoordinateSystem, float sx, float sy, float sw, float sh) const;
-    void putImageData(ImageData&, ImageBuffer::CoordinateSystem, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight);
</del><ins>+    TextDirection toTextDirection(CanvasRenderingContext2DBase::Direction, const RenderStyle** computedStyle = nullptr) const;
</ins><span class="cx"> 
</span><del>-    bool is2d() const override { return true; }
-    bool isAccelerated() const override;
-
-    bool hasInvertibleTransform() const override { return state().hasInvertibleTransform; }
-    TextDirection toTextDirection(Direction, const RenderStyle** computedStyle = nullptr) const;
-
</del><span class="cx">     FloatPoint textOffset(float width, TextDirection);
</span><del>-
-#if ENABLE(ACCELERATED_2D_CANVAS)
-    PlatformLayer* platformLayer() const override;
-#endif
-
-    static const unsigned MaxSaveCount = 1024 * 16;
-    Vector<State, 1> m_stateStack;
-    unsigned m_unrealizedSaveCount { 0 };
-    bool m_usesCSSCompatibilityParseMode;
-#if ENABLE(DASHBOARD_SUPPORT)
-    bool m_usesDashboardCompatibilityMode;
-#endif
-    bool m_usesDisplayListDrawing { false };
-    bool m_tracksDisplayListReplay { false };
-    mutable std::unique_ptr<struct DisplayListDrawingContext> m_recordingContext;
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlcanvasCanvasRenderingContext2DBasecppfromrev225815trunkSourceWebCorehtmlcanvasCanvasRenderingContext2Dcpp"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp (from rev 225815, trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp) (0 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp                                (rev 0)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.cpp   2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -0,0 +1,2332 @@
</span><ins>+/*
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2013, 2014 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CanvasRenderingContext2DBase.h"
+
+#include "BitmapImage.h"
+#include "CSSFontSelector.h"
+#include "CSSParser.h"
+#include "CSSPropertyNames.h"
+#include "CachedImage.h"
+#include "CanvasGradient.h"
+#include "CanvasPattern.h"
+#include "DOMMatrix.h"
+#include "DOMMatrix2DInit.h"
+#include "DisplayListRecorder.h"
+#include "DisplayListReplayer.h"
+#include "FloatQuad.h"
+#include "HTMLImageElement.h"
+#include "HTMLVideoElement.h"
+#include "ImageBitmap.h"
+#include "ImageBuffer.h"
+#include "ImageData.h"
+#include "Path2D.h"
+#include "RenderElement.h"
+#include "RenderImage.h"
+#include "RenderLayer.h"
+#include "RenderTheme.h"
+#include "SecurityOrigin.h"
+#include "StrokeStyleApplier.h"
+#include "StyleProperties.h"
+#include "StyleResolver.h"
+#include "TextMetrics.h"
+#include "TextRun.h"
+#include <wtf/CheckedArithmetic.h>
+#include <wtf/MathExtras.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/text/StringBuilder.h>
+#include <wtf/text/TextStream.h>
+
+#if USE(CG) && !PLATFORM(IOS)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#if USE(CG)
+const ImageSmoothingQuality defaultSmoothingQuality = ImageSmoothingQuality::Low;
+#else
+const ImageSmoothingQuality defaultSmoothingQuality = ImageSmoothingQuality::Medium;
+#endif
+
+const int CanvasRenderingContext2DBase::DefaultFontSize = 10;
+const char* const CanvasRenderingContext2DBase::DefaultFontFamily = "sans-serif";
+const char* const CanvasRenderingContext2DBase::DefaultFont = "10px sans-serif";
+
+struct DisplayListDrawingContext {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    GraphicsContext context;
+    DisplayList::DisplayList displayList;
+    
+    DisplayListDrawingContext(const FloatRect& clip)
+        : context([&](GraphicsContext& context) {
+            return std::make_unique<DisplayList::Recorder>(context, displayList, clip, AffineTransform());
+        })
+    {
+    }
+};
+
+typedef HashMap<const CanvasRenderingContext2DBase*, std::unique_ptr<DisplayList::DisplayList>> ContextDisplayListHashMap;
+
+static ContextDisplayListHashMap& contextDisplayListMap()
+{
+    static NeverDestroyed<ContextDisplayListHashMap> sharedHashMap;
+    return sharedHashMap;
+}
+
+class CanvasStrokeStyleApplier : public StrokeStyleApplier {
+public:
+    CanvasStrokeStyleApplier(CanvasRenderingContext2DBase* canvasContext)
+        : m_canvasContext(canvasContext)
+    {
+    }
+
+    void strokeStyle(GraphicsContext* c) override
+    {
+        c->setStrokeThickness(m_canvasContext->lineWidth());
+        c->setLineCap(m_canvasContext->getLineCap());
+        c->setLineJoin(m_canvasContext->getLineJoin());
+        c->setMiterLimit(m_canvasContext->miterLimit());
+        const Vector<float>& lineDash = m_canvasContext->getLineDash();
+        DashArray convertedLineDash(lineDash.size());
+        for (size_t i = 0; i < lineDash.size(); ++i)
+            convertedLineDash[i] = static_cast<DashArrayElement>(lineDash[i]);
+        c->setLineDash(convertedLineDash, m_canvasContext->lineDashOffset());
+    }
+
+private:
+    CanvasRenderingContext2DBase* m_canvasContext;
+};
+
+CanvasRenderingContext2DBase::CanvasRenderingContext2DBase(CanvasBase& canvas, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode)
+    : CanvasRenderingContext(canvas)
+    , m_stateStack(1)
+    , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode)
+#if ENABLE(DASHBOARD_SUPPORT)
+    , m_usesDashboardCompatibilityMode(usesDashboardCompatibilityMode)
+#endif
+{
+#if !ENABLE(DASHBOARD_SUPPORT)
+    ASSERT_UNUSED(usesDashboardCompatibilityMode, !usesDashboardCompatibilityMode);
+#endif
+}
+
+void CanvasRenderingContext2DBase::unwindStateStack()
+{
+    // Ensure that the state stack in the ImageBuffer's context
+    // is cleared before destruction, to avoid assertions in the
+    // GraphicsContext dtor.
+    if (size_t stackSize = m_stateStack.size()) {
+        auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+        if (GraphicsContext* context = canvas.existingDrawingContext()) {
+            while (--stackSize)
+                context->restore();
+        }
+    }
+}
+
+CanvasRenderingContext2DBase::~CanvasRenderingContext2DBase()
+{
+#if !ASSERT_DISABLED
+    unwindStateStack();
+#endif
+
+    if (UNLIKELY(tracksDisplayListReplay()))
+        contextDisplayListMap().remove(this);
+}
+
+bool CanvasRenderingContext2DBase::isAccelerated() const
+{
+#if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    if (!canvas.hasCreatedImageBuffer())
+        return false;
+    auto* context = drawingContext();
+    return context && context->isAcceleratedContext();
+#else
+    return false;
+#endif
+}
+
+void CanvasRenderingContext2DBase::reset()
+{
+    unwindStateStack();
+    m_stateStack.resize(1);
+    m_stateStack.first() = State();
+    m_path.clear();
+    m_unrealizedSaveCount = 0;
+    
+    m_recordingContext = nullptr;
+}
+
+CanvasRenderingContext2DBase::State::State()
+    : strokeStyle(Color::black)
+    , fillStyle(Color::black)
+    , lineWidth(1)
+    , lineCap(ButtCap)
+    , lineJoin(MiterJoin)
+    , miterLimit(10)
+    , shadowBlur(0)
+    , shadowColor(Color::transparent)
+    , globalAlpha(1)
+    , globalComposite(CompositeSourceOver)
+    , globalBlend(BlendModeNormal)
+    , hasInvertibleTransform(true)
+    , lineDashOffset(0)
+    , imageSmoothingEnabled(true)
+    , imageSmoothingQuality(defaultSmoothingQuality)
+    , textAlign(StartTextAlign)
+    , textBaseline(AlphabeticTextBaseline)
+    , direction(Direction::Inherit)
+    , unparsedFont(DefaultFont)
+{
+}
+
+CanvasRenderingContext2DBase::State::State(const State& other)
+    : unparsedStrokeColor(other.unparsedStrokeColor)
+    , unparsedFillColor(other.unparsedFillColor)
+    , strokeStyle(other.strokeStyle)
+    , fillStyle(other.fillStyle)
+    , lineWidth(other.lineWidth)
+    , lineCap(other.lineCap)
+    , lineJoin(other.lineJoin)
+    , miterLimit(other.miterLimit)
+    , shadowOffset(other.shadowOffset)
+    , shadowBlur(other.shadowBlur)
+    , shadowColor(other.shadowColor)
+    , globalAlpha(other.globalAlpha)
+    , globalComposite(other.globalComposite)
+    , globalBlend(other.globalBlend)
+    , transform(other.transform)
+    , hasInvertibleTransform(other.hasInvertibleTransform)
+    , lineDashOffset(other.lineDashOffset)
+    , imageSmoothingEnabled(other.imageSmoothingEnabled)
+    , imageSmoothingQuality(other.imageSmoothingQuality)
+    , textAlign(other.textAlign)
+    , textBaseline(other.textBaseline)
+    , direction(other.direction)
+    , unparsedFont(other.unparsedFont)
+    , font(other.font)
+{
+}
+
+CanvasRenderingContext2DBase::State& CanvasRenderingContext2DBase::State::operator=(const State& other)
+{
+    if (this == &other)
+        return *this;
+
+    unparsedStrokeColor = other.unparsedStrokeColor;
+    unparsedFillColor = other.unparsedFillColor;
+    strokeStyle = other.strokeStyle;
+    fillStyle = other.fillStyle;
+    lineWidth = other.lineWidth;
+    lineCap = other.lineCap;
+    lineJoin = other.lineJoin;
+    miterLimit = other.miterLimit;
+    shadowOffset = other.shadowOffset;
+    shadowBlur = other.shadowBlur;
+    shadowColor = other.shadowColor;
+    globalAlpha = other.globalAlpha;
+    globalComposite = other.globalComposite;
+    globalBlend = other.globalBlend;
+    transform = other.transform;
+    hasInvertibleTransform = other.hasInvertibleTransform;
+    imageSmoothingEnabled = other.imageSmoothingEnabled;
+    imageSmoothingQuality = other.imageSmoothingQuality;
+    textAlign = other.textAlign;
+    textBaseline = other.textBaseline;
+    direction = other.direction;
+    unparsedFont = other.unparsedFont;
+    font = other.font;
+
+    return *this;
+}
+
+CanvasRenderingContext2DBase::FontProxy::~FontProxy()
+{
+    if (realized())
+        m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
+}
+
+CanvasRenderingContext2DBase::FontProxy::FontProxy(const FontProxy& other)
+    : m_font(other.m_font)
+{
+    if (realized())
+        m_font.fontSelector()->registerForInvalidationCallbacks(*this);
+}
+
+auto CanvasRenderingContext2DBase::FontProxy::operator=(const FontProxy& other) -> FontProxy&
+{
+    if (realized())
+        m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
+
+    m_font = other.m_font;
+
+    if (realized())
+        m_font.fontSelector()->registerForInvalidationCallbacks(*this);
+
+    return *this;
+}
+
+inline void CanvasRenderingContext2DBase::FontProxy::update(FontSelector& selector)
+{
+    ASSERT(&selector == m_font.fontSelector()); // This is an invariant. We should only ever be registered for callbacks on m_font.m_fonts.m_fontSelector.
+    if (realized())
+        m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
+    m_font.update(&selector);
+    if (realized())
+        m_font.fontSelector()->registerForInvalidationCallbacks(*this);
+    ASSERT(&selector == m_font.fontSelector());
+}
+
+void CanvasRenderingContext2DBase::FontProxy::fontsNeedUpdate(FontSelector& selector)
+{
+    ASSERT_ARG(selector, &selector == m_font.fontSelector());
+    ASSERT(realized());
+
+    update(selector);
+}
+
+inline void CanvasRenderingContext2DBase::FontProxy::initialize(FontSelector& fontSelector, const RenderStyle& newStyle)
+{
+    // Beware! m_font.fontSelector() might not point to document.fontSelector()!
+    ASSERT(newStyle.fontCascade().fontSelector() == &fontSelector);
+    if (realized())
+        m_font.fontSelector()->unregisterForInvalidationCallbacks(*this);
+    m_font = newStyle.fontCascade();
+    m_font.update(&fontSelector);
+    ASSERT(&fontSelector == m_font.fontSelector());
+    m_font.fontSelector()->registerForInvalidationCallbacks(*this);
+}
+
+inline const FontMetrics& CanvasRenderingContext2DBase::FontProxy::fontMetrics() const
+{
+    return m_font.fontMetrics();
+}
+
+inline const FontCascadeDescription& CanvasRenderingContext2DBase::FontProxy::fontDescription() const
+{
+    return m_font.fontDescription();
+}
+
+inline float CanvasRenderingContext2DBase::FontProxy::width(const TextRun& textRun, GlyphOverflow* overflow) const
+{
+    return m_font.width(textRun, 0, overflow);
+}
+
+inline void CanvasRenderingContext2DBase::FontProxy::drawBidiText(GraphicsContext& context, const TextRun& run, const FloatPoint& point, FontCascade::CustomFontNotReadyAction action) const
+{
+    context.drawBidiText(m_font, run, point, action);
+}
+
+void CanvasRenderingContext2DBase::realizeSaves()
+{
+    if (m_unrealizedSaveCount)
+        realizeSavesLoop();
+
+    if (m_unrealizedSaveCount) {
+        static NeverDestroyed<String> consoleMessage(MAKE_STATIC_STRING_IMPL("CanvasRenderingContext2D.save() has been called without a matching restore() too many times. Ignoring save()."));
+
+        canvasBase().scriptExecutionContext()->addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, consoleMessage);
+    }
+}
+
+void CanvasRenderingContext2DBase::realizeSavesLoop()
+{
+    ASSERT(m_unrealizedSaveCount);
+    ASSERT(m_stateStack.size() >= 1);
+    GraphicsContext* context = drawingContext();
+    do {
+        if (m_stateStack.size() > MaxSaveCount)
+            break;
+        m_stateStack.append(state());
+        if (context)
+            context->save();
+    } while (--m_unrealizedSaveCount);
+}
+
+void CanvasRenderingContext2DBase::restore()
+{
+    if (m_unrealizedSaveCount) {
+        --m_unrealizedSaveCount;
+        return;
+    }
+    ASSERT(m_stateStack.size() >= 1);
+    if (m_stateStack.size() <= 1)
+        return;
+    m_path.transform(state().transform);
+    m_stateStack.removeLast();
+    if (std::optional<AffineTransform> inverse = state().transform.inverse())
+        m_path.transform(inverse.value());
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->restore();
+}
+
+void CanvasRenderingContext2DBase::setStrokeStyle(CanvasStyle style)
+{
+    if (!style.isValid())
+        return;
+
+    if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentColor(style))
+        return;
+
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+
+    if (style.isCurrentColor()) {
+        if (style.hasOverrideAlpha()) {
+            // FIXME: Should not use RGBA32 here.
+            style = CanvasStyle(colorWithOverrideAlpha(currentColor(&canvas).rgb(), style.overrideAlpha()));
+        } else
+            style = CanvasStyle(currentColor(&canvas));
+    } else
+        checkOrigin(style.canvasPattern().get());
+
+    realizeSaves();
+    State& state = modifiableState();
+    state.strokeStyle = style;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    state.strokeStyle.applyStrokeColor(*c);
+    state.unparsedStrokeColor = String();
+}
+
+void CanvasRenderingContext2DBase::setFillStyle(CanvasStyle style)
+{
+    if (!style.isValid())
+        return;
+
+    if (state().fillStyle.isValid() && state().fillStyle.isEquivalentColor(style))
+        return;
+
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+
+    if (style.isCurrentColor()) {
+        if (style.hasOverrideAlpha()) {
+            // FIXME: Should not use RGBA32 here.
+            style = CanvasStyle(colorWithOverrideAlpha(currentColor(&canvas).rgb(), style.overrideAlpha()));
+        } else
+            style = CanvasStyle(currentColor(&canvas));
+    } else
+        checkOrigin(style.canvasPattern().get());
+
+    realizeSaves();
+    State& state = modifiableState();
+    state.fillStyle = style;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    state.fillStyle.applyFillColor(*c);
+    state.unparsedFillColor = String();
+}
+
+float CanvasRenderingContext2DBase::lineWidth() const
+{
+    return state().lineWidth;
+}
+
+void CanvasRenderingContext2DBase::setLineWidth(float width)
+{
+    if (!(std::isfinite(width) && width > 0))
+        return;
+    if (state().lineWidth == width)
+        return;
+    realizeSaves();
+    modifiableState().lineWidth = width;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setStrokeThickness(width);
+}
+
+static CanvasLineCap toCanvasLineCap(LineCap lineCap)
+{
+    switch (lineCap) {
+    case ButtCap:
+        return CanvasLineCap::Butt;
+    case RoundCap:
+        return CanvasLineCap::Round;
+    case SquareCap:
+        return CanvasLineCap::Square;
+    }
+
+    ASSERT_NOT_REACHED();
+    return CanvasLineCap::Butt;
+}
+
+static LineCap fromCanvasLineCap(CanvasLineCap canvasLineCap)
+{
+    switch (canvasLineCap) {
+    case CanvasLineCap::Butt:
+        return ButtCap;
+    case CanvasLineCap::Round:
+        return RoundCap;
+    case CanvasLineCap::Square:
+        return SquareCap;
+    }
+    
+    ASSERT_NOT_REACHED();
+    return ButtCap;
+}
+
+CanvasLineCap CanvasRenderingContext2DBase::lineCap() const
+{
+    return toCanvasLineCap(state().lineCap);
+}
+
+void CanvasRenderingContext2DBase::setLineCap(CanvasLineCap canvasLineCap)
+{
+    auto lineCap = fromCanvasLineCap(canvasLineCap);
+    if (state().lineCap == lineCap)
+        return;
+    realizeSaves();
+    modifiableState().lineCap = lineCap;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setLineCap(lineCap);
+}
+
+void CanvasRenderingContext2DBase::setLineCap(const String& stringValue)
+{
+    CanvasLineCap cap;
+    if (stringValue == "butt")
+        cap = CanvasLineCap::Butt;
+    else if (stringValue == "round")
+        cap = CanvasLineCap::Round;
+    else if (stringValue == "square")
+        cap = CanvasLineCap::Square;
+    else
+        return;
+    
+    setLineCap(cap);
+}
+
+static CanvasLineJoin toCanvasLineJoin(LineJoin lineJoin)
+{
+    switch (lineJoin) {
+    case RoundJoin:
+        return CanvasLineJoin::Round;
+    case BevelJoin:
+        return CanvasLineJoin::Bevel;
+    case MiterJoin:
+        return CanvasLineJoin::Miter;
+    }
+
+    ASSERT_NOT_REACHED();
+    return CanvasLineJoin::Round;
+}
+
+static LineJoin fromCanvasLineJoin(CanvasLineJoin canvasLineJoin)
+{
+    switch (canvasLineJoin) {
+    case CanvasLineJoin::Round:
+        return RoundJoin;
+    case CanvasLineJoin::Bevel:
+        return BevelJoin;
+    case CanvasLineJoin::Miter:
+        return MiterJoin;
+    }
+    
+    ASSERT_NOT_REACHED();
+    return RoundJoin;
+}
+
+CanvasLineJoin CanvasRenderingContext2DBase::lineJoin() const
+{
+    return toCanvasLineJoin(state().lineJoin);
+}
+
+void CanvasRenderingContext2DBase::setLineJoin(CanvasLineJoin canvasLineJoin)
+{
+    auto lineJoin = fromCanvasLineJoin(canvasLineJoin);
+    if (state().lineJoin == lineJoin)
+        return;
+    realizeSaves();
+    modifiableState().lineJoin = lineJoin;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setLineJoin(lineJoin);
+}
+
+void CanvasRenderingContext2DBase::setLineJoin(const String& stringValue)
+{
+    CanvasLineJoin join;
+    if (stringValue == "round")
+        join = CanvasLineJoin::Round;
+    else if (stringValue == "bevel")
+        join = CanvasLineJoin::Bevel;
+    else if (stringValue == "miter")
+        join = CanvasLineJoin::Miter;
+    else
+        return;
+
+    setLineJoin(join);
+}
+
+float CanvasRenderingContext2DBase::miterLimit() const
+{
+    return state().miterLimit;
+}
+
+void CanvasRenderingContext2DBase::setMiterLimit(float limit)
+{
+    if (!(std::isfinite(limit) && limit > 0))
+        return;
+    if (state().miterLimit == limit)
+        return;
+    realizeSaves();
+    modifiableState().miterLimit = limit;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setMiterLimit(limit);
+}
+
+float CanvasRenderingContext2DBase::shadowOffsetX() const
+{
+    return state().shadowOffset.width();
+}
+
+void CanvasRenderingContext2DBase::setShadowOffsetX(float x)
+{
+    if (!std::isfinite(x))
+        return;
+    if (state().shadowOffset.width() == x)
+        return;
+    realizeSaves();
+    modifiableState().shadowOffset.setWidth(x);
+    applyShadow();
+}
+
+float CanvasRenderingContext2DBase::shadowOffsetY() const
+{
+    return state().shadowOffset.height();
+}
+
+void CanvasRenderingContext2DBase::setShadowOffsetY(float y)
+{
+    if (!std::isfinite(y))
+        return;
+    if (state().shadowOffset.height() == y)
+        return;
+    realizeSaves();
+    modifiableState().shadowOffset.setHeight(y);
+    applyShadow();
+}
+
+float CanvasRenderingContext2DBase::shadowBlur() const
+{
+    return state().shadowBlur;
+}
+
+void CanvasRenderingContext2DBase::setShadowBlur(float blur)
+{
+    if (!(std::isfinite(blur) && blur >= 0))
+        return;
+    if (state().shadowBlur == blur)
+        return;
+    realizeSaves();
+    modifiableState().shadowBlur = blur;
+    applyShadow();
+}
+
+String CanvasRenderingContext2DBase::shadowColor() const
+{
+    return Color(state().shadowColor).serialized();
+}
+
+void CanvasRenderingContext2DBase::setShadowColor(const String& colorString)
+{
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    Color color = parseColorOrCurrentColor(colorString, &canvas);
+    if (!color.isValid())
+        return;
+    if (state().shadowColor == color)
+        return;
+    realizeSaves();
+    modifiableState().shadowColor = color;
+    applyShadow();
+}
+
+const Vector<float>& CanvasRenderingContext2DBase::getLineDash() const
+{
+    return state().lineDash;
+}
+
+static bool lineDashSequenceIsValid(const Vector<float>& dash)
+{
+    for (size_t i = 0; i < dash.size(); i++) {
+        if (!std::isfinite(dash[i]) || dash[i] < 0)
+            return false;
+    }
+    return true;
+}
+
+void CanvasRenderingContext2DBase::setLineDash(const Vector<float>& dash)
+{
+    if (!lineDashSequenceIsValid(dash))
+        return;
+
+    realizeSaves();
+    modifiableState().lineDash = dash;
+    // Spec requires the concatenation of two copies the dash list when the
+    // number of elements is odd
+    if (dash.size() % 2)
+        modifiableState().lineDash.appendVector(dash);
+
+    applyLineDash();
+}
+
+void CanvasRenderingContext2DBase::setWebkitLineDash(const Vector<float>& dash)
+{
+    if (!lineDashSequenceIsValid(dash))
+        return;
+
+    realizeSaves();
+    modifiableState().lineDash = dash;
+
+    applyLineDash();
+}
+
+float CanvasRenderingContext2DBase::lineDashOffset() const
+{
+    return state().lineDashOffset;
+}
+
+void CanvasRenderingContext2DBase::setLineDashOffset(float offset)
+{
+    if (!std::isfinite(offset) || state().lineDashOffset == offset)
+        return;
+
+    realizeSaves();
+    modifiableState().lineDashOffset = offset;
+    applyLineDash();
+}
+
+void CanvasRenderingContext2DBase::applyLineDash() const
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    DashArray convertedLineDash(state().lineDash.size());
+    for (size_t i = 0; i < state().lineDash.size(); ++i)
+        convertedLineDash[i] = static_cast<DashArrayElement>(state().lineDash[i]);
+    c->setLineDash(convertedLineDash, state().lineDashOffset);
+}
+
+float CanvasRenderingContext2DBase::globalAlpha() const
+{
+    return state().globalAlpha;
+}
+
+void CanvasRenderingContext2DBase::setGlobalAlpha(float alpha)
+{
+    if (!(alpha >= 0 && alpha <= 1))
+        return;
+    if (state().globalAlpha == alpha)
+        return;
+    realizeSaves();
+    modifiableState().globalAlpha = alpha;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setAlpha(alpha);
+}
+
+String CanvasRenderingContext2DBase::globalCompositeOperation() const
+{
+    return compositeOperatorName(state().globalComposite, state().globalBlend);
+}
+
+void CanvasRenderingContext2DBase::setGlobalCompositeOperation(const String& operation)
+{
+    CompositeOperator op = CompositeSourceOver;
+    BlendMode blendMode = BlendModeNormal;
+    if (!parseCompositeAndBlendOperator(operation, op, blendMode))
+        return;
+    if ((state().globalComposite == op) && (state().globalBlend == blendMode))
+        return;
+    realizeSaves();
+    modifiableState().globalComposite = op;
+    modifiableState().globalBlend = blendMode;
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    c->setCompositeOperation(op, blendMode);
+}
+
+void CanvasRenderingContext2DBase::scale(float sx, float sy)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+
+    if (!std::isfinite(sx) || !std::isfinite(sy))
+        return;
+
+    AffineTransform newTransform = state().transform;
+    newTransform.scaleNonUniform(sx, sy);
+    if (state().transform == newTransform)
+        return;
+
+    realizeSaves();
+
+    if (!sx || !sy) {
+        modifiableState().hasInvertibleTransform = false;
+        return;
+    }
+
+    modifiableState().transform = newTransform;
+    c->scale(FloatSize(sx, sy));
+    m_path.transform(AffineTransform().scaleNonUniform(1.0 / sx, 1.0 / sy));
+}
+
+void CanvasRenderingContext2DBase::rotate(float angleInRadians)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+
+    if (!std::isfinite(angleInRadians))
+        return;
+
+    AffineTransform newTransform = state().transform;
+    newTransform.rotate(angleInRadians / piDouble * 180.0);
+    if (state().transform == newTransform)
+        return;
+
+    realizeSaves();
+
+    modifiableState().transform = newTransform;
+    c->rotate(angleInRadians);
+    m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0));
+}
+
+void CanvasRenderingContext2DBase::translate(float tx, float ty)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+
+    if (!std::isfinite(tx) | !std::isfinite(ty))
+        return;
+
+    AffineTransform newTransform = state().transform;
+    newTransform.translate(tx, ty);
+    if (state().transform == newTransform)
+        return;
+
+    realizeSaves();
+
+    modifiableState().transform = newTransform;
+    c->translate(tx, ty);
+    m_path.transform(AffineTransform().translate(-tx, -ty));
+}
+
+void CanvasRenderingContext2DBase::transform(float m11, float m12, float m21, float m22, float dx, float dy)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+
+    if (!std::isfinite(m11) | !std::isfinite(m21) | !std::isfinite(dx) | !std::isfinite(m12) | !std::isfinite(m22) | !std::isfinite(dy))
+        return;
+
+    AffineTransform transform(m11, m12, m21, m22, dx, dy);
+    AffineTransform newTransform = state().transform * transform;
+    if (state().transform == newTransform)
+        return;
+
+    realizeSaves();
+
+    if (auto inverse = transform.inverse()) {
+        modifiableState().transform = newTransform;
+        c->concatCTM(transform);
+        m_path.transform(inverse.value());
+        return;
+    }
+    modifiableState().hasInvertibleTransform = false;
+}
+
+Ref<DOMMatrix> CanvasRenderingContext2DBase::getTransform() const
+{
+    return DOMMatrix::create(state().transform.toTransformationMatrix(), DOMMatrixReadOnly::Is2D::Yes);
+}
+
+void CanvasRenderingContext2DBase::setTransform(float m11, float m12, float m21, float m22, float dx, float dy)
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+
+    if (!std::isfinite(m11) | !std::isfinite(m21) | !std::isfinite(dx) | !std::isfinite(m12) | !std::isfinite(m22) | !std::isfinite(dy))
+        return;
+
+    resetTransform();
+    transform(m11, m12, m21, m22, dx, dy);
+}
+
+ExceptionOr<void> CanvasRenderingContext2DBase::setTransform(DOMMatrix2DInit&& matrixInit)
+{
+    auto checkValid = DOMMatrixReadOnly::validateAndFixup(matrixInit);
+    if (checkValid.hasException())
+        return checkValid.releaseException();
+
+    setTransform(matrixInit.a.value_or(1), matrixInit.b.value_or(0), matrixInit.c.value_or(0), matrixInit.d.value_or(1), matrixInit.e.value_or(0), matrixInit.f.value_or(0));
+    return { };
+}
+
+void CanvasRenderingContext2DBase::resetTransform()
+{
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return;
+
+    AffineTransform ctm = state().transform;
+    bool hasInvertibleTransform = state().hasInvertibleTransform;
+
+    realizeSaves();
+
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    c->setCTM(canvas.baseTransform());
+    modifiableState().transform = AffineTransform();
+
+    if (hasInvertibleTransform)
+        m_path.transform(ctm);
+
+    modifiableState().hasInvertibleTransform = true;
+}
+
+void CanvasRenderingContext2DBase::setStrokeColor(const String& color, std::optional<float> alpha)
+{
+    if (alpha) {
+        setStrokeStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha.value()));
+        return;
+    }
+
+    if (color == state().unparsedStrokeColor)
+        return;
+
+    realizeSaves();
+    setStrokeStyle(CanvasStyle::createFromString(color));
+    modifiableState().unparsedStrokeColor = color;
+}
+
+void CanvasRenderingContext2DBase::setStrokeColor(float grayLevel, float alpha)
+{
+    if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
+        return;
+    setStrokeStyle(CanvasStyle(grayLevel, alpha));
+}
+
+void CanvasRenderingContext2DBase::setStrokeColor(float r, float g, float b, float a)
+{
+    if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentRGBA(r, g, b, a))
+        return;
+    setStrokeStyle(CanvasStyle(r, g, b, a));
+}
+
+void CanvasRenderingContext2DBase::setStrokeColor(float c, float m, float y, float k, float a)
+{
+    if (state().strokeStyle.isValid() && state().strokeStyle.isEquivalentCMYKA(c, m, y, k, a))
+        return;
+    setStrokeStyle(CanvasStyle(c, m, y, k, a));
+}
+
+void CanvasRenderingContext2DBase::setFillColor(const String& color, std::optional<float> alpha)
+{
+    if (alpha) {
+        setFillStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha.value()));
+        return;
+    }
+
+    if (color == state().unparsedFillColor)
+        return;
+
+    realizeSaves();
+    setFillStyle(CanvasStyle::createFromString(color));
+    modifiableState().unparsedFillColor = color;
+}
+
+void CanvasRenderingContext2DBase::setFillColor(float grayLevel, float alpha)
+{
+    if (state().fillStyle.isValid() && state().fillStyle.isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
+        return;
+    setFillStyle(CanvasStyle(grayLevel, alpha));
+}
+
+void CanvasRenderingContext2DBase::setFillColor(float r, float g, float b, float a)
+{
+    if (state().fillStyle.isValid() && state().fillStyle.isEquivalentRGBA(r, g, b, a))
+        return;
+    setFillStyle(CanvasStyle(r, g, b, a));
+}
+
+void CanvasRenderingContext2DBase::setFillColor(float c, float m, float y, float k, float a)
+{
+    if (state().fillStyle.isValid() && state().fillStyle.isEquivalentCMYKA(c, m, y, k, a))
+        return;
+    setFillStyle(CanvasStyle(c, m, y, k, a));
+}
+
+void CanvasRenderingContext2DBase::beginPath()
+{
+    m_path.clear();
+}
+
+static bool validateRectForCanvas(float& x, float& y, float& width, float& height)
+{
+    if (!std::isfinite(x) | !std::isfinite(y) | !std::isfinite(width) | !std::isfinite(height))
+        return false;
+
+    if (!width && !height)
+        return false;
+
+    if (width < 0) {
+        width = -width;
+        x -= width;
+    }
+
+    if (height < 0) {
+        height = -height;
+        y -= height;
+    }
+
+    return true;
+}
+
+bool CanvasRenderingContext2DBase::isFullCanvasCompositeMode(CompositeOperator op)
+{
+    // See 4.8.11.1.3 Compositing
+    // CompositeSourceAtop and CompositeDestinationOut are not listed here as the platforms already
+    // implement the specification's behavior.
+    return op == CompositeSourceIn || op == CompositeSourceOut || op == CompositeDestinationIn || op == CompositeDestinationAtop;
+}
+
+static WindRule toWindRule(CanvasFillRule rule)
+{
+    return rule == CanvasFillRule::Nonzero ? RULE_NONZERO : RULE_EVENODD;
+}
+
+void CanvasRenderingContext2DBase::fill(CanvasFillRule windingRule)
+{
+    fillInternal(m_path, windingRule);
+    clearPathForDashboardBackwardCompatibilityMode();
+}
+
+void CanvasRenderingContext2DBase::stroke()
+{
+    strokeInternal(m_path);
+    clearPathForDashboardBackwardCompatibilityMode();
+}
+
+void CanvasRenderingContext2DBase::clip(CanvasFillRule windingRule)
+{
+    clipInternal(m_path, windingRule);
+    clearPathForDashboardBackwardCompatibilityMode();
+}
+
+void CanvasRenderingContext2DBase::fill(Path2D& path, CanvasFillRule windingRule)
+{
+    fillInternal(path.path(), windingRule);
+}
+
+void CanvasRenderingContext2DBase::stroke(Path2D& path)
+{
+    strokeInternal(path.path());
+}
+
+void CanvasRenderingContext2DBase::clip(Path2D& path, CanvasFillRule windingRule)
+{
+    clipInternal(path.path(), windingRule);
+}
+
+void CanvasRenderingContext2DBase::fillInternal(const Path& path, CanvasFillRule windingRule)
+{
+    auto* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+
+    // If gradient size is zero, then paint nothing.
+    auto gradient = c->fillGradient();
+    if (gradient && gradient->isZeroSize())
+        return;
+
+    if (!path.isEmpty()) {
+        auto savedFillRule = c->fillRule();
+        c->setFillRule(toWindRule(windingRule));
+
+        if (isFullCanvasCompositeMode(state().globalComposite)) {
+            beginCompositeLayer();
+            c->fillPath(path);
+            endCompositeLayer();
+            didDrawEntireCanvas();
+        } else if (state().globalComposite == CompositeCopy) {
+            clearCanvas();
+            c->fillPath(path);
+            didDrawEntireCanvas();
+        } else {
+            c->fillPath(path);
+            didDraw(path.fastBoundingRect());
+        }
+        
+        c->setFillRule(savedFillRule);
+    }
+}
+
+void CanvasRenderingContext2DBase::strokeInternal(const Path& path)
+{
+    auto* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+
+    // If gradient size is zero, then paint nothing.
+    auto gradient = c->strokeGradient();
+    if (gradient && gradient->isZeroSize())
+        return;
+
+    if (!path.isEmpty()) {
+        if (isFullCanvasCompositeMode(state().globalComposite)) {
+            beginCompositeLayer();
+            c->strokePath(path);
+            endCompositeLayer();
+            didDrawEntireCanvas();
+        } else if (state().globalComposite == CompositeCopy) {
+            clearCanvas();
+            c->strokePath(path);
+            didDrawEntireCanvas();
+        } else {
+            FloatRect dirtyRect = path.fastBoundingRect();
+            inflateStrokeRect(dirtyRect);
+            c->strokePath(path);
+            didDraw(dirtyRect);
+        }
+    }
+}
+
+void CanvasRenderingContext2DBase::clipInternal(const Path& path, CanvasFillRule windingRule)
+{
+    auto* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+
+    realizeSaves();
+    c->canvasClip(path, toWindRule(windingRule));
+}
+
+inline void CanvasRenderingContext2DBase::beginCompositeLayer()
+{
+#if !USE(CAIRO)
+    drawingContext()->beginTransparencyLayer(1);
+#endif
+}
+
+inline void CanvasRenderingContext2DBase::endCompositeLayer()
+{
+#if !USE(CAIRO)
+    drawingContext()->endTransparencyLayer();    
+#endif
+}
+
+bool CanvasRenderingContext2DBase::isPointInPath(float x, float y, CanvasFillRule windingRule)
+{
+    return isPointInPathInternal(m_path, x, y, windingRule);
+}
+
+bool CanvasRenderingContext2DBase::isPointInStroke(float x, float y)
+{
+    return isPointInStrokeInternal(m_path, x, y);
+}
+
+bool CanvasRenderingContext2DBase::isPointInPath(Path2D& path, float x, float y, CanvasFillRule windingRule)
+{
+    return isPointInPathInternal(path.path(), x, y, windingRule);
+}
+
+bool CanvasRenderingContext2DBase::isPointInStroke(Path2D& path, float x, float y)
+{
+    return isPointInStrokeInternal(path.path(), x, y);
+}
+
+bool CanvasRenderingContext2DBase::isPointInPathInternal(const Path& path, float x, float y, CanvasFillRule windingRule)
+{
+    auto* c = drawingContext();
+    if (!c)
+        return false;
+    if (!state().hasInvertibleTransform)
+        return false;
+
+    auto transformedPoint = state().transform.inverse().value_or(AffineTransform()).mapPoint(FloatPoint(x, y));
+
+    if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
+        return false;
+
+    return path.contains(transformedPoint, toWindRule(windingRule));
+}
+
+bool CanvasRenderingContext2DBase::isPointInStrokeInternal(const Path& path, float x, float y)
+{
+    auto* c = drawingContext();
+    if (!c)
+        return false;
+    if (!state().hasInvertibleTransform)
+        return false;
+
+    auto transformedPoint = state().transform.inverse().value_or(AffineTransform()).mapPoint(FloatPoint(x, y));
+    if (!std::isfinite(transformedPoint.x()) || !std::isfinite(transformedPoint.y()))
+        return false;
+
+    CanvasStrokeStyleApplier applier(this);
+    return path.strokeContains(&applier, transformedPoint);
+}
+
+void CanvasRenderingContext2DBase::clearRect(float x, float y, float width, float height)
+{
+    if (!validateRectForCanvas(x, y, width, height))
+        return;
+    auto* context = drawingContext();
+    if (!context)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+    FloatRect rect(x, y, width, height);
+
+    bool saved = false;
+    if (shouldDrawShadows()) {
+        context->save();
+        saved = true;
+        context->setLegacyShadow(FloatSize(), 0, Color::transparent);
+    }
+    if (state().globalAlpha != 1) {
+        if (!saved) {
+            context->save();
+            saved = true;
+        }
+        context->setAlpha(1);
+    }
+    if (state().globalComposite != CompositeSourceOver) {
+        if (!saved) {
+            context->save();
+            saved = true;
+        }
+        context->setCompositeOperation(CompositeSourceOver);
+    }
+    context->clearRect(rect);
+    if (saved)
+        context->restore();
+    didDraw(rect);
+}
+
+void CanvasRenderingContext2DBase::fillRect(float x, float y, float width, float height)
+{
+    if (!validateRectForCanvas(x, y, width, height))
+        return;
+
+    auto* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+
+    // from the HTML5 Canvas spec:
+    // If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
+    // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
+    auto gradient = c->fillGradient();
+    if (gradient && gradient->isZeroSize())
+        return;
+
+    FloatRect rect(x, y, width, height);
+
+    if (rectContainsCanvas(rect)) {
+        c->fillRect(rect);
+        didDrawEntireCanvas();
+    } else if (isFullCanvasCompositeMode(state().globalComposite)) {
+        beginCompositeLayer();
+        c->fillRect(rect);
+        endCompositeLayer();
+        didDrawEntireCanvas();
+    } else if (state().globalComposite == CompositeCopy) {
+        clearCanvas();
+        c->fillRect(rect);
+        didDrawEntireCanvas();
+    } else {
+        c->fillRect(rect);
+        didDraw(rect);
+    }
+}
+
+void CanvasRenderingContext2DBase::strokeRect(float x, float y, float width, float height)
+{
+    if (!validateRectForCanvas(x, y, width, height))
+        return;
+
+    auto* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+    if (!(state().lineWidth >= 0))
+        return;
+
+    // If gradient size is zero, then paint nothing.
+    auto gradient = c->strokeGradient();
+    if (gradient && gradient->isZeroSize())
+        return;
+
+    FloatRect rect(x, y, width, height);
+    if (isFullCanvasCompositeMode(state().globalComposite)) {
+        beginCompositeLayer();
+        c->strokeRect(rect, state().lineWidth);
+        endCompositeLayer();
+        didDrawEntireCanvas();
+    } else if (state().globalComposite == CompositeCopy) {
+        clearCanvas();
+        c->strokeRect(rect, state().lineWidth);
+        didDrawEntireCanvas();
+    } else {
+        FloatRect boundingRect = rect;
+        boundingRect.inflate(state().lineWidth / 2);
+        c->strokeRect(rect, state().lineWidth);
+        didDraw(boundingRect);
+    }
+}
+
+void CanvasRenderingContext2DBase::setShadow(float width, float height, float blur, const String& colorString, std::optional<float> alpha)
+{
+    Color color = Color::transparent;
+    if (!colorString.isNull()) {
+        auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+        color = parseColorOrCurrentColor(colorString, &canvas);
+        if (!color.isValid())
+            return;
+    }
+    // FIXME: Should not use RGBA32 here.
+    setShadow(FloatSize(width, height), blur, colorWithOverrideAlpha(color.rgb(), alpha));
+}
+
+void CanvasRenderingContext2DBase::setShadow(float width, float height, float blur, float grayLevel, float alpha)
+{
+    setShadow(FloatSize(width, height), blur, Color(grayLevel, grayLevel, grayLevel, alpha));
+}
+
+void CanvasRenderingContext2DBase::setShadow(float width, float height, float blur, float r, float g, float b, float a)
+{
+    setShadow(FloatSize(width, height), blur, Color(r, g, b, a));
+}
+
+void CanvasRenderingContext2DBase::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a)
+{
+    setShadow(FloatSize(width, height), blur, Color(c, m, y, k, a));
+}
+
+void CanvasRenderingContext2DBase::clearShadow()
+{
+    setShadow(FloatSize(), 0, Color::transparent);
+}
+
+void CanvasRenderingContext2DBase::setShadow(const FloatSize& offset, float blur, const Color& color)
+{
+    if (state().shadowOffset == offset && state().shadowBlur == blur && state().shadowColor == color)
+        return;
+    bool wasDrawingShadows = shouldDrawShadows();
+    realizeSaves();
+    modifiableState().shadowOffset = offset;
+    modifiableState().shadowBlur = blur;
+    modifiableState().shadowColor = color;
+    if (!wasDrawingShadows && !shouldDrawShadows())
+        return;
+    applyShadow();
+}
+
+void CanvasRenderingContext2DBase::applyShadow()
+{
+    auto* c = drawingContext();
+    if (!c)
+        return;
+
+    if (shouldDrawShadows()) {
+        float width = state().shadowOffset.width();
+        float height = state().shadowOffset.height();
+        c->setLegacyShadow(FloatSize(width, -height), state().shadowBlur, state().shadowColor);
+    } else
+        c->setLegacyShadow(FloatSize(), 0, Color::transparent);
+}
+
+bool CanvasRenderingContext2DBase::shouldDrawShadows() const
+{
+    return state().shadowColor.isVisible() && (state().shadowBlur || !state().shadowOffset.isZero());
+}
+
+enum class ImageSizeType { AfterDevicePixelRatio, BeforeDevicePixelRatio };
+static LayoutSize size(HTMLImageElement& element, ImageSizeType sizeType = ImageSizeType::BeforeDevicePixelRatio)
+{
+    LayoutSize size;
+    if (auto* cachedImage = element.cachedImage()) {
+        size = cachedImage->imageSizeForRenderer(element.renderer(), 1.0f); // FIXME: Not sure about this.
+        if (sizeType == ImageSizeType::AfterDevicePixelRatio && is<RenderImage>(element.renderer()) && cachedImage->image() && !cachedImage->image()->hasRelativeWidth())
+            size.scale(downcast<RenderImage>(*element.renderer()).imageDevicePixelRatio());
+    }
+    return size;
+}
+
+static inline FloatSize size(HTMLCanvasElement& canvasElement)
+{
+    return canvasElement.size();
+}
+
+static inline FloatSize size(ImageBitmap& imageBitmap)
+{
+    return FloatSize { static_cast<float>(imageBitmap.width()), static_cast<float>(imageBitmap.height()) };
+}
+
+#if ENABLE(VIDEO)
+
+static inline FloatSize size(HTMLVideoElement& video)
+{
+    auto player = video.player();
+    if (!player)
+        return { };
+    return player->naturalSize();
+}
+
+#endif
+
+static inline FloatRect normalizeRect(const FloatRect& rect)
+{
+    return FloatRect(std::min(rect.x(), rect.maxX()),
+        std::min(rect.y(), rect.maxY()),
+        std::max(rect.width(), -rect.width()),
+        std::max(rect.height(), -rect.height()));
+}
+
+ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(CanvasImageSource&& image, float dx, float dy)
+{
+    return WTF::switchOn(image,
+        [&] (RefPtr<HTMLImageElement>& imageElement) -> ExceptionOr<void> {
+            LayoutSize destRectSize = size(*imageElement, ImageSizeType::AfterDevicePixelRatio);
+            LayoutSize sourceRectSize = size(*imageElement, ImageSizeType::BeforeDevicePixelRatio);
+            return this->drawImage(*imageElement, FloatRect { 0, 0, sourceRectSize.width(), sourceRectSize.height() }, FloatRect { dx, dy, destRectSize.width(), destRectSize.height() });
+        },
+        [&] (auto& element) -> ExceptionOr<void> {
+            FloatSize elementSize = size(*element);
+            return this->drawImage(*element, FloatRect { 0, 0, elementSize.width(), elementSize.height() }, FloatRect { dx, dy, elementSize.width(), elementSize.height() });
+        }
+    );
+}
+
+ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(CanvasImageSource&& image, float dx, float dy, float dw, float dh)
+{
+    return WTF::switchOn(image,
+        [&] (auto& element) -> ExceptionOr<void> {
+            FloatSize elementSize = size(*element);
+            return this->drawImage(*element, FloatRect { 0, 0, elementSize.width(), elementSize.height() }, FloatRect { dx, dy, dw, dh });
+        }
+    );
+}
+
+ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(CanvasImageSource&& image, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh)
+{
+    return WTF::switchOn(image,
+        [&] (auto& element) -> ExceptionOr<void> {
+            return this->drawImage(*element, FloatRect { sx, sy, sw, sh }, FloatRect { dx, dy, dw, dh });
+        }
+    );
+}
+
+ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(HTMLImageElement& imageElement, const FloatRect& srcRect, const FloatRect& dstRect)
+{
+    return drawImage(imageElement, srcRect, dstRect, state().globalComposite, state().globalBlend);
+}
+
+ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(HTMLImageElement& imageElement, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator& op, const BlendMode& blendMode)
+{
+    if (!std::isfinite(dstRect.x()) || !std::isfinite(dstRect.y()) || !std::isfinite(dstRect.width()) || !std::isfinite(dstRect.height())
+        || !std::isfinite(srcRect.x()) || !std::isfinite(srcRect.y()) || !std::isfinite(srcRect.width()) || !std::isfinite(srcRect.height()))
+        return { };
+
+    if (!dstRect.width() || !dstRect.height())
+        return { };
+
+    if (!imageElement.complete())
+        return { };
+
+    FloatRect normalizedSrcRect = normalizeRect(srcRect);
+    FloatRect normalizedDstRect = normalizeRect(dstRect);
+
+    FloatRect imageRect = FloatRect(FloatPoint(), size(imageElement, ImageSizeType::BeforeDevicePixelRatio));
+    if (!srcRect.width() || !srcRect.height())
+        return Exception { IndexSizeError };
+
+    // When the source rectangle is outside the source image, the source rectangle must be clipped
+    // to the source image and the destination rectangle must be clipped in the same proportion.
+    FloatRect originalNormalizedSrcRect = normalizedSrcRect;
+    normalizedSrcRect.intersect(imageRect);
+    if (normalizedSrcRect.isEmpty())
+        return { };
+
+    if (normalizedSrcRect != originalNormalizedSrcRect) {
+        normalizedDstRect.setWidth(normalizedDstRect.width() * normalizedSrcRect.width() / originalNormalizedSrcRect.width());
+        normalizedDstRect.setHeight(normalizedDstRect.height() * normalizedSrcRect.height() / originalNormalizedSrcRect.height());
+        if (normalizedDstRect.isEmpty())
+            return { };
+    }
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return { };
+    if (!state().hasInvertibleTransform)
+        return { };
+
+    CachedImage* cachedImage = imageElement.cachedImage();
+    if (!cachedImage)
+        return { };
+
+    RefPtr<Image> image = cachedImage->imageForRenderer(imageElement.renderer());
+    if (!image)
+        return { };
+
+    ImageObserver* observer = image->imageObserver();
+
+    if (image->isSVGImage()) {
+        image->setImageObserver(nullptr);
+        image->setContainerSize(imageRect.size());
+    }
+
+    if (image->isBitmapImage())
+        downcast<BitmapImage>(*image).updateFromSettings(imageElement.document().settings());
+
+    if (rectContainsCanvas(normalizedDstRect)) {
+        c->drawImage(*image, normalizedDstRect, normalizedSrcRect, ImagePaintingOptions(op, blendMode));
+        didDrawEntireCanvas();
+    } else if (isFullCanvasCompositeMode(op)) {
+        fullCanvasCompositedDrawImage(*image, normalizedDstRect, normalizedSrcRect, op);
+        didDrawEntireCanvas();
+    } else if (op == CompositeCopy) {
+        clearCanvas();
+        c->drawImage(*image, normalizedDstRect, normalizedSrcRect, ImagePaintingOptions(op, blendMode));
+        didDrawEntireCanvas();
+    } else {
+        c->drawImage(*image, normalizedDstRect, normalizedSrcRect, ImagePaintingOptions(op, blendMode));
+        didDraw(normalizedDstRect);
+    }
+    
+    if (image->isSVGImage())
+        image->setImageObserver(observer);
+
+    checkOrigin(&imageElement);
+
+    return { };
+}
+
+ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(HTMLCanvasElement& sourceCanvas, const FloatRect& srcRect, const FloatRect& dstRect)
+{
+    FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas.size());
+
+    if (!srcCanvasRect.width() || !srcCanvasRect.height())
+        return Exception { InvalidStateError };
+
+    if (!srcRect.width() || !srcRect.height())
+        return Exception { IndexSizeError };
+
+    if (!srcCanvasRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
+        return { };
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return { };
+    if (!state().hasInvertibleTransform)
+        return { };
+
+    // FIXME: Do this through platform-independent GraphicsContext API.
+    ImageBuffer* buffer = sourceCanvas.buffer();
+    if (!buffer)
+        return { };
+
+    checkOrigin(&sourceCanvas);
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+    // If we're drawing from one accelerated canvas 2d to another, avoid calling sourceCanvas.makeRenderingResultsAvailable()
+    // as that will do a readback to software.
+    RefPtr<CanvasRenderingContext> sourceContext = sourceCanvas.renderingContext();
+    // FIXME: Implement an accelerated path for drawing from a WebGL canvas to a 2d canvas when possible.
+    if (!isAccelerated() || !sourceContext || !sourceContext->isAccelerated() || !sourceContext->is2d())
+        sourceCanvas.makeRenderingResultsAvailable();
+#else
+    sourceCanvas.makeRenderingResultsAvailable();
+#endif
+
+    if (rectContainsCanvas(dstRect)) {
+        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
+        didDrawEntireCanvas();
+    } else if (isFullCanvasCompositeMode(state().globalComposite)) {
+        fullCanvasCompositedDrawImage(*buffer, dstRect, srcRect, state().globalComposite);
+        didDrawEntireCanvas();
+    } else if (state().globalComposite == CompositeCopy) {
+        clearCanvas();
+        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
+        didDrawEntireCanvas();
+    } else {
+        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
+        didDraw(dstRect);
+    }
+
+    return { };
+}
+
+#if ENABLE(VIDEO)
+
+ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(HTMLVideoElement& video, const FloatRect& srcRect, const FloatRect& dstRect)
+{
+    if (video.readyState() == HTMLMediaElement::HAVE_NOTHING || video.readyState() == HTMLMediaElement::HAVE_METADATA)
+        return { };
+
+    FloatRect videoRect = FloatRect(FloatPoint(), size(video));
+    if (!srcRect.width() || !srcRect.height())
+        return Exception { IndexSizeError };
+
+    if (!videoRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
+        return { };
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return { };
+    if (!state().hasInvertibleTransform)
+        return { };
+
+    checkOrigin(&video);
+
+#if USE(CG) || (ENABLE(ACCELERATED_2D_CANVAS) && USE(GSTREAMER_GL) && USE(CAIRO))
+    if (NativeImagePtr image = video.nativeImageForCurrentTime()) {
+        c->drawNativeImage(image, FloatSize(video.videoWidth(), video.videoHeight()), dstRect, srcRect);
+        if (rectContainsCanvas(dstRect))
+            didDrawEntireCanvas();
+        else
+            didDraw(dstRect);
+
+        return { };
+    }
+#endif
+
+    GraphicsContextStateSaver stateSaver(*c);
+    c->clip(dstRect);
+    c->translate(dstRect.location());
+    c->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height()));
+    c->translate(-srcRect.location());
+    video.paintCurrentFrameInContext(*c, FloatRect(FloatPoint(), size(video)));
+    stateSaver.restore();
+    didDraw(dstRect);
+
+    return { };
+}
+
+#endif
+
+ExceptionOr<void> CanvasRenderingContext2DBase::drawImage(ImageBitmap& imageBitmap, const FloatRect& srcRect, const FloatRect& dstRect)
+{
+    if (!imageBitmap.width() || !imageBitmap.height())
+        return Exception { InvalidStateError };
+
+    if (!srcRect.width() || !srcRect.height())
+        return Exception { IndexSizeError };
+
+    FloatRect srcBitmapRect = FloatRect(FloatPoint(), FloatSize(imageBitmap.width(), imageBitmap.height()));
+
+    if (!srcBitmapRect.contains(normalizeRect(srcRect)) || !dstRect.width() || !dstRect.height())
+        return { };
+
+    GraphicsContext* c = drawingContext();
+    if (!c)
+        return { };
+    if (!state().hasInvertibleTransform)
+        return { };
+
+    ImageBuffer* buffer = imageBitmap.buffer();
+    if (!buffer)
+        return { };
+
+    checkOrigin(&imageBitmap);
+
+    if (rectContainsCanvas(dstRect)) {
+        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
+        didDrawEntireCanvas();
+    } else if (isFullCanvasCompositeMode(state().globalComposite)) {
+        fullCanvasCompositedDrawImage(*buffer, dstRect, srcRect, state().globalComposite);
+        didDrawEntireCanvas();
+    } else if (state().globalComposite == CompositeCopy) {
+        clearCanvas();
+        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
+        didDrawEntireCanvas();
+    } else {
+        c->drawImageBuffer(*buffer, dstRect, srcRect, ImagePaintingOptions(state().globalComposite, state().globalBlend));
+        didDraw(dstRect);
+    }
+
+    return { };
+}
+
+void CanvasRenderingContext2DBase::drawImageFromRect(HTMLImageElement& imageElement, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, const String& compositeOperation)
+{
+    CompositeOperator op;
+    auto blendOp = BlendModeNormal;
+    if (!parseCompositeAndBlendOperator(compositeOperation, op, blendOp) || blendOp != BlendModeNormal)
+        op = CompositeSourceOver;
+    drawImage(imageElement, FloatRect { sx, sy, sw, sh }, FloatRect { dx, dy, dw, dh }, op, BlendModeNormal);
+}
+
+void CanvasRenderingContext2DBase::clearCanvas()
+{
+    auto* c = drawingContext();
+    if (!c)
+        return;
+
+    c->save();
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    c->setCTM(canvas.baseTransform());
+    c->clearRect(FloatRect(0, 0, canvas.width(), canvas.height()));
+    c->restore();
+}
+
+Path CanvasRenderingContext2DBase::transformAreaToDevice(const Path& path) const
+{
+    Path transformed(path);
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    transformed.transform(state().transform);
+    transformed.transform(canvas.baseTransform());
+    return transformed;
+}
+
+Path CanvasRenderingContext2DBase::transformAreaToDevice(const FloatRect& rect) const
+{
+    Path path;
+    path.addRect(rect);
+    return transformAreaToDevice(path);
+}
+
+bool CanvasRenderingContext2DBase::rectContainsCanvas(const FloatRect& rect) const
+{
+    FloatQuad quad(rect);
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    FloatQuad canvasQuad(FloatRect(0, 0, canvas.width(), canvas.height()));
+    return state().transform.mapQuad(quad).containsQuad(canvasQuad);
+}
+
+template<class T> IntRect CanvasRenderingContext2DBase::calculateCompositingBufferRect(const T& area, IntSize* croppedOffset)
+{
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+
+    IntRect canvasRect(0, 0, canvas.width(), canvas.height());
+    canvasRect = canvas.baseTransform().mapRect(canvasRect);
+    Path path = transformAreaToDevice(area);
+    IntRect bufferRect = enclosingIntRect(path.fastBoundingRect());
+    IntPoint originalLocation = bufferRect.location();
+    bufferRect.intersect(canvasRect);
+    if (croppedOffset)
+        *croppedOffset = originalLocation - bufferRect.location();
+    return bufferRect;
+}
+
+std::unique_ptr<ImageBuffer> CanvasRenderingContext2DBase::createCompositingBuffer(const IntRect& bufferRect)
+{
+    return ImageBuffer::create(bufferRect.size(), isAccelerated() ? Accelerated : Unaccelerated);
+}
+
+void CanvasRenderingContext2DBase::compositeBuffer(ImageBuffer& buffer, const IntRect& bufferRect, CompositeOperator op)
+{
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    IntRect canvasRect(0, 0, canvas.width(), canvas.height());
+    canvasRect = canvas.baseTransform().mapRect(canvasRect);
+
+    auto* c = drawingContext();
+    if (!c)
+        return;
+
+    c->save();
+    c->setCTM(AffineTransform());
+    c->setCompositeOperation(op);
+
+    c->save();
+    c->clipOut(bufferRect);
+    c->clearRect(canvasRect);
+    c->restore();
+    c->drawImageBuffer(buffer, bufferRect.location(), state().globalComposite);
+    c->restore();
+}
+
+static void drawImageToContext(Image& image, GraphicsContext& context, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
+{
+    context.drawImage(image, dest, src, op);
+}
+
+static void drawImageToContext(ImageBuffer& imageBuffer, GraphicsContext& context, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
+{
+    context.drawImageBuffer(imageBuffer, dest, src, op);
+}
+
+template<class T> void CanvasRenderingContext2DBase::fullCanvasCompositedDrawImage(T& image, const FloatRect& dest, const FloatRect& src, CompositeOperator op)
+{
+    ASSERT(isFullCanvasCompositeMode(op));
+
+    IntSize croppedOffset;
+    auto bufferRect = calculateCompositingBufferRect(dest, &croppedOffset);
+    if (bufferRect.isEmpty()) {
+        clearCanvas();
+        return;
+    }
+
+    auto buffer = createCompositingBuffer(bufferRect);
+    if (!buffer)
+        return;
+
+    auto* c = drawingContext();
+    if (!c)
+        return;
+
+    FloatRect adjustedDest = dest;
+    adjustedDest.setLocation(FloatPoint(0, 0));
+    AffineTransform effectiveTransform = c->getCTM();
+    IntRect transformedAdjustedRect = enclosingIntRect(effectiveTransform.mapRect(adjustedDest));
+    buffer->context().translate(-transformedAdjustedRect.location());
+    buffer->context().translate(croppedOffset);
+    buffer->context().concatCTM(effectiveTransform);
+    drawImageToContext(image, buffer->context(), adjustedDest, src, CompositeSourceOver);
+
+    compositeBuffer(*buffer, bufferRect, op);
+}
+
+void CanvasRenderingContext2DBase::prepareGradientForDashboard(CanvasGradient& gradient) const
+{
+#if ENABLE(DASHBOARD_SUPPORT)
+    if (m_usesDashboardCompatibilityMode)
+        gradient.setDashboardCompatibilityMode();
+#else
+    UNUSED_PARAM(gradient);
+#endif
+}
+
+static CanvasRenderingContext2DBase::Style toStyle(const CanvasStyle& style)
+{
+    if (auto gradient = style.canvasGradient())
+        return gradient;
+    if (auto pattern = style.canvasPattern())
+        return pattern;
+    return style.color();
+}
+
+CanvasRenderingContext2DBase::Style CanvasRenderingContext2DBase::strokeStyle() const
+{
+    return toStyle(state().strokeStyle);
+}
+
+void CanvasRenderingContext2DBase::setStrokeStyle(CanvasRenderingContext2DBase::Style&& style)
+{
+    WTF::switchOn(style,
+        [this] (const String& string) { this->setStrokeColor(string); },
+        [this] (const RefPtr<CanvasGradient>& gradient) { this->setStrokeStyle(CanvasStyle(*gradient)); },
+        [this] (const RefPtr<CanvasPattern>& pattern) { this->setStrokeStyle(CanvasStyle(*pattern)); }
+    );
+}
+
+CanvasRenderingContext2DBase::Style CanvasRenderingContext2DBase::fillStyle() const
+{
+    return toStyle(state().fillStyle);
+}
+
+void CanvasRenderingContext2DBase::setFillStyle(CanvasRenderingContext2DBase::Style&& style)
+{
+    WTF::switchOn(style,
+        [this] (const String& string) { this->setFillColor(string); },
+        [this] (const RefPtr<CanvasGradient>& gradient) { this->setFillStyle(CanvasStyle(*gradient)); },
+        [this] (const RefPtr<CanvasPattern>& pattern) { this->setFillStyle(CanvasStyle(*pattern)); }
+    );
+}
+
+ExceptionOr<Ref<CanvasGradient>> CanvasRenderingContext2DBase::createLinearGradient(float x0, float y0, float x1, float y1)
+{
+    if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(x1) || !std::isfinite(y1))
+        return Exception { NotSupportedError };
+
+    auto gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1));
+    prepareGradientForDashboard(gradient.get());
+    return WTFMove(gradient);
+}
+
+ExceptionOr<Ref<CanvasGradient>> CanvasRenderingContext2DBase::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1)
+{
+    if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(r0) || !std::isfinite(x1) || !std::isfinite(y1) || !std::isfinite(r1))
+        return Exception { NotSupportedError };
+
+    if (r0 < 0 || r1 < 0)
+        return Exception { IndexSizeError };
+
+    auto gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1);
+    prepareGradientForDashboard(gradient.get());
+    return WTFMove(gradient);
+}
+
+ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(CanvasImageSource&& image, const String& repetition)
+{
+    bool repeatX, repeatY;
+    if (!CanvasPattern::parseRepetitionType(repetition, repeatX, repeatY))
+        return Exception { SyntaxError };
+
+    return WTF::switchOn(image,
+        [&] (auto& element) -> ExceptionOr<RefPtr<CanvasPattern>> { return this->createPattern(*element, repeatX, repeatY); }
+    );
+}
+
+ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(HTMLImageElement& imageElement, bool repeatX, bool repeatY)
+{
+    auto* cachedImage = imageElement.cachedImage();
+
+    // If the image loading hasn't started or the image is not complete, it is not fully decodable.
+    if (!cachedImage || !imageElement.complete())
+        return nullptr;
+
+    if (cachedImage->status() == CachedResource::LoadError)
+        return Exception { InvalidStateError };
+
+    bool originClean = cachedImage->isOriginClean(canvasBase().securityOrigin());
+
+    // FIXME: SVG images with animations can switch between clean and dirty (leaking cross-origin
+    // data). We should either:
+    //   1) Take a fixed snapshot of an SVG image when creating a pattern and determine then whether
+    //      the origin is clean.
+    //   2) Dynamically verify the origin checks at draw time, and dirty the canvas accordingly.
+    // To be on the safe side, taint the origin for all patterns containing SVG images for now.
+    if (cachedImage->image()->isSVGImage())
+        originClean = false;
+
+    return RefPtr<CanvasPattern> { CanvasPattern::create(*cachedImage->imageForRenderer(imageElement.renderer()), repeatX, repeatY, originClean) };
+}
+
+ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(HTMLCanvasElement& canvas, bool repeatX, bool repeatY)
+{
+    if (!canvas.width() || !canvas.height() || !canvas.buffer())
+        return Exception { InvalidStateError };
+
+    return RefPtr<CanvasPattern> { CanvasPattern::create(*canvas.copiedImage(), repeatX, repeatY, canvas.originClean()) };
+}
+    
+#if ENABLE(VIDEO)
+
+ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(HTMLVideoElement& videoElement, bool repeatX, bool repeatY)
+{
+    if (videoElement.readyState() < HTMLMediaElement::HAVE_CURRENT_DATA)
+        return nullptr;
+    
+    checkOrigin(&videoElement);
+    bool originClean = canvasBase().originClean();
+
+#if USE(CG) || (ENABLE(ACCELERATED_2D_CANVAS) && USE(GSTREAMER_GL) && USE(CAIRO))
+    if (auto nativeImage = videoElement.nativeImageForCurrentTime())
+        return RefPtr<CanvasPattern> { CanvasPattern::create(BitmapImage::create(WTFMove(nativeImage)), repeatX, repeatY, originClean) };
+#endif
+
+    auto imageBuffer = ImageBuffer::create(size(videoElement), drawingContext() ? drawingContext()->renderingMode() : Accelerated);
+    videoElement.paintCurrentFrameInContext(imageBuffer->context(), FloatRect(FloatPoint(), size(videoElement)));
+    
+    return RefPtr<CanvasPattern> { CanvasPattern::create(ImageBuffer::sinkIntoImage(WTFMove(imageBuffer), Unscaled).releaseNonNull(), repeatX, repeatY, originClean) };
+}
+
+#endif
+
+ExceptionOr<RefPtr<CanvasPattern>> CanvasRenderingContext2DBase::createPattern(ImageBitmap&, bool, bool)
+{
+    // FIXME: Implement.
+    return Exception { TypeError };
+}
+
+void CanvasRenderingContext2DBase::didDrawEntireCanvas()
+{
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    didDraw(FloatRect(FloatPoint::zero(), canvas.size()), CanvasDidDrawApplyClip);
+}
+
+void CanvasRenderingContext2DBase::didDraw(const FloatRect& r, unsigned options)
+{
+    auto* c = drawingContext();
+    if (!c)
+        return;
+    if (!state().hasInvertibleTransform)
+        return;
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+    // If we are drawing to hardware and we have a composited layer, just call contentChanged().
+    if (isAccelerated()) {
+        RenderBox* renderBox = canvas().renderBox();
+        if (renderBox && renderBox->hasAcceleratedCompositing()) {
+            renderBox->contentChanged(CanvasPixelsChanged);
+            canvas().clearCopiedImage();
+            canvas().notifyObserversCanvasChanged(r);
+            return;
+        }
+    }
+#endif
+
+    FloatRect dirtyRect = r;
+    if (options & CanvasDidDrawApplyTransform) {
+        AffineTransform ctm = state().transform;
+        dirtyRect = ctm.mapRect(r);
+    }
+
+    if (options & CanvasDidDrawApplyShadow && state().shadowColor.isVisible()) {
+        // The shadow gets applied after transformation
+        FloatRect shadowRect(dirtyRect);
+        shadowRect.move(state().shadowOffset);
+        shadowRect.inflate(state().shadowBlur);
+        dirtyRect.unite(shadowRect);
+    }
+
+    if (options & CanvasDidDrawApplyClip) {
+        // FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
+        // back out of the GraphicsContext, so to take clip into account for incremental painting,
+        // we'd have to keep the clip path around.
+    }
+
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    canvas.didDraw(dirtyRect);
+}
+
+void CanvasRenderingContext2DBase::setTracksDisplayListReplay(bool tracksDisplayListReplay)
+{
+    if (tracksDisplayListReplay == m_tracksDisplayListReplay)
+        return;
+
+    m_tracksDisplayListReplay = tracksDisplayListReplay;
+    if (!m_tracksDisplayListReplay)
+        contextDisplayListMap().remove(this);
+}
+
+String CanvasRenderingContext2DBase::displayListAsText(DisplayList::AsTextFlags flags) const
+{
+    if (!m_recordingContext)
+        return { };
+    return m_recordingContext->displayList.asText(flags);
+}
+
+String CanvasRenderingContext2DBase::replayDisplayListAsText(DisplayList::AsTextFlags flags) const
+{
+    auto* displayList = contextDisplayListMap().get(this);
+    if (!displayList)
+        return { };
+    return displayList->asText(flags);
+}
+
+void CanvasRenderingContext2DBase::paintRenderingResultsToCanvas()
+{
+    if (UNLIKELY(m_usesDisplayListDrawing)) {
+        if (!m_recordingContext)
+            return;
+
+        auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+
+        FloatRect clip(FloatPoint::zero(), canvas.size());
+        DisplayList::Replayer replayer(*canvas.drawingContext(), m_recordingContext->displayList);
+
+        if (UNLIKELY(m_tracksDisplayListReplay)) {
+            auto replayList = replayer.replay(clip, m_tracksDisplayListReplay);
+            contextDisplayListMap().add(this, WTFMove(replayList));
+        } else
+            replayer.replay(clip);
+
+        m_recordingContext->displayList.clear();
+    }
+}
+
+GraphicsContext* CanvasRenderingContext2DBase::drawingContext() const
+{
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+    if (UNLIKELY(m_usesDisplayListDrawing)) {
+        if (!m_recordingContext)
+            m_recordingContext = std::make_unique<DisplayListDrawingContext>(FloatRect(FloatPoint::zero(), canvas.size()));
+        return &m_recordingContext->context;
+    }
+
+    return canvas.drawingContext();
+}
+
+static RefPtr<ImageData> createEmptyImageData(const IntSize& size)
+{
+    auto data = ImageData::create(size);
+    if (data)
+        data->data()->zeroFill();
+    return data;
+}
+
+ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2DBase::createImageData(ImageData* imageData) const
+{
+    if (!imageData)
+        return Exception { NotSupportedError };
+
+    return createEmptyImageData(imageData->size());
+}
+
+ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2DBase::createImageData(float sw, float sh) const
+{
+    if (!sw || !sh)
+        return Exception { IndexSizeError };
+
+    FloatSize logicalSize(std::abs(sw), std::abs(sh));
+    if (!logicalSize.isExpressibleAsIntSize())
+        return nullptr;
+
+    IntSize size = expandedIntSize(logicalSize);
+    if (size.width() < 1)
+        size.setWidth(1);
+    if (size.height() < 1)
+        size.setHeight(1);
+
+    return createEmptyImageData(size);
+}
+
+ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2DBase::getImageData(float sx, float sy, float sw, float sh) const
+{
+    return getImageData(ImageBuffer::LogicalCoordinateSystem, sx, sy, sw, sh);
+}
+
+ExceptionOr<RefPtr<ImageData>> CanvasRenderingContext2DBase::getImageData(ImageBuffer::CoordinateSystem coordinateSystem, float sx, float sy, float sw, float sh) const
+{
+    if (!canvasBase().originClean()) {
+        static NeverDestroyed<String> consoleMessage(MAKE_STATIC_STRING_IMPL("Unable to get image data from canvas because the canvas has been tainted by cross-origin data."));
+        canvasBase().scriptExecutionContext()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, consoleMessage);
+        return Exception { SecurityError };
+    }
+
+    if (!sw || !sh)
+        return Exception { IndexSizeError };
+
+    if (sw < 0) {
+        sx += sw;
+        sw = -sw;
+    }    
+    if (sh < 0) {
+        sy += sh;
+        sh = -sh;
+    }
+
+    FloatRect logicalRect(sx, sy, sw, sh);
+    if (logicalRect.width() < 1)
+        logicalRect.setWidth(1);
+    if (logicalRect.height() < 1)
+        logicalRect.setHeight(1);
+    if (!logicalRect.isExpressibleAsIntRect())
+        return nullptr;
+
+    IntRect imageDataRect = enclosingIntRect(logicalRect);
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+
+    ImageBuffer* buffer = canvas.buffer();
+    if (!buffer)
+        return createEmptyImageData(imageDataRect.size());
+
+    auto byteArray = buffer->getUnmultipliedImageData(imageDataRect, nullptr, coordinateSystem);
+    if (!byteArray) {
+        StringBuilder consoleMessage;
+        consoleMessage.appendLiteral("Unable to get image data from canvas. Requested size was ");
+        consoleMessage.appendNumber(imageDataRect.width());
+        consoleMessage.appendLiteral(" x ");
+        consoleMessage.appendNumber(imageDataRect.height());
+
+        canvasBase().scriptExecutionContext()->addConsoleMessage(MessageSource::Rendering, MessageLevel::Error, consoleMessage.toString());
+        return Exception { InvalidStateError };
+    }
+
+    return ImageData::create(imageDataRect.size(), byteArray.releaseNonNull());
+}
+
+void CanvasRenderingContext2DBase::putImageData(ImageData& data, float dx, float dy)
+{
+    putImageData(data, dx, dy, 0, 0, data.width(), data.height());
+}
+
+void CanvasRenderingContext2DBase::putImageData(ImageData& data, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight)
+{
+    putImageData(data, ImageBuffer::LogicalCoordinateSystem, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+}
+
+void CanvasRenderingContext2DBase::putImageData(ImageData& data, ImageBuffer::CoordinateSystem coordinateSystem, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight)
+{
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+
+    ImageBuffer* buffer = canvas.buffer();
+    if (!buffer)
+        return;
+
+    if (!data.data())
+        return;
+
+    if (dirtyWidth < 0) {
+        dirtyX += dirtyWidth;
+        dirtyWidth = -dirtyWidth;
+    }
+
+    if (dirtyHeight < 0) {
+        dirtyY += dirtyHeight;
+        dirtyHeight = -dirtyHeight;
+    }
+
+    FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+    clipRect.intersect(IntRect(0, 0, data.width(), data.height()));
+    IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy));
+    IntRect destRect = enclosingIntRect(clipRect);
+    destRect.move(destOffset);
+    destRect.intersect(IntRect(IntPoint(), coordinateSystem == ImageBuffer::LogicalCoordinateSystem ? buffer->logicalSize() : buffer->internalSize()));
+    if (destRect.isEmpty())
+        return;
+    IntRect sourceRect(destRect);
+    sourceRect.move(-destOffset);
+    sourceRect.intersect(IntRect(0, 0, data.width(), data.height()));
+
+    if (!sourceRect.isEmpty())
+        buffer->putByteArray(*data.data(), AlphaPremultiplication::Unpremultiplied, IntSize(data.width(), data.height()), sourceRect, IntPoint(destOffset), coordinateSystem);
+
+    didDraw(destRect, CanvasDidDrawApplyNone); // ignore transform, shadow and clip
+}
+
+void CanvasRenderingContext2DBase::inflateStrokeRect(FloatRect& rect) const
+{
+    // Fast approximation of the stroke's bounding rect.
+    // This yields a slightly oversized rect but is very fast
+    // compared to Path::strokeBoundingRect().
+    static const float root2 = sqrtf(2);
+    float delta = state().lineWidth / 2;
+    if (state().lineJoin == MiterJoin)
+        delta *= state().miterLimit;
+    else if (state().lineCap == SquareCap)
+        delta *= root2;
+    rect.inflate(delta);
+}
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+
+PlatformLayer* CanvasRenderingContext2DBase::platformLayer() const
+{
+    auto& canvas = downcast<HTMLCanvasElement>(canvasBase());
+
+    return canvas.buffer() ? canvas.buffer()->platformLayer() : nullptr;
+}
+
+#endif
+
+static inline InterpolationQuality smoothingToInterpolationQuality(ImageSmoothingQuality quality)
+{
+    switch (quality) {
+    case ImageSmoothingQuality::Low:
+        return InterpolationLow;
+    case ImageSmoothingQuality::Medium:
+        return InterpolationMedium;
+    case ImageSmoothingQuality::High:
+        return InterpolationHigh;
+    }
+
+    ASSERT_NOT_REACHED();
+    return InterpolationLow;
+};
+
+auto CanvasRenderingContext2DBase::imageSmoothingQuality() const -> ImageSmoothingQuality
+{
+    return state().imageSmoothingQuality;
+}
+
+void CanvasRenderingContext2DBase::setImageSmoothingQuality(ImageSmoothingQuality quality)
+{
+    if (quality == state().imageSmoothingQuality)
+        return;
+
+    realizeSaves();
+    modifiableState().imageSmoothingQuality = quality;
+
+    if (!state().imageSmoothingEnabled)
+        return;
+
+    if (auto* context = drawingContext())
+        context->setImageInterpolationQuality(smoothingToInterpolationQuality(quality));
+}
+
+bool CanvasRenderingContext2DBase::imageSmoothingEnabled() const
+{
+    return state().imageSmoothingEnabled;
+}
+
+void CanvasRenderingContext2DBase::setImageSmoothingEnabled(bool enabled)
+{
+    if (enabled == state().imageSmoothingEnabled)
+        return;
+
+    realizeSaves();
+    modifiableState().imageSmoothingEnabled = enabled;
+    auto* c = drawingContext();
+    if (c)
+        c->setImageInterpolationQuality(enabled ? smoothingToInterpolationQuality(state().imageSmoothingQuality) : InterpolationNone);
+}
+
+void CanvasRenderingContext2DBase::setPath(Path2D& path)
+{
+    m_path = path.path();
+}
+
+Ref<Path2D> CanvasRenderingContext2DBase::getPath() const
+{
+    return Path2D::create(m_path);
+}
+
+inline void CanvasRenderingContext2DBase::clearPathForDashboardBackwardCompatibilityMode()
+{
+#if ENABLE(DASHBOARD_SUPPORT)
+    if (m_usesDashboardCompatibilityMode)
+        m_path.clear();
+#endif
+}
+
+} // namespace WebCore
</ins></span></pre></div>
<a id="trunkSourceWebCorehtmlcanvasCanvasRenderingContext2DBasehfromrev225815trunkSourceWebCorehtmlcanvasCanvasRenderingContext2Dh"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.h (from rev 225815, trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.h) (0 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.h                          (rev 0)
+++ trunk/Source/WebCore/html/canvas/CanvasRenderingContext2DBase.h     2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -0,0 +1,382 @@
</span><ins>+/*
+ * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012, 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "AffineTransform.h"
+#include "CanvasDirection.h"
+#include "CanvasFillRule.h"
+#include "CanvasLineCap.h"
+#include "CanvasLineJoin.h"
+#include "CanvasPath.h"
+#include "CanvasRenderingContext.h"
+#include "CanvasStyle.h"
+#include "CanvasTextAlign.h"
+#include "CanvasTextBaseline.h"
+#include "Color.h"
+#include "FloatSize.h"
+#include "FontCascade.h"
+#include "FontSelectorClient.h"
+#include "GraphicsContext.h"
+#include "GraphicsTypes.h"
+#include "ImageBuffer.h"
+#include "ImageSmoothingQuality.h"
+#include "Path.h"
+#include "PlatformLayer.h"
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class CanvasBase;
+class CanvasGradient;
+class CanvasPattern;
+class DOMMatrix;
+class FloatRect;
+class GraphicsContext;
+class HTMLImageElement;
+class HTMLVideoElement;
+class ImageBitmap;
+class ImageData;
+class Path2D;
+class TextMetrics;
+
+struct DOMMatrix2DInit;
+
+#if ENABLE(VIDEO)
+using CanvasImageSource = Variant<RefPtr<HTMLImageElement>, RefPtr<HTMLVideoElement>, RefPtr<HTMLCanvasElement>, RefPtr<ImageBitmap>>;
+#else
+using CanvasImageSource = Variant<RefPtr<HTMLImageElement>, RefPtr<HTMLCanvasElement>, RefPtr<ImageBitmap>>;
+#endif
+
+class CanvasRenderingContext2DBase : public CanvasRenderingContext, public CanvasPath {
+public:
+    CanvasRenderingContext2DBase(CanvasBase&, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode);
+    virtual ~CanvasRenderingContext2DBase();
+
+    float lineWidth() const;
+    void setLineWidth(float);
+
+    CanvasLineCap lineCap() const;
+    void setLineCap(CanvasLineCap);
+    void setLineCap(const String&);
+
+    CanvasLineJoin lineJoin() const;
+    void setLineJoin(CanvasLineJoin);
+    void setLineJoin(const String&);
+
+    float miterLimit() const;
+    void setMiterLimit(float);
+
+    const Vector<float>& getLineDash() const;
+    void setLineDash(const Vector<float>&);
+    const Vector<float>& webkitLineDash() const { return getLineDash(); }
+    void setWebkitLineDash(const Vector<float>&);
+
+    float lineDashOffset() const;
+    void setLineDashOffset(float);
+
+    float shadowOffsetX() const;
+    void setShadowOffsetX(float);
+
+    float shadowOffsetY() const;
+    void setShadowOffsetY(float);
+
+    float shadowBlur() const;
+    void setShadowBlur(float);
+
+    String shadowColor() const;
+    void setShadowColor(const String&);
+
+    float globalAlpha() const;
+    void setGlobalAlpha(float);
+
+    String globalCompositeOperation() const;
+    void setGlobalCompositeOperation(const String&);
+
+    void save() { ++m_unrealizedSaveCount; }
+    void restore();
+
+    void scale(float sx, float sy);
+    void rotate(float angleInRadians);
+    void translate(float tx, float ty);
+    void transform(float m11, float m12, float m21, float m22, float dx, float dy);
+
+    Ref<DOMMatrix> getTransform() const;
+    void setTransform(float m11, float m12, float m21, float m22, float dx, float dy);
+    ExceptionOr<void> setTransform(DOMMatrix2DInit&&);
+    void resetTransform();
+
+    void setStrokeColor(const String& color, std::optional<float> alpha = std::nullopt);
+    void setStrokeColor(float grayLevel, float alpha = 1.0);
+    void setStrokeColor(float r, float g, float b, float a);
+    void setStrokeColor(float c, float m, float y, float k, float a);
+
+    void setFillColor(const String& color, std::optional<float> alpha = std::nullopt);
+    void setFillColor(float grayLevel, float alpha = 1.0f);
+    void setFillColor(float r, float g, float b, float a);
+    void setFillColor(float c, float m, float y, float k, float a);
+
+    void beginPath();
+
+    void fill(CanvasFillRule = CanvasFillRule::Nonzero);
+    void stroke();
+    void clip(CanvasFillRule = CanvasFillRule::Nonzero);
+
+    void fill(Path2D&, CanvasFillRule = CanvasFillRule::Nonzero);
+    void stroke(Path2D&);
+    void clip(Path2D&, CanvasFillRule = CanvasFillRule::Nonzero);
+
+    bool isPointInPath(float x, float y, CanvasFillRule = CanvasFillRule::Nonzero);
+    bool isPointInStroke(float x, float y);
+
+    bool isPointInPath(Path2D&, float x, float y, CanvasFillRule = CanvasFillRule::Nonzero);
+    bool isPointInStroke(Path2D&, float x, float y);
+
+    void clearRect(float x, float y, float width, float height);
+    void fillRect(float x, float y, float width, float height);
+    void strokeRect(float x, float y, float width, float height);
+
+    void setShadow(float width, float height, float blur, const String& color = String(), std::optional<float> alpha = std::nullopt);
+    void setShadow(float width, float height, float blur, float grayLevel, float alpha = 1.0);
+    void setShadow(float width, float height, float blur, float r, float g, float b, float a);
+    void setShadow(float width, float height, float blur, float c, float m, float y, float k, float a);
+
+    void clearShadow();
+
+    ExceptionOr<void> drawImage(CanvasImageSource&&, float dx, float dy);
+    ExceptionOr<void> drawImage(CanvasImageSource&&, float dx, float dy, float dw, float dh);
+    ExceptionOr<void> drawImage(CanvasImageSource&&, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh);
+
+    void drawImageFromRect(HTMLImageElement&, float sx = 0, float sy = 0, float sw = 0, float sh = 0, float dx = 0, float dy = 0, float dw = 0, float dh = 0, const String& compositeOperation = emptyString());
+
+    using Style = Variant<String, RefPtr<CanvasGradient>, RefPtr<CanvasPattern>>;
+    Style strokeStyle() const;
+    void setStrokeStyle(Style&&);
+    Style fillStyle() const;
+    void setFillStyle(Style&&);
+
+    ExceptionOr<Ref<CanvasGradient>> createLinearGradient(float x0, float y0, float x1, float y1);
+    ExceptionOr<Ref<CanvasGradient>> createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1);
+    ExceptionOr<RefPtr<CanvasPattern>> createPattern(CanvasImageSource&&, const String& repetition);
+
+    ExceptionOr<RefPtr<ImageData>> createImageData(ImageData*) const;
+    ExceptionOr<RefPtr<ImageData>> createImageData(float width, float height) const;
+    ExceptionOr<RefPtr<ImageData>> getImageData(float sx, float sy, float sw, float sh) const;
+    void putImageData(ImageData&, float dx, float dy);
+    void putImageData(ImageData&, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight);
+
+    float webkitBackingStorePixelRatio() const { return 1; }
+
+    void reset();
+
+    LineCap getLineCap() const { return state().lineCap; }
+    LineJoin getLineJoin() const { return state().lineJoin; }
+
+    bool imageSmoothingEnabled() const;
+    void setImageSmoothingEnabled(bool);
+
+    ImageSmoothingQuality imageSmoothingQuality() const;
+    void setImageSmoothingQuality(ImageSmoothingQuality);
+
+    void setPath(Path2D&);
+    Ref<Path2D> getPath() const;
+
+    bool usesDisplayListDrawing() const { return m_usesDisplayListDrawing; };
+    void setUsesDisplayListDrawing(bool flag) { m_usesDisplayListDrawing = flag; };
+
+    bool tracksDisplayListReplay() const { return m_tracksDisplayListReplay; }
+    void setTracksDisplayListReplay(bool);
+
+    String displayListAsText(DisplayList::AsTextFlags) const;
+    String replayDisplayListAsText(DisplayList::AsTextFlags) const;
+
+    using Direction = CanvasDirection;
+
+    class FontProxy : public FontSelectorClient {
+    public:
+        FontProxy() = default;
+        virtual ~FontProxy();
+        FontProxy(const FontProxy&);
+        FontProxy& operator=(const FontProxy&);
+
+        bool realized() const { return m_font.fontSelector(); }
+        void initialize(FontSelector&, const RenderStyle&);
+        const FontMetrics& fontMetrics() const;
+        const FontCascadeDescription& fontDescription() const;
+        float width(const TextRun&, GlyphOverflow* = 0) const;
+        void drawBidiText(GraphicsContext&, const TextRun&, const FloatPoint&, FontCascade::CustomFontNotReadyAction) const;
+
+    private:
+        void update(FontSelector&);
+        void fontsNeedUpdate(FontSelector&) override;
+
+        FontCascade m_font;
+    };
+
+    struct State final {
+        State();
+
+        State(const State&);
+        State& operator=(const State&);
+
+        String unparsedStrokeColor;
+        String unparsedFillColor;
+        CanvasStyle strokeStyle;
+        CanvasStyle fillStyle;
+        float lineWidth;
+        LineCap lineCap;
+        LineJoin lineJoin;
+        float miterLimit;
+        FloatSize shadowOffset;
+        float shadowBlur;
+        Color shadowColor;
+        float globalAlpha;
+        CompositeOperator globalComposite;
+        BlendMode globalBlend;
+        AffineTransform transform;
+        bool hasInvertibleTransform;
+        Vector<float> lineDash;
+        float lineDashOffset;
+        bool imageSmoothingEnabled;
+        ImageSmoothingQuality imageSmoothingQuality;
+
+        // Text state.
+        TextAlign textAlign;
+        TextBaseline textBaseline;
+        Direction direction;
+
+        String unparsedFont;
+        FontProxy font;
+    };
+
+    const State& state() const { return m_stateStack.last(); }
+
+protected:
+    static const int DefaultFontSize;
+    static const char* const DefaultFontFamily;
+    static const char* const DefaultFont;
+
+    enum CanvasDidDrawOption {
+        CanvasDidDrawApplyNone = 0,
+        CanvasDidDrawApplyTransform = 1,
+        CanvasDidDrawApplyShadow = 1 << 1,
+        CanvasDidDrawApplyClip = 1 << 2,
+        CanvasDidDrawApplyAll = 0xffffffff
+    };
+
+    bool isFullCanvasCompositeMode(CompositeOperator);
+
+    State& modifiableState() { ASSERT(!m_unrealizedSaveCount || m_stateStack.size() >= MaxSaveCount); return m_stateStack.last(); }
+
+    void applyLineDash() const;
+    void setShadow(const FloatSize& offset, float blur, const Color&);
+    void applyShadow();
+    bool shouldDrawShadows() const;
+
+    void didDraw(const FloatRect&, unsigned options = CanvasDidDrawApplyAll);
+    void didDrawEntireCanvas();
+
+    void paintRenderingResultsToCanvas() override;
+
+    GraphicsContext* drawingContext() const;
+
+    void unwindStateStack();
+    void realizeSaves();
+    void realizeSavesLoop();
+
+    void applyStrokePattern();
+    void applyFillPattern();
+
+    void setStrokeStyle(CanvasStyle);
+    void setFillStyle(CanvasStyle);
+
+    ExceptionOr<RefPtr<CanvasPattern>> createPattern(HTMLImageElement&, bool repeatX, bool repeatY);
+    ExceptionOr<RefPtr<CanvasPattern>> createPattern(HTMLCanvasElement&, bool repeatX, bool repeatY);
+#if ENABLE(VIDEO)
+    ExceptionOr<RefPtr<CanvasPattern>> createPattern(HTMLVideoElement&, bool repeatX, bool repeatY);
+#endif
+    ExceptionOr<RefPtr<CanvasPattern>> createPattern(ImageBitmap&, bool repeatX, bool repeatY);
+
+    ExceptionOr<void> drawImage(HTMLImageElement&, const FloatRect& srcRect, const FloatRect& dstRect);
+    ExceptionOr<void> drawImage(HTMLImageElement&, const FloatRect& srcRect, const FloatRect& dstRect, const CompositeOperator&, const BlendMode&);
+    ExceptionOr<void> drawImage(HTMLCanvasElement&, const FloatRect& srcRect, const FloatRect& dstRect);
+#if ENABLE(VIDEO)
+    ExceptionOr<void> drawImage(HTMLVideoElement&, const FloatRect& srcRect, const FloatRect& dstRect);
+#endif
+    ExceptionOr<void> drawImage(ImageBitmap&, const FloatRect& srcRect, const FloatRect& dstRect);
+
+    void beginCompositeLayer();
+    void endCompositeLayer();
+
+    void fillInternal(const Path&, CanvasFillRule);
+    void strokeInternal(const Path&);
+    void clipInternal(const Path&, CanvasFillRule);
+
+    bool isPointInPathInternal(const Path&, float x, float y, CanvasFillRule);
+    bool isPointInStrokeInternal(const Path&, float x, float y);
+
+    void clearCanvas();
+    Path transformAreaToDevice(const Path&) const;
+    Path transformAreaToDevice(const FloatRect&) const;
+    bool rectContainsCanvas(const FloatRect&) const;
+
+    template<class T> IntRect calculateCompositingBufferRect(const T&, IntSize*);
+    std::unique_ptr<ImageBuffer> createCompositingBuffer(const IntRect&);
+    void compositeBuffer(ImageBuffer&, const IntRect&, CompositeOperator);
+
+    void inflateStrokeRect(FloatRect&) const;
+
+    template<class T> void fullCanvasCompositedDrawImage(T&, const FloatRect&, const FloatRect&, CompositeOperator);
+
+    void prepareGradientForDashboard(CanvasGradient&) const;
+
+    ExceptionOr<RefPtr<ImageData>> getImageData(ImageBuffer::CoordinateSystem, float sx, float sy, float sw, float sh) const;
+    void putImageData(ImageData&, ImageBuffer::CoordinateSystem, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight);
+
+    bool isAccelerated() const override;
+
+    bool hasInvertibleTransform() const override { return state().hasInvertibleTransform; }
+
+#if ENABLE(ACCELERATED_2D_CANVAS)
+    PlatformLayer* platformLayer() const override;
+#endif
+
+    void clearPathForDashboardBackwardCompatibilityMode();
+
+    static const unsigned MaxSaveCount = 1024 * 16;
+    Vector<State, 1> m_stateStack;
+    unsigned m_unrealizedSaveCount { 0 };
+    bool m_usesCSSCompatibilityParseMode;
+#if ENABLE(DASHBOARD_SUPPORT)
+    bool m_usesDashboardCompatibilityMode;
+#endif
+    bool m_usesDisplayListDrawing { false };
+    bool m_tracksDisplayListReplay { false };
+    mutable std::unique_ptr<struct DisplayListDrawingContext> m_recordingContext;
+};
+
+} // namespace WebCore
+
</ins></span></pre></div>
<a id="trunkSourceWebCorehtmlcanvasOffscreenCanvasRenderingContext2Dcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.cpp (0 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.cpp                           (rev 0)
+++ trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.cpp      2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+/*
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2013, 2014 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "OffscreenCanvasRenderingContext2D.h"
+
+namespace WebCore {
+
+OffscreenCanvasRenderingContext2D::OffscreenCanvasRenderingContext2D(CanvasBase& canvas)
+    : CanvasRenderingContext2DBase(canvas, false, false)
+{
+}
+
+OffscreenCanvasRenderingContext2D::~OffscreenCanvasRenderingContext2D() = default;
+
+} // namespace WebCore
+
</ins><span class="cx">Property changes on: trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.cpp
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="svnkeywords"></a>
<div class="addfile"><h4>Added: svn:keywords</h4></div>
<ins>+Date Author Id Revision HeadURL
</ins><span class="cx">\ No newline at end of property
</span><a id="trunkSourceWebCorehtmlcanvasOffscreenCanvasRenderingContext2Dh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.h (0 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.h                             (rev 0)
+++ trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.h        2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+/*
+ * Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CanvasRenderingContext2DBase.h"
+
+#include "OffscreenCanvas.h"
+
+namespace WebCore {
+
+class OffscreenCanvasRenderingContext2D final : public CanvasRenderingContext2DBase {
+public:
+    OffscreenCanvasRenderingContext2D(CanvasBase&);
+    virtual ~OffscreenCanvasRenderingContext2D();
+
+    bool isOffscreen2d() const override { return true; }
+
+    OffscreenCanvas& canvas() const { return downcast<OffscreenCanvas>(canvasBase()); }
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_CANVASRENDERINGCONTEXT(WebCore::OffscreenCanvasRenderingContext2D, isOffscreen2d())
+
</ins><span class="cx">Property changes on: trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.h
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span><a id="svnkeywords"></a>
<div class="addfile"><h4>Added: svn:keywords</h4></div>
<ins>+Date Author Id Revision HeadURL
</ins><span class="cx">\ No newline at end of property
</span><a id="trunkSourceWebCorehtmlcanvasOffscreenCanvasRenderingContext2Didl"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.idl (0 => 225816)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.idl                           (rev 0)
+++ trunk/Source/WebCore/html/canvas/OffscreenCanvasRenderingContext2D.idl      2017-12-12 23:35:51 UTC (rev 225816)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+/*
+* Copyright (C) 2017 Apple Inc. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+[
+    CustomIsReachable,
+    EnabledAtRuntime=ImageBitmapOffscreenCanvas,
+    Exposed=(Window), // FIXME: OffscreenCanvas - should be Window,Worker
+    JSGenerateToJSObject,
+    JSCustomMarkFunction,
+    // CallTracingCallback=recordCanvasAction, // FIXME: OffscreenCanvas.
+] interface OffscreenCanvasRenderingContext2D {
+    readonly attribute OffscreenCanvas canvas;
+    // FIXME: OffscreenCanvas.
+    // void commit();
+
+    // Inspector-only.
+    // FIXME: OffscreenCanvas.
+    // [EnabledAtRuntime=InspectorAdditions] void setPath(Path2D path);
+    // [EnabledAtRuntime=InspectorAdditions, NewObject] Path2D getPath();
+};
+
+OffscreenCanvasRenderingContext2D implements CanvasState;
+OffscreenCanvasRenderingContext2D implements CanvasTransform;
+OffscreenCanvasRenderingContext2D implements CanvasCompositing;
+OffscreenCanvasRenderingContext2D implements CanvasImageSmoothing;
+OffscreenCanvasRenderingContext2D implements CanvasFillStrokeStyles;
+OffscreenCanvasRenderingContext2D implements CanvasShadowStyles;
+OffscreenCanvasRenderingContext2D implements CanvasFilters;
+OffscreenCanvasRenderingContext2D implements CanvasRect;
+OffscreenCanvasRenderingContext2D implements CanvasDrawPath;
+OffscreenCanvasRenderingContext2D implements CanvasDrawImage;
+OffscreenCanvasRenderingContext2D implements CanvasImageData;
+OffscreenCanvasRenderingContext2D implements CanvasPathDrawingStyles;
+OffscreenCanvasRenderingContext2D implements CanvasPath;
</ins></span></pre>
</div>
</div>

</body>
</html>