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