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