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