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