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