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