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