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