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