initial import
[vuplus_webkit] / 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 "WebKitLoseContext.h"
36 #include "Console.h"
37 #include "DOMWindow.h"
38 #include "Extensions3D.h"
39 #include "Frame.h"
40 #include "FrameView.h"
41 #include "HTMLCanvasElement.h"
42 #include "HTMLImageElement.h"
43 #include "HTMLVideoElement.h"
44 #include "ImageBuffer.h"
45 #include "ImageData.h"
46 #include "IntSize.h"
47 #include "NotImplemented.h"
48 #include "OESStandardDerivatives.h"
49 #include "OESTextureFloat.h"
50 #include "OESVertexArrayObject.h"
51 #include "Page.h"
52 #include "RenderBox.h"
53 #include "RenderLayer.h"
54 #include "Settings.h"
55 #include "Uint16Array.h"
56 #include "WebGLActiveInfo.h"
57 #include "WebGLBuffer.h"
58 #include "WebGLContextAttributes.h"
59 #include "WebGLContextEvent.h"
60 #include "WebGLFramebuffer.h"
61 #include "WebGLProgram.h"
62 #include "WebGLRenderbuffer.h"
63 #include "WebGLShader.h"
64 #include "WebGLTexture.h"
65 #include "WebGLUniformLocation.h"
66
67 #include <wtf/ByteArray.h>
68 #include <wtf/OwnArrayPtr.h>
69 #include <wtf/PassOwnArrayPtr.h>
70 #include <wtf/text/StringBuilder.h>
71
72 #if PLATFORM(QT)
73 #undef emit
74 #endif
75
76 namespace WebCore {
77
78 const double secondsBetweenRestoreAttempts = 1.0;
79
80 namespace {
81
82     Platform3DObject objectOrZero(WebGLObject* object)
83     {
84         return object ? object->object() : 0;
85     }
86
87     void clip1D(GC3Dint start, GC3Dsizei range, GC3Dsizei sourceRange, GC3Dint* clippedStart, GC3Dsizei* clippedRange)
88     {
89         ASSERT(clippedStart && clippedRange);
90         if (start < 0) {
91             range += start;
92             start = 0;
93         }
94         GC3Dint end = start + range;
95         if (end > sourceRange)
96             range -= end - sourceRange;
97         *clippedStart = start;
98         *clippedRange = range;
99     }
100
101     // Returns false if no clipping is necessary, i.e., x, y, width, height stay the same.
102     bool clip2D(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height,
103                 GC3Dsizei sourceWidth, GC3Dsizei sourceHeight,
104                 GC3Dint* clippedX, GC3Dint* clippedY, GC3Dsizei* clippedWidth, GC3Dsizei*clippedHeight)
105     {
106         ASSERT(clippedX && clippedY && clippedWidth && clippedHeight);
107         clip1D(x, width, sourceWidth, clippedX, clippedWidth);
108         clip1D(y, height, sourceHeight, clippedY, clippedHeight);
109         return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height);
110     }
111
112     GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
113     {
114         if (value < min)
115             value = min;
116         if (value > max)
117             value = max;
118         return value;
119     }
120
121     // Return true if a character belongs to the ASCII subset as defined in
122     // GLSL ES 1.0 spec section 3.1.
123     bool validateCharacter(unsigned char c)
124     {
125         // Printing characters are valid except " $ ` @ \ ' DEL.
126         if (c >= 32 && c <= 126
127             && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
128             return true;
129         // Horizontal tab, line feed, vertical tab, form feed, carriage return
130         // are also valid.
131         if (c >= 9 && c <= 13)
132             return true;
133         return false;
134     }
135
136     // Strips comments from shader text. This allows non-ASCII characters
137     // to be used in comments without potentially breaking OpenGL
138     // implementations not expecting characters outside the GLSL ES set.
139     class StripComments {
140     public:
141         StripComments(const String& str)
142             : m_parseState(BeginningOfLine)
143             , m_sourceString(str)
144             , m_length(str.length())
145             , m_position(0)
146         {
147             parse();
148         }
149
150         String result()
151         {
152             return m_builder.toString();
153         }
154
155     private:
156         bool hasMoreCharacters()
157         {
158             return (m_position < m_length);
159         }
160
161         void parse()
162         {
163             while (hasMoreCharacters()) {
164                 process(current());
165                 // process() might advance the position.
166                 if (hasMoreCharacters())
167                     advance();
168             }
169         }
170
171         void process(UChar);
172
173         bool peek(UChar& character)
174         {
175             if (m_position + 1 >= m_length)
176                 return false;
177             character = m_sourceString[m_position + 1];
178             return true;
179         }
180
181         UChar current()
182         {
183             ASSERT(m_position < m_length);
184             return m_sourceString[m_position];
185         }
186
187         void advance()
188         {
189             ++m_position;
190         }
191
192         bool isNewline(UChar character)
193         {
194             // Don't attempt to canonicalize newline related characters.
195             return (character == '\n' || character == '\r');
196         }
197
198         void emit(UChar character)
199         {
200             m_builder.append(character);
201         }
202
203         enum ParseState {
204             // Have not seen an ASCII non-whitespace character yet on
205             // this line. Possible that we might see a preprocessor
206             // directive.
207             BeginningOfLine,
208
209             // Have seen at least one ASCII non-whitespace character
210             // on this line.
211             MiddleOfLine,
212
213             // Handling a preprocessor directive. Passes through all
214             // characters up to the end of the line. Disables comment
215             // processing.
216             InPreprocessorDirective,
217
218             // Handling a single-line comment. The comment text is
219             // replaced with a single space.
220             InSingleLineComment,
221
222             // Handling a multi-line comment. Newlines are passed
223             // through to preserve line numbers.
224             InMultiLineComment
225         };
226
227         ParseState m_parseState;
228         String m_sourceString;
229         unsigned m_length;
230         unsigned m_position;
231         StringBuilder m_builder;
232     };
233
234     void StripComments::process(UChar c)
235     {
236         if (isNewline(c)) {
237             // No matter what state we are in, pass through newlines
238             // so we preserve line numbers.
239             emit(c);
240
241             if (m_parseState != InMultiLineComment)
242                 m_parseState = BeginningOfLine;
243
244             return;
245         }
246
247         UChar temp = 0;
248         switch (m_parseState) {
249         case BeginningOfLine:
250             if (WTF::isASCIISpace(c)) {
251                 emit(c);
252                 break;
253             }
254
255             if (c == '#') {
256                 m_parseState = InPreprocessorDirective;
257                 emit(c);
258                 break;
259             }
260
261             // Transition to normal state and re-handle character.
262             m_parseState = MiddleOfLine;
263             process(c);
264             break;
265
266         case MiddleOfLine:
267             if (c == '/' && peek(temp)) {
268                 if (temp == '/') {
269                     m_parseState = InSingleLineComment;
270                     emit(' ');
271                     advance();
272                     break;
273                 }
274
275                 if (temp == '*') {
276                     m_parseState = InMultiLineComment;
277                     // Emit the comment start in case the user has
278                     // an unclosed comment and we want to later
279                     // signal an error.
280                     emit('/');
281                     emit('*');
282                     advance();
283                     break;
284                 }
285             }
286
287             emit(c);
288             break;
289
290         case InPreprocessorDirective:
291             // No matter what the character is, just pass it
292             // through. Do not parse comments in this state. This
293             // might not be the right thing to do long term, but it
294             // should handle the #error preprocessor directive.
295             emit(c);
296             break;
297
298         case InSingleLineComment:
299             // The newline code at the top of this function takes care
300             // of resetting our state when we get out of the
301             // single-line comment. Swallow all other characters.
302             break;
303
304         case InMultiLineComment:
305             if (c == '*' && peek(temp) && temp == '/') {
306                 emit('*');
307                 emit('/');
308                 m_parseState = MiddleOfLine;
309                 advance();
310                 break;
311             }
312
313             // Swallow all other characters. Unclear whether we may
314             // want or need to just emit a space per character to try
315             // to preserve column numbers for debugging purposes.
316             break;
317         }
318     }
319 } // namespace anonymous
320
321 class WebGLStateRestorer {
322 public:
323     WebGLStateRestorer(WebGLRenderingContext* context,
324                        bool changed)
325         : m_context(context)
326         , m_changed(changed)
327     {
328     }
329
330     ~WebGLStateRestorer()
331     {
332         m_context->cleanupAfterGraphicsCall(m_changed);
333     }
334
335 private:
336     WebGLRenderingContext* m_context;
337     bool m_changed;
338 };
339
340 void WebGLRenderingContext::WebGLRenderingContextRestoreTimer::fired()
341 {
342     m_context->maybeRestoreContext(RealLostContext);
343 }
344
345 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
346 public:
347     explicit WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_context(cb) { }
348     virtual void onContextLost() { m_context->forceLostContext(WebGLRenderingContext::RealLostContext); }
349     virtual ~WebGLRenderingContextLostCallback() {}
350 private:
351     WebGLRenderingContext* m_context;
352 };
353
354 PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs)
355 {
356     HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow();
357     GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
358
359     if (attributes.antialias) {
360         Page* p = canvas->document()->page();
361         if (p && !p->settings()->openGLMultisamplingEnabled())
362             attributes.antialias = false;
363     }
364
365     attributes.noExtensions = true;
366     attributes.shareResources = false;
367
368     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
369
370     if (!context) {
371         canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
372         return nullptr;
373     }
374
375     return adoptPtr(new WebGLRenderingContext(canvas, context, attributes));
376 }
377
378 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
379                                              GraphicsContext3D::Attributes attributes)
380     : CanvasRenderingContext(passedCanvas)
381     , m_context(context)
382     , m_restoreAllowed(false)
383     , m_restoreTimer(this)
384     , m_videoCache(4)
385     , m_contextLost(false)
386     , m_attributes(attributes)
387 {
388     ASSERT(m_context);
389     setupFlags();
390     initializeNewContext();
391 }
392
393 void WebGLRenderingContext::initializeNewContext()
394 {
395     ASSERT(!m_contextLost);
396     m_needsUpdate = true;
397     m_markedCanvasDirty = false;
398     m_activeTextureUnit = 0;
399     m_packAlignment = 4;
400     m_unpackAlignment = 4;
401     m_unpackFlipY = false;
402     m_unpackPremultiplyAlpha = false;
403     m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
404     m_boundArrayBuffer = 0;
405     m_currentProgram = 0;
406     m_framebufferBinding = 0;
407     m_renderbufferBinding = 0;
408     m_depthMask = true;
409     m_stencilMask = 0xFFFFFFFF;
410     m_stencilMaskBack = 0xFFFFFFFF;
411     m_stencilFuncRef = 0;
412     m_stencilFuncRefBack = 0;
413     m_stencilFuncMask = 0xFFFFFFFF;
414     m_stencilFuncMaskBack = 0xFFFFFFFF;
415     m_layerCleared = false;
416     
417     m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
418     m_scissorEnabled = false;
419     m_clearDepth = 1;
420     m_clearStencil = 0;
421     m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
422
423     GC3Dint numCombinedTextureImageUnits = 0;
424     m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
425     m_textureUnits.clear();
426     m_textureUnits.resize(numCombinedTextureImageUnits);
427
428     GC3Dint numVertexAttribs = 0;
429     m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
430     m_maxVertexAttribs = numVertexAttribs;
431     
432     m_maxTextureSize = 0;
433     m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
434     m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
435     m_maxCubeMapTextureSize = 0;
436     m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
437     m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
438     m_maxRenderbufferSize = 0;
439     m_context->getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
440     m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
441     m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
442
443     m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
444     addObject(m_defaultVertexArrayObject.get());
445     m_boundVertexArrayObject = m_defaultVertexArrayObject;
446     
447     m_vertexAttribValue.resize(m_maxVertexAttribs);
448
449     if (!isGLES2NPOTStrict())
450         createFallbackBlackTextures1x1();
451     if (!isGLES2Compliant())
452         initVertexAttrib0();
453
454     m_context->reshape(canvas()->width(), canvas()->height());
455     m_context->viewport(0, 0, canvas()->width(), canvas()->height());
456
457     m_context->setContextLostCallback(adoptPtr(new WebGLRenderingContextLostCallback(this)));
458 }
459
460 void WebGLRenderingContext::setupFlags()
461 {
462     ASSERT(m_context);
463
464     m_isGLES2Compliant = m_context->isGLES2Compliant();
465     m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs");
466     m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe");
467     if (m_isGLES2Compliant) {
468         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
469         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
470     } else {
471         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two");
472         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil");
473     }
474 }
475
476 WebGLRenderingContext::~WebGLRenderingContext()
477 {
478     detachAndRemoveAllObjects();
479     m_context->setContextLostCallback(nullptr);
480 }
481
482 void WebGLRenderingContext::markContextChanged()
483 {
484     if (m_framebufferBinding)
485         return;
486     m_context->markContextChanged();
487     m_layerCleared = false;
488 #if USE(ACCELERATED_COMPOSITING)
489     RenderBox* renderBox = canvas()->renderBox();
490     if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing())
491         renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
492     else {
493 #endif
494         if (!m_markedCanvasDirty)
495             canvas()->didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
496 #if USE(ACCELERATED_COMPOSITING)
497     }
498 #endif
499     m_markedCanvasDirty = true;
500 }
501
502 bool WebGLRenderingContext::clearIfComposited(GC3Dbitfield mask)
503 {
504     if (isContextLost()) 
505         return false;
506
507     if (!m_context->layerComposited() || m_layerCleared
508         || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
509         return false;
510
511     RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
512
513     // Determine if it's possible to combine the clear the user asked for and this clear.
514     bool combinedClear = mask && !m_scissorEnabled;
515
516     if (m_framebufferBinding)
517         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
518     m_context->disable(GraphicsContext3D::SCISSOR_TEST);
519     if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
520         m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
521                               m_colorMask[1] ? m_clearColor[1] : 0,
522                               m_colorMask[2] ? m_clearColor[2] : 0,
523                               m_colorMask[3] ? m_clearColor[3] : 0);
524     else
525         m_context->clearColor(0, 0, 0, 0);
526     m_context->colorMask(true, true, true, true);
527     GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
528     if (contextAttributes->depth()) {
529         if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
530             m_context->clearDepth(1.0f);
531         clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
532         m_context->depthMask(true);
533     }
534     if (contextAttributes->stencil()) {
535         if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
536             m_context->clearStencil(m_clearStencil & m_stencilMask);
537         else
538             m_context->clearStencil(0);
539         clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
540         m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
541     }
542     m_context->clear(clearMask);
543
544     // Restore the state that the context set.
545     if (m_scissorEnabled)
546         m_context->enable(GraphicsContext3D::SCISSOR_TEST);
547     m_context->clearColor(m_clearColor[0], m_clearColor[1],
548                           m_clearColor[2], m_clearColor[3]);
549     m_context->colorMask(m_colorMask[0], m_colorMask[1],
550                          m_colorMask[2], m_colorMask[3]);
551     m_context->clearDepth(m_clearDepth);
552     m_context->clearStencil(m_clearStencil);
553     m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
554     m_context->depthMask(m_depthMask);
555     if (m_framebufferBinding)
556         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
557     m_layerCleared = true;
558
559     return combinedClear;
560 }
561
562 void WebGLRenderingContext::markLayerComposited()
563 {
564     m_context->markLayerComposited();
565 }
566
567 void WebGLRenderingContext::paintRenderingResultsToCanvas()
568 {
569     // Until the canvas is written to by the application, the clear that
570     // happened after it was composited should be ignored by the compositor.
571     if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
572         m_context->paintCompositedResultsToCanvas(this);
573         canvas()->makePresentationCopy();
574     } else
575         canvas()->clearPresentationCopy();
576     clearIfComposited();
577     if (!m_markedCanvasDirty && !m_layerCleared)
578         return;
579     canvas()->clearCopiedImage();
580     m_markedCanvasDirty = false;
581     m_context->paintRenderingResultsToCanvas(this);
582 }
583
584 PassRefPtr<ImageData> WebGLRenderingContext::paintRenderingResultsToImageData()
585 {
586     clearIfComposited();
587     return m_context->paintRenderingResultsToImageData();
588 }
589
590 bool WebGLRenderingContext::paintsIntoCanvasBuffer() const
591 {
592     return m_context->paintsIntoCanvasBuffer();
593 }
594
595 void WebGLRenderingContext::reshape(int width, int height)
596 {
597     // This is an approximation because at WebGLRenderingContext level we don't
598     // know if the underlying FBO uses textures or renderbuffers.
599     GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
600     // Limit drawing buffer size to 4k to avoid memory exhaustion.
601     const int sizeUpperLimit = 4096;
602     maxSize = std::min(maxSize, sizeUpperLimit);
603     GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
604     GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
605     width = clamp(width, 1, maxWidth);
606     height = clamp(height, 1, maxHeight);
607
608     if (m_needsUpdate) {
609 #if USE(ACCELERATED_COMPOSITING)
610         RenderBox* renderBox = canvas()->renderBox();
611         if (renderBox && renderBox->hasLayer())
612             renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
613 #endif
614         m_needsUpdate = false;
615     }
616
617     // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
618     // clear (and this matches what reshape will do).
619     m_context->reshape(width, height);
620 }
621
622 int WebGLRenderingContext::drawingBufferWidth() const
623 {
624     return m_context->getInternalFramebufferSize().width();
625 }
626
627 int WebGLRenderingContext::drawingBufferHeight() const
628 {
629     return m_context->getInternalFramebufferSize().height();
630 }
631
632 unsigned int WebGLRenderingContext::sizeInBytes(GC3Denum type)
633 {
634     switch (type) {
635     case GraphicsContext3D::BYTE:
636         return sizeof(GC3Dbyte);
637     case GraphicsContext3D::UNSIGNED_BYTE:
638         return sizeof(GC3Dubyte);
639     case GraphicsContext3D::SHORT:
640         return sizeof(GC3Dshort);
641     case GraphicsContext3D::UNSIGNED_SHORT:
642         return sizeof(GC3Dushort);
643     case GraphicsContext3D::INT:
644         return sizeof(GC3Dint);
645     case GraphicsContext3D::UNSIGNED_INT:
646         return sizeof(GC3Duint);
647     case GraphicsContext3D::FLOAT:
648         return sizeof(GC3Dfloat);
649     }
650     ASSERT_NOT_REACHED();
651     return 0;
652 }
653
654 void WebGLRenderingContext::activeTexture(GC3Denum texture, ExceptionCode& ec)
655 {
656     UNUSED_PARAM(ec);
657     if (isContextLost())
658         return;
659     if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
660         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
661         return;
662     }
663     m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
664     m_context->activeTexture(texture);
665     cleanupAfterGraphicsCall(false);
666 }
667
668 void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
669 {
670     UNUSED_PARAM(ec);
671     if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
672         return;
673     if (!program->attachShader(shader)) {
674         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
675         return;
676     }
677     m_context->attachShader(objectOrZero(program), objectOrZero(shader));
678     shader->onAttached();
679     cleanupAfterGraphicsCall(false);
680 }
681
682 void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
683 {
684     UNUSED_PARAM(ec);
685     if (isContextLost() || !validateWebGLObject(program))
686         return;
687     if (!validateString(name))
688         return;
689     m_context->bindAttribLocation(objectOrZero(program), index, name);
690     cleanupAfterGraphicsCall(false);
691 }
692
693 bool WebGLRenderingContext::checkObjectToBeBound(WebGLObject* object, bool& deleted)
694 {
695     deleted = false;
696     if (isContextLost())
697         return false;
698     if (object) {
699         if (object->context() != this) {
700             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
701             return false;
702         }
703         deleted = !object->object();
704     }
705     return true;
706 }
707
708 void WebGLRenderingContext::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec)
709 {
710     UNUSED_PARAM(ec);
711     bool deleted;
712     if (!checkObjectToBeBound(buffer, deleted))
713         return;
714     if (deleted)
715         buffer = 0;
716     if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
717         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
718         return;
719     }
720     if (target == GraphicsContext3D::ARRAY_BUFFER)
721         m_boundArrayBuffer = buffer;
722     else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
723         m_boundVertexArrayObject->setElementArrayBuffer(buffer);
724     else {
725         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
726         return;
727     }
728
729     m_context->bindBuffer(target, objectOrZero(buffer));
730     if (buffer)
731         buffer->setTarget(target);
732     cleanupAfterGraphicsCall(false);
733 }
734
735 void WebGLRenderingContext::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec)
736 {
737     UNUSED_PARAM(ec);
738     bool deleted;
739     if (!checkObjectToBeBound(buffer, deleted))
740         return;
741     if (deleted)
742         buffer = 0;
743     if (target != GraphicsContext3D::FRAMEBUFFER) {
744         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
745         return;
746     }
747     m_framebufferBinding = buffer;
748     m_context->bindFramebuffer(target, objectOrZero(buffer));
749     if (buffer)
750         buffer->setHasEverBeenBound();
751     cleanupAfterGraphicsCall(false);
752 }
753
754 void WebGLRenderingContext::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
755 {
756     UNUSED_PARAM(ec);
757     bool deleted;
758     if (!checkObjectToBeBound(renderBuffer, deleted))
759         return;
760     if (deleted)
761         renderBuffer = 0;
762     if (target != GraphicsContext3D::RENDERBUFFER) {
763         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
764         return;
765     }
766     m_renderbufferBinding = renderBuffer;
767     m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
768     if (renderBuffer)
769         renderBuffer->setHasEverBeenBound();
770     cleanupAfterGraphicsCall(false);
771 }
772
773 void WebGLRenderingContext::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
774 {
775     UNUSED_PARAM(ec);
776     bool deleted;
777     if (!checkObjectToBeBound(texture, deleted))
778         return;
779     if (deleted)
780         texture = 0;
781     if (texture && texture->getTarget() && texture->getTarget() != target) {
782         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
783         return;
784     }
785     GC3Dint maxLevel = 0;
786     if (target == GraphicsContext3D::TEXTURE_2D) {
787         m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
788         maxLevel = m_maxTextureLevel;
789     } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
790         m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
791         maxLevel = m_maxCubeMapTextureLevel;
792     } else {
793         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
794         return;
795     }
796     m_context->bindTexture(target, objectOrZero(texture));
797     if (texture)
798         texture->setTarget(target, maxLevel);
799
800     // Note: previously we used to automatically set the TEXTURE_WRAP_R
801     // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
802     // ES 2.0 doesn't expose this flag (a bug in the specification) and
803     // otherwise the application has no control over the seams in this
804     // dimension. However, it appears that supporting this properly on all
805     // platforms is fairly involved (will require a HashMap from texture ID
806     // in all ports), and we have not had any complaints, so the logic has
807     // been removed.
808
809     cleanupAfterGraphicsCall(false);
810 }
811
812 void WebGLRenderingContext::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
813 {
814     if (isContextLost())
815         return;
816     m_context->blendColor(red, green, blue, alpha);
817     cleanupAfterGraphicsCall(false);
818 }
819
820 void WebGLRenderingContext::blendEquation(GC3Denum mode)
821 {
822     if (isContextLost() || !validateBlendEquation(mode))
823         return;
824     m_context->blendEquation(mode);
825     cleanupAfterGraphicsCall(false);
826 }
827
828 void WebGLRenderingContext::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
829 {
830     if (isContextLost() || !validateBlendEquation(modeRGB) || !validateBlendEquation(modeAlpha))
831         return;
832     m_context->blendEquationSeparate(modeRGB, modeAlpha);
833     cleanupAfterGraphicsCall(false);
834 }
835
836
837 void WebGLRenderingContext::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
838 {
839     if (isContextLost() || !validateBlendFuncFactors(sfactor, dfactor))
840         return;
841     m_context->blendFunc(sfactor, dfactor);
842     cleanupAfterGraphicsCall(false);
843 }
844
845 void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
846 {
847     if (isContextLost() || !validateBlendFuncFactors(srcRGB, dstRGB))
848         return;
849     m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
850     cleanupAfterGraphicsCall(false);
851 }
852
853 void WebGLRenderingContext::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage, ExceptionCode& ec)
854 {
855     UNUSED_PARAM(ec);
856     if (isContextLost())
857         return;
858     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
859     if (!buffer)
860         return;
861     if (size < 0) {
862         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
863         return;
864     }
865     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
866         if (!buffer->associateBufferData(size)) {
867             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
868             return;
869         }
870     }
871
872     m_context->bufferData(target, size, usage);
873     cleanupAfterGraphicsCall(false);
874 }
875
876 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
877 {
878     UNUSED_PARAM(ec);
879     if (isContextLost())
880         return;
881     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
882     if (!buffer)
883         return;
884     if (!data) {
885         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
886         return;
887     }
888     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
889         if (!buffer->associateBufferData(data)) {
890             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
891             return;
892         }
893     }
894
895     m_context->bufferData(target, data->byteLength(), data->data(), usage);
896     cleanupAfterGraphicsCall(false);
897 }
898
899 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
900 {
901     UNUSED_PARAM(ec);
902     if (isContextLost())
903         return;
904     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
905     if (!buffer)
906         return;
907     if (!data) {
908         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
909         return;
910     }
911     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
912         if (!buffer->associateBufferData(data)) {
913             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
914             return;
915         }
916     }
917
918     m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
919     cleanupAfterGraphicsCall(false);
920 }
921
922 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBuffer* data, ExceptionCode& ec)
923 {
924     UNUSED_PARAM(ec);
925     if (isContextLost())
926         return;
927     WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
928     if (!buffer)
929         return;
930     if (offset < 0) {
931         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
932         return;
933     }
934     if (!data)
935         return;
936     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
937         if (!buffer->associateBufferSubData(offset, data)) {
938             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
939             return;
940         }
941     }
942
943     m_context->bufferSubData(target, offset, data->byteLength(), data->data());
944     cleanupAfterGraphicsCall(false);
945 }
946
947 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBufferView* data, ExceptionCode& ec)
948 {
949     UNUSED_PARAM(ec);
950     if (isContextLost())
951         return;
952     WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
953     if (!buffer)
954         return;
955     if (offset < 0) {
956         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
957         return;
958     }
959     if (!data)
960         return;
961     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
962         if (!buffer->associateBufferSubData(offset, data)) {
963             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
964             return;
965         }
966     }
967
968     m_context->bufferSubData(target, offset, data->byteLength(), data->baseAddress());
969     cleanupAfterGraphicsCall(false);
970 }
971
972 GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target)
973 {
974     if (isContextLost())
975         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
976     if (target != GraphicsContext3D::FRAMEBUFFER) {
977         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
978         return 0;
979     }
980     if (!m_framebufferBinding || !m_framebufferBinding->object())
981         return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
982     if (m_framebufferBinding->isIncomplete(true))
983         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
984     unsigned long result = m_context->checkFramebufferStatus(target);
985     cleanupAfterGraphicsCall(false);
986     return result;
987 }
988
989 void WebGLRenderingContext::clear(GC3Dbitfield mask)
990 {
991     if (isContextLost())
992         return;
993     if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
994         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
995         return;
996     }
997     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
998         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
999         return;
1000     }
1001     if (!clearIfComposited(mask))
1002         m_context->clear(mask);
1003     cleanupAfterGraphicsCall(true);
1004 }
1005
1006 void WebGLRenderingContext::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
1007 {
1008     if (isContextLost())
1009         return;
1010     if (isnan(r))
1011         r = 0;
1012     if (isnan(g))
1013         g = 0;
1014     if (isnan(b))
1015         b = 0;
1016     if (isnan(a))
1017         a = 1;
1018     m_clearColor[0] = r;
1019     m_clearColor[1] = g;
1020     m_clearColor[2] = b;
1021     m_clearColor[3] = a;
1022     m_context->clearColor(r, g, b, a);
1023     cleanupAfterGraphicsCall(false);
1024 }
1025
1026 void WebGLRenderingContext::clearDepth(GC3Dfloat depth)
1027 {
1028     if (isContextLost())
1029         return;
1030     m_clearDepth = depth;
1031     m_context->clearDepth(depth);
1032     cleanupAfterGraphicsCall(false);
1033 }
1034
1035 void WebGLRenderingContext::clearStencil(GC3Dint s)
1036 {
1037     if (isContextLost())
1038         return;
1039     m_clearStencil = s;
1040     m_context->clearStencil(s);
1041     cleanupAfterGraphicsCall(false);
1042 }
1043
1044 void WebGLRenderingContext::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1045 {
1046     if (isContextLost())
1047         return;
1048     m_colorMask[0] = red;
1049     m_colorMask[1] = green;
1050     m_colorMask[2] = blue;
1051     m_colorMask[3] = alpha;
1052     m_context->colorMask(red, green, blue, alpha);
1053     cleanupAfterGraphicsCall(false);
1054 }
1055
1056 void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec)
1057 {
1058     UNUSED_PARAM(ec);
1059     if (isContextLost() || !validateWebGLObject(shader))
1060         return;
1061     m_context->compileShader(objectOrZero(shader));
1062     cleanupAfterGraphicsCall(false);
1063 }
1064
1065 void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
1066 {
1067     if (isContextLost())
1068         return;
1069     if (!validateTexFuncParameters(target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
1070         return;
1071     WebGLTexture* tex = validateTextureBinding(target, true);
1072     if (!tex)
1073         return;
1074     if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1075         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1076         return;
1077     }
1078     if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1079         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1080         return;
1081     }
1082     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1083         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1084         return;
1085     }
1086     clearIfComposited();
1087     if (isResourceSafe())
1088         m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1089     else {
1090         GC3Dint clippedX, clippedY;
1091         GC3Dsizei clippedWidth, clippedHeight;
1092         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1093             m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
1094                                               internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment);
1095             if (clippedWidth > 0 && clippedHeight > 0) {
1096                 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
1097                                              clippedX, clippedY, clippedWidth, clippedHeight);
1098             }
1099         } else
1100             m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1101     }
1102     // FIXME: if the framebuffer is not complete, none of the below should be executed.
1103     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1104     cleanupAfterGraphicsCall(false);
1105 }
1106
1107 void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1108 {
1109     if (isContextLost())
1110         return;
1111     if (!validateTexFuncLevel(target, level))
1112         return;
1113     WebGLTexture* tex = validateTextureBinding(target, true);
1114     if (!tex)
1115         return;
1116     if (!validateSize(xoffset, yoffset) || !validateSize(width, height))
1117         return;
1118     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1119         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1120         return;
1121     }
1122     if (!isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(target, level), getBoundFramebufferColorFormat())) {
1123         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1124         return;
1125     }
1126     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1127         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1128         return;
1129     }
1130     clearIfComposited();
1131     if (isResourceSafe())
1132         m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1133     else {
1134         GC3Dint clippedX, clippedY;
1135         GC3Dsizei clippedWidth, clippedHeight;
1136         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1137             GC3Denum format = tex->getInternalFormat(target, level);
1138             GC3Denum type = tex->getType(target, level);
1139             OwnArrayPtr<unsigned char> zero;
1140             if (width && height) {
1141                 unsigned int size;
1142                 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1143                 if (error != GraphicsContext3D::NO_ERROR) {
1144                     m_context->synthesizeGLError(error);
1145                     return;
1146                 }
1147                 zero = adoptArrayPtr(new unsigned char[size]);
1148                 if (!zero) {
1149                     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1150                     return;
1151                 }
1152                 memset(zero.get(), 0, size);
1153             }
1154             m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1155             if (clippedWidth > 0 && clippedHeight > 0) {
1156                 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1157                                              clippedX, clippedY, clippedWidth, clippedHeight);
1158             }
1159         } else
1160             m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1161     }
1162     cleanupAfterGraphicsCall(false);
1163 }
1164
1165 PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer()
1166 {
1167     if (isContextLost())
1168         return 0;
1169     RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1170     addObject(o.get());
1171     return o;
1172 }
1173
1174 PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer()
1175 {
1176     if (isContextLost())
1177         return 0;
1178     RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1179     addObject(o.get());
1180     return o;
1181 }
1182
1183 PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture()
1184 {
1185     if (isContextLost())
1186         return 0;
1187     RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1188     addObject(o.get());
1189     return o;
1190 }
1191
1192 PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram()
1193 {
1194     if (isContextLost())
1195         return 0;
1196     RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1197     addObject(o.get());
1198     return o;
1199 }
1200
1201 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer()
1202 {
1203     if (isContextLost())
1204         return 0;
1205     RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1206     addObject(o.get());
1207     return o;
1208 }
1209
1210 PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(GC3Denum type, ExceptionCode& ec)
1211 {
1212     UNUSED_PARAM(ec);
1213     if (isContextLost())
1214         return 0;
1215     if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1216         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1217         return 0;
1218     }
1219
1220     RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1221     addObject(o.get());
1222     return o;
1223 }
1224
1225 void WebGLRenderingContext::cullFace(GC3Denum mode)
1226 {
1227     if (isContextLost())
1228         return;
1229     m_context->cullFace(mode);
1230     cleanupAfterGraphicsCall(false);
1231 }
1232
1233 bool WebGLRenderingContext::deleteObject(WebGLObject* object)
1234 {
1235     if (isContextLost() || !object)
1236         return false;
1237     if (object->context() != this) {
1238         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1239         return false;
1240     }
1241     if (object->object())
1242         object->deleteObject();
1243     return true;
1244 }
1245
1246 void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
1247 {
1248     if (!deleteObject(buffer))
1249         return;
1250     if (m_boundArrayBuffer == buffer)
1251         m_boundArrayBuffer = 0;
1252     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1253     if (elementArrayBuffer == buffer)
1254         m_boundVertexArrayObject->setElementArrayBuffer(0);
1255     if (!isGLES2Compliant()) {
1256         WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
1257         if (buffer == state.bufferBinding) {
1258             state.bufferBinding = m_vertexAttrib0Buffer;
1259             state.bytesPerElement = 0;
1260             state.size = 4;
1261             state.type = GraphicsContext3D::FLOAT;
1262             state.normalized = false;
1263             state.stride = 16;
1264             state.originalStride = 0;
1265             state.offset = 0;
1266         }
1267     }
1268 }
1269
1270 void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1271 {
1272     if (!deleteObject(framebuffer))
1273         return;
1274     if (framebuffer == m_framebufferBinding) {
1275         m_framebufferBinding = 0;
1276         // Have to call bindFramebuffer here to bind back to internal fbo.
1277         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1278     }
1279 }
1280
1281 void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
1282 {
1283     deleteObject(program);
1284     // We don't reset m_currentProgram to 0 here because the deletion of the
1285     // current program is delayed.
1286 }
1287
1288 void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1289 {
1290     if (!deleteObject(renderbuffer))
1291         return;
1292     if (renderbuffer == m_renderbufferBinding)
1293         m_renderbufferBinding = 0;
1294     if (m_framebufferBinding)
1295         m_framebufferBinding->removeAttachment(renderbuffer);
1296 }
1297
1298 void WebGLRenderingContext::deleteShader(WebGLShader* shader)
1299 {
1300     deleteObject(shader);
1301 }
1302
1303 void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
1304 {
1305     if (!deleteObject(texture))
1306         return;
1307     for (size_t i = 0; i < m_textureUnits.size(); ++i) {
1308         if (texture == m_textureUnits[i].m_texture2DBinding)
1309             m_textureUnits[i].m_texture2DBinding = 0;
1310         if (texture == m_textureUnits[i].m_textureCubeMapBinding)
1311             m_textureUnits[i].m_textureCubeMapBinding = 0;
1312     }
1313     if (m_framebufferBinding)
1314         m_framebufferBinding->removeAttachment(texture);
1315 }
1316
1317 void WebGLRenderingContext::depthFunc(GC3Denum func)
1318 {
1319     if (isContextLost())
1320         return;
1321     m_context->depthFunc(func);
1322     cleanupAfterGraphicsCall(false);
1323 }
1324
1325 void WebGLRenderingContext::depthMask(GC3Dboolean flag)
1326 {
1327     if (isContextLost())
1328         return;
1329     m_depthMask = flag;
1330     m_context->depthMask(flag);
1331     cleanupAfterGraphicsCall(false);
1332 }
1333
1334 void WebGLRenderingContext::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1335 {
1336     if (isContextLost())
1337         return;
1338     if (zNear > zFar) {
1339         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1340         return;
1341     }
1342     m_context->depthRange(zNear, zFar);
1343     cleanupAfterGraphicsCall(false);
1344 }
1345
1346 void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
1347 {
1348     UNUSED_PARAM(ec);
1349     if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
1350         return;
1351     if (!program->detachShader(shader)) {
1352         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1353         return;
1354     }
1355     m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1356     shader->onDetached();
1357     cleanupAfterGraphicsCall(false);
1358 }
1359
1360 void WebGLRenderingContext::disable(GC3Denum cap)
1361 {
1362     if (isContextLost() || !validateCapability(cap))
1363         return;
1364     if (cap == GraphicsContext3D::SCISSOR_TEST)
1365         m_scissorEnabled = false;
1366     m_context->disable(cap);
1367     cleanupAfterGraphicsCall(false);
1368 }
1369
1370 void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1371 {
1372     UNUSED_PARAM(ec);
1373     if (isContextLost())
1374         return;
1375     if (index >= m_maxVertexAttribs) {
1376         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1377         return;
1378     }
1379
1380     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1381     state.enabled = false;
1382
1383     if (index > 0 || isGLES2Compliant()) {
1384         m_context->disableVertexAttribArray(index);
1385         cleanupAfterGraphicsCall(false);
1386     }
1387 }
1388
1389 bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1390 {
1391     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1392     
1393     if (!elementArrayBuffer)
1394         return false;
1395
1396     if (offset < 0)
1397         return false;
1398
1399     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1400         // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1401         if (offset % 2)
1402             return false;
1403
1404         // Make uoffset an element offset.
1405         offset /= 2;
1406
1407         GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1408         if (offset > n || count > n - offset)
1409             return false;
1410     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1411         GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1412         if (offset > n || count > n - offset)
1413             return false;
1414     }
1415     return true;
1416 }
1417
1418 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& numElementsRequired)
1419 {
1420     // Performs conservative validation by caching a maximum index of
1421     // the given type per element array buffer. If all of the bound
1422     // array buffers have enough elements to satisfy that maximum
1423     // index, skips the expensive per-draw-call iteration in
1424     // validateIndexArrayPrecise.
1425     
1426     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1427
1428     if (!elementArrayBuffer)
1429         return false;
1430
1431     GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
1432     // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1433     if (!numElements)
1434         return false;
1435     const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
1436     ASSERT(buffer);
1437
1438     int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
1439     if (maxIndex < 0) {
1440         // Compute the maximum index in the entire buffer for the given type of index.
1441         switch (type) {
1442         case GraphicsContext3D::UNSIGNED_BYTE: {
1443             const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
1444             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1445                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1446             break;
1447         }
1448         case GraphicsContext3D::UNSIGNED_SHORT: {
1449             numElements /= sizeof(GC3Dushort);
1450             const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
1451             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1452                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1453             break;
1454         }
1455         default:
1456             return false;
1457         }
1458         elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1459     }
1460
1461     if (maxIndex >= 0) {
1462         // The number of required elements is one more than the maximum
1463         // index that will be accessed.
1464         numElementsRequired = maxIndex + 1;
1465         return true;
1466     }
1467
1468     return false;
1469 }
1470
1471 bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, int& numElementsRequired)
1472 {
1473     ASSERT(count >= 0 && offset >= 0);
1474     int lastIndex = -1;
1475     
1476     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1477
1478     if (!elementArrayBuffer)
1479         return false;
1480
1481     if (!count) {
1482         numElementsRequired = 0;
1483         return true;
1484     }
1485
1486     if (!elementArrayBuffer->elementArrayBuffer())
1487         return false;
1488
1489     unsigned long uoffset = offset;
1490     unsigned long n = count;
1491
1492     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1493         // Make uoffset an element offset.
1494         uoffset /= sizeof(GC3Dushort);
1495         const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1496         while (n-- > 0) {
1497             if (*p > lastIndex)
1498                 lastIndex = *p;
1499             ++p;
1500         }
1501     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1502         const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1503         while (n-- > 0) {
1504             if (*p > lastIndex)
1505                 lastIndex = *p;
1506             ++p;
1507         }
1508     }
1509
1510     // Then set the last index in the index array and make sure it is valid.
1511     numElementsRequired = lastIndex + 1;
1512     return numElementsRequired > 0;
1513 }
1514
1515 bool WebGLRenderingContext::validateRenderingState(int numElementsRequired)
1516 {
1517     if (!m_currentProgram)
1518         return false;
1519
1520     // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1521     for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1522         const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
1523         if (state.enabled
1524             && (!state.bufferBinding || !state.bufferBinding->object()))
1525             return false;
1526     }
1527
1528     if (numElementsRequired <= 0)
1529         return true;
1530
1531     // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
1532     int smallestNumElements = INT_MAX;
1533     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1534     for (int i = 0; i < numActiveAttribLocations; ++i) {
1535         int loc = m_currentProgram->getActiveAttribLocation(i);
1536         if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1537             const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1538             if (state.enabled) {
1539                 // Avoid off-by-one errors in numElements computation.
1540                 // For the last element, we will only touch the data for the
1541                 // element and nothing beyond it.
1542                 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1543                 int numElements = 0;
1544                 ASSERT(state.stride > 0);
1545                 if (bytesRemaining >= state.bytesPerElement)
1546                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1547                 if (numElements < smallestNumElements)
1548                     smallestNumElements = numElements;
1549             }
1550         }
1551     }
1552
1553     if (smallestNumElements == INT_MAX)
1554         smallestNumElements = 0;
1555
1556     return numElementsRequired <= smallestNumElements;
1557 }
1558
1559 bool WebGLRenderingContext::validateWebGLObject(WebGLObject* object)
1560 {
1561     if (!object || !object->object()) {
1562         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1563         return false;
1564     }
1565     if (object->context() != this) {
1566         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1567         return false;
1568     }
1569     return true;
1570 }
1571
1572 void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
1573 {
1574     UNUSED_PARAM(ec);
1575
1576     if (isContextLost() || !validateDrawMode(mode))
1577         return;
1578
1579     if (!validateStencilSettings())
1580         return;
1581
1582     if (first < 0 || count < 0) {
1583         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1584         return;
1585     }
1586
1587     if (!count)
1588         return;
1589
1590     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1591         // Ensure we have a valid rendering state
1592         CheckedInt<GC3Dint> checkedFirst(first);
1593         CheckedInt<GC3Dint> checkedCount(count);
1594         CheckedInt<GC3Dint> checkedSum = checkedFirst + checkedCount;
1595         if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) {
1596             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1597             return;
1598         }
1599     } else {
1600         if (!validateRenderingState(0)) {
1601             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1602             return;
1603         }
1604     }
1605
1606     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1607         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1608         return;
1609     }
1610
1611     clearIfComposited();
1612
1613     bool vertexAttrib0Simulated = false;
1614     if (!isGLES2Compliant())
1615         vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1616     if (!isGLES2NPOTStrict())
1617         handleNPOTTextures(true);
1618     m_context->drawArrays(mode, first, count);
1619     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1620         restoreStatesAfterVertexAttrib0Simulation();
1621     if (!isGLES2NPOTStrict())
1622         handleNPOTTextures(false);
1623     cleanupAfterGraphicsCall(true);
1624 }
1625
1626 void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, ExceptionCode& ec)
1627 {
1628     UNUSED_PARAM(ec);
1629
1630     if (isContextLost() || !validateDrawMode(mode))
1631         return;
1632
1633     if (!validateStencilSettings())
1634         return;
1635
1636     switch (type) {
1637     case GraphicsContext3D::UNSIGNED_BYTE:
1638     case GraphicsContext3D::UNSIGNED_SHORT:
1639         break;
1640     default:
1641         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1642         return;
1643     }
1644
1645     if (count < 0 || offset < 0) {
1646         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1647         return;
1648     }
1649
1650     if (!count)
1651         return;
1652
1653     if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1654         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1655         return;
1656     }
1657
1658     int numElements = 0;
1659     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1660         // Ensure we have a valid rendering state
1661         if (!validateElementArraySize(count, type, offset)) {
1662             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1663             return;
1664         }
1665         if (!count)
1666             return;
1667         if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) {
1668             if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
1669                 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1670                 return;
1671             }
1672         }
1673     } else {
1674         if (!validateRenderingState(0)) {
1675             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1676             return;
1677         }
1678     }
1679
1680     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1681         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1682         return;
1683     }
1684     clearIfComposited();
1685
1686     bool vertexAttrib0Simulated = false;
1687     if (!isGLES2Compliant()) {
1688         if (!numElements)
1689             validateIndexArrayPrecise(count, type, offset, numElements);
1690         vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1691     }
1692     if (!isGLES2NPOTStrict())
1693         handleNPOTTextures(true);
1694     m_context->drawElements(mode, count, type, offset);
1695     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1696         restoreStatesAfterVertexAttrib0Simulation();
1697     if (!isGLES2NPOTStrict())
1698         handleNPOTTextures(false);
1699     cleanupAfterGraphicsCall(true);
1700 }
1701
1702 void WebGLRenderingContext::enable(GC3Denum cap)
1703 {
1704     if (isContextLost() || !validateCapability(cap))
1705         return;
1706     if (cap == GraphicsContext3D::SCISSOR_TEST)
1707         m_scissorEnabled = true;
1708     m_context->enable(cap);
1709     cleanupAfterGraphicsCall(false);
1710 }
1711
1712 void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1713 {
1714     UNUSED_PARAM(ec);
1715     if (isContextLost())
1716         return;
1717     if (index >= m_maxVertexAttribs) {
1718         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1719         return;
1720     }
1721
1722     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1723     state.enabled = true;
1724
1725     m_context->enableVertexAttribArray(index);
1726     cleanupAfterGraphicsCall(false);
1727 }
1728
1729 void WebGLRenderingContext::finish()
1730 {
1731     if (isContextLost())
1732         return;
1733     m_context->finish();
1734     cleanupAfterGraphicsCall(false);
1735 }
1736
1737 void WebGLRenderingContext::flush()
1738 {
1739     if (isContextLost())
1740         return;
1741     m_context->flush();
1742     cleanupAfterGraphicsCall(false);
1743 }
1744
1745 void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
1746 {
1747     UNUSED_PARAM(ec);
1748     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1749         return;
1750     if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
1751         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1752         return;
1753     }
1754     if (buffer && buffer->context() != this) {
1755         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1756         return;
1757     }
1758     // Don't allow the default framebuffer to be mutated; all current
1759     // implementations use an FBO internally in place of the default
1760     // FBO.
1761     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1762         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1763         return;
1764     }
1765     Platform3DObject bufferObject = objectOrZero(buffer);
1766     bool reattachDepth = false;
1767     bool reattachStencil = false;
1768     bool reattachDepthStencilDepth = false;
1769     bool reattachDepthStencilStencil = false;
1770     switch (attachment) {
1771     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
1772         m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1773         m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
1774         if (!bufferObject) {
1775             reattachDepth = true;
1776             reattachStencil = true;
1777         }
1778         break;
1779     case GraphicsContext3D::DEPTH_ATTACHMENT:
1780         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1781         if (!bufferObject)
1782             reattachDepthStencilDepth = true;
1783         break;
1784     case GraphicsContext3D::STENCIL_ATTACHMENT:
1785         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1786         if (!bufferObject)
1787             reattachDepthStencilStencil = true;
1788         break;
1789     default:
1790         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1791     }
1792     m_framebufferBinding->setAttachment(attachment, buffer);
1793     if (reattachDepth) {
1794         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT));
1795         if (object)
1796             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1797     }
1798     if (reattachStencil) {
1799         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT));
1800         if (object)
1801             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1802     }
1803     if (reattachDepthStencilDepth) {
1804         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1805         if (object)
1806             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1807     }
1808     if (reattachDepthStencilStencil) {
1809         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1810         if (object)
1811             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1812     }
1813     cleanupAfterGraphicsCall(false);
1814 }
1815
1816 void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
1817 {
1818     UNUSED_PARAM(ec);
1819     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1820         return;
1821     if (level) {
1822         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1823         return;
1824     }
1825     if (texture && texture->context() != this) {
1826         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1827         return;
1828     }
1829     // Don't allow the default framebuffer to be mutated; all current
1830     // implementations use an FBO internally in place of the default
1831     // FBO.
1832     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1833         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1834         return;
1835     }
1836     m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level);
1837     m_framebufferBinding->setAttachment(attachment, textarget, texture, level);
1838     cleanupAfterGraphicsCall(false);
1839 }
1840
1841 void WebGLRenderingContext::frontFace(GC3Denum mode)
1842 {
1843     if (isContextLost())
1844         return;
1845     m_context->frontFace(mode);
1846     cleanupAfterGraphicsCall(false);
1847 }
1848
1849 void WebGLRenderingContext::generateMipmap(GC3Denum target)
1850 {
1851     if (isContextLost())
1852         return;
1853     WebGLTexture* tex = validateTextureBinding(target, false);
1854     if (!tex)
1855         return;
1856     if (!tex->canGenerateMipmaps()) {
1857         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1858         return;
1859     }
1860     // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
1861     // on Mac.  Remove the hack once this driver bug is fixed.
1862 #if OS(DARWIN)
1863     bool needToResetMinFilter = false;
1864     if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
1865         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
1866         needToResetMinFilter = true;
1867     }
1868 #endif
1869     m_context->generateMipmap(target);
1870 #if OS(DARWIN)
1871     if (needToResetMinFilter)
1872         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
1873 #endif
1874     tex->generateMipmapLevelInfo();
1875     cleanupAfterGraphicsCall(false);
1876 }
1877
1878 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
1879 {
1880     UNUSED_PARAM(ec);
1881     if (isContextLost() || !validateWebGLObject(program))
1882         return 0;
1883     ActiveInfo info;
1884     if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
1885         return 0;
1886     return WebGLActiveInfo::create(info.name, info.type, info.size);
1887 }
1888
1889 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
1890 {
1891     UNUSED_PARAM(ec);
1892     if (isContextLost() || !validateWebGLObject(program))
1893         return 0;
1894     ActiveInfo info;
1895     if (!m_context->getActiveUniform(objectOrZero(program), index, info))
1896         return 0;
1897     if (!isGLES2Compliant())
1898         if (info.size > 1 && !info.name.endsWith("[0]"))
1899             info.name.append("[0]");
1900     return WebGLActiveInfo::create(info.name, info.type, info.size);
1901 }
1902
1903 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<WebGLShader*>& shaderObjects, ExceptionCode& ec)
1904 {
1905     UNUSED_PARAM(ec);
1906     shaderObjects.clear();
1907     if (isContextLost() || !validateWebGLObject(program))
1908         return false;
1909
1910     const GC3Denum shaderType[] = {
1911         GraphicsContext3D::VERTEX_SHADER,
1912         GraphicsContext3D::FRAGMENT_SHADER
1913     };
1914     for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
1915         WebGLShader* shader = program->getAttachedShader(shaderType[i]);
1916         if (shader)
1917             shaderObjects.append(shader);
1918     }
1919     return true;
1920 }
1921
1922 GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
1923 {
1924     if (isContextLost())
1925         return -1;
1926     if (!validateString(name))
1927         return -1;
1928     return m_context->getAttribLocation(objectOrZero(program), name);
1929 }
1930
1931 WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
1932 {
1933     UNUSED_PARAM(ec);
1934     if (isContextLost())
1935         return WebGLGetInfo();
1936     if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
1937         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1938         return WebGLGetInfo();
1939     }
1940
1941     if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
1942         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1943         return WebGLGetInfo();
1944     }
1945
1946     WebGLStateRestorer(this, false);
1947     GC3Dint value = 0;
1948     m_context->getBufferParameteriv(target, pname, &value);
1949     if (pname == GraphicsContext3D::BUFFER_SIZE)
1950         return WebGLGetInfo(value);
1951     return WebGLGetInfo(static_cast<unsigned int>(value));
1952 }
1953
1954 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
1955 {
1956     if (isContextLost())
1957         return 0;
1958     // We always need to return a new WebGLContextAttributes object to
1959     // prevent the user from mutating any cached version.
1960     return WebGLContextAttributes::create(m_context->getContextAttributes());
1961 }
1962
1963 GC3Denum WebGLRenderingContext::getError()
1964 {
1965     return m_context->getError();
1966 }
1967
1968 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
1969 {
1970     if (isContextLost())
1971         return 0;
1972
1973     if (equalIgnoringCase(name, "OES_standard_derivatives")
1974         && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
1975         if (!m_oesStandardDerivatives) {
1976             m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
1977             m_oesStandardDerivatives = OESStandardDerivatives::create(this);
1978         }
1979         return m_oesStandardDerivatives.get();
1980     }
1981     if (equalIgnoringCase(name, "OES_texture_float")
1982         && m_context->getExtensions()->supports("GL_OES_texture_float")) {
1983         if (!m_oesTextureFloat) {
1984             m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
1985             m_oesTextureFloat = OESTextureFloat::create(this);
1986         }
1987         return m_oesTextureFloat.get();
1988     }
1989     if (equalIgnoringCase(name, "OES_vertex_array_object")
1990         && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
1991         if (!m_oesVertexArrayObject) {
1992             m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
1993             m_oesVertexArrayObject = OESVertexArrayObject::create(this);
1994         }
1995         return m_oesVertexArrayObject.get();
1996     }
1997     if (equalIgnoringCase(name, "WEBKIT_lose_context")) {
1998         if (!m_webkitLoseContext)
1999             m_webkitLoseContext = WebKitLoseContext::create(this);
2000         return m_webkitLoseContext.get();
2001     }
2002
2003     return 0;
2004 }
2005
2006 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
2007 {
2008     UNUSED_PARAM(ec);
2009     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
2010         return WebGLGetInfo();
2011
2012     if (!m_framebufferBinding || !m_framebufferBinding->object() || m_framebufferBinding->isIncomplete(false)) {
2013         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2014         return WebGLGetInfo();
2015     }
2016
2017     WebGLObject* object = m_framebufferBinding->getAttachment(attachment);
2018     if (!object) {
2019         if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2020             return WebGLGetInfo(GraphicsContext3D::NONE);
2021         // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
2022         // specifies INVALID_OPERATION.
2023         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2024         return WebGLGetInfo();
2025     }
2026
2027     ASSERT(object->isTexture() || object->isRenderbuffer());
2028     if (object->isTexture()) {
2029         switch (pname) {
2030         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2031             return WebGLGetInfo(GraphicsContext3D::TEXTURE);
2032         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2033             return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
2034         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2035         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2036             {
2037                 WebGLStateRestorer(this, false);
2038                 GC3Dint value = 0;
2039                 m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2040                 return WebGLGetInfo(value);
2041             }
2042         default:
2043             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2044             return WebGLGetInfo();
2045         }
2046     } else {
2047         switch (pname) {
2048         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2049             return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
2050         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2051             return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
2052         default:
2053             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2054             return WebGLGetInfo();
2055         }
2056     }
2057 }
2058
2059 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec)
2060 {
2061     UNUSED_PARAM(ec);
2062     if (isContextLost())
2063         return WebGLGetInfo();
2064     WebGLStateRestorer(this, false);
2065     switch (pname) {
2066     case GraphicsContext3D::ACTIVE_TEXTURE:
2067         return getUnsignedIntParameter(pname);
2068     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
2069         return getWebGLFloatArrayParameter(pname);
2070     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
2071         return getWebGLFloatArrayParameter(pname);
2072     case GraphicsContext3D::ALPHA_BITS:
2073         return getIntParameter(pname);
2074     case GraphicsContext3D::ARRAY_BUFFER_BINDING:
2075         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2076     case GraphicsContext3D::BLEND:
2077         return getBooleanParameter(pname);
2078     case GraphicsContext3D::BLEND_COLOR:
2079         return getWebGLFloatArrayParameter(pname);
2080     case GraphicsContext3D::BLEND_DST_ALPHA:
2081         return getUnsignedIntParameter(pname);
2082     case GraphicsContext3D::BLEND_DST_RGB:
2083         return getUnsignedIntParameter(pname);
2084     case GraphicsContext3D::BLEND_EQUATION_ALPHA:
2085         return getUnsignedIntParameter(pname);
2086     case GraphicsContext3D::BLEND_EQUATION_RGB:
2087         return getUnsignedIntParameter(pname);
2088     case GraphicsContext3D::BLEND_SRC_ALPHA:
2089         return getUnsignedIntParameter(pname);
2090     case GraphicsContext3D::BLEND_SRC_RGB:
2091         return getUnsignedIntParameter(pname);
2092     case GraphicsContext3D::BLUE_BITS:
2093         return getIntParameter(pname);
2094     case GraphicsContext3D::COLOR_CLEAR_VALUE:
2095         return getWebGLFloatArrayParameter(pname);
2096     case GraphicsContext3D::COLOR_WRITEMASK:
2097         return getBooleanArrayParameter(pname);
2098     case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
2099         // Defined as null in the spec
2100         return WebGLGetInfo();
2101     case GraphicsContext3D::CULL_FACE:
2102         return getBooleanParameter(pname);
2103     case GraphicsContext3D::CULL_FACE_MODE:
2104         return getUnsignedIntParameter(pname);
2105     case GraphicsContext3D::CURRENT_PROGRAM:
2106         return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2107     case GraphicsContext3D::DEPTH_BITS:
2108         return getIntParameter(pname);
2109     case GraphicsContext3D::DEPTH_CLEAR_VALUE:
2110         return getFloatParameter(pname);
2111     case GraphicsContext3D::DEPTH_FUNC:
2112         return getUnsignedIntParameter(pname);
2113     case GraphicsContext3D::DEPTH_RANGE:
2114         return getWebGLFloatArrayParameter(pname);
2115     case GraphicsContext3D::DEPTH_TEST:
2116         return getBooleanParameter(pname);
2117     case GraphicsContext3D::DEPTH_WRITEMASK:
2118         return getBooleanParameter(pname);
2119     case GraphicsContext3D::DITHER:
2120         return getBooleanParameter(pname);
2121     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
2122         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
2123     case GraphicsContext3D::FRAMEBUFFER_BINDING:
2124         return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2125     case GraphicsContext3D::FRONT_FACE:
2126         return getUnsignedIntParameter(pname);
2127     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2128         return getUnsignedIntParameter(pname);
2129     case GraphicsContext3D::GREEN_BITS:
2130         return getIntParameter(pname);
2131     case GraphicsContext3D::LINE_WIDTH:
2132         return getFloatParameter(pname);
2133     case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2134         return getIntParameter(pname);
2135     case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
2136         return getIntParameter(pname);
2137     case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
2138         return getIntParameter(pname);
2139     case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
2140         return getIntParameter(pname);
2141     case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
2142         return getIntParameter(pname);
2143     case GraphicsContext3D::MAX_TEXTURE_SIZE:
2144         return getIntParameter(pname);
2145     case GraphicsContext3D::MAX_VARYING_VECTORS:
2146         return getIntParameter(pname);
2147     case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
2148         return getIntParameter(pname);
2149     case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2150         return getIntParameter(pname);
2151     case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
2152         return getIntParameter(pname);
2153     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
2154         return getWebGLIntArrayParameter(pname);
2155     case GraphicsContext3D::NUM_COMPRESSED_TEXTURE_FORMATS:
2156         // WebGL 1.0 specifies that there are no compressed texture formats.
2157         return WebGLGetInfo(static_cast<int>(0));
2158     case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
2159         // FIXME: should we always return 0 for this?
2160         return getIntParameter(pname);
2161     case GraphicsContext3D::PACK_ALIGNMENT:
2162         return getIntParameter(pname);
2163     case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
2164         return getFloatParameter(pname);
2165     case GraphicsContext3D::POLYGON_OFFSET_FILL:
2166         return getBooleanParameter(pname);
2167     case GraphicsContext3D::POLYGON_OFFSET_UNITS:
2168         return getFloatParameter(pname);
2169     case GraphicsContext3D::RED_BITS:
2170         return getIntParameter(pname);
2171     case GraphicsContext3D::RENDERBUFFER_BINDING:
2172         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2173     case GraphicsContext3D::RENDERER:
2174         return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
2175     case GraphicsContext3D::SAMPLE_BUFFERS:
2176         return getIntParameter(pname);
2177     case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
2178         return getBooleanParameter(pname);
2179     case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
2180         return getFloatParameter(pname);
2181     case GraphicsContext3D::SAMPLES:
2182         return getIntParameter(pname);
2183     case GraphicsContext3D::SCISSOR_BOX:
2184         return getWebGLIntArrayParameter(pname);
2185     case GraphicsContext3D::SCISSOR_TEST:
2186         return getBooleanParameter(pname);
2187     case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
2188         return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
2189     case GraphicsContext3D::STENCIL_BACK_FAIL:
2190         return getUnsignedIntParameter(pname);
2191     case GraphicsContext3D::STENCIL_BACK_FUNC:
2192         return getUnsignedIntParameter(pname);
2193     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
2194         return getUnsignedIntParameter(pname);
2195     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
2196         return getUnsignedIntParameter(pname);
2197     case GraphicsContext3D::STENCIL_BACK_REF:
2198         return getIntParameter(pname);
2199     case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
2200         return getUnsignedIntParameter(pname);
2201     case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
2202         return getUnsignedIntParameter(pname);
2203     case GraphicsContext3D::STENCIL_BITS:
2204         return getIntParameter(pname);
2205     case GraphicsContext3D::STENCIL_CLEAR_VALUE:
2206         return getIntParameter(pname);
2207     case GraphicsContext3D::STENCIL_FAIL:
2208         return getUnsignedIntParameter(pname);
2209     case GraphicsContext3D::STENCIL_FUNC:
2210         return getUnsignedIntParameter(pname);
2211     case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
2212         return getUnsignedIntParameter(pname);
2213     case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
2214         return getUnsignedIntParameter(pname);
2215     case GraphicsContext3D::STENCIL_REF:
2216         return getIntParameter(pname);
2217     case GraphicsContext3D::STENCIL_TEST:
2218         return getBooleanParameter(pname);
2219     case GraphicsContext3D::STENCIL_VALUE_MASK:
2220         return getUnsignedIntParameter(pname);
2221     case GraphicsContext3D::STENCIL_WRITEMASK:
2222         return getUnsignedIntParameter(pname);
2223     case GraphicsContext3D::SUBPIXEL_BITS:
2224         return getIntParameter(pname);
2225     case GraphicsContext3D::TEXTURE_BINDING_2D:
2226         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
2227     case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
2228         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
2229     case GraphicsContext3D::UNPACK_ALIGNMENT:
2230         return getIntParameter(pname);
2231     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2232         return WebGLGetInfo(m_unpackFlipY);
2233     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2234         return WebGLGetInfo(m_unpackPremultiplyAlpha);
2235     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2236         return WebGLGetInfo(m_unpackColorspaceConversion);
2237     case GraphicsContext3D::VENDOR:
2238         return WebGLGetInfo("Webkit (" + m_context->getString(GraphicsContext3D::VENDOR) + ")");
2239     case GraphicsContext3D::VERSION:
2240         return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
2241     case GraphicsContext3D::VIEWPORT:
2242         return getWebGLIntArrayParameter(pname);
2243     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2244         if (m_oesStandardDerivatives)
2245             return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2246         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2247         return WebGLGetInfo();
2248     case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2249         if (m_oesVertexArrayObject) {
2250             if (!m_boundVertexArrayObject->isDefaultObject())
2251                 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2252             return WebGLGetInfo();
2253         }
2254         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2255         return WebGLGetInfo();
2256     default:
2257         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2258         return WebGLGetInfo();
2259     }
2260 }
2261
2262 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2263 {
2264     UNUSED_PARAM(ec);
2265     if (isContextLost() || !validateWebGLObject(program))
2266         return WebGLGetInfo();
2267
2268     WebGLStateRestorer(this, false);
2269     GC3Dint value = 0;
2270     switch (pname) {
2271     case GraphicsContext3D::DELETE_STATUS:
2272         return WebGLGetInfo(program->isDeleted());
2273     case GraphicsContext3D::VALIDATE_STATUS:
2274         m_context->getProgramiv(objectOrZero(program), pname, &value);
2275         return WebGLGetInfo(static_cast<bool>(value));
2276     case GraphicsContext3D::LINK_STATUS:
2277         return WebGLGetInfo(program->getLinkStatus());
2278     case GraphicsContext3D::ATTACHED_SHADERS:
2279     case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2280     case GraphicsContext3D::ACTIVE_UNIFORMS:
2281         m_context->getProgramiv(objectOrZero(program), pname, &value);
2282         return WebGLGetInfo(value);
2283     default:
2284         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2285         return WebGLGetInfo();
2286     }
2287 }
2288
2289 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2290 {
2291     UNUSED_PARAM(ec);
2292     if (isContextLost())
2293         return String();
2294     if (!validateWebGLObject(program))
2295         return "";
2296     WebGLStateRestorer(this, false);
2297     return m_context->getProgramInfoLog(objectOrZero(program));
2298 }
2299
2300 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2301 {
2302     UNUSED_PARAM(ec);
2303     if (isContextLost())
2304         return WebGLGetInfo();
2305     if (target != GraphicsContext3D::RENDERBUFFER) {
2306         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2307         return WebGLGetInfo();
2308     }
2309     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2310         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2311         return WebGLGetInfo();
2312     }
2313
2314     if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2315         && !m_renderbufferBinding->isValid()) {
2316         ASSERT(!isDepthStencilSupported());
2317         int value = 0;
2318         switch (pname) {
2319         case GraphicsContext3D::RENDERBUFFER_WIDTH:
2320             value = m_renderbufferBinding->getWidth();
2321             break;
2322         case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2323             value = m_renderbufferBinding->getHeight();
2324             break;
2325         case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2326         case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2327         case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2328         case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2329             value = 0;
2330             break;
2331         case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2332             value = 24;
2333             break;
2334         case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2335             value = 8;
2336             break;
2337         case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2338             return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2339         default:
2340             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2341             return WebGLGetInfo();
2342         }
2343         return WebGLGetInfo(value);
2344     }
2345
2346     WebGLStateRestorer(this, false);
2347     GC3Dint value = 0;
2348     switch (pname) {
2349     case GraphicsContext3D::RENDERBUFFER_WIDTH:
2350     case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2351     case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2352     case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2353     case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2354     case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2355     case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2356     case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2357         m_context->getRenderbufferParameteriv(target, pname, &value);
2358         return WebGLGetInfo(value);
2359     case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2360         return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2361     default:
2362         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2363         return WebGLGetInfo();
2364     }
2365 }
2366
2367 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
2368 {
2369     UNUSED_PARAM(ec);
2370     if (isContextLost() || !validateWebGLObject(shader))
2371         return WebGLGetInfo();
2372     WebGLStateRestorer(this, false);
2373     GC3Dint value = 0;
2374     switch (pname) {
2375     case GraphicsContext3D::DELETE_STATUS:
2376         return WebGLGetInfo(shader->isDeleted());
2377     case GraphicsContext3D::COMPILE_STATUS:
2378         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2379         return WebGLGetInfo(static_cast<bool>(value));
2380     case GraphicsContext3D::SHADER_TYPE:
2381         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2382         return WebGLGetInfo(static_cast<unsigned int>(value));
2383     default:
2384         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2385         return WebGLGetInfo();
2386     }
2387 }
2388
2389 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
2390 {
2391     UNUSED_PARAM(ec);
2392     if (isContextLost())
2393         return String();
2394     if (!validateWebGLObject(shader))
2395         return "";
2396     WebGLStateRestorer(this, false);
2397     return m_context->getShaderInfoLog(objectOrZero(shader));
2398 }
2399
2400 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
2401 {
2402     UNUSED_PARAM(ec);
2403     if (isContextLost())
2404         return String();
2405     if (!validateWebGLObject(shader))
2406         return "";
2407     return shader->getSource();
2408 }
2409
2410 Vector<String> WebGLRenderingContext::getSupportedExtensions()
2411 {
2412     Vector<String> result;
2413     if (m_context->getExtensions()->supports("GL_OES_texture_float"))
2414         result.append("OES_texture_float");
2415     if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
2416         result.append("OES_standard_derivatives");
2417     if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
2418         result.append("OES_vertex_array_object");
2419     result.append("WEBKIT_lose_context");
2420     return result;
2421 }
2422
2423 WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2424 {
2425     UNUSED_PARAM(ec);
2426     if (isContextLost())
2427         return WebGLGetInfo();
2428     WebGLTexture* tex = validateTextureBinding(target, false);
2429     if (!tex)
2430         return WebGLGetInfo();
2431     WebGLStateRestorer(this, false);
2432     GC3Dint value = 0;
2433     switch (pname) {
2434     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2435     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2436     case GraphicsContext3D::TEXTURE_WRAP_S:
2437     case GraphicsContext3D::TEXTURE_WRAP_T:
2438         m_context->getTexParameteriv(target, pname, &value);
2439         return WebGLGetInfo(static_cast<unsigned int>(value));
2440     default:
2441         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2442         return WebGLGetInfo();
2443     }
2444 }
2445
2446 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2447 {
2448     UNUSED_PARAM(ec);
2449     if (isContextLost() || !validateWebGLObject(program))
2450         return WebGLGetInfo();
2451     if (!uniformLocation || uniformLocation->program() != program) {
2452         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2453         return WebGLGetInfo();
2454     }
2455     GC3Dint location = uniformLocation->location();
2456
2457     WebGLStateRestorer(this, false);
2458     // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2459     GC3Dint activeUniforms = 0;
2460     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2461     for (GC3Dint i = 0; i < activeUniforms; i++) {
2462         ActiveInfo info;
2463         if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2464             return WebGLGetInfo();
2465         // Strip "[0]" from the name if it's an array.
2466         if (info.size > 1 && info.name.endsWith("[0]"))
2467             info.name = info.name.left(info.name.length() - 3);
2468         // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2469         for (GC3Dint index = 0; index < info.size; ++index) {
2470             String name = info.name;
2471             if (info.size > 1 && index >= 1) {
2472                 name.append('[');
2473                 name.append(String::number(index));
2474                 name.append(']');
2475             }
2476             // Now need to look this up by name again to find its location
2477             GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name);
2478             if (loc == location) {
2479                 // Found it. Use the type in the ActiveInfo to determine the return type.
2480                 GC3Denum baseType;
2481                 unsigned int length;
2482                 switch (info.type) {
2483                 case GraphicsContext3D::BOOL:
2484                     baseType = GraphicsContext3D::BOOL;
2485                     length = 1;
2486                     break;
2487                 case GraphicsContext3D::BOOL_VEC2:
2488                     baseType = GraphicsContext3D::BOOL;
2489                     length = 2;
2490                     break;
2491                 case GraphicsContext3D::BOOL_VEC3:
2492                     baseType = GraphicsContext3D::BOOL;
2493                     length = 3;
2494                     break;
2495                 case GraphicsContext3D::BOOL_VEC4:
2496                     baseType = GraphicsContext3D::BOOL;
2497                     length = 4;
2498                     break;
2499                 case GraphicsContext3D::INT:
2500                     baseType = GraphicsContext3D::INT;
2501                     length = 1;
2502                     break;
2503                 case GraphicsContext3D::INT_VEC2:
2504                     baseType = GraphicsContext3D::INT;
2505                     length = 2;
2506                     break;
2507                 case GraphicsContext3D::INT_VEC3:
2508                     baseType = GraphicsContext3D::INT;
2509                     length = 3;
2510                     break;
2511                 case GraphicsContext3D::INT_VEC4:
2512                     baseType = GraphicsContext3D::INT;
2513                     length = 4;
2514                     break;
2515                 case GraphicsContext3D::FLOAT:
2516                     baseType = GraphicsContext3D::FLOAT;
2517                     length = 1;
2518                     break;
2519                 case GraphicsContext3D::FLOAT_VEC2:
2520                     baseType = GraphicsContext3D::FLOAT;
2521                     length = 2;
2522                     break;
2523                 case GraphicsContext3D::FLOAT_VEC3:
2524                     baseType = GraphicsContext3D::FLOAT;
2525                     length = 3;
2526                     break;
2527                 case GraphicsContext3D::FLOAT_VEC4:
2528                     baseType = GraphicsContext3D::FLOAT;
2529                     length = 4;
2530                     break;
2531                 case GraphicsContext3D::FLOAT_MAT2:
2532                     baseType = GraphicsContext3D::FLOAT;
2533                     length = 4;
2534                     break;
2535                 case GraphicsContext3D::FLOAT_MAT3:
2536                     baseType = GraphicsContext3D::FLOAT;
2537                     length = 9;
2538                     break;
2539                 case GraphicsContext3D::FLOAT_MAT4:
2540                     baseType = GraphicsContext3D::FLOAT;
2541                     length = 16;
2542                     break;
2543                 case GraphicsContext3D::SAMPLER_2D:
2544                 case GraphicsContext3D::SAMPLER_CUBE:
2545                     baseType = GraphicsContext3D::INT;
2546                     length = 1;
2547                     break;
2548                 default:
2549                     // Can't handle this type
2550                     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2551                     return WebGLGetInfo();
2552                 }
2553                 switch (baseType) {
2554                 case GraphicsContext3D::FLOAT: {
2555                     GC3Dfloat value[16] = {0};
2556                     m_context->getUniformfv(objectOrZero(program), location, value);
2557                     if (length == 1)
2558                         return WebGLGetInfo(value[0]);
2559                     return WebGLGetInfo(Float32Array::create(value, length));
2560                 }
2561                 case GraphicsContext3D::INT: {
2562                     GC3Dint value[4] = {0};
2563                     m_context->getUniformiv(objectOrZero(program), location, value);
2564                     if (length == 1)
2565                         return WebGLGetInfo(value[0]);
2566                     return WebGLGetInfo(Int32Array::create(value, length));
2567                 }
2568                 case GraphicsContext3D::BOOL: {
2569                     GC3Dint value[4] = {0};
2570                     m_context->getUniformiv(objectOrZero(program), location, value);
2571                     if (length > 1) {
2572                         bool boolValue[16] = {0};
2573                         for (unsigned j = 0; j < length; j++)
2574                             boolValue[j] = static_cast<bool>(value[j]);
2575                         return WebGLGetInfo(boolValue, length);
2576                     }
2577                     return WebGLGetInfo(static_cast<bool>(value[0]));
2578                 }
2579                 default:
2580                     notImplemented();
2581                 }
2582             }
2583         }
2584     }
2585     // If we get here, something went wrong in our unfortunately complex logic above
2586     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2587     return WebGLGetInfo();
2588 }
2589
2590 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
2591 {
2592     UNUSED_PARAM(ec);
2593     if (isContextLost() || !validateWebGLObject(program))
2594         return 0;
2595     if (!validateString(name))
2596         return 0;
2597     WebGLStateRestorer(this, false);
2598     GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2599     if (uniformLocation == -1)
2600         return 0;
2601     return WebGLUniformLocation::create(program, uniformLocation);
2602 }
2603
2604 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
2605 {
2606     UNUSED_PARAM(ec);
2607     if (isContextLost())
2608         return WebGLGetInfo();
2609     WebGLStateRestorer(this, false);
2610     if (index >= m_maxVertexAttribs) {
2611         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2612         return WebGLGetInfo();
2613     }
2614     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2615     switch (pname) {
2616     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2617         if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
2618             || !state.bufferBinding
2619             || !state.bufferBinding->object())
2620             return WebGLGetInfo();
2621         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
2622     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
2623         return WebGLGetInfo(state.enabled);
2624     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
2625         return WebGLGetInfo(state.normalized);
2626     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
2627         return WebGLGetInfo(state.size);
2628     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
2629         return WebGLGetInfo(state.originalStride);
2630     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
2631         return WebGLGetInfo(state.type);
2632     case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
2633         return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
2634     default:
2635         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2636         return WebGLGetInfo();
2637     }
2638 }
2639
2640 GC3Dsizeiptr WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
2641 {
2642     if (isContextLost())
2643         return 0;
2644     GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
2645     cleanupAfterGraphicsCall(false);
2646     return result;
2647 }
2648
2649 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
2650 {
2651     if (isContextLost())
2652         return;
2653     bool isValid = false;
2654     switch (target) {
2655     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2656         isValid = true;
2657         break;
2658     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2659         if (m_oesStandardDerivatives)
2660             isValid = true;
2661         break;
2662     }
2663     if (!isValid) {
2664         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2665         return;
2666     }
2667     m_context->hint(target, mode);
2668     cleanupAfterGraphicsCall(false);
2669 }
2670
2671 GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
2672 {
2673     if (!buffer || isContextLost())
2674         return 0;
2675
2676     if (!buffer->hasEverBeenBound())
2677         return 0;
2678
2679     return m_context->isBuffer(buffer->object());
2680 }
2681
2682 bool WebGLRenderingContext::isContextLost()
2683 {
2684     return m_contextLost;
2685 }
2686
2687 GC3Dboolean WebGLRenderingContext::isEnabled(GC3Denum cap)
2688 {
2689     if (!validateCapability(cap) || isContextLost())
2690         return 0;
2691     return m_context->isEnabled(cap);
2692 }
2693
2694 GC3Dboolean WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer)
2695 {
2696     if (!framebuffer || isContextLost())
2697         return 0;
2698
2699     if (!framebuffer->hasEverBeenBound())
2700         return 0;
2701
2702     return m_context->isFramebuffer(framebuffer->object());
2703 }
2704
2705 GC3Dboolean WebGLRenderingContext::isProgram(WebGLProgram* program)
2706 {
2707     if (!program || isContextLost())
2708         return 0;
2709
2710     return m_context->isProgram(program->object());
2711 }
2712
2713 GC3Dboolean WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2714 {
2715     if (!renderbuffer || isContextLost())
2716         return 0;
2717
2718     if (!renderbuffer->hasEverBeenBound())
2719         return 0;
2720
2721     return m_context->isRenderbuffer(renderbuffer->object());
2722 }
2723
2724 GC3Dboolean WebGLRenderingContext::isShader(WebGLShader* shader)
2725 {
2726     if (!shader || isContextLost())
2727         return 0;
2728
2729     return m_context->isShader(shader->object());
2730 }
2731
2732 GC3Dboolean WebGLRenderingContext::isTexture(WebGLTexture* texture)
2733 {
2734     if (!texture || isContextLost())
2735         return 0;
2736
2737     if (!texture->hasEverBeenBound())
2738         return 0;
2739
2740     return m_context->isTexture(texture->object());
2741 }
2742
2743 void WebGLRenderingContext::lineWidth(GC3Dfloat width)
2744 {
2745     if (isContextLost())
2746         return;
2747     m_context->lineWidth(width);
2748     cleanupAfterGraphicsCall(false);
2749 }
2750
2751 void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec)
2752 {
2753     UNUSED_PARAM(ec);
2754     if (isContextLost() || !validateWebGLObject(program))
2755         return;
2756     if (!isGLES2Compliant()) {
2757         if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
2758             program->setLinkStatus(false);
2759             return;
2760         }
2761     }
2762
2763     m_context->linkProgram(objectOrZero(program));
2764     program->increaseLinkCount();
2765     // cache link status
2766     GC3Dint value = 0;
2767     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::LINK_STATUS, &value);
2768     program->setLinkStatus(static_cast<bool>(value));
2769     // Need to cache link status before caching active attribute locations.
2770     program->cacheActiveAttribLocations();
2771     cleanupAfterGraphicsCall(false);
2772 }
2773
2774 void WebGLRenderingContext::pixelStorei(GC3Denum pname, GC3Dint param)
2775 {
2776     if (isContextLost())
2777         return;
2778     switch (pname) {
2779     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2780         m_unpackFlipY = param;
2781         break;
2782     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2783         m_unpackPremultiplyAlpha = param;
2784         break;
2785     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2786         if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
2787             m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
2788         else {
2789             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2790             return;
2791         }
2792         break;
2793     case GraphicsContext3D::PACK_ALIGNMENT:
2794     case GraphicsContext3D::UNPACK_ALIGNMENT:
2795         if (param == 1 || param == 2 || param == 4 || param == 8) {
2796             if (pname == GraphicsContext3D::PACK_ALIGNMENT)
2797                 m_packAlignment = param;
2798             else // GraphicsContext3D::UNPACK_ALIGNMENT:
2799                 m_unpackAlignment = param;
2800             m_context->pixelStorei(pname, param);
2801             cleanupAfterGraphicsCall(false);
2802         } else {
2803             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2804             return;
2805         }
2806         break;
2807     default:
2808         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2809         return;
2810     }
2811 }
2812
2813 void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
2814 {
2815     if (isContextLost())
2816         return;
2817     m_context->polygonOffset(factor, units);
2818     cleanupAfterGraphicsCall(false);
2819 }
2820
2821 void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&)
2822 {
2823     if (isContextLost())
2824         return;
2825     // Due to WebGL's same-origin restrictions, it is not possible to
2826     // taint the origin using the WebGL API.
2827     ASSERT(canvas()->originClean());
2828     // Validate input parameters.
2829     if (!pixels) {
2830         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2831         return;
2832     }
2833     switch (format) {
2834     case GraphicsContext3D::ALPHA:
2835     case GraphicsContext3D::RGB:
2836     case GraphicsContext3D::RGBA:
2837         break;
2838     default:
2839         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2840         return;
2841     }
2842     switch (type) {
2843     case GraphicsContext3D::UNSIGNED_BYTE:
2844     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
2845     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
2846     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
2847         break;
2848     default:
2849         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2850         return;
2851     }
2852     if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
2853         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2854         return;
2855     }
2856     // Validate array type against pixel type.
2857     if (!pixels->isUnsignedByteArray()) {
2858         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2859         return;
2860     }
2861     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
2862         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
2863         return;
2864     }
2865     // Calculate array size, taking into consideration of PACK_ALIGNMENT.
2866     unsigned int totalBytesRequired;
2867     unsigned int padding;
2868     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
2869     if (error != GraphicsContext3D::NO_ERROR) {
2870         m_context->synthesizeGLError(error);
2871         return;
2872     }
2873     if (pixels->byteLength() < totalBytesRequired) {
2874         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2875         return;
2876     }
2877     clearIfComposited();
2878     void* data = pixels->baseAddress();
2879     m_context->readPixels(x, y, width, height, format, type, data);
2880 #if OS(DARWIN)
2881     // FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
2882     // when alpha is off, readPixels should set alpha to 255 instead of 0.
2883     if (!m_context->getContextAttributes().alpha) {
2884         unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
2885         for (GC3Dsizei iy = 0; iy < height; ++iy) {
2886             for (GC3Dsizei ix = 0; ix < width; ++ix) {
2887                 pixels[3] = 255;
2888                 pixels += 4;
2889             }
2890             pixels += padding;
2891         }
2892     }
2893 #endif
2894     cleanupAfterGraphicsCall(false);
2895 }
2896
2897 void WebGLRenderingContext::releaseShaderCompiler()
2898 {
2899     if (isContextLost())
2900         return;
2901     m_context->releaseShaderCompiler();
2902     cleanupAfterGraphicsCall(false);
2903 }
2904
2905 void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
2906 {
2907     if (isContextLost())
2908         return;
2909     if (target != GraphicsContext3D::RENDERBUFFER) {
2910         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2911         return;
2912     }
2913     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2914         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2915         return;
2916     }
2917     if (!validateSize(width, height))
2918         return;
2919     switch (internalformat) {
2920     case GraphicsContext3D::DEPTH_COMPONENT16:
2921     case GraphicsContext3D::RGBA4:
2922     case GraphicsContext3D::RGB5_A1:
2923     case GraphicsContext3D::RGB565:
2924     case GraphicsContext3D::STENCIL_INDEX8:
2925         m_context->renderbufferStorage(target, internalformat, width, height);
2926         m_renderbufferBinding->setInternalFormat(internalformat);
2927         m_renderbufferBinding->setIsValid(true);
2928         m_renderbufferBinding->setSize(width, height);
2929         cleanupAfterGraphicsCall(false);
2930         break;
2931     case GraphicsContext3D::DEPTH_STENCIL:
2932         if (isDepthStencilSupported()) {
2933             m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
2934             cleanupAfterGraphicsCall(false);
2935         }
2936         m_renderbufferBinding->setSize(width, height);
2937         m_renderbufferBinding->setIsValid(isDepthStencilSupported());
2938         m_renderbufferBinding->setInternalFormat(internalformat);
2939         break;
2940     default:
2941         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2942     }
2943 }
2944
2945 void WebGLRenderingContext::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
2946 {
2947     if (isContextLost())
2948         return;
2949     m_context->sampleCoverage(value, invert);
2950     cleanupAfterGraphicsCall(false);
2951 }
2952
2953 void WebGLRenderingContext::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
2954 {
2955     if (isContextLost())
2956         return;
2957     if (!validateSize(width, height))
2958         return;
2959     m_context->scissor(x, y, width, height);
2960     cleanupAfterGraphicsCall(false);
2961 }
2962
2963 void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
2964 {
2965     UNUSED_PARAM(ec);
2966     if (isContextLost() || !validateWebGLObject(shader))
2967         return;
2968     String stringWithoutComments = StripComments(string).result();
2969     if (!validateString(stringWithoutComments))
2970         return;
2971     shader->setSource(string);
2972     m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
2973     cleanupAfterGraphicsCall(false);
2974 }
2975
2976 void WebGLRenderingContext::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
2977 {
2978     if (isContextLost())
2979         return;
2980     if (!validateStencilFunc(func))
2981         return;
2982     m_stencilFuncRef = ref;
2983     m_stencilFuncRefBack = ref;
2984     m_stencilFuncMask = mask;
2985     m_stencilFuncMaskBack = mask;
2986     m_context->stencilFunc(func, ref, mask);
2987     cleanupAfterGraphicsCall(false);
2988 }
2989
2990 void WebGLRenderingContext::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
2991 {
2992     if (isContextLost())
2993         return;
2994     if (!validateStencilFunc(func))
2995         return;
2996     switch (face) {
2997     case GraphicsContext3D::FRONT_AND_BACK:
2998         m_stencilFuncRef = ref;
2999         m_stencilFuncRefBack = ref;
3000         m_stencilFuncMask = mask;
3001         m_stencilFuncMaskBack = mask;
3002         break;
3003     case GraphicsContext3D::FRONT:
3004         m_stencilFuncRef = ref;
3005         m_stencilFuncMask = mask;
3006         break;
3007     case GraphicsContext3D::BACK:
3008         m_stencilFuncRefBack = ref;
3009         m_stencilFuncMaskBack = mask;
3010         break;
3011     default:
3012         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3013         return;
3014     }
3015     m_context->stencilFuncSeparate(face, func, ref, mask);
3016     cleanupAfterGraphicsCall(false);
3017 }
3018
3019 void WebGLRenderingContext::stencilMask(GC3Duint mask)
3020 {
3021     if (isContextLost())
3022         return;
3023     m_stencilMask = mask;
3024     m_stencilMaskBack = mask;
3025     m_context->stencilMask(mask);
3026     cleanupAfterGraphicsCall(false);
3027 }
3028
3029 void WebGLRenderingContext::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
3030 {
3031     if (isContextLost())
3032         return;
3033     switch (face) {
3034     case GraphicsContext3D::FRONT_AND_BACK:
3035         m_stencilMask = mask;
3036         m_stencilMaskBack = mask;
3037         break;
3038     case GraphicsContext3D::FRONT:
3039         m_stencilMask = mask;
3040         break;
3041     case GraphicsContext3D::BACK:
3042         m_stencilMaskBack = mask;
3043         break;
3044     default:
3045         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3046         return;
3047     }
3048     m_context->stencilMaskSeparate(face, mask);
3049     cleanupAfterGraphicsCall(false);
3050 }
3051
3052 void WebGLRenderingContext::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3053 {
3054     if (isContextLost())
3055         return;
3056     m_context->stencilOp(fail, zfail, zpass);
3057     cleanupAfterGraphicsCall(false);
3058 }
3059
3060 void WebGLRenderingContext::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3061 {
3062     if (isContextLost())
3063         return;
3064     m_context->stencilOpSeparate(face, fail, zfail, zpass);
3065     cleanupAfterGraphicsCall(false);
3066 }
3067
3068 void WebGLRenderingContext::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3069                                            GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3070                                            GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3071 {
3072     // FIXME: For now we ignore any errors returned
3073     ec = 0;
3074     if (!validateTexFuncParameters(target, level, internalformat, width, height, border, format, type))
3075         return;
3076     WebGLTexture* tex = validateTextureBinding(target, true);
3077     if (!tex)
3078         return;
3079     if (!isGLES2NPOTStrict()) {
3080         if (level && WebGLTexture::isNPOT(width, height)) {
3081             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3082             return;
3083         }
3084     }
3085     if (!pixels) {
3086         bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
3087                                                          border, format, type, m_unpackAlignment);
3088         if (!succeed)
3089             return;
3090     } else {
3091         m_context->texImage2D(target, level, internalformat, width, height,
3092                               border, format, type, pixels);
3093     }
3094     tex->setLevelInfo(target, level, internalformat, width, height, type);
3095     cleanupAfterGraphicsCall(false);
3096 }
3097
3098 void WebGLRenderingContext::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3099                                            GC3Denum format, GC3Denum type, Image* image,
3100                                            bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3101 {
3102     ec = 0;
3103     Vector<uint8_t> data;
3104     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3105         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3106         return;
3107     }
3108     if (m_unpackAlignment != 1)
3109         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3110     texImage2DBase(target, level, internalformat, image->width(), image->height(), 0,
3111                    format, type, data.data(), ec);
3112     if (m_unpackAlignment != 1)
3113         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3114 }
3115
3116 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3117                                        GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3118                                        GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3119 {
3120     if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
3121         return;
3122     void* data = pixels ? pixels->baseAddress() : 0;
3123     Vector<uint8_t> tempData;
3124     bool changeUnpackAlignment = false;
3125     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3126         if (!m_context->extractTextureData(width, height, format, type,
3127                                            m_unpackAlignment,
3128                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3129                                            data,
3130                                            tempData))
3131             return;
3132         data = tempData.data();
3133         changeUnpackAlignment = true;
3134     }
3135     if (changeUnpackAlignment)
3136         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3137     texImage2DBase(target, level, internalformat, width, height, border,
3138                    format, type, data, ec);
3139     if (changeUnpackAlignment)
3140         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3141 }
3142
3143 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3144                                        GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3145 {
3146     ec = 0;
3147     if (isContextLost())
3148         return;
3149     Vector<uint8_t> data;
3150     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3151         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3152         return;
3153     }
3154     if (m_unpackAlignment != 1)
3155         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3156     texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0,
3157                    format, type, data.data(), ec);
3158     if (m_unpackAlignment != 1)
3159         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3160 }
3161
3162 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3163                                        GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3164 {
3165     ec = 0;
3166     if (isContextLost())
3167         return;
3168     if (!validateHTMLImageElement(image))
3169         return;
3170     if (wouldTaintOrigin(image)) {
3171         ec = SECURITY_ERR;
3172         return;
3173     }
3174
3175     texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->image(),
3176                    m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3177 }
3178
3179 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3180                                        GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3181 {
3182     ec = 0;
3183     if (isContextLost())
3184         return;
3185     if (!canvas || !canvas->buffer()) {
3186         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3187         return;
3188     }
3189     if (wouldTaintOrigin(canvas)) {
3190         ec = SECURITY_ERR;
3191         return;
3192     }
3193     RefPtr<ImageData> imageData = canvas->getImageData();
3194     if (imageData)
3195         texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
3196     else
3197         texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(),
3198                        m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3199 }
3200
3201 #if ENABLE(VIDEO)
3202 PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video, ExceptionCode& ec)
3203 {
3204     if (!video || !video->videoWidth() || !video->videoHeight()) {
3205         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3206         return 0;
3207     }
3208     IntSize size(video->videoWidth(), video->videoHeight());
3209     ImageBuffer* buf = m_videoCache.imageBuffer(size);
3210     if (!buf) {
3211         m_context->synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY);
3212         return 0;
3213     }
3214     if (wouldTaintOrigin(video)) {
3215         ec = SECURITY_ERR;
3216         return 0;
3217     }
3218     IntRect destRect(0, 0, size.width(), size.height());
3219     // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
3220     video->paintCurrentFrameInContext(buf->context(), destRect);
3221     return buf->copyImage(CopyBackingStore);
3222 }
3223
3224 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3225                                        GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3226 {
3227     ec = 0;
3228     if (isContextLost())
3229         return;
3230     RefPtr<Image> image = videoFrameToImage(video, ec);
3231     if (!image)
3232         return;
3233     texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3234 }
3235 #endif
3236
3237 void WebGLRenderingContext::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
3238 {
3239     if (isContextLost())
3240         return;
3241     WebGLTexture* tex = validateTextureBinding(target, false);
3242     if (!tex)
3243         return;
3244     switch (pname) {
3245     case GraphicsContext3D::TEXTURE_MIN_FILTER:
3246     case GraphicsContext3D::TEXTURE_MAG_FILTER:
3247         break;
3248     case GraphicsContext3D::TEXTURE_WRAP_S:
3249     case GraphicsContext3D::TEXTURE_WRAP_T:
3250         if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT)
3251             || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) {
3252             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3253             return;
3254         }
3255         break;
3256     default:
3257         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3258         return;
3259     }
3260     if (isFloat) {
3261         tex->setParameterf(pname, paramf);
3262         m_context->texParameterf(target, pname, paramf);
3263     } else {
3264         tex->setParameteri(pname, parami);
3265         m_context->texParameteri(target, pname, parami);
3266     }
3267     cleanupAfterGraphicsCall(false);
3268 }
3269
3270 void WebGLRenderingContext::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
3271 {
3272     texParameter(target, pname, param, 0, true);
3273 }
3274
3275 void WebGLRenderingContext::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
3276 {
3277     texParameter(target, pname, 0, param, false);
3278 }
3279
3280 void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3281                                               GC3Dsizei width, GC3Dsizei height,
3282                                               GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3283 {
3284     // FIXME: For now we ignore any errors returned
3285     ec = 0;
3286     if (isContextLost())
3287         return;
3288     if (!validateTexFuncParameters(target, level, format, width, height, 0, format, type))
3289         return;
3290     if (!validateSize(xoffset, yoffset))
3291         return;
3292     WebGLTexture* tex = validateTextureBinding(target, true);
3293     if (!tex)
3294         return;
3295     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
3296         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3297         return;
3298     }
3299     if (tex->getInternalFormat(target, level) != format || tex->getType(target, level) != type) {
3300         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3301         return;
3302     }
3303     m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
3304     cleanupAfterGraphicsCall(false);
3305 }
3306
3307 void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3308                                               GC3Denum format, GC3Denum type,
3309                                               Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3310 {
3311     ec = 0;
3312     if (isContextLost())
3313         return;
3314     Vector<uint8_t> data;
3315     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3316         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3317         return;
3318     }
3319     texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(),
3320                       format, type, data.data(), ec);
3321 }
3322
3323 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3324                                           GC3Dsizei width, GC3Dsizei height,
3325                                           GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3326 {
3327     if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
3328         return;
3329     void* data = pixels ? pixels->baseAddress() : 0;
3330     Vector<uint8_t> tempData;
3331     bool changeUnpackAlignment = false;
3332     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3333         if (!m_context->extractTextureData(width, height, format, type,
3334                                            m_unpackAlignment,
3335                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3336                                            data,
3337                                            tempData))
3338             return;
3339         data = tempData.data();
3340         changeUnpackAlignment = true;
3341     }
3342     if (changeUnpackAlignment)
3343         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3344     texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
3345     if (changeUnpackAlignment)
3346         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3347 }
3348
3349 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3350                                           GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3351 {
3352     ec = 0;
3353     if (isContextLost())
3354         return;
3355     Vector<uint8_t> data;
3356     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3357         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3358         return;
3359     }
3360     texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(),
3361                       format, type, data.data(), ec);
3362 }
3363
3364 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3365                                           GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3366 {
3367     ec = 0;
3368     if (isContextLost())
3369         return;
3370     if (!validateHTMLImageElement(image))
3371         return;
3372     if (wouldTaintOrigin(image)) {
3373         ec = SECURITY_ERR;
3374         return;
3375     }
3376     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image->cachedImage()->image(),
3377                       m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3378 }
3379
3380 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3381                                           GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3382 {
3383     ec = 0;
3384     if (isContextLost())
3385         return;
3386     if (!canvas || !canvas->buffer()) {
3387         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3388         return;
3389     }
3390     if (wouldTaintOrigin(canvas)) {
3391         ec = SECURITY_ERR;
3392         return;
3393     }
3394     RefPtr<ImageData> imageData = canvas->getImageData();
3395     if (imageData)
3396         texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec);
3397     else
3398         texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(),
3399                           m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3400 }
3401
3402 #if ENABLE(VIDEO)
3403 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3404                                           GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3405 {
3406     ec = 0;
3407     if (isContextLost())
3408         return;
3409     RefPtr<Image> image = videoFrameToImage(video, ec);
3410     if (!image)
3411         return;
3412     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3413 }
3414 #endif
3415
3416 void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode& ec)
3417 {
3418     UNUSED_PARAM(ec);
3419     if (isContextLost() || !location)
3420         return;
3421
3422     if (location->program() != m_currentProgram) {
3423         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3424         return;
3425     }
3426
3427     m_context->uniform1f(location->location(), x);
3428     cleanupAfterGraphicsCall(false);
3429 }
3430
3431 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3432 {
3433     UNUSED_PARAM(ec);
3434     if (isContextLost() || !validateUniformParameters(location, v, 1))
3435         return;
3436
3437     m_context->uniform1fv(location->location(), v->data(), v->length());
3438     cleanupAfterGraphicsCall(false);
3439 }
3440
3441 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3442 {
3443     UNUSED_PARAM(ec);
3444     if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3445         return;
3446
3447     m_context->uniform1fv(location->location(), v, size);
3448     cleanupAfterGraphicsCall(false);
3449 }
3450
3451 void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode& ec)
3452 {
3453     UNUSED_PARAM(ec);
3454     if (isContextLost() || !location)
3455         return;
3456
3457     if (location->program() != m_currentProgram) {
3458         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3459         return;
3460     }
3461
3462     m_context->uniform1i(location->location(), x);
3463     cleanupAfterGraphicsCall(false);
3464 }
3465
3466 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3467 {
3468     UNUSED_PARAM(ec);
3469     if (isContextLost() || !validateUniformParameters(location, v, 1))
3470         return;
3471
3472     m_context->uniform1iv(location->location(), v->data(), v->length());
3473     cleanupAfterGraphicsCall(false);
3474 }
3475
3476 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3477 {
3478     UNUSED_PARAM(ec);
3479     if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3480         return;
3481
3482     m_context->uniform1iv(location->location(), v, size);
3483     cleanupAfterGraphicsCall(false);
3484 }
3485
3486 void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode& ec)
3487 {
3488     UNUSED_PARAM(ec);
3489     if (isContextLost() || !location)
3490         return;
3491
3492     if (location->program() != m_currentProgram) {
3493         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3494         return;
3495     }
3496
3497     m_context->uniform2f(location->location(), x, y);
3498     cleanupAfterGraphicsCall(false);
3499 }
3500
3501 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3502 {
3503     UNUSED_PARAM(ec);
3504     if (isContextLost() || !validateUniformParameters(location, v, 2))
3505         return;
3506
3507     m_context->uniform2fv(location->location(), v->data(), v->length() / 2);
3508     cleanupAfterGraphicsCall(false);
3509 }
3510
3511 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3512 {
3513     UNUSED_PARAM(ec);
3514     if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3515         return;
3516
3517     m_context->uniform2fv(location->location(), v, size / 2);
3518     cleanupAfterGraphicsCall(false);
3519 }
3520
3521 void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode& ec)
3522 {
3523     UNUSED_PARAM(ec);
3524     if (isContextLost() || !location)
3525         return;
3526
3527     if (location->program() != m_currentProgram) {
3528         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3529         return;
3530     }
3531
3532     m_context->uniform2i(location->location(), x, y);
3533     cleanupAfterGraphicsCall(false);
3534 }
3535
3536 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3537 {
3538     UNUSED_PARAM(ec);
3539     if (isContextLost() || !validateUniformParameters(location, v, 2))
3540         return;
3541
3542     m_context->uniform2iv(location->location(), v->data(), v->length() / 2);
3543     cleanupAfterGraphicsCall(false);
3544 }
3545
3546 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3547 {
3548     UNUSED_PARAM(ec);
3549     if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3550         return;
3551
3552     m_context->uniform2iv(location->location(), v, size / 2);
3553     cleanupAfterGraphicsCall(false);
3554 }
3555
3556 void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode& ec)
3557 {
3558     UNUSED_PARAM(ec);
3559     if (isContextLost() || !location)
3560         return;
3561
3562     if (location->program() != m_currentProgram) {
3563         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3564         return;
3565     }
3566
3567     m_context->uniform3f(location->location(), x, y, z);
3568     cleanupAfterGraphicsCall(false);
3569 }
3570
3571 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3572 {
3573     UNUSED_PARAM(ec);
3574     if (isContextLost() || !validateUniformParameters(location, v, 3))
3575         return;
3576
3577     m_context->uniform3fv(location->location(), v->data(), v->length() / 3);
3578     cleanupAfterGraphicsCall(false);
3579 }
3580
3581 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3582 {
3583     UNUSED_PARAM(ec);
3584     if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3585         return;
3586
3587     m_context->uniform3fv(location->location(), v, size / 3);
3588     cleanupAfterGraphicsCall(false);
3589 }
3590
3591 void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode& ec)
3592 {
3593     UNUSED_PARAM(ec);
3594     if (isContextLost() || !location)
3595         return;
3596
3597     if (location->program() != m_currentProgram) {
3598         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3599         return;
3600     }
3601
3602     m_context->uniform3i(location->location(), x, y, z);
3603     cleanupAfterGraphicsCall(false);
3604 }
3605
3606 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3607 {
3608     UNUSED_PARAM(ec);
3609     if (isContextLost() || !validateUniformParameters(location, v, 3))
3610         return;
3611
3612     m_context->uniform3iv(location->location(), v->data(), v->length() / 3);
3613     cleanupAfterGraphicsCall(false);
3614 }
3615
3616 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3617 {
3618     UNUSED_PARAM(ec);
3619     if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3620         return;
3621
3622     m_context->uniform3iv(location->location(), v, size / 3);
3623     cleanupAfterGraphicsCall(false);
3624 }
3625
3626 void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode& ec)
3627 {
3628     UNUSED_PARAM(ec);
3629     if (isContextLost() || !location)
3630         return;
3631
3632     if (location->program() != m_currentProgram) {
3633         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3634         return;
3635     }
3636
3637     m_context->uniform4f(location->location(), x, y, z, w);
3638     cleanupAfterGraphicsCall(false);
3639 }
3640
3641 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3642 {
3643     UNUSED_PARAM(ec);
3644     if (isContextLost() || !validateUniformParameters(location, v, 4))
3645         return;
3646
3647     m_context->uniform4fv(location->location(), v->data(), v->length() / 4);
3648     cleanupAfterGraphicsCall(false);
3649 }
3650
3651 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3652 {
3653     UNUSED_PARAM(ec);
3654     if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3655         return;
3656
3657     m_context->uniform4fv(location->location(), v, size / 4);
3658     cleanupAfterGraphicsCall(false);
3659 }
3660
3661 void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode& ec)
3662 {
3663     UNUSED_PARAM(ec);
3664     if (isContextLost() || !location)
3665         return;
3666
3667     if (location->program() != m_currentProgram) {
3668         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3669         return;
3670     }
3671
3672     m_context->uniform4i(location->location(), x, y, z, w);
3673     cleanupAfterGraphicsCall(false);
3674 }
3675
3676 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3677 {
3678     UNUSED_PARAM(ec);
3679     if (isContextLost() || !validateUniformParameters(location, v, 4))
3680         return;
3681
3682     m_context->uniform4iv(location->location(), v->data(), v->length() / 4);
3683     cleanupAfterGraphicsCall(false);
3684 }
3685
3686 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3687 {
3688     UNUSED_PARAM(ec);
3689     if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3690         return;
3691
3692     m_context->uniform4iv(location->location(), v, size / 4);
3693     cleanupAfterGraphicsCall(false);
3694 }
3695
3696 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3697 {
3698     UNUSED_PARAM(ec);
3699     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 4))
3700         return;
3701     m_context->uniformMatrix2fv(location->location(), transpose, v->data(), v->length() / 4);
3702     cleanupAfterGraphicsCall(false);
3703 }
3704
3705 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3706 {
3707     UNUSED_PARAM(ec);
3708     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 4))
3709         return;
3710     m_context->uniformMatrix2fv(location->location(), transpose, v, size / 4);
3711     cleanupAfterGraphicsCall(false);
3712 }
3713
3714 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3715 {
3716     UNUSED_PARAM(ec);
3717     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 9))
3718         return;
3719     m_context->uniformMatrix3fv(location->location(), transpose, v->data(), v->length() / 9);
3720     cleanupAfterGraphicsCall(false);
3721 }
3722
3723 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3724 {
3725     UNUSED_PARAM(ec);
3726     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 9))
3727         return;
3728     m_context->uniformMatrix3fv(location->location(), transpose, v, size / 9);
3729     cleanupAfterGraphicsCall(false);
3730 }
3731
3732 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3733 {
3734     UNUSED_PARAM(ec);
3735     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 16))
3736         return;
3737     m_context->uniformMatrix4fv(location->location(), transpose, v->data(), v->length() / 16);
3738     cleanupAfterGraphicsCall(false);
3739 }
3740
3741 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3742 {
3743     UNUSED_PARAM(ec);
3744     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 16))
3745         return;
3746     m_context->uniformMatrix4fv(location->location(), transpose, v, size / 16);
3747     cleanupAfterGraphicsCall(false);
3748 }
3749
3750 void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
3751 {
3752     UNUSED_PARAM(ec);
3753     bool deleted;
3754     if (!checkObjectToBeBound(program, deleted))
3755         return;
3756     if (deleted)
3757         program = 0;
3758     if (program && !program->getLinkStatus()) {
3759         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3760         cleanupAfterGraphicsCall(false);
3761         return;
3762     }
3763     if (m_currentProgram != program) {
3764         if (m_currentProgram)
3765             m_currentProgram->onDetached();
3766         m_currentProgram = program;
3767         m_context->useProgram(objectOrZero(program));
3768         if (program)
3769             program->onAttached();
3770     }
3771     cleanupAfterGraphicsCall(false);
3772 }
3773
3774 void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec)
3775 {
3776     UNUSED_PARAM(ec);
3777     if (isContextLost() || !validateWebGLObject(program))
3778         return;
3779     m_context->validateProgram(objectOrZero(program));
3780     cleanupAfterGraphicsCall(false);
3781 }
3782
3783 void WebGLRenderingContext::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
3784 {
3785     vertexAttribfImpl(index, 1, v0, 0.0f, 0.0f, 1.0f);
3786 }
3787
3788 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, Float32Array* v)
3789 {
3790     vertexAttribfvImpl(index, v, 1);
3791 }
3792
3793 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3794 {
3795     vertexAttribfvImpl(index, v, size, 1);
3796 }
3797
3798 void WebGLRenderingContext::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
3799 {
3800     vertexAttribfImpl(index, 2, v0, v1, 0.0f, 1.0f);
3801 }
3802
3803 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, Float32Array* v)
3804 {
3805     vertexAttribfvImpl(index, v, 2);
3806 }
3807
3808 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3809 {
3810     vertexAttribfvImpl(index, v, size, 2);
3811 }
3812
3813 void WebGLRenderingContext::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
3814 {
3815     vertexAttribfImpl(index, 3, v0, v1, v2, 1.0f);
3816 }
3817
3818 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, Float32Array* v)
3819 {
3820     vertexAttribfvImpl(index, v, 3);
3821 }
3822
3823 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3824 {
3825     vertexAttribfvImpl(index, v, size, 3);
3826 }
3827
3828 void WebGLRenderingContext::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
3829 {
3830     vertexAttribfImpl(index, 4, v0, v1, v2, v3);
3831 }
3832
3833 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, Float32Array* v)
3834 {
3835     vertexAttribfvImpl(index, v, 4);
3836 }
3837
3838 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3839 {
3840     vertexAttribfvImpl(index, v, size, 4);
3841 }
3842
3843 void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset, ExceptionCode& ec)
3844 {
3845     UNUSED_PARAM(ec);
3846     if (isContextLost())
3847         return;
3848     switch (type) {
3849     case GraphicsContext3D::BYTE:
3850     case GraphicsContext3D::UNSIGNED_BYTE:
3851     case GraphicsContext3D::SHORT:
3852     case GraphicsContext3D::UNSIGNED_SHORT:
3853     case GraphicsContext3D::FLOAT:
3854         break;
3855     default:
3856         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3857         return;
3858     }
3859     if (index >= m_maxVertexAttribs) {
3860         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3861         return;
3862     }
3863     if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) {
3864         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3865         return;
3866     }
3867     if (!m_boundArrayBuffer) {
3868         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3869         return;
3870     }
3871     // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
3872     unsigned int typeSize = sizeInBytes(type);
3873     if (!typeSize) {
3874         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3875         return;
3876     }
3877     if ((stride % typeSize) || (offset % typeSize)) {
3878         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3879         return;
3880     }
3881     GC3Dsizei bytesPerElement = size * typeSize;
3882
3883     GC3Dsizei validatedStride = stride ? stride : bytesPerElement;
3884
3885     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
3886     state.bufferBinding = m_boundArrayBuffer;
3887     state.bytesPerElement = bytesPerElement;
3888     state.size = size;
3889     state.type = type;
3890     state.normalized = normalized;
3891     state.stride = validatedStride;
3892     state.originalStride = stride;
3893     state.offset = offset;
3894     m_context->vertexAttribPointer(index, size, type, normalized, stride, offset);
3895     cleanupAfterGraphicsCall(false);
3896 }
3897
3898 void WebGLRenderingContext::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
3899 {
3900     if (isContextLost())
3901         return;
3902     if (!validateSize(width, height))
3903         return;
3904     m_context->viewport(x, y, width, height);
3905     cleanupAfterGraphicsCall(false);
3906 }
3907
3908 void WebGLRenderingContext::forceLostContext(WebGLRenderingContext::LostContextMode mode)
3909 {
3910     if (isContextLost()) {
3911         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3912         return;
3913     }
3914
3915     loseContext();
3916
3917     if (mode == RealLostContext)
3918         m_restoreTimer.startOneShot(0);
3919 }
3920
3921 void WebGLRenderingContext::forceRestoreContext()
3922 {
3923     if (!isContextLost()) {
3924         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3925         return;
3926     }
3927
3928     maybeRestoreContext(SyntheticLostContext);
3929 }
3930
3931 void WebGLRenderingContext::removeObject(WebGLObject* object)
3932 {
3933     m_canvasObjects.remove(object);
3934 }
3935
3936 void WebGLRenderingContext::addObject(WebGLObject* object)
3937 {
3938     ASSERT(!isContextLost());
3939     removeObject(object);
3940     m_canvasObjects.add(object);
3941 }
3942
3943 void WebGLRenderingContext::detachAndRemoveAllObjects()
3944 {
3945     while (m_canvasObjects.size() > 0) {
3946         HashSet<WebGLObject*>::iterator it = m_canvasObjects.begin();
3947         (*it)->detachContext();
3948     }
3949 }
3950
3951 WebGLGetInfo WebGLRenderingContext::getBooleanParameter(GC3Denum pname)
3952 {
3953     GC3Dboolean value = 0;
3954     m_context->getBooleanv(pname, &value);
3955     return WebGLGetInfo(static_cast<bool>(value));
3956 }
3957
3958 WebGLGetInfo WebGLRenderingContext::getBooleanArrayParameter(GC3Denum pname)
3959 {
3960     if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
3961         notImplemented();
3962         return WebGLGetInfo(0, 0);
3963     }
3964     GC3Dboolean value[4] = {0};
3965     m_context->getBooleanv(pname, value);
3966     bool boolValue[4];
3967     for (int ii = 0; ii < 4; ++ii)
3968         boolValue[ii] = static_cast<bool>(value[ii]);
3969     return WebGLGetInfo(boolValue, 4);
3970 }
3971
3972 WebGLGetInfo WebGLRenderingContext::getFloatParameter(GC3Denum pname)
3973 {
3974     GC3Dfloat value = 0;
3975     m_context->getFloatv(pname, &value);
3976     return WebGLGetInfo(value);
3977 }
3978
3979 WebGLGetInfo WebGLRenderingContext::getIntParameter(GC3Denum pname)
3980 {
3981     GC3Dint value = 0;
3982     m_context->getIntegerv(pname, &value);
3983     return WebGLGetInfo(value);
3984 }
3985
3986 WebGLGetInfo WebGLRenderingContext::getUnsignedIntParameter(GC3Denum pname)
3987 {
3988     GC3Dint value = 0;
3989     m_context->getIntegerv(pname, &value);
3990     return WebGLGetInfo(static_cast<unsigned int>(value));
3991 }
3992
3993 WebGLGetInfo WebGLRenderingContext::getWebGLFloatArrayParameter(GC3Denum pname)
3994 {
3995     GC3Dfloat value[4] = {0};
3996     m_context->getFloatv(pname, value);
3997     unsigned length = 0;
3998     switch (pname) {
3999     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
4000     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
4001     case GraphicsContext3D::DEPTH_RANGE:
4002         length = 2;
4003         break;
4004     case GraphicsContext3D::BLEND_COLOR:
4005     case GraphicsContext3D::COLOR_CLEAR_VALUE:
4006         length = 4;
4007         break;
4008     default:
4009         notImplemented();
4010     }
4011     return WebGLGetInfo(Float32Array::create(value, length));
4012 }
4013
4014 WebGLGetInfo WebGLRenderingContext::getWebGLIntArrayParameter(GC3Denum pname)
4015 {
4016     GC3Dint value[4] = {0};
4017     m_context->getIntegerv(pname, value);
4018     unsigned length = 0;
4019     switch (pname) {
4020     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
4021         length = 2;
4022         break;
4023     case GraphicsContext3D::SCISSOR_BOX:
4024     case GraphicsContext3D::VIEWPORT:
4025         length = 4;
4026         break;
4027     default:
4028         notImplemented();
4029     }
4030     return WebGLGetInfo(Int32Array::create(value, length));
4031 }
4032
4033 void WebGLRenderingContext::handleNPOTTextures(bool prepareToDraw)
4034 {
4035     bool resetActiveUnit = false;
4036     for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) {
4037         if ((m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4038             || (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())) {
4039             if (ii != m_activeTextureUnit) {
4040                 m_context->activeTexture(ii);
4041                 resetActiveUnit = true;
4042             } else if (resetActiveUnit) {
4043                 m_context->activeTexture(ii);
4044                 resetActiveUnit = false;
4045             }
4046             WebGLTexture* tex2D;
4047             WebGLTexture* texCubeMap;
4048             if (prepareToDraw) {
4049                 tex2D = m_blackTexture2D.get();
4050                 texCubeMap = m_blackTextureCubeMap.get();
4051             } else {
4052                 tex2D = m_textureUnits[ii].m_texture2DBinding.get();
4053                 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
4054             }
4055             if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4056                 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D));
4057             if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())
4058                 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
4059         }
4060     }
4061     if (resetActiveUnit)
4062         m_context->activeTexture(m_activeTextureUnit);
4063 }
4064
4065 void WebGLRenderingContext::createFallbackBlackTextures1x1()
4066 {
4067     unsigned char black[] = {0, 0, 0, 255};
4068     m_blackTexture2D = createTexture();
4069     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D->object());
4070     m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1,
4071                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4072     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
4073     m_blackTextureCubeMap = createTexture();
4074     m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
4075     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4076                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4077     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4078                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4079     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4080                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4081     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4082                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4083     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4084                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4085     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4086                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4087     m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0);
4088 }
4089
4090 bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,
4091                                                                            GC3Denum colorBufferFormat)
4092 {
4093     switch (colorBufferFormat) {
4094     case GraphicsContext3D::ALPHA:
4095         if (texInternalFormat == GraphicsContext3D::ALPHA)
4096             return true;
4097         break;
4098     case GraphicsContext3D::RGB:
4099         if (texInternalFormat == GraphicsContext3D::LUMINANCE
4100             || texInternalFormat == GraphicsContext3D::RGB)
4101             return true;
4102         break;
4103     case GraphicsContext3D::RGBA:
4104         return true;
4105     }
4106     return false;
4107 }
4108
4109 GC3Denum WebGLRenderingContext::getBoundFramebufferColorFormat()
4110 {
4111     if (m_framebufferBinding && m_framebufferBinding->object())
4112         return m_framebufferBinding->getColorBufferFormat();
4113     if (m_attributes.alpha)
4114         return GraphicsContext3D::RGBA;
4115     return GraphicsContext3D::RGB;
4116 }
4117
4118 int WebGLRenderingContext::getBoundFramebufferWidth()
4119 {
4120     if (m_framebufferBinding && m_framebufferBinding->object())
4121         return m_framebufferBinding->getWidth();
4122     return m_context->getInternalFramebufferSize().width();
4123 }
4124
4125 int WebGLRenderingContext::getBoundFramebufferHeight()
4126 {
4127     if (m_framebufferBinding && m_framebufferBinding->object())
4128         return m_framebufferBinding->getHeight();
4129     return m_context->getInternalFramebufferSize().height();
4130 }
4131
4132 WebGLTexture* WebGLRenderingContext::validateTextureBinding(GC3Denum target, bool useSixEnumsForCubeMap)
4133 {
4134     WebGLTexture* tex = 0;
4135     switch (target) {
4136     case GraphicsContext3D::TEXTURE_2D:
4137         tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
4138         break;
4139     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4140     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4141     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4142     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4143     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4144     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4145         if (!useSixEnumsForCubeMap) {
4146             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4147             return 0;
4148         }
4149         tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4150         break;
4151     case GraphicsContext3D::TEXTURE_CUBE_MAP:
4152         if (useSixEnumsForCubeMap) {
4153             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4154             return 0;
4155         }
4156         tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4157         break;
4158     default:
4159         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4160         return 0;
4161     }
4162     if (!tex)
4163         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4164     return tex;
4165 }
4166
4167 bool WebGLRenderingContext::validateSize(GC3Dint x, GC3Dint y)
4168 {
4169     if (x < 0 || y < 0) {
4170         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4171         return false;
4172     }
4173     return true;
4174 }
4175
4176 bool WebGLRenderingContext::validateString(const String& string)
4177 {
4178     for (size_t i = 0; i < string.length(); ++i) {
4179         if (!validateCharacter(string[i])) {
4180             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4181             return false;
4182         }
4183     }
4184     return true;
4185 }
4186
4187 bool WebGLRenderingContext::validateTexFuncFormatAndType(GC3Denum format, GC3Denum type)
4188 {
4189     switch (format) {
4190     case GraphicsContext3D::ALPHA:
4191     case GraphicsContext3D::LUMINANCE:
4192     case GraphicsContext3D::LUMINANCE_ALPHA:
4193     case GraphicsContext3D::RGB:
4194     case GraphicsContext3D::RGBA:
4195         break;
4196     default:
4197         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4198         return false;
4199     }
4200
4201     switch (type) {
4202     case GraphicsContext3D::UNSIGNED_BYTE:
4203     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4204     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4205     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4206         break;
4207     case GraphicsContext3D::FLOAT:
4208         if (m_oesTextureFloat)
4209             break;
4210         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4211         return false;
4212     default:
4213         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4214         return false;
4215     }
4216
4217     // Verify that the combination of format and type is supported.
4218     switch (format) {
4219     case GraphicsContext3D::ALPHA:
4220     case GraphicsContext3D::LUMINANCE:
4221     case GraphicsContext3D::LUMINANCE_ALPHA:
4222         if (type != GraphicsContext3D::UNSIGNED_BYTE
4223             && type != GraphicsContext3D::FLOAT) {
4224             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4225             return false;
4226         }
4227         break;
4228     case GraphicsContext3D::RGB:
4229         if (type != GraphicsContext3D::UNSIGNED_BYTE
4230             && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5
4231             && type != GraphicsContext3D::FLOAT) {
4232             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4233             return false;
4234         }
4235         break;
4236     case GraphicsContext3D::RGBA:
4237         if (type != GraphicsContext3D::UNSIGNED_BYTE
4238             && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4
4239             && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1
4240             && type != GraphicsContext3D::FLOAT) {
4241             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4242             return false;
4243         }
4244         break;
4245     default:
4246         ASSERT_NOT_REACHED();
4247     }
4248
4249     return true;
4250 }
4251
4252 bool WebGLRenderingContext::validateTexFuncLevel(GC3Denum target, GC3Dint level)
4253 {
4254     if (level < 0) {
4255         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4256         return false;
4257     }
4258     switch (target) {
4259     case GraphicsContext3D::TEXTURE_2D:
4260         if (level > m_maxTextureLevel) {
4261             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4262             return false;
4263         }
4264         break;
4265     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4266     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4267     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4268     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4269     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4270     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4271         if (level > m_maxCubeMapTextureLevel) {
4272             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4273             return false;
4274         }
4275         break;
4276     }
4277     // This function only checks if level is legal, so we return true and don't
4278     // generate INVALID_ENUM if target is illegal.
4279     return true;
4280 }
4281
4282 bool WebGLRenderingContext::validateTexFuncParameters(GC3Denum target, GC3Dint level,
4283                                                       GC3Denum internalformat,
4284                                                       GC3Dsizei width, GC3Dsizei height, GC3Dint border,
4285                                                       GC3Denum format, GC3Denum type)
4286 {
4287     // We absolutely have to validate the format and type combination.
4288     // The texImage2D entry points taking HTMLImage, etc. will produce
4289     // temporary data based on this combination, so it must be legal.
4290     if (!validateTexFuncFormatAndType(format, type) || !validateTexFuncLevel(target, level))
4291         return false;
4292
4293     if (width < 0 || height < 0) {
4294         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4295         return false;
4296     }
4297
4298     switch (target) {
4299     case GraphicsContext3D::TEXTURE_2D:
4300         if (width > m_maxTextureSize || height > m_maxTextureSize) {
4301             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4302             return false;
4303         }
4304         break;
4305     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4306     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4307     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4308     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4309     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4310     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4311         if (width != height || width > m_maxCubeMapTextureSize) {
4312             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4313             return false;
4314         }
4315         break;
4316     default:
4317         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4318         return false;
4319     }
4320
4321     if (format != internalformat) {
4322         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4323         return false;
4324     }
4325
4326     if (border) {
4327         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4328         return false;
4329     }
4330
4331     return true;
4332 }
4333
4334 bool WebGLRenderingContext::validateTexFuncData(GC3Dsizei width, GC3Dsizei height,
4335                                                 GC3Denum format, GC3Denum type,
4336                                                 ArrayBufferView* pixels)
4337 {
4338     if (!pixels)
4339         return true;
4340
4341     if (!validateTexFuncFormatAndType(format, type))
4342         return false;
4343
4344     switch (type) {
4345     case GraphicsContext3D::UNSIGNED_BYTE:
4346         if (!pixels->isUnsignedByteArray()) {
4347             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4348             return false;
4349         }
4350         break;
4351     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4352     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4353     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4354         if (!pixels->isUnsignedShortArray()) {
4355             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4356             return false;
4357         }
4358         break;
4359     case GraphicsContext3D::FLOAT: // OES_texture_float
4360         if (!pixels->isFloatArray()) {
4361             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4362             return false;
4363         }
4364         break;
4365     default:
4366         ASSERT_NOT_REACHED();
4367     }
4368
4369     unsigned int totalBytesRequired;
4370     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
4371     if (error != GraphicsContext3D::NO_ERROR) {
4372         m_context->synthesizeGLError(error);
4373         return false;
4374     }
4375     if (pixels->byteLength() < totalBytesRequired) {
4376         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4377         return false;
4378     }
4379     return true;
4380 }
4381
4382 bool WebGLRenderingContext::validateDrawMode(GC3Denum mode)
4383 {
4384     switch (mode) {
4385     case GraphicsContext3D::POINTS:
4386     case GraphicsContext3D::LINE_STRIP:
4387     case GraphicsContext3D::LINE_LOOP:
4388     case GraphicsContext3D::LINES:
4389     case GraphicsContext3D::TRIANGLE_STRIP:
4390     case GraphicsContext3D::TRIANGLE_FAN:
4391     case GraphicsContext3D::TRIANGLES:
4392         return true;
4393     default:
4394         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4395         return false;
4396     }
4397 }
4398
4399 bool WebGLRenderingContext::validateStencilSettings()
4400 {
4401     if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
4402         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4403         return false;
4404     }
4405     return true;
4406 }
4407
4408 bool WebGLRenderingContext::validateStencilFunc(GC3Denum func)
4409 {
4410     switch (func) {
4411     case GraphicsContext3D::NEVER:
4412     case GraphicsContext3D::LESS:
4413     case GraphicsContext3D::LEQUAL:
4414     case GraphicsContext3D::GREATER:
4415     case GraphicsContext3D::GEQUAL:
4416     case GraphicsContext3D::EQUAL:
4417     case GraphicsContext3D::NOTEQUAL:
4418     case GraphicsContext3D::ALWAYS:
4419         return true;
4420     default:
4421         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4422         return false;
4423     }
4424 }
4425
4426 void WebGLRenderingContext::printWarningToConsole(const String& message)
4427 {
4428     canvas()->document()->frame()->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel,
4429                                                                       message, 0, canvas()->document()->url().string());
4430 }
4431
4432 bool WebGLRenderingContext::validateFramebufferFuncParameters(GC3Denum target, GC3Denum attachment)
4433 {
4434     if (target != GraphicsContext3D::FRAMEBUFFER) {
4435         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4436         return false;
4437     }
4438     switch (attachment) {
4439     case GraphicsContext3D::COLOR_ATTACHMENT0:
4440     case GraphicsContext3D::DEPTH_ATTACHMENT:
4441     case GraphicsContext3D::STENCIL_ATTACHMENT:
4442     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
4443         break;
4444     default:
4445         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4446         return false;
4447     }
4448     return true;
4449 }
4450
4451 bool WebGLRenderingContext::validateBlendEquation(GC3Denum mode)
4452 {
4453     switch (mode) {
4454     case GraphicsContext3D::FUNC_ADD:
4455     case GraphicsContext3D::FUNC_SUBTRACT:
4456     case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
4457         return true;
4458     default:
4459         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4460         return false;
4461     }
4462 }
4463
4464 bool WebGLRenderingContext::validateBlendFuncFactors(GC3Denum src, GC3Denum dst)
4465 {
4466     if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
4467          && (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))
4468         || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
4469             && (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) {
4470         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4471         return false;
4472     }
4473     return true;
4474 }
4475
4476 bool WebGLRenderingContext::validateCapability(GC3Denum cap)
4477 {
4478     switch (cap) {
4479     case GraphicsContext3D::BLEND:
4480     case GraphicsContext3D::CULL_FACE:
4481     case GraphicsContext3D::DEPTH_TEST:
4482     case GraphicsContext3D::DITHER:
4483     case GraphicsContext3D::POLYGON_OFFSET_FILL:
4484     case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
4485     case GraphicsContext3D::SAMPLE_COVERAGE:
4486     case GraphicsContext3D::SCISSOR_TEST:
4487     case GraphicsContext3D::STENCIL_TEST:
4488         return true;
4489     default:
4490         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4491         return false;
4492     }
4493 }
4494
4495 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Float32Array* v, GC3Dsizei requiredMinSize)
4496 {
4497     if (!v) {
4498         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4499         return false;
4500     }
4501     return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
4502 }
4503
4504 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Int32Array* v, GC3Dsizei requiredMinSize)
4505 {
4506     if (!v) {
4507         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4508         return false;
4509     }
4510     return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
4511 }
4512
4513 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
4514 {
4515     return validateUniformMatrixParameters(location, false, v, size, requiredMinSize);
4516 }
4517
4518 bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, GC3Dsizei requiredMinSize)
4519 {
4520     if (!v) {
4521         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4522         return false;
4523     }
4524     return validateUniformMatrixParameters(location, transpose, v->data(), v->length(), requiredMinSize);
4525 }
4526
4527 bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
4528 {
4529     if (!location)
4530         return false;
4531     if (location->program() != m_currentProgram) {
4532         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4533         return false;
4534     }
4535     if (!v) {
4536         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4537         return false;
4538     }
4539     if (transpose) {
4540         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4541         return false;
4542     }
4543     if (size < requiredMinSize || (size % requiredMinSize)) {
4544         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4545         return false;
4546     }
4547     return true;
4548 }
4549
4550 WebGLBuffer* WebGLRenderingContext::validateBufferDataParameters(GC3Denum target, GC3Denum usage)
4551 {
4552     WebGLBuffer* buffer = 0;
4553     switch (target) {
4554     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
4555         buffer = m_boundVertexArrayObject->getElementArrayBuffer().get();
4556         break;
4557     case GraphicsContext3D::ARRAY_BUFFER:
4558         buffer = m_boundArrayBuffer.get();
4559         break;
4560     default:
4561         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4562         return 0;
4563     }
4564     if (!buffer) {
4565         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4566         return 0;
4567     }
4568     switch (usage) {
4569     case GraphicsContext3D::STREAM_DRAW:
4570     case GraphicsContext3D::STATIC_DRAW:
4571     case GraphicsContext3D::DYNAMIC_DRAW:
4572         return buffer;
4573     }
4574     m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4575     return 0;
4576 }
4577
4578 bool WebGLRenderingContext::validateHTMLImageElement(HTMLImageElement* image)
4579 {
4580     if (!image || !image->cachedImage()) {
4581         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4582         return false;
4583     }
4584     const KURL& url = image->cachedImage()->response().url();
4585     if (url.isNull() || url.isEmpty() || !url.isValid()) {
4586         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4587         return false;
4588     }
4589     return true;
4590 }
4591
4592 void WebGLRenderingContext::vertexAttribfImpl(GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
4593 {
4594     if (isContextLost())
4595         return;
4596     if (index >= m_maxVertexAttribs) {
4597         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4598         return;
4599     }
4600     // In GL, we skip setting vertexAttrib0 values.
4601     if (index || isGLES2Compliant()) {
4602         switch (expectedSize) {
4603         case 1:
4604             m_context->vertexAttrib1f(index, v0);
4605             break;
4606         case 2:
4607             m_context->vertexAttrib2f(index, v0, v1);
4608             break;
4609         case 3:
4610             m_context->vertexAttrib3f(index, v0, v1, v2);
4611             break;
4612         case 4:
4613             m_context->vertexAttrib4f(index, v0, v1, v2, v3);
4614             break;
4615         }
4616         cleanupAfterGraphicsCall(false);
4617     }
4618     VertexAttribValue& attribValue = m_vertexAttribValue[index];
4619     attribValue.value[0] = v0;
4620     attribValue.value[1] = v1;
4621     attribValue.value[2] = v2;
4622     attribValue.value[3] = v3;
4623 }
4624
4625 void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, Float32Array* v, GC3Dsizei expectedSize)
4626 {
4627     if (isContextLost())
4628         return;
4629     if (!v) {
4630         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4631         return;
4632     }
4633     vertexAttribfvImpl(index, v->data(), v->length(), expectedSize);
4634 }
4635
4636 void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, GC3Dfloat* v, GC3Dsizei size, GC3Dsizei expectedSize)
4637 {
4638     if (isContextLost())
4639         return;
4640     if (!v) {
4641         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4642         return;
4643     }
4644     if (size < expectedSize) {
4645         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4646         return;
4647     }
4648     if (index >= m_maxVertexAttribs) {
4649         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4650         return;
4651     }
4652     // In GL, we skip setting vertexAttrib0 values.
4653     if (index || isGLES2Compliant()) {
4654         switch (expectedSize) {
4655         case 1:
4656             m_context->vertexAttrib1fv(index, v);
4657             break;
4658         case 2:
4659             m_context->vertexAttrib2fv(index, v);
4660             break;
4661         case 3:
4662             m_context->vertexAttrib3fv(index, v);
4663             break;
4664         case 4:
4665             m_context->vertexAttrib4fv(index, v);
4666             break;
4667         }
4668         cleanupAfterGraphicsCall(false);
4669     }
4670     VertexAttribValue& attribValue = m_vertexAttribValue[index];
4671     attribValue.initValue();
4672     for (int ii = 0; ii < expectedSize; ++ii)
4673         attribValue.value[ii] = v[ii];
4674 }
4675
4676 void WebGLRenderingContext::initVertexAttrib0()
4677 {
4678     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4679     
4680     m_vertexAttrib0Buffer = createBuffer();
4681     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
4682     m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW);
4683     m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
4684     state.bufferBinding = m_vertexAttrib0Buffer;
4685     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
4686     m_context->enableVertexAttribArray(0);
4687     m_vertexAttrib0BufferSize = 0;
4688     m_vertexAttrib0BufferValue[0] = 0.0f;
4689     m_vertexAttrib0BufferValue[1] = 0.0f;
4690     m_vertexAttrib0BufferValue[2] = 0.0f;
4691     m_vertexAttrib0BufferValue[3] = 1.0f;
4692     m_forceAttrib0BufferRefill = false;
4693     m_vertexAttrib0UsedBefore = false;
4694 }
4695
4696 bool WebGLRenderingContext::simulateVertexAttrib0(GC3Dsizei numVertex)
4697 {
4698     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4699     const VertexAttribValue& attribValue = m_vertexAttribValue[0];
4700     if (!m_currentProgram)
4701         return false;
4702     bool usingVertexAttrib0 = m_currentProgram->isUsingVertexAttrib0();
4703     if (usingVertexAttrib0)
4704         m_vertexAttrib0UsedBefore = true;
4705     if (state.enabled && usingVertexAttrib0)
4706         return false;
4707     if (!usingVertexAttrib0 && !m_vertexAttrib0UsedBefore)
4708         return false;
4709     m_vertexAttrib0UsedBefore = true;
4710     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
4711     GC3Dsizeiptr bufferDataSize = (numVertex + 1) * 4 * sizeof(GC3Dfloat);
4712     if (bufferDataSize > m_vertexAttrib0BufferSize) {
4713         m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, bufferDataSize, 0, GraphicsContext3D::DYNAMIC_DRAW);
4714         m_vertexAttrib0BufferSize = bufferDataSize;
4715         m_forceAttrib0BufferRefill = true;
4716     }
4717     if (usingVertexAttrib0
4718         && (m_forceAttrib0BufferRefill
4719             || attribValue.value[0] != m_vertexAttrib0BufferValue[0]
4720             || attribValue.value[1] != m_vertexAttrib0BufferValue[1]
4721             || attribValue.value[2] != m_vertexAttrib0BufferValue[2]
4722             || attribValue.value[3] != m_vertexAttrib0BufferValue[3])) {
4723         OwnArrayPtr<GC3Dfloat> bufferData = adoptArrayPtr(new GC3Dfloat[(numVertex + 1) * 4]);
4724         for (GC3Dsizei ii = 0; ii < numVertex + 1; ++ii) {
4725             bufferData[ii * 4] = attribValue.value[0];
4726             bufferData[ii * 4 + 1] = attribValue.value[1];
4727             bufferData[ii * 4 + 2] = attribValue.value[2];
4728             bufferData[ii * 4 + 3] = attribValue.value[3];
4729         }
4730         m_vertexAttrib0BufferValue[0] = attribValue.value[0];
4731         m_vertexAttrib0BufferValue[1] = attribValue.value[1];
4732         m_vertexAttrib0BufferValue[2] = attribValue.value[2];
4733         m_vertexAttrib0BufferValue[3] = attribValue.value[3];
4734         m_forceAttrib0BufferRefill = false;
4735         m_context->bufferSubData(GraphicsContext3D::ARRAY_BUFFER, 0, bufferDataSize, bufferData.get());
4736     }
4737     m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, 0, 0, 0);
4738     return true;
4739 }
4740
4741 void WebGLRenderingContext::restoreStatesAfterVertexAttrib0Simulation()
4742 {
4743     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4744     if (state.bufferBinding != m_vertexAttrib0Buffer) {
4745         m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(state.bufferBinding.get()));
4746         m_context->vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset);
4747     }
4748     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(m_boundArrayBuffer.get()));
4749 }
4750
4751 void WebGLRenderingContext::loseContext()
4752 {
4753     m_contextLost = true;
4754
4755     detachAndRemoveAllObjects();
4756
4757     // There is no direct way to clear errors from a GL implementation and
4758     // looping until getError() becomes NO_ERROR might cause an infinite loop if
4759     // the driver or context implementation had a bug. So, loop a reasonably
4760     // large number of times to clear any existing errors.
4761     for (int i = 0; i < 100; ++i) {
4762         if (m_context->getError() == GraphicsContext3D::NO_ERROR)
4763             break;
4764     }
4765     m_context->synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL);
4766
4767     RefPtr<WebGLContextEvent> event = WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, "");
4768     canvas()->dispatchEvent(event);
4769     m_restoreAllowed = event->defaultPrevented();
4770 }
4771
4772 void WebGLRenderingContext::maybeRestoreContext(WebGLRenderingContext::LostContextMode mode)
4773 {
4774     if (!m_contextLost) {
4775         ASSERT(mode == SyntheticLostContext);
4776         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4777         return;
4778     }
4779
4780     // The rendering context is not restored unless the default
4781     // behavior of the webglcontextlost event was prevented earlier.
4782     if (!m_restoreAllowed) {
4783         if (mode == SyntheticLostContext)
4784             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4785         return;
4786     }
4787
4788     int contextLostReason = m_context->getExtensions()->getGraphicsResetStatusARB();
4789
4790     switch (contextLostReason) {
4791     case GraphicsContext3D::NO_ERROR:
4792         // The GraphicsContext3D implementation might not fully
4793         // support GL_ARB_robustness semantics yet. Alternatively, the
4794         // WebGL WEBKIT_lose_context extension might have been used to
4795         // force a lost context.
4796         break;
4797     case Extensions3D::GUILTY_CONTEXT_RESET_ARB:
4798         // The rendering context is not restored if this context was
4799         // guilty of causing the graphics reset.
4800         printWarningToConsole("WARNING: WebGL content on the page caused the graphics card to reset; not restoring the context");
4801         return;
4802     case Extensions3D::INNOCENT_CONTEXT_RESET_ARB:
4803         // Always allow the context to be restored.
4804         break;
4805     case Extensions3D::UNKNOWN_CONTEXT_RESET_ARB:
4806         // Warn. Ideally, prompt the user telling them that WebGL
4807         // content on the page might have caused the graphics card to
4808         // reset and ask them whether they want to continue running
4809         // the content. Only if they say "yes" should we start
4810         // attempting to restore the context.
4811         printWarningToConsole("WARNING: WebGL content on the page might have caused the graphics card to reset");
4812         break;
4813     }
4814
4815     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, canvas()->document()->view()->root()->hostWindow()));
4816     if (!context) {
4817         if (mode == RealLostContext)
4818             m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
4819         else
4820             // This likely shouldn't happen but is the best way to report it to the WebGL app.
4821             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4822         return;
4823     }
4824
4825     m_context = context;
4826     m_contextLost = false;
4827     initializeNewContext();
4828     canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, ""));
4829 }
4830
4831 WebGLRenderingContext::LRUImageBufferCache::LRUImageBufferCache(int capacity)
4832     : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity]))
4833     , m_capacity(capacity)
4834 {
4835 }
4836
4837 ImageBuffer* WebGLRenderingContext::LRUImageBufferCache::imageBuffer(const IntSize& size)
4838 {
4839     int i;
4840     for (i = 0; i < m_capacity; ++i) {
4841         ImageBuffer* buf = m_buffers[i].get();
4842         if (!buf)
4843             break;
4844         if (buf->size() != size)
4845             continue;
4846         bubbleToFront(i);
4847         return buf;
4848     }
4849
4850     OwnPtr<ImageBuffer> temp = ImageBuffer::create(size);
4851     if (!temp)
4852         return 0;
4853     i = std::min(m_capacity - 1, i);
4854     m_buffers[i] = temp.release();
4855
4856     ImageBuffer* buf = m_buffers[i].get();
4857     bubbleToFront(i);
4858     return buf;
4859 }
4860
4861 void WebGLRenderingContext::LRUImageBufferCache::bubbleToFront(int idx)
4862 {
4863     for (int i = idx; i > 0; --i)
4864         m_buffers[i].swap(m_buffers[i-1]);
4865 }
4866
4867 } // namespace WebCore
4868
4869 #endif // ENABLE(WEBGL)