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