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