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