044e9c3c7d4c96073ce0eba471207f7f925f2dbe
[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_drawingBuffer)
924         m_drawingBuffer->setFramebufferBinding(objectOrZero(m_framebufferBinding.get()));
925     if (!m_framebufferBinding && m_drawingBuffer) {
926         // Instead of binding fb 0, bind the drawing buffer.
927         m_drawingBuffer->bind();
928     } else
929         m_context->bindFramebuffer(target, objectOrZero(buffer));
930     if (buffer)
931         buffer->setHasEverBeenBound();
932     cleanupAfterGraphicsCall(false);
933 }
934
935 void WebGLRenderingContext::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
936 {
937     UNUSED_PARAM(ec);
938     bool deleted;
939     if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
940         return;
941     if (deleted)
942         renderBuffer = 0;
943     if (target != GraphicsContext3D::RENDERBUFFER) {
944         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindRenderbuffer", "invalid target");
945         return;
946     }
947     m_renderbufferBinding = renderBuffer;
948     m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
949     if (renderBuffer)
950         renderBuffer->setHasEverBeenBound();
951     cleanupAfterGraphicsCall(false);
952 }
953
954 void WebGLRenderingContext::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
955 {
956     UNUSED_PARAM(ec);
957     bool deleted;
958     if (!checkObjectToBeBound("bindTexture", texture, deleted))
959         return;
960     if (deleted)
961         texture = 0;
962     if (texture && texture->getTarget() && texture->getTarget() != target) {
963         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
964         return;
965     }
966     GC3Dint maxLevel = 0;
967     if (target == GraphicsContext3D::TEXTURE_2D) {
968         m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
969         maxLevel = m_maxTextureLevel;
970
971         if (m_drawingBuffer && !m_activeTextureUnit)
972             m_drawingBuffer->setTexture2DBinding(objectOrZero(texture));
973
974     } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
975         m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
976         maxLevel = m_maxCubeMapTextureLevel;
977     } else {
978         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindTexture", "invalid target");
979         return;
980     }
981     m_context->bindTexture(target, objectOrZero(texture));
982     if (texture)
983         texture->setTarget(target, maxLevel);
984
985     // Note: previously we used to automatically set the TEXTURE_WRAP_R
986     // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
987     // ES 2.0 doesn't expose this flag (a bug in the specification) and
988     // otherwise the application has no control over the seams in this
989     // dimension. However, it appears that supporting this properly on all
990     // platforms is fairly involved (will require a HashMap from texture ID
991     // in all ports), and we have not had any complaints, so the logic has
992     // been removed.
993
994     cleanupAfterGraphicsCall(false);
995 }
996
997 void WebGLRenderingContext::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
998 {
999     if (isContextLost())
1000         return;
1001     m_context->blendColor(red, green, blue, alpha);
1002     cleanupAfterGraphicsCall(false);
1003 }
1004
1005 void WebGLRenderingContext::blendEquation(GC3Denum mode)
1006 {
1007     if (isContextLost() || !validateBlendEquation("blendEquation", mode))
1008         return;
1009     m_context->blendEquation(mode);
1010     cleanupAfterGraphicsCall(false);
1011 }
1012
1013 void WebGLRenderingContext::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
1014 {
1015     if (isContextLost() || !validateBlendEquation("blendEquation", modeRGB) || !validateBlendEquation("blendEquation", modeAlpha))
1016         return;
1017     m_context->blendEquationSeparate(modeRGB, modeAlpha);
1018     cleanupAfterGraphicsCall(false);
1019 }
1020
1021
1022 void WebGLRenderingContext::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
1023 {
1024     if (isContextLost() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
1025         return;
1026     m_context->blendFunc(sfactor, dfactor);
1027     cleanupAfterGraphicsCall(false);
1028 }
1029
1030 void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
1031 {
1032     // Note: Alpha does not have the same restrictions as RGB.
1033     if (isContextLost() || !validateBlendFuncFactors("blendFunc", srcRGB, dstRGB))
1034         return;
1035     m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
1036     cleanupAfterGraphicsCall(false);
1037 }
1038
1039 void WebGLRenderingContext::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage, ExceptionCode& ec)
1040 {
1041     UNUSED_PARAM(ec);
1042     if (isContextLost())
1043         return;
1044     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1045     if (!buffer)
1046         return;
1047     if (size < 0) {
1048         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size < 0");
1049         return;
1050     }
1051     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1052         if (!buffer->associateBufferData(size)) {
1053             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1054             return;
1055         }
1056     }
1057
1058     m_context->bufferData(target, size, usage);
1059     cleanupAfterGraphicsCall(false);
1060 }
1061
1062 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
1063 {
1064     UNUSED_PARAM(ec);
1065     if (isContextLost())
1066         return;
1067     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1068     if (!buffer)
1069         return;
1070     if (!data) {
1071         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1072         return;
1073     }
1074     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1075         if (!buffer->associateBufferData(data)) {
1076             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1077             return;
1078         }
1079     }
1080
1081     m_context->bufferData(target, data->byteLength(), data->data(), usage);
1082     cleanupAfterGraphicsCall(false);
1083 }
1084
1085 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
1086 {
1087     UNUSED_PARAM(ec);
1088     if (isContextLost())
1089         return;
1090     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1091     if (!buffer)
1092         return;
1093     if (!data) {
1094         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1095         return;
1096     }
1097     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1098         if (!buffer->associateBufferData(data)) {
1099             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1100             return;
1101         }
1102     }
1103
1104     m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
1105     cleanupAfterGraphicsCall(false);
1106 }
1107
1108 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBuffer* data, ExceptionCode& ec)
1109 {
1110     UNUSED_PARAM(ec);
1111     if (isContextLost())
1112         return;
1113     WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1114     if (!buffer)
1115         return;
1116     if (offset < 0) {
1117         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1118         return;
1119     }
1120     if (!data)
1121         return;
1122     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1123         if (!buffer->associateBufferSubData(offset, data)) {
1124             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1125             return;
1126         }
1127     }
1128
1129     m_context->bufferSubData(target, offset, data->byteLength(), data->data());
1130     cleanupAfterGraphicsCall(false);
1131 }
1132
1133 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBufferView* data, ExceptionCode& ec)
1134 {
1135     UNUSED_PARAM(ec);
1136     if (isContextLost())
1137         return;
1138     WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1139     if (!buffer)
1140         return;
1141     if (offset < 0) {
1142         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1143         return;
1144     }
1145     if (!data)
1146         return;
1147     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1148         if (!buffer->associateBufferSubData(offset, data)) {
1149             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1150             return;
1151         }
1152     }
1153
1154     m_context->bufferSubData(target, offset, data->byteLength(), data->baseAddress());
1155     cleanupAfterGraphicsCall(false);
1156 }
1157
1158 GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target)
1159 {
1160     if (isContextLost())
1161         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
1162     if (target != GraphicsContext3D::FRAMEBUFFER) {
1163         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "checkFramebufferStatus", "invalid target");
1164         return 0;
1165     }
1166     if (!m_framebufferBinding || !m_framebufferBinding->object())
1167         return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
1168     GC3Denum result = m_framebufferBinding->checkStatus();
1169     if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
1170         return result;
1171     result = m_context->checkFramebufferStatus(target);
1172     cleanupAfterGraphicsCall(false);
1173     return result;
1174 }
1175
1176 void WebGLRenderingContext::clear(GC3Dbitfield mask)
1177 {
1178     if (isContextLost())
1179         return;
1180     if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
1181         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "clear", "invalid mask");
1182         return;
1183     }
1184     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1185         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "clear", "can not render to framebuffer");
1186         return;
1187     }
1188     if (!clearIfComposited(mask))
1189         m_context->clear(mask);
1190     cleanupAfterGraphicsCall(true);
1191 }
1192
1193 void WebGLRenderingContext::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
1194 {
1195     if (isContextLost())
1196         return;
1197     if (isnan(r))
1198         r = 0;
1199     if (isnan(g))
1200         g = 0;
1201     if (isnan(b))
1202         b = 0;
1203     if (isnan(a))
1204         a = 1;
1205     m_clearColor[0] = r;
1206     m_clearColor[1] = g;
1207     m_clearColor[2] = b;
1208     m_clearColor[3] = a;
1209     m_context->clearColor(r, g, b, a);
1210     cleanupAfterGraphicsCall(false);
1211 }
1212
1213 void WebGLRenderingContext::clearDepth(GC3Dfloat depth)
1214 {
1215     if (isContextLost())
1216         return;
1217     m_clearDepth = depth;
1218     m_context->clearDepth(depth);
1219     cleanupAfterGraphicsCall(false);
1220 }
1221
1222 void WebGLRenderingContext::clearStencil(GC3Dint s)
1223 {
1224     if (isContextLost())
1225         return;
1226     m_clearStencil = s;
1227     m_context->clearStencil(s);
1228     cleanupAfterGraphicsCall(false);
1229 }
1230
1231 void WebGLRenderingContext::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1232 {
1233     if (isContextLost())
1234         return;
1235     m_colorMask[0] = red;
1236     m_colorMask[1] = green;
1237     m_colorMask[2] = blue;
1238     m_colorMask[3] = alpha;
1239     m_context->colorMask(red, green, blue, alpha);
1240     cleanupAfterGraphicsCall(false);
1241 }
1242
1243 void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec)
1244 {
1245     UNUSED_PARAM(ec);
1246     if (isContextLost() || !validateWebGLObject("compileShader", shader))
1247         return;
1248     m_context->compileShader(objectOrZero(shader));
1249     cleanupAfterGraphicsCall(false);
1250 }
1251
1252 void WebGLRenderingContext::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width,
1253                                                  GC3Dsizei height, GC3Dint border, ArrayBufferView* data)
1254 {
1255     if (isContextLost())
1256         return;
1257     if (!validateTexFuncLevel("compressedTexImage2D", target, level))
1258         return;
1259
1260     if (!validateCompressedTexFormat(internalformat)) {
1261         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
1262         return;
1263     }
1264     if (border) {
1265         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "border not 0");
1266         return;
1267     }
1268     if (!validateCompressedTexDimensions("compressedTexImage2D", level, width, height, internalformat))
1269         return;
1270     if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
1271         return;
1272
1273     WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
1274     if (!tex)
1275         return;
1276     if (!isGLES2NPOTStrict()) {
1277         if (level && WebGLTexture::isNPOT(width, height)) {
1278             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2");
1279             return;
1280         }
1281     }
1282     graphicsContext3D()->compressedTexImage2D(target, level, internalformat, width, height,
1283                                               border, data->byteLength(), data->baseAddress());
1284     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1285     cleanupAfterGraphicsCall(false);
1286 }
1287
1288 void WebGLRenderingContext::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
1289                                                     GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView* data)
1290 {
1291     if (isContextLost())
1292         return;
1293     if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
1294         return;
1295     if (!validateCompressedTexFormat(format)) {
1296         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
1297         return;
1298     }
1299     if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
1300         return;
1301
1302     WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
1303     if (!tex)
1304         return;
1305
1306     if (format != tex->getInternalFormat(target, level)) {
1307         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
1308         return;
1309     }
1310
1311     if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
1312         return;
1313
1314     graphicsContext3D()->compressedTexSubImage2D(target, level, xoffset, yoffset,
1315                                                  width, height, format, data->byteLength(), data->baseAddress());
1316     cleanupAfterGraphicsCall(false);
1317 }
1318
1319 void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
1320 {
1321     if (isContextLost())
1322         return;
1323     if (!validateTexFuncParameters("copyTexImage2D", target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
1324         return;
1325     WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true);
1326     if (!tex)
1327         return;
1328     if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1329         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexImage2D", "framebuffer is incompatible format");
1330         return;
1331     }
1332     if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1333         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexImage2D", "level > 0 not power of 2");
1334         return;
1335     }
1336     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1337         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D", "framebuffer not readable");
1338         return;
1339     }
1340     clearIfComposited();
1341     if (isResourceSafe()) {
1342         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1343         m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1344     } else {
1345         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1346         GC3Dint clippedX, clippedY;
1347         GC3Dsizei clippedWidth, clippedHeight;
1348         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1349             m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
1350                                               internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment);
1351             if (clippedWidth > 0 && clippedHeight > 0) {
1352                 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
1353                                              clippedX, clippedY, clippedWidth, clippedHeight);
1354             }
1355         } else
1356             m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1357     }
1358     // FIXME: if the framebuffer is not complete, none of the below should be executed.
1359     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1360     cleanupAfterGraphicsCall(false);
1361 }
1362
1363 void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1364 {
1365     if (isContextLost())
1366         return;
1367     if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
1368         return;
1369     WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
1370     if (!tex)
1371         return;
1372     if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
1373         return;
1374     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1375         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
1376         return;
1377     }
1378     if (!isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(target, level), getBoundFramebufferColorFormat())) {
1379         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
1380         return;
1381     }
1382     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1383         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", "framebuffer not readable");
1384         return;
1385     }
1386     clearIfComposited();
1387     if (isResourceSafe()) {
1388         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1389         m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1390     } else {
1391         GC3Dint clippedX, clippedY;
1392         GC3Dsizei clippedWidth, clippedHeight;
1393         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1394             GC3Denum format = tex->getInternalFormat(target, level);
1395             GC3Denum type = tex->getType(target, level);
1396             OwnArrayPtr<unsigned char> zero;
1397             if (width && height) {
1398                 unsigned int size;
1399                 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1400                 if (error != GraphicsContext3D::NO_ERROR) {
1401                     synthesizeGLError(error, "copyTexSubImage2D", "bad dimensions");
1402                     return;
1403                 }
1404                 zero = adoptArrayPtr(new unsigned char[size]);
1405                 if (!zero) {
1406                     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "out of memory");
1407                     return;
1408                 }
1409                 memset(zero.get(), 0, size);
1410             }
1411             m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1412             if (clippedWidth > 0 && clippedHeight > 0) {
1413                 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1414                 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1415                                              clippedX, clippedY, clippedWidth, clippedHeight);
1416             }
1417         } else {
1418             ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1419             m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1420         }
1421     }
1422     cleanupAfterGraphicsCall(false);
1423 }
1424
1425 PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer()
1426 {
1427     if (isContextLost())
1428         return 0;
1429     RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1430     addSharedObject(o.get());
1431     return o;
1432 }
1433
1434 PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer()
1435 {
1436     if (isContextLost())
1437         return 0;
1438     RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1439     addContextObject(o.get());
1440     return o;
1441 }
1442
1443 PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture()
1444 {
1445     if (isContextLost())
1446         return 0;
1447     RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1448     addSharedObject(o.get());
1449     return o;
1450 }
1451
1452 PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram()
1453 {
1454     if (isContextLost())
1455         return 0;
1456     RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1457     addSharedObject(o.get());
1458     return o;
1459 }
1460
1461 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer()
1462 {
1463     if (isContextLost())
1464         return 0;
1465     RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1466     addSharedObject(o.get());
1467     return o;
1468 }
1469
1470 PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(GC3Denum type, ExceptionCode& ec)
1471 {
1472     UNUSED_PARAM(ec);
1473     if (isContextLost())
1474         return 0;
1475     if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1476         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "createShader", "invalid shader type");
1477         return 0;
1478     }
1479
1480     RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1481     addSharedObject(o.get());
1482     return o;
1483 }
1484
1485 void WebGLRenderingContext::cullFace(GC3Denum mode)
1486 {
1487     if (isContextLost())
1488         return;
1489     m_context->cullFace(mode);
1490     cleanupAfterGraphicsCall(false);
1491 }
1492
1493 bool WebGLRenderingContext::deleteObject(WebGLObject* object)
1494 {
1495     if (isContextLost() || !object)
1496         return false;
1497     if (!object->validate(contextGroup(), this)) {
1498         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "delete", "object does not belong to this context");
1499         return false;
1500     }
1501     if (object->object())
1502         // We need to pass in context here because we want
1503         // things in this context unbound.
1504         object->deleteObject(graphicsContext3D());
1505     return true;
1506 }
1507
1508 void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
1509 {
1510     if (!deleteObject(buffer))
1511         return;
1512     if (m_boundArrayBuffer == buffer)
1513         m_boundArrayBuffer = 0;
1514     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1515     if (elementArrayBuffer == buffer)
1516         m_boundVertexArrayObject->setElementArrayBuffer(0);
1517     if (!isGLES2Compliant()) {
1518         WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
1519         if (buffer == state.bufferBinding) {
1520             state.bufferBinding = m_vertexAttrib0Buffer;
1521             state.bytesPerElement = 0;
1522             state.size = 4;
1523             state.type = GraphicsContext3D::FLOAT;
1524             state.normalized = false;
1525             state.stride = 16;
1526             state.originalStride = 0;
1527             state.offset = 0;
1528         }
1529     }
1530 }
1531
1532 void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1533 {
1534     if (!deleteObject(framebuffer))
1535         return;
1536     if (framebuffer == m_framebufferBinding) {
1537         m_framebufferBinding = 0;
1538         if (m_drawingBuffer) {
1539             m_drawingBuffer->setFramebufferBinding(0);
1540             // Have to call bindFramebuffer here to bind back to internal fbo.
1541             m_drawingBuffer->bind();
1542         } else
1543             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1544     }
1545 }
1546
1547 void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
1548 {
1549     deleteObject(program);
1550     // We don't reset m_currentProgram to 0 here because the deletion of the
1551     // current program is delayed.
1552 }
1553
1554 void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1555 {
1556     if (!deleteObject(renderbuffer))
1557         return;
1558     if (renderbuffer == m_renderbufferBinding)
1559         m_renderbufferBinding = 0;
1560     if (m_framebufferBinding)
1561         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1562 }
1563
1564 void WebGLRenderingContext::deleteShader(WebGLShader* shader)
1565 {
1566     deleteObject(shader);
1567 }
1568
1569 void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
1570 {
1571     if (!deleteObject(texture))
1572         return;
1573     for (size_t i = 0; i < m_textureUnits.size(); ++i) {
1574         if (texture == m_textureUnits[i].m_texture2DBinding)
1575             m_textureUnits[i].m_texture2DBinding = 0;
1576         if (texture == m_textureUnits[i].m_textureCubeMapBinding)
1577             m_textureUnits[i].m_textureCubeMapBinding = 0;
1578     }
1579     if (m_framebufferBinding)
1580         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1581 }
1582
1583 void WebGLRenderingContext::depthFunc(GC3Denum func)
1584 {
1585     if (isContextLost())
1586         return;
1587     m_context->depthFunc(func);
1588     cleanupAfterGraphicsCall(false);
1589 }
1590
1591 void WebGLRenderingContext::depthMask(GC3Dboolean flag)
1592 {
1593     if (isContextLost())
1594         return;
1595     m_depthMask = flag;
1596     m_context->depthMask(flag);
1597     cleanupAfterGraphicsCall(false);
1598 }
1599
1600 void WebGLRenderingContext::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1601 {
1602     if (isContextLost())
1603         return;
1604     if (zNear > zFar) {
1605         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "depthRange", "zNear > zFar");
1606         return;
1607     }
1608     m_context->depthRange(zNear, zFar);
1609     cleanupAfterGraphicsCall(false);
1610 }
1611
1612 void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
1613 {
1614     UNUSED_PARAM(ec);
1615     if (isContextLost() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
1616         return;
1617     if (!program->detachShader(shader)) {
1618         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "detachShader", "shader not attached");
1619         return;
1620     }
1621     m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1622     shader->onDetached(graphicsContext3D());
1623     cleanupAfterGraphicsCall(false);
1624 }
1625
1626 void WebGLRenderingContext::disable(GC3Denum cap)
1627 {
1628     if (isContextLost() || !validateCapability("disable", cap))
1629         return;
1630     if (cap == GraphicsContext3D::SCISSOR_TEST) {
1631         m_scissorEnabled = false;
1632         if (m_drawingBuffer)
1633             m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1634     }
1635     m_context->disable(cap);
1636     cleanupAfterGraphicsCall(false);
1637 }
1638
1639 void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1640 {
1641     UNUSED_PARAM(ec);
1642     if (isContextLost())
1643         return;
1644     if (index >= m_maxVertexAttribs) {
1645         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "disableVertexAttribArray", "index out of range");
1646         return;
1647     }
1648
1649     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1650     state.enabled = false;
1651
1652     if (index > 0 || isGLES2Compliant()) {
1653         m_context->disableVertexAttribArray(index);
1654         cleanupAfterGraphicsCall(false);
1655     }
1656 }
1657
1658 bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1659 {
1660     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1661     
1662     if (!elementArrayBuffer)
1663         return false;
1664
1665     if (offset < 0)
1666         return false;
1667
1668     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1669         // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1670         if (offset % 2)
1671             return false;
1672
1673         // Make uoffset an element offset.
1674         offset /= 2;
1675
1676         GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1677         if (offset > n || count > n - offset)
1678             return false;
1679     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1680         GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1681         if (offset > n || count > n - offset)
1682             return false;
1683     }
1684     return true;
1685 }
1686
1687 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& numElementsRequired)
1688 {
1689     // Performs conservative validation by caching a maximum index of
1690     // the given type per element array buffer. If all of the bound
1691     // array buffers have enough elements to satisfy that maximum
1692     // index, skips the expensive per-draw-call iteration in
1693     // validateIndexArrayPrecise.
1694     
1695     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1696
1697     if (!elementArrayBuffer)
1698         return false;
1699
1700     GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
1701     // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1702     if (!numElements)
1703         return false;
1704     const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
1705     ASSERT(buffer);
1706
1707     int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
1708     if (maxIndex < 0) {
1709         // Compute the maximum index in the entire buffer for the given type of index.
1710         switch (type) {
1711         case GraphicsContext3D::UNSIGNED_BYTE: {
1712             const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
1713             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1714                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1715             break;
1716         }
1717         case GraphicsContext3D::UNSIGNED_SHORT: {
1718             numElements /= sizeof(GC3Dushort);
1719             const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
1720             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1721                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1722             break;
1723         }
1724         default:
1725             return false;
1726         }
1727         elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1728     }
1729
1730     if (maxIndex >= 0) {
1731         // The number of required elements is one more than the maximum
1732         // index that will be accessed.
1733         numElementsRequired = maxIndex + 1;
1734         return true;
1735     }
1736
1737     return false;
1738 }
1739
1740 bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, int& numElementsRequired)
1741 {
1742     ASSERT(count >= 0 && offset >= 0);
1743     int lastIndex = -1;
1744     
1745     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1746
1747     if (!elementArrayBuffer)
1748         return false;
1749
1750     if (!count) {
1751         numElementsRequired = 0;
1752         return true;
1753     }
1754
1755     if (!elementArrayBuffer->elementArrayBuffer())
1756         return false;
1757
1758     unsigned long uoffset = offset;
1759     unsigned long n = count;
1760
1761     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1762         // Make uoffset an element offset.
1763         uoffset /= sizeof(GC3Dushort);
1764         const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1765         while (n-- > 0) {
1766             if (*p > lastIndex)
1767                 lastIndex = *p;
1768             ++p;
1769         }
1770     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1771         const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1772         while (n-- > 0) {
1773             if (*p > lastIndex)
1774                 lastIndex = *p;
1775             ++p;
1776         }
1777     }
1778
1779     // Then set the last index in the index array and make sure it is valid.
1780     numElementsRequired = lastIndex + 1;
1781     return numElementsRequired > 0;
1782 }
1783
1784 bool WebGLRenderingContext::validateRenderingState(int numElementsRequired)
1785 {
1786     if (!m_currentProgram)
1787         return false;
1788
1789     // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1790     for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1791         const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
1792         if (state.enabled
1793             && (!state.bufferBinding || !state.bufferBinding->object()))
1794             return false;
1795     }
1796
1797     if (numElementsRequired <= 0)
1798         return true;
1799
1800     // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
1801     int smallestNumElements = INT_MAX;
1802     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1803     for (int i = 0; i < numActiveAttribLocations; ++i) {
1804         int loc = m_currentProgram->getActiveAttribLocation(i);
1805         if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1806             const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1807             if (state.enabled) {
1808                 // Avoid off-by-one errors in numElements computation.
1809                 // For the last element, we will only touch the data for the
1810                 // element and nothing beyond it.
1811                 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1812                 int numElements = 0;
1813                 ASSERT(state.stride > 0);
1814                 if (bytesRemaining >= state.bytesPerElement)
1815                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1816                 if (numElements < smallestNumElements)
1817                     smallestNumElements = numElements;
1818             }
1819         }
1820     }
1821
1822     if (smallestNumElements == INT_MAX)
1823         smallestNumElements = 0;
1824
1825     return numElementsRequired <= smallestNumElements;
1826 }
1827
1828 bool WebGLRenderingContext::validateWebGLObject(const char* functionName, WebGLObject* object)
1829 {
1830     if (!object || !object->object()) {
1831         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no object or object deleted");
1832         return false;
1833     }
1834     if (!object->validate(contextGroup(), this)) {
1835         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object does not belong to this context");
1836         return false;
1837     }
1838     return true;
1839 }
1840
1841 void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
1842 {
1843     UNUSED_PARAM(ec);
1844
1845     if (isContextLost() || !validateDrawMode("drawArrays", mode))
1846         return;
1847
1848     if (!validateStencilSettings("drawArrays"))
1849         return;
1850
1851     if (first < 0 || count < 0) {
1852         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawArrays", "first or count < 0");
1853         return;
1854     }
1855
1856     if (!count)
1857         return;
1858
1859     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1860         // Ensure we have a valid rendering state
1861         CheckedInt<GC3Dint> checkedFirst(first);
1862         CheckedInt<GC3Dint> checkedCount(count);
1863         CheckedInt<GC3Dint> checkedSum = checkedFirst + checkedCount;
1864         if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) {
1865             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attempt to access out of bounds arrays");
1866             return;
1867         }
1868     } else {
1869         if (!validateRenderingState(0)) {
1870             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attribs not setup correctly");
1871             return;
1872         }
1873     }
1874
1875     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1876         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawArrays", "framebuffer can not be rendered to");
1877         return;
1878     }
1879
1880     clearIfComposited();
1881
1882     bool vertexAttrib0Simulated = false;
1883     if (!isGLES2Compliant())
1884         vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1885     if (!isGLES2NPOTStrict())
1886         handleNPOTTextures(true);
1887     m_context->drawArrays(mode, first, count);
1888     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1889         restoreStatesAfterVertexAttrib0Simulation();
1890     if (!isGLES2NPOTStrict())
1891         handleNPOTTextures(false);
1892     cleanupAfterGraphicsCall(true);
1893 }
1894
1895 void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, ExceptionCode& ec)
1896 {
1897     UNUSED_PARAM(ec);
1898
1899     if (isContextLost() || !validateDrawMode("drawElements", mode))
1900         return;
1901
1902     if (!validateStencilSettings("drawElements"))
1903         return;
1904
1905     switch (type) {
1906     case GraphicsContext3D::UNSIGNED_BYTE:
1907     case GraphicsContext3D::UNSIGNED_SHORT:
1908         break;
1909     default:
1910         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "drawElements", "invalid type");
1911         return;
1912     }
1913
1914     if (count < 0 || offset < 0) {
1915         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawElements", "count or offset < 0");
1916         return;
1917     }
1918
1919     if (!count)
1920         return;
1921
1922     if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1923         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "no ELEMENT_ARRAY_BUFFER bound");
1924         return;
1925     }
1926
1927     int numElements = 0;
1928     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1929         // Ensure we have a valid rendering state
1930         if (!validateElementArraySize(count, type, offset)) {
1931             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "request out of bounds for current ELEMENT_ARRAY_BUFFER");
1932             return;
1933         }
1934         if (!count)
1935             return;
1936         if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) {
1937             if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
1938                 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attempt to access out of bounds arrays");
1939                 return;
1940             }
1941         }
1942     } else {
1943         if (!validateRenderingState(0)) {
1944             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attribs not setup correctly");
1945             return;
1946         }
1947     }
1948
1949     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1950         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawElements", "framebuffer can not be rendered to");
1951         return;
1952     }
1953     clearIfComposited();
1954
1955     bool vertexAttrib0Simulated = false;
1956     if (!isGLES2Compliant()) {
1957         if (!numElements)
1958             validateIndexArrayPrecise(count, type, offset, numElements);
1959         vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1960     }
1961     if (!isGLES2NPOTStrict())
1962         handleNPOTTextures(true);
1963     m_context->drawElements(mode, count, type, offset);
1964     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1965         restoreStatesAfterVertexAttrib0Simulation();
1966     if (!isGLES2NPOTStrict())
1967         handleNPOTTextures(false);
1968     cleanupAfterGraphicsCall(true);
1969 }
1970
1971 void WebGLRenderingContext::enable(GC3Denum cap)
1972 {
1973     if (isContextLost() || !validateCapability("enable", cap))
1974         return;
1975     if (cap == GraphicsContext3D::SCISSOR_TEST) {
1976         m_scissorEnabled = true;
1977         if (m_drawingBuffer)
1978             m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1979     }
1980     m_context->enable(cap);
1981     cleanupAfterGraphicsCall(false);
1982 }
1983
1984 void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1985 {
1986     UNUSED_PARAM(ec);
1987     if (isContextLost())
1988         return;
1989     if (index >= m_maxVertexAttribs) {
1990         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "enableVertexAttribArray", "index out of range");
1991         return;
1992     }
1993
1994     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1995     state.enabled = true;
1996
1997     m_context->enableVertexAttribArray(index);
1998     cleanupAfterGraphicsCall(false);
1999 }
2000
2001 void WebGLRenderingContext::finish()
2002 {
2003     if (isContextLost())
2004         return;
2005     m_context->finish();
2006     cleanupAfterGraphicsCall(false);
2007 }
2008
2009 void WebGLRenderingContext::flush()
2010 {
2011     if (isContextLost())
2012         return;
2013     m_context->flush();
2014     cleanupAfterGraphicsCall(false);
2015 }
2016
2017 void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
2018 {
2019     UNUSED_PARAM(ec);
2020     if (isContextLost() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
2021         return;
2022     if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
2023         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
2024         return;
2025     }
2026     if (buffer && !buffer->validate(contextGroup(), this)) {
2027         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
2028         return;
2029     }
2030     // Don't allow the default framebuffer to be mutated; all current
2031     // implementations use an FBO internally in place of the default
2032     // FBO.
2033     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2034         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
2035         return;
2036     }
2037     Platform3DObject bufferObject = objectOrZero(buffer);
2038     bool reattachDepth = false;
2039     bool reattachStencil = false;
2040     bool reattachDepthStencilDepth = false;
2041     bool reattachDepthStencilStencil = false;
2042     switch (attachment) {
2043     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2044         m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
2045         m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
2046         if (!bufferObject) {
2047             reattachDepth = true;
2048             reattachStencil = true;
2049         }
2050         break;
2051     case GraphicsContext3D::DEPTH_ATTACHMENT:
2052         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
2053         if (!bufferObject)
2054             reattachDepthStencilDepth = true;
2055         break;
2056     case GraphicsContext3D::STENCIL_ATTACHMENT:
2057         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
2058         if (!bufferObject)
2059             reattachDepthStencilStencil = true;
2060         break;
2061     default:
2062         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
2063     }
2064     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
2065     if (reattachDepth) {
2066         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT));
2067         if (object)
2068             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
2069     }
2070     if (reattachStencil) {
2071         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT));
2072         if (object)
2073             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
2074     }
2075     if (reattachDepthStencilDepth) {
2076         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
2077         if (object)
2078             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
2079     }
2080     if (reattachDepthStencilStencil) {
2081         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
2082         if (object)
2083             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
2084     }
2085     cleanupAfterGraphicsCall(false);
2086 }
2087
2088 void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
2089 {
2090     UNUSED_PARAM(ec);
2091     if (isContextLost() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
2092         return;
2093     if (level) {
2094         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "framebufferTexture2D", "level not 0");
2095         return;
2096     }
2097     if (texture && !texture->validate(contextGroup(), this)) {
2098         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
2099         return;
2100     }
2101     // Don't allow the default framebuffer to be mutated; all current
2102     // implementations use an FBO internally in place of the default
2103     // FBO.
2104     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2105         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
2106         return;
2107     }
2108     m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level);
2109     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
2110     cleanupAfterGraphicsCall(false);
2111 }
2112
2113 void WebGLRenderingContext::frontFace(GC3Denum mode)
2114 {
2115     if (isContextLost())
2116         return;
2117     m_context->frontFace(mode);
2118     cleanupAfterGraphicsCall(false);
2119 }
2120
2121 void WebGLRenderingContext::generateMipmap(GC3Denum target)
2122 {
2123     if (isContextLost())
2124         return;
2125     WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
2126     if (!tex)
2127         return;
2128     if (!tex->canGenerateMipmaps()) {
2129         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
2130         return;
2131     }
2132     // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
2133     // on Mac.  Remove the hack once this driver bug is fixed.
2134 #if OS(DARWIN)
2135     bool needToResetMinFilter = false;
2136     if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
2137         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
2138         needToResetMinFilter = true;
2139     }
2140 #endif
2141     m_context->generateMipmap(target);
2142 #if OS(DARWIN)
2143     if (needToResetMinFilter)
2144         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
2145 #endif
2146     tex->generateMipmapLevelInfo();
2147     cleanupAfterGraphicsCall(false);
2148 }
2149
2150 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2151 {
2152     UNUSED_PARAM(ec);
2153     if (isContextLost() || !validateWebGLObject("getActiveAttrib", program))
2154         return 0;
2155     ActiveInfo info;
2156     if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
2157         return 0;
2158     return WebGLActiveInfo::create(info.name, info.type, info.size);
2159 }
2160
2161 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2162 {
2163     UNUSED_PARAM(ec);
2164     if (isContextLost() || !validateWebGLObject("getActiveUniform", program))
2165         return 0;
2166     ActiveInfo info;
2167     if (!m_context->getActiveUniform(objectOrZero(program), index, info))
2168         return 0;
2169     if (!isGLES2Compliant())
2170         if (info.size > 1 && !info.name.endsWith("[0]"))
2171             info.name.append("[0]");
2172     return WebGLActiveInfo::create(info.name, info.type, info.size);
2173 }
2174
2175 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader> >& shaderObjects, ExceptionCode& ec)
2176 {
2177     UNUSED_PARAM(ec);
2178     shaderObjects.clear();
2179     if (isContextLost() || !validateWebGLObject("getAttachedShaders", program))
2180         return false;
2181
2182     const GC3Denum shaderType[] = {
2183         GraphicsContext3D::VERTEX_SHADER,
2184         GraphicsContext3D::FRAGMENT_SHADER
2185     };
2186     for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
2187         WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2188         if (shader)
2189             shaderObjects.append(shader);
2190     }
2191     return true;
2192 }
2193
2194 GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
2195 {
2196     if (isContextLost() || !validateWebGLObject("getAttribLocation", program))
2197         return -1;
2198     if (!validateLocationLength("getAttribLocation", name))
2199         return -1;
2200     if (!validateString("getAttribLocation", name))
2201         return -1;
2202     if (isPrefixReserved(name))
2203         return -1;
2204     if (!program->getLinkStatus()) {
2205         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getAttribLocation", "program not linked");
2206         return 0;
2207     }
2208     return m_context->getAttribLocation(objectOrZero(program), name);
2209 }
2210
2211 WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2212 {
2213     UNUSED_PARAM(ec);
2214     if (isContextLost())
2215         return WebGLGetInfo();
2216     if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
2217         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid target");
2218         return WebGLGetInfo();
2219     }
2220
2221     if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
2222         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2223         return WebGLGetInfo();
2224     }
2225
2226     WebGLStateRestorer(this, false);
2227     GC3Dint value = 0;
2228     m_context->getBufferParameteriv(target, pname, &value);
2229     if (pname == GraphicsContext3D::BUFFER_SIZE)
2230         return WebGLGetInfo(value);
2231     return WebGLGetInfo(static_cast<unsigned int>(value));
2232 }
2233
2234 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
2235 {
2236     if (isContextLost())
2237         return 0;
2238     // We always need to return a new WebGLContextAttributes object to
2239     // prevent the user from mutating any cached version.
2240     return WebGLContextAttributes::create(m_context->getContextAttributes());
2241 }
2242
2243 GC3Denum WebGLRenderingContext::getError()
2244 {
2245     return m_context->getError();
2246 }
2247
2248 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
2249 {
2250     if (isContextLost())
2251         return 0;
2252
2253     if (equalIgnoringCase(name, "WEBKIT_EXT_texture_filter_anisotropic")
2254         && m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic")) {
2255         if (!m_extTextureFilterAnisotropic) {
2256             m_context->getExtensions()->ensureEnabled("GL_EXT_texture_filter_anisotropic");
2257             m_extTextureFilterAnisotropic = EXTTextureFilterAnisotropic::create(this);
2258         }
2259         return m_extTextureFilterAnisotropic.get();
2260     }
2261     if (equalIgnoringCase(name, "OES_standard_derivatives")
2262         && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
2263         if (!m_oesStandardDerivatives) {
2264             m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
2265             m_oesStandardDerivatives = OESStandardDerivatives::create(this);
2266         }
2267         return m_oesStandardDerivatives.get();
2268     }
2269     if (equalIgnoringCase(name, "OES_texture_float")
2270         && m_context->getExtensions()->supports("GL_OES_texture_float")) {
2271         if (!m_oesTextureFloat) {
2272             m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
2273             m_oesTextureFloat = OESTextureFloat::create(this);
2274         }
2275         return m_oesTextureFloat.get();
2276     }
2277     if (equalIgnoringCase(name, "OES_vertex_array_object")
2278         && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
2279         if (!m_oesVertexArrayObject) {
2280             m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
2281             m_oesVertexArrayObject = OESVertexArrayObject::create(this);
2282         }
2283         return m_oesVertexArrayObject.get();
2284     }
2285     if (equalIgnoringCase(name, "WEBKIT_WEBGL_lose_context")
2286         // FIXME: remove this after a certain grace period.
2287         || equalIgnoringCase(name, "WEBKIT_lose_context")) {
2288         if (!m_webglLoseContext)
2289             m_webglLoseContext = WebGLLoseContext::create(this);
2290         return m_webglLoseContext.get();
2291     }
2292     if (equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_s3tc")) {
2293         // Use WEBKIT_ prefix until extension is official.
2294         if (!m_webglCompressedTextureS3TC)
2295             m_webglCompressedTextureS3TC = WebGLCompressedTextureS3TC::create(this);
2296         return m_webglCompressedTextureS3TC.get();
2297     }
2298
2299     if (allowPrivilegedExtensions()) {
2300         if (equalIgnoringCase(name, "WEBGL_debug_renderer_info")) {
2301             if (!m_webglDebugRendererInfo)
2302                 m_webglDebugRendererInfo = WebGLDebugRendererInfo::create(this);
2303             return m_webglDebugRendererInfo.get();
2304         }
2305         if (equalIgnoringCase(name, "WEBGL_debug_shaders")
2306             && m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source")) {
2307             if (!m_webglDebugShaders)
2308                 m_webglDebugShaders = WebGLDebugShaders::create(this);
2309             return m_webglDebugShaders.get();
2310         }
2311     }
2312
2313     return 0;
2314 }
2315
2316 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
2317 {
2318     UNUSED_PARAM(ec);
2319     if (isContextLost() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
2320         return WebGLGetInfo();
2321
2322     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2323         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
2324         return WebGLGetInfo();
2325     }
2326
2327     WebGLSharedObject* object = m_framebufferBinding->getAttachment(attachment);
2328     if (!object) {
2329         if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2330             return WebGLGetInfo(GraphicsContext3D::NONE);
2331         // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
2332         // specifies INVALID_OPERATION.
2333         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
2334         return WebGLGetInfo();
2335     }
2336
2337     ASSERT(object->isTexture() || object->isRenderbuffer());
2338     if (object->isTexture()) {
2339         switch (pname) {
2340         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2341             return WebGLGetInfo(GraphicsContext3D::TEXTURE);
2342         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2343             return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
2344         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2345         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2346             {
2347                 WebGLStateRestorer(this, false);
2348                 GC3Dint value = 0;
2349                 m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2350                 return WebGLGetInfo(value);
2351             }
2352         default:
2353             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
2354             return WebGLGetInfo();
2355         }
2356     } else {
2357         switch (pname) {
2358         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2359             return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
2360         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2361             return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
2362         default:
2363             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
2364             return WebGLGetInfo();
2365         }
2366     }
2367 }
2368
2369 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec)
2370 {
2371     UNUSED_PARAM(ec);
2372     if (isContextLost())
2373         return WebGLGetInfo();
2374     WebGLStateRestorer(this, false);
2375     switch (pname) {
2376     case GraphicsContext3D::ACTIVE_TEXTURE:
2377         return getUnsignedIntParameter(pname);
2378     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
2379         return getWebGLFloatArrayParameter(pname);
2380     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
2381         return getWebGLFloatArrayParameter(pname);
2382     case GraphicsContext3D::ALPHA_BITS:
2383         return getIntParameter(pname);
2384     case GraphicsContext3D::ARRAY_BUFFER_BINDING:
2385         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2386     case GraphicsContext3D::BLEND:
2387         return getBooleanParameter(pname);
2388     case GraphicsContext3D::BLEND_COLOR:
2389         return getWebGLFloatArrayParameter(pname);
2390     case GraphicsContext3D::BLEND_DST_ALPHA:
2391         return getUnsignedIntParameter(pname);
2392     case GraphicsContext3D::BLEND_DST_RGB:
2393         return getUnsignedIntParameter(pname);
2394     case GraphicsContext3D::BLEND_EQUATION_ALPHA:
2395         return getUnsignedIntParameter(pname);
2396     case GraphicsContext3D::BLEND_EQUATION_RGB:
2397         return getUnsignedIntParameter(pname);
2398     case GraphicsContext3D::BLEND_SRC_ALPHA:
2399         return getUnsignedIntParameter(pname);
2400     case GraphicsContext3D::BLEND_SRC_RGB:
2401         return getUnsignedIntParameter(pname);
2402     case GraphicsContext3D::BLUE_BITS:
2403         return getIntParameter(pname);
2404     case GraphicsContext3D::COLOR_CLEAR_VALUE:
2405         return getWebGLFloatArrayParameter(pname);
2406     case GraphicsContext3D::COLOR_WRITEMASK:
2407         return getBooleanArrayParameter(pname);
2408     case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
2409         return WebGLGetInfo(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()));
2410     case GraphicsContext3D::CULL_FACE:
2411         return getBooleanParameter(pname);
2412     case GraphicsContext3D::CULL_FACE_MODE:
2413         return getUnsignedIntParameter(pname);
2414     case GraphicsContext3D::CURRENT_PROGRAM:
2415         return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2416     case GraphicsContext3D::DEPTH_BITS:
2417         return getIntParameter(pname);
2418     case GraphicsContext3D::DEPTH_CLEAR_VALUE:
2419         return getFloatParameter(pname);
2420     case GraphicsContext3D::DEPTH_FUNC:
2421         return getUnsignedIntParameter(pname);
2422     case GraphicsContext3D::DEPTH_RANGE:
2423         return getWebGLFloatArrayParameter(pname);
2424     case GraphicsContext3D::DEPTH_TEST:
2425         return getBooleanParameter(pname);
2426     case GraphicsContext3D::DEPTH_WRITEMASK:
2427         return getBooleanParameter(pname);
2428     case GraphicsContext3D::DITHER:
2429         return getBooleanParameter(pname);
2430     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
2431         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
2432     case GraphicsContext3D::FRAMEBUFFER_BINDING:
2433         return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2434     case GraphicsContext3D::FRONT_FACE:
2435         return getUnsignedIntParameter(pname);
2436     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2437         return getUnsignedIntParameter(pname);
2438     case GraphicsContext3D::GREEN_BITS:
2439         return getIntParameter(pname);
2440     case GraphicsContext3D::LINE_WIDTH:
2441         return getFloatParameter(pname);
2442     case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2443         return getIntParameter(pname);
2444     case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
2445         return getIntParameter(pname);
2446     case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
2447         return getIntParameter(pname);
2448     case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
2449         return getIntParameter(pname);
2450     case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
2451         return getIntParameter(pname);
2452     case GraphicsContext3D::MAX_TEXTURE_SIZE:
2453         return getIntParameter(pname);
2454     case GraphicsContext3D::MAX_VARYING_VECTORS:
2455         return getIntParameter(pname);
2456     case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
2457         return getIntParameter(pname);
2458     case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2459         return getIntParameter(pname);
2460     case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
2461         return getIntParameter(pname);
2462     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
2463         return getWebGLIntArrayParameter(pname);
2464     case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
2465         // FIXME: should we always return 0 for this?
2466         return getIntParameter(pname);
2467     case GraphicsContext3D::PACK_ALIGNMENT:
2468         return getIntParameter(pname);
2469     case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
2470         return getFloatParameter(pname);
2471     case GraphicsContext3D::POLYGON_OFFSET_FILL:
2472         return getBooleanParameter(pname);
2473     case GraphicsContext3D::POLYGON_OFFSET_UNITS:
2474         return getFloatParameter(pname);
2475     case GraphicsContext3D::RED_BITS:
2476         return getIntParameter(pname);
2477     case GraphicsContext3D::RENDERBUFFER_BINDING:
2478         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2479     case GraphicsContext3D::RENDERER:
2480         return WebGLGetInfo(String("WebKit WebGL"));
2481     case GraphicsContext3D::SAMPLE_BUFFERS:
2482         return getIntParameter(pname);
2483     case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
2484         return getBooleanParameter(pname);
2485     case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
2486         return getFloatParameter(pname);
2487     case GraphicsContext3D::SAMPLES:
2488         return getIntParameter(pname);
2489     case GraphicsContext3D::SCISSOR_BOX:
2490         return getWebGLIntArrayParameter(pname);
2491     case GraphicsContext3D::SCISSOR_TEST:
2492         return getBooleanParameter(pname);
2493     case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
2494         return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
2495     case GraphicsContext3D::STENCIL_BACK_FAIL:
2496         return getUnsignedIntParameter(pname);
2497     case GraphicsContext3D::STENCIL_BACK_FUNC:
2498         return getUnsignedIntParameter(pname);
2499     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
2500         return getUnsignedIntParameter(pname);
2501     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
2502         return getUnsignedIntParameter(pname);
2503     case GraphicsContext3D::STENCIL_BACK_REF:
2504         return getIntParameter(pname);
2505     case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
2506         return getUnsignedIntParameter(pname);
2507     case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
2508         return getUnsignedIntParameter(pname);
2509     case GraphicsContext3D::STENCIL_BITS:
2510         return getIntParameter(pname);
2511     case GraphicsContext3D::STENCIL_CLEAR_VALUE:
2512         return getIntParameter(pname);
2513     case GraphicsContext3D::STENCIL_FAIL:
2514         return getUnsignedIntParameter(pname);
2515     case GraphicsContext3D::STENCIL_FUNC:
2516         return getUnsignedIntParameter(pname);
2517     case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
2518         return getUnsignedIntParameter(pname);
2519     case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
2520         return getUnsignedIntParameter(pname);
2521     case GraphicsContext3D::STENCIL_REF:
2522         return getIntParameter(pname);
2523     case GraphicsContext3D::STENCIL_TEST:
2524         return getBooleanParameter(pname);
2525     case GraphicsContext3D::STENCIL_VALUE_MASK:
2526         return getUnsignedIntParameter(pname);
2527     case GraphicsContext3D::STENCIL_WRITEMASK:
2528         return getUnsignedIntParameter(pname);
2529     case GraphicsContext3D::SUBPIXEL_BITS:
2530         return getIntParameter(pname);
2531     case GraphicsContext3D::TEXTURE_BINDING_2D:
2532         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
2533     case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
2534         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
2535     case GraphicsContext3D::UNPACK_ALIGNMENT:
2536         return getIntParameter(pname);
2537     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2538         return WebGLGetInfo(m_unpackFlipY);
2539     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2540         return WebGLGetInfo(m_unpackPremultiplyAlpha);
2541     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2542         return WebGLGetInfo(m_unpackColorspaceConversion);
2543     case GraphicsContext3D::VENDOR:
2544         return WebGLGetInfo(String("WebKit"));
2545     case GraphicsContext3D::VERSION:
2546         return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
2547     case GraphicsContext3D::VIEWPORT:
2548         return getWebGLIntArrayParameter(pname);
2549     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2550         if (m_oesStandardDerivatives)
2551             return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2552         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
2553         return WebGLGetInfo();
2554     case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
2555         if (m_webglDebugRendererInfo)
2556             return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
2557         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2558         return WebGLGetInfo();
2559     case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
2560         if (m_webglDebugRendererInfo)
2561             return WebGLGetInfo(m_context->getString(GraphicsContext3D::VENDOR));
2562         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2563         return WebGLGetInfo();
2564     case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2565         if (m_oesVertexArrayObject) {
2566             if (!m_boundVertexArrayObject->isDefaultObject())
2567                 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2568             return WebGLGetInfo();
2569         }
2570         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
2571         return WebGLGetInfo();
2572     case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2573         if (m_extTextureFilterAnisotropic)
2574             return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT);
2575         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2576         return WebGLGetInfo();
2577     default:
2578         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name");
2579         return WebGLGetInfo();
2580     }
2581 }
2582
2583 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2584 {
2585     UNUSED_PARAM(ec);
2586     if (isContextLost() || !validateWebGLObject("getProgramParameter", program))
2587         return WebGLGetInfo();
2588
2589     WebGLStateRestorer(this, false);
2590     GC3Dint value = 0;
2591     switch (pname) {
2592     case GraphicsContext3D::DELETE_STATUS:
2593         return WebGLGetInfo(program->isDeleted());
2594     case GraphicsContext3D::VALIDATE_STATUS:
2595         m_context->getProgramiv(objectOrZero(program), pname, &value);
2596         return WebGLGetInfo(static_cast<bool>(value));
2597     case GraphicsContext3D::LINK_STATUS:
2598         return WebGLGetInfo(program->getLinkStatus());
2599     case GraphicsContext3D::ATTACHED_SHADERS:
2600     case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2601     case GraphicsContext3D::ACTIVE_UNIFORMS:
2602         m_context->getProgramiv(objectOrZero(program), pname, &value);
2603         return WebGLGetInfo(value);
2604     default:
2605         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2606         return WebGLGetInfo();
2607     }
2608 }
2609
2610 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2611 {
2612     UNUSED_PARAM(ec);
2613     if (isContextLost())
2614         return String();
2615     if (!validateWebGLObject("getProgramInfoLog", program))
2616         return "";
2617     WebGLStateRestorer(this, false);
2618     return ensureNotNull(m_context->getProgramInfoLog(objectOrZero(program)));
2619 }
2620
2621 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2622 {
2623     UNUSED_PARAM(ec);
2624     if (isContextLost())
2625         return WebGLGetInfo();
2626     if (target != GraphicsContext3D::RENDERBUFFER) {
2627         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2628         return WebGLGetInfo();
2629     }
2630     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2631         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2632         return WebGLGetInfo();
2633     }
2634
2635     if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2636         && !m_renderbufferBinding->isValid()) {
2637         ASSERT(!isDepthStencilSupported());
2638         int value = 0;
2639         switch (pname) {
2640         case GraphicsContext3D::RENDERBUFFER_WIDTH:
2641             value = m_renderbufferBinding->getWidth();
2642             break;
2643         case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2644             value = m_renderbufferBinding->getHeight();
2645             break;
2646         case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2647         case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2648         case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2649         case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2650             value = 0;
2651             break;
2652         case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2653             value = 24;
2654             break;
2655         case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2656             value = 8;
2657             break;
2658         case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2659             return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2660         default:
2661             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2662             return WebGLGetInfo();
2663         }
2664         return WebGLGetInfo(value);
2665     }
2666
2667     WebGLStateRestorer(this, false);
2668     GC3Dint value = 0;
2669     switch (pname) {
2670     case GraphicsContext3D::RENDERBUFFER_WIDTH:
2671     case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2672     case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2673     case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2674     case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2675     case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2676     case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2677     case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2678         m_context->getRenderbufferParameteriv(target, pname, &value);
2679         return WebGLGetInfo(value);
2680     case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2681         return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2682     default:
2683         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2684         return WebGLGetInfo();
2685     }
2686 }
2687
2688 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
2689 {
2690     UNUSED_PARAM(ec);
2691     if (isContextLost() || !validateWebGLObject("getShaderParameter", shader))
2692         return WebGLGetInfo();
2693     WebGLStateRestorer(this, false);
2694     GC3Dint value = 0;
2695     switch (pname) {
2696     case GraphicsContext3D::DELETE_STATUS:
2697         return WebGLGetInfo(shader->isDeleted());
2698     case GraphicsContext3D::COMPILE_STATUS:
2699         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2700         return WebGLGetInfo(static_cast<bool>(value));
2701     case GraphicsContext3D::SHADER_TYPE:
2702         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2703         return WebGLGetInfo(static_cast<unsigned int>(value));
2704     default:
2705         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderParameter", "invalid parameter name");
2706         return WebGLGetInfo();
2707     }
2708 }
2709
2710 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
2711 {
2712     UNUSED_PARAM(ec);
2713     if (isContextLost())
2714         return String();
2715     if (!validateWebGLObject("getShaderInfoLog", shader))
2716         return "";
2717     WebGLStateRestorer(this, false);
2718     return ensureNotNull(m_context->getShaderInfoLog(objectOrZero(shader)));
2719 }
2720
2721 PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContext::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode& ec)
2722 {
2723     UNUSED_PARAM(ec);
2724     if (isContextLost())
2725         return 0;
2726     switch (shaderType) {
2727     case GraphicsContext3D::VERTEX_SHADER:
2728     case GraphicsContext3D::FRAGMENT_SHADER:
2729         break;
2730     default:
2731         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
2732         return 0;
2733     }
2734     switch (precisionType) {
2735     case GraphicsContext3D::LOW_FLOAT:
2736     case GraphicsContext3D::MEDIUM_FLOAT:
2737     case GraphicsContext3D::HIGH_FLOAT:
2738     case GraphicsContext3D::LOW_INT:
2739     case GraphicsContext3D::MEDIUM_INT:
2740     case GraphicsContext3D::HIGH_INT:
2741         break;
2742     default:
2743         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
2744         return 0;
2745     }
2746
2747     GC3Dint range[2] = {0, 0};
2748     GC3Dint precision = 0;
2749     m_context->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
2750     return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
2751 }
2752
2753 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
2754 {
2755     UNUSED_PARAM(ec);
2756     if (isContextLost())
2757         return String();
2758     if (!validateWebGLObject("getShaderSource", shader))
2759         return "";
2760     return ensureNotNull(shader->getSource());
2761 }
2762
2763 Vector<String> WebGLRenderingContext::getSupportedExtensions()
2764 {
2765     Vector<String> result;
2766     if (m_context->getExtensions()->supports("GL_OES_texture_float"))
2767         result.append("OES_texture_float");
2768     if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
2769         result.append("OES_standard_derivatives");
2770     if (m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic"))
2771         result.append("WEBKIT_EXT_texture_filter_anisotropic");
2772     if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
2773         result.append("OES_vertex_array_object");
2774     result.append("WEBKIT_WEBGL_lose_context");
2775     if (WebGLCompressedTextureS3TC::supported(this))
2776         result.append("WEBKIT_WEBGL_compressed_texture_s3tc");
2777
2778     if (allowPrivilegedExtensions()) {
2779         if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
2780             result.append("WEBGL_debug_shaders");
2781         result.append("WEBGL_debug_renderer_info");
2782     }
2783
2784     return result;
2785 }
2786
2787 WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2788 {
2789     UNUSED_PARAM(ec);
2790     if (isContextLost())
2791         return WebGLGetInfo();
2792     WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
2793     if (!tex)
2794         return WebGLGetInfo();
2795     WebGLStateRestorer(this, false);
2796     GC3Dint value = 0;
2797     switch (pname) {
2798     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2799     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2800     case GraphicsContext3D::TEXTURE_WRAP_S:
2801     case GraphicsContext3D::TEXTURE_WRAP_T:
2802         m_context->getTexParameteriv(target, pname, &value);
2803         return WebGLGetInfo(static_cast<unsigned int>(value));
2804     case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2805         if (m_extTextureFilterAnisotropic) {
2806             m_context->getTexParameteriv(target, pname, &value);
2807             return WebGLGetInfo(static_cast<unsigned int>(value));
2808         }
2809         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2810         return WebGLGetInfo();
2811     default:
2812         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name");
2813         return WebGLGetInfo();
2814     }
2815 }
2816
2817 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2818 {
2819     UNUSED_PARAM(ec);
2820     if (isContextLost() || !validateWebGLObject("getUniform", program))
2821         return WebGLGetInfo();
2822     if (!uniformLocation || uniformLocation->program() != program) {
2823         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
2824         return WebGLGetInfo();
2825     }
2826     GC3Dint location = uniformLocation->location();
2827
2828     WebGLStateRestorer(this, false);
2829     // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2830     GC3Dint activeUniforms = 0;
2831     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2832     for (GC3Dint i = 0; i < activeUniforms; i++) {
2833         ActiveInfo info;
2834         if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2835             return WebGLGetInfo();
2836         // Strip "[0]" from the name if it's an array.
2837         if (info.size > 1 && info.name.endsWith("[0]"))
2838             info.name = info.name.left(info.name.length() - 3);
2839         // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2840         for (GC3Dint index = 0; index < info.size; ++index) {
2841             String name = info.name;
2842             if (info.size > 1 && index >= 1) {
2843                 name.append('[');
2844                 name.append(String::number(index));
2845                 name.append(']');
2846             }
2847             // Now need to look this up by name again to find its location
2848             GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name);
2849             if (loc == location) {
2850                 // Found it. Use the type in the ActiveInfo to determine the return type.
2851                 GC3Denum baseType;
2852                 unsigned int length;
2853                 switch (info.type) {
2854                 case GraphicsContext3D::BOOL:
2855                     baseType = GraphicsContext3D::BOOL;
2856                     length = 1;
2857                     break;
2858                 case GraphicsContext3D::BOOL_VEC2:
2859                     baseType = GraphicsContext3D::BOOL;
2860                     length = 2;
2861                     break;
2862                 case GraphicsContext3D::BOOL_VEC3:
2863                     baseType = GraphicsContext3D::BOOL;
2864                     length = 3;
2865                     break;
2866                 case GraphicsContext3D::BOOL_VEC4:
2867                     baseType = GraphicsContext3D::BOOL;
2868                     length = 4;
2869                     break;
2870                 case GraphicsContext3D::INT:
2871                     baseType = GraphicsContext3D::INT;
2872                     length = 1;
2873                     break;
2874                 case GraphicsContext3D::INT_VEC2:
2875                     baseType = GraphicsContext3D::INT;
2876                     length = 2;
2877                     break;
2878                 case GraphicsContext3D::INT_VEC3:
2879                     baseType = GraphicsContext3D::INT;
2880                     length = 3;
2881                     break;
2882                 case GraphicsContext3D::INT_VEC4:
2883                     baseType = GraphicsContext3D::INT;
2884                     length = 4;
2885                     break;
2886                 case GraphicsContext3D::FLOAT:
2887                     baseType = GraphicsContext3D::FLOAT;
2888                     length = 1;
2889                     break;
2890                 case GraphicsContext3D::FLOAT_VEC2:
2891                     baseType = GraphicsContext3D::FLOAT;
2892                     length = 2;
2893                     break;
2894                 case GraphicsContext3D::FLOAT_VEC3:
2895                     baseType = GraphicsContext3D::FLOAT;
2896                     length = 3;
2897                     break;
2898                 case GraphicsContext3D::FLOAT_VEC4:
2899                     baseType = GraphicsContext3D::FLOAT;
2900                     length = 4;
2901                     break;
2902                 case GraphicsContext3D::FLOAT_MAT2:
2903                     baseType = GraphicsContext3D::FLOAT;
2904                     length = 4;
2905                     break;
2906                 case GraphicsContext3D::FLOAT_MAT3:
2907                     baseType = GraphicsContext3D::FLOAT;
2908                     length = 9;
2909                     break;
2910                 case GraphicsContext3D::FLOAT_MAT4:
2911                     baseType = GraphicsContext3D::FLOAT;
2912                     length = 16;
2913                     break;
2914                 case GraphicsContext3D::SAMPLER_2D:
2915                 case GraphicsContext3D::SAMPLER_CUBE:
2916                     baseType = GraphicsContext3D::INT;
2917                     length = 1;
2918                     break;
2919                 default:
2920                     // Can't handle this type
2921                     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unhandled type");
2922                     return WebGLGetInfo();
2923                 }
2924                 switch (baseType) {
2925                 case GraphicsContext3D::FLOAT: {
2926                     GC3Dfloat value[16] = {0};
2927                     m_context->getUniformfv(objectOrZero(program), location, value);
2928                     if (length == 1)
2929                         return WebGLGetInfo(value[0]);
2930                     return WebGLGetInfo(Float32Array::create(value, length));
2931                 }
2932                 case GraphicsContext3D::INT: {
2933                     GC3Dint value[4] = {0};
2934                     m_context->getUniformiv(objectOrZero(program), location, value);
2935                     if (length == 1)
2936                         return WebGLGetInfo(value[0]);
2937                     return WebGLGetInfo(Int32Array::create(value, length));
2938                 }
2939                 case GraphicsContext3D::BOOL: {
2940                     GC3Dint value[4] = {0};
2941                     m_context->getUniformiv(objectOrZero(program), location, value);
2942                     if (length > 1) {
2943                         bool boolValue[16] = {0};
2944                         for (unsigned j = 0; j < length; j++)
2945                             boolValue[j] = static_cast<bool>(value[j]);
2946                         return WebGLGetInfo(boolValue, length);
2947                     }
2948                     return WebGLGetInfo(static_cast<bool>(value[0]));
2949                 }
2950                 default:
2951                     notImplemented();
2952                 }
2953             }
2954         }
2955     }
2956     // If we get here, something went wrong in our unfortunately complex logic above
2957     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unknown error");
2958     return WebGLGetInfo();
2959 }
2960
2961 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
2962 {
2963     UNUSED_PARAM(ec);
2964     if (isContextLost() || !validateWebGLObject("getUniformLocation", program))
2965         return 0;
2966     if (!validateLocationLength("getUniformLocation", name))
2967         return 0;
2968     if (!validateString("getUniformLocation", name))
2969         return 0;
2970     if (isPrefixReserved(name))
2971         return 0;
2972     if (!program->getLinkStatus()) {
2973         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniformLocation", "program not linked");
2974         return 0;
2975     }
2976     WebGLStateRestorer(this, false);
2977     GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2978     if (uniformLocation == -1)
2979         return 0;
2980     return WebGLUniformLocation::create(program, uniformLocation);
2981 }
2982
2983 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
2984 {
2985     UNUSED_PARAM(ec);
2986     if (isContextLost())
2987         return WebGLGetInfo();
2988     WebGLStateRestorer(this, false);
2989     if (index >= m_maxVertexAttribs) {
2990         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
2991         return WebGLGetInfo();
2992     }
2993     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2994     switch (pname) {
2995     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2996         if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
2997             || !state.bufferBinding
2998             || !state.bufferBinding->object())
2999             return WebGLGetInfo();
3000         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
3001     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
3002         return WebGLGetInfo(state.enabled);
3003     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
3004         return WebGLGetInfo(state.normalized);
3005     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
3006         return WebGLGetInfo(state.size);
3007     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
3008         return WebGLGetInfo(state.originalStride);
3009     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
3010         return WebGLGetInfo(state.type);
3011     case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
3012         return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
3013     default:
3014         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
3015         return WebGLGetInfo();
3016     }
3017 }
3018
3019 GC3Dsizeiptr WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
3020 {
3021     if (isContextLost())
3022         return 0;
3023     GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
3024     cleanupAfterGraphicsCall(false);
3025     return result;
3026 }
3027
3028 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
3029 {
3030     if (isContextLost())
3031         return;
3032     bool isValid = false;
3033     switch (target) {
3034     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
3035         isValid = true;
3036         break;
3037     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
3038         if (m_oesStandardDerivatives)
3039             isValid = true;
3040         break;
3041     }
3042     if (!isValid) {
3043         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target");
3044         return;
3045     }
3046     m_context->hint(target, mode);
3047     cleanupAfterGraphicsCall(false);
3048 }
3049
3050 GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
3051 {
3052     if (!buffer || isContextLost())
3053         return 0;
3054
3055     if (!buffer->hasEverBeenBound())
3056         return 0;
3057
3058     return m_context->isBuffer(buffer->object());
3059 }
3060
3061 bool WebGLRenderingContext::isContextLost()
3062 {
3063     return m_contextLost;
3064 }
3065
3066 GC3Dboolean WebGLRenderingContext::isEnabled(GC3Denum cap)
3067 {
3068     if (isContextLost() || !validateCapability("isEnabled", cap))
3069         return 0;
3070     return m_context->isEnabled(cap);
3071 }
3072
3073 GC3Dboolean WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer)
3074 {
3075     if (!framebuffer || isContextLost())
3076         return 0;
3077
3078     if (!framebuffer->hasEverBeenBound())
3079         return 0;
3080
3081     return m_context->isFramebuffer(framebuffer->object());
3082 }
3083
3084 GC3Dboolean WebGLRenderingContext::isProgram(WebGLProgram* program)
3085 {
3086     if (!program || isContextLost())
3087         return 0;
3088
3089     return m_context->isProgram(program->object());
3090 }
3091
3092 GC3Dboolean WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
3093 {
3094     if (!renderbuffer || isContextLost())
3095         return 0;
3096
3097     if (!renderbuffer->hasEverBeenBound())
3098         return 0;
3099
3100     return m_context->isRenderbuffer(renderbuffer->object());
3101 }
3102
3103 GC3Dboolean WebGLRenderingContext::isShader(WebGLShader* shader)
3104 {
3105     if (!shader || isContextLost())
3106         return 0;
3107
3108     return m_context->isShader(shader->object());
3109 }
3110
3111 GC3Dboolean WebGLRenderingContext::isTexture(WebGLTexture* texture)
3112 {
3113     if (!texture || isContextLost())
3114         return 0;
3115
3116     if (!texture->hasEverBeenBound())
3117         return 0;
3118
3119     return m_context->isTexture(texture->object());
3120 }
3121
3122 void WebGLRenderingContext::lineWidth(GC3Dfloat width)
3123 {
3124     if (isContextLost())
3125         return;
3126     m_context->lineWidth(width);
3127     cleanupAfterGraphicsCall(false);
3128 }
3129
3130 void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec)
3131 {
3132     UNUSED_PARAM(ec);
3133     if (isContextLost() || !validateWebGLObject("linkProgram", program))
3134         return;
3135     if (!isGLES2Compliant()) {
3136         if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
3137             program->setLinkStatus(false);
3138             return;
3139         }
3140     }
3141
3142     m_context->linkProgram(objectOrZero(program));
3143     program->increaseLinkCount();
3144     cleanupAfterGraphicsCall(false);
3145 }
3146
3147 void WebGLRenderingContext::pixelStorei(GC3Denum pname, GC3Dint param)
3148 {
3149     if (isContextLost())
3150         return;
3151     switch (pname) {
3152     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
3153         m_unpackFlipY = param;
3154         break;
3155     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
3156         m_unpackPremultiplyAlpha = param;
3157         break;
3158     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
3159         if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
3160             m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
3161         else {
3162             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
3163             return;
3164         }
3165         break;
3166     case GraphicsContext3D::PACK_ALIGNMENT:
3167     case GraphicsContext3D::UNPACK_ALIGNMENT:
3168         if (param == 1 || param == 2 || param == 4 || param == 8) {
3169             if (pname == GraphicsContext3D::PACK_ALIGNMENT)
3170                 m_packAlignment = param;
3171             else // GraphicsContext3D::UNPACK_ALIGNMENT:
3172                 m_unpackAlignment = param;
3173             m_context->pixelStorei(pname, param);
3174             cleanupAfterGraphicsCall(false);
3175         } else {
3176             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
3177             return;
3178         }
3179         break;
3180     default:
3181         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "pixelStorei", "invalid parameter name");
3182         return;
3183     }
3184 }
3185
3186 void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
3187 {
3188     if (isContextLost())
3189         return;
3190     m_context->polygonOffset(factor, units);
3191     cleanupAfterGraphicsCall(false);
3192 }
3193
3194 void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&)
3195 {
3196     if (isContextLost())
3197         return;
3198     // Due to WebGL's same-origin restrictions, it is not possible to
3199     // taint the origin using the WebGL API.
3200     ASSERT(canvas()->originClean());
3201     // Validate input parameters.
3202     if (!pixels) {
3203         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "readPixels", "no destination ArrayBufferView");
3204         return;
3205     }
3206     switch (format) {
3207     case GraphicsContext3D::ALPHA:
3208     case GraphicsContext3D::RGB:
3209     case GraphicsContext3D::RGBA:
3210         break;
3211     default:
3212         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid format");
3213         return;
3214     }
3215     switch (type) {
3216     case GraphicsContext3D::UNSIGNED_BYTE:
3217     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
3218     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
3219     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
3220         break;
3221     default:
3222         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid type");
3223         return;
3224     }
3225     if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
3226         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "format not RGBA or type not UNSIGNED_BYTE");
3227         return;
3228     }
3229     // Validate array type against pixel type.
3230     if (!pixels->isUnsignedByteArray()) {
3231         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not Uint8Array");
3232         return;
3233     }
3234     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
3235         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "readPixels", "framebuffer not readable");
3236         return;
3237     }
3238     // Calculate array size, taking into consideration of PACK_ALIGNMENT.
3239     unsigned int totalBytesRequired;
3240     unsigned int padding;
3241     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
3242     if (error != GraphicsContext3D::NO_ERROR) {
3243         synthesizeGLError(error, "readPixels", "invalid dimensions");
3244         return;
3245     }
3246     if (pixels->byteLength() < totalBytesRequired) {
3247         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
3248         return;
3249     }
3250     clearIfComposited();
3251     void* data = pixels->baseAddress();
3252
3253     {
3254         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
3255         m_context->readPixels(x, y, width, height, format, type, data);
3256     }
3257
3258 #if OS(DARWIN)
3259     // FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
3260     // when alpha is off, readPixels should set alpha to 255 instead of 0.
3261     if (!m_context->getContextAttributes().alpha) {
3262         unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
3263         for (GC3Dsizei iy = 0; iy < height; ++iy) {
3264             for (GC3Dsizei ix = 0; ix < width; ++ix) {
3265                 pixels[3] = 255;
3266                 pixels += 4;
3267             }
3268             pixels += padding;
3269         }
3270     }
3271 #endif
3272     cleanupAfterGraphicsCall(false);
3273 }
3274
3275 void WebGLRenderingContext::releaseShaderCompiler()
3276 {
3277     if (isContextLost())
3278         return;
3279     m_context->releaseShaderCompiler();
3280     cleanupAfterGraphicsCall(false);
3281 }
3282
3283 void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
3284 {
3285     if (isContextLost())
3286         return;
3287     if (target != GraphicsContext3D::RENDERBUFFER) {
3288         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid target");
3289         return;
3290     }
3291     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
3292         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer");
3293         return;
3294     }
3295     if (!validateSize("renderbufferStorage", width, height))
3296         return;
3297     switch (internalformat) {
3298     case GraphicsContext3D::DEPTH_COMPONENT16:
3299     case GraphicsContext3D::RGBA4:
3300     case GraphicsContext3D::RGB5_A1:
3301     case GraphicsContext3D::RGB565:
3302     case GraphicsContext3D::STENCIL_INDEX8:
3303         m_context->renderbufferStorage(target, internalformat, width, height);
3304         m_renderbufferBinding->setInternalFormat(internalformat);
3305         m_renderbufferBinding->setIsValid(true);
3306         m_renderbufferBinding->setSize(width, height);
3307         cleanupAfterGraphicsCall(false);
3308         break;
3309     case GraphicsContext3D::DEPTH_STENCIL:
3310         if (isDepthStencilSupported()) {
3311             m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
3312             cleanupAfterGraphicsCall(false);
3313         }
3314         m_renderbufferBinding->setSize(width, height);
3315         m_renderbufferBinding->setIsValid(isDepthStencilSupported());
3316         m_renderbufferBinding->setInternalFormat(internalformat);
3317         break;
3318     default:
3319         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
3320     }
3321 }
3322
3323 void WebGLRenderingContext::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
3324 {
3325     if (isContextLost())
3326         return;
3327     m_context->sampleCoverage(value, invert);
3328     cleanupAfterGraphicsCall(false);
3329 }
3330
3331 void WebGLRenderingContext::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
3332 {
3333     if (isContextLost())
3334         return;
3335     if (!validateSize("scissor", width, height))
3336         return;
3337     m_context->scissor(x, y, width, height);
3338     cleanupAfterGraphicsCall(false);
3339 }
3340
3341 void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
3342 {
3343     UNUSED_PARAM(ec);
3344     if (isContextLost() || !validateWebGLObject("shaderSource", shader))
3345         return;
3346     String stringWithoutComments = StripComments(string).result();
3347     if (!validateString("shaderSource", stringWithoutComments))
3348         return;
3349     shader->setSource(string);
3350     m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
3351     cleanupAfterGraphicsCall(false);
3352 }
3353
3354 void WebGLRenderingContext::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
3355 {
3356     if (isContextLost())
3357         return;
3358     if (!validateStencilFunc("stencilFunc", func))
3359         return;
3360     m_stencilFuncRef = ref;
3361     m_stencilFuncRefBack = ref;
3362     m_stencilFuncMask = mask;
3363     m_stencilFuncMaskBack = mask;
3364     m_context->stencilFunc(func, ref, mask);
3365     cleanupAfterGraphicsCall(false);
3366 }
3367
3368 void WebGLRenderingContext::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
3369 {
3370     if (isContextLost())
3371         return;
3372     if (!validateStencilFunc("stencilFuncSeparate", func))
3373         return;
3374     switch (face) {
3375     case GraphicsContext3D::FRONT_AND_BACK:
3376         m_stencilFuncRef = ref;
3377         m_stencilFuncRefBack = ref;
3378         m_stencilFuncMask = mask;
3379         m_stencilFuncMaskBack = mask;
3380         break;
3381     case GraphicsContext3D::FRONT:
3382         m_stencilFuncRef = ref;
3383         m_stencilFuncMask = mask;
3384         break;
3385     case GraphicsContext3D::BACK:
3386         m_stencilFuncRefBack = ref;
3387         m_stencilFuncMaskBack = mask;
3388         break;
3389     default:
3390         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilFuncSeparate", "invalid face");
3391         return;
3392     }
3393     m_context->stencilFuncSeparate(face, func, ref, mask);
3394     cleanupAfterGraphicsCall(false);
3395 }
3396
3397 void WebGLRenderingContext::stencilMask(GC3Duint mask)
3398 {
3399     if (isContextLost())
3400         return;
3401     m_stencilMask = mask;
3402     m_stencilMaskBack = mask;
3403     m_context->stencilMask(mask);
3404     cleanupAfterGraphicsCall(false);
3405 }
3406
3407 void WebGLRenderingContext::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
3408 {
3409     if (isContextLost())
3410         return;
3411     switch (face) {
3412     case GraphicsContext3D::FRONT_AND_BACK:
3413         m_stencilMask = mask;
3414         m_stencilMaskBack = mask;
3415         break;
3416     case GraphicsContext3D::FRONT:
3417         m_stencilMask = mask;
3418         break;
3419     case GraphicsContext3D::BACK:
3420         m_stencilMaskBack = mask;
3421         break;
3422     default:
3423         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilMaskSeparate", "invalid face");
3424         return;
3425     }
3426     m_context->stencilMaskSeparate(face, mask);
3427     cleanupAfterGraphicsCall(false);
3428 }
3429
3430 void WebGLRenderingContext::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3431 {
3432     if (isContextLost())
3433         return;
3434     m_context->stencilOp(fail, zfail, zpass);
3435     cleanupAfterGraphicsCall(false);
3436 }
3437
3438 void WebGLRenderingContext::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3439 {
3440     if (isContextLost())
3441         return;
3442     m_context->stencilOpSeparate(face, fail, zfail, zpass);
3443     cleanupAfterGraphicsCall(false);
3444 }
3445
3446 void WebGLRenderingContext::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3447                                            GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3448                                            GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3449 {
3450     // FIXME: For now we ignore any errors returned
3451     ec = 0;
3452     if (!validateTexFuncParameters("texImage2D", target, level, internalformat, width, height, border, format, type))
3453         return;
3454     WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
3455     if (!tex)
3456         return;
3457     if (!isGLES2NPOTStrict()) {
3458         if (level && WebGLTexture::isNPOT(width, height)) {
3459             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "level > 0 not power of 2");
3460             return;
3461         }
3462     }
3463     if (!pixels) {
3464         bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
3465                                                          border, format, type, m_unpackAlignment);
3466         if (!succeed)
3467             return;
3468     } else {
3469         m_context->texImage2D(target, level, internalformat, width, height,
3470                               border, format, type, pixels);
3471     }
3472     tex->setLevelInfo(target, level, internalformat, width, height, type);
3473     cleanupAfterGraphicsCall(false);
3474 }
3475
3476 void WebGLRenderingContext::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3477                                            GC3Denum format, GC3Denum type, Image* image,
3478                                            bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3479 {
3480     ec = 0;
3481     Vector<uint8_t> data;
3482     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3483         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3484         return;
3485     }
3486     if (m_unpackAlignment != 1)
3487         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3488     texImage2DBase(target, level, internalformat, image->width(), image->height(), 0,
3489                    format, type, data.data(), ec);
3490     if (m_unpackAlignment != 1)
3491         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3492 }
3493
3494 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3495                                        GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3496                                        GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3497 {
3498     if (isContextLost() || !validateTexFuncData("texImage2D", width, height, format, type, pixels, NullAllowed))
3499         return;
3500     void* data = pixels ? pixels->baseAddress() : 0;
3501     Vector<uint8_t> tempData;
3502     bool changeUnpackAlignment = false;
3503     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3504         if (!m_context->extractTextureData(width, height, format, type,
3505                                            m_unpackAlignment,
3506                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3507                                            data,
3508                                            tempData))
3509             return;
3510         data = tempData.data();
3511         changeUnpackAlignment = true;
3512     }
3513     if (changeUnpackAlignment)
3514         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3515     texImage2DBase(target, level, internalformat, width, height, border,
3516                    format, type, data, ec);
3517     if (changeUnpackAlignment)
3518         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3519 }
3520
3521 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3522                                        GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3523 {
3524     ec = 0;
3525     if (isContextLost())
3526         return;
3527     Vector<uint8_t> data;
3528     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3529         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3530         return;
3531     }
3532     if (m_unpackAlignment != 1)
3533         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3534     texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0,
3535                    format, type, data.data(), ec);
3536     if (m_unpackAlignment != 1)
3537         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3538 }
3539
3540 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3541                                        GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3542 {
3543     ec = 0;
3544     if (isContextLost())
3545         return;
3546     if (!validateHTMLImageElement("texImage2D", image))
3547         return;
3548     if (wouldTaintOrigin(image)) {
3549         ec = SECURITY_ERR;
3550         return;
3551     }
3552
3553     texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->imageForRenderer(image->renderer()),
3554                    m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3555 }
3556
3557 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3558                                        GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3559 {
3560     ec = 0;
3561     if (isContextLost())
3562         return;
3563     if (!canvas || !canvas->buffer()) {
3564         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "no canvas");
3565         return;
3566     }
3567     if (wouldTaintOrigin(canvas)) {
3568         ec = SECURITY_ERR;
3569         return;
3570     }
3571     RefPtr<ImageData> imageData = canvas->getImageData();
3572     if (imageData)
3573         texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
3574     else
3575         texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(),
3576                        m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3577 }
3578
3579 #if ENABLE(VIDEO)
3580 PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video, ExceptionCode& ec)
3581 {
3582     if (!video || !video->videoWidth() || !video->videoHeight()) {
3583         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "no video");
3584         return 0;
3585     }
3586     IntSize size(video->videoWidth(), video->videoHeight());
3587     ImageBuffer* buf = m_videoCache.imageBuffer(size);
3588     if (!buf) {
3589         synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "texImage2D", "out of memory");
3590         return 0;
3591     }
3592     if (wouldTaintOrigin(video)) {
3593         ec = SECURITY_ERR;
3594         return 0;
3595     }
3596     IntRect destRect(0, 0, size.width(), size.height());
3597     // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
3598     video->paintCurrentFrameInContext(buf->context(), destRect);
3599     return buf->copyImage(CopyBackingStore);
3600 }
3601
3602 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3603                                        GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3604 {
3605     ec = 0;
3606     if (isContextLost())
3607         return;
3608     RefPtr<Image> image = videoFrameToImage(video, ec);
3609     if (!image)
3610         return;
3611     texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3612 }
3613 #endif
3614
3615 void WebGLRenderingContext::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
3616 {
3617     if (isContextLost())
3618         return;
3619     WebGLTexture* tex = validateTextureBinding("texParameter", target, false);
3620     if (!tex)
3621         return;
3622     switch (pname) {
3623     case GraphicsContext3D::TEXTURE_MIN_FILTER:
3624     case GraphicsContext3D::TEXTURE_MAG_FILTER:
3625         break;
3626     case GraphicsContext3D::TEXTURE_WRAP_S:
3627     case GraphicsContext3D::TEXTURE_WRAP_T:
3628         if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT)
3629             || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) {
3630             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter");
3631             return;
3632         }
3633         break;
3634     case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
3635         if (!m_extTextureFilterAnisotropic) {
3636             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter, EXT_texture_filter_anisotropic not enabled");
3637             return;
3638         }
3639         break;
3640     default:
3641         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter name");
3642         return;
3643     }
3644     if (isFloat) {
3645         tex->setParameterf(pname, paramf);
3646         m_context->texParameterf(target, pname, paramf);
3647     } else {
3648         tex->setParameteri(pname, parami);
3649         m_context->texParameteri(target, pname, parami);
3650     }
3651     cleanupAfterGraphicsCall(false);
3652 }
3653
3654 void WebGLRenderingContext::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
3655 {
3656     texParameter(target, pname, param, 0, true);
3657 }
3658
3659 void WebGLRenderingContext::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
3660 {
3661     texParameter(target, pname, 0, param, false);
3662 }
3663
3664 void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3665                                               GC3Dsizei width, GC3Dsizei height,
3666                                               GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3667 {
3668     // FIXME: For now we ignore any errors returned
3669     ec = 0;
3670     if (isContextLost())
3671         return;
3672     if (!validateTexFuncParameters("texSubImage2D", target, level, format, width, height, 0, format, type))
3673         return;
3674     if (!validateSize("texSubImage2D", xoffset, yoffset))
3675         return;
3676     WebGLTexture* tex = validateTextureBinding("texSubImage2D", target, true);
3677     if (!tex)
3678         return;
3679     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
3680         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "dimensions out of range");
3681         return;
3682     }
3683     if (tex->getInternalFormat(target, level) != format || tex->getType(target, level) != type) {
3684         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "texSubImage2D", "type and format do not match texture");
3685         return;
3686     }
3687     m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
3688     cleanupAfterGraphicsCall(false);
3689 }
3690
3691 void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3692                                               GC3Denum format, GC3Denum type,
3693                                               Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3694 {
3695     ec = 0;
3696     if (isContextLost())
3697         return;
3698     Vector<uint8_t> data;
3699     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3700         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image");
3701         return;
3702     }
3703     texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(),
3704                       format, type, data.data(), ec);
3705 }
3706
3707 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3708                                           GC3Dsizei width, GC3Dsizei height,
3709                                           GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3710 {
3711     if (isContextLost() || !validateTexFuncData("texSubImage2D", width, height, format, type, pixels, NullNotAllowed))
3712         return;
3713     void* data = pixels->baseAddress();
3714     Vector<uint8_t> tempData;
3715     bool changeUnpackAlignment = false;
3716     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3717         if (!m_context->extractTextureData(width, height, format, type,
3718                                            m_unpackAlignment,
3719                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3720                                            data,
3721                                            tempData))
3722             return;
3723         data = tempData.data();
3724         changeUnpackAlignment = true;
3725     }
3726     if (changeUnpackAlignment)
3727         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3728     texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
3729     if (changeUnpackAlignment)
3730         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3731 }
3732
3733 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3734                                           GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3735 {
3736     ec = 0;
3737     if (isContextLost())
3738         return;
3739     Vector<uint8_t> data;
3740     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3741         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image data");
3742         return;
3743     }
3744     texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(),
3745                       format, type, data.data(), ec);
3746 }
3747
3748 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3749                                           GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3750 {
3751     ec = 0;
3752     if (isContextLost())
3753         return;
3754     if (!validateHTMLImageElement("texSubImage2D", image))
3755         return;
3756     if (wouldTaintOrigin(image)) {
3757         ec = SECURITY_ERR;
3758         return;