dcb18188345baf94a056349763ab35e8d301f800
[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 "CanvasPixelArray.h"
34 #include "CheckedInt.h"
35 #include "Console.h"
36 #include "DOMWindow.h"
37 #include "ExceptionCode.h"
38 #include "Extensions3D.h"
39 #include "Frame.h"
40 #include "FrameView.h"
41 #include "HTMLCanvasElement.h"
42 #include "HTMLImageElement.h"
43 #include "HTMLVideoElement.h"
44 #include "ImageBuffer.h"
45 #include "ImageData.h"
46 #include "IntSize.h"
47 #include "NotImplemented.h"
48 #include "OESStandardDerivatives.h"
49 #include "OESTextureFloat.h"
50 #include "OESVertexArrayObject.h"
51 #include "Page.h"
52 #include "RenderBox.h"
53 #include "RenderLayer.h"
54 #include "Settings.h"
55 #include "WebGLActiveInfo.h"
56 #include "WebGLBuffer.h"
57 #include "WebGLCompressedTextures.h"
58 #include "WebGLContextAttributes.h"
59 #include "WebGLContextEvent.h"
60 #include "WebGLDebugRendererInfo.h"
61 #include "WebGLDebugShaders.h"
62 #include "WebGLFramebuffer.h"
63 #include "WebGLLoseContext.h"
64 #include "WebGLProgram.h"
65 #include "WebGLRenderbuffer.h"
66 #include "WebGLShader.h"
67 #include "WebGLTexture.h"
68 #include "WebGLUniformLocation.h"
69
70 #include <wtf/ByteArray.h>
71 #include <wtf/OwnArrayPtr.h>
72 #include <wtf/PassOwnArrayPtr.h>
73 #include <wtf/Uint16Array.h>
74 #include <wtf/text/StringBuilder.h>
75
76 #if PLATFORM(QT)
77 #undef emit
78 #endif
79
80 namespace WebCore {
81
82 const double secondsBetweenRestoreAttempts = 1.0;
83
84 namespace {
85
86     class ScopedDrawingBufferBinder {
87     public:
88         ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer* framebufferBinding)
89             : m_drawingBuffer(drawingBuffer)
90             , m_framebufferBinding(framebufferBinding)
91         {
92             // Commit DrawingBuffer if needed (e.g., for multisampling)
93             if (!m_framebufferBinding && m_drawingBuffer)
94                 m_drawingBuffer->commit();
95         }
96
97         ~ScopedDrawingBufferBinder()
98         {
99             // Restore DrawingBuffer if needed
100             if (!m_framebufferBinding && m_drawingBuffer)
101                 m_drawingBuffer->bind();
102         }
103
104     private:
105         DrawingBuffer* m_drawingBuffer;
106         WebGLFramebuffer* m_framebufferBinding;
107     };
108
109     Platform3DObject objectOrZero(WebGLObject* object)
110     {
111         return object ? object->object() : 0;
112     }
113
114     void clip1D(GC3Dint start, GC3Dsizei range, GC3Dsizei sourceRange, GC3Dint* clippedStart, GC3Dsizei* clippedRange)
115     {
116         ASSERT(clippedStart && clippedRange);
117         if (start < 0) {
118             range += start;
119             start = 0;
120         }
121         GC3Dint end = start + range;
122         if (end > sourceRange)
123             range -= end - sourceRange;
124         *clippedStart = start;
125         *clippedRange = range;
126     }
127
128     // Returns false if no clipping is necessary, i.e., x, y, width, height stay the same.
129     bool clip2D(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height,
130                 GC3Dsizei sourceWidth, GC3Dsizei sourceHeight,
131                 GC3Dint* clippedX, GC3Dint* clippedY, GC3Dsizei* clippedWidth, GC3Dsizei*clippedHeight)
132     {
133         ASSERT(clippedX && clippedY && clippedWidth && clippedHeight);
134         clip1D(x, width, sourceWidth, clippedX, clippedWidth);
135         clip1D(y, height, sourceHeight, clippedY, clippedHeight);
136         return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height);
137     }
138
139     GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
140     {
141         if (value < min)
142             value = min;
143         if (value > max)
144             value = max;
145         return value;
146     }
147
148     // Return true if a character belongs to the ASCII subset as defined in
149     // GLSL ES 1.0 spec section 3.1.
150     bool validateCharacter(unsigned char c)
151     {
152         // Printing characters are valid except " $ ` @ \ ' DEL.
153         if (c >= 32 && c <= 126
154             && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
155             return true;
156         // Horizontal tab, line feed, vertical tab, form feed, carriage return
157         // are also valid.
158         if (c >= 9 && c <= 13)
159             return true;
160         return false;
161     }
162
163     // Strips comments from shader text. This allows non-ASCII characters
164     // to be used in comments without potentially breaking OpenGL
165     // implementations not expecting characters outside the GLSL ES set.
166     class StripComments {
167     public:
168         StripComments(const String& str)
169             : m_parseState(BeginningOfLine)
170             , m_sourceString(str)
171             , m_length(str.length())
172             , m_position(0)
173         {
174             parse();
175         }
176
177         String result()
178         {
179             return m_builder.toString();
180         }
181
182     private:
183         bool hasMoreCharacters()
184         {
185             return (m_position < m_length);
186         }
187
188         void parse()
189         {
190             while (hasMoreCharacters()) {
191                 process(current());
192                 // process() might advance the position.
193                 if (hasMoreCharacters())
194                     advance();
195             }
196         }
197
198         void process(UChar);
199
200         bool peek(UChar& character)
201         {
202             if (m_position + 1 >= m_length)
203                 return false;
204             character = m_sourceString[m_position + 1];
205             return true;
206         }
207
208         UChar current()
209         {
210             ASSERT(m_position < m_length);
211             return m_sourceString[m_position];
212         }
213
214         void advance()
215         {
216             ++m_position;
217         }
218
219         bool isNewline(UChar character)
220         {
221             // Don't attempt to canonicalize newline related characters.
222             return (character == '\n' || character == '\r');
223         }
224
225         void emit(UChar character)
226         {
227             m_builder.append(character);
228         }
229
230         enum ParseState {
231             // Have not seen an ASCII non-whitespace character yet on
232             // this line. Possible that we might see a preprocessor
233             // directive.
234             BeginningOfLine,
235
236             // Have seen at least one ASCII non-whitespace character
237             // on this line.
238             MiddleOfLine,
239
240             // Handling a preprocessor directive. Passes through all
241             // characters up to the end of the line. Disables comment
242             // processing.
243             InPreprocessorDirective,
244
245             // Handling a single-line comment. The comment text is
246             // replaced with a single space.
247             InSingleLineComment,
248
249             // Handling a multi-line comment. Newlines are passed
250             // through to preserve line numbers.
251             InMultiLineComment
252         };
253
254         ParseState m_parseState;
255         String m_sourceString;
256         unsigned m_length;
257         unsigned m_position;
258         StringBuilder m_builder;
259     };
260
261     void StripComments::process(UChar c)
262     {
263         if (isNewline(c)) {
264             // No matter what state we are in, pass through newlines
265             // so we preserve line numbers.
266             emit(c);
267
268             if (m_parseState != InMultiLineComment)
269                 m_parseState = BeginningOfLine;
270
271             return;
272         }
273
274         UChar temp = 0;
275         switch (m_parseState) {
276         case BeginningOfLine:
277             if (WTF::isASCIISpace(c)) {
278                 emit(c);
279                 break;
280             }
281
282             if (c == '#') {
283                 m_parseState = InPreprocessorDirective;
284                 emit(c);
285                 break;
286             }
287
288             // Transition to normal state and re-handle character.
289             m_parseState = MiddleOfLine;
290             process(c);
291             break;
292
293         case MiddleOfLine:
294             if (c == '/' && peek(temp)) {
295                 if (temp == '/') {
296                     m_parseState = InSingleLineComment;
297                     emit(' ');
298                     advance();
299                     break;
300                 }
301
302                 if (temp == '*') {
303                     m_parseState = InMultiLineComment;
304                     // Emit the comment start in case the user has
305                     // an unclosed comment and we want to later
306                     // signal an error.
307                     emit('/');
308                     emit('*');
309                     advance();
310                     break;
311                 }
312             }
313
314             emit(c);
315             break;
316
317         case InPreprocessorDirective:
318             // No matter what the character is, just pass it
319             // through. Do not parse comments in this state. This
320             // might not be the right thing to do long term, but it
321             // should handle the #error preprocessor directive.
322             emit(c);
323             break;
324
325         case InSingleLineComment:
326             // The newline code at the top of this function takes care
327             // of resetting our state when we get out of the
328             // single-line comment. Swallow all other characters.
329             break;
330
331         case InMultiLineComment:
332             if (c == '*' && peek(temp) && temp == '/') {
333                 emit('*');
334                 emit('/');
335                 m_parseState = MiddleOfLine;
336                 advance();
337                 break;
338             }
339
340             // Swallow all other characters. Unclear whether we may
341             // want or need to just emit a space per character to try
342             // to preserve column numbers for debugging purposes.
343             break;
344         }
345     }
346 } // namespace anonymous
347
348 class WebGLStateRestorer {
349 public:
350     WebGLStateRestorer(WebGLRenderingContext* context,
351                        bool changed)
352         : m_context(context)
353         , m_changed(changed)
354     {
355     }
356
357     ~WebGLStateRestorer()
358     {
359         m_context->cleanupAfterGraphicsCall(m_changed);
360     }
361
362 private:
363     WebGLRenderingContext* m_context;
364     bool m_changed;
365 };
366
367 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
368 public:
369     explicit WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_context(cb) { }
370     virtual void onContextLost() { m_context->forceLostContext(WebGLRenderingContext::RealLostContext); }
371     virtual ~WebGLRenderingContextLostCallback() {}
372 private:
373     WebGLRenderingContext* m_context;
374 };
375
376 PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs)
377 {
378     HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow();
379     GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
380
381     if (attributes.antialias) {
382         Page* p = canvas->document()->page();
383         if (p && !p->settings()->openGLMultisamplingEnabled())
384             attributes.antialias = false;
385     }
386
387     attributes.noExtensions = true;
388 #if PLATFORM(CHROMIUM)
389     attributes.shareResources = true;
390 #else
391     attributes.shareResources = false;
392 #endif
393
394
395     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
396
397     if (!context) {
398         canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
399         return nullptr;
400     }
401
402     return adoptPtr(new WebGLRenderingContext(canvas, context, attributes));
403 }
404
405 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
406                                              GraphicsContext3D::Attributes attributes)
407     : CanvasRenderingContext(passedCanvas)
408     , m_context(context)
409     , m_drawingBuffer(0)
410     , m_dispatchContextLostEventTimer(this, &WebGLRenderingContext::dispatchContextLostEvent)
411     , m_restoreAllowed(false)
412     , m_restoreTimer(this, &WebGLRenderingContext::maybeRestoreContext)
413     , m_videoCache(4)
414     , m_contextLost(false)
415     , m_contextLostMode(SyntheticLostContext)
416     , m_attributes(attributes)
417 {
418     ASSERT(m_context);
419
420 #if PLATFORM(CHROMIUM)
421     // Create the DrawingBuffer and initialize the platform layer.
422     m_drawingBuffer = DrawingBuffer::create(m_context.get(), IntSize(canvas()->width(), canvas()->height()), !m_attributes.preserveDrawingBuffer);
423 #endif
424
425     if (m_drawingBuffer)
426         m_drawingBuffer->bind();
427
428     setupFlags();
429     initializeNewContext();
430 }
431
432 void WebGLRenderingContext::initializeNewContext()
433 {
434     ASSERT(!m_contextLost);
435     m_needsUpdate = true;
436     m_markedCanvasDirty = false;
437     m_activeTextureUnit = 0;
438     m_packAlignment = 4;
439     m_unpackAlignment = 4;
440     m_unpackFlipY = false;
441     m_unpackPremultiplyAlpha = false;
442     m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
443     m_boundArrayBuffer = 0;
444     m_currentProgram = 0;
445     m_framebufferBinding = 0;
446     m_renderbufferBinding = 0;
447     m_depthMask = true;
448     m_stencilMask = 0xFFFFFFFF;
449     m_stencilMaskBack = 0xFFFFFFFF;
450     m_stencilFuncRef = 0;
451     m_stencilFuncRefBack = 0;
452     m_stencilFuncMask = 0xFFFFFFFF;
453     m_stencilFuncMaskBack = 0xFFFFFFFF;
454     m_layerCleared = false;
455     
456     m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
457     m_scissorEnabled = false;
458     m_clearDepth = 1;
459     m_clearStencil = 0;
460     m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
461
462     GC3Dint numCombinedTextureImageUnits = 0;
463     m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
464     m_textureUnits.clear();
465     m_textureUnits.resize(numCombinedTextureImageUnits);
466
467     GC3Dint numVertexAttribs = 0;
468     m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
469     m_maxVertexAttribs = numVertexAttribs;
470     
471     m_maxTextureSize = 0;
472     m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
473     m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
474     m_maxCubeMapTextureSize = 0;
475     m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
476     m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
477     m_maxRenderbufferSize = 0;
478     m_context->getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
479     m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
480     m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
481
482     m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
483     addObject(m_defaultVertexArrayObject.get());
484     m_boundVertexArrayObject = m_defaultVertexArrayObject;
485     
486     m_vertexAttribValue.resize(m_maxVertexAttribs);
487
488     if (!isGLES2NPOTStrict())
489         createFallbackBlackTextures1x1();
490     if (!isGLES2Compliant())
491         initVertexAttrib0();
492
493     if (m_drawingBuffer)
494         m_drawingBuffer->reset(IntSize(canvas()->width(), canvas()->height()));
495
496     m_context->reshape(canvas()->width(), canvas()->height());
497     m_context->viewport(0, 0, canvas()->width(), canvas()->height());
498
499     m_context->setContextLostCallback(adoptPtr(new WebGLRenderingContextLostCallback(this)));
500 }
501
502 void WebGLRenderingContext::setupFlags()
503 {
504     ASSERT(m_context);
505
506     m_isGLES2Compliant = m_context->isGLES2Compliant();
507     m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs");
508     m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe");
509     if (m_isGLES2Compliant) {
510         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
511         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
512     } else {
513         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two");
514         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil");
515     }
516 }
517
518 bool WebGLRenderingContext::allowPrivilegedExtensions() const
519 {
520     Page* p = canvas()->document()->page();
521     if (p && p->settings())
522         return p->settings()->privilegedWebGLExtensionsEnabled();
523     return false;
524 }
525
526 WebGLRenderingContext::~WebGLRenderingContext()
527 {
528     detachAndRemoveAllObjects();
529     m_context->setContextLostCallback(nullptr);
530 }
531
532 void WebGLRenderingContext::markContextChanged()
533 {
534     if (m_framebufferBinding)
535         return;
536
537     m_context->markContextChanged();
538
539     m_layerCleared = false;
540 #if USE(ACCELERATED_COMPOSITING)
541     RenderBox* renderBox = canvas()->renderBox();
542     if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing()) {
543         m_markedCanvasDirty = true;
544         renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
545     } else {
546 #endif
547         if (!m_markedCanvasDirty) {
548             m_markedCanvasDirty = true;
549             canvas()->didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
550         }
551 #if USE(ACCELERATED_COMPOSITING)
552     }
553 #endif
554 }
555
556 bool WebGLRenderingContext::clearIfComposited(GC3Dbitfield mask)
557 {
558     if (isContextLost()) 
559         return false;
560
561     if (!m_context->layerComposited() || m_layerCleared
562         || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
563         return false;
564
565     RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
566
567     // Determine if it's possible to combine the clear the user asked for and this clear.
568     bool combinedClear = mask && !m_scissorEnabled;
569
570     if (m_framebufferBinding) {
571         if (m_drawingBuffer)
572             m_drawingBuffer->bind();
573         else
574             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
575     }
576     m_context->disable(GraphicsContext3D::SCISSOR_TEST);
577     if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
578         m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
579                               m_colorMask[1] ? m_clearColor[1] : 0,
580                               m_colorMask[2] ? m_clearColor[2] : 0,
581                               m_colorMask[3] ? m_clearColor[3] : 0);
582     else
583         m_context->clearColor(0, 0, 0, 0);
584     m_context->colorMask(true, true, true, true);
585     GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
586     if (contextAttributes->depth()) {
587         if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
588             m_context->clearDepth(1.0f);
589         clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
590         m_context->depthMask(true);
591     }
592     if (contextAttributes->stencil()) {
593         if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
594             m_context->clearStencil(m_clearStencil & m_stencilMask);
595         else
596             m_context->clearStencil(0);
597         clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
598         m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
599     }
600     m_context->clear(clearMask);
601
602     // Restore the state that the context set.
603     if (m_scissorEnabled)
604         m_context->enable(GraphicsContext3D::SCISSOR_TEST);
605     m_context->clearColor(m_clearColor[0], m_clearColor[1],
606                           m_clearColor[2], m_clearColor[3]);
607     m_context->colorMask(m_colorMask[0], m_colorMask[1],
608                          m_colorMask[2], m_colorMask[3]);
609     m_context->clearDepth(m_clearDepth);
610     m_context->clearStencil(m_clearStencil);
611     m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
612     m_context->depthMask(m_depthMask);
613     if (m_framebufferBinding)
614         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
615     m_layerCleared = true;
616
617     return combinedClear;
618 }
619
620 void WebGLRenderingContext::markLayerComposited()
621 {
622     m_context->markLayerComposited();
623 }
624
625 void WebGLRenderingContext::paintRenderingResultsToCanvas()
626 {
627     // Until the canvas is written to by the application, the clear that
628     // happened after it was composited should be ignored by the compositor.
629     if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
630         m_context->paintCompositedResultsToCanvas(this);
631
632 #if USE(ACCELERATED_COMPOSITING) && PLATFORM(CHROMIUM)
633         if (m_drawingBuffer)
634             m_drawingBuffer->paintCompositedResultsToCanvas(this);
635 #endif
636
637         canvas()->makePresentationCopy();
638     } else
639         canvas()->clearPresentationCopy();
640     clearIfComposited();
641
642     if (!m_markedCanvasDirty && !m_layerCleared)
643         return;
644
645     canvas()->clearCopiedImage();
646     m_markedCanvasDirty = false;
647
648     if (m_drawingBuffer)
649         m_drawingBuffer->commit();
650     m_context->paintRenderingResultsToCanvas(this, m_drawingBuffer.get());
651
652     if (m_drawingBuffer) {
653         if (m_framebufferBinding)
654             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
655         else
656             m_drawingBuffer->bind();
657     }
658 }
659
660 PassRefPtr<ImageData> WebGLRenderingContext::paintRenderingResultsToImageData()
661 {
662     clearIfComposited();
663     if (m_drawingBuffer)
664         m_drawingBuffer->commit();
665     RefPtr<ImageData> imageData = m_context->paintRenderingResultsToImageData(m_drawingBuffer.get());
666
667     if (m_drawingBuffer) {
668         if (m_framebufferBinding)
669             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
670         else
671             m_drawingBuffer->bind();
672     }
673
674     return imageData;
675 }
676
677 bool WebGLRenderingContext::paintsIntoCanvasBuffer() const
678 {
679     return m_context->paintsIntoCanvasBuffer();
680 }
681
682 void WebGLRenderingContext::reshape(int width, int height)
683 {
684     // This is an approximation because at WebGLRenderingContext level we don't
685     // know if the underlying FBO uses textures or renderbuffers.
686     GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
687     // Limit drawing buffer size to 4k to avoid memory exhaustion.
688     const int sizeUpperLimit = 4096;
689     maxSize = std::min(maxSize, sizeUpperLimit);
690     GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
691     GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
692     width = clamp(width, 1, maxWidth);
693     height = clamp(height, 1, maxHeight);
694
695     if (m_needsUpdate) {
696 #if USE(ACCELERATED_COMPOSITING)
697         RenderBox* renderBox = canvas()->renderBox();
698         if (renderBox && renderBox->hasLayer())
699             renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
700 #endif
701         m_needsUpdate = false;
702     }
703
704     // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
705     // clear (and this matches what reshape will do).
706     if (m_drawingBuffer)
707         m_drawingBuffer->reset(IntSize(width, height));
708     else
709         m_context->reshape(width, height);
710 }
711
712 int WebGLRenderingContext::drawingBufferWidth() const
713 {
714     if (m_drawingBuffer)
715         return m_drawingBuffer->size().width();
716
717     return m_context->getInternalFramebufferSize().width();
718 }
719
720 int WebGLRenderingContext::drawingBufferHeight() const
721 {
722     if (m_drawingBuffer)
723         return m_drawingBuffer->size().height();
724
725     return m_context->getInternalFramebufferSize().height();
726 }
727
728 unsigned int WebGLRenderingContext::sizeInBytes(GC3Denum type)
729 {
730     switch (type) {
731     case GraphicsContext3D::BYTE:
732         return sizeof(GC3Dbyte);
733     case GraphicsContext3D::UNSIGNED_BYTE:
734         return sizeof(GC3Dubyte);
735     case GraphicsContext3D::SHORT:
736         return sizeof(GC3Dshort);
737     case GraphicsContext3D::UNSIGNED_SHORT:
738         return sizeof(GC3Dushort);
739     case GraphicsContext3D::INT:
740         return sizeof(GC3Dint);
741     case GraphicsContext3D::UNSIGNED_INT:
742         return sizeof(GC3Duint);
743     case GraphicsContext3D::FLOAT:
744         return sizeof(GC3Dfloat);
745     }
746     ASSERT_NOT_REACHED();
747     return 0;
748 }
749
750 void WebGLRenderingContext::activeTexture(GC3Denum texture, ExceptionCode& ec)
751 {
752     UNUSED_PARAM(ec);
753     if (isContextLost())
754         return;
755     if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
756         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
757         return;
758     }
759     m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
760     m_context->activeTexture(texture);
761
762     if (m_drawingBuffer)
763         m_drawingBuffer->setActiveTextureUnit(texture);
764
765     cleanupAfterGraphicsCall(false);
766 }
767
768 void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
769 {
770     UNUSED_PARAM(ec);
771     if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
772         return;
773     if (!program->attachShader(shader)) {
774         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
775         return;
776     }
777     m_context->attachShader(objectOrZero(program), objectOrZero(shader));
778     shader->onAttached();
779     cleanupAfterGraphicsCall(false);
780 }
781
782 void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
783 {
784     UNUSED_PARAM(ec);
785     if (isContextLost() || !validateWebGLObject(program))
786         return;
787     if (!validateLocationLength(name))
788         return;
789     if (!validateString(name))
790         return;
791     m_context->bindAttribLocation(objectOrZero(program), index, name);
792     cleanupAfterGraphicsCall(false);
793 }
794
795 bool WebGLRenderingContext::checkObjectToBeBound(WebGLObject* object, bool& deleted)
796 {
797     deleted = false;
798     if (isContextLost())
799         return false;
800     if (object) {
801         if (object->context() != this) {
802             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
803             return false;
804         }
805         deleted = !object->object();
806     }
807     return true;
808 }
809
810 void WebGLRenderingContext::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec)
811 {
812     UNUSED_PARAM(ec);
813     bool deleted;
814     if (!checkObjectToBeBound(buffer, deleted))
815         return;
816     if (deleted)
817         buffer = 0;
818     if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
819         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
820         return;
821     }
822     if (target == GraphicsContext3D::ARRAY_BUFFER)
823         m_boundArrayBuffer = buffer;
824     else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
825         m_boundVertexArrayObject->setElementArrayBuffer(buffer);
826     else {
827         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
828         return;
829     }
830
831     m_context->bindBuffer(target, objectOrZero(buffer));
832     if (buffer)
833         buffer->setTarget(target);
834     cleanupAfterGraphicsCall(false);
835 }
836
837 void WebGLRenderingContext::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec)
838 {
839     UNUSED_PARAM(ec);
840     bool deleted;
841     if (!checkObjectToBeBound(buffer, deleted))
842         return;
843     if (deleted)
844         buffer = 0;
845     if (target != GraphicsContext3D::FRAMEBUFFER) {
846         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
847         return;
848     }
849     m_framebufferBinding = buffer;
850     if (!m_framebufferBinding && m_drawingBuffer) {
851         // Instead of binding fb 0, bind the drawing buffer.
852         m_drawingBuffer->bind();
853     } else
854         m_context->bindFramebuffer(target, objectOrZero(buffer));
855     if (buffer)
856         buffer->setHasEverBeenBound();
857     cleanupAfterGraphicsCall(false);
858 }
859
860 void WebGLRenderingContext::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
861 {
862     UNUSED_PARAM(ec);
863     bool deleted;
864     if (!checkObjectToBeBound(renderBuffer, deleted))
865         return;
866     if (deleted)
867         renderBuffer = 0;
868     if (target != GraphicsContext3D::RENDERBUFFER) {
869         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
870         return;
871     }
872     m_renderbufferBinding = renderBuffer;
873     m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
874     if (renderBuffer)
875         renderBuffer->setHasEverBeenBound();
876     cleanupAfterGraphicsCall(false);
877 }
878
879 void WebGLRenderingContext::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
880 {
881     UNUSED_PARAM(ec);
882     bool deleted;
883     if (!checkObjectToBeBound(texture, deleted))
884         return;
885     if (deleted)
886         texture = 0;
887     if (texture && texture->getTarget() && texture->getTarget() != target) {
888         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
889         return;
890     }
891     GC3Dint maxLevel = 0;
892     if (target == GraphicsContext3D::TEXTURE_2D) {
893         m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
894         maxLevel = m_maxTextureLevel;
895
896         if (m_drawingBuffer && !m_activeTextureUnit)
897             m_drawingBuffer->setTexture2DBinding(objectOrZero(texture));
898
899     } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
900         m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
901         maxLevel = m_maxCubeMapTextureLevel;
902     } else {
903         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
904         return;
905     }
906     m_context->bindTexture(target, objectOrZero(texture));
907     if (texture)
908         texture->setTarget(target, maxLevel);
909
910     // Note: previously we used to automatically set the TEXTURE_WRAP_R
911     // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
912     // ES 2.0 doesn't expose this flag (a bug in the specification) and
913     // otherwise the application has no control over the seams in this
914     // dimension. However, it appears that supporting this properly on all
915     // platforms is fairly involved (will require a HashMap from texture ID
916     // in all ports), and we have not had any complaints, so the logic has
917     // been removed.
918
919     cleanupAfterGraphicsCall(false);
920 }
921
922 void WebGLRenderingContext::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
923 {
924     if (isContextLost())
925         return;
926     m_context->blendColor(red, green, blue, alpha);
927     cleanupAfterGraphicsCall(false);
928 }
929
930 void WebGLRenderingContext::blendEquation(GC3Denum mode)
931 {
932     if (isContextLost() || !validateBlendEquation(mode))
933         return;
934     m_context->blendEquation(mode);
935     cleanupAfterGraphicsCall(false);
936 }
937
938 void WebGLRenderingContext::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
939 {
940     if (isContextLost() || !validateBlendEquation(modeRGB) || !validateBlendEquation(modeAlpha))
941         return;
942     m_context->blendEquationSeparate(modeRGB, modeAlpha);
943     cleanupAfterGraphicsCall(false);
944 }
945
946
947 void WebGLRenderingContext::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
948 {
949     if (isContextLost() || !validateBlendFuncFactors(sfactor, dfactor))
950         return;
951     m_context->blendFunc(sfactor, dfactor);
952     cleanupAfterGraphicsCall(false);
953 }
954
955 void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
956 {
957     if (isContextLost() || !validateBlendFuncFactors(srcRGB, dstRGB))
958         return;
959     m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
960     cleanupAfterGraphicsCall(false);
961 }
962
963 void WebGLRenderingContext::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage, ExceptionCode& ec)
964 {
965     UNUSED_PARAM(ec);
966     if (isContextLost())
967         return;
968     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
969     if (!buffer)
970         return;
971     if (size < 0) {
972         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
973         return;
974     }
975     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
976         if (!buffer->associateBufferData(size)) {
977             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
978             return;
979         }
980     }
981
982     m_context->bufferData(target, size, usage);
983     cleanupAfterGraphicsCall(false);
984 }
985
986 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
987 {
988     UNUSED_PARAM(ec);
989     if (isContextLost())
990         return;
991     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
992     if (!buffer)
993         return;
994     if (!data) {
995         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
996         return;
997     }
998     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
999         if (!buffer->associateBufferData(data)) {
1000             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1001             return;
1002         }
1003     }
1004
1005     m_context->bufferData(target, data->byteLength(), data->data(), usage);
1006     cleanupAfterGraphicsCall(false);
1007 }
1008
1009 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
1010 {
1011     UNUSED_PARAM(ec);
1012     if (isContextLost())
1013         return;
1014     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
1015     if (!buffer)
1016         return;
1017     if (!data) {
1018         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1019         return;
1020     }
1021     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1022         if (!buffer->associateBufferData(data)) {
1023             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1024             return;
1025         }
1026     }
1027
1028     m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
1029     cleanupAfterGraphicsCall(false);
1030 }
1031
1032 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBuffer* data, ExceptionCode& ec)
1033 {
1034     UNUSED_PARAM(ec);
1035     if (isContextLost())
1036         return;
1037     WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
1038     if (!buffer)
1039         return;
1040     if (offset < 0) {
1041         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1042         return;
1043     }
1044     if (!data)
1045         return;
1046     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1047         if (!buffer->associateBufferSubData(offset, data)) {
1048             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1049             return;
1050         }
1051     }
1052
1053     m_context->bufferSubData(target, offset, data->byteLength(), data->data());
1054     cleanupAfterGraphicsCall(false);
1055 }
1056
1057 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBufferView* data, ExceptionCode& ec)
1058 {
1059     UNUSED_PARAM(ec);
1060     if (isContextLost())
1061         return;
1062     WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
1063     if (!buffer)
1064         return;
1065     if (offset < 0) {
1066         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1067         return;
1068     }
1069     if (!data)
1070         return;
1071     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1072         if (!buffer->associateBufferSubData(offset, data)) {
1073             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1074             return;
1075         }
1076     }
1077
1078     m_context->bufferSubData(target, offset, data->byteLength(), data->baseAddress());
1079     cleanupAfterGraphicsCall(false);
1080 }
1081
1082 GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target)
1083 {
1084     if (isContextLost())
1085         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
1086     if (target != GraphicsContext3D::FRAMEBUFFER) {
1087         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1088         return 0;
1089     }
1090     if (!m_framebufferBinding || !m_framebufferBinding->object())
1091         return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
1092     GC3Denum result = m_framebufferBinding->checkStatus();
1093     if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
1094         return result;
1095     result = m_context->checkFramebufferStatus(target);
1096     cleanupAfterGraphicsCall(false);
1097     return result;
1098 }
1099
1100 void WebGLRenderingContext::clear(GC3Dbitfield mask)
1101 {
1102     if (isContextLost())
1103         return;
1104     if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
1105         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1106         return;
1107     }
1108     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1109         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1110         return;
1111     }
1112     if (!clearIfComposited(mask))
1113         m_context->clear(mask);
1114     cleanupAfterGraphicsCall(true);
1115 }
1116
1117 void WebGLRenderingContext::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
1118 {
1119     if (isContextLost())
1120         return;
1121     if (isnan(r))
1122         r = 0;
1123     if (isnan(g))
1124         g = 0;
1125     if (isnan(b))
1126         b = 0;
1127     if (isnan(a))
1128         a = 1;
1129     m_clearColor[0] = r;
1130     m_clearColor[1] = g;
1131     m_clearColor[2] = b;
1132     m_clearColor[3] = a;
1133     m_context->clearColor(r, g, b, a);
1134     cleanupAfterGraphicsCall(false);
1135 }
1136
1137 void WebGLRenderingContext::clearDepth(GC3Dfloat depth)
1138 {
1139     if (isContextLost())
1140         return;
1141     m_clearDepth = depth;
1142     m_context->clearDepth(depth);
1143     cleanupAfterGraphicsCall(false);
1144 }
1145
1146 void WebGLRenderingContext::clearStencil(GC3Dint s)
1147 {
1148     if (isContextLost())
1149         return;
1150     m_clearStencil = s;
1151     m_context->clearStencil(s);
1152     cleanupAfterGraphicsCall(false);
1153 }
1154
1155 void WebGLRenderingContext::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1156 {
1157     if (isContextLost())
1158         return;
1159     m_colorMask[0] = red;
1160     m_colorMask[1] = green;
1161     m_colorMask[2] = blue;
1162     m_colorMask[3] = alpha;
1163     m_context->colorMask(red, green, blue, alpha);
1164     cleanupAfterGraphicsCall(false);
1165 }
1166
1167 void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec)
1168 {
1169     UNUSED_PARAM(ec);
1170     if (isContextLost() || !validateWebGLObject(shader))
1171         return;
1172     m_context->compileShader(objectOrZero(shader));
1173     cleanupAfterGraphicsCall(false);
1174 }
1175
1176 void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
1177 {
1178     if (isContextLost())
1179         return;
1180     if (!validateTexFuncParameters(target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
1181         return;
1182     WebGLTexture* tex = validateTextureBinding(target, true);
1183     if (!tex)
1184         return;
1185     if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1186         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1187         return;
1188     }
1189     if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1190         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1191         return;
1192     }
1193     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1194         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1195         return;
1196     }
1197     clearIfComposited();
1198     if (isResourceSafe()) {
1199         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1200         m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1201     } else {
1202         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1203         GC3Dint clippedX, clippedY;
1204         GC3Dsizei clippedWidth, clippedHeight;
1205         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1206             m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
1207                                               internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment);
1208             if (clippedWidth > 0 && clippedHeight > 0) {
1209                 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
1210                                              clippedX, clippedY, clippedWidth, clippedHeight);
1211             }
1212         } else
1213             m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1214     }
1215     // FIXME: if the framebuffer is not complete, none of the below should be executed.
1216     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1217     cleanupAfterGraphicsCall(false);
1218 }
1219
1220 void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1221 {
1222     if (isContextLost())
1223         return;
1224     if (!validateTexFuncLevel(target, level))
1225         return;
1226     WebGLTexture* tex = validateTextureBinding(target, true);
1227     if (!tex)
1228         return;
1229     if (!validateSize(xoffset, yoffset) || !validateSize(width, height))
1230         return;
1231     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1232         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1233         return;
1234     }
1235     if (!isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(target, level), getBoundFramebufferColorFormat())) {
1236         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1237         return;
1238     }
1239     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1240         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1241         return;
1242     }
1243     clearIfComposited();
1244     if (isResourceSafe()) {
1245         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1246         m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1247     } else {
1248         GC3Dint clippedX, clippedY;
1249         GC3Dsizei clippedWidth, clippedHeight;
1250         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1251             GC3Denum format = tex->getInternalFormat(target, level);
1252             GC3Denum type = tex->getType(target, level);
1253             OwnArrayPtr<unsigned char> zero;
1254             if (width && height) {
1255                 unsigned int size;
1256                 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1257                 if (error != GraphicsContext3D::NO_ERROR) {
1258                     m_context->synthesizeGLError(error);
1259                     return;
1260                 }
1261                 zero = adoptArrayPtr(new unsigned char[size]);
1262                 if (!zero) {
1263                     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1264                     return;
1265                 }
1266                 memset(zero.get(), 0, size);
1267             }
1268             m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1269             if (clippedWidth > 0 && clippedHeight > 0) {
1270                 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1271                 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1272                                              clippedX, clippedY, clippedWidth, clippedHeight);
1273             }
1274         } else {
1275             ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1276             m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1277         }
1278     }
1279     cleanupAfterGraphicsCall(false);
1280 }
1281
1282 PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer()
1283 {
1284     if (isContextLost())
1285         return 0;
1286     RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1287     addObject(o.get());
1288     return o;
1289 }
1290
1291 PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer()
1292 {
1293     if (isContextLost())
1294         return 0;
1295     RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1296     addObject(o.get());
1297     return o;
1298 }
1299
1300 PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture()
1301 {
1302     if (isContextLost())
1303         return 0;
1304     RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1305     addObject(o.get());
1306     return o;
1307 }
1308
1309 PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram()
1310 {
1311     if (isContextLost())
1312         return 0;
1313     RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1314     addObject(o.get());
1315     return o;
1316 }
1317
1318 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer()
1319 {
1320     if (isContextLost())
1321         return 0;
1322     RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1323     addObject(o.get());
1324     return o;
1325 }
1326
1327 PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(GC3Denum type, ExceptionCode& ec)
1328 {
1329     UNUSED_PARAM(ec);
1330     if (isContextLost())
1331         return 0;
1332     if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1333         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1334         return 0;
1335     }
1336
1337     RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1338     addObject(o.get());
1339     return o;
1340 }
1341
1342 void WebGLRenderingContext::cullFace(GC3Denum mode)
1343 {
1344     if (isContextLost())
1345         return;
1346     m_context->cullFace(mode);
1347     cleanupAfterGraphicsCall(false);
1348 }
1349
1350 bool WebGLRenderingContext::deleteObject(WebGLObject* object)
1351 {
1352     if (isContextLost() || !object)
1353         return false;
1354     if (object->context() != this) {
1355         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1356         return false;
1357     }
1358     if (object->object())
1359         object->deleteObject();
1360     return true;
1361 }
1362
1363 void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
1364 {
1365     if (!deleteObject(buffer))
1366         return;
1367     if (m_boundArrayBuffer == buffer)
1368         m_boundArrayBuffer = 0;
1369     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1370     if (elementArrayBuffer == buffer)
1371         m_boundVertexArrayObject->setElementArrayBuffer(0);
1372     if (!isGLES2Compliant()) {
1373         WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
1374         if (buffer == state.bufferBinding) {
1375             state.bufferBinding = m_vertexAttrib0Buffer;
1376             state.bytesPerElement = 0;
1377             state.size = 4;
1378             state.type = GraphicsContext3D::FLOAT;
1379             state.normalized = false;
1380             state.stride = 16;
1381             state.originalStride = 0;
1382             state.offset = 0;
1383         }
1384     }
1385 }
1386
1387 void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1388 {
1389     if (!deleteObject(framebuffer))
1390         return;
1391     if (framebuffer == m_framebufferBinding) {
1392         m_framebufferBinding = 0;
1393         // Have to call bindFramebuffer here to bind back to internal fbo.
1394         if (m_drawingBuffer)
1395             m_drawingBuffer->bind();
1396         else
1397             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1398     }
1399 }
1400
1401 void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
1402 {
1403     deleteObject(program);
1404     // We don't reset m_currentProgram to 0 here because the deletion of the
1405     // current program is delayed.
1406 }
1407
1408 void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1409 {
1410     if (!deleteObject(renderbuffer))
1411         return;
1412     if (renderbuffer == m_renderbufferBinding)
1413         m_renderbufferBinding = 0;
1414     if (m_framebufferBinding)
1415         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1416 }
1417
1418 void WebGLRenderingContext::deleteShader(WebGLShader* shader)
1419 {
1420     deleteObject(shader);
1421 }
1422
1423 void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
1424 {
1425     if (!deleteObject(texture))
1426         return;
1427     for (size_t i = 0; i < m_textureUnits.size(); ++i) {
1428         if (texture == m_textureUnits[i].m_texture2DBinding)
1429             m_textureUnits[i].m_texture2DBinding = 0;
1430         if (texture == m_textureUnits[i].m_textureCubeMapBinding)
1431             m_textureUnits[i].m_textureCubeMapBinding = 0;
1432     }
1433     if (m_framebufferBinding)
1434         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1435 }
1436
1437 void WebGLRenderingContext::depthFunc(GC3Denum func)
1438 {
1439     if (isContextLost())
1440         return;
1441     m_context->depthFunc(func);
1442     cleanupAfterGraphicsCall(false);
1443 }
1444
1445 void WebGLRenderingContext::depthMask(GC3Dboolean flag)
1446 {
1447     if (isContextLost())
1448         return;
1449     m_depthMask = flag;
1450     m_context->depthMask(flag);
1451     cleanupAfterGraphicsCall(false);
1452 }
1453
1454 void WebGLRenderingContext::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1455 {
1456     if (isContextLost())
1457         return;
1458     if (zNear > zFar) {
1459         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1460         return;
1461     }
1462     m_context->depthRange(zNear, zFar);
1463     cleanupAfterGraphicsCall(false);
1464 }
1465
1466 void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
1467 {
1468     UNUSED_PARAM(ec);
1469     if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
1470         return;
1471     if (!program->detachShader(shader)) {
1472         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1473         return;
1474     }
1475     m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1476     shader->onDetached();
1477     cleanupAfterGraphicsCall(false);
1478 }
1479
1480 void WebGLRenderingContext::disable(GC3Denum cap)
1481 {
1482     if (isContextLost() || !validateCapability(cap))
1483         return;
1484     if (cap == GraphicsContext3D::SCISSOR_TEST) {
1485         m_scissorEnabled = false;
1486         if (m_drawingBuffer)
1487             m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1488     }
1489     m_context->disable(cap);
1490     cleanupAfterGraphicsCall(false);
1491 }
1492
1493 void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1494 {
1495     UNUSED_PARAM(ec);
1496     if (isContextLost())
1497         return;
1498     if (index >= m_maxVertexAttribs) {
1499         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1500         return;
1501     }
1502
1503     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1504     state.enabled = false;
1505
1506     if (index > 0 || isGLES2Compliant()) {
1507         m_context->disableVertexAttribArray(index);
1508         cleanupAfterGraphicsCall(false);
1509     }
1510 }
1511
1512 bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1513 {
1514     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1515     
1516     if (!elementArrayBuffer)
1517         return false;
1518
1519     if (offset < 0)
1520         return false;
1521
1522     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1523         // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1524         if (offset % 2)
1525             return false;
1526
1527         // Make uoffset an element offset.
1528         offset /= 2;
1529
1530         GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1531         if (offset > n || count > n - offset)
1532             return false;
1533     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1534         GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1535         if (offset > n || count > n - offset)
1536             return false;
1537     }
1538     return true;
1539 }
1540
1541 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& numElementsRequired)
1542 {
1543     // Performs conservative validation by caching a maximum index of
1544     // the given type per element array buffer. If all of the bound
1545     // array buffers have enough elements to satisfy that maximum
1546     // index, skips the expensive per-draw-call iteration in
1547     // validateIndexArrayPrecise.
1548     
1549     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1550
1551     if (!elementArrayBuffer)
1552         return false;
1553
1554     GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
1555     // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1556     if (!numElements)
1557         return false;
1558     const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
1559     ASSERT(buffer);
1560
1561     int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
1562     if (maxIndex < 0) {
1563         // Compute the maximum index in the entire buffer for the given type of index.
1564         switch (type) {
1565         case GraphicsContext3D::UNSIGNED_BYTE: {
1566             const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
1567             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1568                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1569             break;
1570         }
1571         case GraphicsContext3D::UNSIGNED_SHORT: {
1572             numElements /= sizeof(GC3Dushort);
1573             const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
1574             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1575                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1576             break;
1577         }
1578         default:
1579             return false;
1580         }
1581         elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1582     }
1583
1584     if (maxIndex >= 0) {
1585         // The number of required elements is one more than the maximum
1586         // index that will be accessed.
1587         numElementsRequired = maxIndex + 1;
1588         return true;
1589     }
1590
1591     return false;
1592 }
1593
1594 bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, int& numElementsRequired)
1595 {
1596     ASSERT(count >= 0 && offset >= 0);
1597     int lastIndex = -1;
1598     
1599     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1600
1601     if (!elementArrayBuffer)
1602         return false;
1603
1604     if (!count) {
1605         numElementsRequired = 0;
1606         return true;
1607     }
1608
1609     if (!elementArrayBuffer->elementArrayBuffer())
1610         return false;
1611
1612     unsigned long uoffset = offset;
1613     unsigned long n = count;
1614
1615     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1616         // Make uoffset an element offset.
1617         uoffset /= sizeof(GC3Dushort);
1618         const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1619         while (n-- > 0) {
1620             if (*p > lastIndex)
1621                 lastIndex = *p;
1622             ++p;
1623         }
1624     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1625         const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1626         while (n-- > 0) {
1627             if (*p > lastIndex)
1628                 lastIndex = *p;
1629             ++p;
1630         }
1631     }
1632
1633     // Then set the last index in the index array and make sure it is valid.
1634     numElementsRequired = lastIndex + 1;
1635     return numElementsRequired > 0;
1636 }
1637
1638 bool WebGLRenderingContext::validateRenderingState(int numElementsRequired)
1639 {
1640     if (!m_currentProgram)
1641         return false;
1642
1643     // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1644     for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1645         const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
1646         if (state.enabled
1647             && (!state.bufferBinding || !state.bufferBinding->object()))
1648             return false;
1649     }
1650
1651     if (numElementsRequired <= 0)
1652         return true;
1653
1654     // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
1655     int smallestNumElements = INT_MAX;
1656     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1657     for (int i = 0; i < numActiveAttribLocations; ++i) {
1658         int loc = m_currentProgram->getActiveAttribLocation(i);
1659         if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1660             const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1661             if (state.enabled) {
1662                 // Avoid off-by-one errors in numElements computation.
1663                 // For the last element, we will only touch the data for the
1664                 // element and nothing beyond it.
1665                 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1666                 int numElements = 0;
1667                 ASSERT(state.stride > 0);
1668                 if (bytesRemaining >= state.bytesPerElement)
1669                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1670                 if (numElements < smallestNumElements)
1671                     smallestNumElements = numElements;
1672             }
1673         }
1674     }
1675
1676     if (smallestNumElements == INT_MAX)
1677         smallestNumElements = 0;
1678
1679     return numElementsRequired <= smallestNumElements;
1680 }
1681
1682 bool WebGLRenderingContext::validateWebGLObject(WebGLObject* object)
1683 {
1684     if (!object || !object->object()) {
1685         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1686         return false;
1687     }
1688     if (object->context() != this) {
1689         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1690         return false;
1691     }
1692     return true;
1693 }
1694
1695 void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
1696 {
1697     UNUSED_PARAM(ec);
1698
1699     if (isContextLost() || !validateDrawMode(mode))
1700         return;
1701
1702     if (!validateStencilSettings())
1703         return;
1704
1705     if (first < 0 || count < 0) {
1706         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1707         return;
1708     }
1709
1710     if (!count)
1711         return;
1712
1713     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1714         // Ensure we have a valid rendering state
1715         CheckedInt<GC3Dint> checkedFirst(first);
1716         CheckedInt<GC3Dint> checkedCount(count);
1717         CheckedInt<GC3Dint> checkedSum = checkedFirst + checkedCount;
1718         if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) {
1719             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1720             return;
1721         }
1722     } else {
1723         if (!validateRenderingState(0)) {
1724             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1725             return;
1726         }
1727     }
1728
1729     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1730         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1731         return;
1732     }
1733
1734     clearIfComposited();
1735
1736     bool vertexAttrib0Simulated = false;
1737     if (!isGLES2Compliant())
1738         vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1739     if (!isGLES2NPOTStrict())
1740         handleNPOTTextures(true);
1741     m_context->drawArrays(mode, first, count);
1742     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1743         restoreStatesAfterVertexAttrib0Simulation();
1744     if (!isGLES2NPOTStrict())
1745         handleNPOTTextures(false);
1746     cleanupAfterGraphicsCall(true);
1747 }
1748
1749 void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, ExceptionCode& ec)
1750 {
1751     UNUSED_PARAM(ec);
1752
1753     if (isContextLost() || !validateDrawMode(mode))
1754         return;
1755
1756     if (!validateStencilSettings())
1757         return;
1758
1759     switch (type) {
1760     case GraphicsContext3D::UNSIGNED_BYTE:
1761     case GraphicsContext3D::UNSIGNED_SHORT:
1762         break;
1763     default:
1764         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1765         return;
1766     }
1767
1768     if (count < 0 || offset < 0) {
1769         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1770         return;
1771     }
1772
1773     if (!count)
1774         return;
1775
1776     if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1777         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1778         return;
1779     }
1780
1781     int numElements = 0;
1782     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1783         // Ensure we have a valid rendering state
1784         if (!validateElementArraySize(count, type, offset)) {
1785             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1786             return;
1787         }
1788         if (!count)
1789             return;
1790         if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) {
1791             if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
1792                 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1793                 return;
1794             }
1795         }
1796     } else {
1797         if (!validateRenderingState(0)) {
1798             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1799             return;
1800         }
1801     }
1802
1803     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1804         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1805         return;
1806     }
1807     clearIfComposited();
1808
1809     bool vertexAttrib0Simulated = false;
1810     if (!isGLES2Compliant()) {
1811         if (!numElements)
1812             validateIndexArrayPrecise(count, type, offset, numElements);
1813         vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1814     }
1815     if (!isGLES2NPOTStrict())
1816         handleNPOTTextures(true);
1817     m_context->drawElements(mode, count, type, offset);
1818     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1819         restoreStatesAfterVertexAttrib0Simulation();
1820     if (!isGLES2NPOTStrict())
1821         handleNPOTTextures(false);
1822     cleanupAfterGraphicsCall(true);
1823 }
1824
1825 void WebGLRenderingContext::enable(GC3Denum cap)
1826 {
1827     if (isContextLost() || !validateCapability(cap))
1828         return;
1829     if (cap == GraphicsContext3D::SCISSOR_TEST) {
1830         m_scissorEnabled = true;
1831         if (m_drawingBuffer)
1832             m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1833     }
1834     m_context->enable(cap);
1835     cleanupAfterGraphicsCall(false);
1836 }
1837
1838 void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1839 {
1840     UNUSED_PARAM(ec);
1841     if (isContextLost())
1842         return;
1843     if (index >= m_maxVertexAttribs) {
1844         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1845         return;
1846     }
1847
1848     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1849     state.enabled = true;
1850
1851     m_context->enableVertexAttribArray(index);
1852     cleanupAfterGraphicsCall(false);
1853 }
1854
1855 void WebGLRenderingContext::finish()
1856 {
1857     if (isContextLost())
1858         return;
1859     m_context->finish();
1860     cleanupAfterGraphicsCall(false);
1861 }
1862
1863 void WebGLRenderingContext::flush()
1864 {
1865     if (isContextLost())
1866         return;
1867     m_context->flush();
1868     cleanupAfterGraphicsCall(false);
1869 }
1870
1871 void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
1872 {
1873     UNUSED_PARAM(ec);
1874     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1875         return;
1876     if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
1877         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1878         return;
1879     }
1880     if (buffer && buffer->context() != this) {
1881         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1882         return;
1883     }
1884     // Don't allow the default framebuffer to be mutated; all current
1885     // implementations use an FBO internally in place of the default
1886     // FBO.
1887     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1888         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1889         return;
1890     }
1891     Platform3DObject bufferObject = objectOrZero(buffer);
1892     bool reattachDepth = false;
1893     bool reattachStencil = false;
1894     bool reattachDepthStencilDepth = false;
1895     bool reattachDepthStencilStencil = false;
1896     switch (attachment) {
1897     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
1898         m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1899         m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
1900         if (!bufferObject) {
1901             reattachDepth = true;
1902             reattachStencil = true;
1903         }
1904         break;
1905     case GraphicsContext3D::DEPTH_ATTACHMENT:
1906         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1907         if (!bufferObject)
1908             reattachDepthStencilDepth = true;
1909         break;
1910     case GraphicsContext3D::STENCIL_ATTACHMENT:
1911         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1912         if (!bufferObject)
1913             reattachDepthStencilStencil = true;
1914         break;
1915     default:
1916         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1917     }
1918     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
1919     if (reattachDepth) {
1920         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT));
1921         if (object)
1922             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1923     }
1924     if (reattachStencil) {
1925         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT));
1926         if (object)
1927             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1928     }
1929     if (reattachDepthStencilDepth) {
1930         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1931         if (object)
1932             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1933     }
1934     if (reattachDepthStencilStencil) {
1935         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1936         if (object)
1937             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1938     }
1939     cleanupAfterGraphicsCall(false);
1940 }
1941
1942 void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
1943 {
1944     UNUSED_PARAM(ec);
1945     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1946         return;
1947     if (level) {
1948         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1949         return;
1950     }
1951     if (texture && texture->context() != this) {
1952         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1953         return;
1954     }
1955     // Don't allow the default framebuffer to be mutated; all current
1956     // implementations use an FBO internally in place of the default
1957     // FBO.
1958     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1959         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1960         return;
1961     }
1962     m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level);
1963     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
1964     cleanupAfterGraphicsCall(false);
1965 }
1966
1967 void WebGLRenderingContext::frontFace(GC3Denum mode)
1968 {
1969     if (isContextLost())
1970         return;
1971     m_context->frontFace(mode);
1972     cleanupAfterGraphicsCall(false);
1973 }
1974
1975 void WebGLRenderingContext::generateMipmap(GC3Denum target)
1976 {
1977     if (isContextLost())
1978         return;
1979     WebGLTexture* tex = validateTextureBinding(target, false);
1980     if (!tex)
1981         return;
1982     if (!tex->canGenerateMipmaps()) {
1983         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1984         return;
1985     }
1986     // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
1987     // on Mac.  Remove the hack once this driver bug is fixed.
1988 #if OS(DARWIN)
1989     bool needToResetMinFilter = false;
1990     if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
1991         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
1992         needToResetMinFilter = true;
1993     }
1994 #endif
1995     m_context->generateMipmap(target);
1996 #if OS(DARWIN)
1997     if (needToResetMinFilter)
1998         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
1999 #endif
2000     tex->generateMipmapLevelInfo();
2001     cleanupAfterGraphicsCall(false);
2002 }
2003
2004 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2005 {
2006     UNUSED_PARAM(ec);
2007     if (isContextLost() || !validateWebGLObject(program))
2008         return 0;
2009     ActiveInfo info;
2010     if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
2011         return 0;
2012     return WebGLActiveInfo::create(info.name, info.type, info.size);
2013 }
2014
2015 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2016 {
2017     UNUSED_PARAM(ec);
2018     if (isContextLost() || !validateWebGLObject(program))
2019         return 0;
2020     ActiveInfo info;
2021     if (!m_context->getActiveUniform(objectOrZero(program), index, info))
2022         return 0;
2023     if (!isGLES2Compliant())
2024         if (info.size > 1 && !info.name.endsWith("[0]"))
2025             info.name.append("[0]");
2026     return WebGLActiveInfo::create(info.name, info.type, info.size);
2027 }
2028
2029 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader> >& shaderObjects, ExceptionCode& ec)
2030 {
2031     UNUSED_PARAM(ec);
2032     shaderObjects.clear();
2033     if (isContextLost() || !validateWebGLObject(program))
2034         return false;
2035
2036     const GC3Denum shaderType[] = {
2037         GraphicsContext3D::VERTEX_SHADER,
2038         GraphicsContext3D::FRAGMENT_SHADER
2039     };
2040     for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
2041         WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2042         if (shader)
2043             shaderObjects.append(shader);
2044     }
2045     return true;
2046 }
2047
2048 GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
2049 {
2050     if (isContextLost())
2051         return -1;
2052     if (!validateLocationLength(name))
2053         return -1;
2054     if (!validateString(name))
2055         return -1;
2056     return m_context->getAttribLocation(objectOrZero(program), name);
2057 }
2058
2059 WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2060 {
2061     UNUSED_PARAM(ec);
2062     if (isContextLost())
2063         return WebGLGetInfo();
2064     if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
2065         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2066         return WebGLGetInfo();
2067     }
2068
2069     if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
2070         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2071         return WebGLGetInfo();
2072     }
2073
2074     WebGLStateRestorer(this, false);
2075     GC3Dint value = 0;
2076     m_context->getBufferParameteriv(target, pname, &value);
2077     if (pname == GraphicsContext3D::BUFFER_SIZE)
2078         return WebGLGetInfo(value);
2079     return WebGLGetInfo(static_cast<unsigned int>(value));
2080 }
2081
2082 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
2083 {
2084     if (isContextLost())
2085         return 0;
2086     // We always need to return a new WebGLContextAttributes object to
2087     // prevent the user from mutating any cached version.
2088     return WebGLContextAttributes::create(m_context->getContextAttributes());
2089 }
2090
2091 GC3Denum WebGLRenderingContext::getError()
2092 {
2093     return m_context->getError();
2094 }
2095
2096 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
2097 {
2098     if (isContextLost())
2099         return 0;
2100
2101     if (equalIgnoringCase(name, "OES_standard_derivatives")
2102         && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
2103         if (!m_oesStandardDerivatives) {
2104             m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
2105             m_oesStandardDerivatives = OESStandardDerivatives::create(this);
2106         }
2107         return m_oesStandardDerivatives.get();
2108     }
2109     if (equalIgnoringCase(name, "OES_texture_float")
2110         && m_context->getExtensions()->supports("GL_OES_texture_float")) {
2111         if (!m_oesTextureFloat) {
2112             m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
2113             m_oesTextureFloat = OESTextureFloat::create(this);
2114         }
2115         return m_oesTextureFloat.get();
2116     }
2117     if (equalIgnoringCase(name, "OES_vertex_array_object")
2118         && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
2119         if (!m_oesVertexArrayObject) {
2120             m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
2121             m_oesVertexArrayObject = OESVertexArrayObject::create(this);
2122         }
2123         return m_oesVertexArrayObject.get();
2124     }
2125     if (equalIgnoringCase(name, "WEBKIT_WEBGL_lose_context")
2126         // FIXME: remove this after a certain grace period.
2127         || equalIgnoringCase(name, "WEBKIT_lose_context")) {
2128         if (!m_webglLoseContext)
2129             m_webglLoseContext = WebGLLoseContext::create(this);
2130         return m_webglLoseContext.get();
2131     }
2132     if (equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_textures")) {
2133         // Use WEBKIT_ prefix until extension is official.
2134         if (!m_webglCompressedTextures)
2135             m_webglCompressedTextures = WebGLCompressedTextures::create(this);
2136         return m_webglCompressedTextures.get();
2137     }
2138
2139     if (allowPrivilegedExtensions()) {
2140         if (equalIgnoringCase(name, "WEBGL_debug_renderer_info")) {
2141             if (!m_webglDebugRendererInfo)
2142                 m_webglDebugRendererInfo = WebGLDebugRendererInfo::create(this);
2143             return m_webglDebugRendererInfo.get();
2144         }
2145         if (equalIgnoringCase(name, "WEBGL_debug_shaders")
2146             && m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source")) {
2147             if (!m_webglDebugShaders)
2148                 m_webglDebugShaders = WebGLDebugShaders::create(this);
2149             return m_webglDebugShaders.get();
2150         }
2151     }
2152
2153     return 0;
2154 }
2155
2156 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
2157 {
2158     UNUSED_PARAM(ec);
2159     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
2160         return WebGLGetInfo();
2161
2162     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2163         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2164         return WebGLGetInfo();
2165     }
2166
2167     WebGLObject* object = m_framebufferBinding->getAttachment(attachment);
2168     if (!object) {
2169         if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2170             return WebGLGetInfo(GraphicsContext3D::NONE);
2171         // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
2172         // specifies INVALID_OPERATION.
2173         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2174         return WebGLGetInfo();
2175     }
2176
2177     ASSERT(object->isTexture() || object->isRenderbuffer());
2178     if (object->isTexture()) {
2179         switch (pname) {
2180         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2181             return WebGLGetInfo(GraphicsContext3D::TEXTURE);
2182         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2183             return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
2184         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2185         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2186             {
2187                 WebGLStateRestorer(this, false);
2188                 GC3Dint value = 0;
2189                 m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2190                 return WebGLGetInfo(value);
2191             }
2192         default:
2193             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2194             return WebGLGetInfo();
2195         }
2196     } else {
2197         switch (pname) {
2198         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2199             return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
2200         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2201             return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
2202         default:
2203             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2204             return WebGLGetInfo();
2205         }
2206     }
2207 }
2208
2209 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec)
2210 {
2211     UNUSED_PARAM(ec);
2212     if (isContextLost())
2213         return WebGLGetInfo();
2214     WebGLStateRestorer(this, false);
2215     switch (pname) {
2216     case GraphicsContext3D::ACTIVE_TEXTURE:
2217         return getUnsignedIntParameter(pname);
2218     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
2219         return getWebGLFloatArrayParameter(pname);
2220     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
2221         return getWebGLFloatArrayParameter(pname);
2222     case GraphicsContext3D::ALPHA_BITS:
2223         return getIntParameter(pname);
2224     case GraphicsContext3D::ARRAY_BUFFER_BINDING:
2225         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2226     case GraphicsContext3D::BLEND:
2227         return getBooleanParameter(pname);
2228     case GraphicsContext3D::BLEND_COLOR:
2229         return getWebGLFloatArrayParameter(pname);
2230     case GraphicsContext3D::BLEND_DST_ALPHA:
2231         return getUnsignedIntParameter(pname);
2232     case GraphicsContext3D::BLEND_DST_RGB:
2233         return getUnsignedIntParameter(pname);
2234     case GraphicsContext3D::BLEND_EQUATION_ALPHA:
2235         return getUnsignedIntParameter(pname);
2236     case GraphicsContext3D::BLEND_EQUATION_RGB:
2237         return getUnsignedIntParameter(pname);
2238     case GraphicsContext3D::BLEND_SRC_ALPHA:
2239         return getUnsignedIntParameter(pname);
2240     case GraphicsContext3D::BLEND_SRC_RGB:
2241         return getUnsignedIntParameter(pname);
2242     case GraphicsContext3D::BLUE_BITS:
2243         return getIntParameter(pname);
2244     case GraphicsContext3D::COLOR_CLEAR_VALUE:
2245         return getWebGLFloatArrayParameter(pname);
2246     case GraphicsContext3D::COLOR_WRITEMASK:
2247         return getBooleanArrayParameter(pname);
2248     case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
2249         if (m_webglCompressedTextures)
2250             return m_webglCompressedTextures->getCompressedTextureFormats();
2251         // Defined as null in the spec
2252         return WebGLGetInfo();
2253     case GraphicsContext3D::CULL_FACE:
2254         return getBooleanParameter(pname);
2255     case GraphicsContext3D::CULL_FACE_MODE:
2256         return getUnsignedIntParameter(pname);
2257     case GraphicsContext3D::CURRENT_PROGRAM:
2258         return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2259     case GraphicsContext3D::DEPTH_BITS:
2260         return getIntParameter(pname);
2261     case GraphicsContext3D::DEPTH_CLEAR_VALUE:
2262         return getFloatParameter(pname);
2263     case GraphicsContext3D::DEPTH_FUNC:
2264         return getUnsignedIntParameter(pname);
2265     case GraphicsContext3D::DEPTH_RANGE:
2266         return getWebGLFloatArrayParameter(pname);
2267     case GraphicsContext3D::DEPTH_TEST:
2268         return getBooleanParameter(pname);
2269     case GraphicsContext3D::DEPTH_WRITEMASK:
2270         return getBooleanParameter(pname);
2271     case GraphicsContext3D::DITHER:
2272         return getBooleanParameter(pname);
2273     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
2274         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
2275     case GraphicsContext3D::FRAMEBUFFER_BINDING:
2276         return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2277     case GraphicsContext3D::FRONT_FACE:
2278         return getUnsignedIntParameter(pname);
2279     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2280         return getUnsignedIntParameter(pname);
2281     case GraphicsContext3D::GREEN_BITS:
2282         return getIntParameter(pname);
2283     case GraphicsContext3D::LINE_WIDTH:
2284         return getFloatParameter(pname);
2285     case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2286         return getIntParameter(pname);
2287     case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
2288         return getIntParameter(pname);
2289     case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
2290         return getIntParameter(pname);
2291     case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
2292         return getIntParameter(pname);
2293     case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
2294         return getIntParameter(pname);
2295     case GraphicsContext3D::MAX_TEXTURE_SIZE:
2296         return getIntParameter(pname);
2297     case GraphicsContext3D::MAX_VARYING_VECTORS:
2298         return getIntParameter(pname);
2299     case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
2300         return getIntParameter(pname);
2301     case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2302         return getIntParameter(pname);
2303     case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
2304         return getIntParameter(pname);
2305     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
2306         return getWebGLIntArrayParameter(pname);
2307     case GraphicsContext3D::NUM_COMPRESSED_TEXTURE_FORMATS:
2308         // WebGL 1.0 specifies that there are no compressed texture formats.
2309         return WebGLGetInfo(static_cast<int>(0));
2310     case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
2311         // FIXME: should we always return 0 for this?
2312         return getIntParameter(pname);
2313     case GraphicsContext3D::PACK_ALIGNMENT:
2314         return getIntParameter(pname);
2315     case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
2316         return getFloatParameter(pname);
2317     case GraphicsContext3D::POLYGON_OFFSET_FILL:
2318         return getBooleanParameter(pname);
2319     case GraphicsContext3D::POLYGON_OFFSET_UNITS:
2320         return getFloatParameter(pname);
2321     case GraphicsContext3D::RED_BITS:
2322         return getIntParameter(pname);
2323     case GraphicsContext3D::RENDERBUFFER_BINDING:
2324         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2325     case GraphicsContext3D::RENDERER:
2326         return WebGLGetInfo(String("WebKit WebGL"));
2327     case GraphicsContext3D::SAMPLE_BUFFERS:
2328         return getIntParameter(pname);
2329     case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
2330         return getBooleanParameter(pname);
2331     case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
2332         return getFloatParameter(pname);
2333     case GraphicsContext3D::SAMPLES:
2334         return getIntParameter(pname);
2335     case GraphicsContext3D::SCISSOR_BOX:
2336         return getWebGLIntArrayParameter(pname);
2337     case GraphicsContext3D::SCISSOR_TEST:
2338         return getBooleanParameter(pname);
2339     case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
2340         return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
2341     case GraphicsContext3D::STENCIL_BACK_FAIL:
2342         return getUnsignedIntParameter(pname);
2343     case GraphicsContext3D::STENCIL_BACK_FUNC:
2344         return getUnsignedIntParameter(pname);
2345     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
2346         return getUnsignedIntParameter(pname);
2347     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
2348         return getUnsignedIntParameter(pname);
2349     case GraphicsContext3D::STENCIL_BACK_REF:
2350         return getIntParameter(pname);
2351     case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
2352         return getUnsignedIntParameter(pname);
2353     case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
2354         return getUnsignedIntParameter(pname);
2355     case GraphicsContext3D::STENCIL_BITS:
2356         return getIntParameter(pname);
2357     case GraphicsContext3D::STENCIL_CLEAR_VALUE:
2358         return getIntParameter(pname);
2359     case GraphicsContext3D::STENCIL_FAIL:
2360         return getUnsignedIntParameter(pname);
2361     case GraphicsContext3D::STENCIL_FUNC:
2362         return getUnsignedIntParameter(pname);
2363     case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
2364         return getUnsignedIntParameter(pname);
2365     case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
2366         return getUnsignedIntParameter(pname);
2367     case GraphicsContext3D::STENCIL_REF:
2368         return getIntParameter(pname);
2369     case GraphicsContext3D::STENCIL_TEST:
2370         return getBooleanParameter(pname);
2371     case GraphicsContext3D::STENCIL_VALUE_MASK:
2372         return getUnsignedIntParameter(pname);
2373     case GraphicsContext3D::STENCIL_WRITEMASK:
2374         return getUnsignedIntParameter(pname);
2375     case GraphicsContext3D::SUBPIXEL_BITS:
2376         return getIntParameter(pname);
2377     case GraphicsContext3D::TEXTURE_BINDING_2D:
2378         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
2379     case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
2380         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
2381     case GraphicsContext3D::UNPACK_ALIGNMENT:
2382         return getIntParameter(pname);
2383     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2384         return WebGLGetInfo(m_unpackFlipY);
2385     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2386         return WebGLGetInfo(m_unpackPremultiplyAlpha);
2387     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2388         return WebGLGetInfo(m_unpackColorspaceConversion);
2389     case GraphicsContext3D::VENDOR:
2390         return WebGLGetInfo(String("WebKit"));
2391     case GraphicsContext3D::VERSION:
2392         return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
2393     case GraphicsContext3D::VIEWPORT:
2394         return getWebGLIntArrayParameter(pname);
2395     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2396         if (m_oesStandardDerivatives)
2397             return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2398         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2399         return WebGLGetInfo();
2400     case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
2401         if (m_webglDebugRendererInfo)
2402             return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
2403         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2404         return WebGLGetInfo();
2405     case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
2406         if (m_webglDebugRendererInfo)
2407             return WebGLGetInfo(m_context->getString(GraphicsContext3D::VENDOR));
2408         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2409         return WebGLGetInfo();
2410     case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2411         if (m_oesVertexArrayObject) {
2412             if (!m_boundVertexArrayObject->isDefaultObject())
2413                 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2414             return WebGLGetInfo();
2415         }
2416         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2417         return WebGLGetInfo();
2418     default:
2419         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2420         return WebGLGetInfo();
2421     }
2422 }
2423
2424 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2425 {
2426     UNUSED_PARAM(ec);
2427     if (isContextLost() || !validateWebGLObject(program))
2428         return WebGLGetInfo();
2429
2430     WebGLStateRestorer(this, false);
2431     GC3Dint value = 0;
2432     switch (pname) {
2433     case GraphicsContext3D::DELETE_STATUS:
2434         return WebGLGetInfo(program->isDeleted());
2435     case GraphicsContext3D::VALIDATE_STATUS:
2436         m_context->getProgramiv(objectOrZero(program), pname, &value);
2437         return WebGLGetInfo(static_cast<bool>(value));
2438     case GraphicsContext3D::LINK_STATUS:
2439         return WebGLGetInfo(program->getLinkStatus());
2440     case GraphicsContext3D::ATTACHED_SHADERS:
2441     case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2442     case GraphicsContext3D::ACTIVE_UNIFORMS:
2443         m_context->getProgramiv(objectOrZero(program), pname, &value);
2444         return WebGLGetInfo(value);
2445     default:
2446         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2447         return WebGLGetInfo();
2448     }
2449 }
2450
2451 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2452 {
2453     UNUSED_PARAM(ec);
2454     if (isContextLost())
2455         return String();
2456     if (!validateWebGLObject(program))
2457         return "";
2458     WebGLStateRestorer(this, false);
2459     return m_context->getProgramInfoLog(objectOrZero(program));
2460 }
2461
2462 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2463 {
2464     UNUSED_PARAM(ec);
2465     if (isContextLost())
2466         return WebGLGetInfo();
2467     if (target != GraphicsContext3D::RENDERBUFFER) {
2468         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2469         return WebGLGetInfo();
2470     }
2471     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2472         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2473         return WebGLGetInfo();
2474     }
2475
2476     if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2477         && !m_renderbufferBinding->isValid()) {
2478         ASSERT(!isDepthStencilSupported());
2479         int value = 0;
2480         switch (pname) {
2481         case GraphicsContext3D::RENDERBUFFER_WIDTH:
2482             value = m_renderbufferBinding->getWidth();
2483             break;
2484         case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2485             value = m_renderbufferBinding->getHeight();
2486             break;
2487         case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2488         case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2489         case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2490         case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2491             value = 0;
2492             break;
2493         case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2494             value = 24;
2495             break;
2496         case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2497             value = 8;
2498             break;
2499         case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2500             return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2501         default:
2502             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2503             return WebGLGetInfo();
2504         }
2505         return WebGLGetInfo(value);
2506     }
2507
2508     WebGLStateRestorer(this, false);
2509     GC3Dint value = 0;
2510     switch (pname) {
2511     case GraphicsContext3D::RENDERBUFFER_WIDTH:
2512     case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2513     case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2514     case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2515     case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2516     case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2517     case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2518     case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2519         m_context->getRenderbufferParameteriv(target, pname, &value);
2520         return WebGLGetInfo(value);
2521     case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2522         return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2523     default:
2524         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2525         return WebGLGetInfo();
2526     }
2527 }
2528
2529 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
2530 {
2531     UNUSED_PARAM(ec);
2532     if (isContextLost() || !validateWebGLObject(shader))
2533         return WebGLGetInfo();
2534     WebGLStateRestorer(this, false);
2535     GC3Dint value = 0;
2536     switch (pname) {
2537     case GraphicsContext3D::DELETE_STATUS:
2538         return WebGLGetInfo(shader->isDeleted());
2539     case GraphicsContext3D::COMPILE_STATUS:
2540         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2541         return WebGLGetInfo(static_cast<bool>(value));
2542     case GraphicsContext3D::SHADER_TYPE:
2543         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2544         return WebGLGetInfo(static_cast<unsigned int>(value));
2545     default:
2546         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2547         return WebGLGetInfo();
2548     }
2549 }
2550
2551 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
2552 {
2553     UNUSED_PARAM(ec);
2554     if (isContextLost())
2555         return String();
2556     if (!validateWebGLObject(shader))
2557         return "";
2558     WebGLStateRestorer(this, false);
2559     return m_context->getShaderInfoLog(objectOrZero(shader));
2560 }
2561
2562 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
2563 {
2564     UNUSED_PARAM(ec);
2565     if (isContextLost())
2566         return String();
2567     if (!validateWebGLObject(shader))
2568         return "";
2569     return shader->getSource();
2570 }
2571
2572 Vector<String> WebGLRenderingContext::getSupportedExtensions()
2573 {
2574     Vector<String> result;
2575     if (m_context->getExtensions()->supports("GL_OES_texture_float"))
2576         result.append("OES_texture_float");
2577     if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
2578         result.append("OES_standard_derivatives");
2579     if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
2580         result.append("OES_vertex_array_object");
2581     result.append("WEBKIT_WEBGL_lose_context");
2582     if (WebGLCompressedTextures::supported(this))
2583         result.append("WEBKIT_WEBGL_compressed_textures");
2584
2585     if (allowPrivilegedExtensions()) {
2586         if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
2587             result.append("WEBGL_debug_shaders");
2588         result.append("WEBGL_debug_renderer_info");
2589     }
2590
2591     return result;
2592 }
2593
2594 WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2595 {
2596     UNUSED_PARAM(ec);
2597     if (isContextLost())
2598         return WebGLGetInfo();
2599     WebGLTexture* tex = validateTextureBinding(target, false);
2600     if (!tex)
2601         return WebGLGetInfo();
2602     WebGLStateRestorer(this, false);
2603     GC3Dint value = 0;
2604     switch (pname) {
2605     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2606     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2607     case GraphicsContext3D::TEXTURE_WRAP_S:
2608     case GraphicsContext3D::TEXTURE_WRAP_T:
2609         m_context->getTexParameteriv(target, pname, &value);
2610         return WebGLGetInfo(static_cast<unsigned int>(value));
2611     default:
2612         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2613         return WebGLGetInfo();
2614     }
2615 }
2616
2617 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2618 {
2619     UNUSED_PARAM(ec);
2620     if (isContextLost() || !validateWebGLObject(program))
2621         return WebGLGetInfo();
2622     if (!uniformLocation || uniformLocation->program() != program) {
2623         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2624         return WebGLGetInfo();
2625     }
2626     GC3Dint location = uniformLocation->location();
2627
2628     WebGLStateRestorer(this, false);
2629     // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2630     GC3Dint activeUniforms = 0;
2631     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2632     for (GC3Dint i = 0; i < activeUniforms; i++) {
2633         ActiveInfo info;
2634         if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2635             return WebGLGetInfo();
2636         // Strip "[0]" from the name if it's an array.
2637         if (info.size > 1 && info.name.endsWith("[0]"))
2638             info.name = info.name.left(info.name.length() - 3);
2639         // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2640         for (GC3Dint index = 0; index < info.size; ++index) {
2641             String name = info.name;
2642             if (info.size > 1 && index >= 1) {
2643                 name.append('[');
2644                 name.append(String::number(index));
2645                 name.append(']');
2646             }
2647             // Now need to look this up by name again to find its location
2648             GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name);
2649             if (loc == location) {
2650                 // Found it. Use the type in the ActiveInfo to determine the return type.
2651                 GC3Denum baseType;
2652                 unsigned int length;
2653                 switch (info.type) {
2654                 case GraphicsContext3D::BOOL:
2655                     baseType = GraphicsContext3D::BOOL;
2656                     length = 1;
2657                     break;
2658                 case GraphicsContext3D::BOOL_VEC2:
2659                     baseType = GraphicsContext3D::BOOL;
2660                     length = 2;
2661                     break;
2662                 case GraphicsContext3D::BOOL_VEC3:
2663                     baseType = GraphicsContext3D::BOOL;
2664                     length = 3;
2665                     break;
2666                 case GraphicsContext3D::BOOL_VEC4:
2667                     baseType = GraphicsContext3D::BOOL;
2668                     length = 4;
2669                     break;
2670                 case GraphicsContext3D::INT:
2671                     baseType = GraphicsContext3D::INT;
2672                     length = 1;
2673                     break;
2674                 case GraphicsContext3D::INT_VEC2:
2675                     baseType = GraphicsContext3D::INT;
2676                     length = 2;
2677                     break;
2678                 case GraphicsContext3D::INT_VEC3:
2679                     baseType = GraphicsContext3D::INT;
2680                     length = 3;
2681                     break;
2682                 case GraphicsContext3D::INT_VEC4:
2683                     baseType = GraphicsContext3D::INT;
2684                     length = 4;
2685                     break;
2686                 case GraphicsContext3D::FLOAT:
2687                     baseType = GraphicsContext3D::FLOAT;
2688                     length = 1;
2689                     break;
2690                 case GraphicsContext3D::FLOAT_VEC2:
2691                     baseType = GraphicsContext3D::FLOAT;
2692                     length = 2;
2693                     break;
2694                 case GraphicsContext3D::FLOAT_VEC3:
2695                     baseType = GraphicsContext3D::FLOAT;
2696                     length = 3;
2697                     break;
2698                 case GraphicsContext3D::FLOAT_VEC4:
2699                     baseType = GraphicsContext3D::FLOAT;
2700                     length = 4;
2701                     break;
2702                 case GraphicsContext3D::FLOAT_MAT2:
2703                     baseType = GraphicsContext3D::FLOAT;
2704                     length = 4;
2705                     break;
2706                 case GraphicsContext3D::FLOAT_MAT3:
2707                     baseType = GraphicsContext3D::FLOAT;
2708                     length = 9;
2709                     break;
2710                 case GraphicsContext3D::FLOAT_MAT4:
2711                     baseType = GraphicsContext3D::FLOAT;
2712                     length = 16;
2713                     break;
2714                 case GraphicsContext3D::SAMPLER_2D:
2715                 case GraphicsContext3D::SAMPLER_CUBE:
2716                     baseType = GraphicsContext3D::INT;
2717                     length = 1;
2718                     break;
2719                 default:
2720                     // Can't handle this type
2721                     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2722                     return WebGLGetInfo();
2723                 }
2724                 switch (baseType) {
2725                 case GraphicsContext3D::FLOAT: {
2726                     GC3Dfloat value[16] = {0};
2727                     m_context->getUniformfv(objectOrZero(program), location, value);
2728                     if (length == 1)
2729                         return WebGLGetInfo(value[0]);
2730                     return WebGLGetInfo(Float32Array::create(value, length));
2731                 }
2732                 case GraphicsContext3D::INT: {
2733                     GC3Dint value[4] = {0};
2734                     m_context->getUniformiv(objectOrZero(program), location, value);
2735                     if (length == 1)
2736                         return WebGLGetInfo(value[0]);
2737                     return WebGLGetInfo(Int32Array::create(value, length));
2738                 }
2739                 case GraphicsContext3D::BOOL: {
2740                     GC3Dint value[4] = {0};
2741                     m_context->getUniformiv(objectOrZero(program), location, value);
2742                     if (length > 1) {
2743                         bool boolValue[16] = {0};
2744                         for (unsigned j = 0; j < length; j++)
2745                             boolValue[j] = static_cast<bool>(value[j]);
2746                         return WebGLGetInfo(boolValue, length);
2747                     }
2748                     return WebGLGetInfo(static_cast<bool>(value[0]));
2749                 }
2750                 default:
2751                     notImplemented();
2752                 }
2753             }
2754         }
2755     }
2756     // If we get here, something went wrong in our unfortunately complex logic above
2757     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2758     return WebGLGetInfo();
2759 }
2760
2761 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
2762 {
2763     UNUSED_PARAM(ec);
2764     if (isContextLost() || !validateWebGLObject(program))
2765         return 0;
2766     if (!validateLocationLength(name))
2767         return 0;
2768     if (!validateString(name))
2769         return 0;
2770     WebGLStateRestorer(this, false);
2771     GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2772     if (uniformLocation == -1)
2773         return 0;
2774     return WebGLUniformLocation::create(program, uniformLocation);
2775 }
2776
2777 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
2778 {
2779     UNUSED_PARAM(ec);
2780     if (isContextLost())
2781         return WebGLGetInfo();
2782     WebGLStateRestorer(this, false);
2783     if (index >= m_maxVertexAttribs) {
2784         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2785         return WebGLGetInfo();
2786     }
2787     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2788     switch (pname) {
2789     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2790         if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
2791             || !state.bufferBinding
2792             || !state.bufferBinding->object())
2793             return WebGLGetInfo();
2794         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
2795     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
2796         return WebGLGetInfo(state.enabled);
2797     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
2798         return WebGLGetInfo(state.normalized);
2799     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
2800         return WebGLGetInfo(state.size);
2801     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
2802         return WebGLGetInfo(state.originalStride);
2803     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
2804         return WebGLGetInfo(state.type);
2805     case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
2806         return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
2807     default:
2808         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2809         return WebGLGetInfo();
2810     }
2811 }
2812
2813 GC3Dsizeiptr WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
2814 {
2815     if (isContextLost())
2816         return 0;
2817     GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
2818     cleanupAfterGraphicsCall(false);
2819     return result;
2820 }
2821
2822 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
2823 {
2824     if (isContextLost())
2825         return;
2826     bool isValid = false;
2827     switch (target) {
2828     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2829         isValid = true;
2830         break;
2831     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2832         if (m_oesStandardDerivatives)
2833             isValid = true;
2834         break;
2835     }
2836     if (!isValid) {
2837         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2838         return;
2839     }
2840     m_context->hint(target, mode);
2841     cleanupAfterGraphicsCall(false);
2842 }
2843
2844 GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
2845 {
2846     if (!buffer || isContextLost())
2847         return 0;
2848
2849     if (!buffer->hasEverBeenBound())
2850         return 0;
2851
2852     return m_context->isBuffer(buffer->object());
2853 }
2854
2855 bool WebGLRenderingContext::isContextLost()
2856 {
2857     return m_contextLost;
2858 }
2859
2860 GC3Dboolean WebGLRenderingContext::isEnabled(GC3Denum cap)
2861 {
2862     if (!validateCapability(cap) || isContextLost())
2863         return 0;
2864     return m_context->isEnabled(cap);
2865 }
2866
2867 GC3Dboolean WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer)
2868 {
2869     if (!framebuffer || isContextLost())
2870         return 0;
2871
2872     if (!framebuffer->hasEverBeenBound())
2873         return 0;
2874
2875     return m_context->isFramebuffer(framebuffer->object());
2876 }
2877
2878 GC3Dboolean WebGLRenderingContext::isProgram(WebGLProgram* program)
2879 {
2880     if (!program || isContextLost())
2881         return 0;
2882
2883     return m_context->isProgram(program->object());
2884 }
2885
2886 GC3Dboolean WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2887 {
2888     if (!renderbuffer || isContextLost())
2889         return 0;
2890
2891     if (!renderbuffer->hasEverBeenBound())
2892         return 0;
2893
2894     return m_context->isRenderbuffer(renderbuffer->object());
2895 }
2896
2897 GC3Dboolean WebGLRenderingContext::isShader(WebGLShader* shader)
2898 {
2899     if (!shader || isContextLost())
2900         return 0;
2901
2902     return m_context->isShader(shader->object());
2903 }
2904
2905 GC3Dboolean WebGLRenderingContext::isTexture(WebGLTexture* texture)
2906 {
2907     if (!texture || isContextLost())
2908         return 0;
2909
2910     if (!texture->hasEverBeenBound())
2911         return 0;
2912
2913     return m_context->isTexture(texture->object());
2914 }
2915
2916 void WebGLRenderingContext::lineWidth(GC3Dfloat width)
2917 {
2918     if (isContextLost())
2919         return;
2920     m_context->lineWidth(width);
2921     cleanupAfterGraphicsCall(false);
2922 }
2923
2924 void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec)
2925 {
2926     UNUSED_PARAM(ec);
2927     if (isContextLost() || !validateWebGLObject(program))
2928         return;
2929     if (!isGLES2Compliant()) {
2930         if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
2931             program->setLinkStatus(false);
2932             return;
2933         }
2934     }
2935
2936     m_context->linkProgram(objectOrZero(program));
2937     program->increaseLinkCount();
2938     // cache link status
2939     GC3Dint value = 0;
2940     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::LINK_STATUS, &value);
2941     program->setLinkStatus(static_cast<bool>(value));
2942     // Need to cache link status before caching active attribute locations.
2943     program->cacheActiveAttribLocations();
2944     cleanupAfterGraphicsCall(false);
2945 }
2946
2947 void WebGLRenderingContext::pixelStorei(GC3Denum pname, GC3Dint param)
2948 {
2949     if (isContextLost())
2950         return;
2951     switch (pname) {
2952     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2953         m_unpackFlipY = param;
2954         break;
2955     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2956         m_unpackPremultiplyAlpha = param;
2957         break;
2958     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2959         if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
2960             m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
2961         else {
2962             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2963             return;
2964         }
2965         break;
2966     case GraphicsContext3D::PACK_ALIGNMENT:
2967     case GraphicsContext3D::UNPACK_ALIGNMENT:
2968         if (param == 1 || param == 2 || param == 4 || param == 8) {
2969             if (pname == GraphicsContext3D::PACK_ALIGNMENT)
2970                 m_packAlignment = param;
2971             else // GraphicsContext3D::UNPACK_ALIGNMENT:
2972                 m_unpackAlignment = param;
2973             m_context->pixelStorei(pname, param);
2974             cleanupAfterGraphicsCall(false);
2975         } else {
2976             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2977             return;
2978         }
2979         break;
2980     default:
2981         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2982         return;
2983     }
2984 }
2985
2986 void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
2987 {
2988     if (isContextLost())
2989         return;
2990     m_context->polygonOffset(factor, units);
2991     cleanupAfterGraphicsCall(false);
2992 }
2993
2994 void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&)
2995 {
2996     if (isContextLost())
2997         return;
2998     // Due to WebGL's same-origin restrictions, it is not possible to
2999     // taint the origin using the WebGL API.
3000     ASSERT(canvas()->originClean());
3001     // Validate input parameters.
3002     if (!pixels) {
3003         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3004         return;
3005     }
3006     switch (format) {
3007     case GraphicsContext3D::ALPHA:
3008     case GraphicsContext3D::RGB:
3009     case GraphicsContext3D::RGBA:
3010         break;
3011     default:
3012         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3013         return;
3014     }
3015     switch (type) {
3016     case GraphicsContext3D::UNSIGNED_BYTE:
3017     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
3018     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
3019     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
3020         break;
3021     default:
3022         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3023         return;
3024     }
3025     if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
3026         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3027         return;
3028     }
3029     // Validate array type against pixel type.
3030     if (!pixels->isUnsignedByteArray()) {
3031         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3032         return;
3033     }
3034     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
3035         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
3036         return;
3037     }
3038     // Calculate array size, taking into consideration of PACK_ALIGNMENT.
3039     unsigned int totalBytesRequired;
3040     unsigned int padding;
3041     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
3042     if (error != GraphicsContext3D::NO_ERROR) {
3043         m_context->synthesizeGLError(error);
3044         return;
3045     }
3046     if (pixels->byteLength() < totalBytesRequired) {
3047         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3048         return;
3049     }
3050     clearIfComposited();
3051     void* data = pixels->baseAddress();
3052
3053     {
3054         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
3055         m_context->readPixels(x, y, width, height, format, type, data);
3056     }
3057
3058 #if OS(DARWIN)
3059     // FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
3060     // when alpha is off, readPixels should set alpha to 255 instead of 0.
3061     if (!m_context->getContextAttributes().alpha) {
3062         unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
3063         for (GC3Dsizei iy = 0; iy < height; ++iy) {
3064             for (GC3Dsizei ix = 0; ix < width; ++ix) {
3065                 pixels[3] = 255;
3066                 pixels += 4;
3067             }
3068             pixels += padding;
3069         }
3070     }
3071 #endif
3072     cleanupAfterGraphicsCall(false);
3073 }
3074
3075 void WebGLRenderingContext::releaseShaderCompiler()
3076 {
3077     if (isContextLost())
3078         return;
3079     m_context->releaseShaderCompiler();
3080     cleanupAfterGraphicsCall(false);
3081 }
3082
3083 void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
3084 {
3085     if (isContextLost())
3086         return;
3087     if (target != GraphicsContext3D::RENDERBUFFER) {
3088         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3089         return;
3090     }
3091     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
3092         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3093         return;
3094     }
3095     if (!validateSize(width, height))
3096         return;
3097     switch (internalformat) {
3098     case GraphicsContext3D::DEPTH_COMPONENT16:
3099     case GraphicsContext3D::RGBA4:
3100     case GraphicsContext3D::RGB5_A1:
3101     case GraphicsContext3D::RGB565:
3102     case GraphicsContext3D::STENCIL_INDEX8:
3103         m_context->renderbufferStorage(target, internalformat, width, height);
3104         m_renderbufferBinding->setInternalFormat(internalformat);
3105         m_renderbufferBinding->setIsValid(true);
3106         m_renderbufferBinding->setSize(width, height);
3107         cleanupAfterGraphicsCall(false);
3108         break;
3109     case GraphicsContext3D::DEPTH_STENCIL:
3110         if (isDepthStencilSupported()) {
3111             m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
3112             cleanupAfterGraphicsCall(false);
3113         }
3114         m_renderbufferBinding->setSize(width, height);
3115         m_renderbufferBinding->setIsValid(isDepthStencilSupported());
3116         m_renderbufferBinding->setInternalFormat(internalformat);
3117         break;
3118     default:
3119         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3120     }
3121 }
3122
3123 void WebGLRenderingContext::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
3124 {
3125     if (isContextLost())
3126         return;
3127     m_context->sampleCoverage(value, invert);
3128     cleanupAfterGraphicsCall(false);
3129 }
3130
3131 void WebGLRenderingContext::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
3132 {
3133     if (isContextLost())
3134         return;
3135     if (!validateSize(width, height))
3136         return;
3137     m_context->scissor(x, y, width, height);
3138     cleanupAfterGraphicsCall(false);
3139 }
3140
3141 void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
3142 {
3143     UNUSED_PARAM(ec);
3144     if (isContextLost() || !validateWebGLObject(shader))
3145         return;
3146     String stringWithoutComments = StripComments(string).result();
3147     if (!validateString(stringWithoutComments))
3148         return;
3149     shader->setSource(string);
3150     m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
3151     cleanupAfterGraphicsCall(false);
3152 }
3153
3154 void WebGLRenderingContext::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
3155 {
3156     if (isContextLost())
3157         return;
3158     if (!validateStencilFunc(func))
3159         return;
3160     m_stencilFuncRef = ref;
3161     m_stencilFuncRefBack = ref;
3162     m_stencilFuncMask = mask;
3163     m_stencilFuncMaskBack = mask;
3164     m_context->stencilFunc(func, ref, mask);
3165     cleanupAfterGraphicsCall(false);
3166 }
3167
3168 void WebGLRenderingContext::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
3169 {
3170     if (isContextLost())
3171         return;
3172     if (!validateStencilFunc(func))
3173         return;
3174     switch (face) {
3175     case GraphicsContext3D::FRONT_AND_BACK:
3176         m_stencilFuncRef = ref;
3177         m_stencilFuncRefBack = ref;
3178         m_stencilFuncMask = mask;
3179         m_stencilFuncMaskBack = mask;
3180         break;
3181     case GraphicsContext3D::FRONT:
3182         m_stencilFuncRef = ref;
3183         m_stencilFuncMask = mask;
3184         break;
3185     case GraphicsContext3D::BACK:
3186         m_stencilFuncRefBack = ref;
3187         m_stencilFuncMaskBack = mask;
3188         break;
3189     default:
3190         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3191         return;
3192     }
3193     m_context->stencilFuncSeparate(face, func, ref, mask);
3194     cleanupAfterGraphicsCall(false);
3195 }
3196
3197 void WebGLRenderingContext::stencilMask(GC3Duint mask)
3198 {
3199     if (isContextLost())
3200         return;
3201     m_stencilMask = mask;
3202     m_stencilMaskBack = mask;
3203     m_context->stencilMask(mask);
3204     cleanupAfterGraphicsCall(false);
3205 }
3206
3207 void WebGLRenderingContext::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
3208 {
3209     if (isContextLost())
3210         return;
3211     switch (face) {
3212     case GraphicsContext3D::FRONT_AND_BACK:
3213         m_stencilMask = mask;
3214         m_stencilMaskBack = mask;
3215         break;
3216     case GraphicsContext3D::FRONT:
3217         m_stencilMask = mask;
3218         break;
3219     case GraphicsContext3D::BACK:
3220         m_stencilMaskBack = mask;
3221         break;
3222     default:
3223         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3224         return;
3225     }
3226     m_context->stencilMaskSeparate(face, mask);
3227     cleanupAfterGraphicsCall(false);
3228 }
3229
3230 void WebGLRenderingContext::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3231 {
3232     if (isContextLost())
3233         return;
3234     m_context->stencilOp(fail, zfail, zpass);
3235     cleanupAfterGraphicsCall(false);
3236 }
3237
3238 void WebGLRenderingContext::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3239 {
3240     if (isContextLost())
3241         return;
3242     m_context->stencilOpSeparate(face, fail, zfail, zpass);
3243     cleanupAfterGraphicsCall(false);
3244 }
3245
3246 void WebGLRenderingContext::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3247                                            GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3248                                            GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3249 {
3250     // FIXME: For now we ignore any errors returned
3251     ec = 0;
3252     if (!validateTexFuncParameters(target, level, internalformat, width, height, border, format, type))
3253         return;
3254     WebGLTexture* tex = validateTextureBinding(target, true);
3255     if (!tex)
3256         return;
3257     if (!isGLES2NPOTStrict()) {
3258         if (level && WebGLTexture::isNPOT(width, height)) {
3259             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3260             return;
3261         }
3262     }
3263     if (!pixels) {
3264         bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
3265                                                          border, format, type, m_unpackAlignment);
3266         if (!succeed)
3267             return;
3268     } else {
3269         m_context->texImage2D(target, level, internalformat, width, height,
3270                               border, format, type, pixels);
3271     }
3272     tex->setLevelInfo(target, level, internalformat, width, height, type);
3273     cleanupAfterGraphicsCall(false);
3274 }
3275
3276 void WebGLRenderingContext::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3277                                            GC3Denum format, GC3Denum type, Image* image,
3278                                            bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3279 {
3280     ec = 0;
3281     Vector<uint8_t> data;
3282     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3283         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3284         return;
3285     }
3286     if (m_unpackAlignment != 1)
3287         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3288     texImage2DBase(target, level, internalformat, image->width(), image->height(), 0,
3289                    format, type, data.data(), ec);
3290     if (m_unpackAlignment != 1)
3291         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3292 }
3293
3294 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3295                                        GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3296                                        GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3297 {
3298     if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
3299         return;
3300     void* data = pixels ? pixels->baseAddress() : 0;
3301     Vector<uint8_t> tempData;
3302     bool changeUnpackAlignment = false;
3303     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3304         if (!m_context->extractTextureData(width, height, format, type,
3305                                            m_unpackAlignment,
3306                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3307                                            data,
3308                                            tempData))
3309             return;
3310         data = tempData.data();
3311         changeUnpackAlignment = true;
3312     }
3313     if (changeUnpackAlignment)
3314         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3315     texImage2DBase(target, level, internalformat, width, height, border,
3316                    format, type, data, ec);
3317     if (changeUnpackAlignment)
3318         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3319 }
3320
3321 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3322                                        GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3323 {
3324     ec = 0;
3325     if (isContextLost())
3326         return;
3327     Vector<uint8_t> data;
3328     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3329         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3330         return;
3331     }
3332     if (m_unpackAlignment != 1)
3333         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3334     texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0,
3335                    format, type, data.data(), ec);
3336     if (m_unpackAlignment != 1)
3337         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3338 }
3339
3340 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3341                                        GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3342 {
3343     ec = 0;
3344     if (isContextLost())
3345         return;
3346     if (!validateHTMLImageElement(image))
3347         return;
3348     if (wouldTaintOrigin(image)) {
3349         ec = SECURITY_ERR;
3350         return;
3351     }
3352
3353     texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->imageForRenderer(image->renderer()),
3354                    m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3355 }
3356
3357 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3358                                        GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3359 {
3360     ec = 0;
3361     if (isContextLost())
3362         return;
3363     if (!canvas || !canvas->buffer()) {
3364         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3365         return;
3366     }
3367     if (wouldTaintOrigin(canvas)) {
3368         ec = SECURITY_ERR;
3369         return;
3370     }
3371     RefPtr<ImageData> imageData = canvas->getImageData();
3372     if (imageData)
3373         texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
3374     else
3375         texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(),
3376                        m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3377 }
3378
3379 #if ENABLE(VIDEO)
3380 PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video, ExceptionCode& ec)
3381 {
3382     if (!video || !video->videoWidth() || !video->videoHeight()) {
3383         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3384         return 0;
3385     }
3386     IntSize size(video->videoWidth(), video->videoHeight());
3387     ImageBuffer* buf = m_videoCache.imageBuffer(size);
3388     if (!buf) {
3389         m_context->synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY);
3390         return 0;
3391     }
3392     if (wouldTaintOrigin(video)) {
3393         ec = SECURITY_ERR;
3394         return 0;
3395     }
3396     IntRect destRect(0, 0, size.width(), size.height());
3397     // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
3398     video->paintCurrentFrameInContext(buf->context(), destRect);
3399     return buf->copyImage(CopyBackingStore);
3400 }
3401
3402 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3403                                        GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3404 {
3405     ec = 0;
3406     if (isContextLost())
3407         return;
3408     RefPtr<Image> image = videoFrameToImage(video, ec);
3409     if (!image)
3410         return;
3411     texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3412 }
3413 #endif
3414
3415 void WebGLRenderingContext::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
3416 {
3417     if (isContextLost())
3418         return;
3419     WebGLTexture* tex = validateTextureBinding(target, false);
3420     if (!tex)
3421         return;
3422     switch (pname) {
3423     case GraphicsContext3D::TEXTURE_MIN_FILTER:
3424     case GraphicsContext3D::TEXTURE_MAG_FILTER:
3425         break;
3426     case GraphicsContext3D::TEXTURE_WRAP_S:
3427     case GraphicsContext3D::TEXTURE_WRAP_T:
3428         if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT)
3429             || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) {
3430             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3431             return;
3432         }
3433         break;
3434     default:
3435         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3436         return;
3437     }
3438     if (isFloat) {
3439         tex->setParameterf(pname, paramf);
3440         m_context->texParameterf(target, pname, paramf);
3441     } else {
3442         tex->setParameteri(pname, parami);
3443         m_context->texParameteri(target, pname, parami);
3444     }
3445     cleanupAfterGraphicsCall(false);
3446 }
3447
3448 void WebGLRenderingContext::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
3449 {
3450     texParameter(target, pname, param, 0, true);
3451 }
3452
3453 void WebGLRenderingContext::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
3454 {
3455     texParameter(target, pname, 0, param, false);
3456 }
3457
3458 void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3459                                               GC3Dsizei width, GC3Dsizei height,
3460                                               GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3461 {
3462     // FIXME: For now we ignore any errors returned
3463     ec = 0;
3464     if (isContextLost())
3465         return;
3466     if (!validateTexFuncParameters(target, level, format, width, height, 0, format, type))
3467         return;
3468     if (!validateSize(xoffset, yoffset))
3469         return;
3470     WebGLTexture* tex = validateTextureBinding(target, true);
3471     if (!tex)
3472         return;
3473     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
3474         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3475         return;
3476     }
3477     if (tex->getInternalFormat(target, level) != format || tex->getType(target, level) != type) {
3478         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3479         return;
3480     }
3481     m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
3482     cleanupAfterGraphicsCall(false);
3483 }
3484
3485 void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3486                                               GC3Denum format, GC3Denum type,
3487                                               Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3488 {
3489     ec = 0;
3490     if (isContextLost())
3491         return;
3492     Vector<uint8_t> data;
3493     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3494         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3495         return;
3496     }
3497     texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(),
3498                       format, type, data.data(), ec);
3499 }
3500
3501 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3502                                           GC3Dsizei width, GC3Dsizei height,
3503                                           GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3504 {
3505     if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
3506         return;
3507     void* data = pixels ? pixels->baseAddress() : 0;
3508     Vector<uint8_t> tempData;
3509     bool changeUnpackAlignment = false;
3510     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3511         if (!m_context->extractTextureData(width, height, format, type,
3512                                            m_unpackAlignment,
3513                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3514                                            data,
3515                                            tempData))
3516             return;
3517         data = tempData.data();
3518         changeUnpackAlignment = true;
3519     }
3520     if (changeUnpackAlignment)
3521         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3522     texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
3523     if (changeUnpackAlignment)
3524         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3525 }
3526
3527 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3528                                           GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3529 {
3530     ec = 0;
3531     if (isContextLost())
3532         return;
3533     Vector<uint8_t> data;
3534     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3535         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3536         return;
3537     }
3538     texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(),
3539                       format, type, data.data(), ec);
3540 }
3541
3542 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3543                                           GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3544 {
3545     ec = 0;
3546     if (isContextLost())
3547         return;
3548     if (!validateHTMLImageElement(image))
3549         return;
3550     if (wouldTaintOrigin(image)) {
3551         ec = SECURITY_ERR;
3552         return;
3553     }
3554     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image->cachedImage()->imageForRenderer(image->renderer()),
3555                       m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3556 }
3557
3558 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3559                                           GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3560 {
3561     ec = 0;
3562     if (isContextLost())
3563         return;
3564     if (!canvas || !canvas->buffer()) {
3565         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3566         return;
3567     }
3568     if (wouldTaintOrigin(canvas)) {
3569         ec = SECURITY_ERR;
3570         return;
3571     }
3572     RefPtr<ImageData> imageData = canvas->getImageData();
3573     if (imageData)
3574         texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec);
3575     else
3576         texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(),
3577                           m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3578 }
3579
3580 #if ENABLE(VIDEO)
3581 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3582                                           GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3583 {
3584     ec = 0;
3585     if (isContextLost())
3586         return;
3587     RefPtr<Image> image = videoFrameToImage(video, ec);
3588     if (!image)
3589         return;
3590     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3591 }
3592 #endif
3593
3594 void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode& ec)
3595 {
3596     UNUSED_PARAM(ec);
3597     if (isContextLost() || !location)
3598         return;
3599
3600     if (location->program() != m_currentProgram) {
3601         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3602         return;
3603     }
3604
3605     m_context->uniform1f(location->location(), x);
3606     cleanupAfterGraphicsCall(false);
3607 }
3608
3609 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3610 {
3611     UNUSED_PARAM(ec);
3612     if (isContextLost() || !validateUniformParameters(location, v, 1))
3613         return;
3614
3615     m_context->uniform1fv(location->location(), v->data(), v->length());
3616     cleanupAfterGraphicsCall(false);
3617 }
3618
3619 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3620 {
3621     UNUSED_PARAM(ec);
3622     if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3623         return;
3624
3625     m_context->uniform1fv(location->location(), v, size);
3626     cleanupAfterGraphicsCall(false);
3627 }
3628
3629 void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode& ec)
3630 {
3631     UNUSED_PARAM(ec);
3632     if (isContextLost() || !location)
3633         return;
3634
3635     if (location->program() != m_currentProgram) {
3636         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3637         return;
3638     }
3639
3640     m_context->uniform1i(location->location(), x);
3641     cleanupAfterGraphicsCall(false);
3642 }
3643
3644 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3645 {
3646     UNUSED_PARAM(ec);
3647     if (isContextLost() || !validateUniformParameters(location, v, 1))
3648         return;
3649
3650     m_context->uniform1iv(location->location(), v->data(), v->length());
3651     cleanupAfterGraphicsCall(false);
3652 }
3653
3654 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3655 {
3656     UNUSED_PARAM(ec);
3657     if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3658         return;
3659
3660     m_context->uniform1iv(location->location(), v, size);
3661     cleanupAfterGraphicsCall(false);
3662 }
3663
3664 void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode& ec)
3665 {
3666     UNUSED_PARAM(ec);
3667     if (isContextLost() || !location)
3668         return;
3669
3670     if (location->program() != m_currentProgram) {
3671         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3672         return;
3673     }
3674
3675     m_context->uniform2f(location->location(), x, y);
3676     cleanupAfterGraphicsCall(false);
3677 }
3678
3679 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3680 {
3681     UNUSED_PARAM(ec);
3682     if (isContextLost() || !validateUniformParameters(location, v, 2))
3683         return;
3684
3685     m_context->uniform2fv(location->location(), v->data(), v->length() / 2);
3686     cleanupAfterGraphicsCall(false);
3687 }
3688
3689 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3690 {
3691     UNUSED_PARAM(ec);
3692     if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3693         return;
3694
3695     m_context->uniform2fv(location->location(), v, size / 2);
3696     cleanupAfterGraphicsCall(false);
3697 }
3698
3699 void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode& ec)
3700 {
3701     UNUSED_PARAM(ec);
3702     if (isContextLost() || !location)
3703         return;
3704
3705     if (location->program() != m_currentProgram) {
3706         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3707         return;
3708     }
3709
3710     m_context->uniform2i(location->location(), x, y);
3711     cleanupAfterGraphicsCall(false);
3712 }
3713
3714 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3715 {
3716     UNUSED_PARAM(ec);
3717     if (isContextLost() || !validateUniformParameters(location, v, 2))
3718         return;
3719
3720     m_context->uniform2iv(location->location(), v->data(), v->length() / 2);
3721     cleanupAfterGraphicsCall(false);
3722 }
3723
3724 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3725 {
3726     UNUSED_PARAM(ec);
3727     if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3728         return;
3729
3730     m_context->uniform2iv(location->location(), v, size / 2);
3731     cleanupAfterGraphicsCall(false);
3732 }
3733
3734 void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode& ec)
3735 {
3736     UNUSED_PARAM(ec);
3737     if (isContextLost() || !location)
3738         return;
3739
3740     if (location->program() != m_currentProgram) {
3741         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3742         return;
3743     }
3744
3745     m_context->uniform3f(location->location(), x, y, z);
3746     cleanupAfterGraphicsCall(false);
3747 }
3748
3749 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3750 {
3751     UNUSED_PARAM(ec);
3752     if (isContextLost() || !validateUniformParameters(location, v, 3))
3753         return;
3754
3755     m_context->uniform3fv(location->location(), v->data(), v->length() / 3);
3756     cleanupAfterGraphicsCall(false);
3757 }
3758
3759 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3760 {
3761     UNUSED_PARAM(ec);
3762     if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3763         return;
3764
3765     m_context->uniform3fv(location->location(), v, size / 3);
3766     cleanupAfterGraphicsCall(false);
3767 }
3768
3769 void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode& ec)
3770 {
3771     UNUSED_PARAM(ec);
3772     if (isContextLost() || !location)
3773         return;
3774
3775     if (location->program() != m_currentProgram) {
3776         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3777         return;
3778     }
3779
3780     m_context->uniform3i(location->location(), x, y, z);
3781     cleanupAfterGraphicsCall(false);
3782 }
3783
3784 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3785 {
3786     UNUSED_PARAM(ec);
3787     if (isContextLost() || !validateUniformParameters(location, v, 3))
3788         return;
3789
3790     m_context->uniform3iv(location->location(), v->data(), v->length() / 3);
3791     cleanupAfterGraphicsCall(false);
3792 }
3793
3794 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3795 {
3796     UNUSED_PARAM(ec);
3797     if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3798         return;
3799
3800     m_context->uniform3iv(location->location(), v, size / 3);
3801     cleanupAfterGraphicsCall(false);
3802 }
3803
3804 void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode& ec)
3805 {
3806     UNUSED_PARAM(ec);
3807     if (isContextLost() || !location)
3808         return;
3809
3810     if (location->program() != m_currentProgram) {
3811         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3812         return;
3813     }
3814
3815     m_context->uniform4f(location->location(), x, y, z, w);
3816     cleanupAfterGraphicsCall(false);
3817 }
3818
3819 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3820 {
3821     UNUSED_PARAM(ec);
3822     if (isContextLost() || !validateUniformParameters(location, v, 4))