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