<!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>[186507] branches/safari-600.1.4.17-branch/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/186507">186507</a></dd>
<dt>Author</dt> <dd>matthew_hanson@apple.com</dd>
<dt>Date</dt> <dd>2015-07-08 09:41:44 -0700 (Wed, 08 Jul 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/186384">r186384</a>. rdar://problem/21708281</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari6001417branchSourceWebCoreChangeLog">branches/safari-600.1.4.17-branch/Source/WebCore/ChangeLog</a></li>
<li><a href="#branchessafari6001417branchSourceWebCorehtmlcanvasWebGLRenderingContextcpp">branches/safari-600.1.4.17-branch/Source/WebCore/html/canvas/WebGLRenderingContext.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchessafari6001417branchSourceWebCorehtmlcanvasWebGLRenderingContextBasecpp">branches/safari-600.1.4.17-branch/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari6001417branchSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1.4.17-branch/Source/WebCore/ChangeLog (186506 => 186507)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1.4.17-branch/Source/WebCore/ChangeLog        2015-07-08 16:41:39 UTC (rev 186506)
+++ branches/safari-600.1.4.17-branch/Source/WebCore/ChangeLog        2015-07-08 16:41:44 UTC (rev 186507)
</span><span class="lines">@@ -1,5 +1,20 @@
</span><span class="cx"> 2015-07-08  Matthew Hanson  &lt;matthew_hanson@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Merge r186384. rdar://problem/21708281
+
+    2015-07-06  Dean Jackson  &lt;dino@apple.com&gt;
+
+            Memory corruption in WebGLRenderingContext::simulateVertexAttrib0
+            https://bugs.webkit.org/show_bug.cgi?id=146652
+            &lt;rdar://problem/21567767&gt;
+
+            Follow-up fix.
+
+            * html/canvas/WebGLRenderingContextBase.cpp:
+            (WebCore::WebGLRenderingContextBase::simulateVertexAttrib0):
+
+2015-07-08  Matthew Hanson  &lt;matthew_hanson@apple.com&gt;
+
</ins><span class="cx">         Merge r186380. rdar://problem/21708281
</span><span class="cx"> 
</span><span class="cx">     2015-07-06  Dean Jackson  &lt;dino@apple.com&gt;
</span></span></pre></div>
<a id="branchessafari6001417branchSourceWebCorehtmlcanvasWebGLRenderingContextcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1.4.17-branch/Source/WebCore/html/canvas/WebGLRenderingContext.cpp (186506 => 186507)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1.4.17-branch/Source/WebCore/html/canvas/WebGLRenderingContext.cpp        2015-07-08 16:41:39 UTC (rev 186506)
+++ branches/safari-600.1.4.17-branch/Source/WebCore/html/canvas/WebGLRenderingContext.cpp        2015-07-08 16:41:44 UTC (rev 186507)
</span><span class="lines">@@ -5907,7 +5907,9 @@
</span><span class="cx">         return false;
</span><span class="cx">     m_vertexAttrib0UsedBefore = true;
</span><span class="cx">     m_context-&gt;bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer-&gt;object());
</span><del>-    Checked&lt;GC3Dsizeiptr, RecordOverflow&gt; bufferDataSize = (numVertex + 1) * 4 * sizeof(GC3Dfloat);
</del><ins>+    Checked&lt;GC3Dsizeiptr, RecordOverflow&gt; bufferDataSize(numVertex);
+    bufferDataSize += 1;
+    bufferDataSize *= Checked&lt;GC3Dsizeiptr, RecordOverflow&gt;(4 * sizeof(GC3Dfloat));
</ins><span class="cx">     if (bufferDataSize.hasOverflowed())
</span><span class="cx">         return false;
</span><span class="cx">     if (bufferDataSize.unsafeGet() &gt; m_vertexAttrib0BufferSize) {
</span></span></pre></div>
<a id="branchessafari6001417branchSourceWebCorehtmlcanvasWebGLRenderingContextBasecppfromrev186506branchessafari6001417branchSourceWebCorehtmlcanvasWebGLRenderingContextcpp"></a>
<div class="copfile"><h4>Copied: branches/safari-600.1.4.17-branch/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp (from rev 186506, branches/safari-600.1.4.17-branch/Source/WebCore/html/canvas/WebGLRenderingContext.cpp) (0 => 186507)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1.4.17-branch/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp                                (rev 0)
+++ branches/safari-600.1.4.17-branch/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp        2015-07-08 16:41:44 UTC (rev 186507)
</span><span class="lines">@@ -0,0 +1,5050 @@
</span><ins>+/*
+ * Copyright (C) 2015 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. 
+ */
+
+#include &quot;config.h&quot;
+
+#if ENABLE(WEBGL)
+#include &quot;WebGLRenderingContextBase.h&quot;
+
+#include &quot;ANGLEInstancedArrays.h&quot;
+#include &quot;CachedImage.h&quot;
+#include &quot;DOMWindow.h&quot;
+#include &quot;Document.h&quot;
+#include &quot;EXTBlendMinMax.h&quot;
+#include &quot;EXTFragDepth.h&quot;
+#include &quot;EXTShaderTextureLOD.h&quot;
+#include &quot;EXTTextureFilterAnisotropic.h&quot;
+#include &quot;EXTsRGB.h&quot;
+#include &quot;ExceptionCode.h&quot;
+#include &quot;Extensions3D.h&quot;
+#include &quot;Frame.h&quot;
+#include &quot;FrameLoader.h&quot;
+#include &quot;FrameLoaderClient.h&quot;
+#include &quot;FrameView.h&quot;
+#include &quot;GraphicsContext.h&quot;
+#include &quot;HTMLCanvasElement.h&quot;
+#include &quot;HTMLImageElement.h&quot;
+#include &quot;HTMLVideoElement.h&quot;
+#include &quot;ImageBuffer.h&quot;
+#include &quot;ImageData.h&quot;
+#include &quot;IntSize.h&quot;
+#include &quot;Logging.h&quot;
+#include &quot;MainFrame.h&quot;
+#include &quot;NotImplemented.h&quot;
+#include &quot;OESElementIndexUint.h&quot;
+#include &quot;OESStandardDerivatives.h&quot;
+#include &quot;OESTextureFloat.h&quot;
+#include &quot;OESTextureFloatLinear.h&quot;
+#include &quot;OESTextureHalfFloat.h&quot;
+#include &quot;OESTextureHalfFloatLinear.h&quot;
+#include &quot;OESVertexArrayObject.h&quot;
+#include &quot;Page.h&quot;
+#include &quot;RenderBox.h&quot;
+#include &quot;Settings.h&quot;
+#include &quot;WebGL2RenderingContext.h&quot;
+#include &quot;WebGLActiveInfo.h&quot;
+#include &quot;WebGLBuffer.h&quot;
+#include &quot;WebGLCompressedTextureATC.h&quot;
+#include &quot;WebGLCompressedTexturePVRTC.h&quot;
+#include &quot;WebGLCompressedTextureS3TC.h&quot;
+#include &quot;WebGLContextAttributes.h&quot;
+#include &quot;WebGLContextEvent.h&quot;
+#include &quot;WebGLContextGroup.h&quot;
+#include &quot;WebGLDebugRendererInfo.h&quot;
+#include &quot;WebGLDebugShaders.h&quot;
+#include &quot;WebGLDepthTexture.h&quot;
+#include &quot;WebGLDrawBuffers.h&quot;
+#include &quot;WebGLFramebuffer.h&quot;
+#include &quot;WebGLLoseContext.h&quot;
+#include &quot;WebGLProgram.h&quot;
+#include &quot;WebGLRenderbuffer.h&quot;
+#include &quot;WebGLRenderingContext.h&quot;
+#include &quot;WebGLShader.h&quot;
+#include &quot;WebGLShaderPrecisionFormat.h&quot;
+#include &quot;WebGLTexture.h&quot;
+#include &quot;WebGLUniformLocation.h&quot;
+
+#include &lt;runtime/JSCInlines.h&gt;
+#include &lt;runtime/TypedArrayInlines.h&gt;
+#include &lt;runtime/Uint32Array.h&gt;
+#include &lt;wtf/CheckedArithmetic.h&gt;
+#include &lt;wtf/StdLibExtras.h&gt;
+#include &lt;wtf/text/CString.h&gt;
+#include &lt;wtf/text/StringBuilder.h&gt;
+
+namespace WebCore {
+
+const double secondsBetweenRestoreAttempts = 1.0;
+const int maxGLErrorsAllowedToConsole = 256;
+
+namespace {
+    
+    Platform3DObject objectOrZero(WebGLObject* object)
+    {
+        return object ? object-&gt;object() : 0;
+    }
+
+    GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
+    {
+        if (value &lt; min)
+            value = min;
+        if (value &gt; max)
+            value = max;
+        return value;
+    }
+
+    // Return true if a character belongs to the ASCII subset as defined in
+    // GLSL ES 1.0 spec section 3.1.
+    bool validateCharacter(unsigned char c)
+    {
+        // Printing characters are valid except &quot; $ ` @ \ ' DEL.
+        if (c &gt;= 32 &amp;&amp; c &lt;= 126
+            &amp;&amp; c != '&quot;' &amp;&amp; c != '$' &amp;&amp; c != '`' &amp;&amp; c != '@' &amp;&amp; c != '\\' &amp;&amp; c != '\'')
+            return true;
+        // Horizontal tab, line feed, vertical tab, form feed, carriage return
+        // are also valid.
+        if (c &gt;= 9 &amp;&amp; c &lt;= 13)
+            return true;
+        return false;
+    }
+
+    bool isPrefixReserved(const String&amp; name)
+    {
+        if (name.startsWith(&quot;gl_&quot;) || name.startsWith(&quot;webgl_&quot;) || name.startsWith(&quot;_webgl_&quot;))
+            return true;
+        return false;
+    }
+
+    // Strips comments from shader text. This allows non-ASCII characters
+    // to be used in comments without potentially breaking OpenGL
+    // implementations not expecting characters outside the GLSL ES set.
+    class StripComments {
+    public:
+        StripComments(const String&amp; str)
+            : m_parseState(BeginningOfLine)
+            , m_sourceString(str)
+            , m_length(str.length())
+            , m_position(0)
+        {
+            parse();
+        }
+
+        String result()
+        {
+            return m_builder.toString();
+        }
+
+    private:
+        bool hasMoreCharacters() const
+        {
+            return (m_position &lt; m_length);
+        }
+
+        void parse()
+        {
+            while (hasMoreCharacters()) {
+                process(current());
+                // process() might advance the position.
+                if (hasMoreCharacters())
+                    advance();
+            }
+        }
+
+        void process(UChar);
+
+        bool peek(UChar&amp; character) const
+        {
+            if (m_position + 1 &gt;= m_length)
+                return false;
+            character = m_sourceString[m_position + 1];
+            return true;
+        }
+
+        UChar current() const
+        {
+            ASSERT_WITH_SECURITY_IMPLICATION(m_position &lt; m_length);
+            return m_sourceString[m_position];
+        }
+
+        void advance()
+        {
+            ++m_position;
+        }
+
+        bool isNewline(UChar character) const
+        {
+            // Don't attempt to canonicalize newline related characters.
+            return (character == '\n' || character == '\r');
+        }
+
+        void emit(UChar character)
+        {
+            m_builder.append(character);
+        }
+
+        enum ParseState {
+            // Have not seen an ASCII non-whitespace character yet on
+            // this line. Possible that we might see a preprocessor
+            // directive.
+            BeginningOfLine,
+
+            // Have seen at least one ASCII non-whitespace character
+            // on this line.
+            MiddleOfLine,
+
+            // Handling a preprocessor directive. Passes through all
+            // characters up to the end of the line. Disables comment
+            // processing.
+            InPreprocessorDirective,
+
+            // Handling a single-line comment. The comment text is
+            // replaced with a single space.
+            InSingleLineComment,
+
+            // Handling a multi-line comment. Newlines are passed
+            // through to preserve line numbers.
+            InMultiLineComment
+        };
+
+        ParseState m_parseState;
+        String m_sourceString;
+        unsigned m_length;
+        unsigned m_position;
+        StringBuilder m_builder;
+    };
+
+    void StripComments::process(UChar c)
+    {
+        if (isNewline(c)) {
+            // No matter what state we are in, pass through newlines
+            // so we preserve line numbers.
+            emit(c);
+
+            if (m_parseState != InMultiLineComment)
+                m_parseState = BeginningOfLine;
+
+            return;
+        }
+
+        UChar temp = 0;
+        switch (m_parseState) {
+        case BeginningOfLine:
+            if (WTF::isASCIISpace(c)) {
+                emit(c);
+                break;
+            }
+
+            if (c == '#') {
+                m_parseState = InPreprocessorDirective;
+                emit(c);
+                break;
+            }
+
+            // Transition to normal state and re-handle character.
+            m_parseState = MiddleOfLine;
+            process(c);
+            break;
+
+        case MiddleOfLine:
+            if (c == '/' &amp;&amp; peek(temp)) {
+                if (temp == '/') {
+                    m_parseState = InSingleLineComment;
+                    emit(' ');
+                    advance();
+                    break;
+                }
+
+                if (temp == '*') {
+                    m_parseState = InMultiLineComment;
+                    // Emit the comment start in case the user has
+                    // an unclosed comment and we want to later
+                    // signal an error.
+                    emit('/');
+                    emit('*');
+                    advance();
+                    break;
+                }
+            }
+
+            emit(c);
+            break;
+
+        case InPreprocessorDirective:
+            // No matter what the character is, just pass it
+            // through. Do not parse comments in this state. This
+            // might not be the right thing to do long term, but it
+            // should handle the #error preprocessor directive.
+            emit(c);
+            break;
+
+        case InSingleLineComment:
+            // The newline code at the top of this function takes care
+            // of resetting our state when we get out of the
+            // single-line comment. Swallow all other characters.
+            break;
+
+        case InMultiLineComment:
+            if (c == '*' &amp;&amp; peek(temp) &amp;&amp; temp == '/') {
+                emit('*');
+                emit('/');
+                m_parseState = MiddleOfLine;
+                advance();
+                break;
+            }
+
+            // Swallow all other characters. Unclear whether we may
+            // want or need to just emit a space per character to try
+            // to preserve column numbers for debugging purposes.
+            break;
+        }
+    }
+} // namespace anonymous
+
+class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit WebGLRenderingContextLostCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
+    virtual void onContextLost() override { m_context-&gt;forceLostContext(WebGLRenderingContext::RealLostContext); }
+    virtual ~WebGLRenderingContextLostCallback() {}
+private:
+    WebGLRenderingContextBase* m_context;
+};
+
+class WebGLRenderingContextErrorMessageCallback : public GraphicsContext3D::ErrorMessageCallback {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
+    virtual void onErrorMessage(const String&amp; message, GC3Dint) override
+    {
+        if (m_context-&gt;m_synthesizedErrorsToConsole)
+            m_context-&gt;printGLErrorToConsole(message);
+    }
+    virtual ~WebGLRenderingContextErrorMessageCallback() { }
+private:
+    WebGLRenderingContextBase* m_context;
+};
+
+std::unique_ptr&lt;WebGLRenderingContextBase&gt; WebGLRenderingContextBase::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs, const String&amp; type)
+{
+#if !ENABLE(WEBGL2)
+    UNUSED_PARAM(type);
+#endif
+
+    Document&amp; document = canvas-&gt;document();
+    Frame* frame = document.frame();
+    if (!frame)
+        return nullptr;
+
+    // The FrameLoaderClient might block creation of a new WebGL context despite the page settings; in
+    // particular, if WebGL contexts were lost one or more times via the GL_ARB_robustness extension.
+    if (!frame-&gt;loader().client().allowWebGL(frame-&gt;settings().webGLEnabled())) {
+        canvas-&gt;dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, &quot;Web page was not allowed to create a WebGL context.&quot;));
+        return nullptr;
+    }
+
+    bool isPendingPolicyResolution = false;
+    Document&amp; topDocument = document.topDocument();
+    Page* page = topDocument.page();
+    bool forcingPendingPolicy = frame-&gt;settings().isForcePendingWebGLPolicy();
+
+    if (forcingPendingPolicy || (page &amp;&amp; !topDocument.url().isLocalFile())) {
+        WebGLLoadPolicy policy = forcingPendingPolicy ? WebGLPendingCreation : page-&gt;mainFrame().loader().client().webGLPolicyForURL(topDocument.url());
+
+        if (policy == WebGLBlockCreation) {
+            LOG(WebGL, &quot;The policy for this URL (%s) is to block WebGL.&quot;, topDocument.url().host().utf8().data());
+            return nullptr;
+        }
+
+        if (policy == WebGLPendingCreation) {
+            LOG(WebGL, &quot;WebGL policy is pending. May need to be resolved later.&quot;);
+            isPendingPolicyResolution = true;
+        }
+    }
+
+    GraphicsContext3D::Attributes attributes = attrs ? attrs-&gt;attributes() : GraphicsContext3D::Attributes();
+
+    if (attributes.antialias) {
+        if (!frame-&gt;settings().openGLMultisamplingEnabled())
+            attributes.antialias = false;
+    }
+
+    attributes.noExtensions = true;
+    attributes.shareResources = false;
+    attributes.preferDiscreteGPU = true;
+
+    if (frame-&gt;settings().forceSoftwareWebGLRendering())
+        attributes.forceSoftwareRenderer = true;
+
+    if (page)
+        attributes.devicePixelRatio = page-&gt;deviceScaleFactor();
+
+    if (isPendingPolicyResolution) {
+        LOG(WebGL, &quot;Create a WebGL context that looks real, but will require a policy resolution if used.&quot;);
+        std::unique_ptr&lt;WebGLRenderingContextBase&gt; renderingContext = nullptr;
+#if ENABLE(WEBGL2)
+        if (type == &quot;experimental-webgl2&quot;)
+            renderingContext = std::unique_ptr&lt;WebGL2RenderingContext&gt;(new WebGL2RenderingContext(canvas, attributes));
+        else
+#endif
+            renderingContext = std::unique_ptr&lt;WebGLRenderingContext&gt;(new WebGLRenderingContext(canvas, attributes));
+        renderingContext-&gt;suspendIfNeeded();
+        return renderingContext;
+    }
+
+    HostWindow* hostWindow = document.view()-&gt;root()-&gt;hostWindow();
+    RefPtr&lt;GraphicsContext3D&gt; context(GraphicsContext3D::create(attributes, hostWindow));
+
+    if (!context || !context-&gt;makeContextCurrent()) {
+        canvas-&gt;dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, &quot;Could not create a WebGL context.&quot;));
+        return nullptr;
+    }
+
+    Extensions3D* extensions = context-&gt;getExtensions();
+    if (extensions-&gt;supports(&quot;GL_EXT_debug_marker&quot;))
+        extensions-&gt;pushGroupMarkerEXT(&quot;WebGLRenderingContext&quot;);
+
+    std::unique_ptr&lt;WebGLRenderingContextBase&gt; renderingContext = nullptr;
+#if ENABLE(WEBGL2)
+    if (type == &quot;experimental-webgl2&quot;)
+        renderingContext = std::unique_ptr&lt;WebGL2RenderingContext&gt;(new WebGL2RenderingContext(canvas, context, attributes));
+    else
+#endif
+        renderingContext = std::unique_ptr&lt;WebGLRenderingContext&gt;(new WebGLRenderingContext(canvas, context, attributes));
+    renderingContext-&gt;suspendIfNeeded();
+
+    return renderingContext;
+}
+
+WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, GraphicsContext3D::Attributes attributes)
+    : CanvasRenderingContext(passedCanvas)
+    , ActiveDOMObject(&amp;passedCanvas-&gt;document())
+    , m_context(0)
+    , m_dispatchContextLostEventTimer(*this, &amp;WebGLRenderingContextBase::dispatchContextLostEvent)
+    , m_restoreAllowed(false)
+    , m_restoreTimer(*this, &amp;WebGLRenderingContextBase::maybeRestoreContext)
+    , m_generatedImageCache(0)
+    , m_contextLost(false)
+    , m_contextLostMode(SyntheticLostContext)
+    , m_attributes(attributes)
+    , m_synthesizedErrorsToConsole(true)
+    , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
+    , m_isPendingPolicyResolution(true)
+    , m_hasRequestedPolicyResolution(false)
+{
+}
+
+WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, PassRefPtr&lt;GraphicsContext3D&gt; context, GraphicsContext3D::Attributes attributes)
+    : CanvasRenderingContext(passedCanvas)
+    , ActiveDOMObject(&amp;passedCanvas-&gt;document())
+    , m_context(context)
+    , m_dispatchContextLostEventTimer(*this, &amp;WebGLRenderingContextBase::dispatchContextLostEvent)
+    , m_restoreAllowed(false)
+    , m_restoreTimer(*this, &amp;WebGLRenderingContextBase::maybeRestoreContext)
+    , m_generatedImageCache(4)
+    , m_contextLost(false)
+    , m_contextLostMode(SyntheticLostContext)
+    , m_attributes(attributes)
+    , m_synthesizedErrorsToConsole(true)
+    , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
+    , m_isPendingPolicyResolution(false)
+    , m_hasRequestedPolicyResolution(false)
+{
+    ASSERT(m_context);
+    m_contextGroup = WebGLContextGroup::create();
+    m_contextGroup-&gt;addContext(this);
+    
+    m_context-&gt;setWebGLContext(this);
+
+    m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
+    m_context-&gt;getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
+
+    setupFlags();
+    initializeNewContext();
+}
+
+void WebGLRenderingContextBase::initializeNewContext()
+{
+    ASSERT(!m_contextLost);
+    m_needsUpdate = true;
+    m_markedCanvasDirty = false;
+    m_activeTextureUnit = 0;
+    m_packAlignment = 4;
+    m_unpackAlignment = 4;
+    m_unpackFlipY = false;
+    m_unpackPremultiplyAlpha = false;
+    m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
+    m_boundArrayBuffer = nullptr;
+    m_currentProgram = nullptr;
+    m_framebufferBinding = nullptr;
+    m_renderbufferBinding = nullptr;
+    m_depthMask = true;
+    m_stencilEnabled = false;
+    m_stencilMask = 0xFFFFFFFF;
+    m_stencilMaskBack = 0xFFFFFFFF;
+    m_stencilFuncRef = 0;
+    m_stencilFuncRefBack = 0;
+    m_stencilFuncMask = 0xFFFFFFFF;
+    m_stencilFuncMaskBack = 0xFFFFFFFF;
+    m_layerCleared = false;
+    m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
+    
+    m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
+    m_scissorEnabled = false;
+    m_clearDepth = 1;
+    m_clearStencil = 0;
+    m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
+
+    GC3Dint numCombinedTextureImageUnits = 0;
+    m_context-&gt;getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &amp;numCombinedTextureImageUnits);
+    m_textureUnits.clear();
+    m_textureUnits.resize(numCombinedTextureImageUnits);
+
+    GC3Dint numVertexAttribs = 0;
+    m_context-&gt;getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &amp;numVertexAttribs);
+    m_maxVertexAttribs = numVertexAttribs;
+    
+    m_maxTextureSize = 0;
+    m_context-&gt;getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &amp;m_maxTextureSize);
+    m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
+    m_maxCubeMapTextureSize = 0;
+    m_context-&gt;getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &amp;m_maxCubeMapTextureSize);
+    m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
+    m_maxRenderbufferSize = 0;
+    m_context-&gt;getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &amp;m_maxRenderbufferSize);
+
+    // These two values from EXT_draw_buffers are lazily queried.
+    m_maxDrawBuffers = 0;
+    m_maxColorAttachments = 0;
+
+    m_backDrawBuffer = GraphicsContext3D::BACK;
+    m_drawBuffersWebGLRequirementsChecked = false;
+    m_drawBuffersSupported = false;
+    
+    m_vertexAttribValue.resize(m_maxVertexAttribs);
+
+    if (!isGLES2NPOTStrict())
+        createFallbackBlackTextures1x1();
+
+    IntSize canvasSize = clampedCanvasSize();
+    m_context-&gt;reshape(canvasSize.width(), canvasSize.height());
+    m_context-&gt;viewport(0, 0, canvasSize.width(), canvasSize.height());
+    m_context-&gt;scissor(0, 0, canvasSize.width(), canvasSize.height());
+
+    m_context-&gt;setContextLostCallback(std::make_unique&lt;WebGLRenderingContextLostCallback&gt;(this));
+    m_context-&gt;setErrorMessageCallback(std::make_unique&lt;WebGLRenderingContextErrorMessageCallback&gt;(this));
+}
+
+void WebGLRenderingContextBase::setupFlags()
+{
+    ASSERT(m_context);
+
+    if (Page* page = canvas()-&gt;document().page())
+        m_synthesizedErrorsToConsole = page-&gt;settings().webGLErrorsToConsoleEnabled();
+
+    m_isGLES2Compliant = m_context-&gt;isGLES2Compliant();
+    m_isErrorGeneratedOnOutOfBoundsAccesses = m_context-&gt;getExtensions()-&gt;isEnabled(&quot;GL_CHROMIUM_strict_attribs&quot;);
+    m_isResourceSafe = m_context-&gt;getExtensions()-&gt;isEnabled(&quot;GL_CHROMIUM_resource_safe&quot;);
+    if (m_isGLES2Compliant) {
+        m_isGLES2NPOTStrict = !m_context-&gt;getExtensions()-&gt;isEnabled(&quot;GL_OES_texture_npot&quot;);
+        m_isDepthStencilSupported = m_context-&gt;getExtensions()-&gt;isEnabled(&quot;GL_OES_packed_depth_stencil&quot;);
+    } else {
+        m_isGLES2NPOTStrict = !m_context-&gt;getExtensions()-&gt;isEnabled(&quot;GL_ARB_texture_non_power_of_two&quot;);
+        m_isDepthStencilSupported = m_context-&gt;getExtensions()-&gt;isEnabled(&quot;GL_EXT_packed_depth_stencil&quot;);
+    }
+    m_isRobustnessEXTSupported = m_context-&gt;getExtensions()-&gt;isEnabled(&quot;GL_EXT_robustness&quot;);
+}
+
+bool WebGLRenderingContextBase::allowPrivilegedExtensions() const
+{
+    if (Page* page = canvas()-&gt;document().page())
+        return page-&gt;settings().privilegedWebGLExtensionsEnabled();
+    return false;
+}
+
+void WebGLRenderingContextBase::addCompressedTextureFormat(GC3Denum format)
+{
+    if (!m_compressedTextureFormats.contains(format))
+        m_compressedTextureFormats.append(format);
+}
+
+WebGLRenderingContextBase::~WebGLRenderingContextBase()
+{
+    // Remove all references to WebGLObjects so if they are the last reference
+    // they will be freed before the last context is removed from the context group.
+    m_boundArrayBuffer = nullptr;
+    m_defaultVertexArrayObject = nullptr;
+    m_boundVertexArrayObject = nullptr;
+    m_vertexAttrib0Buffer = nullptr;
+    m_currentProgram = nullptr;
+    m_framebufferBinding = nullptr;
+    m_renderbufferBinding = nullptr;
+
+    for (size_t i = 0; i &lt; m_textureUnits.size(); ++i) {
+        m_textureUnits[i].texture2DBinding = nullptr;
+        m_textureUnits[i].textureCubeMapBinding = nullptr;
+    }
+
+    m_blackTexture2D = nullptr;
+    m_blackTextureCubeMap = nullptr;
+
+    if (!m_isPendingPolicyResolution) {
+        detachAndRemoveAllObjects();
+        destroyGraphicsContext3D();
+        m_contextGroup-&gt;removeContext(this);
+    }
+}
+
+void WebGLRenderingContextBase::destroyGraphicsContext3D()
+{
+    if (m_isPendingPolicyResolution)
+        return;
+
+    if (m_context) {
+        m_context-&gt;setContextLostCallback(nullptr);
+        m_context-&gt;setErrorMessageCallback(nullptr);
+        m_context = nullptr;
+    }
+}
+
+void WebGLRenderingContextBase::markContextChanged()
+{
+    if (m_framebufferBinding)
+        return;
+
+    m_context-&gt;markContextChanged();
+
+    m_layerCleared = false;
+    RenderBox* renderBox = canvas()-&gt;renderBox();
+    if (isAccelerated() &amp;&amp; renderBox &amp;&amp; renderBox-&gt;hasAcceleratedCompositing()) {
+        m_markedCanvasDirty = true;
+        canvas()-&gt;clearCopiedImage();
+        renderBox-&gt;contentChanged(CanvasChanged);
+    } else {
+        if (!m_markedCanvasDirty) {
+            m_markedCanvasDirty = true;
+            canvas()-&gt;didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize()));
+        }
+    }
+}
+
+bool WebGLRenderingContextBase::clearIfComposited(GC3Dbitfield mask)
+{
+    if (isContextLostOrPending())
+        return false;
+
+    if (!m_context-&gt;layerComposited() || m_layerCleared
+        || m_attributes.preserveDrawingBuffer || (mask &amp;&amp; m_framebufferBinding))
+        return false;
+
+    RefPtr&lt;WebGLContextAttributes&gt; contextAttributes = getContextAttributes();
+
+    // Determine if it's possible to combine the clear the user asked for and this clear.
+    bool combinedClear = mask &amp;&amp; !m_scissorEnabled;
+
+    m_context-&gt;disable(GraphicsContext3D::SCISSOR_TEST);
+    if (combinedClear &amp;&amp; (mask &amp; GraphicsContext3D::COLOR_BUFFER_BIT))
+        m_context-&gt;clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
+                              m_colorMask[1] ? m_clearColor[1] : 0,
+                              m_colorMask[2] ? m_clearColor[2] : 0,
+                              m_colorMask[3] ? m_clearColor[3] : 0);
+    else
+        m_context-&gt;clearColor(0, 0, 0, 0);
+    m_context-&gt;colorMask(true, true, true, true);
+    GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
+    if (contextAttributes-&gt;depth()) {
+        if (!combinedClear || !m_depthMask || !(mask &amp; GraphicsContext3D::DEPTH_BUFFER_BIT))
+            m_context-&gt;clearDepth(1.0f);
+        clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
+        m_context-&gt;depthMask(true);
+    }
+    if (contextAttributes-&gt;stencil()) {
+        if (combinedClear &amp;&amp; (mask &amp; GraphicsContext3D::STENCIL_BUFFER_BIT))
+            m_context-&gt;clearStencil(m_clearStencil &amp; m_stencilMask);
+        else
+            m_context-&gt;clearStencil(0);
+        clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
+        m_context-&gt;stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
+    }
+    if (m_framebufferBinding)
+        m_context-&gt;bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
+    m_context-&gt;clear(clearMask);
+
+    restoreStateAfterClear();
+    if (m_framebufferBinding)
+        m_context-&gt;bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
+    m_layerCleared = true;
+
+    return combinedClear;
+}
+
+void WebGLRenderingContextBase::restoreStateAfterClear()
+{
+    // Restore the state that the context set.
+    if (m_scissorEnabled)
+        m_context-&gt;enable(GraphicsContext3D::SCISSOR_TEST);
+    m_context-&gt;clearColor(m_clearColor[0], m_clearColor[1],
+                          m_clearColor[2], m_clearColor[3]);
+    m_context-&gt;colorMask(m_colorMask[0], m_colorMask[1],
+                         m_colorMask[2], m_colorMask[3]);
+    m_context-&gt;clearDepth(m_clearDepth);
+    m_context-&gt;clearStencil(m_clearStencil);
+    m_context-&gt;stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
+    m_context-&gt;depthMask(m_depthMask);
+}
+
+void WebGLRenderingContextBase::markLayerComposited()
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;markLayerComposited();
+}
+
+void WebGLRenderingContextBase::paintRenderingResultsToCanvas()
+{
+    if (isContextLostOrPending())
+        return;
+
+    if (canvas()-&gt;document().printing())
+        canvas()-&gt;clearPresentationCopy();
+
+    // Until the canvas is written to by the application, the clear that
+    // happened after it was composited should be ignored by the compositor.
+    if (m_context-&gt;layerComposited() &amp;&amp; !m_attributes.preserveDrawingBuffer) {
+        m_context-&gt;paintCompositedResultsToCanvas(canvas()-&gt;buffer());
+
+        canvas()-&gt;makePresentationCopy();
+    } else
+        canvas()-&gt;clearPresentationCopy();
+    clearIfComposited();
+
+    if (!m_markedCanvasDirty &amp;&amp; !m_layerCleared)
+        return;
+
+    canvas()-&gt;clearCopiedImage();
+    m_markedCanvasDirty = false;
+
+    m_context-&gt;paintRenderingResultsToCanvas(canvas()-&gt;buffer());
+}
+
+PassRefPtr&lt;ImageData&gt; WebGLRenderingContextBase::paintRenderingResultsToImageData()
+{
+    if (isContextLostOrPending())
+        return nullptr;
+    clearIfComposited();
+    return m_context-&gt;paintRenderingResultsToImageData();
+}
+
+void WebGLRenderingContextBase::reshape(int width, int height)
+{
+    if (isContextLostOrPending())
+        return;
+
+    // This is an approximation because at WebGLRenderingContext level we don't
+    // know if the underlying FBO uses textures or renderbuffers.
+    GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
+    // Limit drawing buffer size to 4k to avoid memory exhaustion.
+    const int sizeUpperLimit = 4096;
+    maxSize = std::min(maxSize, sizeUpperLimit);
+    GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
+    GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
+    width = clamp(width, 1, maxWidth);
+    height = clamp(height, 1, maxHeight);
+
+    if (m_needsUpdate) {
+        RenderBox* renderBox = canvas()-&gt;renderBox();
+        if (renderBox &amp;&amp; renderBox-&gt;hasAcceleratedCompositing())
+            renderBox-&gt;contentChanged(CanvasChanged);
+        m_needsUpdate = false;
+    }
+
+    // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
+    // clear (and this matches what reshape will do).
+    m_context-&gt;reshape(width, height);
+
+    m_context-&gt;bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(m_textureUnits[m_activeTextureUnit].texture2DBinding.get()));
+    m_context-&gt;bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
+    if (m_framebufferBinding)
+      m_context-&gt;bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
+}
+
+int WebGLRenderingContextBase::drawingBufferWidth() const
+{
+    if (m_isPendingPolicyResolution &amp;&amp; !m_hasRequestedPolicyResolution)
+        return 0;
+
+    return m_context-&gt;getInternalFramebufferSize().width();
+}
+
+int WebGLRenderingContextBase::drawingBufferHeight() const
+{
+    if (m_isPendingPolicyResolution &amp;&amp; !m_hasRequestedPolicyResolution)
+        return 0;
+
+    return m_context-&gt;getInternalFramebufferSize().height();
+}
+
+unsigned WebGLRenderingContextBase::sizeInBytes(GC3Denum type)
+{
+    switch (type) {
+    case GraphicsContext3D::BYTE:
+        return sizeof(GC3Dbyte);
+    case GraphicsContext3D::UNSIGNED_BYTE:
+        return sizeof(GC3Dubyte);
+    case GraphicsContext3D::SHORT:
+        return sizeof(GC3Dshort);
+    case GraphicsContext3D::UNSIGNED_SHORT:
+        return sizeof(GC3Dushort);
+    case GraphicsContext3D::INT:
+        return sizeof(GC3Dint);
+    case GraphicsContext3D::UNSIGNED_INT:
+        return sizeof(GC3Duint);
+    case GraphicsContext3D::FLOAT:
+        return sizeof(GC3Dfloat);
+    }
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+void WebGLRenderingContextBase::activeTexture(GC3Denum texture, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return;
+    if (texture - GraphicsContext3D::TEXTURE0 &gt;= m_textureUnits.size()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;activeTexture&quot;, &quot;texture unit out of range&quot;);
+        return;
+    }
+    m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
+    m_context-&gt;activeTexture(texture);
+}
+
+void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;attachShader&quot;, program) || !validateWebGLObject(&quot;attachShader&quot;, shader))
+        return;
+    if (!program-&gt;attachShader(shader)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;attachShader&quot;, &quot;shader attachment already has shader&quot;);
+        return;
+    }
+    m_context-&gt;attachShader(objectOrZero(program), objectOrZero(shader));
+    shader-&gt;onAttached();
+}
+
+void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String&amp; name, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;bindAttribLocation&quot;, program))
+        return;
+    if (!validateLocationLength(&quot;bindAttribLocation&quot;, name))
+        return;
+    if (!validateString(&quot;bindAttribLocation&quot;, name))
+        return;
+    if (isPrefixReserved(name)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;bindAttribLocation&quot;, &quot;reserved prefix&quot;);
+        return;
+    }
+    if (index &gt;= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bindAttribLocation&quot;, &quot;index out of range&quot;);
+        return;
+    }
+    m_context-&gt;bindAttribLocation(objectOrZero(program), index, name);
+}
+
+bool WebGLRenderingContextBase::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool&amp; deleted)
+{
+    deleted = false;
+    if (isContextLostOrPending())
+        return false;
+    if (object) {
+        if (!object-&gt;validate(contextGroup(), this)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;object not from this context&quot;);
+            return false;
+        }
+        deleted = !object-&gt;object();
+    }
+    return true;
+}
+
+void WebGLRenderingContextBase::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound(&quot;bindBuffer&quot;, buffer, deleted))
+        return;
+    if (deleted)
+        buffer = 0;
+    if (buffer &amp;&amp; buffer-&gt;getTarget() &amp;&amp; buffer-&gt;getTarget() != target) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;bindBuffer&quot;, &quot;buffers can not be used with multiple targets&quot;);
+        return;
+    }
+    if (target == GraphicsContext3D::ARRAY_BUFFER)
+        m_boundArrayBuffer = buffer;
+    else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
+        m_boundVertexArrayObject-&gt;setElementArrayBuffer(buffer);
+    else {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;bindBuffer&quot;, &quot;invalid target&quot;);
+        return;
+    }
+
+    m_context-&gt;bindBuffer(target, objectOrZero(buffer));
+    if (buffer)
+        buffer-&gt;setTarget(target);
+}
+
+void WebGLRenderingContextBase::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound(&quot;bindFramebuffer&quot;, buffer, deleted))
+        return;
+    if (deleted)
+        buffer = 0;
+    if (target != GraphicsContext3D::FRAMEBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;bindFramebuffer&quot;, &quot;invalid target&quot;);
+        return;
+    }
+    m_framebufferBinding = buffer;
+    m_context-&gt;bindFramebuffer(target, objectOrZero(buffer));
+    if (buffer)
+        buffer-&gt;setHasEverBeenBound();
+    applyStencilTest();
+}
+
+void WebGLRenderingContextBase::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound(&quot;bindRenderbuffer&quot;, renderBuffer, deleted))
+        return;
+    if (deleted)
+        renderBuffer = 0;
+    if (target != GraphicsContext3D::RENDERBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;bindRenderbuffer&quot;, &quot;invalid target&quot;);
+        return;
+    }
+    m_renderbufferBinding = renderBuffer;
+    m_context-&gt;bindRenderbuffer(target, objectOrZero(renderBuffer));
+    if (renderBuffer)
+        renderBuffer-&gt;setHasEverBeenBound();
+}
+
+void WebGLRenderingContextBase::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound(&quot;bindTexture&quot;, texture, deleted))
+        return;
+    if (deleted)
+        texture = 0;
+    if (texture &amp;&amp; texture-&gt;getTarget() &amp;&amp; texture-&gt;getTarget() != target) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;bindTexture&quot;, &quot;textures can not be used with multiple targets&quot;);
+        return;
+    }
+    GC3Dint maxLevel = 0;
+    if (target == GraphicsContext3D::TEXTURE_2D) {
+        m_textureUnits[m_activeTextureUnit].texture2DBinding = texture;
+        maxLevel = m_maxTextureLevel;
+    } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
+        m_textureUnits[m_activeTextureUnit].textureCubeMapBinding = texture;
+        maxLevel = m_maxCubeMapTextureLevel;
+    } else {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;bindTexture&quot;, &quot;invalid target&quot;);
+        return;
+    }
+    m_context-&gt;bindTexture(target, objectOrZero(texture));
+    if (texture)
+        texture-&gt;setTarget(target, maxLevel);
+
+    // Note: previously we used to automatically set the TEXTURE_WRAP_R
+    // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
+    // ES 2.0 doesn't expose this flag (a bug in the specification) and
+    // otherwise the application has no control over the seams in this
+    // dimension. However, it appears that supporting this properly on all
+    // platforms is fairly involved (will require a HashMap from texture ID
+    // in all ports), and we have not had any complaints, so the logic has
+    // been removed.
+}
+
+void WebGLRenderingContextBase::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;blendColor(red, green, blue, alpha);
+}
+
+void WebGLRenderingContextBase::blendEquation(GC3Denum mode)
+{
+    if (isContextLostOrPending() || !validateBlendEquation(&quot;blendEquation&quot;, mode))
+        return;
+    m_context-&gt;blendEquation(mode);
+}
+
+void WebGLRenderingContextBase::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
+{
+    if (isContextLostOrPending() || !validateBlendEquation(&quot;blendEquation&quot;, modeRGB) || !validateBlendEquation(&quot;blendEquation&quot;, modeAlpha))
+        return;
+    m_context-&gt;blendEquationSeparate(modeRGB, modeAlpha);
+}
+
+
+void WebGLRenderingContextBase::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
+{
+    if (isContextLostOrPending() || !validateBlendFuncFactors(&quot;blendFunc&quot;, sfactor, dfactor))
+        return;
+    m_context-&gt;blendFunc(sfactor, dfactor);
+}
+
+void WebGLRenderingContextBase::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
+{
+    // Note: Alpha does not have the same restrictions as RGB.
+    if (isContextLostOrPending() || !validateBlendFuncFactors(&quot;blendFunc&quot;, srcRGB, dstRGB))
+        return;
+    m_context-&gt;blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+void WebGLRenderingContextBase::bufferData(GC3Denum target, long long size, GC3Denum usage, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters(&quot;bufferData&quot;, target, usage);
+    if (!buffer)
+        return;
+    if (size &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferData&quot;, &quot;size &lt; 0&quot;);
+        return;
+    }
+    if (!size) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferData&quot;, &quot;size == 0&quot;);
+        return;
+    }
+    if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
+        if (!buffer-&gt;associateBufferData(static_cast&lt;GC3Dsizeiptr&gt;(size))) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferData&quot;, &quot;invalid buffer&quot;);
+            return;
+        }
+    }
+
+    m_context-&gt;moveErrorsToSyntheticErrorList();
+    m_context-&gt;bufferData(target, static_cast&lt;GC3Dsizeiptr&gt;(size), usage);
+    if (m_context-&gt;moveErrorsToSyntheticErrorList()) {
+        // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
+        buffer-&gt;disassociateBufferData();
+    }
+}
+
+void WebGLRenderingContextBase::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters(&quot;bufferData&quot;, target, usage);
+    if (!buffer)
+        return;
+    if (!data) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferData&quot;, &quot;no data&quot;);
+        return;
+    }
+    if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
+        if (!buffer-&gt;associateBufferData(data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferData&quot;, &quot;invalid buffer&quot;);
+            return;
+        }
+    }
+
+    m_context-&gt;moveErrorsToSyntheticErrorList();
+    m_context-&gt;bufferData(target, data-&gt;byteLength(), data-&gt;data(), usage);
+    if (m_context-&gt;moveErrorsToSyntheticErrorList()) {
+        // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
+        buffer-&gt;disassociateBufferData();
+    }
+}
+
+void WebGLRenderingContextBase::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters(&quot;bufferData&quot;, target, usage);
+    if (!buffer)
+        return;
+    if (!data) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferData&quot;, &quot;no data&quot;);
+        return;
+    }
+    if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
+        if (!buffer-&gt;associateBufferData(data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferData&quot;, &quot;invalid buffer&quot;);
+            return;
+        }
+    }
+
+    m_context-&gt;moveErrorsToSyntheticErrorList();
+    m_context-&gt;bufferData(target, data-&gt;byteLength(), data-&gt;baseAddress(), usage);
+    if (m_context-&gt;moveErrorsToSyntheticErrorList()) {
+        // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
+        buffer-&gt;disassociateBufferData();
+    }
+}
+
+void WebGLRenderingContextBase::bufferSubData(GC3Denum target, long long offset, ArrayBuffer* data, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters(&quot;bufferSubData&quot;, target, GraphicsContext3D::STATIC_DRAW);
+    if (!buffer)
+        return;
+    if (offset &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferSubData&quot;, &quot;offset &lt; 0&quot;);
+        return;
+    }
+    if (!data)
+        return;
+    if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
+        if (!buffer-&gt;associateBufferSubData(static_cast&lt;GC3Dintptr&gt;(offset), data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferSubData&quot;, &quot;offset out of range&quot;);
+            return;
+        }
+    }
+
+    m_context-&gt;moveErrorsToSyntheticErrorList();
+    m_context-&gt;bufferSubData(target, static_cast&lt;GC3Dintptr&gt;(offset), data-&gt;byteLength(), data-&gt;data());
+    if (m_context-&gt;moveErrorsToSyntheticErrorList()) {
+        // The bufferSubData function failed. Tell the buffer it doesn't have the data it thinks it does.
+        buffer-&gt;disassociateBufferData();
+    }
+}
+
+void WebGLRenderingContextBase::bufferSubData(GC3Denum target, long long offset, ArrayBufferView* data, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return;
+    WebGLBuffer* buffer = validateBufferDataParameters(&quot;bufferSubData&quot;, target, GraphicsContext3D::STATIC_DRAW);
+    if (!buffer)
+        return;
+    if (offset &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferSubData&quot;, &quot;offset &lt; 0&quot;);
+        return;
+    }
+    if (!data)
+        return;
+    if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
+        if (!buffer-&gt;associateBufferSubData(static_cast&lt;GC3Dintptr&gt;(offset), data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;bufferSubData&quot;, &quot;offset out of range&quot;);
+            return;
+        }
+    }
+
+    m_context-&gt;moveErrorsToSyntheticErrorList();
+    m_context-&gt;bufferSubData(target, static_cast&lt;GC3Dintptr&gt;(offset), data-&gt;byteLength(), data-&gt;baseAddress());
+    if (m_context-&gt;moveErrorsToSyntheticErrorList()) {
+        // The bufferSubData function failed. Tell the buffer it doesn't have the data it thinks it does.
+        buffer-&gt;disassociateBufferData();
+    }
+}
+
+GC3Denum WebGLRenderingContextBase::checkFramebufferStatus(GC3Denum target)
+{
+    if (isContextLostOrPending())
+        return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
+    if (target != GraphicsContext3D::FRAMEBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;checkFramebufferStatus&quot;, &quot;invalid target&quot;);
+        return 0;
+    }
+    if (!m_framebufferBinding || !m_framebufferBinding-&gt;object())
+        return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
+    const char* reason = &quot;framebuffer incomplete&quot;;
+    GC3Denum result = m_framebufferBinding-&gt;checkStatus(&amp;reason);
+    if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+        printGLWarningToConsole(&quot;checkFramebufferStatus&quot;, reason);
+        return result;
+    }
+    result = m_context-&gt;checkFramebufferStatus(target);
+    return result;
+}
+
+void WebGLRenderingContextBase::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
+{
+    if (isContextLostOrPending())
+        return;
+    if (std::isnan(r))
+        r = 0;
+    if (std::isnan(g))
+        g = 0;
+    if (std::isnan(b))
+        b = 0;
+    if (std::isnan(a))
+        a = 1;
+    m_clearColor[0] = r;
+    m_clearColor[1] = g;
+    m_clearColor[2] = b;
+    m_clearColor[3] = a;
+    m_context-&gt;clearColor(r, g, b, a);
+}
+
+void WebGLRenderingContextBase::clearDepth(GC3Dfloat depth)
+{
+    if (isContextLostOrPending())
+        return;
+    m_clearDepth = depth;
+    m_context-&gt;clearDepth(depth);
+}
+
+void WebGLRenderingContextBase::clearStencil(GC3Dint s)
+{
+    if (isContextLostOrPending())
+        return;
+    m_clearStencil = s;
+    m_context-&gt;clearStencil(s);
+}
+
+void WebGLRenderingContextBase::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
+{
+    if (isContextLostOrPending())
+        return;
+    m_colorMask[0] = red;
+    m_colorMask[1] = green;
+    m_colorMask[2] = blue;
+    m_colorMask[3] = alpha;
+    m_context-&gt;colorMask(red, green, blue, alpha);
+}
+
+void WebGLRenderingContextBase::compileShader(WebGLShader* shader, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;compileShader&quot;, shader))
+        return;
+    m_context-&gt;compileShader(objectOrZero(shader));
+    GC3Dint value;
+    m_context-&gt;getShaderiv(objectOrZero(shader), GraphicsContext3D::COMPILE_STATUS, &amp;value);
+    shader-&gt;setValid(value);
+}
+
+void WebGLRenderingContextBase::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width,
+                                                 GC3Dsizei height, GC3Dint border, ArrayBufferView* data)
+{
+    if (isContextLostOrPending())
+        return;
+    if (!validateTexFuncLevel(&quot;compressedTexImage2D&quot;, target, level))
+        return;
+
+    if (!validateCompressedTexFormat(internalformat)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;compressedTexImage2D&quot;, &quot;invalid internalformat&quot;);
+        return;
+    }
+    if (border) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;compressedTexImage2D&quot;, &quot;border not 0&quot;);
+        return;
+    }
+    if (!validateCompressedTexDimensions(&quot;compressedTexImage2D&quot;, target, level, width, height, internalformat))
+        return;
+    if (!validateCompressedTexFuncData(&quot;compressedTexImage2D&quot;, width, height, internalformat, data))
+        return;
+
+    WebGLTexture* tex = validateTextureBinding(&quot;compressedTexImage2D&quot;, target, true);
+    if (!tex)
+        return;
+    if (!isGLES2NPOTStrict()) {
+        if (level &amp;&amp; WebGLTexture::isNPOT(width, height)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;compressedTexImage2D&quot;, &quot;level &gt; 0 not power of 2&quot;);
+            return;
+        }
+    }
+    m_context-&gt;moveErrorsToSyntheticErrorList();
+    m_context-&gt;compressedTexImage2D(target, level, internalformat, width, height,
+        border, data-&gt;byteLength(), data-&gt;baseAddress());
+    if (m_context-&gt;moveErrorsToSyntheticErrorList()) {
+        // The compressedTexImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
+        tex-&gt;markInvalid(target, level);
+        return;
+    }
+
+    tex-&gt;setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
+    tex-&gt;setCompressed();
+}
+
+void WebGLRenderingContextBase::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                                    GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView* data)
+{
+    if (isContextLostOrPending())
+        return;
+    if (!validateTexFuncLevel(&quot;compressedTexSubImage2D&quot;, target, level))
+        return;
+    if (!validateCompressedTexFormat(format)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;compressedTexSubImage2D&quot;, &quot;invalid format&quot;);
+        return;
+    }
+    if (!validateCompressedTexFuncData(&quot;compressedTexSubImage2D&quot;, width, height, format, data))
+        return;
+
+    WebGLTexture* tex = validateTextureBinding(&quot;compressedTexSubImage2D&quot;, target, true);
+    if (!tex)
+        return;
+
+    if (format != tex-&gt;getInternalFormat(target, level)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;compressedTexSubImage2D&quot;, &quot;format does not match texture format&quot;);
+        return;
+    }
+
+    if (!validateCompressedTexSubDimensions(&quot;compressedTexSubImage2D&quot;, target, level, xoffset, yoffset, width, height, format, tex))
+        return;
+
+    graphicsContext3D()-&gt;compressedTexSubImage2D(target, level, xoffset, yoffset,
+                                                 width, height, format, data-&gt;byteLength(), data-&gt;baseAddress());
+    tex-&gt;setCompressed();
+}
+
+bool WebGLRenderingContextBase::validateSettableTexFormat(const char* functionName, GC3Denum format)
+{
+    if (GraphicsContext3D::getClearBitsByFormat(format) &amp; (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;format can not be set, only rendered to&quot;);
+        return false;
+    }
+    return true;
+}
+
+void WebGLRenderingContextBase::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+    if (isContextLostOrPending())
+        return;
+    if (!validateTexFuncLevel(&quot;copyTexSubImage2D&quot;, target, level))
+        return;
+    WebGLTexture* tex = validateTextureBinding(&quot;copyTexSubImage2D&quot;, target, true);
+    if (!tex)
+        return;
+    if (!validateSize(&quot;copyTexSubImage2D&quot;, xoffset, yoffset) || !validateSize(&quot;copyTexSubImage2D&quot;, width, height))
+        return;
+    // Before checking if it is in the range, check if overflow happens first.
+    if (xoffset + width &lt; 0 || yoffset + height &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;copyTexSubImage2D&quot;, &quot;bad dimensions&quot;);
+        return;
+    }
+    if (xoffset + width &gt; tex-&gt;getWidth(target, level) || yoffset + height &gt; tex-&gt;getHeight(target, level)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;copyTexSubImage2D&quot;, &quot;rectangle out of range&quot;);
+        return;
+    }
+    GC3Denum internalformat = tex-&gt;getInternalFormat(target, level);
+    if (!validateSettableTexFormat(&quot;copyTexSubImage2D&quot;, internalformat))
+        return;
+    if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;copyTexSubImage2D&quot;, &quot;framebuffer is incompatible format&quot;);
+        return;
+    }
+    const char* reason = &quot;framebuffer incomplete&quot;;
+    if (m_framebufferBinding &amp;&amp; !m_framebufferBinding-&gt;onAccess(graphicsContext3D(), !isResourceSafe(), &amp;reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, &quot;copyTexSubImage2D&quot;, reason);
+        return;
+    }
+    clearIfComposited();
+    if (isResourceSafe())
+        m_context-&gt;copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+    else {
+        GC3Dint clippedX, clippedY;
+        GC3Dsizei clippedWidth, clippedHeight;
+        if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &amp;clippedX, &amp;clippedY, &amp;clippedWidth, &amp;clippedHeight)) {
+            GC3Denum format = tex-&gt;getInternalFormat(target, level);
+            GC3Denum type = tex-&gt;getType(target, level);
+            std::unique_ptr&lt;unsigned char[]&gt; zero;
+            if (width &amp;&amp; height) {
+                unsigned int size;
+                GC3Denum error = m_context-&gt;computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &amp;size, 0);
+                if (error != GraphicsContext3D::NO_ERROR) {
+                    synthesizeGLError(error, &quot;copyTexSubImage2D&quot;, &quot;bad dimensions&quot;);
+                    return;
+                }
+                zero = std::make_unique&lt;unsigned char[]&gt;(size);
+                if (!zero) {
+                    synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;copyTexSubImage2D&quot;, &quot;out of memory&quot;);
+                    return;
+                }
+                memset(zero.get(), 0, size);
+            }
+            m_context-&gt;texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
+            if (clippedWidth &gt; 0 &amp;&amp; clippedHeight &gt; 0)
+                m_context-&gt;copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
+                                             clippedX, clippedY, clippedWidth, clippedHeight);
+        } else
+            m_context-&gt;copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+    }
+}
+
+PassRefPtr&lt;WebGLBuffer&gt; WebGLRenderingContextBase::createBuffer()
+{
+    if (isContextLostOrPending())
+        return nullptr;
+    RefPtr&lt;WebGLBuffer&gt; o = WebGLBuffer::create(this);
+    addSharedObject(o.get());
+    return o;
+}
+
+PassRefPtr&lt;WebGLFramebuffer&gt; WebGLRenderingContextBase::createFramebuffer()
+{
+    if (isContextLostOrPending())
+        return nullptr;
+    RefPtr&lt;WebGLFramebuffer&gt; o = WebGLFramebuffer::create(this);
+    addContextObject(o.get());
+    return o;
+}
+
+PassRefPtr&lt;WebGLTexture&gt; WebGLRenderingContextBase::createTexture()
+{
+    if (isContextLostOrPending())
+        return nullptr;
+    RefPtr&lt;WebGLTexture&gt; o = WebGLTexture::create(this);
+    addSharedObject(o.get());
+    return o;
+}
+
+PassRefPtr&lt;WebGLProgram&gt; WebGLRenderingContextBase::createProgram()
+{
+    if (isContextLostOrPending())
+        return nullptr;
+    RefPtr&lt;WebGLProgram&gt; o = WebGLProgram::create(this);
+    addSharedObject(o.get());
+    return o;
+}
+
+PassRefPtr&lt;WebGLRenderbuffer&gt; WebGLRenderingContextBase::createRenderbuffer()
+{
+    if (isContextLostOrPending())
+        return nullptr;
+    RefPtr&lt;WebGLRenderbuffer&gt; o = WebGLRenderbuffer::create(this);
+    addSharedObject(o.get());
+    return o;
+}
+
+PassRefPtr&lt;WebGLShader&gt; WebGLRenderingContextBase::createShader(GC3Denum type, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return nullptr;
+    if (type != GraphicsContext3D::VERTEX_SHADER &amp;&amp; type != GraphicsContext3D::FRAGMENT_SHADER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;createShader&quot;, &quot;invalid shader type&quot;);
+        return nullptr;
+    }
+
+    RefPtr&lt;WebGLShader&gt; o = WebGLShader::create(this, type);
+    addSharedObject(o.get());
+    return o;
+}
+
+void WebGLRenderingContextBase::cullFace(GC3Denum mode)
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;cullFace(mode);
+}
+
+bool WebGLRenderingContextBase::deleteObject(WebGLObject* object)
+{
+    if (isContextLostOrPending() || !object)
+        return false;
+    if (!object-&gt;validate(contextGroup(), this)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;delete&quot;, &quot;object does not belong to this context&quot;);
+        return false;
+    }
+    if (object-&gt;object())
+        // We need to pass in context here because we want
+        // things in this context unbound.
+        object-&gt;deleteObject(graphicsContext3D());
+    return true;
+}
+
+void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer)
+{
+    if (!deleteObject(buffer))
+        return;
+    if (m_boundArrayBuffer == buffer)
+        m_boundArrayBuffer = nullptr;
+
+    m_boundVertexArrayObject-&gt;unbindBuffer(buffer);
+}
+
+void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer)
+{
+    if (!deleteObject(framebuffer))
+        return;
+    if (framebuffer == m_framebufferBinding) {
+        m_framebufferBinding = nullptr;
+        m_context-&gt;bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
+    }
+}
+
+void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program)
+{
+    deleteObject(program);
+    // We don't reset m_currentProgram to 0 here because the deletion of the
+    // current program is delayed.
+}
+
+void WebGLRenderingContextBase::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
+{
+    if (!deleteObject(renderbuffer))
+        return;
+    if (renderbuffer == m_renderbufferBinding)
+        m_renderbufferBinding = nullptr;
+    if (m_framebufferBinding)
+        m_framebufferBinding-&gt;removeAttachmentFromBoundFramebuffer(renderbuffer);
+}
+
+void WebGLRenderingContextBase::deleteShader(WebGLShader* shader)
+{
+    deleteObject(shader);
+}
+
+void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture)
+{
+    if (!deleteObject(texture))
+        return;
+    for (size_t i = 0; i &lt; m_textureUnits.size(); ++i) {
+        if (texture == m_textureUnits[i].texture2DBinding)
+            m_textureUnits[i].texture2DBinding = nullptr;
+        if (texture == m_textureUnits[i].textureCubeMapBinding)
+            m_textureUnits[i].textureCubeMapBinding = nullptr;
+    }
+    if (m_framebufferBinding)
+        m_framebufferBinding-&gt;removeAttachmentFromBoundFramebuffer(texture);
+}
+
+void WebGLRenderingContextBase::depthFunc(GC3Denum func)
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;depthFunc(func);
+}
+
+void WebGLRenderingContextBase::depthMask(GC3Dboolean flag)
+{
+    if (isContextLostOrPending())
+        return;
+    m_depthMask = flag;
+    m_context-&gt;depthMask(flag);
+}
+
+void WebGLRenderingContextBase::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
+{
+    if (isContextLostOrPending())
+        return;
+    if (zNear &gt; zFar) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;depthRange&quot;, &quot;zNear &gt; zFar&quot;);
+        return;
+    }
+    m_context-&gt;depthRange(zNear, zFar);
+}
+
+void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;detachShader&quot;, program) || !validateWebGLObject(&quot;detachShader&quot;, shader))
+        return;
+    if (!program-&gt;detachShader(shader)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;detachShader&quot;, &quot;shader not attached&quot;);
+        return;
+    }
+    m_context-&gt;detachShader(objectOrZero(program), objectOrZero(shader));
+    shader-&gt;onDetached(graphicsContext3D());
+}
+
+void WebGLRenderingContextBase::disable(GC3Denum cap)
+{
+    if (isContextLostOrPending() || !validateCapability(&quot;disable&quot;, cap))
+        return;
+    if (cap == GraphicsContext3D::STENCIL_TEST) {
+        m_stencilEnabled = false;
+        applyStencilTest();
+        return;
+    }
+    if (cap == GraphicsContext3D::SCISSOR_TEST)
+        m_scissorEnabled = false;
+    m_context-&gt;disable(cap);
+}
+
+void WebGLRenderingContextBase::disableVertexAttribArray(GC3Duint index, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return;
+    if (index &gt;= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;disableVertexAttribArray&quot;, &quot;index out of range&quot;);
+        return;
+    }
+
+    WebGLVertexArrayObjectBase::VertexAttribState&amp; state = m_boundVertexArrayObject-&gt;getVertexAttribState(index);
+    state.enabled = false;
+
+    if (index &gt; 0 || isGLES2Compliant())
+        m_context-&gt;disableVertexAttribArray(index);
+}
+
+bool WebGLRenderingContextBase::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
+{
+    RefPtr&lt;WebGLBuffer&gt; elementArrayBuffer = m_boundVertexArrayObject-&gt;getElementArrayBuffer();
+    
+    if (!elementArrayBuffer)
+        return false;
+
+    if (offset &lt; 0)
+        return false;
+
+    if (type == GraphicsContext3D::UNSIGNED_INT) {
+        // For an unsigned int array, offset must be divisible by 4 for alignment reasons.
+        if (offset % 4)
+            return false;
+
+        // Make uoffset an element offset.
+        offset /= 4;
+
+        GC3Dsizeiptr n = elementArrayBuffer-&gt;byteLength() / 4;
+        if (offset &gt; n || count &gt; n - offset)
+            return false;
+    } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
+        // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
+        if (offset % 2)
+            return false;
+
+        // Make uoffset an element offset.
+        offset /= 2;
+
+        GC3Dsizeiptr n = elementArrayBuffer-&gt;byteLength() / 2;
+        if (offset &gt; n || count &gt; n - offset)
+            return false;
+    } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
+        GC3Dsizeiptr n = elementArrayBuffer-&gt;byteLength();
+        if (offset &gt; n || count &gt; n - offset)
+            return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, unsigned&amp; numElementsRequired)
+{
+    ASSERT(count &gt;= 0 &amp;&amp; offset &gt;= 0);
+    unsigned lastIndex = 0;
+    
+    RefPtr&lt;WebGLBuffer&gt; elementArrayBuffer = m_boundVertexArrayObject-&gt;getElementArrayBuffer();
+
+    if (!elementArrayBuffer)
+        return false;
+
+    if (!count) {
+        numElementsRequired = 0;
+        return true;
+    }
+
+    if (!elementArrayBuffer-&gt;elementArrayBuffer())
+        return false;
+
+    unsigned long uoffset = offset;
+    unsigned long n = count;
+
+    if (type == GraphicsContext3D::UNSIGNED_INT) {
+        // Make uoffset an element offset.
+        uoffset /= sizeof(GC3Duint);
+        const GC3Duint* p = static_cast&lt;const GC3Duint*&gt;(elementArrayBuffer-&gt;elementArrayBuffer()-&gt;data()) + uoffset;
+        while (n-- &gt; 0) {
+            if (*p &gt; lastIndex)
+                lastIndex = *p;
+            ++p;
+        }
+    } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
+        // Make uoffset an element offset.
+        uoffset /= sizeof(GC3Dushort);
+        const GC3Dushort* p = static_cast&lt;const GC3Dushort*&gt;(elementArrayBuffer-&gt;elementArrayBuffer()-&gt;data()) + uoffset;
+        while (n-- &gt; 0) {
+            if (*p &gt; lastIndex)
+                lastIndex = *p;
+            ++p;
+        }
+    } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
+        const GC3Dubyte* p = static_cast&lt;const GC3Dubyte*&gt;(elementArrayBuffer-&gt;elementArrayBuffer()-&gt;data()) + uoffset;
+        while (n-- &gt; 0) {
+            if (*p &gt; lastIndex)
+                lastIndex = *p;
+            ++p;
+        }
+    }
+
+    // Then set the last index in the index array and make sure it is valid.
+    numElementsRequired = lastIndex + 1;
+    return numElementsRequired &gt; 0;
+}
+
+bool WebGLRenderingContextBase::validateVertexAttributes(unsigned elementCount, unsigned primitiveCount)
+{
+    if (!m_currentProgram)
+        return false;
+
+    // Look in each enabled vertex attrib and check if they've been bound to a buffer.
+    for (unsigned i = 0; i &lt; m_maxVertexAttribs; ++i) {
+        if (!m_boundVertexArrayObject-&gt;getVertexAttribState(i).validateBinding())
+            return false;
+    }
+
+    if (elementCount &lt;= 0)
+        return true;
+
+
+    // Look in each consumed vertex attrib (by the current program).
+    bool sawNonInstancedAttrib = false;
+    bool sawEnabledAttrib = false;
+    int numActiveAttribLocations = m_currentProgram-&gt;numActiveAttribLocations();
+    for (int i = 0; i &lt; numActiveAttribLocations; ++i) {
+        int loc = m_currentProgram-&gt;getActiveAttribLocation(i);
+        if (loc &gt;= 0 &amp;&amp; loc &lt; static_cast&lt;int&gt;(m_maxVertexAttribs)) {
+            const WebGLVertexArrayObjectBase::VertexAttribState&amp; state = m_boundVertexArrayObject-&gt;getVertexAttribState(loc);
+            if (state.enabled) {
+                sawEnabledAttrib = true;
+                // Avoid off-by-one errors in numElements computation.
+                // For the last element, we will only touch the data for the
+                // element and nothing beyond it.
+                int bytesRemaining = static_cast&lt;int&gt;(state.bufferBinding-&gt;byteLength() - state.offset);
+                unsigned numElements = 0;
+                ASSERT(state.stride &gt; 0);
+                if (bytesRemaining &gt;= state.bytesPerElement)
+                    numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
+                unsigned instancesRequired = 0;
+                if (state.divisor) {
+                    instancesRequired = ceil(static_cast&lt;float&gt;(primitiveCount) / state.divisor);
+                    if (instancesRequired &gt; numElements)
+                        return false;
+                } else {
+                    sawNonInstancedAttrib = true;
+                    if (elementCount &gt; numElements)
+                        return false;
+                }
+            }
+        }
+    }
+
+    if (!sawNonInstancedAttrib &amp;&amp; sawEnabledAttrib)
+        return false;
+
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateWebGLObject(const char* functionName, WebGLObject* object)
+{
+    if (!object || !object-&gt;object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no object or object deleted&quot;);
+        return false;
+    }
+    if (!object-&gt;validate(contextGroup(), this)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;object does not belong to this context&quot;);
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primitiveCount)
+{
+    if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
+        return false;
+
+    if (!validateStencilSettings(functionName))
+        return false;
+
+    if (first &lt; 0 || count &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;first or count &lt; 0&quot;);
+        return false;
+    }
+
+    if (!count) {
+        markContextChanged();
+        return false;
+    }
+
+    if (primitiveCount &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;primcount &lt; 0&quot;);
+        return false;
+    }
+
+    if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
+        // Ensure we have a valid rendering state
+        Checked&lt;GC3Dint, RecordOverflow&gt; checkedFirst(first);
+        Checked&lt;GC3Dint, RecordOverflow&gt; checkedCount(count);
+        Checked&lt;GC3Dint, RecordOverflow&gt; checkedSum = checkedFirst + checkedCount;
+        Checked&lt;GC3Dint, RecordOverflow&gt; checkedPrimitiveCount(primitiveCount);
+        if (checkedSum.hasOverflowed() || checkedPrimitiveCount.hasOverflowed() || !validateVertexAttributes(checkedSum.unsafeGet(), checkedPrimitiveCount.unsafeGet())) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;attempt to access out of bounds arrays&quot;);
+            return false;
+        }
+    } else {
+        if (!validateVertexAttributes(0)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;attribs not setup correctly&quot;);
+            return false;
+        }
+    }
+
+    const char* reason = &quot;framebuffer incomplete&quot;;
+    if (m_framebufferBinding &amp;&amp; !m_framebufferBinding-&gt;onAccess(graphicsContext3D(), !isResourceSafe(), &amp;reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
+        return false;
+    }
+
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned&amp; numElements, GC3Dsizei primitiveCount)
+{
+    if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
+    return false;
+    
+    if (!validateStencilSettings(functionName))
+    return false;
+    
+    switch (type) {
+    case GraphicsContext3D::UNSIGNED_BYTE:
+    case GraphicsContext3D::UNSIGNED_SHORT:
+        break;
+    case GraphicsContext3D::UNSIGNED_INT:
+        if (m_oesElementIndexUint || isWebGL2())
+            break;
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid type&quot;);
+        return false;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid type&quot;);
+        return false;
+    }
+    
+    if (count &lt; 0 || offset &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;count or offset &lt; 0&quot;);
+        return false;
+    }
+    
+    if (!count) {
+        markContextChanged();
+        return false;
+    }
+    
+    if (primitiveCount &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;primcount &lt; 0&quot;);
+        return false;
+    }
+    
+    if (!m_boundVertexArrayObject-&gt;getElementArrayBuffer()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;no ELEMENT_ARRAY_BUFFER bound&quot;);
+        return false;
+    }
+    
+    if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
+        // Ensure we have a valid rendering state
+        if (!validateElementArraySize(count, type, static_cast&lt;GC3Dintptr&gt;(offset))) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;request out of bounds for current ELEMENT_ARRAY_BUFFER&quot;);
+            return false;
+        }
+        if (!count)
+            return false;
+        
+        Checked&lt;GC3Dint, RecordOverflow&gt; checkedCount(count);
+        Checked&lt;GC3Dint, RecordOverflow&gt; checkedPrimitiveCount(primitiveCount);
+        if (checkedCount.hasOverflowed() || checkedPrimitiveCount.hasOverflowed()) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;attempt to access out of bounds arrays&quot;);
+            return false;
+        }
+        
+        if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
+            if (!validateIndexArrayPrecise(checkedCount.unsafeGet(), type, static_cast&lt;GC3Dintptr&gt;(offset), numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
+                synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;attempt to access out of bounds arrays&quot;);
+                return false;
+            }
+        }
+    } else {
+        if (!validateVertexAttributes(0)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;attribs not setup correctly&quot;);
+            return false;
+        }
+    }
+    
+    const char* reason = &quot;framebuffer incomplete&quot;;
+    if (m_framebufferBinding &amp;&amp; !m_framebufferBinding-&gt;onAccess(graphicsContext3D(), !isResourceSafe(), &amp;reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
+        return false;
+    }
+    
+    return true;
+}
+
+void WebGLRenderingContextBase::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+
+    if (!validateDrawArrays(&quot;drawArrays&quot;, mode, first, count, 0))
+        return;
+
+    clearIfComposited();
+
+    bool vertexAttrib0Simulated = false;
+    if (!isGLES2Compliant())
+        vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness(&quot;drawArrays&quot;, true);
+
+    m_context-&gt;drawArrays(mode, first, count);
+
+    if (!isGLES2Compliant() &amp;&amp; vertexAttrib0Simulated)
+        restoreStatesAfterVertexAttrib0Simulation();
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness(&quot;drawArrays&quot;, false);
+    markContextChanged();
+}
+
+void WebGLRenderingContextBase::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+
+    unsigned numElements = 0;
+    if (!validateDrawElements(&quot;drawElements&quot;, mode, count, type, offset, numElements, 0))
+        return;
+
+    clearIfComposited();
+
+    bool vertexAttrib0Simulated = false;
+    if (!isGLES2Compliant()) {
+        if (!numElements)
+            validateIndexArrayPrecise(count, type, static_cast&lt;GC3Dintptr&gt;(offset), numElements);
+        vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
+    }
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness(&quot;drawElements&quot;, true);
+
+    m_context-&gt;drawElements(mode, count, type, static_cast&lt;GC3Dintptr&gt;(offset));
+
+    if (!isGLES2Compliant() &amp;&amp; vertexAttrib0Simulated)
+        restoreStatesAfterVertexAttrib0Simulation();
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness(&quot;drawElements&quot;, false);
+    markContextChanged();
+}
+
+void WebGLRenderingContextBase::enable(GC3Denum cap)
+{
+    if (isContextLostOrPending() || !validateCapability(&quot;enable&quot;, cap))
+        return;
+    if (cap == GraphicsContext3D::STENCIL_TEST) {
+        m_stencilEnabled = true;
+        applyStencilTest();
+        return;
+    }
+    if (cap == GraphicsContext3D::SCISSOR_TEST)
+        m_scissorEnabled = true;
+    m_context-&gt;enable(cap);
+}
+
+void WebGLRenderingContextBase::enableVertexAttribArray(GC3Duint index, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return;
+    if (index &gt;= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;enableVertexAttribArray&quot;, &quot;index out of range&quot;);
+        return;
+    }
+
+    WebGLVertexArrayObjectBase::VertexAttribState&amp; state = m_boundVertexArrayObject-&gt;getVertexAttribState(index);
+    state.enabled = true;
+
+    m_context-&gt;enableVertexAttribArray(index);
+}
+
+void WebGLRenderingContextBase::finish()
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;finish();
+}
+
+void WebGLRenderingContextBase::flush()
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;flush();
+}
+
+void WebGLRenderingContextBase::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateFramebufferFuncParameters(&quot;framebufferRenderbuffer&quot;, target, attachment))
+        return;
+    if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;framebufferRenderbuffer&quot;, &quot;invalid target&quot;);
+        return;
+    }
+    if (buffer &amp;&amp; !buffer-&gt;validate(contextGroup(), this)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;framebufferRenderbuffer&quot;, &quot;no buffer or buffer not from this context&quot;);
+        return;
+    }
+    // Don't allow the default framebuffer to be mutated; all current
+    // implementations use an FBO internally in place of the default
+    // FBO.
+    if (!m_framebufferBinding || !m_framebufferBinding-&gt;object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;framebufferRenderbuffer&quot;, &quot;no framebuffer bound&quot;);
+        return;
+    }
+    Platform3DObject bufferObject = objectOrZero(buffer);
+    switch (attachment) {
+    case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+        m_context-&gt;framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
+        m_context-&gt;framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
+        break;
+    default:
+        m_context-&gt;framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
+    }
+    m_framebufferBinding-&gt;setAttachmentForBoundFramebuffer(attachment, buffer);
+    applyStencilTest();
+}
+
+void WebGLRenderingContextBase::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateFramebufferFuncParameters(&quot;framebufferTexture2D&quot;, target, attachment))
+        return;
+    if (level) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;framebufferTexture2D&quot;, &quot;level not 0&quot;);
+        return;
+    }
+    if (texture &amp;&amp; !texture-&gt;validate(contextGroup(), this)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;framebufferTexture2D&quot;, &quot;no texture or texture not from this context&quot;);
+        return;
+    }
+    // Don't allow the default framebuffer to be mutated; all current
+    // implementations use an FBO internally in place of the default
+    // FBO.
+    if (!m_framebufferBinding || !m_framebufferBinding-&gt;object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;framebufferTexture2D&quot;, &quot;no framebuffer bound&quot;);
+        return;
+    }
+    Platform3DObject textureObject = objectOrZero(texture);
+    switch (attachment) {
+    case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+        m_context-&gt;framebufferTexture2D(target, GraphicsContext3D::DEPTH_ATTACHMENT, textarget, textureObject, level);
+        m_context-&gt;framebufferTexture2D(target, GraphicsContext3D::STENCIL_ATTACHMENT, textarget, textureObject, level);
+        break;
+    case GraphicsContext3D::DEPTH_ATTACHMENT:
+        m_context-&gt;framebufferTexture2D(target, attachment, textarget, textureObject, level);
+        break;
+    case GraphicsContext3D::STENCIL_ATTACHMENT:
+        m_context-&gt;framebufferTexture2D(target, attachment, textarget, textureObject, level);
+        break;
+    default:
+        m_context-&gt;framebufferTexture2D(target, attachment, textarget, textureObject, level);
+    }
+    m_framebufferBinding-&gt;setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
+    applyStencilTest();
+}
+
+void WebGLRenderingContextBase::frontFace(GC3Denum mode)
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;frontFace(mode);
+}
+
+void WebGLRenderingContextBase::generateMipmap(GC3Denum target)
+{
+    if (isContextLostOrPending())
+        return;
+    WebGLTexture* tex = validateTextureBinding(&quot;generateMipmap&quot;, target, false);
+    if (!tex)
+        return;
+    if (!tex-&gt;canGenerateMipmaps()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;generateMipmap&quot;, &quot;level 0 not power of 2 or not all the same size&quot;);
+        return;
+    }
+    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=123916. Compressed textures should be allowed in WebGL 2:
+    if (tex-&gt;isCompressed()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;generateMipmap&quot;, &quot;trying to generate mipmaps from compressed texture&quot;);
+        return;
+    }
+    if (!validateSettableTexFormat(&quot;generateMipmap&quot;, tex-&gt;getInternalFormat(target, 0)))
+        return;
+
+    // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
+    // on Mac.  Remove the hack once this driver bug is fixed.
+#if OS(DARWIN)
+    bool needToResetMinFilter = false;
+    if (tex-&gt;getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
+        m_context-&gt;texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
+        needToResetMinFilter = true;
+    }
+#endif
+    m_context-&gt;generateMipmap(target);
+#if OS(DARWIN)
+    if (needToResetMinFilter)
+        m_context-&gt;texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex-&gt;getMinFilter());
+#endif
+    tex-&gt;generateMipmapLevelInfo();
+}
+
+PassRefPtr&lt;WebGLActiveInfo&gt; WebGLRenderingContextBase::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getActiveAttrib&quot;, program))
+        return nullptr;
+    ActiveInfo info;
+    if (!m_context-&gt;getActiveAttrib(objectOrZero(program), index, info))
+        return nullptr;
+
+    LOG(WebGL, &quot;Returning active attribute %d: %s&quot;, index, info.name.utf8().data());
+
+    return WebGLActiveInfo::create(info.name, info.type, info.size);
+}
+
+PassRefPtr&lt;WebGLActiveInfo&gt; WebGLRenderingContextBase::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getActiveUniform&quot;, program))
+        return 0;
+    ActiveInfo info;
+    if (!m_context-&gt;getActiveUniform(objectOrZero(program), index, info))
+        return nullptr;
+    if (!isGLES2Compliant())
+        if (info.size &gt; 1 &amp;&amp; !info.name.endsWith(&quot;[0]&quot;))
+            info.name.append(&quot;[0]&quot;);
+
+    LOG(WebGL, &quot;Returning active uniform %d: %s&quot;, index, info.name.utf8().data());
+
+    return WebGLActiveInfo::create(info.name, info.type, info.size);
+}
+
+bool WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program, Vector&lt;RefPtr&lt;WebGLShader&gt;&gt;&amp; shaderObjects, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    shaderObjects.clear();
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getAttachedShaders&quot;, program))
+        return false;
+
+    const GC3Denum shaderType[] = {
+        GraphicsContext3D::VERTEX_SHADER,
+        GraphicsContext3D::FRAGMENT_SHADER
+    };
+    for (unsigned i = 0; i &lt; sizeof(shaderType) / sizeof(GC3Denum); ++i) {
+        WebGLShader* shader = program-&gt;getAttachedShader(shaderType[i]);
+        if (shader)
+            shaderObjects.append(shader);
+    }
+    return true;
+}
+
+GC3Dint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String&amp; name)
+{
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getAttribLocation&quot;, program))
+        return -1;
+    if (!validateLocationLength(&quot;getAttribLocation&quot;, name))
+        return -1;
+    if (!validateString(&quot;getAttribLocation&quot;, name))
+        return -1;
+    if (isPrefixReserved(name))
+        return -1;
+    if (!program-&gt;getLinkStatus()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;getAttribLocation&quot;, &quot;program not linked&quot;);
+        return -1;
+    }
+    return m_context-&gt;getAttribLocation(objectOrZero(program), name);
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return WebGLGetInfo();
+    if (target != GraphicsContext3D::ARRAY_BUFFER &amp;&amp; target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getBufferParameter&quot;, &quot;invalid target&quot;);
+        return WebGLGetInfo();
+    }
+
+    if (pname != GraphicsContext3D::BUFFER_SIZE &amp;&amp; pname != GraphicsContext3D::BUFFER_USAGE) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getBufferParameter&quot;, &quot;invalid parameter name&quot;);
+        return WebGLGetInfo();
+    }
+
+    GC3Dint value = 0;
+    m_context-&gt;getBufferParameteriv(target, pname, &amp;value);
+    if (pname == GraphicsContext3D::BUFFER_SIZE)
+        return WebGLGetInfo(value);
+    return WebGLGetInfo(static_cast&lt;unsigned int&gt;(value));
+}
+
+PassRefPtr&lt;WebGLContextAttributes&gt; WebGLRenderingContextBase::getContextAttributes()
+{
+    if (isContextLostOrPending())
+        return nullptr;
+    // We always need to return a new WebGLContextAttributes object to
+    // prevent the user from mutating any cached version.
+
+    // Also, we need to enforce requested values of &quot;false&quot; for depth
+    // and stencil, regardless of the properties of the underlying
+    // GraphicsContext3D.
+    RefPtr&lt;WebGLContextAttributes&gt; attributes = WebGLContextAttributes::create(m_context-&gt;getContextAttributes());
+    if (!m_attributes.depth)
+        attributes-&gt;setDepth(false);
+    if (!m_attributes.stencil)
+        attributes-&gt;setStencil(false);
+    return attributes.release();
+}
+
+GC3Denum WebGLRenderingContextBase::getError()
+{
+    if (m_isPendingPolicyResolution)
+        return GraphicsContext3D::NO_ERROR;
+    return m_context-&gt;getError();
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getProgramParameter&quot;, program))
+        return WebGLGetInfo();
+
+    GC3Dint value = 0;
+    switch (pname) {
+    case GraphicsContext3D::DELETE_STATUS:
+        return WebGLGetInfo(program-&gt;isDeleted());
+    case GraphicsContext3D::VALIDATE_STATUS:
+        m_context-&gt;getProgramiv(objectOrZero(program), pname, &amp;value);
+        return WebGLGetInfo(static_cast&lt;bool&gt;(value));
+    case GraphicsContext3D::LINK_STATUS:
+        return WebGLGetInfo(program-&gt;getLinkStatus());
+    case GraphicsContext3D::ATTACHED_SHADERS:
+        m_context-&gt;getProgramiv(objectOrZero(program), pname, &amp;value);
+        return WebGLGetInfo(value);
+    case GraphicsContext3D::ACTIVE_ATTRIBUTES:
+    case GraphicsContext3D::ACTIVE_UNIFORMS:
+        m_context-&gt;getNonBuiltInActiveSymbolCount(objectOrZero(program), pname, &amp;value);
+        return WebGLGetInfo(value);
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getProgramParameter&quot;, &quot;invalid parameter name&quot;);
+        return WebGLGetInfo();
+    }
+}
+
+String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getProgramInfoLog&quot;, program))
+        return String();
+    return ensureNotNull(m_context-&gt;getProgramInfoLog(objectOrZero(program)));
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return WebGLGetInfo();
+    if (target != GraphicsContext3D::RENDERBUFFER) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getRenderbufferParameter&quot;, &quot;invalid target&quot;);
+        return WebGLGetInfo();
+    }
+    if (!m_renderbufferBinding || !m_renderbufferBinding-&gt;object()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;getRenderbufferParameter&quot;, &quot;no renderbuffer bound&quot;);
+        return WebGLGetInfo();
+    }
+
+    if (m_renderbufferBinding-&gt;getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
+        &amp;&amp; !m_renderbufferBinding-&gt;isValid()) {
+        ASSERT(!isDepthStencilSupported());
+        int value = 0;
+        switch (pname) {
+        case GraphicsContext3D::RENDERBUFFER_WIDTH:
+            value = m_renderbufferBinding-&gt;getWidth();
+            break;
+        case GraphicsContext3D::RENDERBUFFER_HEIGHT:
+            value = m_renderbufferBinding-&gt;getHeight();
+            break;
+        case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
+        case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
+        case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
+        case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
+            value = 0;
+            break;
+        case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
+            value = 24;
+            break;
+        case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
+            value = 8;
+            break;
+        case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
+            return WebGLGetInfo(m_renderbufferBinding-&gt;getInternalFormat());
+        default:
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getRenderbufferParameter&quot;, &quot;invalid parameter name&quot;);
+            return WebGLGetInfo();
+        }
+        return WebGLGetInfo(value);
+    }
+
+    GC3Dint value = 0;
+    switch (pname) {
+    case GraphicsContext3D::RENDERBUFFER_WIDTH:
+    case GraphicsContext3D::RENDERBUFFER_HEIGHT:
+    case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
+    case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
+        m_context-&gt;getRenderbufferParameteriv(target, pname, &amp;value);
+        return WebGLGetInfo(value);
+    case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
+        return WebGLGetInfo(m_renderbufferBinding-&gt;getInternalFormat());
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getRenderbufferParameter&quot;, &quot;invalid parameter name&quot;);
+        return WebGLGetInfo();
+    }
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getShaderParameter&quot;, shader))
+        return WebGLGetInfo();
+    GC3Dint value = 0;
+    switch (pname) {
+    case GraphicsContext3D::DELETE_STATUS:
+        return WebGLGetInfo(shader-&gt;isDeleted());
+    case GraphicsContext3D::COMPILE_STATUS:
+        m_context-&gt;getShaderiv(objectOrZero(shader), pname, &amp;value);
+        return WebGLGetInfo(static_cast&lt;bool&gt;(value));
+    case GraphicsContext3D::SHADER_TYPE:
+        m_context-&gt;getShaderiv(objectOrZero(shader), pname, &amp;value);
+        return WebGLGetInfo(static_cast&lt;unsigned int&gt;(value));
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getShaderParameter&quot;, &quot;invalid parameter name&quot;);
+        return WebGLGetInfo();
+    }
+}
+
+String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getShaderInfoLog&quot;, shader))
+        return String();
+    return ensureNotNull(m_context-&gt;getShaderInfoLog(objectOrZero(shader)));
+}
+
+PassRefPtr&lt;WebGLShaderPrecisionFormat&gt; WebGLRenderingContextBase::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return nullptr;
+    switch (shaderType) {
+    case GraphicsContext3D::VERTEX_SHADER:
+    case GraphicsContext3D::FRAGMENT_SHADER:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getShaderPrecisionFormat&quot;, &quot;invalid shader type&quot;);
+        return nullptr;
+    }
+    switch (precisionType) {
+    case GraphicsContext3D::LOW_FLOAT:
+    case GraphicsContext3D::MEDIUM_FLOAT:
+    case GraphicsContext3D::HIGH_FLOAT:
+    case GraphicsContext3D::LOW_INT:
+    case GraphicsContext3D::MEDIUM_INT:
+    case GraphicsContext3D::HIGH_INT:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getShaderPrecisionFormat&quot;, &quot;invalid precision type&quot;);
+        return nullptr;
+    }
+
+    GC3Dint range[2] = {0, 0};
+    GC3Dint precision = 0;
+    m_context-&gt;getShaderPrecisionFormat(shaderType, precisionType, range, &amp;precision);
+    return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
+}
+
+String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getShaderSource&quot;, shader))
+        return String();
+    return ensureNotNull(shader-&gt;getSource());
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return WebGLGetInfo();
+    WebGLTexture* tex = validateTextureBinding(&quot;getTexParameter&quot;, target, false);
+    if (!tex)
+        return WebGLGetInfo();
+    GC3Dint value = 0;
+    switch (pname) {
+    case GraphicsContext3D::TEXTURE_MAG_FILTER:
+    case GraphicsContext3D::TEXTURE_MIN_FILTER:
+    case GraphicsContext3D::TEXTURE_WRAP_S:
+    case GraphicsContext3D::TEXTURE_WRAP_T:
+        m_context-&gt;getTexParameteriv(target, pname, &amp;value);
+        return WebGLGetInfo(static_cast&lt;unsigned int&gt;(value));
+    case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
+        if (m_extTextureFilterAnisotropic) {
+            m_context-&gt;getTexParameteriv(target, pname, &amp;value);
+            return WebGLGetInfo(static_cast&lt;unsigned int&gt;(value));
+        }
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getTexParameter&quot;, &quot;invalid parameter name, EXT_texture_filter_anisotropic not enabled&quot;);
+        return WebGLGetInfo();
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getTexParameter&quot;, &quot;invalid parameter name&quot;);
+        return WebGLGetInfo();
+    }
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getUniform&quot;, program))
+        return WebGLGetInfo();
+    if (!uniformLocation || uniformLocation-&gt;program() != program) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;getUniform&quot;, &quot;no uniformlocation or not valid for this program&quot;);
+        return WebGLGetInfo();
+    }
+    GC3Dint location = uniformLocation-&gt;location();
+
+    GC3Denum baseType;
+    unsigned length;
+    switch (uniformLocation-&gt;type()) {
+    case GraphicsContext3D::BOOL:
+        baseType = GraphicsContext3D::BOOL;
+        length = 1;
+        break;
+    case GraphicsContext3D::BOOL_VEC2:
+        baseType = GraphicsContext3D::BOOL;
+        length = 2;
+        break;
+    case GraphicsContext3D::BOOL_VEC3:
+        baseType = GraphicsContext3D::BOOL;
+        length = 3;
+        break;
+    case GraphicsContext3D::BOOL_VEC4:
+        baseType = GraphicsContext3D::BOOL;
+        length = 4;
+        break;
+    case GraphicsContext3D::INT:
+        baseType = GraphicsContext3D::INT;
+        length = 1;
+        break;
+    case GraphicsContext3D::INT_VEC2:
+        baseType = GraphicsContext3D::INT;
+        length = 2;
+        break;
+    case GraphicsContext3D::INT_VEC3:
+        baseType = GraphicsContext3D::INT;
+        length = 3;
+        break;
+    case GraphicsContext3D::INT_VEC4:
+        baseType = GraphicsContext3D::INT;
+        length = 4;
+        break;
+    case GraphicsContext3D::FLOAT:
+        baseType = GraphicsContext3D::FLOAT;
+        length = 1;
+        break;
+    case GraphicsContext3D::FLOAT_VEC2:
+        baseType = GraphicsContext3D::FLOAT;
+        length = 2;
+        break;
+    case GraphicsContext3D::FLOAT_VEC3:
+        baseType = GraphicsContext3D::FLOAT;
+        length = 3;
+        break;
+    case GraphicsContext3D::FLOAT_VEC4:
+        baseType = GraphicsContext3D::FLOAT;
+        length = 4;
+        break;
+    case GraphicsContext3D::FLOAT_MAT2:
+        baseType = GraphicsContext3D::FLOAT;
+        length = 4;
+        break;
+    case GraphicsContext3D::FLOAT_MAT3:
+        baseType = GraphicsContext3D::FLOAT;
+        length = 9;
+        break;
+    case GraphicsContext3D::FLOAT_MAT4:
+        baseType = GraphicsContext3D::FLOAT;
+        length = 16;
+        break;
+    case GraphicsContext3D::SAMPLER_2D:
+    case GraphicsContext3D::SAMPLER_CUBE:
+        baseType = GraphicsContext3D::INT;
+        length = 1;
+        break;
+    default:
+        // Can't handle this type
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;getUniform&quot;, &quot;unhandled type&quot;);
+        return WebGLGetInfo();
+    }
+    switch (baseType) {
+    case GraphicsContext3D::FLOAT: {
+        GC3Dfloat value[16] = {0};
+        if (m_isRobustnessEXTSupported)
+            m_context-&gt;getExtensions()-&gt;getnUniformfvEXT(objectOrZero(program), location, 16 * sizeof(GC3Dfloat), value);
+        else
+            m_context-&gt;getUniformfv(objectOrZero(program), location, value);
+        if (length == 1)
+            return WebGLGetInfo(value[0]);
+        return WebGLGetInfo(Float32Array::create(value, length).release());
+    }
+    case GraphicsContext3D::INT: {
+        GC3Dint value[4] = {0};
+        if (m_isRobustnessEXTSupported)
+            m_context-&gt;getExtensions()-&gt;getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
+        else
+            m_context-&gt;getUniformiv(objectOrZero(program), location, value);
+        if (length == 1)
+            return WebGLGetInfo(value[0]);
+        return WebGLGetInfo(Int32Array::create(value, length).release());
+    }
+    case GraphicsContext3D::BOOL: {
+        GC3Dint value[4] = {0};
+        if (m_isRobustnessEXTSupported)
+            m_context-&gt;getExtensions()-&gt;getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
+        else
+            m_context-&gt;getUniformiv(objectOrZero(program), location, value);
+        if (length &gt; 1) {
+            bool boolValue[16] = {0};
+            for (unsigned j = 0; j &lt; length; j++)
+                boolValue[j] = static_cast&lt;bool&gt;(value[j]);
+            return WebGLGetInfo(boolValue, length);
+        }
+        return WebGLGetInfo(static_cast&lt;bool&gt;(value[0]));
+    }
+    default:
+        notImplemented();
+    }
+
+    // If we get here, something went wrong in our unfortunately complex logic above
+    synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;getUniform&quot;, &quot;unknown error&quot;);
+    return WebGLGetInfo();
+}
+
+PassRefPtr&lt;WebGLUniformLocation&gt; WebGLRenderingContextBase::getUniformLocation(WebGLProgram* program, const String&amp; name, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;getUniformLocation&quot;, program))
+        return nullptr;
+    if (!validateLocationLength(&quot;getUniformLocation&quot;, name))
+        return nullptr;
+    if (!validateString(&quot;getUniformLocation&quot;, name))
+        return nullptr;
+    if (isPrefixReserved(name))
+        return nullptr;
+    if (!program-&gt;getLinkStatus()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;getUniformLocation&quot;, &quot;program not linked&quot;);
+        return nullptr;
+    }
+    GC3Dint uniformLocation = m_context-&gt;getUniformLocation(objectOrZero(program), name);
+    if (uniformLocation == -1)
+        return nullptr;
+
+    GC3Dint activeUniforms = 0;
+    m_context-&gt;getNonBuiltInActiveSymbolCount(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &amp;activeUniforms);
+    for (GC3Dint i = 0; i &lt; activeUniforms; i++) {
+        ActiveInfo info;
+        if (!m_context-&gt;getActiveUniform(objectOrZero(program), i, info))
+            return nullptr;
+        // Strip &quot;[0]&quot; from the name if it's an array.
+        if (info.name.endsWith(&quot;[0]&quot;))
+            info.name = info.name.left(info.name.length() - 3);
+        // If it's an array, we need to iterate through each element, appending &quot;[index]&quot; to the name.
+        for (GC3Dint index = 0; index &lt; info.size; ++index) {
+            String uniformName = info.name + &quot;[&quot; + String::number(index) + &quot;]&quot;;
+
+            if (name == uniformName || name == info.name)
+                return WebGLUniformLocation::create(program, uniformLocation, info.type);
+        }
+    }
+    return nullptr;
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+
+    if (isContextLostOrPending())
+        return WebGLGetInfo();
+
+    if (index &gt;= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;getVertexAttrib&quot;, &quot;index out of range&quot;);
+        return WebGLGetInfo();
+    }
+
+    const WebGLVertexArrayObjectBase::VertexAttribState&amp; state = m_boundVertexArrayObject-&gt;getVertexAttribState(index);
+
+    if ((isWebGL2() || m_angleInstancedArrays) &amp;&amp; pname == GraphicsContext3D::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)
+        return WebGLGetInfo(state.divisor);
+
+    switch (pname) {
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+        if ((!isGLES2Compliant() &amp;&amp; !index &amp;&amp; m_boundVertexArrayObject-&gt;getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
+            || !state.bufferBinding
+            || !state.bufferBinding-&gt;object())
+            return WebGLGetInfo();
+        return WebGLGetInfo(PassRefPtr&lt;WebGLBuffer&gt;(state.bufferBinding));
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
+        return WebGLGetInfo(state.enabled);
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
+        return WebGLGetInfo(state.normalized);
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
+        return WebGLGetInfo(state.size);
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
+        return WebGLGetInfo(state.originalStride);
+    case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
+        return WebGLGetInfo(state.type);
+    case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
+        return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4).release());
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;getVertexAttrib&quot;, &quot;invalid parameter name&quot;);
+        return WebGLGetInfo();
+    }
+}
+
+long long WebGLRenderingContextBase::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
+{
+    if (isContextLostOrPending())
+        return 0;
+    GC3Dsizeiptr result = m_context-&gt;getVertexAttribOffset(index, pname);
+    return static_cast&lt;long long&gt;(result);
+}
+
+GC3Dboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer)
+{
+    if (!buffer || isContextLostOrPending())
+        return 0;
+
+    if (!buffer-&gt;hasEverBeenBound())
+        return 0;
+
+    return m_context-&gt;isBuffer(buffer-&gt;object());
+}
+
+bool WebGLRenderingContextBase::isContextLost() const
+{
+    return m_contextLost;
+}
+
+bool WebGLRenderingContextBase::isContextLostOrPending()
+{
+    if (m_isPendingPolicyResolution &amp;&amp; !m_hasRequestedPolicyResolution) {
+        LOG(WebGL, &quot;Context is being used. Attempt to resolve the policy.&quot;);
+        Document&amp; document = canvas()-&gt;document().topDocument();
+        Page* page = document.page();
+        if (page &amp;&amp; !document.url().isLocalFile())
+            page-&gt;mainFrame().loader().client().resolveWebGLPolicyForURL(document.url());
+        // FIXME: We don't currently do anything with the result from resolution. A more
+        // complete implementation might try to construct a real context, etc and proceed
+        // with normal operation.
+        // https://bugs.webkit.org/show_bug.cgi?id=129122
+        m_hasRequestedPolicyResolution = true;
+    }
+
+    return m_contextLost || m_isPendingPolicyResolution;
+}
+
+GC3Dboolean WebGLRenderingContextBase::isEnabled(GC3Denum cap)
+{
+    if (isContextLostOrPending() || !validateCapability(&quot;isEnabled&quot;, cap))
+        return 0;
+    if (cap == GraphicsContext3D::STENCIL_TEST)
+        return m_stencilEnabled;
+    return m_context-&gt;isEnabled(cap);
+}
+
+GC3Dboolean WebGLRenderingContextBase::isFramebuffer(WebGLFramebuffer* framebuffer)
+{
+    if (!framebuffer || isContextLostOrPending())
+        return 0;
+
+    if (!framebuffer-&gt;hasEverBeenBound())
+        return 0;
+
+    return m_context-&gt;isFramebuffer(framebuffer-&gt;object());
+}
+
+GC3Dboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program)
+{
+    if (!program || isContextLostOrPending())
+        return 0;
+
+    return m_context-&gt;isProgram(program-&gt;object());
+}
+
+GC3Dboolean WebGLRenderingContextBase::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
+{
+    if (!renderbuffer || isContextLostOrPending())
+        return 0;
+
+    if (!renderbuffer-&gt;hasEverBeenBound())
+        return 0;
+
+    return m_context-&gt;isRenderbuffer(renderbuffer-&gt;object());
+}
+
+GC3Dboolean WebGLRenderingContextBase::isShader(WebGLShader* shader)
+{
+    if (!shader || isContextLostOrPending())
+        return 0;
+
+    return m_context-&gt;isShader(shader-&gt;object());
+}
+
+GC3Dboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture)
+{
+    if (!texture || isContextLostOrPending())
+        return 0;
+
+    if (!texture-&gt;hasEverBeenBound())
+        return 0;
+
+    return m_context-&gt;isTexture(texture-&gt;object());
+}
+
+void WebGLRenderingContextBase::lineWidth(GC3Dfloat width)
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;lineWidth(width);
+}
+
+void WebGLRenderingContextBase::linkProgram(WebGLProgram* program, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;linkProgram&quot;, program))
+        return;
+    if (!isGLES2Compliant()) {
+        WebGLShader* vertexShader = program-&gt;getAttachedShader(GraphicsContext3D::VERTEX_SHADER);
+        WebGLShader* fragmentShader = program-&gt;getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER);
+        if (!vertexShader || !vertexShader-&gt;isValid() || !fragmentShader || !fragmentShader-&gt;isValid() || !m_context-&gt;precisionsMatch(objectOrZero(vertexShader), objectOrZero(fragmentShader)) || !m_context-&gt;checkVaryingsPacking(objectOrZero(vertexShader), objectOrZero(fragmentShader))) {
+            program-&gt;setLinkStatus(false);
+            return;
+        }
+    }
+
+    m_context-&gt;linkProgram(objectOrZero(program));
+    program-&gt;increaseLinkCount();
+}
+
+void WebGLRenderingContextBase::pixelStorei(GC3Denum pname, GC3Dint param)
+{
+    if (isContextLostOrPending())
+        return;
+    switch (pname) {
+    case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
+        m_unpackFlipY = param;
+        break;
+    case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
+        m_unpackPremultiplyAlpha = param;
+        break;
+    case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
+        if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
+            m_unpackColorspaceConversion = static_cast&lt;GC3Denum&gt;(param);
+        else {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;pixelStorei&quot;, &quot;invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL&quot;);
+            return;
+        }
+        break;
+    case GraphicsContext3D::PACK_ALIGNMENT:
+    case GraphicsContext3D::UNPACK_ALIGNMENT:
+        if (param == 1 || param == 2 || param == 4 || param == 8) {
+            if (pname == GraphicsContext3D::PACK_ALIGNMENT)
+                m_packAlignment = param;
+            else // GraphicsContext3D::UNPACK_ALIGNMENT:
+                m_unpackAlignment = param;
+            m_context-&gt;pixelStorei(pname, param);
+        } else {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;pixelStorei&quot;, &quot;invalid parameter for alignment&quot;);
+            return;
+        }
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;pixelStorei&quot;, &quot;invalid parameter name&quot;);
+        return;
+    }
+}
+
+void WebGLRenderingContextBase::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;polygonOffset(factor, units);
+}
+
+void WebGLRenderingContextBase::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&amp;)
+{
+    if (isContextLostOrPending())
+        return;
+    // Due to WebGL's same-origin restrictions, it is not possible to
+    // taint the origin using the WebGL API.
+    ASSERT(canvas()-&gt;originClean());
+    // Validate input parameters.
+    if (!pixels) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;readPixels&quot;, &quot;no destination ArrayBufferView&quot;);
+        return;
+    }
+    switch (format) {
+    case GraphicsContext3D::ALPHA:
+    case GraphicsContext3D::RGB:
+    case GraphicsContext3D::RGBA:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;readPixels&quot;, &quot;invalid format&quot;);
+        return;
+    }
+    switch (type) {
+    case GraphicsContext3D::UNSIGNED_BYTE:
+    case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
+    case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
+    case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;readPixels&quot;, &quot;invalid type&quot;);
+        return;
+    }
+    if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;readPixels&quot;, &quot;format not RGBA or type not UNSIGNED_BYTE&quot;);
+        return;
+    }
+    // Validate array type against pixel type.
+    if (pixels-&gt;getType() != JSC::TypeUint8) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;readPixels&quot;, &quot;ArrayBufferView not Uint8Array&quot;);
+        return;
+    }
+    const char* reason = &quot;framebuffer incomplete&quot;;
+    if (m_framebufferBinding &amp;&amp; !m_framebufferBinding-&gt;onAccess(graphicsContext3D(), !isResourceSafe(), &amp;reason)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, &quot;readPixels&quot;, reason);
+        return;
+    }
+    // Calculate array size, taking into consideration of PACK_ALIGNMENT.
+    unsigned int totalBytesRequired = 0;
+    unsigned int padding = 0;
+    if (!m_isRobustnessEXTSupported) {
+        GC3Denum error = m_context-&gt;computeImageSizeInBytes(format, type, width, height, m_packAlignment, &amp;totalBytesRequired, &amp;padding);
+        if (error != GraphicsContext3D::NO_ERROR) {
+            synthesizeGLError(error, &quot;readPixels&quot;, &quot;invalid dimensions&quot;);
+            return;
+        }
+        if (pixels-&gt;byteLength() &lt; totalBytesRequired) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;readPixels&quot;, &quot;ArrayBufferView not large enough for dimensions&quot;);
+            return;
+        }
+    }
+
+    clearIfComposited();
+    void* data = pixels-&gt;baseAddress();
+
+    {
+        if (m_isRobustnessEXTSupported)
+            m_context-&gt;getExtensions()-&gt;readnPixelsEXT(x, y, width, height, format, type, pixels-&gt;byteLength(), data);
+        else
+            m_context-&gt;readPixels(x, y, width, height, format, type, data);
+    }
+
+#if OS(DARWIN)
+    if (m_isRobustnessEXTSupported) // we haven't computed padding
+        m_context-&gt;computeImageSizeInBytes(format, type, width, height, m_packAlignment, &amp;totalBytesRequired, &amp;padding);
+    // FIXME: remove this section when GL driver bug on Mac AND the GLES driver bug
+    // on QC is fixed, i.e., when alpha is off, readPixels should
+    // set alpha to 255 instead of 0.
+    if (!m_framebufferBinding &amp;&amp; !m_context-&gt;getContextAttributes().alpha) {
+        unsigned char* pixels = reinterpret_cast&lt;unsigned char*&gt;(data);
+        for (GC3Dsizei iy = 0; iy &lt; height; ++iy) {
+            for (GC3Dsizei ix = 0; ix &lt; width; ++ix) {
+                pixels[3] = 255;
+                pixels += 4;
+            }
+            pixels += padding;
+        }
+    }
+#endif
+}
+
+void WebGLRenderingContextBase::releaseShaderCompiler()
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;releaseShaderCompiler();
+}
+
+void WebGLRenderingContextBase::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;sampleCoverage(value, invert);
+}
+
+void WebGLRenderingContextBase::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+    if (isContextLostOrPending())
+        return;
+    if (!validateSize(&quot;scissor&quot;, width, height))
+        return;
+    m_context-&gt;scissor(x, y, width, height);
+}
+
+void WebGLRenderingContextBase::shaderSource(WebGLShader* shader, const String&amp; string, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;shaderSource&quot;, shader))
+        return;
+    String stringWithoutComments = StripComments(string).result();
+    if (!validateString(&quot;shaderSource&quot;, stringWithoutComments))
+        return;
+    shader-&gt;setSource(string);
+    m_context-&gt;shaderSource(objectOrZero(shader), stringWithoutComments);
+}
+
+void WebGLRenderingContextBase::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+    if (isContextLostOrPending())
+        return;
+    if (!validateStencilFunc(&quot;stencilFunc&quot;, func))
+        return;
+    m_stencilFuncRef = ref;
+    m_stencilFuncRefBack = ref;
+    m_stencilFuncMask = mask;
+    m_stencilFuncMaskBack = mask;
+    m_context-&gt;stencilFunc(func, ref, mask);
+}
+
+void WebGLRenderingContextBase::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+    if (isContextLostOrPending())
+        return;
+    if (!validateStencilFunc(&quot;stencilFuncSeparate&quot;, func))
+        return;
+    switch (face) {
+    case GraphicsContext3D::FRONT_AND_BACK:
+        m_stencilFuncRef = ref;
+        m_stencilFuncRefBack = ref;
+        m_stencilFuncMask = mask;
+        m_stencilFuncMaskBack = mask;
+        break;
+    case GraphicsContext3D::FRONT:
+        m_stencilFuncRef = ref;
+        m_stencilFuncMask = mask;
+        break;
+    case GraphicsContext3D::BACK:
+        m_stencilFuncRefBack = ref;
+        m_stencilFuncMaskBack = mask;
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;stencilFuncSeparate&quot;, &quot;invalid face&quot;);
+        return;
+    }
+    m_context-&gt;stencilFuncSeparate(face, func, ref, mask);
+}
+
+void WebGLRenderingContextBase::stencilMask(GC3Duint mask)
+{
+    if (isContextLostOrPending())
+        return;
+    m_stencilMask = mask;
+    m_stencilMaskBack = mask;
+    m_context-&gt;stencilMask(mask);
+}
+
+void WebGLRenderingContextBase::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
+{
+    if (isContextLostOrPending())
+        return;
+    switch (face) {
+    case GraphicsContext3D::FRONT_AND_BACK:
+        m_stencilMask = mask;
+        m_stencilMaskBack = mask;
+        break;
+    case GraphicsContext3D::FRONT:
+        m_stencilMask = mask;
+        break;
+    case GraphicsContext3D::BACK:
+        m_stencilMaskBack = mask;
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;stencilMaskSeparate&quot;, &quot;invalid face&quot;);
+        return;
+    }
+    m_context-&gt;stencilMaskSeparate(face, mask);
+}
+
+void WebGLRenderingContextBase::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;stencilOp(fail, zfail, zpass);
+}
+
+void WebGLRenderingContextBase::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+    if (isContextLostOrPending())
+        return;
+    m_context-&gt;stencilOpSeparate(face, fail, zfail, zpass);
+}
+
+void WebGLRenderingContextBase::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode&amp; ec)
+{
+    // FIXME: For now we ignore any errors returned.
+    ec = 0;
+    WebGLTexture* tex = validateTextureBinding(&quot;texImage2D&quot;, target, true);
+    ASSERT(validateTexFuncParameters(&quot;texImage2D&quot;, TexImage, target, level, internalformat, width, height, border, format, type));
+    ASSERT(tex);
+    ASSERT(!level || !WebGLTexture::isNPOT(width, height));
+    if (!pixels) {
+        // Note: Chromium's OpenGL implementation clears textures and isResourceSafe() is therefore true.
+        // For other implementations, if they are using ANGLE_depth_texture, ANGLE depth textures
+        // can not be cleared with texImage2D and must be cleared by binding to an fbo and calling
+        // clear.
+        if (isResourceSafe())
+            m_context-&gt;texImage2D(target, level, internalformat, width, height, border, format, type, nullptr);
+        else {
+            bool succeed = m_context-&gt;texImage2DResourceSafe(target, level, internalformat, width, height,
+                                                             border, format, type, m_unpackAlignment);
+            if (!succeed)
+                return;
+        }
+    } else {
+        ASSERT(validateSettableTexFormat(&quot;texImage2D&quot;, internalformat));
+        m_context-&gt;moveErrorsToSyntheticErrorList();
+        m_context-&gt;texImage2D(target, level, internalformat, width, height,
+                              border, format, type, pixels);
+        if (m_context-&gt;moveErrorsToSyntheticErrorList()) {
+            // The texImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
+            tex-&gt;markInvalid(target, level);
+            return;
+        }
+    }
+    tex-&gt;setLevelInfo(target, level, internalformat, width, height, type);
+}
+
+void WebGLRenderingContextBase::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionCode&amp; ec)
+{
+    ec = 0;
+    Vector&lt;uint8_t&gt; data;
+    GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);
+    if (!imageExtractor.extractSucceeded()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;texImage2D&quot;, &quot;bad image data&quot;);
+        return;
+    }
+    GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
+    GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
+    const void* imagePixelData = imageExtractor.imagePixelData();
+
+    bool needConversion = true;
+    if (type == GraphicsContext3D::UNSIGNED_BYTE &amp;&amp; sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 &amp;&amp; format == GraphicsContext3D::RGBA &amp;&amp; alphaOp == GraphicsContext3D::AlphaDoNothing &amp;&amp; !flipY)
+        needConversion = false;
+    else {
+        if (!m_context-&gt;packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;texImage2D&quot;, &quot;packImage error&quot;);
+            return;
+        }
+    }
+
+    if (m_unpackAlignment != 1)
+        m_context-&gt;pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+    texImage2DBase(target, level, internalformat, image-&gt;width(), image-&gt;height(), 0, format, type, needConversion ? data.data() : imagePixelData, ec);
+    if (m_unpackAlignment != 1)
+        m_context-&gt;pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
+}
+
+bool WebGLRenderingContextBase::validateTexFunc(const char* functionName, TexFuncValidationFunctionType functionType, TexFuncValidationSourceType sourceType, GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint xoffset, GC3Dint yoffset)
+{
+    if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, border, format, type))
+        return false;
+
+    WebGLTexture* texture = validateTextureBinding(functionName, target, true);
+    if (!texture)
+        return false;
+
+    if (functionType != TexSubImage) {
+        if (level &amp;&amp; WebGLTexture::isNPOT(width, height)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;level &gt; 0 not power of 2&quot;);
+            return false;
+        }
+        // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat
+        // by checking if the ArrayBufferView is null or not.
+        if (sourceType != SourceArrayBufferView) {
+            if (!validateSettableTexFormat(functionName, format))
+                return false;
+        }
+    } else {
+        if (!validateSettableTexFormat(functionName, format))
+            return false;
+        if (!validateSize(functionName, xoffset, yoffset))
+            return false;
+        // Before checking if it is in the range, check if overflow happens first.
+        if (xoffset + width &lt; 0 || yoffset + height &lt; 0) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;bad dimensions&quot;);
+            return false;
+        }
+        if (xoffset + width &gt; texture-&gt;getWidth(target, level) || yoffset + height &gt; texture-&gt;getHeight(target, level)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;dimensions out of range&quot;);
+            return false;
+        }
+        if (texture-&gt;getInternalFormat(target, level) != format || texture-&gt;getType(target, level) != type) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;type and format do not match texture&quot;);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Dsizei width, GC3Dsizei height, GC3Dint border,
+                                       GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&amp; ec)
+{
+    if (isContextLostOrPending() || !validateTexFuncData(&quot;texImage2D&quot;, level, width, height, internalformat, format, type, pixels, NullAllowed)
+        || !validateTexFunc(&quot;texImage2D&quot;, TexImage, SourceArrayBufferView, target, level, internalformat, width, height, border, format, type, 0, 0))
+        return;
+    void* data = pixels ? pixels-&gt;baseAddress() : 0;
+    Vector&lt;uint8_t&gt; tempData;
+    bool changeUnpackAlignment = false;
+    if (data &amp;&amp; (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
+        if (!m_context-&gt;extractTextureData(width, height, format, type,
+                                           m_unpackAlignment,
+                                           m_unpackFlipY, m_unpackPremultiplyAlpha,
+                                           data,
+                                           tempData))
+            return;
+        data = tempData.data();
+        changeUnpackAlignment = true;
+    }
+    if (changeUnpackAlignment)
+        m_context-&gt;pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+    texImage2DBase(target, level, internalformat, width, height, border,
+                   format, type, data, ec);
+    if (changeUnpackAlignment)
+        m_context-&gt;pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
+}
+
+void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode&amp; ec)
+{
+    ec = 0;
+    if (isContextLostOrPending() || !pixels || !validateTexFunc(&quot;texImage2D&quot;, TexImage, SourceImageData, target, level, internalformat, pixels-&gt;width(), pixels-&gt;height(), 0, format, type, 0, 0))
+        return;
+    Vector&lt;uint8_t&gt; data;
+    bool needConversion = true;
+    // The data from ImageData is always of format RGBA8.
+    // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
+    if (!m_unpackFlipY &amp;&amp; !m_unpackPremultiplyAlpha &amp;&amp; format == GraphicsContext3D::RGBA &amp;&amp; type == GraphicsContext3D::UNSIGNED_BYTE)
+        needConversion = false;
+    else {
+        if (!m_context-&gt;extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;texImage2D&quot;, &quot;bad image data&quot;);
+            return;
+        }
+    }
+    if (m_unpackAlignment != 1)
+        m_context-&gt;pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+    texImage2DBase(target, level, internalformat, pixels-&gt;width(), pixels-&gt;height(), 0, format, type, needConversion ? data.data() : pixels-&gt;data()-&gt;data(), ec);
+    if (m_unpackAlignment != 1)
+        m_context-&gt;pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
+}
+
+PassRefPtr&lt;Image&gt; WebGLRenderingContextBase::drawImageIntoBuffer(Image* image, int width, int height, int deviceScaleFactor)
+{
+    IntSize size(width, height);
+    size.scale(deviceScaleFactor);
+    ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
+    if (!buf) {
+        synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, &quot;texImage2D&quot;, &quot;out of memory&quot;);
+        return nullptr;
+    }
+
+    FloatRect srcRect(FloatPoint(), image-&gt;size());
+    FloatRect destRect(FloatPoint(), size);
+    buf-&gt;context()-&gt;drawImage(image, ColorSpaceDeviceRGB, destRect, srcRect);
+    return buf-&gt;copyImage(ImageBuffer::fastCopyImageMode());
+}
+
+void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode&amp; ec)
+{
+    ec = 0;
+    if (isContextLostOrPending() || !validateHTMLImageElement(&quot;texImage2D&quot;, image, ec))
+        return;
+
+    RefPtr&lt;Image&gt; imageForRender = image-&gt;cachedImage()-&gt;imageForRenderer(image-&gt;renderer());
+    if (imageForRender-&gt;isSVGImage())
+        imageForRender = drawImageIntoBuffer(imageForRender.get(), image-&gt;width(), image-&gt;height(), 1);
+
+    if (!imageForRender || !validateTexFunc(&quot;texImage2D&quot;, TexImage, SourceHTMLImageElement, target, level, internalformat, imageForRender-&gt;width(), imageForRender-&gt;height(), 0, format, type, 0, 0))
+        return;
+
+    texImage2DImpl(target, level, internalformat, format, type, imageForRender.get(), GraphicsContext3D::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
+}
+
+void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode&amp; ec)
+{
+    ec = 0;
+    if (isContextLostOrPending() || !validateHTMLCanvasElement(&quot;texImage2D&quot;, canvas, ec) || !validateTexFunc(&quot;texImage2D&quot;, TexImage, SourceHTMLCanvasElement, target, level, internalformat, canvas-&gt;width(), canvas-&gt;height(), 0, format, type, 0, 0))
+        return;
+
+    WebGLTexture* texture = validateTextureBinding(&quot;texImage2D&quot;, target, true);
+    // If possible, copy from the canvas element directly to the texture
+    // via the GPU, without a read-back to system memory.
+    //
+    // FIXME: restriction of (RGB || RGBA)/UNSIGNED_BYTE should be lifted when
+    // ImageBuffer::copyToPlatformTexture implementations are fully functional.
+    if (GraphicsContext3D::TEXTURE_2D == target &amp;&amp; texture &amp;&amp; type == texture-&gt;getType(target, level)
+        &amp;&amp; (format == GraphicsContext3D::RGB || format == GraphicsContext3D::RGBA) &amp;&amp; type == GraphicsContext3D::UNSIGNED_BYTE) {
+        ImageBuffer* buffer = canvas-&gt;buffer();
+        if (buffer &amp;&amp; buffer-&gt;copyToPlatformTexture(*m_context.get(), texture-&gt;object(), internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
+            texture-&gt;setLevelInfo(target, level, internalformat, canvas-&gt;width(), canvas-&gt;height(), type);
+            return;
+        }
+    }
+
+    RefPtr&lt;ImageData&gt; imageData = canvas-&gt;getImageData();
+    if (imageData)
+        texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
+    else
+        texImage2DImpl(target, level, internalformat, format, type, canvas-&gt;copiedImage(), GraphicsContext3D::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
+}
+
+#if ENABLE(VIDEO)
+PassRefPtr&lt;Image&gt; WebGLRenderingContextBase::videoFrameToImage(HTMLVideoElement* video, BackingStoreCopy backingStoreCopy, ExceptionCode&amp;)
+{
+    IntSize size(video-&gt;videoWidth(), video-&gt;videoHeight());
+    ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
+    if (!buf) {
+        synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, &quot;texImage2D&quot;, &quot;out of memory&quot;);
+        return nullptr;
+    }
+    FloatRect destRect(0, 0, size.width(), size.height());
+    // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
+    video-&gt;paintCurrentFrameInContext(buf-&gt;context(), destRect);
+    return buf-&gt;copyImage(backingStoreCopy);
+}
+
+void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
+                                       GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode&amp; ec)
+{
+    ec = 0;
+    if (isContextLostOrPending() || !validateHTMLVideoElement(&quot;texImage2D&quot;, video, ec)
+        || !validateTexFunc(&quot;texImage2D&quot;, TexImage, SourceHTMLVideoElement, target, level, internalformat, video-&gt;videoWidth(), video-&gt;videoHeight(), 0, format, type, 0, 0))
+        return;
+
+    // Go through the fast path doing a GPU-GPU textures copy without a readback to system memory if possible.
+    // Otherwise, it will fall back to the normal SW path.
+    // FIXME: The current restrictions require that format shoud be RGB or RGBA,
+    // type should be UNSIGNED_BYTE and level should be 0. It may be lifted in the future.
+    WebGLTexture* texture = validateTextureBinding(&quot;texImage2D&quot;, target, true);
+    if (GraphicsContext3D::TEXTURE_2D == target &amp;&amp; texture
+        &amp;&amp; (format == GraphicsContext3D::RGB || format == GraphicsContext3D::RGBA)
+        &amp;&amp; type == GraphicsContext3D::UNSIGNED_BYTE
+        &amp;&amp; (texture-&gt;getType(target, level) == GraphicsContext3D::UNSIGNED_BYTE || !texture-&gt;isValid(target, level))
+        &amp;&amp; !level) {
+        if (video-&gt;copyVideoTextureToPlatformTexture(m_context.get(), texture-&gt;object(), level, type, internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
+            texture-&gt;setLevelInfo(target, level, internalformat, video-&gt;videoWidth(), video-&gt;videoHeight(), type);
+            return;
+        }
+    }
+
+    // Normal pure SW path.
+    RefPtr&lt;Image&gt; image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode(), ec);
+    if (!image)
+        return;
+    texImage2DImpl(target, level, internalformat, format, type, image.get(), GraphicsContext3D::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
+}
+#endif
+
+void WebGLRenderingContextBase::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
+{
+    if (isContextLostOrPending())
+        return;
+    WebGLTexture* tex = validateTextureBinding(&quot;texParameter&quot;, target, false);
+    if (!tex)
+        return;
+    switch (pname) {
+    case GraphicsContext3D::TEXTURE_MIN_FILTER:
+    case GraphicsContext3D::TEXTURE_MAG_FILTER:
+        break;
+    case GraphicsContext3D::TEXTURE_WRAP_S:
+    case GraphicsContext3D::TEXTURE_WRAP_T:
+        if ((isFloat &amp;&amp; paramf != GraphicsContext3D::CLAMP_TO_EDGE &amp;&amp; paramf != GraphicsContext3D::MIRRORED_REPEAT &amp;&amp; paramf != GraphicsContext3D::REPEAT)
+            || (!isFloat &amp;&amp; parami != GraphicsContext3D::CLAMP_TO_EDGE &amp;&amp; parami != GraphicsContext3D::MIRRORED_REPEAT &amp;&amp; parami != GraphicsContext3D::REPEAT)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;texParameter&quot;, &quot;invalid parameter&quot;);
+            return;
+        }
+        break;
+    case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
+        if (!m_extTextureFilterAnisotropic) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;texParameter&quot;, &quot;invalid parameter, EXT_texture_filter_anisotropic not enabled&quot;);
+            return;
+        }
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;texParameter&quot;, &quot;invalid parameter name&quot;);
+        return;
+    }
+    if (isFloat) {
+        tex-&gt;setParameterf(pname, paramf);
+        m_context-&gt;texParameterf(target, pname, paramf);
+    } else {
+        tex-&gt;setParameteri(pname, parami);
+        m_context-&gt;texParameteri(target, pname, parami);
+    }
+}
+
+void WebGLRenderingContextBase::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
+{
+    texParameter(target, pname, param, 0, true);
+}
+
+void WebGLRenderingContextBase::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
+{
+    texParameter(target, pname, 0, param, false);
+}
+
+void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !location)
+        return;
+
+    if (location-&gt;program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;uniform1f&quot;, &quot;location not for current program&quot;);
+        return;
+    }
+
+    m_context-&gt;uniform1f(location-&gt;location(), x);
+}
+
+void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform1fv&quot;, location, v, 1))
+        return;
+
+    m_context-&gt;uniform1fv(location-&gt;location(), v-&gt;length(), v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform1fv&quot;, location, v, size, 1))
+        return;
+
+    m_context-&gt;uniform1fv(location-&gt;location(), size, v);
+}
+
+void WebGLRenderingContextBase::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !location)
+        return;
+
+    if (location-&gt;program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;uniform1i&quot;, &quot;location not for current program&quot;);
+        return;
+    }
+
+    if ((location-&gt;type() == GraphicsContext3D::SAMPLER_2D || location-&gt;type() == GraphicsContext3D::SAMPLER_CUBE) &amp;&amp; x &gt;= (int)m_textureUnits.size()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;uniform1i&quot;, &quot;invalid texture unit&quot;);
+        return;
+    }
+
+    m_context-&gt;uniform1i(location-&gt;location(), x);
+}
+
+void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform1iv&quot;, location, v, 1))
+        return;
+
+    if (location-&gt;type() == GraphicsContext3D::SAMPLER_2D || location-&gt;type() == GraphicsContext3D::SAMPLER_CUBE)
+        for (unsigned i = 0; i &lt; v-&gt;length(); ++i) {
+            if (v-&gt;data()[i] &gt;= static_cast&lt;int&gt;(m_textureUnits.size())) {
+                LOG(WebGL, &quot;Texture unit size=%zu, v[%d]=%d. Location type = %04X.&quot;, m_textureUnits.size(), i, v-&gt;data()[i], location-&gt;type());
+                synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;uniform1iv&quot;, &quot;invalid texture unit&quot;);
+                return;
+            }
+        }
+
+    m_context-&gt;uniform1iv(location-&gt;location(), v-&gt;length(), v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform1iv&quot;, location, v, size, 1))
+        return;
+
+    if (location-&gt;type() == GraphicsContext3D::SAMPLER_2D || location-&gt;type() == GraphicsContext3D::SAMPLER_CUBE)
+        for (unsigned i = 0; i &lt; static_cast&lt;unsigned&gt;(size); ++i) {
+            if (((GC3Dint*)v)[i] &gt;= static_cast&lt;int&gt;(m_textureUnits.size())) {
+                synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;uniform1iv&quot;, &quot;invalid texture unit&quot;);
+                return;
+            }
+        }
+
+    m_context-&gt;uniform1iv(location-&gt;location(), size, v);
+}
+
+void WebGLRenderingContextBase::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !location)
+        return;
+
+    if (location-&gt;program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;uniform2f&quot;, &quot;location not for current program&quot;);
+        return;
+    }
+
+    m_context-&gt;uniform2f(location-&gt;location(), x, y);
+}
+
+void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform2fv&quot;, location, v, 2))
+        return;
+
+    m_context-&gt;uniform2fv(location-&gt;location(), v-&gt;length() / 2, v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform2fv&quot;, location, v, size, 2))
+        return;
+
+    m_context-&gt;uniform2fv(location-&gt;location(), size / 2, v);
+}
+
+void WebGLRenderingContextBase::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !location)
+        return;
+
+    if (location-&gt;program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;uniform2i&quot;, &quot;location not for current program&quot;);
+        return;
+    }
+
+    m_context-&gt;uniform2i(location-&gt;location(), x, y);
+}
+
+void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform2iv&quot;, location, v, 2))
+        return;
+
+    m_context-&gt;uniform2iv(location-&gt;location(), v-&gt;length() / 2, v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform2iv&quot;, location, v, size, 2))
+        return;
+
+    m_context-&gt;uniform2iv(location-&gt;location(), size / 2, v);
+}
+
+void WebGLRenderingContextBase::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !location)
+        return;
+
+    if (location-&gt;program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;uniform3f&quot;, &quot;location not for current program&quot;);
+        return;
+    }
+
+    m_context-&gt;uniform3f(location-&gt;location(), x, y, z);
+}
+
+void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform3fv&quot;, location, v, 3))
+        return;
+
+    m_context-&gt;uniform3fv(location-&gt;location(), v-&gt;length() / 3, v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform3fv&quot;, location, v, size, 3))
+        return;
+
+    m_context-&gt;uniform3fv(location-&gt;location(), size / 3, v);
+}
+
+void WebGLRenderingContextBase::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !location)
+        return;
+
+    if (location-&gt;program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;uniform3i&quot;, &quot;location not for current program&quot;);
+        return;
+    }
+
+    m_context-&gt;uniform3i(location-&gt;location(), x, y, z);
+}
+
+void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform3iv&quot;, location, v, 3))
+        return;
+
+    m_context-&gt;uniform3iv(location-&gt;location(), v-&gt;length() / 3, v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform3iv&quot;, location, v, size, 3))
+        return;
+
+    m_context-&gt;uniform3iv(location-&gt;location(), size / 3, v);
+}
+
+void WebGLRenderingContextBase::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !location)
+        return;
+
+    if (location-&gt;program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;uniform4f&quot;, &quot;location not for current program&quot;);
+        return;
+    }
+
+    m_context-&gt;uniform4f(location-&gt;location(), x, y, z, w);
+}
+
+void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform4fv&quot;, location, v, 4))
+        return;
+
+    m_context-&gt;uniform4fv(location-&gt;location(), v-&gt;length() / 4, v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform4fv&quot;, location, v, size, 4))
+        return;
+
+    m_context-&gt;uniform4fv(location-&gt;location(), size / 4, v);
+}
+
+void WebGLRenderingContextBase::uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !location)
+        return;
+
+    if (location-&gt;program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;uniform4i&quot;, &quot;location not for current program&quot;);
+        return;
+    }
+
+    m_context-&gt;uniform4i(location-&gt;location(), x, y, z, w);
+}
+
+void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform4iv&quot;, location, v, 4))
+        return;
+
+    m_context-&gt;uniform4iv(location-&gt;location(), v-&gt;length() / 4, v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformParameters(&quot;uniform4iv&quot;, location, v, size, 4))
+        return;
+
+    m_context-&gt;uniform4iv(location-&gt;location(), size / 4, v);
+}
+
+void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformMatrixParameters(&quot;uniformMatrix2fv&quot;, location, transpose, v, 4))
+        return;
+    m_context-&gt;uniformMatrix2fv(location-&gt;location(), v-&gt;length() / 4, transpose, v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformMatrixParameters(&quot;uniformMatrix2fv&quot;, location, transpose, v, size, 4))
+        return;
+    m_context-&gt;uniformMatrix2fv(location-&gt;location(), size / 4, transpose, v);
+}
+
+void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformMatrixParameters(&quot;uniformMatrix3fv&quot;, location, transpose, v, 9))
+        return;
+    m_context-&gt;uniformMatrix3fv(location-&gt;location(), v-&gt;length() / 9, transpose, v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformMatrixParameters(&quot;uniformMatrix3fv&quot;, location, transpose, v, size, 9))
+        return;
+    m_context-&gt;uniformMatrix3fv(location-&gt;location(), size / 9, transpose, v);
+}
+
+void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformMatrixParameters(&quot;uniformMatrix4fv&quot;, location, transpose, v, 16))
+        return;
+    m_context-&gt;uniformMatrix4fv(location-&gt;location(), v-&gt;length() / 16, transpose, v-&gt;data());
+}
+
+void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateUniformMatrixParameters(&quot;uniformMatrix4fv&quot;, location, transpose, v, size, 16))
+        return;
+    m_context-&gt;uniformMatrix4fv(location-&gt;location(), size / 16, transpose, v);
+}
+
+void WebGLRenderingContextBase::useProgram(WebGLProgram* program, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    bool deleted;
+    if (!checkObjectToBeBound(&quot;useProgram&quot;, program, deleted))
+        return;
+    if (deleted)
+        program = 0;
+    if (program &amp;&amp; !program-&gt;getLinkStatus()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;useProgram&quot;, &quot;program not valid&quot;);
+        return;
+    }
+    if (m_currentProgram != program) {
+        if (m_currentProgram)
+            m_currentProgram-&gt;onDetached(graphicsContext3D());
+        m_currentProgram = program;
+        m_context-&gt;useProgram(objectOrZero(program));
+        if (program)
+            program-&gt;onAttached();
+    }
+}
+
+void WebGLRenderingContextBase::validateProgram(WebGLProgram* program, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending() || !validateWebGLObject(&quot;validateProgram&quot;, program))
+        return;
+    m_context-&gt;validateProgram(objectOrZero(program));
+}
+
+void WebGLRenderingContextBase::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
+{
+    vertexAttribfImpl(&quot;vertexAttrib1f&quot;, index, 1, v0, 0.0f, 0.0f, 1.0f);
+}
+
+void WebGLRenderingContextBase::vertexAttrib1fv(GC3Duint index, Float32Array* v)
+{
+    vertexAttribfvImpl(&quot;vertexAttrib1fv&quot;, index, v, 1);
+}
+
+void WebGLRenderingContextBase::vertexAttrib1fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
+{
+    vertexAttribfvImpl(&quot;vertexAttrib1fv&quot;, index, v, size, 1);
+}
+
+void WebGLRenderingContextBase::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
+{
+    vertexAttribfImpl(&quot;vertexAttrib2f&quot;, index, 2, v0, v1, 0.0f, 1.0f);
+}
+
+void WebGLRenderingContextBase::vertexAttrib2fv(GC3Duint index, Float32Array* v)
+{
+    vertexAttribfvImpl(&quot;vertexAttrib2fv&quot;, index, v, 2);
+}
+
+void WebGLRenderingContextBase::vertexAttrib2fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
+{
+    vertexAttribfvImpl(&quot;vertexAttrib2fv&quot;, index, v, size, 2);
+}
+
+void WebGLRenderingContextBase::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
+{
+    vertexAttribfImpl(&quot;vertexAttrib3f&quot;, index, 3, v0, v1, v2, 1.0f);
+}
+
+void WebGLRenderingContextBase::vertexAttrib3fv(GC3Duint index, Float32Array* v)
+{
+    vertexAttribfvImpl(&quot;vertexAttrib3fv&quot;, index, v, 3);
+}
+
+void WebGLRenderingContextBase::vertexAttrib3fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
+{
+    vertexAttribfvImpl(&quot;vertexAttrib3fv&quot;, index, v, size, 3);
+}
+
+void WebGLRenderingContextBase::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+    vertexAttribfImpl(&quot;vertexAttrib4f&quot;, index, 4, v0, v1, v2, v3);
+}
+
+void WebGLRenderingContextBase::vertexAttrib4fv(GC3Duint index, Float32Array* v)
+{
+    vertexAttribfvImpl(&quot;vertexAttrib4fv&quot;, index, v, 4);
+}
+
+void WebGLRenderingContextBase::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
+{
+    vertexAttribfvImpl(&quot;vertexAttrib4fv&quot;, index, v, size, 4);
+}
+
+void WebGLRenderingContextBase::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, long long offset, ExceptionCode&amp; ec)
+{
+    UNUSED_PARAM(ec);
+    if (isContextLostOrPending())
+        return;
+    switch (type) {
+    case GraphicsContext3D::BYTE:
+    case GraphicsContext3D::UNSIGNED_BYTE:
+    case GraphicsContext3D::SHORT:
+    case GraphicsContext3D::UNSIGNED_SHORT:
+    case GraphicsContext3D::FLOAT:
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;vertexAttribPointer&quot;, &quot;invalid type&quot;);
+        return;
+    }
+    if (index &gt;= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;vertexAttribPointer&quot;, &quot;index out of range&quot;);
+        return;
+    }
+    if (size &lt; 1 || size &gt; 4 || stride &lt; 0 || stride &gt; 255 || offset &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;vertexAttribPointer&quot;, &quot;bad size, stride or offset&quot;);
+        return;
+    }
+    if (!m_boundArrayBuffer) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;vertexAttribPointer&quot;, &quot;no bound ARRAY_BUFFER&quot;);
+        return;
+    }
+    // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
+    unsigned int typeSize = sizeInBytes(type);
+    if (!typeSize) {
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, &quot;vertexAttribPointer&quot;, &quot;invalid type&quot;);
+        return;
+    }
+    if ((stride % typeSize) || (static_cast&lt;GC3Dintptr&gt;(offset) % typeSize)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;vertexAttribPointer&quot;, &quot;stride or offset not valid for type&quot;);
+        return;
+    }
+    GC3Dsizei bytesPerElement = size * typeSize;
+
+    m_boundVertexArrayObject-&gt;setVertexAttribState(index, bytesPerElement, size, type, normalized, stride, static_cast&lt;GC3Dintptr&gt;(offset), m_boundArrayBuffer);
+    m_context-&gt;vertexAttribPointer(index, size, type, normalized, stride, static_cast&lt;GC3Dintptr&gt;(offset));
+}
+
+void WebGLRenderingContextBase::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+    if (isContextLostOrPending())
+        return;
+    if (!validateSize(&quot;viewport&quot;, width, height))
+        return;
+    m_context-&gt;viewport(x, y, width, height);
+}
+
+void WebGLRenderingContextBase::forceLostContext(WebGLRenderingContextBase::LostContextMode mode)
+{
+    if (isContextLostOrPending()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;loseContext&quot;, &quot;context already lost&quot;);
+        return;
+    }
+
+    m_contextGroup-&gt;loseContextGroup(mode);
+}
+
+void WebGLRenderingContextBase::loseContextImpl(WebGLRenderingContextBase::LostContextMode mode)
+{
+    if (isContextLost())
+        return;
+
+    m_contextLost = true;
+    m_contextLostMode = mode;
+
+    if (mode == RealLostContext) {
+        // Inform the embedder that a lost context was received. In response, the embedder might
+        // decide to take action such as asking the user for permission to use WebGL again.
+        if (Frame* frame = canvas()-&gt;document().frame())
+            frame-&gt;loader().client().didLoseWebGLContext(m_context-&gt;getExtensions()-&gt;getGraphicsResetStatusARB());
+    }
+
+    detachAndRemoveAllObjects();
+
+    // There is no direct way to clear errors from a GL implementation and
+    // looping until getError() becomes NO_ERROR might cause an infinite loop if
+    // the driver or context implementation had a bug. So, loop a reasonably
+    // large number of times to clear any existing errors.
+    for (int i = 0; i &lt; 100; ++i) {
+        if (m_context-&gt;getError() == GraphicsContext3D::NO_ERROR)
+            break;
+    }
+    ConsoleDisplayPreference display = (mode == RealLostContext) ? DisplayInConsole: DontDisplayInConsole;
+    synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL, &quot;loseContext&quot;, &quot;context lost&quot;, display);
+
+    // Don't allow restoration unless the context lost event has both been
+    // dispatched and its default behavior prevented.
+    m_restoreAllowed = false;
+
+    // Always defer the dispatch of the context lost event, to implement
+    // the spec behavior of queueing a task.
+    m_dispatchContextLostEventTimer.startOneShot(0);
+}
+
+void WebGLRenderingContextBase::forceRestoreContext()
+{
+    if (!isContextLostOrPending()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;restoreContext&quot;, &quot;context not lost&quot;);
+        return;
+    }
+
+    if (!m_restoreAllowed) {
+        if (m_contextLostMode == SyntheticLostContext)
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;restoreContext&quot;, &quot;context restoration not allowed&quot;);
+        return;
+    }
+
+    if (!m_restoreTimer.isActive())
+        m_restoreTimer.startOneShot(0);
+}
+
+PlatformLayer* WebGLRenderingContextBase::platformLayer() const
+{
+    return (!isContextLost() &amp;&amp; !m_isPendingPolicyResolution) ? m_context-&gt;platformLayer() : 0;
+}
+
+void WebGLRenderingContextBase::removeSharedObject(WebGLSharedObject* object)
+{
+    if (m_isPendingPolicyResolution)
+        return;
+
+    m_contextGroup-&gt;removeObject(object);
+}
+
+void WebGLRenderingContextBase::addSharedObject(WebGLSharedObject* object)
+{
+    if (m_isPendingPolicyResolution)
+        return;
+
+    ASSERT(!isContextLost());
+    m_contextGroup-&gt;addObject(object);
+}
+
+void WebGLRenderingContextBase::removeContextObject(WebGLContextObject* object)
+{
+    if (m_isPendingPolicyResolution)
+        return;
+
+    m_contextObjects.remove(object);
+}
+
+void WebGLRenderingContextBase::addContextObject(WebGLContextObject* object)
+{
+    if (m_isPendingPolicyResolution)
+        return;
+
+    ASSERT(!isContextLost());
+    m_contextObjects.add(object);
+}
+
+void WebGLRenderingContextBase::detachAndRemoveAllObjects()
+{
+    if (m_isPendingPolicyResolution)
+        return;
+
+    while (m_contextObjects.size() &gt; 0) {
+        HashSet&lt;WebGLContextObject*&gt;::iterator it = m_contextObjects.begin();
+        (*it)-&gt;detachContext();
+    }
+}
+
+bool WebGLRenderingContextBase::hasPendingActivity() const
+{
+    return false;
+}
+
+void WebGLRenderingContextBase::stop()
+{
+    if (!isContextLost() &amp;&amp; !m_isPendingPolicyResolution) {
+        forceLostContext(SyntheticLostContext);
+        destroyGraphicsContext3D();
+    }
+}
+
+const char* WebGLRenderingContextBase::activeDOMObjectName() const
+{
+    return &quot;WebGLRenderingContext&quot;;
+}
+
+bool WebGLRenderingContextBase::canSuspendForPageCache() const
+{
+    // FIXME: We should try and do better here.
+    return false;
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getBooleanParameter(GC3Denum pname)
+{
+    GC3Dboolean value = 0;
+    m_context-&gt;getBooleanv(pname, &amp;value);
+    return WebGLGetInfo(static_cast&lt;bool&gt;(value));
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getBooleanArrayParameter(GC3Denum pname)
+{
+    if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
+        notImplemented();
+        return WebGLGetInfo(0, 0);
+    }
+    GC3Dboolean value[4] = {0};
+    m_context-&gt;getBooleanv(pname, value);
+    bool boolValue[4];
+    for (int ii = 0; ii &lt; 4; ++ii)
+        boolValue[ii] = static_cast&lt;bool&gt;(value[ii]);
+    return WebGLGetInfo(boolValue, 4);
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getFloatParameter(GC3Denum pname)
+{
+    GC3Dfloat value = 0;
+    m_context-&gt;getFloatv(pname, &amp;value);
+    return WebGLGetInfo(value);
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getIntParameter(GC3Denum pname)
+{
+    GC3Dint value = 0;
+    m_context-&gt;getIntegerv(pname, &amp;value);
+    return WebGLGetInfo(value);
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getUnsignedIntParameter(GC3Denum pname)
+{
+    GC3Dint value = 0;
+    m_context-&gt;getIntegerv(pname, &amp;value);
+    return WebGLGetInfo(static_cast&lt;unsigned int&gt;(value));
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getInt64Parameter(GC3Denum pname)
+{
+    GC3Dint64 value = 0;
+    m_context-&gt;getInteger64v(pname, &amp;value);
+    return WebGLGetInfo(value);
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getWebGLFloatArrayParameter(GC3Denum pname)
+{
+    GC3Dfloat value[4] = {0};
+    m_context-&gt;getFloatv(pname, value);
+    unsigned length = 0;
+    switch (pname) {
+    case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
+    case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
+    case GraphicsContext3D::DEPTH_RANGE:
+        length = 2;
+        break;
+    case GraphicsContext3D::BLEND_COLOR:
+    case GraphicsContext3D::COLOR_CLEAR_VALUE:
+        length = 4;
+        break;
+    default:
+        notImplemented();
+    }
+    return WebGLGetInfo(Float32Array::create(value, length).release());
+}
+
+WebGLGetInfo WebGLRenderingContextBase::getWebGLIntArrayParameter(GC3Denum pname)
+{
+    GC3Dint value[4] = {0};
+    m_context-&gt;getIntegerv(pname, value);
+    unsigned length = 0;
+    switch (pname) {
+    case GraphicsContext3D::MAX_VIEWPORT_DIMS:
+        length = 2;
+        break;
+    case GraphicsContext3D::SCISSOR_BOX:
+    case GraphicsContext3D::VIEWPORT:
+        length = 4;
+        break;
+    default:
+        notImplemented();
+    }
+    return WebGLGetInfo(Int32Array::create(value, length).release());
+}
+
+void WebGLRenderingContextBase::checkTextureCompleteness(const char* functionName, bool prepareToDraw)
+{
+    bool resetActiveUnit = false;
+    WebGLTexture::TextureExtensionFlag extensions = static_cast&lt;WebGLTexture::TextureExtensionFlag&gt;((m_oesTextureFloatLinear ? WebGLTexture::TextureExtensionFloatLinearEnabled : 0) | (m_oesTextureHalfFloatLinear ? WebGLTexture::TextureExtensionHalfFloatLinearEnabled : 0));
+
+    for (unsigned ii = 0; ii &lt; m_textureUnits.size(); ++ii) {
+        if ((m_textureUnits[ii].texture2DBinding &amp;&amp; m_textureUnits[ii].texture2DBinding-&gt;needToUseBlackTexture(extensions))
+            || (m_textureUnits[ii].textureCubeMapBinding &amp;&amp; m_textureUnits[ii].textureCubeMapBinding-&gt;needToUseBlackTexture(extensions))) {
+            if (ii != m_activeTextureUnit) {
+                m_context-&gt;activeTexture(ii);
+                resetActiveUnit = true;
+            } else if (resetActiveUnit) {
+                m_context-&gt;activeTexture(ii);
+                resetActiveUnit = false;
+            }
+            WebGLTexture* tex2D;
+            WebGLTexture* texCubeMap;
+            if (prepareToDraw) {
+                String msg(String(&quot;texture bound to texture unit &quot;) + String::number(ii)
+                    + &quot; is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete',&quot;
+                    + &quot; or it is a float/half-float type with linear filtering and without the relevant float/half-float linear extension enabled.&quot;);
+                printGLWarningToConsole(functionName, msg.utf8().data());
+                tex2D = m_blackTexture2D.get();
+                texCubeMap = m_blackTextureCubeMap.get();
+            } else {
+                tex2D = m_textureUnits[ii].texture2DBinding.get();
+                texCubeMap = m_textureUnits[ii].textureCubeMapBinding.get();
+            }
+            if (m_textureUnits[ii].texture2DBinding &amp;&amp; m_textureUnits[ii].texture2DBinding-&gt;needToUseBlackTexture(extensions))
+                m_context-&gt;bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D));
+            if (m_textureUnits[ii].textureCubeMapBinding &amp;&amp; m_textureUnits[ii].textureCubeMapBinding-&gt;needToUseBlackTexture(extensions))
+                m_context-&gt;bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
+        }
+    }
+    if (resetActiveUnit)
+        m_context-&gt;activeTexture(m_activeTextureUnit);
+}
+
+void WebGLRenderingContextBase::createFallbackBlackTextures1x1()
+{
+    unsigned char black[] = {0, 0, 0, 255};
+    m_blackTexture2D = createTexture();
+    m_context-&gt;bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D-&gt;object());
+    m_context-&gt;texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context-&gt;bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
+    m_blackTextureCubeMap = createTexture();
+    m_context-&gt;bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap-&gt;object());
+    m_context-&gt;texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context-&gt;texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context-&gt;texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context-&gt;texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context-&gt;texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context-&gt;texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
+                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
+    m_context-&gt;bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0);
+}
+
+bool WebGLRenderingContextBase::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,
+                                                                           GC3Denum colorBufferFormat)
+{
+    unsigned need = GraphicsContext3D::getChannelBitsByFormat(texInternalFormat);
+    unsigned have = GraphicsContext3D::getChannelBitsByFormat(colorBufferFormat);
+    return (need &amp; have) == need;
+}
+
+GC3Denum WebGLRenderingContextBase::getBoundFramebufferColorFormat()
+{
+    if (m_framebufferBinding &amp;&amp; m_framebufferBinding-&gt;object())
+        return m_framebufferBinding-&gt;getColorBufferFormat();
+    if (m_attributes.alpha)
+        return GraphicsContext3D::RGBA;
+    return GraphicsContext3D::RGB;
+}
+
+int WebGLRenderingContextBase::getBoundFramebufferWidth()
+{
+    if (m_framebufferBinding &amp;&amp; m_framebufferBinding-&gt;object())
+        return m_framebufferBinding-&gt;getColorBufferWidth();
+    return m_context-&gt;getInternalFramebufferSize().width();
+}
+
+int WebGLRenderingContextBase::getBoundFramebufferHeight()
+{
+    if (m_framebufferBinding &amp;&amp; m_framebufferBinding-&gt;object())
+        return m_framebufferBinding-&gt;getColorBufferHeight();
+    return m_context-&gt;getInternalFramebufferSize().height();
+}
+
+WebGLTexture* WebGLRenderingContextBase::validateTextureBinding(const char* functionName, GC3Denum target, bool useSixEnumsForCubeMap)
+{
+    WebGLTexture* texture = nullptr;
+    switch (target) {
+    case GraphicsContext3D::TEXTURE_2D:
+        texture = m_textureUnits[m_activeTextureUnit].texture2DBinding.get();
+        break;
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        if (!useSixEnumsForCubeMap) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid texture target&quot;);
+            return nullptr;
+        }
+        texture = m_textureUnits[m_activeTextureUnit].textureCubeMapBinding.get();
+        break;
+    case GraphicsContext3D::TEXTURE_CUBE_MAP:
+        if (useSixEnumsForCubeMap) {
+            synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid texture target&quot;);
+            return nullptr;
+        }
+        texture = m_textureUnits[m_activeTextureUnit].textureCubeMapBinding.get();
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid texture target&quot;);
+        return nullptr;
+    }
+    if (!texture)
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;no texture&quot;);
+    return texture;
+}
+
+bool WebGLRenderingContextBase::validateLocationLength(const char* functionName, const String&amp; string)
+{
+    const unsigned maxWebGLLocationLength = 256;
+    if (string.length() &gt; maxWebGLLocationLength) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;location length &gt; 256&quot;);
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateSize(const char* functionName, GC3Dint x, GC3Dint y)
+{
+    if (x &lt; 0 || y &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;size &lt; 0&quot;);
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateString(const char* functionName, const String&amp; string)
+{
+    for (size_t i = 0; i &lt; string.length(); ++i) {
+        if (!validateCharacter(string[i])) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;string not ASCII&quot;);
+            return false;
+        }
+    }
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateTexFuncLevel(const char* functionName, GC3Denum target, GC3Dint level)
+{
+    if (level &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;level &lt; 0&quot;);
+        return false;
+    }
+    switch (target) {
+    case GraphicsContext3D::TEXTURE_2D:
+        if (level &gt;= m_maxTextureLevel) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;level out of range&quot;);
+            return false;
+        }
+        break;
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
+    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
+        if (level &gt;= m_maxCubeMapTextureLevel) {
+            synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;level out of range&quot;);
+            return false;
+        }
+        break;
+    }
+    // This function only checks if level is legal, so we return true and don't
+    // generate INVALID_ENUM if target is illegal.
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateCompressedTexFormat(GC3Denum format)
+{
+    return m_compressedTextureFormats.contains(format);
+}
+
+bool WebGLRenderingContextBase::validateCompressedTexFuncData(const char* functionName,
+                                                          GC3Dsizei width, GC3Dsizei height,
+                                                          GC3Denum format, ArrayBufferView* pixels)
+{
+    if (!pixels) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no pixels&quot;);
+        return false;
+    }
+    if (width &lt; 0 || height &lt; 0) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;width or height &lt; 0&quot;);
+        return false;
+    }
+
+    unsigned int bytesRequired = 0;
+
+    switch (format) {
+    case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_ATC_RGB_AMD:
+        {
+            const int kBlockSize = 8;
+            const int kBlockWidth = 4;
+            const int kBlockHeight = 4;
+            int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
+            int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
+            bytesRequired = numBlocksAcross * numBlocksDown * kBlockSize;
+        }
+        break;
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT:
+    case Extensions3D::COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
+    case Extensions3D::COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
+        {
+            const int kBlockSize = 16;
+            const int kBlockWidth = 4;
+            const int kBlockHeight = 4;
+            int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
+            int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
+            bytesRequired = numBlocksAcross * numBlocksDown * kBlockSize;
+        }
+        break;
+    case Extensions3D::COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
+        {
+            const int kBlockSize = 8;
+            const int kBlockWidth = 8;
+            const int kBlockHeight = 8;
+            bytesRequired = (std::max(width, kBlockWidth) * std::max(height, kBlockHeight) * 4 + 7) / kBlockSize;
+        }
+        break;
+    case Extensions3D::COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
+        {
+            const int kBlockSize = 8;
+            const int kBlockWidth = 16;
+            const int kBlockHeight = 8;
+            bytesRequired = (std::max(width, kBlockWidth) * std::max(height, kBlockHeight) * 2 + 7) / kBlockSize;
+        }
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid format&quot;);
+        return false;
+    }
+
+    if (pixels-&gt;byteLength() != bytesRequired) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;length of ArrayBufferView is not correct for dimensions&quot;);
+        return false;
+    }
+
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateCompressedTexDimensions(const char* functionName, GC3Denum target, GC3Dint level, GC3Dsizei width, GC3Dsizei height, GC3Denum format)
+{
+    switch (format) {
+    case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT: {
+        const GC3Dsizei kBlockWidth = 4;
+        const GC3Dsizei kBlockHeight = 4;
+        const GC3Dint maxTextureSize = target ? m_maxTextureSize : m_maxCubeMapTextureSize;
+        const GC3Dsizei maxCompressedDimension = maxTextureSize &gt;&gt; level;
+        bool widthValid = (level &amp;&amp; width == 1) || (level &amp;&amp; width == 2) || (!(width % kBlockWidth) &amp;&amp; width &lt;= maxCompressedDimension);
+        bool heightValid = (level &amp;&amp; height == 1) || (level &amp;&amp; height == 2) || (!(height % kBlockHeight) &amp;&amp; height &lt;= maxCompressedDimension);
+        if (!widthValid || !heightValid) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;width or height invalid for level&quot;);
+            return false;
+        }
+        return true;
+    }
+    case Extensions3D::COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
+        // Height and width must be powers of 2.
+        if ((width &amp; (width - 1)) || (height &amp; (height - 1))) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;width or height invalid for level&quot;);
+            return false;
+        }
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool WebGLRenderingContextBase::validateCompressedTexSubDimensions(const char* functionName, GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
+                                                               GC3Dsizei width, GC3Dsizei height, GC3Denum format, WebGLTexture* tex)
+{
+    if (xoffset &lt; 0 || yoffset &lt; 0) {
+      synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;xoffset or yoffset &lt; 0&quot;);
+      return false;
+    }
+
+    switch (format) {
+    case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT: {
+        const int kBlockWidth = 4;
+        const int kBlockHeight = 4;
+        if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;xoffset or yoffset not multiple of 4&quot;);
+            return false;
+        }
+        if (width - xoffset &gt; tex-&gt;getWidth(target, level)
+            || height - yoffset &gt; tex-&gt;getHeight(target, level)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;dimensions out of range&quot;);
+            return false;
+        }
+        return validateCompressedTexDimensions(functionName, target, level, width, height, format);
+    }
+    case Extensions3D::COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
+    case Extensions3D::COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
+        if (xoffset || yoffset) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;xoffset and yoffset must be zero&quot;);
+            return false;
+        }
+        if (width != tex-&gt;getWidth(target, level)
+            || height != tex-&gt;getHeight(target, level)) {
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;dimensions must match existing level&quot;);
+            return false;
+        }
+        return validateCompressedTexDimensions(functionName, target, level, width, height, format);
+    }
+    default:
+        return false;
+    }
+}
+
+bool WebGLRenderingContextBase::validateDrawMode(const char* functionName, GC3Denum mode)
+{
+    switch (mode) {
+    case GraphicsContext3D::POINTS:
+    case GraphicsContext3D::LINE_STRIP:
+    case GraphicsContext3D::LINE_LOOP:
+    case GraphicsContext3D::LINES:
+    case GraphicsContext3D::TRIANGLE_STRIP:
+    case GraphicsContext3D::TRIANGLE_FAN:
+    case GraphicsContext3D::TRIANGLES:
+        return true;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid draw mode&quot;);
+        return false;
+    }
+}
+
+bool WebGLRenderingContextBase::validateStencilSettings(const char* functionName)
+{
+    if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;front and back stencils settings do not match&quot;);
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateStencilFunc(const char* functionName, GC3Denum func)
+{
+    switch (func) {
+    case GraphicsContext3D::NEVER:
+    case GraphicsContext3D::LESS:
+    case GraphicsContext3D::LEQUAL:
+    case GraphicsContext3D::GREATER:
+    case GraphicsContext3D::GEQUAL:
+    case GraphicsContext3D::EQUAL:
+    case GraphicsContext3D::NOTEQUAL:
+    case GraphicsContext3D::ALWAYS:
+        return true;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid function&quot;);
+        return false;
+    }
+}
+
+void WebGLRenderingContextBase::printGLErrorToConsole(const String&amp; message)
+{
+    if (!m_numGLErrorsToConsoleAllowed)
+        return;
+
+    --m_numGLErrorsToConsoleAllowed;
+    printWarningToConsole(message);
+
+    if (!m_numGLErrorsToConsoleAllowed)
+        printWarningToConsole(&quot;WebGL: too many errors, no more errors will be reported to the console for this context.&quot;);
+}
+
+void WebGLRenderingContextBase::printWarningToConsole(const String&amp; message)
+{
+    if (!canvas())
+        return;
+    canvas()-&gt;document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Warning, message);
+}
+
+bool WebGLRenderingContextBase::validateBlendFuncFactors(const char* functionName, GC3Denum src, GC3Denum dst)
+{
+    if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
+         &amp;&amp; (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))
+        || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
+            &amp;&amp; (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;incompatible src and dst&quot;);
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Float32Array* v, GC3Dsizei requiredMinSize)
+{
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no array&quot;);
+        return false;
+    }
+    return validateUniformMatrixParameters(functionName, location, false, v-&gt;data(), v-&gt;length(), requiredMinSize);
+}
+
+bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Int32Array* v, GC3Dsizei requiredMinSize)
+{
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no array&quot;);
+        return false;
+    }
+    return validateUniformMatrixParameters(functionName, location, false, v-&gt;data(), v-&gt;length(), requiredMinSize);
+}
+
+bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
+{
+    return validateUniformMatrixParameters(functionName, location, false, v, size, requiredMinSize);
+}
+
+bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, GC3Dsizei requiredMinSize)
+{
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no array&quot;);
+        return false;
+    }
+    return validateUniformMatrixParameters(functionName, location, transpose, v-&gt;data(), v-&gt;length(), requiredMinSize);
+}
+
+bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GC3Dboolean transpose, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
+{
+    if (!location)
+        return false;
+    if (location-&gt;program() != m_currentProgram) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;location is not from current program&quot;);
+        return false;
+    }
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no array&quot;);
+        return false;
+    }
+    if (transpose) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;transpose not FALSE&quot;);
+        return false;
+    }
+    if (size &lt; requiredMinSize || (size % requiredMinSize)) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;invalid size&quot;);
+        return false;
+    }
+    return true;
+}
+
+WebGLBuffer* WebGLRenderingContextBase::validateBufferDataParameters(const char* functionName, GC3Denum target, GC3Denum usage)
+{
+    WebGLBuffer* buffer = 0;
+    switch (target) {
+    case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
+        buffer = m_boundVertexArrayObject-&gt;getElementArrayBuffer().get();
+        break;
+    case GraphicsContext3D::ARRAY_BUFFER:
+        buffer = m_boundArrayBuffer.get();
+        break;
+    default:
+        synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid target&quot;);
+        return nullptr;
+    }
+    if (!buffer) {
+        synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, &quot;no buffer&quot;);
+        return nullptr;
+    }
+    switch (usage) {
+    case GraphicsContext3D::STREAM_DRAW:
+    case GraphicsContext3D::STATIC_DRAW:
+    case GraphicsContext3D::DYNAMIC_DRAW:
+        return buffer;
+    }
+    synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, &quot;invalid usage&quot;);
+    return nullptr;
+}
+
+bool WebGLRenderingContextBase::validateHTMLImageElement(const char* functionName, HTMLImageElement* image, ExceptionCode&amp; ec)
+{
+    if (!image || !image-&gt;cachedImage()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no image&quot;);
+        return false;
+    }
+    const URL&amp; url = image-&gt;cachedImage()-&gt;response().url();
+    if (url.isNull() || url.isEmpty() || !url.isValid()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;invalid image&quot;);
+        return false;
+    }
+    if (wouldTaintOrigin(image)) {
+        ec = SECURITY_ERR;
+        return false;
+    }
+    return true;
+}
+
+bool WebGLRenderingContextBase::validateHTMLCanvasElement(const char* functionName, HTMLCanvasElement* canvas, ExceptionCode&amp; ec)
+{
+    if (!canvas || !canvas-&gt;buffer()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no canvas&quot;);
+        return false;
+    }
+    if (wouldTaintOrigin(canvas)) {
+        ec = SECURITY_ERR;
+        return false;
+    }
+    return true;
+}
+
+#if ENABLE(VIDEO)
+bool WebGLRenderingContextBase::validateHTMLVideoElement(const char* functionName, HTMLVideoElement* video, ExceptionCode&amp; ec)
+{
+    if (!video || !video-&gt;videoWidth() || !video-&gt;videoHeight()) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no video&quot;);
+        return false;
+    }
+    if (wouldTaintOrigin(video)) {
+        ec = SECURITY_ERR;
+        return false;
+    }
+    return true;
+}
+#endif
+
+void WebGLRenderingContextBase::vertexAttribfImpl(const char* functionName, GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+    if (isContextLostOrPending())
+        return;
+    if (index &gt;= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;index out of range&quot;);
+        return;
+    }
+    // In GL, we skip setting vertexAttrib0 values.
+    if (index || isGLES2Compliant()) {
+        switch (expectedSize) {
+        case 1:
+            m_context-&gt;vertexAttrib1f(index, v0);
+            break;
+        case 2:
+            m_context-&gt;vertexAttrib2f(index, v0, v1);
+            break;
+        case 3:
+            m_context-&gt;vertexAttrib3f(index, v0, v1, v2);
+            break;
+        case 4:
+            m_context-&gt;vertexAttrib4f(index, v0, v1, v2, v3);
+            break;
+        }
+    }
+    VertexAttribValue&amp; attribValue = m_vertexAttribValue[index];
+    attribValue.value[0] = v0;
+    attribValue.value[1] = v1;
+    attribValue.value[2] = v2;
+    attribValue.value[3] = v3;
+}
+
+void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GC3Duint index, Float32Array* v, GC3Dsizei expectedSize)
+{
+    if (isContextLostOrPending())
+        return;
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no array&quot;);
+        return;
+    }
+    vertexAttribfvImpl(functionName, index, v-&gt;data(), v-&gt;length(), expectedSize);
+}
+
+void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GC3Duint index, GC3Dfloat* v, GC3Dsizei size, GC3Dsizei expectedSize)
+{
+    if (isContextLostOrPending())
+        return;
+    if (!v) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;no array&quot;);
+        return;
+    }
+    if (size &lt; expectedSize) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;invalid size&quot;);
+        return;
+    }
+    if (index &gt;= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, &quot;index out of range&quot;);
+        return;
+    }
+    // In GL, we skip setting vertexAttrib0 values.
+    if (index || isGLES2Compliant()) {
+        switch (expectedSize) {
+        case 1:
+            m_context-&gt;vertexAttrib1fv(index, v);
+            break;
+        case 2:
+            m_context-&gt;vertexAttrib2fv(index, v);
+            break;
+        case 3:
+            m_context-&gt;vertexAttrib3fv(index, v);
+            break;
+        case 4:
+            m_context-&gt;vertexAttrib4fv(index, v);
+            break;
+        }
+    }
+    VertexAttribValue&amp; attribValue = m_vertexAttribValue[index];
+    attribValue.initValue();
+    for (int ii = 0; ii &lt; expectedSize; ++ii)
+        attribValue.value[ii] = v[ii];
+}
+
+void WebGLRenderingContextBase::initVertexAttrib0()
+{
+    WebGLVertexArrayObjectBase::VertexAttribState&amp; state = m_boundVertexArrayObject-&gt;getVertexAttribState(0);
+    
+    m_vertexAttrib0Buffer = createBuffer();
+    m_context-&gt;bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer-&gt;object());
+    m_context-&gt;bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW);
+    m_context-&gt;vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
+    state.bufferBinding = m_vertexAttrib0Buffer;
+    m_context-&gt;bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
+    m_context-&gt;enableVertexAttribArray(0);
+    m_vertexAttrib0BufferSize = 0;
+    m_vertexAttrib0BufferValue[0] = 0.0f;
+    m_vertexAttrib0BufferValue[1] = 0.0f;
+    m_vertexAttrib0BufferValue[2] = 0.0f;
+    m_vertexAttrib0BufferValue[3] = 1.0f;
+    m_forceAttrib0BufferRefill = false;
+    m_vertexAttrib0UsedBefore = false;
+}
+
+bool WebGLRenderingContextBase::simulateVertexAttrib0(GC3Dsizei numVertex)
+{
+    const WebGLVertexArrayObjectBase::VertexAttribState&amp; state = m_boundVertexArrayObject-&gt;getVertexAttribState(0);
+    const VertexAttribValue&amp; attribValue = m_vertexAttribValue[0];
+    if (!m_currentProgram)
+        return false;
+    bool usingVertexAttrib0 = m_currentProgram-&gt;isUsingVertexAttrib0();
+    if (usingVertexAttrib0)
+        m_vertexAttrib0UsedBefore = true;
+    if (state.enabled &amp;&amp; usingVertexAttrib0)
+        return false;
+    if (!usingVertexAttrib0 &amp;&amp; !m_vertexAttrib0UsedBefore)
+        return false;
+    m_vertexAttrib0UsedBefore = true;
+    m_context-&gt;bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer-&gt;object());
+    Checked&lt;GC3Dsizeiptr, RecordOverflow&gt; bufferDataSize = (numVertex + 1) * 4 * sizeof(GC3Dfloat);
+    if (bufferDataSize.hasOverflowed())
+        return false;
+    if (bufferDataSize.unsafeGet() &gt; m_vertexAttrib0BufferSize) {
+        m_context-&gt;bufferData(GraphicsContext3D::ARRAY_BUFFER, bufferDataSize.unsafeGet(), 0, GraphicsContext3D::DYNAMIC_DRAW);
+        m_vertexAttrib0BufferSize = bufferDataSize.unsafeGet();
+        m_forceAttrib0BufferRefill = true;
+    }
+    if (usingVertexAttrib0
+        &amp;&amp; (m_forceAttrib0BufferRefill
+            || attribValue.value[0] != m_vertexAttrib0BufferValue[0]
+            || attribValue.value[1] != m_vertexAttrib0BufferValue[1]
+            || attribValue.value[2] != m_vertexAttrib0BufferValue[2]
+            || attribValue.value[3] != m_vertexAttrib0BufferValue[3])) {
+        auto bufferData = std::make_unique&lt;GC3Dfloat[]&gt;((numVertex + 1) * 4);
+        for (GC3Dsizei ii = 0; ii &lt; numVertex + 1; ++ii) {
+            bufferData[ii * 4] = attribValue.value[0];
+            bufferData[ii * 4 + 1] = attribValue.value[1];
+            bufferData[ii * 4 + 2] = attribValue.value[2];
+            bufferData[ii * 4 + 3] = attribValue.value[3];
+        }
+        m_vertexAttrib0BufferValue[0] = attribValue.value[0];
+        m_vertexAttrib0BufferValue[1] = attribValue.value[1];
+        m_vertexAttrib0BufferValue[2] = attribValue.value[2];
+        m_vertexAttrib0BufferValue[3] = attribValue.value[3];
+        m_forceAttrib0BufferRefill = false;
+        m_context-&gt;bufferSubData(GraphicsContext3D::ARRAY_BUFFER, 0, bufferDataSize.unsafeGet(), bufferData.get());
+    }
+    m_context-&gt;vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, 0, 0, 0);
+    return true;
+}
+
+void WebGLRenderingContextBase::restoreStatesAfterVertexAttrib0Simulation()
+{
+    const WebGLVertexArrayObjectBase::VertexAttribState&amp; state = m_boundVertexArrayObject-&gt;getVertexAttribState(0);
+    if (state.bufferBinding != m_vertexAttrib0Buffer) {
+        m_context-&gt;bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(state.bufferBinding.get()));
+        m_context-&gt;vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset);
+    }
+    m_context-&gt;bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(m_boundArrayBuffer.get()));
+}
+
+void WebGLRenderingContextBase::dispatchContextLostEvent()
+{
+    RefPtr&lt;WebGLContextEvent&gt; event = WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, &quot;&quot;);
+    canvas()-&gt;dispatchEvent(event);
+    m_restoreAllowed = event-&gt;defaultPrevented();
+    if (m_contextLostMode == RealLostContext &amp;&amp; m_restoreAllowed)
+        m_restoreTimer.startOneShot(0);
+}
+
+void WebGLRenderingContextBase::maybeRestoreContext()
+{
+    ASSERT(m_contextLost);
+    if (!m_contextLost)
+        return;
+
+    // The rendering context is not restored unless the default behavior of the
+    // webglcontextlost event was prevented earlier.
+    //
+    // Because of the way m_restoreTimer is set up for real vs. synthetic lost
+    // context events, we don't have to worry about this test short-circuiting
+    // the retry loop for real context lost events.
+    if (!m_restoreAllowed)
+        return;
+
+    int contextLostReason = m_context-&gt;getExtensions()-&gt;getGraphicsResetStatusARB();
+
+    switch (contextLostReason) {
+    case GraphicsContext3D::NO_ERROR:
+        // The GraphicsContext3D implementation might not fully
+        // support GL_ARB_robustness semantics yet. Alternatively, the
+        // WEBGL_lose_context extension might have been used to force
+        // a lost context.
+        break;
+    case Extensions3D::GUILTY_CONTEXT_RESET_ARB:
+        // The rendering context is not restored if this context was
+        // guilty of causing the graphics reset.
+        printWarningToConsole(&quot;WARNING: WebGL content on the page caused the graphics card to reset; not restoring the context&quot;);
+        return;
+    case Extensions3D::INNOCENT_CONTEXT_RESET_ARB:
+        // Always allow the context to be restored.
+        break;
+    case Extensions3D::UNKNOWN_CONTEXT_RESET_ARB:
+        // Warn. Ideally, prompt the user telling them that WebGL
+        // content on the page might have caused the graphics card to
+        // reset and ask them whether they want to continue running
+        // the content. Only if they say &quot;yes&quot; should we start
+        // attempting to restore the context.
+        printWarningToConsole(&quot;WARNING: WebGL content on the page might have caused the graphics card to reset&quot;);
+        break;
+    }
+
+    Frame* frame = canvas()-&gt;document().frame();
+    if (!frame)
+        return;
+
+    if (!frame-&gt;loader().client().allowWebGL(frame-&gt;settings().webGLEnabled()))
+        return;
+
+    FrameView* view = frame-&gt;view();
+    if (!view)
+        return;
+    ScrollView* root = view-&gt;root();
+    if (!root)
+        return;
+    HostWindow* hostWindow = root-&gt;hostWindow();
+    if (!hostWindow)
+        return;
+
+    RefPtr&lt;GraphicsContext3D&gt; context(GraphicsContext3D::create(m_attributes, hostWindow));
+    if (!context) {
+        if (m_contextLostMode == RealLostContext)
+            m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
+        else
+            // This likely shouldn't happen but is the best way to report it to the WebGL app.
+            synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, &quot;&quot;, &quot;error restoring context&quot;);
+        return;
+    }
+
+    m_context = context;
+    m_contextLost = false;
+    setupFlags();
+    initializeNewContext();
+    initializeVertexArrayObjects();
+    canvas()-&gt;dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, &quot;&quot;));
+}
+
+String WebGLRenderingContextBase::ensureNotNull(const String&amp; text) const
+{
+    if (text.isNull())
+        return WTF::emptyString();
+    return text;
+}
+
+WebGLRenderingContextBase::LRUImageBufferCache::LRUImageBufferCache(int capacity)
+    : m_buffers(std::make_unique&lt;std::unique_ptr&lt;ImageBuffer&gt;[]&gt;(capacity))
+    , m_capacity(capacity)
+{
+}
+
+ImageBuffer* WebGLRenderingContextBase::LRUImageBufferCache::imageBuffer(const IntSize&amp; size)
+{
+    int i;
+    for (i = 0; i &lt; m_capacity; ++i) {
+        ImageBuffer* buf = m_buffers[i].get();
+        if (!buf)
+            break;
+        if (buf-&gt;logicalSize() != size)
+            continue;
+        bubbleToFront(i);
+        return buf;
+    }
+
+    std::unique_ptr&lt;ImageBuffer&gt; temp = ImageBuffer::create(size, 1);
+    if (!temp)
+        return nullptr;
+    i = std::min(m_capacity - 1, i);
+    m_buffers[i] = WTF::move(temp);
+
+    ImageBuffer* buf = m_buffers[i].get();
+    bubbleToFront(i);
+    return buf;
+}
+
+void WebGLRenderingContextBase::LRUImageBufferCache::bubbleToFront(int idx)
+{
+    for (int i = idx; i &gt; 0; --i)
+        m_buffers[i].swap(m_buffers[i-1]);
+}
+
+namespace {
+
+    String GetErrorString(GC3Denum error)
+    {
+        switch (error) {
+        case GraphicsContext3D::INVALID_ENUM:
+            return &quot;INVALID_ENUM&quot;;
+        case GraphicsContext3D::INVALID_VALUE:
+            return &quot;INVALID_VALUE&quot;;
+        case GraphicsContext3D::INVALID_OPERATION:
+            return &quot;INVALID_OPERATION&quot;;
+        case GraphicsContext3D::OUT_OF_MEMORY:
+            return &quot;OUT_OF_MEMORY&quot;;
+        case GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION:
+            return &quot;INVALID_FRAMEBUFFER_OPERATION&quot;;
+        case GraphicsContext3D::CONTEXT_LOST_WEBGL:
+            return &quot;CONTEXT_LOST_WEBGL&quot;;
+        default:
+            return String::format(&quot;WebGL ERROR(%04x)&quot;, error);
+        }
+    }
+
+} // namespace anonymous
+
+void WebGLRenderingContextBase::synthesizeGLError(GC3Denum error, const char* functionName, const char* description, ConsoleDisplayPreference display)
+{
+    if (m_synthesizedErrorsToConsole &amp;&amp; display == DisplayInConsole) {
+      String str = String(&quot;WebGL: &quot;) + GetErrorString(error) +  &quot;: &quot; + String(functionName) + &quot;: &quot; + String(description);
+      printGLErrorToConsole(str);
+    }
+    m_context-&gt;synthesizeGLError(error);
+}
+
+
+void WebGLRenderingContextBase::printGLWarningToConsole(const char* functionName, const char* description)
+{
+    if (m_synthesizedErrorsToConsole) {
+        String str = String(&quot;WebGL: &quot;) + String(functionName) + &quot;: &quot; + String(description);
+        printGLErrorToConsole(str);
+    }
+}
+
+void WebGLRenderingContextBase::applyStencilTest()
+{
+    bool haveStencilBuffer = false;
+
+    if (m_framebufferBinding)
+        haveStencilBuffer = m_framebufferBinding-&gt;hasStencilBuffer();
+    else {
+        RefPtr&lt;WebGLContextAttributes&gt; attributes = getContextAttributes();
+        haveStencilBuffer = attributes-&gt;stencil();
+    }
+    enableOrDisable(GraphicsContext3D::STENCIL_TEST,
+                    m_stencilEnabled &amp;&amp; haveStencilBuffer);
+}
+
+void WebGLRenderingContextBase::enableOrDisable(GC3Denum capability, bool enable)
+{
+    if (enable)
+        m_context-&gt;enable(capability);
+    else
+        m_context-&gt;disable(capability);
+}
+
+IntSize WebGLRenderingContextBase::clampedCanvasSize()
+{
+    return IntSize(clamp(canvas()-&gt;width(), 1, m_maxViewportDims[0]),
+                   clamp(canvas()-&gt;height(), 1, m_maxViewportDims[1]));
+}
+
+GC3Dint WebGLRenderingContextBase::getMaxDrawBuffers()
+{
+    if (!supportsDrawBuffers())
+        return 0;
+    if (!m_maxDrawBuffers)
+        m_context-&gt;getIntegerv(Extensions3D::MAX_DRAW_BUFFERS_EXT, &amp;m_maxDrawBuffers);
+    if (!m_maxColorAttachments)
+        m_context-&gt;getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &amp;m_maxColorAttachments);
+    // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS &gt;= MAX_DRAW_BUFFERS.
+    return std::min(m_maxDrawBuffers, m_maxColorAttachments);
+}
+
+GC3Dint WebGLRenderingContextBase::getMaxColorAttachments()
+{
+    if (!supportsDrawBuffers())
+        return 0;
+    if (!m_maxColorAttachments)
+        m_context-&gt;getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &amp;m_maxColorAttachments);
+    return m_maxColorAttachments;
+}
+
+void WebGLRenderingContextBase::setBackDrawBuffer(GC3Denum buf)
+{
+    m_backDrawBuffer = buf;
+}
+
+void WebGLRenderingContextBase::restoreCurrentFramebuffer()
+{
+    ExceptionCode ec;
+    bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_framebufferBinding.get(), ec);
+}
+
+void WebGLRenderingContextBase::restoreCurrentTexture2D()
+{
+    ExceptionCode ec;
+    bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureUnits[m_activeTextureUnit].texture2DBinding.get(), ec);
+}
+
+bool WebGLRenderingContextBase::supportsDrawBuffers()
+{
+    if (!m_drawBuffersWebGLRequirementsChecked) {
+        m_drawBuffersWebGLRequirementsChecked = true;
+        m_drawBuffersSupported = WebGLDrawBuffers::supported(this);
+    }
+    return m_drawBuffersSupported;
+}
+
+void WebGLRenderingContextBase::drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
+{
+    if (!primcount) {
+        markContextChanged();
+        return;
+    }
+
+    if (!validateDrawArrays(&quot;drawArraysInstanced&quot;, mode, first, count, primcount))
+        return;
+
+    clearIfComposited();
+
+    bool vertexAttrib0Simulated = false;
+    if (!isGLES2Compliant())
+        vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness(&quot;drawArraysInstanced&quot;, true);
+
+    m_context-&gt;drawArraysInstanced(mode, first, count, primcount);
+
+    if (!isGLES2Compliant() &amp;&amp; vertexAttrib0Simulated)
+        restoreStatesAfterVertexAttrib0Simulation();
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness(&quot;drawArraysInstanced&quot;, false);
+    markContextChanged();
+}
+
+void WebGLRenderingContextBase::drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, GC3Dsizei primcount)
+{
+    if (!primcount) {
+        markContextChanged();
+        return;
+    }
+
+    unsigned numElements = 0;
+    if (!validateDrawElements(&quot;drawElementsInstanced&quot;, mode, count, type, offset, numElements, primcount))
+        return;
+
+    clearIfComposited();
+
+    bool vertexAttrib0Simulated = false;
+    if (!isGLES2Compliant()) {
+        if (!numElements)
+            validateIndexArrayPrecise(count, type, static_cast&lt;GC3Dintptr&gt;(offset), numElements);
+        vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
+    }
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness(&quot;drawElementsInstanced&quot;, true);
+
+    m_context-&gt;drawElementsInstanced(mode, count, type, static_cast&lt;GC3Dintptr&gt;(offset), primcount);
+
+    if (!isGLES2Compliant() &amp;&amp; vertexAttrib0Simulated)
+        restoreStatesAfterVertexAttrib0Simulation();
+    if (!isGLES2NPOTStrict())
+        checkTextureCompleteness(&quot;drawElementsInstanced&quot;, false);
+    markContextChanged();
+}
+
+void WebGLRenderingContextBase::vertexAttribDivisor(GC3Duint index, GC3Duint divisor)
+{
+    if (isContextLostOrPending())
+        return;
+
+    if (index &gt;= m_maxVertexAttribs) {
+        synthesizeGLError(GraphicsContext3D::INVALID_VALUE, &quot;vertexAttribDivisor&quot;, &quot;index out of range&quot;);
+        return;
+    }
+
+    m_boundVertexArrayObject-&gt;setVertexAttribDivisor(index, divisor);
+    m_context-&gt;vertexAttribDivisor(index, divisor);
+}
+
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGL)
</ins></span></pre>
</div>
</div>

</body>
</html>