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