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