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