c5610d3875ebbf4a3b861e9106e68d170477b572
[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         if (!m_boundVertexArrayObject->getVertexAttribState(i).validateBinding())
1885             return false;
1886     }
1887
1888     if (numElementsRequired <= 0)
1889         return true;
1890
1891     // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
1892     unsigned smallestNumElements = UINT_MAX;
1893     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1894     for (int i = 0; i < numActiveAttribLocations; ++i) {
1895         int loc = m_currentProgram->getActiveAttribLocation(i);
1896         if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1897             const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1898             if (state.enabled) {
1899                 // Avoid off-by-one errors in numElements computation.
1900                 // For the last element, we will only touch the data for the
1901                 // element and nothing beyond it.
1902                 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1903                 unsigned numElements = 0;
1904                 ASSERT(state.stride > 0);
1905                 if (bytesRemaining >= state.bytesPerElement)
1906                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1907                 if (numElements < smallestNumElements)
1908                     smallestNumElements = numElements;
1909             }
1910         }
1911     }
1912
1913     if (smallestNumElements == INT_MAX)
1914         smallestNumElements = 0;
1915
1916     return numElementsRequired <= smallestNumElements;
1917 }
1918
1919 bool WebGLRenderingContext::validateWebGLObject(const char* functionName, WebGLObject* object)
1920 {
1921     if (!object || !object->object()) {
1922         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no object or object deleted");
1923         return false;
1924     }
1925     if (!object->validate(contextGroup(), this)) {
1926         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object does not belong to this context");
1927         return false;
1928     }
1929     return true;
1930 }
1931
1932 void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
1933 {
1934     UNUSED_PARAM(ec);
1935
1936     if (isContextLost() || !validateDrawMode("drawArrays", mode))
1937         return;
1938
1939     if (!validateStencilSettings("drawArrays"))
1940         return;
1941
1942     if (first < 0 || count < 0) {
1943         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawArrays", "first or count < 0");
1944         return;
1945     }
1946
1947     if (!count) {
1948         cleanupAfterGraphicsCall(true);
1949         return;
1950     }
1951
1952     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1953         // Ensure we have a valid rendering state
1954         Checked<GC3Dint, RecordOverflow> checkedFirst(first);
1955         Checked<GC3Dint, RecordOverflow> checkedCount(count);
1956         Checked<GC3Dint, RecordOverflow> checkedSum = checkedFirst + checkedCount;
1957         if (checkedSum.hasOverflowed() || !validateVertexAttributes(checkedSum.unsafeGet())) {
1958             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attempt to access out of bounds arrays");
1959             return;
1960         }
1961     } else {
1962         if (!validateVertexAttributes(0)) {
1963             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attribs not setup correctly");
1964             return;
1965         }
1966     }
1967
1968     const char* reason = "framebuffer incomplete";
1969     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1970         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawArrays", reason);
1971         return;
1972     }
1973
1974     clearIfComposited();
1975
1976     bool vertexAttrib0Simulated = false;
1977     if (!isGLES2Compliant())
1978         vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1979     if (!isGLES2NPOTStrict())
1980         handleNPOTTextures("drawArrays", true);
1981     m_context->drawArrays(mode, first, count);
1982     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1983         restoreStatesAfterVertexAttrib0Simulation();
1984     if (!isGLES2NPOTStrict())
1985         handleNPOTTextures("drawArrays", false);
1986     cleanupAfterGraphicsCall(true);
1987 }
1988
1989 void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode& ec)
1990 {
1991     UNUSED_PARAM(ec);
1992
1993     if (isContextLost() || !validateDrawMode("drawElements", mode))
1994         return;
1995
1996     if (!validateStencilSettings("drawElements"))
1997         return;
1998
1999     switch (type) {
2000     case GraphicsContext3D::UNSIGNED_BYTE:
2001     case GraphicsContext3D::UNSIGNED_SHORT:
2002         break;
2003     case GraphicsContext3D::UNSIGNED_INT:
2004         if (m_oesElementIndexUint)
2005             break;
2006         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "drawElements", "invalid type");
2007         return;
2008     default:
2009         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "drawElements", "invalid type");
2010         return;
2011     }
2012
2013     if (count < 0 || offset < 0) {
2014         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawElements", "count or offset < 0");
2015         return;
2016     }
2017
2018     if (!count) {
2019         cleanupAfterGraphicsCall(true);
2020         return;
2021     }
2022
2023     if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
2024         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "no ELEMENT_ARRAY_BUFFER bound");
2025         return;
2026     }
2027
2028     unsigned numElements = 0;
2029     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
2030         // Ensure we have a valid rendering state
2031         if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
2032             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "request out of bounds for current ELEMENT_ARRAY_BUFFER");
2033             return;
2034         }
2035         if (!count)
2036             return;
2037         if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements)) {
2038             if (!validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements) || !validateVertexAttributes(numElements)) {
2039                 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attempt to access out of bounds arrays");
2040                 return;
2041             }
2042         }
2043     } else {
2044         if (!validateVertexAttributes(0)) {
2045             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attribs not setup correctly");
2046             return;
2047         }
2048     }
2049
2050     const char* reason = "framebuffer incomplete";
2051     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
2052         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawElements", reason);
2053         return;
2054     }
2055     clearIfComposited();
2056
2057     bool vertexAttrib0Simulated = false;
2058     if (!isGLES2Compliant()) {
2059         if (!numElements)
2060             validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
2061         vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
2062     }
2063     if (!isGLES2NPOTStrict())
2064         handleNPOTTextures("drawElements", true);
2065     m_context->drawElements(mode, count, type, static_cast<GC3Dintptr>(offset));
2066     if (!isGLES2Compliant() && vertexAttrib0Simulated)
2067         restoreStatesAfterVertexAttrib0Simulation();
2068     if (!isGLES2NPOTStrict())
2069         handleNPOTTextures("drawElements", false);
2070     cleanupAfterGraphicsCall(true);
2071 }
2072
2073 void WebGLRenderingContext::enable(GC3Denum cap)
2074 {
2075     if (isContextLost() || !validateCapability("enable", cap))
2076         return;
2077     if (cap == GraphicsContext3D::STENCIL_TEST) {
2078         m_stencilEnabled = true;
2079         applyStencilTest();
2080         cleanupAfterGraphicsCall(false);
2081         return;
2082     }
2083     if (cap == GraphicsContext3D::SCISSOR_TEST) {
2084         m_scissorEnabled = true;
2085         if (m_drawingBuffer)
2086             m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
2087     }
2088     m_context->enable(cap);
2089     cleanupAfterGraphicsCall(false);
2090 }
2091
2092 void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
2093 {
2094     UNUSED_PARAM(ec);
2095     if (isContextLost())
2096         return;
2097     if (index >= m_maxVertexAttribs) {
2098         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "enableVertexAttribArray", "index out of range");
2099         return;
2100     }
2101
2102     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2103     state.enabled = true;
2104
2105     m_context->enableVertexAttribArray(index);
2106     cleanupAfterGraphicsCall(false);
2107 }
2108
2109 void WebGLRenderingContext::finish()
2110 {
2111     if (isContextLost())
2112         return;
2113     m_context->finish();
2114     cleanupAfterGraphicsCall(false);
2115 }
2116
2117 void WebGLRenderingContext::flush()
2118 {
2119     if (isContextLost())
2120         return;
2121     m_context->flush();
2122     cleanupAfterGraphicsCall(false);
2123 }
2124
2125 void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
2126 {
2127     UNUSED_PARAM(ec);
2128     if (isContextLost() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
2129         return;
2130     if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
2131         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
2132         return;
2133     }
2134     if (buffer && !buffer->validate(contextGroup(), this)) {
2135         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
2136         return;
2137     }
2138     // Don't allow the default framebuffer to be mutated; all current
2139     // implementations use an FBO internally in place of the default
2140     // FBO.
2141     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2142         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
2143         return;
2144     }
2145     Platform3DObject bufferObject = objectOrZero(buffer);
2146     switch (attachment) {
2147     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2148         m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
2149         m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
2150         break;
2151     default:
2152         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
2153     }
2154     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
2155     applyStencilTest();
2156     cleanupAfterGraphicsCall(false);
2157 }
2158
2159 void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
2160 {
2161     UNUSED_PARAM(ec);
2162     if (isContextLost() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
2163         return;
2164     if (level) {
2165         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "framebufferTexture2D", "level not 0");
2166         return;
2167     }
2168     if (texture && !texture->validate(contextGroup(), this)) {
2169         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
2170         return;
2171     }
2172     // Don't allow the default framebuffer to be mutated; all current
2173     // implementations use an FBO internally in place of the default
2174     // FBO.
2175     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2176         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
2177         return;
2178     }
2179     Platform3DObject textureObject = objectOrZero(texture);
2180     switch (attachment) {
2181     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2182         m_context->framebufferTexture2D(target, GraphicsContext3D::DEPTH_ATTACHMENT, textarget, textureObject, level);
2183         m_context->framebufferTexture2D(target, GraphicsContext3D::STENCIL_ATTACHMENT, textarget, textureObject, level);
2184         break;
2185     case GraphicsContext3D::DEPTH_ATTACHMENT:
2186         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2187         break;
2188     case GraphicsContext3D::STENCIL_ATTACHMENT:
2189         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2190         break;
2191     default:
2192         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2193     }
2194     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
2195     applyStencilTest();
2196     cleanupAfterGraphicsCall(false);
2197 }
2198
2199 void WebGLRenderingContext::frontFace(GC3Denum mode)
2200 {
2201     if (isContextLost())
2202         return;
2203     m_context->frontFace(mode);
2204     cleanupAfterGraphicsCall(false);
2205 }
2206
2207 void WebGLRenderingContext::generateMipmap(GC3Denum target)
2208 {
2209     if (isContextLost())
2210         return;
2211     WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
2212     if (!tex)
2213         return;
2214     if (!tex->canGenerateMipmaps()) {
2215         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
2216         return;
2217     }
2218     if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0)))
2219         return;
2220
2221     // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
2222     // on Mac.  Remove the hack once this driver bug is fixed.
2223 #if OS(DARWIN)
2224     bool needToResetMinFilter = false;
2225     if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
2226         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
2227         needToResetMinFilter = true;
2228     }
2229 #endif
2230     m_context->generateMipmap(target);
2231 #if OS(DARWIN)
2232     if (needToResetMinFilter)
2233         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
2234 #endif
2235     tex->generateMipmapLevelInfo();
2236     cleanupAfterGraphicsCall(false);
2237 }
2238
2239 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2240 {
2241     UNUSED_PARAM(ec);
2242     if (isContextLost() || !validateWebGLObject("getActiveAttrib", program))
2243         return 0;
2244     ActiveInfo info;
2245     if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
2246         return 0;
2247     return WebGLActiveInfo::create(info.name, info.type, info.size);
2248 }
2249
2250 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2251 {
2252     UNUSED_PARAM(ec);
2253     if (isContextLost() || !validateWebGLObject("getActiveUniform", program))
2254         return 0;
2255     ActiveInfo info;
2256     if (!m_context->getActiveUniform(objectOrZero(program), index, info))
2257         return 0;
2258     if (!isGLES2Compliant())
2259         if (info.size > 1 && !info.name.endsWith("[0]"))
2260             info.name.append("[0]");
2261     return WebGLActiveInfo::create(info.name, info.type, info.size);
2262 }
2263
2264 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader> >& shaderObjects, ExceptionCode& ec)
2265 {
2266     UNUSED_PARAM(ec);
2267     shaderObjects.clear();
2268     if (isContextLost() || !validateWebGLObject("getAttachedShaders", program))
2269         return false;
2270
2271     const GC3Denum shaderType[] = {
2272         GraphicsContext3D::VERTEX_SHADER,
2273         GraphicsContext3D::FRAGMENT_SHADER
2274     };
2275     for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
2276         WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2277         if (shader)
2278             shaderObjects.append(shader);
2279     }
2280     return true;
2281 }
2282
2283 GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
2284 {
2285     if (isContextLost() || !validateWebGLObject("getAttribLocation", program))
2286         return -1;
2287     if (!validateLocationLength("getAttribLocation", name))
2288         return -1;
2289     if (!validateString("getAttribLocation", name))
2290         return -1;
2291     if (isPrefixReserved(name))
2292         return -1;
2293     if (!program->getLinkStatus()) {
2294         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getAttribLocation", "program not linked");
2295         return 0;
2296     }
2297     return m_context->getAttribLocation(objectOrZero(program), name);
2298 }
2299
2300 WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2301 {
2302     UNUSED_PARAM(ec);
2303     if (isContextLost())
2304         return WebGLGetInfo();
2305     if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
2306         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid target");
2307         return WebGLGetInfo();
2308     }
2309
2310     if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
2311         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2312         return WebGLGetInfo();
2313     }
2314
2315     WebGLStateRestorer(this, false);
2316     GC3Dint value = 0;
2317     m_context->getBufferParameteriv(target, pname, &value);
2318     if (pname == GraphicsContext3D::BUFFER_SIZE)
2319         return WebGLGetInfo(value);
2320     return WebGLGetInfo(static_cast<unsigned int>(value));
2321 }
2322
2323 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
2324 {
2325     if (isContextLost())
2326         return 0;
2327     // We always need to return a new WebGLContextAttributes object to
2328     // prevent the user from mutating any cached version.
2329
2330     // Also, we need to enforce requested values of "false" for depth
2331     // and stencil, regardless of the properties of the underlying
2332     // GraphicsContext3D or DrawingBuffer.
2333     RefPtr<WebGLContextAttributes> attributes = WebGLContextAttributes::create(m_context->getContextAttributes());
2334     if (!m_attributes.depth)
2335         attributes->setDepth(false);
2336     if (!m_attributes.stencil)
2337         attributes->setStencil(false);
2338     if (m_drawingBuffer) {
2339         // The DrawingBuffer obtains its parameters from GraphicsContext3D::getContextAttributes(),
2340         // but it makes its own determination of whether multisampling is supported.
2341         attributes->setAntialias(m_drawingBuffer->multisample());
2342     }
2343     return attributes.release();
2344 }
2345
2346 GC3Denum WebGLRenderingContext::getError()
2347 {
2348     return m_context->getError();
2349 }
2350
2351 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
2352 {
2353     if (isContextLost())
2354         return 0;
2355
2356     if (equalIgnoringCase(name, "WEBKIT_EXT_texture_filter_anisotropic")
2357         && m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic")) {
2358         if (!m_extTextureFilterAnisotropic) {
2359             m_context->getExtensions()->ensureEnabled("GL_EXT_texture_filter_anisotropic");
2360             m_extTextureFilterAnisotropic = EXTTextureFilterAnisotropic::create(this);
2361         }
2362         return m_extTextureFilterAnisotropic.get();
2363     }
2364     if (equalIgnoringCase(name, "OES_standard_derivatives")
2365         && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
2366         if (!m_oesStandardDerivatives) {
2367             m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
2368             m_oesStandardDerivatives = OESStandardDerivatives::create(this);
2369         }
2370         return m_oesStandardDerivatives.get();
2371     }
2372     if (equalIgnoringCase(name, "OES_texture_float")
2373         && m_context->getExtensions()->supports("GL_OES_texture_float")) {
2374         if (!m_oesTextureFloat) {
2375             m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
2376             m_oesTextureFloat = OESTextureFloat::create(this);
2377         }
2378         return m_oesTextureFloat.get();
2379     }
2380     if (equalIgnoringCase(name, "OES_texture_half_float")
2381         && m_context->getExtensions()->supports("GL_OES_texture_half_float")) {
2382         if (!m_oesTextureHalfFloat) {
2383             m_context->getExtensions()->ensureEnabled("GL_OES_texture_half_float");
2384             m_oesTextureHalfFloat = OESTextureHalfFloat::create(this);
2385         }
2386         return m_oesTextureHalfFloat.get();
2387     }
2388     if (equalIgnoringCase(name, "OES_vertex_array_object")
2389         && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
2390         if (!m_oesVertexArrayObject) {
2391             m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
2392             m_oesVertexArrayObject = OESVertexArrayObject::create(this);
2393         }
2394         return m_oesVertexArrayObject.get();
2395     }
2396     if (equalIgnoringCase(name, "OES_element_index_uint")
2397         && m_context->getExtensions()->supports("GL_OES_element_index_uint")) {
2398         if (!m_oesElementIndexUint) {
2399             m_context->getExtensions()->ensureEnabled("GL_OES_element_index_uint");
2400             m_oesElementIndexUint = OESElementIndexUint::create(this);
2401         }
2402         return m_oesElementIndexUint.get();
2403     }
2404     if (equalIgnoringCase(name, "WEBGL_lose_context")) {
2405         if (!m_webglLoseContext)
2406             m_webglLoseContext = WebGLLoseContext::create(this);
2407         return m_webglLoseContext.get();
2408     }
2409     if ((equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_atc"))
2410         && WebGLCompressedTextureATC::supported(this)) {
2411         if (!m_webglCompressedTextureATC)
2412             m_webglCompressedTextureATC = WebGLCompressedTextureATC::create(this);
2413         return m_webglCompressedTextureATC.get();
2414     }
2415     if ((equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_pvrtc"))
2416         && WebGLCompressedTexturePVRTC::supported(this)) {
2417         if (!m_webglCompressedTexturePVRTC)
2418             m_webglCompressedTexturePVRTC = WebGLCompressedTexturePVRTC::create(this);
2419     }
2420     if (equalIgnoringCase(name, "WEBGL_compressed_texture_s3tc")
2421         && WebGLCompressedTextureS3TC::supported(this)) {
2422         if (!m_webglCompressedTextureS3TC)
2423             m_webglCompressedTextureS3TC = WebGLCompressedTextureS3TC::create(this);
2424         return m_webglCompressedTextureS3TC.get();
2425     }
2426     if (equalIgnoringCase(name, "WEBGL_depth_texture")
2427         && WebGLDepthTexture::supported(graphicsContext3D())) {
2428         if (!m_webglDepthTexture) {
2429             m_context->getExtensions()->ensureEnabled("GL_CHROMIUM_depth_texture");
2430             m_webglDepthTexture = WebGLDepthTexture::create(this);
2431         }
2432         return m_webglDepthTexture.get();
2433     }
2434     if (equalIgnoringCase(name, "EXT_draw_buffers") && supportsDrawBuffers()) {
2435         if (!m_extDrawBuffers) {
2436             m_context->getExtensions()->ensureEnabled("GL_EXT_draw_buffers");
2437             m_extDrawBuffers = EXTDrawBuffers::create(this);
2438         }
2439         return m_extDrawBuffers.get();
2440     }
2441     if (allowPrivilegedExtensions()) {
2442         if (equalIgnoringCase(name, "WEBGL_debug_renderer_info")) {
2443             if (!m_webglDebugRendererInfo)
2444                 m_webglDebugRendererInfo = WebGLDebugRendererInfo::create(this);
2445             return m_webglDebugRendererInfo.get();
2446         }
2447         if (equalIgnoringCase(name, "WEBGL_debug_shaders")
2448             && m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source")) {
2449             if (!m_webglDebugShaders)
2450                 m_webglDebugShaders = WebGLDebugShaders::create(this);
2451             return m_webglDebugShaders.get();
2452         }
2453     }
2454
2455     return 0;
2456 }
2457
2458 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
2459 {
2460     UNUSED_PARAM(ec);
2461     if (isContextLost() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
2462         return WebGLGetInfo();
2463
2464     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2465         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
2466         return WebGLGetInfo();
2467     }
2468
2469     WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
2470     if (!object) {
2471         if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2472             return WebGLGetInfo(GraphicsContext3D::NONE);
2473         // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
2474         // specifies INVALID_OPERATION.
2475         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
2476         return WebGLGetInfo();
2477     }
2478
2479     ASSERT(object->isTexture() || object->isRenderbuffer());
2480     if (object->isTexture()) {
2481         switch (pname) {
2482         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2483             return WebGLGetInfo(GraphicsContext3D::TEXTURE);
2484         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2485             return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
2486         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2487         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2488             {
2489                 WebGLStateRestorer(this, false);
2490                 GC3Dint value = 0;
2491                 m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2492                 return WebGLGetInfo(value);
2493             }
2494         default:
2495             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
2496             return WebGLGetInfo();
2497         }
2498     } else {
2499         switch (pname) {
2500         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2501             return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
2502         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2503             return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
2504         default:
2505             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
2506             return WebGLGetInfo();
2507         }
2508     }
2509 }
2510
2511 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec)
2512 {
2513     UNUSED_PARAM(ec);
2514     if (isContextLost())
2515         return WebGLGetInfo();
2516     const int intZero = 0;
2517     WebGLStateRestorer(this, false);
2518     switch (pname) {
2519     case GraphicsContext3D::ACTIVE_TEXTURE:
2520         return getUnsignedIntParameter(pname);
2521     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
2522         return getWebGLFloatArrayParameter(pname);
2523     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
2524         return getWebGLFloatArrayParameter(pname);
2525     case GraphicsContext3D::ALPHA_BITS:
2526         return getIntParameter(pname);
2527     case GraphicsContext3D::ARRAY_BUFFER_BINDING:
2528         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2529     case GraphicsContext3D::BLEND:
2530         return getBooleanParameter(pname);
2531     case GraphicsContext3D::BLEND_COLOR:
2532         return getWebGLFloatArrayParameter(pname);
2533     case GraphicsContext3D::BLEND_DST_ALPHA:
2534         return getUnsignedIntParameter(pname);
2535     case GraphicsContext3D::BLEND_DST_RGB:
2536         return getUnsignedIntParameter(pname);
2537     case GraphicsContext3D::BLEND_EQUATION_ALPHA:
2538         return getUnsignedIntParameter(pname);
2539     case GraphicsContext3D::BLEND_EQUATION_RGB:
2540         return getUnsignedIntParameter(pname);
2541     case GraphicsContext3D::BLEND_SRC_ALPHA:
2542         return getUnsignedIntParameter(pname);
2543     case GraphicsContext3D::BLEND_SRC_RGB:
2544         return getUnsignedIntParameter(pname);
2545     case GraphicsContext3D::BLUE_BITS:
2546         return getIntParameter(pname);
2547     case GraphicsContext3D::COLOR_CLEAR_VALUE:
2548         return getWebGLFloatArrayParameter(pname);
2549     case GraphicsContext3D::COLOR_WRITEMASK:
2550         return getBooleanArrayParameter(pname);
2551     case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
2552         return WebGLGetInfo(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()));
2553     case GraphicsContext3D::CULL_FACE:
2554         return getBooleanParameter(pname);
2555     case GraphicsContext3D::CULL_FACE_MODE:
2556         return getUnsignedIntParameter(pname);
2557     case GraphicsContext3D::CURRENT_PROGRAM:
2558         return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2559     case GraphicsContext3D::DEPTH_BITS:
2560         if (!m_framebufferBinding && !m_attributes.depth)
2561             return WebGLGetInfo(intZero);
2562         return getIntParameter(pname);
2563     case GraphicsContext3D::DEPTH_CLEAR_VALUE:
2564         return getFloatParameter(pname);
2565     case GraphicsContext3D::DEPTH_FUNC:
2566         return getUnsignedIntParameter(pname);
2567     case GraphicsContext3D::DEPTH_RANGE:
2568         return getWebGLFloatArrayParameter(pname);
2569     case GraphicsContext3D::DEPTH_TEST:
2570         return getBooleanParameter(pname);
2571     case GraphicsContext3D::DEPTH_WRITEMASK:
2572         return getBooleanParameter(pname);
2573     case GraphicsContext3D::DITHER:
2574         return getBooleanParameter(pname);
2575     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
2576         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
2577     case GraphicsContext3D::FRAMEBUFFER_BINDING:
2578         return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2579     case GraphicsContext3D::FRONT_FACE:
2580         return getUnsignedIntParameter(pname);
2581     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2582         return getUnsignedIntParameter(pname);
2583     case GraphicsContext3D::GREEN_BITS:
2584         return getIntParameter(pname);
2585     case GraphicsContext3D::LINE_WIDTH:
2586         return getFloatParameter(pname);
2587     case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2588         return getIntParameter(pname);
2589     case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
2590         return getIntParameter(pname);
2591     case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
2592         return getIntParameter(pname);
2593     case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
2594         return getIntParameter(pname);
2595     case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
2596         return getIntParameter(pname);
2597     case GraphicsContext3D::MAX_TEXTURE_SIZE:
2598         return getIntParameter(pname);
2599     case GraphicsContext3D::MAX_VARYING_VECTORS:
2600         return getIntParameter(pname);
2601     case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
2602         return getIntParameter(pname);
2603     case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2604         return getIntParameter(pname);
2605     case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
2606         return getIntParameter(pname);
2607     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
2608         return getWebGLIntArrayParameter(pname);
2609     case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
2610         // FIXME: should we always return 0 for this?
2611         return getIntParameter(pname);
2612     case GraphicsContext3D::PACK_ALIGNMENT:
2613         return getIntParameter(pname);
2614     case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
2615         return getFloatParameter(pname);
2616     case GraphicsContext3D::POLYGON_OFFSET_FILL:
2617         return getBooleanParameter(pname);
2618     case GraphicsContext3D::POLYGON_OFFSET_UNITS:
2619         return getFloatParameter(pname);
2620     case GraphicsContext3D::RED_BITS:
2621         return getIntParameter(pname);
2622     case GraphicsContext3D::RENDERBUFFER_BINDING:
2623         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2624     case GraphicsContext3D::RENDERER:
2625         return WebGLGetInfo(String("WebKit WebGL"));
2626     case GraphicsContext3D::SAMPLE_BUFFERS:
2627         return getIntParameter(pname);
2628     case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
2629         return getBooleanParameter(pname);
2630     case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
2631         return getFloatParameter(pname);
2632     case GraphicsContext3D::SAMPLES:
2633         return getIntParameter(pname);
2634     case GraphicsContext3D::SCISSOR_BOX:
2635         return getWebGLIntArrayParameter(pname);
2636     case GraphicsContext3D::SCISSOR_TEST:
2637         return getBooleanParameter(pname);
2638     case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
2639         return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
2640     case GraphicsContext3D::STENCIL_BACK_FAIL:
2641         return getUnsignedIntParameter(pname);
2642     case GraphicsContext3D::STENCIL_BACK_FUNC:
2643         return getUnsignedIntParameter(pname);
2644     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
2645         return getUnsignedIntParameter(pname);
2646     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
2647         return getUnsignedIntParameter(pname);
2648     case GraphicsContext3D::STENCIL_BACK_REF:
2649         return getIntParameter(pname);
2650     case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
2651         return getUnsignedIntParameter(pname);
2652     case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
2653         return getUnsignedIntParameter(pname);
2654     case GraphicsContext3D::STENCIL_BITS:
2655         if (!m_framebufferBinding && !m_attributes.stencil)
2656             return WebGLGetInfo(intZero);
2657         return getIntParameter(pname);
2658     case GraphicsContext3D::STENCIL_CLEAR_VALUE:
2659         return getIntParameter(pname);
2660     case GraphicsContext3D::STENCIL_FAIL:
2661         return getUnsignedIntParameter(pname);
2662     case GraphicsContext3D::STENCIL_FUNC:
2663         return getUnsignedIntParameter(pname);
2664     case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
2665         return getUnsignedIntParameter(pname);
2666     case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
2667         return getUnsignedIntParameter(pname);
2668     case GraphicsContext3D::STENCIL_REF:
2669         return getIntParameter(pname);
2670     case GraphicsContext3D::STENCIL_TEST:
2671         return getBooleanParameter(pname);
2672     case GraphicsContext3D::STENCIL_VALUE_MASK:
2673         return getUnsignedIntParameter(pname);
2674     case GraphicsContext3D::STENCIL_WRITEMASK:
2675         return getUnsignedIntParameter(pname);
2676     case GraphicsContext3D::SUBPIXEL_BITS:
2677         return getIntParameter(pname);
2678     case GraphicsContext3D::TEXTURE_BINDING_2D:
2679         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureBinding));
2680     case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
2681         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureBinding));
2682     case GraphicsContext3D::UNPACK_ALIGNMENT:
2683         return getIntParameter(pname);
2684     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2685         return WebGLGetInfo(m_unpackFlipY);
2686     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2687         return WebGLGetInfo(m_unpackPremultiplyAlpha);
2688     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2689         return WebGLGetInfo(m_unpackColorspaceConversion);
2690     case GraphicsContext3D::VENDOR:
2691         return WebGLGetInfo(String("WebKit"));
2692     case GraphicsContext3D::VERSION:
2693         return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
2694     case GraphicsContext3D::VIEWPORT:
2695         return getWebGLIntArrayParameter(pname);
2696     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2697         if (m_oesStandardDerivatives)
2698             return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2699         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
2700         return WebGLGetInfo();
2701     case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
2702         if (m_webglDebugRendererInfo)
2703             return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
2704         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2705         return WebGLGetInfo();
2706     case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
2707         if (m_webglDebugRendererInfo)
2708             return WebGLGetInfo(m_context->getString(GraphicsContext3D::VENDOR));
2709         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2710         return WebGLGetInfo();
2711     case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2712         if (m_oesVertexArrayObject) {
2713             if (!m_boundVertexArrayObject->isDefaultObject())
2714                 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2715             return WebGLGetInfo();
2716         }
2717         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
2718         return WebGLGetInfo();
2719     case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2720         if (m_extTextureFilterAnisotropic)
2721             return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT);
2722         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2723         return WebGLGetInfo();
2724     case Extensions3D::MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN
2725         if (m_extDrawBuffers)
2726             return WebGLGetInfo(getMaxColorAttachments());
2727         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_draw_buffers not enabled");
2728         return WebGLGetInfo();
2729     case Extensions3D::MAX_DRAW_BUFFERS_EXT:
2730         if (m_extDrawBuffers)
2731             return WebGLGetInfo(getMaxDrawBuffers());
2732         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_draw_buffers not enabled");
2733         return WebGLGetInfo();
2734     default:
2735         if (m_extDrawBuffers
2736             && pname >= Extensions3D::DRAW_BUFFER0_EXT
2737             && pname < static_cast<GC3Denum>(Extensions3D::DRAW_BUFFER0_EXT + getMaxDrawBuffers())) {
2738             GC3Dint value = GraphicsContext3D::NONE;
2739             if (m_framebufferBinding)
2740                 value = m_framebufferBinding->getDrawBuffer(pname);
2741             else // emulated backbuffer
2742                 value = m_backDrawBuffer;
2743             return WebGLGetInfo(value);
2744         }
2745         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name");
2746         return WebGLGetInfo();
2747     }
2748 }
2749
2750 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2751 {
2752     UNUSED_PARAM(ec);
2753     if (isContextLost() || !validateWebGLObject("getProgramParameter", program))
2754         return WebGLGetInfo();
2755
2756     WebGLStateRestorer(this, false);
2757     GC3Dint value = 0;
2758     switch (pname) {
2759     case GraphicsContext3D::DELETE_STATUS:
2760         return WebGLGetInfo(program->isDeleted());
2761     case GraphicsContext3D::VALIDATE_STATUS:
2762         m_context->getProgramiv(objectOrZero(program), pname, &value);
2763         return WebGLGetInfo(static_cast<bool>(value));
2764     case GraphicsContext3D::LINK_STATUS:
2765         return WebGLGetInfo(program->getLinkStatus());
2766     case GraphicsContext3D::ATTACHED_SHADERS:
2767     case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2768     case GraphicsContext3D::ACTIVE_UNIFORMS:
2769         m_context->getProgramiv(objectOrZero(program), pname, &value);
2770         return WebGLGetInfo(value);
2771     default:
2772         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2773         return WebGLGetInfo();
2774     }
2775 }
2776
2777 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2778 {
2779     UNUSED_PARAM(ec);
2780     if (isContextLost())
2781         return String();
2782     if (!validateWebGLObject("getProgramInfoLog", program))
2783         return "";
2784     WebGLStateRestorer(this, false);
2785     return ensureNotNull(m_context->getProgramInfoLog(objectOrZero(program)));
2786 }
2787
2788 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2789 {
2790     UNUSED_PARAM(ec);
2791     if (isContextLost())
2792         return WebGLGetInfo();
2793     if (target != GraphicsContext3D::RENDERBUFFER) {
2794         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2795         return WebGLGetInfo();
2796     }
2797     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2798         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2799         return WebGLGetInfo();
2800     }
2801
2802     if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2803         && !m_renderbufferBinding->isValid()) {
2804         ASSERT(!isDepthStencilSupported());
2805         int value = 0;
2806         switch (pname) {
2807         case GraphicsContext3D::RENDERBUFFER_WIDTH:
2808             value = m_renderbufferBinding->getWidth();
2809             break;
2810         case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2811             value = m_renderbufferBinding->getHeight();
2812             break;
2813         case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2814         case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2815         case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2816         case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2817             value = 0;
2818             break;
2819         case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2820             value = 24;
2821             break;
2822         case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2823             value = 8;
2824             break;
2825         case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2826             return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2827         default:
2828             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2829             return WebGLGetInfo();
2830         }
2831         return WebGLGetInfo(value);
2832     }
2833
2834     WebGLStateRestorer(this, false);
2835     GC3Dint value = 0;
2836     switch (pname) {
2837     case GraphicsContext3D::RENDERBUFFER_WIDTH:
2838     case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2839     case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2840     case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2841     case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2842     case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2843     case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2844     case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2845         m_context->getRenderbufferParameteriv(target, pname, &value);
2846         return WebGLGetInfo(value);
2847     case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2848         return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2849     default:
2850         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2851         return WebGLGetInfo();
2852     }
2853 }
2854
2855 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
2856 {
2857     UNUSED_PARAM(ec);
2858     if (isContextLost() || !validateWebGLObject("getShaderParameter", shader))
2859         return WebGLGetInfo();
2860     WebGLStateRestorer(this, false);
2861     GC3Dint value = 0;
2862     switch (pname) {
2863     case GraphicsContext3D::DELETE_STATUS:
2864         return WebGLGetInfo(shader->isDeleted());
2865     case GraphicsContext3D::COMPILE_STATUS:
2866         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2867         return WebGLGetInfo(static_cast<bool>(value));
2868     case GraphicsContext3D::SHADER_TYPE:
2869         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2870         return WebGLGetInfo(static_cast<unsigned int>(value));
2871     default:
2872         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderParameter", "invalid parameter name");
2873         return WebGLGetInfo();
2874     }
2875 }
2876
2877 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
2878 {
2879     UNUSED_PARAM(ec);
2880     if (isContextLost())
2881         return String();
2882     if (!validateWebGLObject("getShaderInfoLog", shader))
2883         return "";
2884     WebGLStateRestorer(this, false);
2885     return ensureNotNull(m_context->getShaderInfoLog(objectOrZero(shader)));
2886 }
2887
2888 PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContext::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode& ec)
2889 {
2890     UNUSED_PARAM(ec);
2891     if (isContextLost())
2892         return 0;
2893     switch (shaderType) {
2894     case GraphicsContext3D::VERTEX_SHADER:
2895     case GraphicsContext3D::FRAGMENT_SHADER:
2896         break;
2897     default:
2898         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
2899         return 0;
2900     }
2901     switch (precisionType) {
2902     case GraphicsContext3D::LOW_FLOAT:
2903     case GraphicsContext3D::MEDIUM_FLOAT:
2904     case GraphicsContext3D::HIGH_FLOAT:
2905     case GraphicsContext3D::LOW_INT:
2906     case GraphicsContext3D::MEDIUM_INT:
2907     case GraphicsContext3D::HIGH_INT:
2908         break;
2909     default:
2910         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
2911         return 0;
2912     }
2913
2914     GC3Dint range[2] = {0, 0};
2915     GC3Dint precision = 0;
2916     m_context->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
2917     return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
2918 }
2919
2920 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
2921 {
2922     UNUSED_PARAM(ec);
2923     if (isContextLost())
2924         return String();
2925     if (!validateWebGLObject("getShaderSource", shader))
2926         return "";
2927     return ensureNotNull(shader->getSource());
2928 }
2929
2930 Vector<String> WebGLRenderingContext::getSupportedExtensions()
2931 {
2932     Vector<String> result;
2933     if (m_context->getExtensions()->supports("GL_OES_texture_float"))
2934         result.append("OES_texture_float");
2935     if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
2936         result.append("OES_standard_derivatives");
2937     if (m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic"))
2938         result.append("WEBKIT_EXT_texture_filter_anisotropic");
2939     if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
2940         result.append("OES_vertex_array_object");
2941     if (m_context->getExtensions()->supports("GL_OES_element_index_uint"))
2942         result.append("OES_element_index_uint");
2943     result.append("WEBGL_lose_context");
2944     if (WebGLCompressedTextureATC::supported(this))
2945         result.append("WEBKIT_WEBGL_compressed_texture_atc");
2946     if (WebGLCompressedTexturePVRTC::supported(this))
2947         result.append("WEBKIT_WEBGL_compressed_texture_pvrtc");
2948     if (WebGLCompressedTextureS3TC::supported(this))
2949         result.append("WEBGL_compressed_texture_s3tc");
2950     if (WebGLDepthTexture::supported(graphicsContext3D()))
2951         result.append("WEBGL_depth_texture");
2952     if (supportsDrawBuffers())
2953         result.append("EXT_draw_buffers");
2954
2955     if (allowPrivilegedExtensions()) {
2956         if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
2957             result.append("WEBGL_debug_shaders");
2958         result.append("WEBGL_debug_renderer_info");
2959     }
2960
2961     return result;
2962 }
2963
2964 WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2965 {
2966     UNUSED_PARAM(ec);
2967     if (isContextLost())
2968         return WebGLGetInfo();
2969     WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
2970     if (!tex)
2971         return WebGLGetInfo();
2972     WebGLStateRestorer(this, false);
2973     GC3Dint value = 0;
2974     switch (pname) {
2975     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2976     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2977     case GraphicsContext3D::TEXTURE_WRAP_S:
2978     case GraphicsContext3D::TEXTURE_WRAP_T:
2979         m_context->getTexParameteriv(target, pname, &value);
2980         return WebGLGetInfo(static_cast<unsigned int>(value));
2981     case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2982         if (m_extTextureFilterAnisotropic) {
2983             m_context->getTexParameteriv(target, pname, &value);
2984             return WebGLGetInfo(static_cast<unsigned int>(value));
2985         }
2986         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2987         return WebGLGetInfo();
2988     default:
2989         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name");
2990         return WebGLGetInfo();
2991     }
2992 }
2993
2994 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2995 {
2996     UNUSED_PARAM(ec);
2997     if (isContextLost() || !validateWebGLObject("getUniform", program))
2998         return WebGLGetInfo();
2999     if (!uniformLocation || uniformLocation->program() != program) {
3000         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
3001         return WebGLGetInfo();
3002     }
3003     GC3Dint location = uniformLocation->location();
3004
3005     WebGLStateRestorer(this, false);
3006     // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
3007     GC3Dint activeUniforms = 0;
3008     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
3009     for (GC3Dint i = 0; i < activeUniforms; i++) {
3010         ActiveInfo info;
3011         if (!m_context->getActiveUniform(objectOrZero(program), i, info))
3012             return WebGLGetInfo();
3013         // Strip "[0]" from the name if it's an array.
3014         if (info.size > 1 && info.name.endsWith("[0]"))
3015             info.name = info.name.left(info.name.length() - 3);
3016         // If it's an array, we need to iterate through each element, appending "[index]" to the name.
3017         for (GC3Dint index = 0; index < info.size; ++index) {
3018             String name = info.name;
3019             if (info.size > 1 && index >= 1) {
3020                 name.append('[');
3021                 name.append(String::number(index));
3022                 name.append(']');
3023             }
3024             // Now need to look this up by name again to find its location
3025             GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name);
3026             if (loc == location) {
3027                 // Found it. Use the type in the ActiveInfo to determine the return type.
3028                 GC3Denum baseType;
3029                 unsigned int length;
3030                 switch (info.type) {
3031                 case GraphicsContext3D::BOOL:
3032                     baseType = GraphicsContext3D::BOOL;
3033                     length = 1;
3034                     break;
3035                 case GraphicsContext3D::BOOL_VEC2:
3036                     baseType = GraphicsContext3D::BOOL;
3037                     length = 2;
3038                     break;
3039                 case GraphicsContext3D::BOOL_VEC3:
3040                     baseType = GraphicsContext3D::BOOL;
3041                     length = 3;
3042                     break;
3043                 case GraphicsContext3D::BOOL_VEC4:
3044                     baseType = GraphicsContext3D::BOOL;
3045                     length = 4;
3046                     break;
3047                 case GraphicsContext3D::INT:
3048                     baseType = GraphicsContext3D::INT;
3049                     length = 1;
3050                     break;
3051                 case GraphicsContext3D::INT_VEC2:
3052                     baseType = GraphicsContext3D::INT;
3053                     length = 2;
3054                     break;
3055                 case GraphicsContext3D::INT_VEC3:
3056                     baseType = GraphicsContext3D::INT;
3057                     length = 3;
3058                     break;
3059                 case GraphicsContext3D::INT_VEC4:
3060                     baseType = GraphicsContext3D::INT;
3061                     length = 4;
3062                     break;
3063                 case GraphicsContext3D::FLOAT:
3064                     baseType = GraphicsContext3D::FLOAT;
3065                     length = 1;
3066                     break;
3067                 case GraphicsContext3D::FLOAT_VEC2:
3068                     baseType = GraphicsContext3D::FLOAT;
3069                     length = 2;
3070                     break;
3071                 case GraphicsContext3D::FLOAT_VEC3:
3072                     baseType = GraphicsContext3D::FLOAT;
3073                     length = 3;
3074                     break;
3075                 case GraphicsContext3D::FLOAT_VEC4:
3076                     baseType = GraphicsContext3D::FLOAT;
3077                     length = 4;
3078                     break;
3079                 case GraphicsContext3D::FLOAT_MAT2:
3080                     baseType = GraphicsContext3D::FLOAT;
3081                     length = 4;
3082                     break;
3083                 case GraphicsContext3D::FLOAT_MAT3:
3084                     baseType = GraphicsContext3D::FLOAT;
3085                     length = 9;
3086                     break;
3087                 case GraphicsContext3D::FLOAT_MAT4:
3088                     baseType = GraphicsContext3D::FLOAT;
3089                     length = 16;
3090                     break;
3091                 case GraphicsContext3D::SAMPLER_2D:
3092                 case GraphicsContext3D::SAMPLER_CUBE:
3093                     baseType = GraphicsContext3D::INT;
3094                     length = 1;
3095                     break;
3096                 default:
3097                     // Can't handle this type
3098                     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unhandled type");
3099                     return WebGLGetInfo();
3100                 }
3101                 switch (baseType) {
3102                 case GraphicsContext3D::FLOAT: {
3103                     GC3Dfloat value[16] = {0};
3104                     if (m_isRobustnessEXTSupported)
3105                         m_context->getExtensions()->getnUniformfvEXT(objectOrZero(program), location, 16 * sizeof(GC3Dfloat), value);
3106                     else
3107                         m_context->getUniformfv(objectOrZero(program), location, value);
3108                     if (length == 1)
3109                         return WebGLGetInfo(value[0]);
3110                     return WebGLGetInfo(Float32Array::create(value, length));
3111                 }
3112                 case GraphicsContext3D::INT: {
3113                     GC3Dint value[4] = {0};
3114                     if (m_isRobustnessEXTSupported)
3115                         m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
3116                     else
3117                         m_context->getUniformiv(objectOrZero(program), location, value);
3118                     if (length == 1)
3119                         return WebGLGetInfo(value[0]);
3120                     return WebGLGetInfo(Int32Array::create(value, length));
3121                 }
3122                 case GraphicsContext3D::BOOL: {
3123                     GC3Dint value[4] = {0};
3124                     if (m_isRobustnessEXTSupported)
3125                         m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
3126                     else
3127                         m_context->getUniformiv(objectOrZero(program), location, value);
3128                     if (length > 1) {
3129                         bool boolValue[16] = {0};
3130                         for (unsigned j = 0; j < length; j++)
3131                             boolValue[j] = static_cast<bool>(value[j]);
3132                         return WebGLGetInfo(boolValue, length);
3133                     }
3134                     return WebGLGetInfo(static_cast<bool>(value[0]));
3135                 }
3136                 default:
3137                     notImplemented();
3138                 }
3139             }
3140         }
3141     }
3142     // If we get here, something went wrong in our unfortunately complex logic above
3143     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unknown error");
3144     return WebGLGetInfo();
3145 }
3146
3147 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
3148 {
3149     UNUSED_PARAM(ec);
3150     if (isContextLost() || !validateWebGLObject("getUniformLocation", program))
3151         return 0;
3152     if (!validateLocationLength("getUniformLocation", name))
3153         return 0;
3154     if (!validateString("getUniformLocation", name))
3155         return 0;
3156     if (isPrefixReserved(name))
3157         return 0;
3158     if (!program->getLinkStatus()) {
3159         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniformLocation", "program not linked");
3160         return 0;
3161     }
3162     WebGLStateRestorer(this, false);
3163     GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
3164     if (uniformLocation == -1)
3165         return 0;
3166     return WebGLUniformLocation::create(program, uniformLocation);
3167 }
3168
3169 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
3170 {
3171     UNUSED_PARAM(ec);
3172     if (isContextLost())
3173         return WebGLGetInfo();
3174     WebGLStateRestorer(this, false);
3175     if (index >= m_maxVertexAttribs) {
3176         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
3177         return WebGLGetInfo();
3178     }
3179     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
3180     switch (pname) {
3181     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
3182         if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
3183             || !state.bufferBinding
3184             || !state.bufferBinding->object())
3185             return WebGLGetInfo();
3186         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
3187     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
3188         return WebGLGetInfo(state.enabled);
3189     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
3190         return WebGLGetInfo(state.normalized);
3191     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
3192         return WebGLGetInfo(state.size);
3193     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
3194         return WebGLGetInfo(state.originalStride);
3195     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
3196         return WebGLGetInfo(state.type);
3197     case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
3198         return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
3199     default:
3200         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
3201         return WebGLGetInfo();
3202     }
3203 }
3204
3205 long long WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
3206 {
3207     if (isContextLost())
3208         return 0;
3209     GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
3210     cleanupAfterGraphicsCall(false);
3211     return static_cast<long long>(result);
3212 }
3213
3214 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
3215 {
3216     if (isContextLost())
3217         return;
3218     bool isValid = false;
3219     switch (target) {
3220     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
3221         isValid = true;
3222         break;
3223     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
3224         if (m_oesStandardDerivatives)
3225             isValid = true;
3226         break;
3227     }
3228     if (!isValid) {
3229         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target");
3230         return;
3231     }
3232     m_context->hint(target, mode);
3233     cleanupAfterGraphicsCall(false);
3234 }
3235
3236 GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
3237 {
3238     if (!buffer || isContextLost())
3239         return 0;