192c7db9704cdef5e1b3e46e3a305aa9c6a1407f
[WebKit-https.git] / Source / WebCore / html / canvas / WebGLRenderingContextBase.cpp
1 /*
2  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "WebGLRenderingContextBase.h"
28
29 #if ENABLE(WEBGL)
30
31 #include "ANGLEInstancedArrays.h"
32 #include "CachedImage.h"
33 #include "DOMWindow.h"
34 #include "DiagnosticLoggingClient.h"
35 #include "DiagnosticLoggingKeys.h"
36 #include "Document.h"
37 #include "EXTBlendMinMax.h"
38 #include "EXTFragDepth.h"
39 #include "EXTShaderTextureLOD.h"
40 #include "EXTTextureFilterAnisotropic.h"
41 #include "EXTsRGB.h"
42 #include "EventNames.h"
43 #include "ExceptionCode.h"
44 #include "Extensions3D.h"
45 #include "Frame.h"
46 #include "FrameLoader.h"
47 #include "FrameLoaderClient.h"
48 #include "FrameView.h"
49 #include "GraphicsContext.h"
50 #include "HTMLCanvasElement.h"
51 #include "HTMLImageElement.h"
52 #include "HTMLVideoElement.h"
53 #include "ImageBuffer.h"
54 #include "ImageData.h"
55 #include "IntSize.h"
56 #include "Logging.h"
57 #include "MainFrame.h"
58 #include "NotImplemented.h"
59 #include "OESElementIndexUint.h"
60 #include "OESStandardDerivatives.h"
61 #include "OESTextureFloat.h"
62 #include "OESTextureFloatLinear.h"
63 #include "OESTextureHalfFloat.h"
64 #include "OESTextureHalfFloatLinear.h"
65 #include "OESVertexArrayObject.h"
66 #include "Page.h"
67 #include "RenderBox.h"
68 #include "RuntimeEnabledFeatures.h"
69 #include "Settings.h"
70 #include "WebGL2RenderingContext.h"
71 #include "WebGLActiveInfo.h"
72 #include "WebGLBuffer.h"
73 #include "WebGLCompressedTextureATC.h"
74 #include "WebGLCompressedTexturePVRTC.h"
75 #include "WebGLCompressedTextureS3TC.h"
76 #include "WebGLContextAttributes.h"
77 #include "WebGLContextEvent.h"
78 #include "WebGLContextGroup.h"
79 #include "WebGLDebugRendererInfo.h"
80 #include "WebGLDebugShaders.h"
81 #include "WebGLDepthTexture.h"
82 #include "WebGLDrawBuffers.h"
83 #include "WebGLFramebuffer.h"
84 #include "WebGLLoseContext.h"
85 #include "WebGLProgram.h"
86 #include "WebGLRenderbuffer.h"
87 #include "WebGLRenderingContext.h"
88 #include "WebGLShader.h"
89 #include "WebGLShaderPrecisionFormat.h"
90 #include "WebGLTexture.h"
91 #include "WebGLUniformLocation.h"
92
93 #include <runtime/JSCInlines.h>
94 #include <runtime/TypedArrayInlines.h>
95 #include <runtime/Uint32Array.h>
96 #include <wtf/CheckedArithmetic.h>
97 #include <wtf/StdLibExtras.h>
98 #include <wtf/text/CString.h>
99 #include <wtf/text/StringBuilder.h>
100
101 namespace WebCore {
102
103 const double secondsBetweenRestoreAttempts = 1.0;
104 const int maxGLErrorsAllowedToConsole = 256;
105 static const std::chrono::seconds checkContextLossHandlingDelay { 3 };
106
107 namespace {
108     
109     Platform3DObject objectOrZero(WebGLObject* object)
110     {
111         return object ? object->object() : 0;
112     }
113
114     GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
115     {
116         if (value < min)
117             value = min;
118         if (value > max)
119             value = max;
120         return value;
121     }
122
123     // Return true if a character belongs to the ASCII subset as defined in
124     // GLSL ES 1.0 spec section 3.1.
125     bool validateCharacter(unsigned char c)
126     {
127         // Printing characters are valid except " $ ` @ \ ' DEL.
128         if (c >= 32 && c <= 126
129             && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
130             return true;
131         // Horizontal tab, line feed, vertical tab, form feed, carriage return
132         // are also valid.
133         if (c >= 9 && c <= 13)
134             return true;
135         return false;
136     }
137
138     bool isPrefixReserved(const String& name)
139     {
140         if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_"))
141             return true;
142         return false;
143     }
144
145     // Strips comments from shader text. This allows non-ASCII characters
146     // to be used in comments without potentially breaking OpenGL
147     // implementations not expecting characters outside the GLSL ES set.
148     class StripComments {
149     public:
150         StripComments(const String& str)
151             : m_parseState(BeginningOfLine)
152             , m_sourceString(str)
153             , m_length(str.length())
154             , m_position(0)
155         {
156             parse();
157         }
158
159         String result()
160         {
161             return m_builder.toString();
162         }
163
164     private:
165         bool hasMoreCharacters() const
166         {
167             return (m_position < m_length);
168         }
169
170         void parse()
171         {
172             while (hasMoreCharacters()) {
173                 process(current());
174                 // process() might advance the position.
175                 if (hasMoreCharacters())
176                     advance();
177             }
178         }
179
180         void process(UChar);
181
182         bool peek(UChar& character) const
183         {
184             if (m_position + 1 >= m_length)
185                 return false;
186             character = m_sourceString[m_position + 1];
187             return true;
188         }
189
190         UChar current() const
191         {
192             ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length);
193             return m_sourceString[m_position];
194         }
195
196         void advance()
197         {
198             ++m_position;
199         }
200
201         bool isNewline(UChar character) const
202         {
203             // Don't attempt to canonicalize newline related characters.
204             return (character == '\n' || character == '\r');
205         }
206
207         void emit(UChar character)
208         {
209             m_builder.append(character);
210         }
211
212         enum ParseState {
213             // Have not seen an ASCII non-whitespace character yet on
214             // this line. Possible that we might see a preprocessor
215             // directive.
216             BeginningOfLine,
217
218             // Have seen at least one ASCII non-whitespace character
219             // on this line.
220             MiddleOfLine,
221
222             // Handling a preprocessor directive. Passes through all
223             // characters up to the end of the line. Disables comment
224             // processing.
225             InPreprocessorDirective,
226
227             // Handling a single-line comment. The comment text is
228             // replaced with a single space.
229             InSingleLineComment,
230
231             // Handling a multi-line comment. Newlines are passed
232             // through to preserve line numbers.
233             InMultiLineComment
234         };
235
236         ParseState m_parseState;
237         String m_sourceString;
238         unsigned m_length;
239         unsigned m_position;
240         StringBuilder m_builder;
241     };
242
243     void StripComments::process(UChar c)
244     {
245         if (isNewline(c)) {
246             // No matter what state we are in, pass through newlines
247             // so we preserve line numbers.
248             emit(c);
249
250             if (m_parseState != InMultiLineComment)
251                 m_parseState = BeginningOfLine;
252
253             return;
254         }
255
256         UChar temp = 0;
257         switch (m_parseState) {
258         case BeginningOfLine:
259             if (WTF::isASCIISpace(c)) {
260                 emit(c);
261                 break;
262             }
263
264             if (c == '#') {
265                 m_parseState = InPreprocessorDirective;
266                 emit(c);
267                 break;
268             }
269
270             // Transition to normal state and re-handle character.
271             m_parseState = MiddleOfLine;
272             process(c);
273             break;
274
275         case MiddleOfLine:
276             if (c == '/' && peek(temp)) {
277                 if (temp == '/') {
278                     m_parseState = InSingleLineComment;
279                     emit(' ');
280                     advance();
281                     break;
282                 }
283
284                 if (temp == '*') {
285                     m_parseState = InMultiLineComment;
286                     // Emit the comment start in case the user has
287                     // an unclosed comment and we want to later
288                     // signal an error.
289                     emit('/');
290                     emit('*');
291                     advance();
292                     break;
293                 }
294             }
295
296             emit(c);
297             break;
298
299         case InPreprocessorDirective:
300             // No matter what the character is, just pass it
301             // through. Do not parse comments in this state. This
302             // might not be the right thing to do long term, but it
303             // should handle the #error preprocessor directive.
304             emit(c);
305             break;
306
307         case InSingleLineComment:
308             // The newline code at the top of this function takes care
309             // of resetting our state when we get out of the
310             // single-line comment. Swallow all other characters.
311             break;
312
313         case InMultiLineComment:
314             if (c == '*' && peek(temp) && temp == '/') {
315                 emit('*');
316                 emit('/');
317                 m_parseState = MiddleOfLine;
318                 advance();
319                 break;
320             }
321
322             // Swallow all other characters. Unclear whether we may
323             // want or need to just emit a space per character to try
324             // to preserve column numbers for debugging purposes.
325             break;
326         }
327     }
328 } // namespace anonymous
329
330 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
331     WTF_MAKE_FAST_ALLOCATED;
332 public:
333     explicit WebGLRenderingContextLostCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
334     void onContextLost() override { m_context->forceLostContext(WebGLRenderingContext::RealLostContext); }
335     virtual ~WebGLRenderingContextLostCallback() {}
336 private:
337     WebGLRenderingContextBase* m_context;
338 };
339
340 class WebGLRenderingContextErrorMessageCallback : public GraphicsContext3D::ErrorMessageCallback {
341     WTF_MAKE_FAST_ALLOCATED;
342 public:
343     explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
344     void onErrorMessage(const String& message, GC3Dint) override
345     {
346         if (m_context->m_synthesizedErrorsToConsole)
347             m_context->printGLErrorToConsole(message);
348     }
349     virtual ~WebGLRenderingContextErrorMessageCallback() { }
350 private:
351     WebGLRenderingContextBase* m_context;
352 };
353
354 std::unique_ptr<WebGLRenderingContextBase> WebGLRenderingContextBase::create(HTMLCanvasElement& canvas, WebGLContextAttributes& attributes, const String& type)
355 {
356 #if ENABLE(WEBGL2)
357     if (type == "webgl2" && !RuntimeEnabledFeatures::sharedFeatures().webGL2Enabled())
358         return nullptr;
359 #else
360     UNUSED_PARAM(type);
361 #endif
362
363     Document& document = canvas.document();
364     Frame* frame = document.frame();
365     if (!frame)
366         return nullptr;
367
368     // The FrameLoaderClient might block creation of a new WebGL context despite the page settings; in
369     // particular, if WebGL contexts were lost one or more times via the GL_ARB_robustness extension.
370     if (!frame->loader().client().allowWebGL(frame->settings().webGLEnabled())) {
371         canvas.dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Web page was not allowed to create a WebGL context."));
372         return nullptr;
373     }
374
375     bool isPendingPolicyResolution = false;
376     Document& topDocument = document.topDocument();
377     Page* page = topDocument.page();
378     bool forcingPendingPolicy = frame->settings().isForcePendingWebGLPolicy();
379
380     if (forcingPendingPolicy || (page && !topDocument.url().isLocalFile())) {
381         WebGLLoadPolicy policy = forcingPendingPolicy ? WebGLPendingCreation : page->mainFrame().loader().client().webGLPolicyForURL(topDocument.url());
382
383         if (policy == WebGLBlockCreation) {
384             LOG(WebGL, "The policy for this URL (%s) is to block WebGL.", topDocument.url().host().utf8().data());
385             return nullptr;
386         }
387
388         if (policy == WebGLPendingCreation) {
389             LOG(WebGL, "WebGL policy is pending. May need to be resolved later.");
390             isPendingPolicyResolution = true;
391         }
392     }
393
394     attributes.noExtensions = true;
395     attributes.shareResources = false;
396
397     if (frame->settings().forceSoftwareWebGLRendering())
398         attributes.forceSoftwareRenderer = true;
399
400     attributes.initialPowerPreference = attributes.powerPreference;
401     if (frame->settings().preferLowPowerWebGLRendering())
402         attributes.powerPreference = GraphicsContext3DPowerPreference::LowPower;
403
404     if (page)
405         attributes.devicePixelRatio = page->deviceScaleFactor();
406
407 #if ENABLE(WEBGL2)
408     if (type == "webgl2")
409         attributes.useGLES3 = true;
410 #endif
411
412     if (isPendingPolicyResolution) {
413         LOG(WebGL, "Create a WebGL context that looks real, but will require a policy resolution if used.");
414         std::unique_ptr<WebGLRenderingContextBase> renderingContext = nullptr;
415 #if ENABLE(WEBGL2)
416         if (type == "webgl2")
417             renderingContext = std::make_unique<WebGL2RenderingContext>(canvas, attributes);
418         else
419 #endif
420             renderingContext = std::make_unique<WebGLRenderingContext>(canvas, attributes);
421         renderingContext->suspendIfNeeded();
422         return renderingContext;
423     }
424
425     auto context = GraphicsContext3D::create(attributes, document.view()->root()->hostWindow());
426     if (!context || !context->makeContextCurrent()) {
427         canvas.dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
428         return nullptr;
429     }
430
431     auto& extensions = context->getExtensions();
432     if (extensions.supports(ASCIILiteral { "GL_EXT_debug_marker" }))
433         extensions.pushGroupMarkerEXT(ASCIILiteral { "WebGLRenderingContext" });
434
435 #if ENABLE(WEBGL2) && PLATFORM(MAC)
436     // glTexStorage() was only added to Core in OpenGL 4.2.
437     // However, according to https://developer.apple.com/opengl/capabilities/ all Apple GPUs support this extension.
438     if (attributes.useGLES3 && !extensions.supports("GL_ARB_texture_storage"))
439         return nullptr;
440 #endif
441
442     std::unique_ptr<WebGLRenderingContextBase> renderingContext;
443 #if ENABLE(WEBGL2)
444     if (type == "webgl2")
445         renderingContext = std::make_unique<WebGL2RenderingContext>(canvas, context.releaseNonNull(), attributes);
446     else
447 #endif
448         renderingContext = std::make_unique<WebGLRenderingContext>(canvas, context.releaseNonNull(), attributes);
449     renderingContext->suspendIfNeeded();
450
451     return renderingContext;
452 }
453
454 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement& passedCanvas, WebGLContextAttributes attributes)
455     : CanvasRenderingContext(passedCanvas)
456     , ActiveDOMObject(&passedCanvas.document())
457     , m_dispatchContextLostEventTimer(*this, &WebGLRenderingContextBase::dispatchContextLostEvent)
458     , m_restoreTimer(*this, &WebGLRenderingContextBase::maybeRestoreContext)
459     , m_attributes(attributes)
460     , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
461     , m_isPendingPolicyResolution(true)
462     , m_checkForContextLossHandlingTimer(*this, &WebGLRenderingContextBase::checkForContextLossHandling)
463 {
464     registerWithWebGLStateTracker();
465     m_checkForContextLossHandlingTimer.startOneShot(checkContextLossHandlingDelay);
466 }
467
468 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement& passedCanvas, Ref<GraphicsContext3D>&& context, WebGLContextAttributes attributes)
469     : CanvasRenderingContext(passedCanvas)
470     , ActiveDOMObject(&passedCanvas.document())
471     , m_context(WTFMove(context))
472     , m_dispatchContextLostEventTimer(*this, &WebGLRenderingContextBase::dispatchContextLostEvent)
473     , m_restoreTimer(*this, &WebGLRenderingContextBase::maybeRestoreContext)
474     , m_generatedImageCache(4)
475     , m_attributes(attributes)
476     , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
477     , m_checkForContextLossHandlingTimer(*this, &WebGLRenderingContextBase::checkForContextLossHandling)
478 {
479     m_contextGroup = WebGLContextGroup::create();
480     m_contextGroup->addContext(*this);
481     
482     m_context->setWebGLContext(this);
483
484     m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
485
486     setupFlags();
487     initializeNewContext();
488     registerWithWebGLStateTracker();
489     m_checkForContextLossHandlingTimer.startOneShot(checkContextLossHandlingDelay);
490 }
491
492 // We check for context loss handling after a few seconds to give the JS a chance to register the event listeners
493 // and to discard temporary GL contexts (e.g. feature detection).
494 void WebGLRenderingContextBase::checkForContextLossHandling()
495 {
496     if (!canvas().renderer())
497         return;
498
499     auto* page = canvas().document().page();
500     if (!page)
501         return;
502
503     bool handlesContextLoss = canvas().hasEventListeners(eventNames().webglcontextlostEvent) && canvas().hasEventListeners(eventNames().webglcontextrestoredEvent);
504     page->diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::pageHandlesWebGLContextLossKey(), handlesContextLoss ? DiagnosticLoggingKeys::yesKey() : DiagnosticLoggingKeys::noKey(), ShouldSample::No);
505 }
506
507 void WebGLRenderingContextBase::registerWithWebGLStateTracker()
508 {
509     auto* page = canvas().document().page();
510     if (!page)
511         return;
512
513     auto* tracker = page->webGLStateTracker();
514     if (!tracker)
515         return;
516
517     m_trackerToken = tracker->token(m_attributes.initialPowerPreference);
518 }
519
520 void WebGLRenderingContextBase::initializeNewContext()
521 {
522     ASSERT(!m_contextLost);
523     m_needsUpdate = true;
524     m_markedCanvasDirty = false;
525     m_activeTextureUnit = 0;
526     m_packAlignment = 4;
527     m_unpackAlignment = 4;
528     m_unpackFlipY = false;
529     m_unpackPremultiplyAlpha = false;
530     m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
531     m_boundArrayBuffer = nullptr;
532     m_currentProgram = nullptr;
533     m_framebufferBinding = nullptr;
534     m_renderbufferBinding = nullptr;
535     m_depthMask = true;
536     m_stencilEnabled = false;
537     m_stencilMask = 0xFFFFFFFF;
538     m_stencilMaskBack = 0xFFFFFFFF;
539     m_stencilFuncRef = 0;
540     m_stencilFuncRefBack = 0;
541     m_stencilFuncMask = 0xFFFFFFFF;
542     m_stencilFuncMaskBack = 0xFFFFFFFF;
543     m_layerCleared = false;
544     m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
545     
546     m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
547     m_scissorEnabled = false;
548     m_clearDepth = 1;
549     m_clearStencil = 0;
550     m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
551
552     GC3Dint numCombinedTextureImageUnits = 0;
553     m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
554     m_textureUnits.clear();
555     m_textureUnits.resize(numCombinedTextureImageUnits);
556     for (GC3Dint i = 0; i < numCombinedTextureImageUnits; ++i)
557         m_unrenderableTextureUnits.add(i);
558
559     GC3Dint numVertexAttribs = 0;
560     m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
561     m_maxVertexAttribs = numVertexAttribs;
562     
563     m_maxTextureSize = 0;
564     m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
565     m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
566     m_maxCubeMapTextureSize = 0;
567     m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
568     m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
569     m_maxRenderbufferSize = 0;
570     m_context->getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
571
572     // These two values from EXT_draw_buffers are lazily queried.
573     m_maxDrawBuffers = 0;
574     m_maxColorAttachments = 0;
575
576     m_backDrawBuffer = GraphicsContext3D::BACK;
577     m_drawBuffersWebGLRequirementsChecked = false;
578     m_drawBuffersSupported = false;
579     
580     m_vertexAttribValue.resize(m_maxVertexAttribs);
581
582     if (!isGLES2NPOTStrict())
583         createFallbackBlackTextures1x1();
584
585     IntSize canvasSize = clampedCanvasSize();
586     m_context->reshape(canvasSize.width(), canvasSize.height());
587     m_context->viewport(0, 0, canvasSize.width(), canvasSize.height());
588     m_context->scissor(0, 0, canvasSize.width(), canvasSize.height());
589
590     m_context->setContextLostCallback(std::make_unique<WebGLRenderingContextLostCallback>(this));
591     m_context->setErrorMessageCallback(std::make_unique<WebGLRenderingContextErrorMessageCallback>(this));
592 }
593
594 void WebGLRenderingContextBase::setupFlags()
595 {
596     ASSERT(m_context);
597
598     if (Page* page = canvas().document().page())
599         m_synthesizedErrorsToConsole = page->settings().webGLErrorsToConsoleEnabled();
600
601     m_isGLES2Compliant = m_context->isGLES2Compliant();
602     if (m_isGLES2Compliant) {
603         m_isGLES2NPOTStrict = !m_context->getExtensions().isEnabled("GL_OES_texture_npot");
604         m_isDepthStencilSupported = m_context->getExtensions().isEnabled("GL_OES_packed_depth_stencil");
605     } else {
606         m_isGLES2NPOTStrict = !m_context->getExtensions().isEnabled("GL_ARB_texture_non_power_of_two");
607         m_isDepthStencilSupported = m_context->getExtensions().isEnabled("GL_EXT_packed_depth_stencil");
608     }
609     m_isRobustnessEXTSupported = m_context->getExtensions().isEnabled("GL_EXT_robustness");
610 }
611
612 void WebGLRenderingContextBase::addCompressedTextureFormat(GC3Denum format)
613 {
614     if (!m_compressedTextureFormats.contains(format))
615         m_compressedTextureFormats.append(format);
616 }
617
618 WebGLRenderingContextBase::~WebGLRenderingContextBase()
619 {
620     // Remove all references to WebGLObjects so if they are the last reference
621     // they will be freed before the last context is removed from the context group.
622     m_boundArrayBuffer = nullptr;
623     m_defaultVertexArrayObject = nullptr;
624     m_boundVertexArrayObject = nullptr;
625     m_vertexAttrib0Buffer = nullptr;
626     m_currentProgram = nullptr;
627     m_framebufferBinding = nullptr;
628     m_renderbufferBinding = nullptr;
629
630     for (auto& textureUnit : m_textureUnits) {
631         textureUnit.texture2DBinding = nullptr;
632         textureUnit.textureCubeMapBinding = nullptr;
633     }
634
635     m_blackTexture2D = nullptr;
636     m_blackTextureCubeMap = nullptr;
637
638     if (!m_isPendingPolicyResolution) {
639         detachAndRemoveAllObjects();
640         destroyGraphicsContext3D();
641         m_contextGroup->removeContext(*this);
642     }
643 }
644
645 void WebGLRenderingContextBase::destroyGraphicsContext3D()
646 {
647     if (m_isPendingPolicyResolution)
648         return;
649
650     if (m_context) {
651         m_context->setContextLostCallback(nullptr);
652         m_context->setErrorMessageCallback(nullptr);
653         m_context = nullptr;
654     }
655 }
656
657 void WebGLRenderingContextBase::markContextChanged()
658 {
659     if (m_framebufferBinding)
660         return;
661
662     m_context->markContextChanged();
663
664     m_layerCleared = false;
665     RenderBox* renderBox = canvas().renderBox();
666     if (isAccelerated() && renderBox && renderBox->hasAcceleratedCompositing()) {
667         m_markedCanvasDirty = true;
668         canvas().clearCopiedImage();
669         renderBox->contentChanged(CanvasChanged);
670     } else {
671         if (!m_markedCanvasDirty) {
672             m_markedCanvasDirty = true;
673             canvas().didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize()));
674         }
675     }
676 }
677
678 bool WebGLRenderingContextBase::clearIfComposited(GC3Dbitfield mask)
679 {
680     if (isContextLostOrPending())
681         return false;
682
683     if (!m_context->layerComposited() || m_layerCleared
684         || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
685         return false;
686
687     auto contextAttributes = getContextAttributes();
688     ASSERT(contextAttributes);
689
690     // Determine if it's possible to combine the clear the user asked for and this clear.
691     bool combinedClear = mask && !m_scissorEnabled;
692
693     m_context->disable(GraphicsContext3D::SCISSOR_TEST);
694     if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
695         m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
696                               m_colorMask[1] ? m_clearColor[1] : 0,
697                               m_colorMask[2] ? m_clearColor[2] : 0,
698                               m_colorMask[3] ? m_clearColor[3] : 0);
699     else
700         m_context->clearColor(0, 0, 0, 0);
701     m_context->colorMask(true, true, true, true);
702     GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
703     if (contextAttributes->depth) {
704         if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
705             m_context->clearDepth(1.0f);
706         clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
707         m_context->depthMask(true);
708     }
709     if (contextAttributes->stencil) {
710         if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
711             m_context->clearStencil(m_clearStencil & m_stencilMask);
712         else
713             m_context->clearStencil(0);
714         clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
715         m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
716     }
717     if (m_framebufferBinding)
718         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
719     m_context->clear(clearMask);
720
721     restoreStateAfterClear();
722     if (m_framebufferBinding)
723         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
724     m_layerCleared = true;
725
726     return combinedClear;
727 }
728
729 void WebGLRenderingContextBase::restoreStateAfterClear()
730 {
731     // Restore the state that the context set.
732     if (m_scissorEnabled)
733         m_context->enable(GraphicsContext3D::SCISSOR_TEST);
734     m_context->clearColor(m_clearColor[0], m_clearColor[1],
735                           m_clearColor[2], m_clearColor[3]);
736     m_context->colorMask(m_colorMask[0], m_colorMask[1],
737                          m_colorMask[2], m_colorMask[3]);
738     m_context->clearDepth(m_clearDepth);
739     m_context->clearStencil(m_clearStencil);
740     m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
741     m_context->depthMask(m_depthMask);
742 }
743
744 void WebGLRenderingContextBase::markLayerComposited()
745 {
746     if (isContextLostOrPending())
747         return;
748     m_context->markLayerComposited();
749 }
750
751 void WebGLRenderingContextBase::paintRenderingResultsToCanvas()
752 {
753     if (isContextLostOrPending())
754         return;
755
756     if (canvas().document().printing())
757         canvas().clearPresentationCopy();
758
759     // Until the canvas is written to by the application, the clear that
760     // happened after it was composited should be ignored by the compositor.
761     if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
762         m_context->paintCompositedResultsToCanvas(canvas().buffer());
763
764         canvas().makePresentationCopy();
765     } else
766         canvas().clearPresentationCopy();
767     clearIfComposited();
768
769     if (!m_markedCanvasDirty && !m_layerCleared)
770         return;
771
772     canvas().clearCopiedImage();
773     m_markedCanvasDirty = false;
774
775     m_context->paintRenderingResultsToCanvas(canvas().buffer());
776 }
777
778 RefPtr<ImageData> WebGLRenderingContextBase::paintRenderingResultsToImageData()
779 {
780     if (isContextLostOrPending())
781         return nullptr;
782     clearIfComposited();
783     return m_context->paintRenderingResultsToImageData();
784 }
785
786 WebGLTexture::TextureExtensionFlag WebGLRenderingContextBase::textureExtensionFlags() const
787 {
788     return static_cast<WebGLTexture::TextureExtensionFlag>((m_oesTextureFloatLinear ? WebGLTexture::TextureExtensionFloatLinearEnabled : 0) | (m_oesTextureHalfFloatLinear ? WebGLTexture::TextureExtensionHalfFloatLinearEnabled : 0));
789 }
790
791 void WebGLRenderingContextBase::reshape(int width, int height)
792 {
793     if (isContextLostOrPending())
794         return;
795
796     // This is an approximation because at WebGLRenderingContext level we don't
797     // know if the underlying FBO uses textures or renderbuffers.
798     GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
799     // Limit drawing buffer size to 4k to avoid memory exhaustion.
800     const int sizeUpperLimit = 4096;
801     maxSize = std::min(maxSize, sizeUpperLimit);
802     GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
803     GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
804     width = clamp(width, 1, maxWidth);
805     height = clamp(height, 1, maxHeight);
806
807     if (m_needsUpdate) {
808         RenderBox* renderBox = canvas().renderBox();
809         if (renderBox && renderBox->hasAcceleratedCompositing())
810             renderBox->contentChanged(CanvasChanged);
811         m_needsUpdate = false;
812     }
813
814     // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
815     // clear (and this matches what reshape will do).
816     m_context->reshape(width, height);
817
818     auto& textureUnit = m_textureUnits[m_activeTextureUnit];
819     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(textureUnit.texture2DBinding.get()));
820     if (textureUnit.texture2DBinding && textureUnit.texture2DBinding->needToUseBlackTexture(textureExtensionFlags()))
821         m_unrenderableTextureUnits.add(m_activeTextureUnit);
822     m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
823     if (m_framebufferBinding)
824       m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
825 }
826
827 int WebGLRenderingContextBase::drawingBufferWidth() const
828 {
829     if (isContextLost())
830         return 0;
831
832     if (m_isPendingPolicyResolution && !m_hasRequestedPolicyResolution)
833         return 0;
834
835     return m_context->getInternalFramebufferSize().width();
836 }
837
838 int WebGLRenderingContextBase::drawingBufferHeight() const
839 {
840     if (isContextLost())
841         return 0;
842
843     if (m_isPendingPolicyResolution && !m_hasRequestedPolicyResolution)
844         return 0;
845
846     return m_context->getInternalFramebufferSize().height();
847 }
848
849 unsigned WebGLRenderingContextBase::sizeInBytes(GC3Denum type)
850 {
851     switch (type) {
852     case GraphicsContext3D::BYTE:
853         return sizeof(GC3Dbyte);
854     case GraphicsContext3D::UNSIGNED_BYTE:
855         return sizeof(GC3Dubyte);
856     case GraphicsContext3D::SHORT:
857         return sizeof(GC3Dshort);
858     case GraphicsContext3D::UNSIGNED_SHORT:
859         return sizeof(GC3Dushort);
860     case GraphicsContext3D::INT:
861         return sizeof(GC3Dint);
862     case GraphicsContext3D::UNSIGNED_INT:
863         return sizeof(GC3Duint);
864     case GraphicsContext3D::FLOAT:
865         return sizeof(GC3Dfloat);
866     }
867     ASSERT_NOT_REACHED();
868     return 0;
869 }
870
871 void WebGLRenderingContextBase::activeTexture(GC3Denum texture)
872 {
873     if (isContextLostOrPending())
874         return;
875     if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
876         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "activeTexture", "texture unit out of range");
877         return;
878     }
879     m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
880     m_context->activeTexture(texture);
881 }
882
883 void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader)
884 {
885     if (isContextLostOrPending() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader))
886         return;
887     if (!program->attachShader(shader)) {
888         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "attachShader", "shader attachment already has shader");
889         return;
890     }
891     m_context->attachShader(objectOrZero(program), objectOrZero(shader));
892     shader->onAttached();
893 }
894
895 void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name)
896 {
897     if (isContextLostOrPending() || !validateWebGLObject("bindAttribLocation", program))
898         return;
899     if (!validateLocationLength("bindAttribLocation", name))
900         return;
901     if (!validateString("bindAttribLocation", name))
902         return;
903     if (isPrefixReserved(name)) {
904         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindAttribLocation", "reserved prefix");
905         return;
906     }
907     if (index >= m_maxVertexAttribs) {
908         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bindAttribLocation", "index out of range");
909         return;
910     }
911     m_context->bindAttribLocation(objectOrZero(program), index, name);
912 }
913
914 bool WebGLRenderingContextBase::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted)
915 {
916     deleted = false;
917     if (isContextLostOrPending())
918         return false;
919     if (object) {
920         if (!object->validate(contextGroup(), *this)) {
921             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object not from this context");
922             return false;
923         }
924         deleted = !object->object();
925     }
926     return true;
927 }
928
929 void WebGLRenderingContextBase::bindBuffer(GC3Denum target, WebGLBuffer* buffer)
930 {
931     bool deleted;
932     if (!checkObjectToBeBound("bindBuffer", buffer, deleted))
933         return;
934     if (deleted)
935         buffer = nullptr;
936     if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
937         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets");
938         return;
939     }
940     if (target == GraphicsContext3D::ARRAY_BUFFER)
941         m_boundArrayBuffer = buffer;
942     else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
943         m_boundVertexArrayObject->setElementArrayBuffer(buffer);
944     else {
945         bool success = false;
946 #if ENABLE(WEBGL2)
947         if (isWebGL2()) {
948             success = true;
949             switch (target) {
950             case GraphicsContext3D::COPY_READ_BUFFER:
951                 m_boundCopyReadBuffer = buffer;
952                 break;
953             case GraphicsContext3D::COPY_WRITE_BUFFER:
954                 m_boundCopyWriteBuffer = buffer;
955                 break;
956             case GraphicsContext3D::PIXEL_PACK_BUFFER:
957                 m_boundPixelPackBuffer = buffer;
958                 break;
959             case GraphicsContext3D::PIXEL_UNPACK_BUFFER:
960                 m_boundPixelUnpackBuffer = buffer;
961                 break;
962             case GraphicsContext3D::TRANSFORM_FEEDBACK_BUFFER:
963                 m_boundTransformFeedbackBuffer = buffer;
964                 break;
965             case GraphicsContext3D::UNIFORM_BUFFER:
966                 m_boundUniformBuffer = buffer;
967                 break;
968             default:
969                 success = false;
970                 break;
971             }
972         }
973 #endif
974         if (!success) {
975             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindBuffer", "invalid target");
976             return;
977         }
978     }
979
980     m_context->bindBuffer(target, objectOrZero(buffer));
981     if (buffer)
982         buffer->setTarget(target, isWebGL2());
983 }
984
985 void WebGLRenderingContextBase::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer)
986 {
987     bool deleted;
988     if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted))
989         return;
990     if (deleted)
991         buffer = 0;
992     if (target != GraphicsContext3D::FRAMEBUFFER) {
993         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindFramebuffer", "invalid target");
994         return;
995     }
996     m_framebufferBinding = buffer;
997     m_context->bindFramebuffer(target, objectOrZero(buffer));
998     if (buffer)
999         buffer->setHasEverBeenBound();
1000     applyStencilTest();
1001 }
1002
1003 void WebGLRenderingContextBase::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer)
1004 {
1005     bool deleted;
1006     if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
1007         return;
1008     if (deleted)
1009         renderBuffer = 0;
1010     if (target != GraphicsContext3D::RENDERBUFFER) {
1011         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindRenderbuffer", "invalid target");
1012         return;
1013     }
1014     m_renderbufferBinding = renderBuffer;
1015     m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
1016     if (renderBuffer)
1017         renderBuffer->setHasEverBeenBound();
1018 }
1019
1020 void WebGLRenderingContextBase::bindTexture(GC3Denum target, WebGLTexture* texture)
1021 {
1022     bool deleted;
1023     if (!checkObjectToBeBound("bindTexture", texture, deleted))
1024         return;
1025     if (deleted)
1026         texture = nullptr;
1027     if (texture && texture->getTarget() && texture->getTarget() != target) {
1028         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
1029         return;
1030     }
1031     GC3Dint maxLevel = 0;
1032     auto& textureUnit = m_textureUnits[m_activeTextureUnit];
1033     if (target == GraphicsContext3D::TEXTURE_2D) {
1034         textureUnit.texture2DBinding = texture;
1035         maxLevel = m_maxTextureLevel;
1036         if (texture && texture->needToUseBlackTexture(textureExtensionFlags()))
1037             m_unrenderableTextureUnits.add(m_activeTextureUnit);
1038         else
1039             m_unrenderableTextureUnits.remove(m_activeTextureUnit);
1040     } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
1041         textureUnit.textureCubeMapBinding = texture;
1042         maxLevel = m_maxCubeMapTextureLevel;
1043         if (texture && texture->needToUseBlackTexture(textureExtensionFlags()))
1044             m_unrenderableTextureUnits.add(m_activeTextureUnit);
1045         else
1046             m_unrenderableTextureUnits.remove(m_activeTextureUnit);
1047     } else {
1048         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindTexture", "invalid target");
1049         return;
1050     }
1051     m_context->bindTexture(target, objectOrZero(texture));
1052     if (texture)
1053         texture->setTarget(target, maxLevel);
1054
1055     // Note: previously we used to automatically set the TEXTURE_WRAP_R
1056     // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
1057     // ES 2.0 doesn't expose this flag (a bug in the specification) and
1058     // otherwise the application has no control over the seams in this
1059     // dimension. However, it appears that supporting this properly on all
1060     // platforms is fairly involved (will require a HashMap from texture ID
1061     // in all ports), and we have not had any complaints, so the logic has
1062     // been removed.
1063 }
1064
1065 void WebGLRenderingContextBase::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
1066 {
1067     if (isContextLostOrPending())
1068         return;
1069     m_context->blendColor(red, green, blue, alpha);
1070 }
1071
1072 void WebGLRenderingContextBase::blendEquation(GC3Denum mode)
1073 {
1074     if (isContextLostOrPending() || !validateBlendEquation("blendEquation", mode))
1075         return;
1076     m_context->blendEquation(mode);
1077 }
1078
1079 void WebGLRenderingContextBase::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
1080 {
1081     if (isContextLostOrPending() || !validateBlendEquation("blendEquation", modeRGB) || !validateBlendEquation("blendEquation", modeAlpha))
1082         return;
1083     m_context->blendEquationSeparate(modeRGB, modeAlpha);
1084 }
1085
1086
1087 void WebGLRenderingContextBase::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
1088 {
1089     if (isContextLostOrPending() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
1090         return;
1091     m_context->blendFunc(sfactor, dfactor);
1092 }
1093
1094 void WebGLRenderingContextBase::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
1095 {
1096     // Note: Alpha does not have the same restrictions as RGB.
1097     if (isContextLostOrPending() || !validateBlendFuncFactors("blendFunc", srcRGB, dstRGB))
1098         return;
1099     m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
1100 }
1101
1102 void WebGLRenderingContextBase::bufferData(GC3Denum target, long long size, GC3Denum usage)
1103 {
1104     if (isContextLostOrPending())
1105         return;
1106     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1107     if (!buffer)
1108         return;
1109     if (size < 0) {
1110         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size < 0");
1111         return;
1112     }
1113     if (!size) {
1114         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size == 0");
1115         return;
1116     }
1117     if (!buffer->associateBufferData(static_cast<GC3Dsizeiptr>(size))) {
1118         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1119         return;
1120     }
1121
1122     m_context->moveErrorsToSyntheticErrorList();
1123     m_context->bufferData(target, static_cast<GC3Dsizeiptr>(size), usage);
1124     if (m_context->moveErrorsToSyntheticErrorList()) {
1125         // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1126         buffer->disassociateBufferData();
1127     }
1128 }
1129
1130 void WebGLRenderingContextBase::bufferData(GC3Denum target, std::optional<BufferDataSource>&& data, GC3Denum usage)
1131 {
1132     if (isContextLostOrPending())
1133         return;
1134     if (!data) {
1135         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "null data");
1136         return;
1137     }
1138     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1139     if (!buffer)
1140         return;
1141
1142     WTF::visit([&](auto& data) {
1143         if (!buffer->associateBufferData(data.get())) {
1144             this->synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1145             return;
1146         }
1147
1148         m_context->moveErrorsToSyntheticErrorList();
1149         m_context->bufferData(target, data->byteLength(), data->data(), usage);
1150         if (m_context->moveErrorsToSyntheticErrorList()) {
1151             // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1152             buffer->disassociateBufferData();
1153         }
1154     }, data.value());
1155 }
1156
1157 void WebGLRenderingContextBase::bufferSubData(GC3Denum target, long long offset, std::optional<BufferDataSource>&& data)
1158 {
1159     if (isContextLostOrPending())
1160         return;
1161     WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1162     if (!buffer)
1163         return;
1164     if (offset < 0) {
1165         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1166         return;
1167     }
1168     if (!data)
1169         return;
1170
1171     WTF::visit([&](auto& data) {
1172         if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data.get())) {
1173             this->synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1174             return;
1175         }
1176
1177         m_context->moveErrorsToSyntheticErrorList();
1178         m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->data());
1179         if (m_context->moveErrorsToSyntheticErrorList()) {
1180             // The bufferSubData function failed. Tell the buffer it doesn't have the data it thinks it does.
1181             buffer->disassociateBufferData();
1182         }
1183     }, data.value());
1184 }
1185
1186 GC3Denum WebGLRenderingContextBase::checkFramebufferStatus(GC3Denum target)
1187 {
1188     if (isContextLostOrPending())
1189         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
1190     if (target != GraphicsContext3D::FRAMEBUFFER) {
1191         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "checkFramebufferStatus", "invalid target");
1192         return 0;
1193     }
1194     if (!m_framebufferBinding || !m_framebufferBinding->object())
1195         return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
1196     const char* reason = "framebuffer incomplete";
1197     GC3Denum result = m_framebufferBinding->checkStatus(&reason);
1198     if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
1199         printGLWarningToConsole("checkFramebufferStatus", reason);
1200         return result;
1201     }
1202     result = m_context->checkFramebufferStatus(target);
1203     return result;
1204 }
1205
1206 void WebGLRenderingContextBase::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
1207 {
1208     if (isContextLostOrPending())
1209         return;
1210     if (std::isnan(r))
1211         r = 0;
1212     if (std::isnan(g))
1213         g = 0;
1214     if (std::isnan(b))
1215         b = 0;
1216     if (std::isnan(a))
1217         a = 1;
1218     m_clearColor[0] = r;
1219     m_clearColor[1] = g;
1220     m_clearColor[2] = b;
1221     m_clearColor[3] = a;
1222     m_context->clearColor(r, g, b, a);
1223 }
1224
1225 void WebGLRenderingContextBase::clearDepth(GC3Dfloat depth)
1226 {
1227     if (isContextLostOrPending())
1228         return;
1229     m_clearDepth = depth;
1230     m_context->clearDepth(depth);
1231 }
1232
1233 void WebGLRenderingContextBase::clearStencil(GC3Dint s)
1234 {
1235     if (isContextLostOrPending())
1236         return;
1237     m_clearStencil = s;
1238     m_context->clearStencil(s);
1239 }
1240
1241 void WebGLRenderingContextBase::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1242 {
1243     if (isContextLostOrPending())
1244         return;
1245     m_colorMask[0] = red;
1246     m_colorMask[1] = green;
1247     m_colorMask[2] = blue;
1248     m_colorMask[3] = alpha;
1249     m_context->colorMask(red, green, blue, alpha);
1250 }
1251
1252 void WebGLRenderingContextBase::compileShader(WebGLShader* shader)
1253 {
1254     if (isContextLostOrPending() || !validateWebGLObject("compileShader", shader))
1255         return;
1256     m_context->compileShader(objectOrZero(shader));
1257     GC3Dint value;
1258     m_context->getShaderiv(objectOrZero(shader), GraphicsContext3D::COMPILE_STATUS, &value);
1259     shader->setValid(value);
1260 }
1261
1262 void WebGLRenderingContextBase::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, ArrayBufferView& data)
1263 {
1264     if (isContextLostOrPending())
1265         return;
1266     if (!validateTexFuncLevel("compressedTexImage2D", target, level))
1267         return;
1268
1269     if (!validateCompressedTexFormat(internalformat)) {
1270         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
1271         return;
1272     }
1273     if (border) {
1274         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "border not 0");
1275         return;
1276     }
1277     if (!validateCompressedTexDimensions("compressedTexImage2D", target, level, width, height, internalformat))
1278         return;
1279     if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
1280         return;
1281
1282     WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
1283     if (!tex)
1284         return;
1285     if (!validateNPOTTextureLevel(width, height, level, "compressedTexImage2D"))
1286         return;
1287     m_context->moveErrorsToSyntheticErrorList();
1288     m_context->compressedTexImage2D(target, level, internalformat, width, height,
1289         border, data.byteLength(), data.baseAddress());
1290     if (m_context->moveErrorsToSyntheticErrorList()) {
1291         // The compressedTexImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
1292         tex->markInvalid(target, level);
1293         return;
1294     }
1295
1296     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1297     tex->setCompressed();
1298 }
1299
1300 void WebGLRenderingContextBase::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView& data)
1301 {
1302     if (isContextLostOrPending())
1303         return;
1304     if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
1305         return;
1306     if (!validateCompressedTexFormat(format)) {
1307         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
1308         return;
1309     }
1310     if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
1311         return;
1312
1313     WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
1314     if (!tex)
1315         return;
1316
1317     if (format != tex->getInternalFormat(target, level)) {
1318         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
1319         return;
1320     }
1321
1322     if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
1323         return;
1324
1325     graphicsContext3D()->compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, data.byteLength(), data.baseAddress());
1326     tex->setCompressed();
1327 }
1328
1329 bool WebGLRenderingContextBase::validateSettableTexInternalFormat(const char* functionName, GC3Denum internalFormat)
1330 {
1331     switch (internalFormat) {
1332     case GraphicsContext3D::DEPTH_COMPONENT:
1333     case GraphicsContext3D::DEPTH_STENCIL:
1334     case GraphicsContext3D::DEPTH_COMPONENT16:
1335     case GraphicsContext3D::DEPTH_COMPONENT24:
1336     case GraphicsContext3D::DEPTH_COMPONENT32F:
1337     case GraphicsContext3D::DEPTH24_STENCIL8:
1338     case GraphicsContext3D::DEPTH32F_STENCIL8:
1339     case GraphicsContext3D::STENCIL_INDEX8:
1340         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format can not be set, only rendered to");
1341         return false;
1342     default:
1343         return true;
1344     }
1345 }
1346
1347 void WebGLRenderingContextBase::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1348 {
1349     if (isContextLostOrPending())
1350         return;
1351     if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
1352         return;
1353     WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
1354     if (!tex)
1355         return;
1356     if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
1357         return;
1358     // Before checking if it is in the range, check if overflow happens first.
1359     if (xoffset + width < 0 || yoffset + height < 0) {
1360         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "bad dimensions");
1361         return;
1362     }
1363     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1364         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
1365         return;
1366     }
1367     GC3Denum internalFormat = tex->getInternalFormat(target, level);
1368     if (!validateSettableTexInternalFormat("copyTexSubImage2D", internalFormat))
1369         return;
1370     if (!isTexInternalFormatColorBufferCombinationValid(internalFormat, getBoundFramebufferColorFormat())) {
1371         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
1372         return;
1373     }
1374     const char* reason = "framebuffer incomplete";
1375     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
1376         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", reason);
1377         return;
1378     }
1379     clearIfComposited();
1380
1381     GC3Dint clippedX, clippedY;
1382     GC3Dsizei clippedWidth, clippedHeight;
1383     if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1384         GC3Denum format;
1385         GC3Denum type;
1386         if (!GraphicsContext3D::possibleFormatAndTypeForInternalFormat(tex->getInternalFormat(target, level), format, type)) {
1387             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "copyTexSubImage2D", "Texture has unknown internal format");
1388             return;
1389         }
1390         std::unique_ptr<unsigned char[]> zero;
1391         if (width && height) {
1392             unsigned size;
1393             GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, nullptr);
1394             if (error != GraphicsContext3D::NO_ERROR) {
1395                 synthesizeGLError(error, "copyTexSubImage2D", "bad dimensions");
1396                 return;
1397             }
1398             zero = std::make_unique<unsigned char[]>(size);
1399             if (!zero) {
1400                 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "out of memory");
1401                 return;
1402             }
1403             memset(zero.get(), 0, size);
1404         }
1405         m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1406         if (clippedWidth > 0 && clippedHeight > 0)
1407             m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y, clippedX, clippedY, clippedWidth, clippedHeight);
1408     } else
1409         m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1410 }
1411
1412 RefPtr<WebGLBuffer> WebGLRenderingContextBase::createBuffer()
1413 {
1414     if (isContextLostOrPending())
1415         return nullptr;
1416     auto buffer = WebGLBuffer::create(*this);
1417     addSharedObject(buffer.get());
1418     return WTFMove(buffer);
1419 }
1420
1421 RefPtr<WebGLFramebuffer> WebGLRenderingContextBase::createFramebuffer()
1422 {
1423     if (isContextLostOrPending())
1424         return nullptr;
1425     auto buffer = WebGLFramebuffer::create(*this);
1426     addContextObject(buffer.get());
1427     return WTFMove(buffer);
1428 }
1429
1430 RefPtr<WebGLTexture> WebGLRenderingContextBase::createTexture()
1431 {
1432     if (isContextLostOrPending())
1433         return nullptr;
1434     auto texture = WebGLTexture::create(*this);
1435     addSharedObject(texture.get());
1436     return WTFMove(texture);
1437 }
1438
1439 RefPtr<WebGLProgram> WebGLRenderingContextBase::createProgram()
1440 {
1441     if (isContextLostOrPending())
1442         return nullptr;
1443     auto program = WebGLProgram::create(*this);
1444     addSharedObject(program.get());
1445     return WTFMove(program);
1446 }
1447
1448 RefPtr<WebGLRenderbuffer> WebGLRenderingContextBase::createRenderbuffer()
1449 {
1450     if (isContextLostOrPending())
1451         return nullptr;
1452     auto buffer = WebGLRenderbuffer::create(*this);
1453     addSharedObject(buffer.get());
1454     return WTFMove(buffer);
1455 }
1456
1457 RefPtr<WebGLShader> WebGLRenderingContextBase::createShader(GC3Denum type)
1458 {
1459     if (isContextLostOrPending())
1460         return nullptr;
1461     if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1462         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "createShader", "invalid shader type");
1463         return nullptr;
1464     }
1465
1466     auto shader = WebGLShader::create(*this, type);
1467     addSharedObject(shader.get());
1468     return WTFMove(shader);
1469 }
1470
1471 void WebGLRenderingContextBase::cullFace(GC3Denum mode)
1472 {
1473     if (isContextLostOrPending())
1474         return;
1475     m_context->cullFace(mode);
1476 }
1477
1478 bool WebGLRenderingContextBase::deleteObject(WebGLObject* object)
1479 {
1480     if (isContextLostOrPending() || !object)
1481         return false;
1482     if (!object->validate(contextGroup(), *this)) {
1483         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "delete", "object does not belong to this context");
1484         return false;
1485     }
1486     if (object->object())
1487         // We need to pass in context here because we want
1488         // things in this context unbound.
1489         object->deleteObject(graphicsContext3D());
1490     return true;
1491 }
1492
1493 void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer)
1494 {
1495     if (!deleteObject(buffer))
1496         return;
1497     if (m_boundArrayBuffer == buffer)
1498         m_boundArrayBuffer = nullptr;
1499
1500     m_boundVertexArrayObject->unbindBuffer(*buffer);
1501 }
1502
1503 void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1504 {
1505     if (!deleteObject(framebuffer))
1506         return;
1507     if (framebuffer == m_framebufferBinding) {
1508         m_framebufferBinding = nullptr;
1509         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1510     }
1511 }
1512
1513 void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program)
1514 {
1515     deleteObject(program);
1516     // We don't reset m_currentProgram to 0 here because the deletion of the
1517     // current program is delayed.
1518 }
1519
1520 void WebGLRenderingContextBase::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1521 {
1522     if (!deleteObject(renderbuffer))
1523         return;
1524     if (renderbuffer == m_renderbufferBinding)
1525         m_renderbufferBinding = nullptr;
1526     if (m_framebufferBinding)
1527         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1528 }
1529
1530 void WebGLRenderingContextBase::deleteShader(WebGLShader* shader)
1531 {
1532     deleteObject(shader);
1533 }
1534
1535 void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture)
1536 {
1537     if (!deleteObject(texture))
1538         return;
1539
1540     unsigned current = 0;
1541     for (auto& textureUnit : m_textureUnits) {
1542         if (texture == textureUnit.texture2DBinding) {
1543             textureUnit.texture2DBinding = nullptr;
1544             m_unrenderableTextureUnits.remove(current);
1545         }
1546         if (texture == textureUnit.textureCubeMapBinding) {
1547             textureUnit.textureCubeMapBinding = nullptr;
1548             m_unrenderableTextureUnits.remove(current);
1549         }
1550         ++current;
1551     }
1552     if (m_framebufferBinding)
1553         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1554 }
1555
1556 void WebGLRenderingContextBase::depthFunc(GC3Denum func)
1557 {
1558     if (isContextLostOrPending())
1559         return;
1560     m_context->depthFunc(func);
1561 }
1562
1563 void WebGLRenderingContextBase::depthMask(GC3Dboolean flag)
1564 {
1565     if (isContextLostOrPending())
1566         return;
1567     m_depthMask = flag;
1568     m_context->depthMask(flag);
1569 }
1570
1571 void WebGLRenderingContextBase::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1572 {
1573     if (isContextLostOrPending())
1574         return;
1575     if (zNear > zFar) {
1576         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "depthRange", "zNear > zFar");
1577         return;
1578     }
1579     m_context->depthRange(zNear, zFar);
1580 }
1581
1582 void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader)
1583 {
1584     if (isContextLostOrPending() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
1585         return;
1586     if (!program->detachShader(shader)) {
1587         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "detachShader", "shader not attached");
1588         return;
1589     }
1590     m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1591     shader->onDetached(graphicsContext3D());
1592 }
1593
1594 void WebGLRenderingContextBase::disable(GC3Denum cap)
1595 {
1596     if (isContextLostOrPending() || !validateCapability("disable", cap))
1597         return;
1598     if (cap == GraphicsContext3D::STENCIL_TEST) {
1599         m_stencilEnabled = false;
1600         applyStencilTest();
1601         return;
1602     }
1603     if (cap == GraphicsContext3D::SCISSOR_TEST)
1604         m_scissorEnabled = false;
1605     m_context->disable(cap);
1606 }
1607
1608 void WebGLRenderingContextBase::disableVertexAttribArray(GC3Duint index)
1609 {
1610     if (isContextLostOrPending())
1611         return;
1612     if (index >= m_maxVertexAttribs) {
1613         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "disableVertexAttribArray", "index out of range");
1614         return;
1615     }
1616
1617     WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1618     state.enabled = false;
1619
1620     if (index > 0 || isGLES2Compliant())
1621         m_context->disableVertexAttribArray(index);
1622 }
1623
1624 bool WebGLRenderingContextBase::validateNPOTTextureLevel(GC3Dsizei width, GC3Dsizei height, GC3Dint level, const char* functionName)
1625 {
1626     if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1627         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level > 0 not power of 2");
1628         return false;
1629     }
1630
1631     return true;
1632 }
1633
1634 bool WebGLRenderingContextBase::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1635 {
1636     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1637     
1638     if (!elementArrayBuffer)
1639         return false;
1640
1641     if (offset < 0)
1642         return false;
1643
1644     if (type == GraphicsContext3D::UNSIGNED_INT) {
1645         // For an unsigned int array, offset must be divisible by 4 for alignment reasons.
1646         if (offset % 4)
1647             return false;
1648
1649         // Make uoffset an element offset.
1650         offset /= 4;
1651
1652         GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 4;
1653         if (offset > n || count > n - offset)
1654             return false;
1655     } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1656         // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1657         if (offset % 2)
1658             return false;
1659
1660         // Make uoffset an element offset.
1661         offset /= 2;
1662
1663         GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1664         if (offset > n || count > n - offset)
1665             return false;
1666     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1667         GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1668         if (offset > n || count > n - offset)
1669             return false;
1670     }
1671     return true;
1672 }
1673
1674 bool WebGLRenderingContextBase::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, unsigned& numElementsRequired)
1675 {
1676     ASSERT(count >= 0 && offset >= 0);
1677     unsigned lastIndex = 0;
1678     
1679     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1680
1681     if (!elementArrayBuffer)
1682         return false;
1683
1684     if (!count) {
1685         numElementsRequired = 0;
1686         return true;
1687     }
1688
1689     if (!elementArrayBuffer->elementArrayBuffer())
1690         return false;
1691
1692     unsigned long uoffset = offset;
1693     unsigned long n = count;
1694
1695     if (type == GraphicsContext3D::UNSIGNED_INT) {
1696         // Make uoffset an element offset.
1697         uoffset /= sizeof(GC3Duint);
1698         const GC3Duint* p = static_cast<const GC3Duint*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1699         while (n-- > 0) {
1700             if (*p > lastIndex)
1701                 lastIndex = *p;
1702             ++p;
1703         }
1704     } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1705         // Make uoffset an element offset.
1706         uoffset /= sizeof(GC3Dushort);
1707         const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1708         while (n-- > 0) {
1709             if (*p > lastIndex)
1710                 lastIndex = *p;
1711             ++p;
1712         }
1713     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1714         const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1715         while (n-- > 0) {
1716             if (*p > lastIndex)
1717                 lastIndex = *p;
1718             ++p;
1719         }
1720     }
1721
1722     // Then set the last index in the index array and make sure it is valid.
1723     numElementsRequired = lastIndex + 1;
1724     return numElementsRequired > 0;
1725 }
1726
1727 bool WebGLRenderingContextBase::validateVertexAttributes(unsigned elementCount, unsigned primitiveCount)
1728 {
1729     if (!m_currentProgram)
1730         return false;
1731
1732     // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1733     for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1734         if (!m_boundVertexArrayObject->getVertexAttribState(i).validateBinding())
1735             return false;
1736     }
1737
1738     if (elementCount <= 0)
1739         return true;
1740
1741     // Look in each consumed vertex attrib (by the current program).
1742     bool sawNonInstancedAttrib = false;
1743     bool sawEnabledAttrib = false;
1744     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1745     for (int i = 0; i < numActiveAttribLocations; ++i) {
1746         int loc = m_currentProgram->getActiveAttribLocation(i);
1747         if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1748             const WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1749             if (state.enabled) {
1750                 sawEnabledAttrib = true;
1751                 // Avoid off-by-one errors in numElements computation.
1752                 // For the last element, we will only touch the data for the
1753                 // element and nothing beyond it.
1754                 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1755                 unsigned numElements = 0;
1756                 ASSERT(state.stride > 0);
1757                 if (bytesRemaining >= state.bytesPerElement)
1758                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1759                 unsigned instancesRequired = 0;
1760                 if (state.divisor) {
1761                     instancesRequired = ceil(static_cast<float>(primitiveCount) / state.divisor);
1762                     if (instancesRequired > numElements)
1763                         return false;
1764                 } else {
1765                     sawNonInstancedAttrib = true;
1766                     if (elementCount > numElements)
1767                         return false;
1768                 }
1769             }
1770         }
1771     }
1772
1773     if (!sawNonInstancedAttrib && sawEnabledAttrib)
1774         return false;
1775
1776     bool usingSimulatedArrayBuffer = m_currentProgram->isUsingVertexAttrib0();
1777
1778     // Guard against access into non-existent buffers.
1779     if (elementCount && !sawEnabledAttrib && !usingSimulatedArrayBuffer)
1780         return false;
1781
1782     if (elementCount && sawEnabledAttrib) {
1783         if (!m_boundArrayBuffer && !m_boundVertexArrayObject->getElementArrayBuffer()) {
1784             if (usingSimulatedArrayBuffer) {
1785                 auto& state = m_boundVertexArrayObject->getVertexAttribState(0);
1786                 if (state.enabled && state.isBound()) {
1787                     if (state.bufferBinding->getTarget() == GraphicsContext3D::ARRAY_BUFFER || state.bufferBinding->getTarget() == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
1788                         return !!state.bufferBinding->byteLength();
1789                 }
1790             }
1791             return false;
1792         }
1793     }
1794     
1795     return true;
1796 }
1797
1798 bool WebGLRenderingContextBase::validateWebGLObject(const char* functionName, WebGLObject* object)
1799 {
1800     if (!object || !object->object()) {
1801         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no object or object deleted");
1802         return false;
1803     }
1804     if (!object->validate(contextGroup(), *this)) {
1805         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object does not belong to this context");
1806         return false;
1807     }
1808     return true;
1809 }
1810
1811 bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primitiveCount)
1812 {
1813     if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
1814         return false;
1815
1816     if (!validateStencilSettings(functionName))
1817         return false;
1818
1819     if (first < 0 || count < 0) {
1820         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "first or count < 0");
1821         return false;
1822     }
1823
1824     if (!count) {
1825         markContextChanged();
1826         return false;
1827     }
1828
1829     if (primitiveCount < 0) {
1830         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
1831         return false;
1832     }
1833
1834     // Ensure we have a valid rendering state.
1835     Checked<GC3Dint, RecordOverflow> checkedFirst(first);
1836     Checked<GC3Dint, RecordOverflow> checkedCount(count);
1837     Checked<GC3Dint, RecordOverflow> checkedSum = checkedFirst + checkedCount;
1838     Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
1839     if (checkedSum.hasOverflowed() || checkedPrimitiveCount.hasOverflowed() || !validateVertexAttributes(checkedSum.unsafeGet(), checkedPrimitiveCount.unsafeGet())) {
1840         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
1841         return false;
1842     }
1843     if (!validateSimulatedVertexAttrib0(checkedSum.unsafeGet() - 1)) {
1844         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access outside the bounds of the simulated vertexAttrib0 array");
1845         return false;
1846     }
1847
1848     const char* reason = "framebuffer incomplete";
1849     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
1850         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
1851         return false;
1852     }
1853
1854     return true;
1855 }
1856
1857 bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primitiveCount)
1858 {
1859     if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
1860         return false;
1861     
1862     if (!validateStencilSettings(functionName))
1863         return false;
1864     
1865     switch (type) {
1866     case GraphicsContext3D::UNSIGNED_BYTE:
1867     case GraphicsContext3D::UNSIGNED_SHORT:
1868         break;
1869     case GraphicsContext3D::UNSIGNED_INT:
1870         if (m_oesElementIndexUint || isWebGL2())
1871             break;
1872         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
1873         return false;
1874     default:
1875         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
1876         return false;
1877     }
1878     
1879     if (count < 0 || offset < 0) {
1880         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "count or offset < 0");
1881         return false;
1882     }
1883     
1884     if (!count) {
1885         markContextChanged();
1886         return false;
1887     }
1888     
1889     if (primitiveCount < 0) {
1890         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
1891         return false;
1892     }
1893     
1894     if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1895         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
1896         return false;
1897     }
1898
1899     // Ensure we have a valid rendering state.
1900     if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
1901         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "request out of bounds for current ELEMENT_ARRAY_BUFFER");
1902         return false;
1903     }
1904     if (!count)
1905         return false;
1906     
1907     Checked<GC3Dint, RecordOverflow> checkedCount(count);
1908     Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
1909     if (checkedCount.hasOverflowed() || checkedPrimitiveCount.hasOverflowed()) {
1910         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
1911         return false;
1912     }
1913     
1914     if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
1915         if (!validateIndexArrayPrecise(checkedCount.unsafeGet(), type, static_cast<GC3Dintptr>(offset), numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
1916             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
1917             return false;
1918         }
1919     }
1920
1921     if (!validateSimulatedVertexAttrib0(numElements)) {
1922         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access outside the bounds of the simulated vertexAttrib0 array");
1923         return false;
1924     }
1925     
1926     const char* reason = "framebuffer incomplete";
1927     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
1928         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
1929         return false;
1930     }
1931     
1932     return true;
1933 }
1934
1935 void WebGLRenderingContextBase::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count)
1936 {
1937     if (!validateDrawArrays("drawArrays", mode, first, count, 0))
1938         return;
1939
1940     clearIfComposited();
1941
1942     bool vertexAttrib0Simulated = false;
1943     if (!isGLES2Compliant())
1944         vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1945     bool usesFallbackTexture = false;
1946     if (!isGLES2NPOTStrict())
1947         usesFallbackTexture = checkTextureCompleteness("drawArrays", true);
1948
1949     m_context->drawArrays(mode, first, count);
1950
1951     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1952         restoreStatesAfterVertexAttrib0Simulation();
1953     if (usesFallbackTexture)
1954         checkTextureCompleteness("drawArrays", false);
1955     markContextChanged();
1956 }
1957
1958 void WebGLRenderingContextBase::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset)
1959 {
1960     unsigned numElements = 0;
1961     if (!validateDrawElements("drawElements", mode, count, type, offset, numElements, 0))
1962         return;
1963
1964     clearIfComposited();
1965
1966     bool vertexAttrib0Simulated = false;
1967     if (!isGLES2Compliant()) {
1968         if (!numElements)
1969             validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
1970         vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1971     }
1972
1973     bool usesFallbackTexture = false;
1974     if (!isGLES2NPOTStrict())
1975         usesFallbackTexture = checkTextureCompleteness("drawElements", true);
1976
1977     m_context->drawElements(mode, count, type, static_cast<GC3Dintptr>(offset));
1978
1979     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1980         restoreStatesAfterVertexAttrib0Simulation();
1981     if (usesFallbackTexture)
1982         checkTextureCompleteness("drawElements", false);
1983     markContextChanged();
1984 }
1985
1986 void WebGLRenderingContextBase::enable(GC3Denum cap)
1987 {
1988     if (isContextLostOrPending() || !validateCapability("enable", cap))
1989         return;
1990     if (cap == GraphicsContext3D::STENCIL_TEST) {
1991         m_stencilEnabled = true;
1992         applyStencilTest();
1993         return;
1994     }
1995     if (cap == GraphicsContext3D::SCISSOR_TEST)
1996         m_scissorEnabled = true;
1997     m_context->enable(cap);
1998 }
1999
2000 void WebGLRenderingContextBase::enableVertexAttribArray(GC3Duint index)
2001 {
2002     if (isContextLostOrPending())
2003         return;
2004     if (index >= m_maxVertexAttribs) {
2005         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "enableVertexAttribArray", "index out of range");
2006         return;
2007     }
2008
2009     WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2010     state.enabled = true;
2011
2012     m_context->enableVertexAttribArray(index);
2013 }
2014
2015 void WebGLRenderingContextBase::finish()
2016 {
2017     if (isContextLostOrPending())
2018         return;
2019     m_context->finish();
2020 }
2021
2022 void WebGLRenderingContextBase::flush()
2023 {
2024     if (isContextLostOrPending())
2025         return;
2026     m_context->flush();
2027 }
2028
2029 void WebGLRenderingContextBase::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer)
2030 {
2031     if (isContextLostOrPending() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
2032         return;
2033     if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
2034         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
2035         return;
2036     }
2037     if (buffer && !buffer->validate(contextGroup(), *this)) {
2038         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
2039         return;
2040     }
2041     // Don't allow the default framebuffer to be mutated; all current
2042     // implementations use an FBO internally in place of the default
2043     // FBO.
2044     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2045         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
2046         return;
2047     }
2048     Platform3DObject bufferObject = objectOrZero(buffer);
2049     switch (attachment) {
2050     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2051         m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
2052         m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
2053         break;
2054     default:
2055         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
2056     }
2057     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
2058     applyStencilTest();
2059 }
2060
2061 void WebGLRenderingContextBase::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level)
2062 {
2063     if (isContextLostOrPending() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
2064         return;
2065     if (level) {
2066         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "framebufferTexture2D", "level not 0");
2067         return;
2068     }
2069     if (texture && !texture->validate(contextGroup(), *this)) {
2070         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
2071         return;
2072     }
2073     // Don't allow the default framebuffer to be mutated; all current
2074     // implementations use an FBO internally in place of the default
2075     // FBO.
2076     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2077         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
2078         return;
2079     }
2080     Platform3DObject textureObject = objectOrZero(texture);
2081     switch (attachment) {
2082     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2083         m_context->framebufferTexture2D(target, GraphicsContext3D::DEPTH_ATTACHMENT, textarget, textureObject, level);
2084         m_context->framebufferTexture2D(target, GraphicsContext3D::STENCIL_ATTACHMENT, textarget, textureObject, level);
2085         break;
2086     case GraphicsContext3D::DEPTH_ATTACHMENT:
2087         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2088         break;
2089     case GraphicsContext3D::STENCIL_ATTACHMENT:
2090         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2091         break;
2092     default:
2093         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2094     }
2095     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
2096     applyStencilTest();
2097 }
2098
2099 void WebGLRenderingContextBase::frontFace(GC3Denum mode)
2100 {
2101     if (isContextLostOrPending())
2102         return;
2103     m_context->frontFace(mode);
2104 }
2105
2106 void WebGLRenderingContextBase::generateMipmap(GC3Denum target)
2107 {
2108     if (isContextLostOrPending())
2109         return;
2110     WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
2111     if (!tex)
2112         return;
2113     if (!tex->canGenerateMipmaps()) {
2114         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
2115         return;
2116     }
2117     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=123916. Compressed textures should be allowed in WebGL 2:
2118     if (tex->isCompressed()) {
2119         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "trying to generate mipmaps from compressed texture");
2120         return;
2121     }
2122     if (!validateSettableTexInternalFormat("generateMipmap", tex->getInternalFormat(target, 0)))
2123         return;
2124
2125     // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
2126     // on Mac.  Remove the hack once this driver bug is fixed.
2127 #if OS(DARWIN)
2128     bool needToResetMinFilter = false;
2129     if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
2130         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
2131         needToResetMinFilter = true;
2132     }
2133 #endif
2134     m_context->generateMipmap(target);
2135 #if OS(DARWIN)
2136     if (needToResetMinFilter)
2137         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
2138 #endif
2139     tex->generateMipmapLevelInfo();
2140 }
2141
2142 RefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveAttrib(WebGLProgram* program, GC3Duint index)
2143 {
2144     if (isContextLostOrPending() || !validateWebGLObject("getActiveAttrib", program))
2145         return nullptr;
2146     ActiveInfo info;
2147     if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
2148         return nullptr;
2149
2150     LOG(WebGL, "Returning active attribute %d: %s", index, info.name.utf8().data());
2151
2152     return WebGLActiveInfo::create(info.name, info.type, info.size);
2153 }
2154
2155 RefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveUniform(WebGLProgram* program, GC3Duint index)
2156 {
2157     if (isContextLostOrPending() || !validateWebGLObject("getActiveUniform", program))
2158         return nullptr;
2159     ActiveInfo info;
2160     if (!m_context->getActiveUniform(objectOrZero(program), index, info))
2161         return nullptr;
2162     if (!isGLES2Compliant())
2163         if (info.size > 1 && !info.name.endsWith("[0]"))
2164             info.name.append("[0]");
2165
2166     LOG(WebGL, "Returning active uniform %d: %s", index, info.name.utf8().data());
2167
2168     return WebGLActiveInfo::create(info.name, info.type, info.size);
2169 }
2170
2171 std::optional<Vector<RefPtr<WebGLShader>>> WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program)
2172 {
2173     if (isContextLostOrPending() || !validateWebGLObject("getAttachedShaders", program))
2174         return std::nullopt;
2175
2176     const GC3Denum shaderTypes[] = {
2177         GraphicsContext3D::VERTEX_SHADER,
2178         GraphicsContext3D::FRAGMENT_SHADER
2179     };
2180     Vector<RefPtr<WebGLShader>> shaderObjects;
2181     for (auto shaderType : shaderTypes) {
2182         WebGLShader* shader = program->getAttachedShader(shaderType);
2183         if (shader)
2184             shaderObjects.append(shader);
2185     }
2186     return shaderObjects;
2187 }
2188
2189 GC3Dint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String& name)
2190 {
2191     if (isContextLostOrPending() || !validateWebGLObject("getAttribLocation", program))
2192         return -1;
2193     if (!validateLocationLength("getAttribLocation", name))
2194         return -1;
2195     if (!validateString("getAttribLocation", name))
2196         return -1;
2197     if (isPrefixReserved(name))
2198         return -1;
2199     if (!program->getLinkStatus()) {
2200         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getAttribLocation", "program not linked");
2201         return -1;
2202     }
2203     return m_context->getAttribLocation(objectOrZero(program), name);
2204 }
2205
2206 WebGLAny WebGLRenderingContextBase::getBufferParameter(GC3Denum target, GC3Denum pname)
2207 {
2208     if (isContextLostOrPending())
2209         return nullptr;
2210
2211     bool valid = false;
2212     if (target == GraphicsContext3D::ARRAY_BUFFER || target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
2213         valid = true;
2214 #if ENABLE(WEBGL2)
2215     if (isWebGL2()) {
2216         switch (target) {
2217         case GraphicsContext3D::COPY_READ_BUFFER:
2218         case GraphicsContext3D::COPY_WRITE_BUFFER:
2219         case GraphicsContext3D::PIXEL_PACK_BUFFER:
2220         case GraphicsContext3D::PIXEL_UNPACK_BUFFER:
2221         case GraphicsContext3D::TRANSFORM_FEEDBACK_BUFFER:
2222         case GraphicsContext3D::UNIFORM_BUFFER:
2223             valid = true;
2224         }
2225     }
2226 #endif
2227     if (!valid) {
2228         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid target");
2229         return nullptr;
2230     }
2231
2232     if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
2233         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2234         return nullptr;
2235     }
2236
2237     GC3Dint value = 0;
2238     m_context->getBufferParameteriv(target, pname, &value);
2239     if (pname == GraphicsContext3D::BUFFER_SIZE)
2240         return value;
2241     return static_cast<unsigned>(value);
2242 }
2243
2244 std::optional<WebGLContextAttributes> WebGLRenderingContextBase::getContextAttributes()
2245 {
2246     if (isContextLostOrPending())
2247         return std::nullopt;
2248
2249     // Also, we need to enforce requested values of "false" for depth
2250     // and stencil, regardless of the properties of the underlying
2251     // GraphicsContext3D.
2252
2253     auto attributes = m_context->getContextAttributes();
2254     if (!m_attributes.depth)
2255         attributes.depth = false;
2256     if (!m_attributes.stencil)
2257         attributes.stencil = false;
2258     return WTFMove(attributes);
2259 }
2260
2261 GC3Denum WebGLRenderingContextBase::getError()
2262 {
2263     if (m_isPendingPolicyResolution)
2264         return GraphicsContext3D::NO_ERROR;
2265     return m_context->getError();
2266 }
2267
2268 WebGLAny WebGLRenderingContextBase::getProgramParameter(WebGLProgram* program, GC3Denum pname)
2269 {
2270     if (isContextLostOrPending() || !validateWebGLObject("getProgramParameter", program))
2271         return nullptr;
2272
2273     GC3Dint value = 0;
2274     switch (pname) {
2275     case GraphicsContext3D::DELETE_STATUS:
2276         return program->isDeleted();
2277     case GraphicsContext3D::VALIDATE_STATUS:
2278         m_context->getProgramiv(objectOrZero(program), pname, &value);
2279         return static_cast<bool>(value);
2280     case GraphicsContext3D::LINK_STATUS:
2281         return program->getLinkStatus();
2282     case GraphicsContext3D::ATTACHED_SHADERS:
2283         m_context->getProgramiv(objectOrZero(program), pname, &value);
2284         return value;
2285     case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2286     case GraphicsContext3D::ACTIVE_UNIFORMS:
2287         m_context->getNonBuiltInActiveSymbolCount(objectOrZero(program), pname, &value);
2288         return value;
2289     default:
2290         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2291         return nullptr;
2292     }
2293 }
2294
2295 String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program)
2296 {
2297     if (isContextLostOrPending() || !validateWebGLObject("getProgramInfoLog", program))
2298         return String();
2299     return ensureNotNull(m_context->getProgramInfoLog(objectOrZero(program)));
2300 }
2301
2302 WebGLAny WebGLRenderingContextBase::getRenderbufferParameter(GC3Denum target, GC3Denum pname)
2303 {
2304     if (isContextLostOrPending())
2305         return nullptr;
2306     if (target != GraphicsContext3D::RENDERBUFFER) {
2307         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2308         return nullptr;
2309     }
2310     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2311         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2312         return nullptr;
2313     }
2314
2315     if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2316         && !m_renderbufferBinding->isValid()) {
2317         ASSERT(!isDepthStencilSupported());
2318         int value = 0;
2319         switch (pname) {
2320         case GraphicsContext3D::RENDERBUFFER_WIDTH:
2321             value = m_renderbufferBinding->getWidth();
2322             break;
2323         case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2324             value = m_renderbufferBinding->getHeight();
2325             break;
2326         case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2327         case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2328         case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2329         case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2330             value = 0;
2331             break;
2332         case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2333             value = 24;
2334             break;
2335         case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2336             value = 8;
2337             break;
2338         case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2339             return m_renderbufferBinding->getInternalFormat();
2340         default:
2341             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2342             return nullptr;
2343         }
2344         return value;
2345     }
2346
2347     GC3Dint value = 0;
2348     switch (pname) {
2349     case GraphicsContext3D::RENDERBUFFER_WIDTH:
2350     case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2351     case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2352     case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2353     case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2354     case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2355     case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2356     case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2357         m_context->getRenderbufferParameteriv(target, pname, &value);
2358         return value;
2359     case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2360         return m_renderbufferBinding->getInternalFormat();
2361     default:
2362         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2363         return nullptr;
2364     }
2365 }
2366
2367 WebGLAny WebGLRenderingContextBase::getShaderParameter(WebGLShader* shader, GC3Denum pname)
2368 {
2369     if (isContextLostOrPending() || !validateWebGLObject("getShaderParameter", shader))
2370         return nullptr;
2371     GC3Dint value = 0;
2372     switch (pname) {
2373     case GraphicsContext3D::DELETE_STATUS:
2374         return shader->isDeleted();
2375     case GraphicsContext3D::COMPILE_STATUS:
2376         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2377         return static_cast<bool>(value);
2378     case GraphicsContext3D::SHADER_TYPE:
2379         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2380         return static_cast<unsigned>(value);
2381     default:
2382         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderParameter", "invalid parameter name");
2383         return nullptr;
2384     }
2385 }
2386
2387 String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader)
2388 {
2389     if (isContextLostOrPending() || !validateWebGLObject("getShaderInfoLog", shader))
2390         return String();
2391     return ensureNotNull(m_context->getShaderInfoLog(objectOrZero(shader)));
2392 }
2393
2394 RefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContextBase::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType)
2395 {
2396     if (isContextLostOrPending())
2397         return nullptr;
2398     switch (shaderType) {
2399     case GraphicsContext3D::VERTEX_SHADER:
2400     case GraphicsContext3D::FRAGMENT_SHADER:
2401         break;
2402     default:
2403         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
2404         return nullptr;
2405     }
2406     switch (precisionType) {
2407     case GraphicsContext3D::LOW_FLOAT:
2408     case GraphicsContext3D::MEDIUM_FLOAT:
2409     case GraphicsContext3D::HIGH_FLOAT:
2410     case GraphicsContext3D::LOW_INT:
2411     case GraphicsContext3D::MEDIUM_INT:
2412     case GraphicsContext3D::HIGH_INT:
2413         break;
2414     default:
2415         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
2416         return nullptr;
2417     }
2418
2419     GC3Dint range[2] = {0, 0};
2420     GC3Dint precision = 0;
2421     m_context->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
2422     return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
2423 }
2424
2425 String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader)
2426 {
2427     if (isContextLostOrPending() || !validateWebGLObject("getShaderSource", shader))
2428         return String();
2429     return ensureNotNull(shader->getSource());
2430 }
2431
2432 WebGLAny WebGLRenderingContextBase::getTexParameter(GC3Denum target, GC3Denum pname)
2433 {
2434     if (isContextLostOrPending())
2435         return nullptr;
2436     WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
2437     if (!tex)
2438         return nullptr;
2439     GC3Dint value = 0;
2440     switch (pname) {
2441     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2442     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2443     case GraphicsContext3D::TEXTURE_WRAP_S:
2444     case GraphicsContext3D::TEXTURE_WRAP_T:
2445         m_context->getTexParameteriv(target, pname, &value);
2446         return static_cast<unsigned>(value);
2447     case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2448         if (m_extTextureFilterAnisotropic) {
2449             m_context->getTexParameteriv(target, pname, &value);
2450             return static_cast<unsigned>(value);
2451         }
2452         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2453         return nullptr;
2454     default:
2455         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name");
2456         return nullptr;
2457     }
2458 }
2459
2460 WebGLAny WebGLRenderingContextBase::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation)
2461 {
2462     if (isContextLostOrPending() || !validateWebGLObject("getUniform", program))
2463         return nullptr;
2464     if (!uniformLocation || uniformLocation->program() != program) {
2465         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
2466         return nullptr;
2467     }
2468     GC3Dint location = uniformLocation->location();
2469
2470     GC3Denum baseType;
2471     unsigned length;
2472     switch (uniformLocation->type()) {
2473     case GraphicsContext3D::BOOL:
2474         baseType = GraphicsContext3D::BOOL;
2475         length = 1;
2476         break;
2477     case GraphicsContext3D::BOOL_VEC2:
2478         baseType = GraphicsContext3D::BOOL;
2479         length = 2;
2480         break;
2481     case GraphicsContext3D::BOOL_VEC3:
2482         baseType = GraphicsContext3D::BOOL;
2483         length = 3;
2484         break;
2485     case GraphicsContext3D::BOOL_VEC4:
2486         baseType = GraphicsContext3D::BOOL;
2487         length = 4;
2488         break;
2489     case GraphicsContext3D::INT:
2490         baseType = GraphicsContext3D::INT;
2491         length = 1;
2492         break;
2493     case GraphicsContext3D::INT_VEC2:
2494         baseType = GraphicsContext3D::INT;
2495         length = 2;
2496         break;
2497     case GraphicsContext3D::INT_VEC3:
2498         baseType = GraphicsContext3D::INT;
2499         length = 3;
2500         break;
2501     case GraphicsContext3D::INT_VEC4:
2502         baseType = GraphicsContext3D::INT;
2503         length = 4;
2504         break;
2505     case GraphicsContext3D::FLOAT:
2506         baseType = GraphicsContext3D::FLOAT;
2507         length = 1;
2508         break;
2509     case GraphicsContext3D::FLOAT_VEC2:
2510         baseType = GraphicsContext3D::FLOAT;
2511         length = 2;
2512         break;
2513     case GraphicsContext3D::FLOAT_VEC3:
2514         baseType = GraphicsContext3D::FLOAT;
2515         length = 3;
2516         break;
2517     case GraphicsContext3D::FLOAT_VEC4:
2518         baseType = GraphicsContext3D::FLOAT;
2519         length = 4;
2520         break;
2521     case GraphicsContext3D::FLOAT_MAT2:
2522         baseType = GraphicsContext3D::FLOAT;
2523         length = 4;
2524         break;
2525     case GraphicsContext3D::FLOAT_MAT3:
2526         baseType = GraphicsContext3D::FLOAT;
2527         length = 9;
2528         break;
2529     case GraphicsContext3D::FLOAT_MAT4:
2530         baseType = GraphicsContext3D::FLOAT;
2531         length = 16;
2532         break;
2533     case GraphicsContext3D::SAMPLER_2D:
2534     case GraphicsContext3D::SAMPLER_CUBE:
2535         baseType = GraphicsContext3D::INT;
2536         length = 1;
2537         break;
2538     default:
2539         // Can't handle this type
2540         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unhandled type");
2541         return nullptr;
2542     }
2543     switch (baseType) {
2544     case GraphicsContext3D::FLOAT: {
2545         GC3Dfloat value[16] = {0};
2546         if (m_isRobustnessEXTSupported)
2547             m_context->getExtensions().getnUniformfvEXT(objectOrZero(program), location, 16 * sizeof(GC3Dfloat), value);
2548         else
2549             m_context->getUniformfv(objectOrZero(program), location, value);
2550         if (length == 1)
2551             return value[0];
2552         return Float32Array::create(value, length);
2553     }
2554     case GraphicsContext3D::INT: {
2555         GC3Dint value[4] = {0};
2556         if (m_isRobustnessEXTSupported)
2557             m_context->getExtensions().getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
2558         else
2559             m_context->getUniformiv(objectOrZero(program), location, value);
2560         if (length == 1)
2561             return value[0];
2562         return Int32Array::create(value, length);
2563     }
2564     case GraphicsContext3D::BOOL: {
2565         GC3Dint value[4] = {0};
2566         if (m_isRobustnessEXTSupported)
2567             m_context->getExtensions().getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
2568         else
2569             m_context->getUniformiv(objectOrZero(program), location, value);
2570         if (length > 1) {
2571             Vector<bool> vector(length);
2572             for (unsigned j = 0; j < length; j++)
2573                 vector[j] = value[j];
2574             return WTFMove(vector);
2575         }
2576         return static_cast<bool>(value[0]);
2577     }
2578     default:
2579         notImplemented();
2580     }
2581
2582     // If we get here, something went wrong in our unfortunately complex logic above
2583     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unknown error");
2584     return nullptr;
2585 }
2586
2587 RefPtr<WebGLUniformLocation> WebGLRenderingContextBase::getUniformLocation(WebGLProgram* program, const String& name)
2588 {
2589     if (isContextLostOrPending() || !validateWebGLObject("getUniformLocation", program))
2590         return nullptr;
2591     if (!validateLocationLength("getUniformLocation", name))
2592         return nullptr;
2593     if (!validateString("getUniformLocation", name))
2594         return nullptr;
2595     if (isPrefixReserved(name))
2596         return nullptr;
2597     if (!program->getLinkStatus()) {
2598         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniformLocation", "program not linked");
2599         return nullptr;
2600     }
2601     GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2602     if (uniformLocation == -1)
2603         return nullptr;
2604
2605     GC3Dint activeUniforms = 0;
2606     m_context->getNonBuiltInActiveSymbolCount(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2607     for (GC3Dint i = 0; i < activeUniforms; i++) {
2608         ActiveInfo info;
2609         if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2610             return nullptr;
2611         // Strip "[0]" from the name if it's an array.
2612         if (info.name.endsWith("[0]"))
2613             info.name = info.name.left(info.name.length() - 3);
2614         // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2615         for (GC3Dint index = 0; index < info.size; ++index) {
2616             String uniformName = info.name + "[" + String::number(index) + "]";
2617
2618             if (name == uniformName || name == info.name)
2619                 return WebGLUniformLocation::create(program, uniformLocation, info.type);
2620         }
2621     }
2622     return nullptr;
2623 }
2624
2625 WebGLAny WebGLRenderingContextBase::getVertexAttrib(GC3Duint index, GC3Denum pname)
2626 {
2627     if (isContextLostOrPending())
2628         return nullptr;
2629
2630     if (index >= m_maxVertexAttribs) {
2631         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
2632         return nullptr;
2633     }
2634
2635     const WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2636
2637     if ((isWebGL2() || m_angleInstancedArrays) && pname == GraphicsContext3D::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)
2638         return state.divisor;
2639
2640     switch (pname) {
2641     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2642         if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
2643             || !state.bufferBinding
2644             || !state.bufferBinding->object())
2645             return nullptr;
2646         return state.bufferBinding;
2647     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
2648         return state.enabled;
2649     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
2650         return state.normalized;
2651     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
2652         return state.size;
2653     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
2654         return state.originalStride;
2655     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
2656         return state.type;
2657     case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
2658         return Float32Array::create(m_vertexAttribValue[index].value, 4);
2659     default:
2660         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
2661         return nullptr;
2662     }
2663 }
2664
2665 long long WebGLRenderingContextBase::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
2666 {
2667     if (isContextLostOrPending())
2668         return 0;
2669     return m_context->getVertexAttribOffset(index, pname);
2670 }
2671
2672 GC3Dboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer)
2673 {
2674     if (!buffer || isContextLostOrPending())
2675         return 0;
2676
2677     if (!buffer->hasEverBeenBound())
2678         return 0;
2679
2680     return m_context->isBuffer(buffer->object());
2681 }
2682
2683 bool WebGLRenderingContextBase::isContextLost() const
2684 {
2685     return m_contextLost;
2686 }
2687
2688 bool WebGLRenderingContextBase::isContextLostOrPending()
2689 {
2690     if (m_isPendingPolicyResolution && !m_hasRequestedPolicyResolution) {
2691         LOG(WebGL, "Context is being used. Attempt to resolve the policy.");
2692         Document& document = canvas().document().topDocument();
2693         Page* page = document.page();
2694         if (page && !document.url().isLocalFile())
2695             page->mainFrame().loader().client().resolveWebGLPolicyForURL(document.url());
2696         // FIXME: We don't currently do anything with the result from resolution. A more
2697         // complete implementation might try to construct a real context, etc and proceed
2698         // with normal operation.
2699         // https://bugs.webkit.org/show_bug.cgi?id=129122
2700         m_hasRequestedPolicyResolution = true;
2701     }
2702
2703     return m_contextLost || m_isPendingPolicyResolution;
2704 }
2705
2706 GC3Dboolean WebGLRenderingContextBase::isEnabled(GC3Denum cap)
2707 {
2708     if (isContextLostOrPending() || !validateCapability("isEnabled", cap))
2709         return 0;
2710     if (cap == GraphicsContext3D::STENCIL_TEST)
2711         return m_stencilEnabled;
2712     return m_context->isEnabled(cap);
2713 }
2714
2715 GC3Dboolean WebGLRenderingContextBase::isFramebuffer(WebGLFramebuffer* framebuffer)
2716 {
2717     if (!framebuffer || isContextLostOrPending())
2718         return 0;
2719
2720     if (!framebuffer->hasEverBeenBound())
2721         return 0;
2722
2723     return m_context->isFramebuffer(framebuffer->object());
2724 }
2725
2726 GC3Dboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program)
2727 {
2728     if (!program || isContextLostOrPending())
2729         return 0;
2730
2731     return m_context->isProgram(program->object());
2732 }
2733
2734 GC3Dboolean WebGLRenderingContextBase::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2735 {
2736     if (!renderbuffer || isContextLostOrPending())
2737         return 0;
2738
2739     if (!renderbuffer->hasEverBeenBound())
2740         return 0;
2741
2742     return m_context->isRenderbuffer(renderbuffer->object());
2743 }
2744
2745 GC3Dboolean WebGLRenderingContextBase::isShader(WebGLShader* shader)
2746 {
2747     if (!shader || isContextLostOrPending())
2748         return 0;
2749
2750     return m_context->isShader(shader->object());
2751 }
2752
2753 GC3Dboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture)
2754 {
2755     if (!texture || isContextLostOrPending())
2756         return 0;
2757
2758     if (!texture->hasEverBeenBound())
2759         return 0;
2760
2761     return m_context->isTexture(texture->object());
2762 }
2763
2764 void WebGLRenderingContextBase::lineWidth(GC3Dfloat width)
2765 {
2766     if (isContextLostOrPending())
2767         return;
2768     m_context->lineWidth(width);
2769 }
2770
2771 void WebGLRenderingContextBase::linkProgram(WebGLProgram* program)
2772 {
2773     if (isContextLostOrPending() || !validateWebGLObject("linkProgram", program))
2774         return;
2775     WebGLShader* vertexShader = program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER);
2776     WebGLShader* fragmentShader = program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER);
2777     if (!vertexShader || !vertexShader->isValid() || !fragmentShader || !fragmentShader->isValid() || !m_context->precisionsMatch(objectOrZero(vertexShader), objectOrZero(fragmentShader)) || !m_context->checkVaryingsPacking(objectOrZero(vertexShader), objectOrZero(fragmentShader))) {
2778         program->setLinkStatus(false);
2779         return;
2780     }
2781
2782     m_context->linkProgram(objectOrZero(program));
2783     program->increaseLinkCount();
2784 }
2785
2786 void WebGLRenderingContextBase::pixelStorei(GC3Denum pname, GC3Dint param)
2787 {
2788     if (isContextLostOrPending())
2789         return;
2790     switch (pname) {
2791     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2792         m_unpackFlipY = param;
2793         break;
2794     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2795         m_unpackPremultiplyAlpha = param;
2796         break;
2797     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2798         if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
2799             m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
2800         else {
2801             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
2802             return;
2803         }
2804         break;
2805     case GraphicsContext3D::PACK_ALIGNMENT:
2806     case GraphicsContext3D::UNPACK_ALIGNMENT:
2807         if (param == 1 || param == 2 || param == 4 || param == 8) {
2808             if (pname == GraphicsContext3D::PACK_ALIGNMENT)
2809                 m_packAlignment = param;
2810             else // GraphicsContext3D::UNPACK_ALIGNMENT:
2811                 m_unpackAlignment = param;
2812             m_context->pixelStorei(pname, param);
2813         } else {
2814             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
2815             return;
2816         }
2817         break;
2818     default:
2819         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "pixelStorei", "invalid parameter name");
2820         return;
2821     }
2822 }
2823
2824 void WebGLRenderingContextBase::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
2825 {
2826     if (isContextLostOrPending())
2827         return;
2828     m_context->polygonOffset(factor, units);
2829 }
2830
2831 enum class InternalFormatTheme {
2832     None,
2833     NormalizedFixedPoint,
2834     Packed,
2835     SignedNormalizedFixedPoint,
2836     FloatingPoint,
2837     SignedInteger,
2838     UnsignedInteger
2839 };
2840
2841 static InternalFormatTheme internalFormatTheme(GC3Denum internalFormat)
2842 {
2843     switch (internalFormat) {
2844     case GraphicsContext3D::RGB:
2845     case GraphicsContext3D::RGBA:
2846     case GraphicsContext3D::LUMINANCE_ALPHA:
2847     case GraphicsContext3D::LUMINANCE:
2848     case GraphicsContext3D::ALPHA:
2849     case GraphicsContext3D::R8:
2850     case GraphicsContext3D::RG8:
2851     case GraphicsContext3D::RGB8:
2852     case GraphicsContext3D::SRGB8:
2853     case GraphicsContext3D::RGBA8:
2854     case GraphicsContext3D::SRGB8_ALPHA8:
2855     case GraphicsContext3D::SRGB_ALPHA:
2856         return InternalFormatTheme::NormalizedFixedPoint;
2857     case GraphicsContext3D::RGB565:
2858     case GraphicsContext3D::RGB5_A1:
2859     case GraphicsContext3D::RGBA4:
2860     case GraphicsContext3D::RGB9_E5:
2861     case GraphicsContext3D::RGB10_A2:
2862     case GraphicsContext3D::R11F_G11F_B10F:
2863     case GraphicsContext3D::RGB10_A2UI:
2864         return InternalFormatTheme::Packed;
2865     case GraphicsContext3D::R8_SNORM:
2866     case GraphicsContext3D::RG8_SNORM:
2867     case GraphicsContext3D::RGB8_SNORM:
2868     case GraphicsContext3D::RGBA8_SNORM:
2869         return InternalFormatTheme::SignedNormalizedFixedPoint;
2870     case GraphicsContext3D::R16F:
2871     case GraphicsContext3D::R32F:
2872     case GraphicsContext3D::RG16F:
2873     case GraphicsContext3D::RG32F:
2874     case GraphicsContext3D::RGB16F:
2875     case GraphicsContext3D::RGB32F:
2876     case GraphicsContext3D::RGBA16F:
2877     case GraphicsContext3D::RGBA32F:
2878         return InternalFormatTheme::FloatingPoint;
2879     case GraphicsContext3D::R8I:
2880     case GraphicsContext3D::R16I:
2881     case GraphicsContext3D::R32I:
2882     case GraphicsContext3D::RG8I:
2883     case GraphicsContext3D::RG16I:
2884     case GraphicsContext3D::RG32I:
2885     case GraphicsContext3D::RGB8I:
2886     case GraphicsContext3D::RGB16I:
2887     case GraphicsContext3D::RGB32I:
2888     case GraphicsContext3D::RGBA8I:
2889     case GraphicsContext3D::RGBA16I:
2890     case GraphicsContext3D::RGBA32I:
2891         return InternalFormatTheme::SignedInteger;
2892     case GraphicsContext3D::R8UI:
2893     case GraphicsContext3D::R16UI:
2894     case GraphicsContext3D::R32UI:
2895     case GraphicsContext3D::RG8UI:
2896     case GraphicsContext3D::RG16UI:
2897     case GraphicsContext3D::RG32UI:
2898     case GraphicsContext3D::RGB8UI:
2899     case GraphicsContext3D::RGB16UI:
2900     case GraphicsContext3D::RGB32UI:
2901     case GraphicsContext3D::RGBA8UI:
2902     case GraphicsContext3D::RGBA16UI:
2903     case GraphicsContext3D::RGBA32UI:
2904         return InternalFormatTheme::UnsignedInteger;
2905     default:
2906         return InternalFormatTheme::None;
2907     }
2908 }
2909
2910 static int numberOfComponentsForFormat(GC3Denum format)
2911 {
2912     switch (format) {
2913     case GraphicsContext3D::RED:
2914     case GraphicsContext3D::RED_INTEGER:
2915         return 1;
2916     case GraphicsContext3D::RG:
2917     case GraphicsContext3D::RG_INTEGER:
2918         return 2;
2919     case GraphicsContext3D::RGB:
2920     case GraphicsContext3D::RGB_INTEGER:
2921         return 3;
2922     case GraphicsContext3D::RGBA:
2923     case GraphicsContext3D::RGBA_INTEGER:
2924         return 4;
2925     default:
2926         return 0;
2927     }
2928 }
2929
2930 static int numberOfComponentsForInternalFormat(GC3Denum internalFormat)
2931 {
2932     switch (internalFormat) {
2933     case GraphicsContext3D::LUMINANCE:
2934     case GraphicsContext3D::ALPHA:
2935     case GraphicsContext3D::R8:
2936     case GraphicsContext3D::R8_SNORM:
2937     case GraphicsContext3D::R16F:
2938     case GraphicsContext3D::R32F:
2939     case GraphicsContext3D::R8UI:
2940     case GraphicsContext3D::R8I:
2941     case GraphicsContext3D::R16UI:
2942     case GraphicsContext3D::R16I:
2943     case GraphicsContext3D::R32UI:
2944     case GraphicsContext3D::R32I:
2945     case GraphicsContext3D::DEPTH_COMPONENT16:
2946     case GraphicsContext3D::DEPTH_COMPONENT24:
2947     case GraphicsContext3D::DEPTH_COMPONENT32F:
2948         return 1;
2949     case GraphicsContext3D::RG8:
2950     case GraphicsContext3D::LUMINANCE_ALPHA:
2951     case GraphicsContext3D::RG8_SNORM:
2952     case GraphicsContext3D::RG16F:
2953     case GraphicsContext3D::RG32F:
2954     case GraphicsContext3D::RG8UI:
2955     case GraphicsContext3D::RG8I:
2956     case GraphicsContext3D::RG16UI:
2957     case GraphicsContext3D::RG16I:
2958     case GraphicsContext3D::RG32UI:
2959     case GraphicsContext3D::RG32I:
2960     case GraphicsContext3D::DEPTH24_STENCIL8:
2961     case GraphicsContext3D::DEPTH32F_STENCIL8:
2962         return 2;
2963     case GraphicsContext3D::RGB:
2964     case GraphicsContext3D::RGB8:
2965     case GraphicsContext3D::SRGB8:
2966     case GraphicsContext3D::RGB565:
2967     case GraphicsContext3D::RGB8_SNORM:
2968     case GraphicsContext3D::R11F_G11F_B10F:
2969     case GraphicsContext3D::RGB9_E5:
2970     case GraphicsContext3D::RGB16F:
2971     case GraphicsContext3D::RGB32F:
2972     case GraphicsContext3D::RGB8UI:
2973     case GraphicsContext3D::RGB8I:
2974     case GraphicsContext3D::RGB16UI:
2975     case GraphicsContext3D::RGB16I:
2976     case GraphicsContext3D::RGB32UI:
2977     case GraphicsContext3D::RGB32I:
2978         return 3;
2979     case GraphicsContext3D::RGBA:
2980     case GraphicsContext3D::RGBA8:
2981     case GraphicsContext3D::SRGB_ALPHA:
2982     case GraphicsContext3D::SRGB8_ALPHA8:
2983     case GraphicsContext3D::RGBA8_SNORM:
2984     case GraphicsContext3D::RGB5_A1:
2985     case GraphicsContext3D::RGBA4:
2986     case GraphicsContext3D::RGB10_A2:
2987     case GraphicsContext3D::RGBA16F:
2988     case GraphicsContext3D::RGBA32F:
2989     case GraphicsContext3D::RGBA8UI:
2990     case GraphicsContext3D::RGBA8I:
2991     case GraphicsContext3D::RGB10_A2UI:
2992     case GraphicsContext3D::RGBA16UI:
2993     case GraphicsContext3D::RGBA16I:
2994     case GraphicsContext3D::RGBA32UI:
2995     case GraphicsContext3D::RGBA32I:
2996         return 4;
2997     default:
2998         return 0;
2999     }
3000 }
3001
3002 void WebGLRenderingContextBase::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView& pixels)
3003 {
3004     if (isContextLostOrPending())
3005         return;
3006     // Due to WebGL's same-origin restrictions, it is not possible to
3007     // taint the origin using the WebGL API.
3008     ASSERT(canvas().originClean());
3009
3010     GC3Denum internalFormat = 0;
3011     if (m_framebufferBinding) {
3012         const char* reason = "framebuffer incomplete";
3013         if (!m_framebufferBinding->onAccess(graphicsContext3D(), &reason)) {
3014             synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
3015             return;
3016         }
3017         // FIXME: readBuffer() should affect this
3018         internalFormat = m_framebufferBinding->getColorBufferFormat();
3019     } else {
3020         if (m_attributes.alpha)
3021             internalFormat = GraphicsContext3D::RGB8;
3022         else
3023             internalFormat = GraphicsContext3D::RGBA8;
3024     }
3025
3026     if (!internalFormat) {
3027         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "Incorrect internal format");
3028         return;
3029     }
3030
3031     if (isWebGL1()) {
3032         switch (format) {
3033         case GraphicsContext3D::ALPHA:
3034         case GraphicsContext3D::RGB:
3035         case GraphicsContext3D::RGBA:
3036             break;
3037         default:
3038             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid format");
3039             return;
3040         }
3041         switch (type) {
3042         case GraphicsContext3D::UNSIGNED_BYTE:
3043         case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
3044         case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
3045         case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
3046             break;
3047         default:
3048             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid type");
3049             return;
3050         }
3051         if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
3052             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "format not RGBA or type not UNSIGNED_BYTE");
3053             return;
3054         }
3055     }
3056
3057     InternalFormatTheme internalFormatTheme = WebCore::internalFormatTheme(internalFormat);
3058     int internalFormatComponentCount = numberOfComponentsForInternalFormat(internalFormat);
3059     if (internalFormatTheme == InternalFormatTheme::None || !internalFormatComponentCount) {
3060         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "Incorrect internal format");
3061         return;
3062     }
3063
3064 #define INTERNAL_FORMAT_CHECK(themeMacro, typeMacro, pixelTypeMacro) case InternalFormatTheme::themeMacro: \
3065         if (type != GraphicsContext3D::typeMacro || pixels.getType() != JSC::pixelTypeMacro) { \
3066             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "type does not match internal format"); \
3067             return; \
3068         } \
3069         if (format != GraphicsContext3D::RED && format != GraphicsContext3D::RG && format != GraphicsContext3D::RGB && format != GraphicsContext3D::RGBA) { \
3070             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "Unknown format"); \
3071             return; \
3072         } \
3073         if (numberOfComponentsForFormat(format) < internalFormatComponentCount) { \
3074             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "Not enough components in format"); \
3075             return; \
3076         } \
3077         break;
3078
3079 #define INTERNAL_FORMAT_INTEGER_CHECK(themeMacro, typeMacro, pixelTypeMacro) case InternalFormatTheme::themeMacro: \
3080         if (type != GraphicsContext3D::typeMacro || pixels.getType() != JSC::pixelTypeMacro) { \
3081             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "type does not match internal format"); \
3082             return; \
3083         } \
3084         if (format != GraphicsContext3D::RED_INTEGER && format != GraphicsContext3D::RG_INTEGER && format != GraphicsContext3D::RGB_INTEGER && format != GraphicsContext3D::RGBA_INTEGER) { \
3085             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "Unknown format"); \
3086             return; \
3087         } \
3088         if (numberOfComponentsForFormat(format) < internalFormatComponentCount) { \
3089             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "Not enough components in format"); \
3090             return; \
3091         } \
3092         break;
3093
3094 #define PACKED_INTERNAL_FORMAT_CHECK(internalFormatMacro, formatMacro, type0Macro, pixelType0Macro, type1Macro, pixelType1Macro) case GraphicsContext3D::internalFormatMacro: \
3095         if (!(type == GraphicsContext3D::type0Macro && pixels.getType() == JSC::pixelType0Macro) \
3096             && !(type == GraphicsContext3D::type1Macro && pixels.getType() == JSC::pixelType1Macro)) { \
3097             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "type does not match internal format"); \
3098             return; \
3099         } \
3100         if (format != GraphicsContext3D::formatMacro) { \
3101             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "Invalid format"); \
3102             return; \
3103         } \
3104         break;
3105
3106     switch (internalFormatTheme) {
3107     INTERNAL_FORMAT_CHECK        (NormalizedFixedPoint      , UNSIGNED_BYTE, TypeUint8  );
3108     INTERNAL_FORMAT_CHECK        (SignedNormalizedFixedPoint, BYTE         , TypeInt8   );
3109     INTERNAL_FORMAT_CHECK        (FloatingPoint             , FLOAT        , TypeFloat32);
3110     INTERNAL_FORMAT_INTEGER_CHECK(SignedInteger             , INT          , TypeInt32  );
3111     INTERNAL_FORMAT_INTEGER_CHECK(UnsignedInteger           , UNSIGNED_INT , TypeUint32 );
3112     case InternalFormatTheme::Packed:
3113         switch (internalFormat) {
3114         PACKED_INTERNAL_FORMAT_CHECK(RGB565        , RGB         , UNSIGNED_SHORT_5_6_5        , TypeUint16, UNSIGNED_BYTE              , TypeUint8  );
3115         PACKED_INTERNAL_FORMAT_CHECK(RGB5_A1       , RGBA        , UNSIGNED_SHORT_5_5_5_1      , TypeUint16, UNSIGNED_BYTE              , TypeUint8  );
3116         PACKED_INTERNAL_FORMAT_CHECK(RGBA4         , RGBA        , UNSIGNED_SHORT_4_4_4_4      , TypeUint16, UNSIGNED_BYTE              , TypeUint8  );
3117         PACKED_INTERNAL_FORMAT_CHECK(RGB9_E5       , RGB         , UNSIGNED_INT_5_9_9_9_REV    , TypeUint32, UNSIGNED_INT_5_9_9_9_REV   , TypeUint32 );
3118         PACKED_INTERNAL_FORMAT_CHECK(RGB10_A2      , RGBA        , UNSIGNED_INT_2_10_10_10_REV , TypeUint32, UNSIGNED_INT_2_10_10_10_REV, TypeUint32 );
3119         PACKED_INTERNAL_FORMAT_CHECK(R11F_G11F_B10F, RGB         , UNSIGNED_INT_10F_11F_11F_REV, TypeUint32, FLOAT                      , TypeFloat32);
3120         PACKED_INTERNAL_FORMAT_CHECK(RGB10_A2UI    , RGBA_INTEGER, UNSIGNED_INT_2_10_10_10_REV , TypeUint32, UNSIGNED_INT_2_10_10_10_REV, TypeUint32 );
3121         }
3122         break;
3123     case InternalFormatTheme::None:
3124         ASSERT_NOT_REACHED();
3125     }
3126 #undef INTERNAL_FORMAT_CHECK
3127 #undef INTERNAL_FORMAT_INTEGER_CHECK
3128 #undef PACKED_INTERNAL_FORMAT_CHECK
3129
3130     // Calculate array size, taking into consideration of PACK_ALIGNMENT.
3131     unsigned totalBytesRequired = 0;
3132     unsigned padding = 0;
3133     if (!m_isRobustnessEXTSupported) {
3134         GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
3135         if (error != GraphicsContext3D::NO_ERROR) {
3136             synthesizeGLError(error, "readPixels", "invalid dimensions");
3137             return;
3138         }
3139         if (pixels.byteLength() < totalBytesRequired) {
3140             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
3141             return;
3142         }
3143     }
3144
3145     clearIfComposited();
3146     void* data = pixels.baseAddress();
3147
3148     if (m_isRobustnessEXTSupported)
3149         m_context->getExtensions().readnPixelsEXT(x, y, width, height, format, type, pixels.byteLength(), data);
3150     else
3151         m_context->readPixels(x, y, width, height, format, type, data);
3152 }
3153
3154 void WebGLRenderingContextBase::releaseShaderCompiler()
3155 {
3156     if (isContextLostOrPending())
3157         return;
3158     m_context->releaseShaderCompiler();
3159 }
3160
3161 void WebGLRenderingContextBase::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
3162 {
3163     if (isContextLostOrPending())
3164         return;
3165     m_context->sampleCoverage(value, invert);
3166 }
3167
3168 void WebGLRenderingContextBase::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
3169 {
3170     if (isContextLostOrPending())
3171         return;
3172     if (!validateSize("scissor", width, height))
3173         return;
3174     m_context->scissor(x, y, width, height);
3175 }
3176
3177 void WebGLRenderingContextBase::shaderSource(WebGLShader* shader, const String& string)
3178 {
3179     if (isContextLostOrPending() || !validateWebGLObject("shaderSource", shader))
3180         return;
3181     String stringWithoutComments = StripComments(string).result();
3182     if (!validateString("shaderSource", stringWithoutComments))
3183         return;
3184     shader->setSource(string);
3185     m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
3186 }
3187
3188 void WebGLRenderingContextBase::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
3189 {
3190     if (isContextLostOrPending())
3191         return;
3192     if (!validateStencilFunc("stencilFunc", func))
3193         return;
3194     m_stencilFuncRef = ref;
3195     m_stencilFuncRefBack = ref;
3196     m_stencilFuncMask = mask;
3197     m_stencilFuncMaskBack = mask;
3198     m_context->stencilFunc(func, ref, mask);
3199 }
3200
3201 void WebGLRenderingContextBase::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
3202 {
3203     if (isContextLostOrPending())
3204         return;
3205     if (!validateStencilFunc("stencilFuncSeparate", func))
3206         return;
3207     switch (face) {
3208     case GraphicsContext3D::FRONT_AND_BACK:
3209         m_stencilFuncRef = ref;
3210         m_stencilFuncRefBack = ref;
3211         m_stencilFuncMask = mask;
3212         m_stencilFuncMaskBack = mask;
3213         break;
3214     case GraphicsContext3D::FRONT:
3215         m_stencilFuncRef = ref;
3216         m_stencilFuncMask = mask;
3217         break;
3218     case GraphicsContext3D::BACK:
3219         m_stencilFuncRefBack = ref;
3220         m_stencilFuncMaskBack = mask;
3221         break;
3222     default:
3223         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilFuncSeparate", "invalid face");
3224         return;
3225     }
3226     m_context->stencilFuncSeparate(face, func, ref, mask);
3227 }
3228
3229 void WebGLRenderingContextBase::stencilMask(GC3Duint mask)
3230 {
3231     if (isContextLostOrPending())
3232         return;
3233     m_stencilMask = mask;
3234     m_stencilMaskBack = mask;
3235     m_context->stencilMask(mask);
3236 }
3237
3238 void WebGLRenderingContextBase::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
3239 {
3240     if (isContextLostOrPending())
3241         return;
3242     switch (face) {
3243     case GraphicsContext3D::FRONT_AND_BACK:
3244         m_stencilMask = mask;
3245         m_stencilMaskBack = mask;
3246         break;
3247     case GraphicsContext3D::FRONT:
3248         m_stencilMask = mask;
3249         break;
3250     case GraphicsContext3D::BACK:
3251         m_stencilMaskBack = mask;
3252         break;
3253     default:
3254         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilMaskSeparate", "invalid face");
3255         return;
3256     }
3257     m_context->stencilMaskSeparate(face, mask);
3258 }
3259
3260 void WebGLRenderingContextBase::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3261 {
3262     if (isContextLostOrPending())
3263         return;
3264     m_context->stencilOp(fail, zfail, zpass);
3265 }
3266
3267 void WebGLRenderingContextBase::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3268 {
3269     if (isContextLostOrPending())
3270         return;
3271     m_context->stencilOpSeparate(face, fail, zfail, zpass);
3272 }
3273
3274 void WebGLRenderingContextBase::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalFormat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels)
3275 {
3276     // FIXME: For now we ignore any errors returned.
3277     WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
3278     ASSERT(validateTexFuncParameters("texImage2D", TexImage, target, level, internalFormat, width, height, border, format, type));
3279     ASSERT(tex);
3280     ASSERT(validateNPOTTextureLevel(width, height, level, "texImage2D"));
3281     if (!pixels) {
3282         if (!m_context->texImage2DResourceSafe(target, level, internalFormat, width, height, border, format, type, m_unpackAlignment))
3283             return;
3284     } else {
3285         ASSERT(validateSettableTexInternalFormat("texImage2D", internalFormat));
3286         m_context->moveErrorsToSyntheticErrorList();
3287         m_context->texImage2D(target, level, internalFormat, width, height,
3288                               border, format, type, pixels);
3289         if (m_context->moveErrorsToSyntheticErrorList()) {
3290             // The texImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
3291             tex->markInvalid(target, level);
3292             return;
3293         }
3294     }
3295     tex->setLevelInfo(target, level, internalFormat, width, height, type);
3296 }
3297
3298 void WebGLRenderingContextBase::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha)
3299 {
3300     Vector<uint8_t> data;
3301     GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);
3302     if (!imageExtractor.extractSucceeded()) {
3303         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3304         return;
3305     }
3306     GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
3307     GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
3308     const void* imagePixelData = imageExtractor.imagePixelData();
3309
3310     bool needConversion = true;
3311     if (type == GraphicsContext3D::UNSIGNED_BYTE && sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 && format == GraphicsContext3D::RGBA && alphaOp == GraphicsContext3D::AlphaDoNothing && !flipY)
3312         needConversion = false;
3313     else {
3314         if (!m_context->packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
3315             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "packImage error");
3316             return;
3317         }
3318     }
3319
3320     if (m_unpackAlignment != 1)
3321         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3322     texImage2DBase(target, level, internalformat, image->width(), image->height(), 0, format, type, needConversion ? data.data() : imagePixelData);
3323     if (m_unpackAlignment != 1)
3324         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3325 }
3326
3327 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)
3328 {
3329     if (!validateTexFuncParameters(functionName, functionType, target, level, internalFormat, width, height, border, format, type))
3330         return false;
3331
3332     WebGLTexture* texture = validateTextureBinding(functionName, target, true);
3333     if (!texture)
3334         return false;
3335
3336     if (functionType != TexSubImage) {
3337         if (functionType == TexImage && texture->immutable()) {
3338             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "texStorage() called on this texture previously");
3339             return false;
3340         }
3341         if (!validateNPOTTextureLevel(width, height, level, functionName))
3342             return false;
3343         // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat
3344         // by checking if the ArrayBufferView is null or not.
3345         if (sourceType != SourceArrayBufferView) {
3346             if (!validateSettableTexInternalFormat(functionName, internalFormat))
3347                 return false;
3348         }
3349     } else {
3350         if (!validateSettableTexInternalFormat(functionName, internalFormat))
3351             return false;
3352         if (!validateSize(functionName, xoffset, yoffset))
3353             return false;
3354         // Before checking if it is in the range, check if overflow happens first.
3355         if (xoffset + width < 0 || yoffset + height < 0) {
3356             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "bad dimensions");
3357             return false;
3358         }
3359         if (xoffset + width > texture->getWidth(target, level) || yoffset + height > texture->getHeight(target, level)) {
3360             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "dimensions out of range");
3361             return false;
3362         }
3363         if (texture->getInternalFormat(target, level) != internalFormat || (isWebGL1() && texture->getType(target, level) != type)) {
3364             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type and format do not match texture");
3365             return false;
3366         }
3367     }
3368
3369     return true;
3370 }
3371
3372 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalFormat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, RefPtr<ArrayBufferView>&& pixels)
3373 {
3374     if (isContextLostOrPending() || !validateTexFuncData("texImage2D", level, width, height, internalFormat, format, type, pixels.get(), NullAllowed)
3375         || !validateTexFunc("texImage2D", TexImage, SourceArrayBufferView, target, level, internalFormat, width, height, border, format, type, 0, 0))
3376         return;
3377     void* data = pixels ? pixels->baseAddress() : 0;
3378     Vector<uint8_t> tempData;
3379     bool changeUnpackAlignment = false;
3380     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3381         if (!m_context->extractTextureData(width, height, format, type,
3382                                            m_unpackAlignment,
3383                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3384                                            data,
3385                                            tempData))
3386             return;
3387         data = tempData.data();
3388         changeUnpackAlignment = true;
3389     }
3390     if (changeUnpackAlignment)
3391         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3392     texImage2DBase(target, level, internalFormat, width, height, border, format, type, data);
3393     if (changeUnpackAlignment)
3394         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3395 }
3396
3397 void WebGLRenderingContextBase::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha)
3398 {
3399     Vector<uint8_t> data;
3400     GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);
3401     if (!imageExtractor.extractSucceeded()) {
3402         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image");
3403         return;
3404     }
3405     GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
3406     GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
3407     const void* imagePixelData = imageExtractor.imagePixelData();
3408     
3409     bool needConversion = true;
3410     if (type == GraphicsContext3D::UNSIGNED_BYTE && sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 && format == GraphicsContext3D::RGBA && alphaOp == GraphicsContext3D::AlphaDoNothing && !flipY)
3411         needConversion = false;
3412     else {
3413         if (!m_context->packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
3414             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3415             return;
3416         }
3417     }
3418     
3419     if (m_unpackAlignment != 1)
3420         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3421
3422     texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(), format, format, type, needConversion ? data.data() : imagePixelData);
3423
3424     if (m_unpackAlignment != 1)
3425         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3426 }
3427
3428 void WebGLRenderingContextBase::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, RefPtr<ArrayBufferView>&& pixels)
3429 {
3430     if (isContextLostOrPending())
3431         return;
3432
3433     WebGLTexture* texture = validateTextureBinding("texSubImage2D", target, true);
3434     if (!texture)
3435         return;
3436
3437     GC3Denum internalFormat = texture->getInternalFormat(target, level);
3438     if (!internalFormat) {
3439         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "invalid texture target or level");
3440         return;
3441     }
3442
3443     if (!validateTexFuncData("texSubImage2D", level, width, height, internalFormat, format, type, pixels.get(), NullNotAllowed))
3444         return;
3445
3446     if (!validateTexFunc("texSubImage2D", TexSubImage, SourceArrayBufferView, target, level, internalFormat, width, height, 0, format, type, xoffset, yoffset))
3447         return;
3448     
3449     void* data = pixels->baseAddress();
3450     Vector<uint8_t> tempData;
3451     bool changeUnpackAlignment = false;
3452     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3453         if (!m_context->extractTextureData(width, height, format, type, m_unpackAlignment, m_unpackFlipY, m_unpackPremultiplyAlpha, data, tempData))
3454             return;
3455         data = tempData.data();
3456         changeUnpackAlignment = true;
3457     }
3458     if (changeUnpackAlignment)
3459         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3460
3461     texSubImage2DBase(target, level, xoffset, yoffset, width, height, internalFormat, format, type, data);
3462
3463     if (changeUnpackAlignment)
3464         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3465 }
3466
3467 ExceptionOr<void> WebGLRenderingContextBase::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Denum format, GC3Denum type, std::optional<TexImageSource>&& source)
3468 {
3469     if (!source) {
3470         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "source is null");
3471         return { };
3472     }
3473
3474     if (isContextLostOrPending())
3475         return { };
3476
3477     auto visitor = WTF::makeVisitor([&](const RefPtr<ImageData>& pixels) -> ExceptionOr<void> {
3478         WebGLTexture* texture = validateTextureBinding("texSubImage2D", target, true);
3479         if (!texture)
3480             return { };
3481
3482         GC3Denum internalFormat = texture->getInternalFormat(target, level);
3483         if (!internalFormat) {
3484             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "invalid texture target or level");
3485             return { };
3486         }
3487
3488         if (!validateTexFunc("texSubImage2D", TexSubImage, SourceImageData, target, level, internalFormat, pixels->width(), pixels->height(), 0, format, type, xoffset, yoffset))
3489             return { };
3490
3491         Vector<uint8_t> data;
3492         bool needConversion = true;
3493         // The data from ImageData is always of format RGBA8.
3494         // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3495         if (format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE && !m_unpackFlipY && !m_unpackPremultiplyAlpha)
3496             needConversion = false;
3497         else {
3498             if (!m_context->extractImageData(pixels.get(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3499                 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image data");
3500                 return { };
3501             }
3502         }
3503         if (m_unpackAlignment != 1)
3504             m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3505
3506         texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(), format, format, type, needConversion ? data.data() : pixels->data()->data());
3507
3508         if (m_unpackAlignment != 1)
3509             m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3510
3511         return { };
3512     } , [&](const RefPtr<HTMLImageElement>& image) -> ExceptionOr<void> {
3513         if (wouldTaintOrigin(image.get()))
3514             return Exception { SECURITY_ERR };
3515         if (isContextLostOrPending() || !validateHTMLImageElement("texSubImage2D", image.get()))
3516             return { };
3517
3518         RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
3519         if (!imageForRender)
3520             return { };
3521
3522         if (imageForRender->isSVGImage())
3523             imageForRender = drawImageIntoBuffer(*imageForRender, image->width(), image->height(), 1);
3524
3525         WebGLTexture* texture = validateTextureBinding("texSubImage2D", target, true);
3526         if (!texture)
3527             return { };
3528
3529         GC3Denum internalFormat = texture->getInternalFormat(target, level);
3530         if (!internalFormat) {
3531             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "invalid texture target or level");
3532             return { };
3533         }
3534
3535         if (!imageForRender || !validateTexFunc("texSubImage2D", TexSubImage, SourceHTMLImageElement, target, level, internalFormat, imageForRender->width(), imageForRender->height(), 0, format, type, xoffset, yoffset))
3536             return { };
3537
3538         texSubImage2DImpl(target, level, xoffset, yoffset, format, type, imageForRender.get(), GraphicsContext3D::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha);
3539         return { };
3540     }, [&](const RefPtr<HTMLCanvasElement>& canvas) -> ExceptionOr<void> {
3541         if (wouldTaintOrigin(canvas.get()))
3542             return Exception { SECURITY_ERR };
3543         if (isContextLostOrPending() || !validateHTMLCanvasElement("texSubImage2D", canvas.get()))
3544             return { };
3545
3546         WebGLTexture* texture = validateTextureBinding("texSubImage2D", target, true);
3547         if (!texture)
3548             return { };
3549
3550         GC3Denum internalFormat = texture->getInternalFormat(target, level);
3551         if (!internalFormat) {
3552             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "invalid texture target or level");
3553             return { };
3554         }
3555
3556         if (!validateTexFunc("texSubImage2D", TexSubImage, SourceHTMLCanvasElement, target, level, internalFormat, canvas->width(), canvas->height(), 0, format, type, xoffset, yoffset))
3557             return { };
3558
3559         RefPtr<ImageData> imageData = canvas->getImageData();
3560         if (imageData)
3561             texSubImage2D(target, level, xoffset, yoffset, format, type, TexImageSource(imageData.get()));
3562         else
3563             texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(), GraphicsContext3D::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha);
3564         return { };
3565     }, [&](const RefPtr<HTMLVideoElement>& video) -> ExceptionOr<void> {
3566         if (wouldTaintOrigin(video.get()))
3567             return Exception { SECURITY_ERR };
3568         if (isContextLostOrPending() || !validateHTMLVideoElement("texSubImage2D", video.get()))
3569             return { };
3570
3571         WebGLTexture* texture = validateTextureBinding("texSubImage2D", target, true);
3572         if (!texture)
3573             return { };
3574
3575         GC3Denum internalFormat = texture->getInternalFormat(target, level);
3576         if (!internalFormat) {
3577             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "invalid texture target or level");
3578             return { };
3579         }
3580
3581         if (!validateTexFunc("texSubImage2D", TexSubImage, SourceHTMLVideoElement, target, level, internalFormat, video->videoWidth(), video->videoHeight(), 0, format, type, xoffset, yoffset))
3582             return { };
3583
3584         RefPtr<Image> image = videoFrameToImage(video.get(), ImageBuffer::fastCopyImageMode());
3585         if (!image)
3586             return { };
3587         texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), GraphicsContext3D::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha);
3588         return { };
3589     });
3590
3591     return WTF::visit(visitor, source.value());
3592 }
3593
3594 bool WebGLRenderingContextBase::validateArrayBufferType(const char* functionName, GC3Denum type, std::optional<JSC::TypedArrayType> arrayType)
3595 {
3596 #define TYPE_VALIDATION_CASE(arrayTypeMacro) if (arrayType && arrayType.value() != JSC::arrayTypeMacro) { \
3597             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not " #arrayTypeMacro); \
3598             return false; \
3599         } \
3600         break;
3601
3602     switch (type) {
3603     case GraphicsContext3D::UNSIGNED_BYTE:
3604         TYPE_VALIDATION_CASE(TypeUint8);
3605     case GraphicsContext3D::BYTE:
3606         TYPE_VALIDATION_CASE(TypeInt8);
3607     case GraphicsContext3D::UNSIGNED_SHORT:
3608     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
3609     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
3610     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
3611         TYPE_VALIDATION_CASE(TypeUint16);
3612     case GraphicsContext3D::SHORT:
3613         TYPE_VALIDATION_CASE(TypeInt16);
3614     case GraphicsContext3D::UNSIGNED_INT_2_10_10_10_REV:
3615     case GraphicsContext3D::UNSIGNED_INT_10F_11F_11F_REV:
3616     case GraphicsContext3D::UNSIGNED_INT_5_9_9_9_REV:
3617     case GraphicsContext3D::UNSIGNED_INT_24_8:
3618     case GraphicsContext3D::UNSIGNED_INT:
3619         TYPE_VALIDATION_CASE(TypeUint32);
3620     case GraphicsContext3D::INT:
3621         TYPE_VALIDATION_CASE(TypeInt32);
3622     case GraphicsContext3D::FLOAT: // OES_texture_float
3623         TYPE_VALIDATION_CASE(TypeFloat32);
3624     case GraphicsContext3D::HALF_FLOAT_OES: // OES_texture_half_float
3625     case GraphicsContext3D::HALF_FLOAT:
3626     case GraphicsContext3D::FLOAT_32_UNSIGNED_INT_24_8_REV:
3627         // As per the specification, ArrayBufferView should be null when
3628         // OES_texture_half_float is enabled.
3629         if (arrayType) {
3630             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type HALF_FLOAT_OES but ArrayBufferView is not NULL");
3631             return false;
3632         }
3633         break;
3634     default:
3635         ASSERT_NOT_REACHED();
3636         return false;
3637     }
3638 #undef TYPE_VALIDATION_CASE
3639     return true;
3640 }
3641
3642 bool WebGLRenderingContextBase::validateTexFuncData(const char* functionName, GC3Dint level, GC3Dsizei width, GC3Dsizei height, GC3Denum internalFormat, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, NullDisposition disposition)
3643 {
3644     if (!pixels) {
3645         if (disposition == NullAllowed)
3646             return true;
3647         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no pixels");
3648         return false;
3649     }
3650
3651     if (!validateTexFuncFormatAndType(functionName, internalFormat, format, type, level))
3652         return false;
3653     if (!validateSettableTexInternalFormat(functionName, internalFormat))
3654         return false;
3655     if (!validateArrayBufferType(functionName, type, pixels ? std::optional<JSC::TypedArrayType>(pixels->getType()) : std::nullopt))
3656         return false;
3657     
3658     unsigned totalBytesRequired;
3659     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, nullptr);
3660     if (error != GraphicsContext3D::NO_ERROR) {
3661         synthesizeGLError(error, functionName, "invalid texture dimensions");
3662         return false;
3663     }
3664     if (pixels->byteLength() < totalBytesRequired) {
3665         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request");
3666         return false;
3667     }
3668     return true;
3669 }
3670
3671 bool WebGLRenderingContextBase::validateTexFuncParameters(const char* functionName,
3672     TexFuncValidationFunctionType functionType,
3673     GC3Denum target, GC3Dint level,
3674     GC3Denum internalformat,
3675     GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3676     GC3Denum format, GC3Denum type)
3677 {
3678     // We absolutely have to validate the format and type combination.
3679     // The texImage2D entry points taking HTMLImage, etc. will produce
3680     // temporary data based on this combination, so it must be legal.
3681     if (!validateTexFuncFormatAndType(functionName, internalformat, format, type, level) || !validateTexFuncLevel(functionName, target, level))
3682         return false;
3683     
3684     if (width < 0 || height < 0) {
3685         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height < 0");
3686         return false;
3687     }
3688     
3689     GC3Dint maxTextureSizeForLevel = pow(2.0, m_maxTextureLevel - 1 - level);
3690     switch (target) {
3691     case GraphicsContext3D::TEXTURE_2D:
3692         if (width > maxTextureSizeForLevel || height > maxTextureSizeForLevel) {
3693             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range");
3694             return false;
3695         }
3696         break;
3697     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
3698     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
3699     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
3700     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
3701     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
3702     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
3703         if (functionType != TexSubImage && width != height) {
3704             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width != height for cube map");
3705             return false;
3706         }
3707         // No need to check height here. For texImage width == height.
3708         // For texSubImage that will be checked when checking yoffset + height is in range.
3709         if (width > maxTextureSizeForLevel) {
3710             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range for cube map");
3711             return false;
3712         }
3713         break;
3714     default:
3715         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
3716         return false;
3717     }
3718     
3719     if (border) {
3720         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "border != 0");
3721         return false;
3722     }
3723     
3724     return true;
3725 }
3726
3727 bool WebGLRenderingContextBase::validateTexFuncFormatAndType(const char* functionName, GC3Denum internalFormat, GC3Denum format, GC3Denum type, GC3Dint level)
3728 {
3729     switch (format) {
3730     case GraphicsContext3D::ALPHA:
3731     case GraphicsContext3D::LUMINANCE:
3732     case GraphicsContext3D::LUMINANCE_ALPHA:
3733     case GraphicsContext3D::RGB:
3734     case GraphicsContext3D::RGBA:
3735         break;
3736     case GraphicsContext3D::DEPTH_STENCIL: