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