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