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