[CherryPick] Set the initial scissor box for WebGL
[framework/web/webkit-efl.git] / Source / WebCore / html / canvas / WebGLRenderingContext.cpp
1 /*
2  * Copyright (C) 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(WEBGL)
29
30 #include "WebGLRenderingContext.h"
31
32 #include "CachedImage.h"
33 #include "CheckedInt.h"
34 #include "Console.h"
35 #include "DOMWindow.h"
36 #include "EXTTextureFilterAnisotropic.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 "Settings.h"
54 #include "WebGLActiveInfo.h"
55 #include "WebGLBuffer.h"
56 #include "WebGLCompressedTextureS3TC.h"
57 #include "WebGLContextAttributes.h"
58 #include "WebGLContextEvent.h"
59 #include "WebGLContextGroup.h"
60 #include "WebGLDebugRendererInfo.h"
61 #include "WebGLDebugShaders.h"
62 #include "WebGLDepthTexture.h"
63 #include "WebGLFramebuffer.h"
64 #include "WebGLLoseContext.h"
65 #include "WebGLProgram.h"
66 #include "WebGLRenderbuffer.h"
67 #include "WebGLShader.h"
68 #include "WebGLShaderPrecisionFormat.h"
69 #include "WebGLTexture.h"
70 #include "WebGLUniformLocation.h"
71
72 #include <wtf/OwnArrayPtr.h>
73 #include <wtf/PassOwnArrayPtr.h>
74 #include <wtf/Uint16Array.h>
75 #include <wtf/Uint32Array.h>
76 #include <wtf/text/StringBuilder.h>
77
78 #if PLATFORM(QT)
79 #undef emit
80 #endif
81
82 namespace WebCore {
83
84 const double secondsBetweenRestoreAttempts = 1.0;
85 const int maxGLErrorsAllowedToConsole = 256;
86
87 namespace {
88
89     class ScopedDrawingBufferBinder {
90     public:
91         ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer* framebufferBinding)
92             : m_drawingBuffer(drawingBuffer)
93             , m_framebufferBinding(framebufferBinding)
94         {
95             // Commit DrawingBuffer if needed (e.g., for multisampling)
96             if (!m_framebufferBinding && m_drawingBuffer)
97                 m_drawingBuffer->commit();
98         }
99
100         ~ScopedDrawingBufferBinder()
101         {
102             // Restore DrawingBuffer if needed
103             if (!m_framebufferBinding && m_drawingBuffer)
104                 m_drawingBuffer->bind();
105         }
106
107     private:
108         DrawingBuffer* m_drawingBuffer;
109         WebGLFramebuffer* m_framebufferBinding;
110     };
111
112     Platform3DObject objectOrZero(WebGLObject* object)
113     {
114         return object ? object->object() : 0;
115     }
116
117     void clip1D(GC3Dint start, GC3Dsizei range, GC3Dsizei sourceRange, GC3Dint* clippedStart, GC3Dsizei* clippedRange)
118     {
119         ASSERT(clippedStart && clippedRange);
120         if (start < 0) {
121             range += start;
122             start = 0;
123         }
124         GC3Dint end = start + range;
125         if (end > sourceRange)
126             range -= end - sourceRange;
127         *clippedStart = start;
128         *clippedRange = range;
129     }
130
131     // Returns false if no clipping is necessary, i.e., x, y, width, height stay the same.
132     bool clip2D(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height,
133                 GC3Dsizei sourceWidth, GC3Dsizei sourceHeight,
134                 GC3Dint* clippedX, GC3Dint* clippedY, GC3Dsizei* clippedWidth, GC3Dsizei*clippedHeight)
135     {
136         ASSERT(clippedX && clippedY && clippedWidth && clippedHeight);
137         clip1D(x, width, sourceWidth, clippedX, clippedWidth);
138         clip1D(y, height, sourceHeight, clippedY, clippedHeight);
139         return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height);
140     }
141
142     GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
143     {
144         if (value < min)
145             value = min;
146         if (value > max)
147             value = max;
148         return value;
149     }
150
151     // Return true if a character belongs to the ASCII subset as defined in
152     // GLSL ES 1.0 spec section 3.1.
153     bool validateCharacter(unsigned char c)
154     {
155         // Printing characters are valid except " $ ` @ \ ' DEL.
156         if (c >= 32 && c <= 126
157             && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
158             return true;
159         // Horizontal tab, line feed, vertical tab, form feed, carriage return
160         // are also valid.
161         if (c >= 9 && c <= 13)
162             return true;
163         return false;
164     }
165
166     bool isPrefixReserved(const String& name)
167     {
168         if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_"))
169             return true;
170         return false;
171     }
172
173     // Strips comments from shader text. This allows non-ASCII characters
174     // to be used in comments without potentially breaking OpenGL
175     // implementations not expecting characters outside the GLSL ES set.
176     class StripComments {
177     public:
178         StripComments(const String& str)
179             : m_parseState(BeginningOfLine)
180             , m_sourceString(str)
181             , m_length(str.length())
182             , m_position(0)
183         {
184             parse();
185         }
186
187         String result()
188         {
189             return m_builder.toString();
190         }
191
192     private:
193         bool hasMoreCharacters()
194         {
195             return (m_position < m_length);
196         }
197
198         void parse()
199         {
200             while (hasMoreCharacters()) {
201                 process(current());
202                 // process() might advance the position.
203                 if (hasMoreCharacters())
204                     advance();
205             }
206         }
207
208         void process(UChar);
209
210         bool peek(UChar& character)
211         {
212             if (m_position + 1 >= m_length)
213                 return false;
214             character = m_sourceString[m_position + 1];
215             return true;
216         }
217
218         UChar current()
219         {
220             ASSERT(m_position < m_length);
221             return m_sourceString[m_position];
222         }
223
224         void advance()
225         {
226             ++m_position;
227         }
228
229         bool isNewline(UChar character)
230         {
231             // Don't attempt to canonicalize newline related characters.
232             return (character == '\n' || character == '\r');
233         }
234
235         void emit(UChar character)
236         {
237             m_builder.append(character);
238         }
239
240         enum ParseState {
241             // Have not seen an ASCII non-whitespace character yet on
242             // this line. Possible that we might see a preprocessor
243             // directive.
244             BeginningOfLine,
245
246             // Have seen at least one ASCII non-whitespace character
247             // on this line.
248             MiddleOfLine,
249
250             // Handling a preprocessor directive. Passes through all
251             // characters up to the end of the line. Disables comment
252             // processing.
253             InPreprocessorDirective,
254
255             // Handling a single-line comment. The comment text is
256             // replaced with a single space.
257             InSingleLineComment,
258
259             // Handling a multi-line comment. Newlines are passed
260             // through to preserve line numbers.
261             InMultiLineComment
262         };
263
264         ParseState m_parseState;
265         String m_sourceString;
266         unsigned m_length;
267         unsigned m_position;
268         StringBuilder m_builder;
269     };
270
271     void StripComments::process(UChar c)
272     {
273         if (isNewline(c)) {
274             // No matter what state we are in, pass through newlines
275             // so we preserve line numbers.
276             emit(c);
277
278             if (m_parseState != InMultiLineComment)
279                 m_parseState = BeginningOfLine;
280
281             return;
282         }
283
284         UChar temp = 0;
285         switch (m_parseState) {
286         case BeginningOfLine:
287             if (WTF::isASCIISpace(c)) {
288                 emit(c);
289                 break;
290             }
291
292             if (c == '#') {
293                 m_parseState = InPreprocessorDirective;
294                 emit(c);
295                 break;
296             }
297
298             // Transition to normal state and re-handle character.
299             m_parseState = MiddleOfLine;
300             process(c);
301             break;
302
303         case MiddleOfLine:
304             if (c == '/' && peek(temp)) {
305                 if (temp == '/') {
306                     m_parseState = InSingleLineComment;
307                     emit(' ');
308                     advance();
309                     break;
310                 }
311
312                 if (temp == '*') {
313                     m_parseState = InMultiLineComment;
314                     // Emit the comment start in case the user has
315                     // an unclosed comment and we want to later
316                     // signal an error.
317                     emit('/');
318                     emit('*');
319                     advance();
320                     break;
321                 }
322             }
323
324             emit(c);
325             break;
326
327         case InPreprocessorDirective:
328             // No matter what the character is, just pass it
329             // through. Do not parse comments in this state. This
330             // might not be the right thing to do long term, but it
331             // should handle the #error preprocessor directive.
332             emit(c);
333             break;
334
335         case InSingleLineComment:
336             // The newline code at the top of this function takes care
337             // of resetting our state when we get out of the
338             // single-line comment. Swallow all other characters.
339             break;
340
341         case InMultiLineComment:
342             if (c == '*' && peek(temp) && temp == '/') {
343                 emit('*');
344                 emit('/');
345                 m_parseState = MiddleOfLine;
346                 advance();
347                 break;
348             }
349
350             // Swallow all other characters. Unclear whether we may
351             // want or need to just emit a space per character to try
352             // to preserve column numbers for debugging purposes.
353             break;
354         }
355     }
356 } // namespace anonymous
357
358 class WebGLStateRestorer {
359 public:
360     WebGLStateRestorer(WebGLRenderingContext* context,
361                        bool changed)
362         : m_context(context)
363         , m_changed(changed)
364     {
365     }
366
367     ~WebGLStateRestorer()
368     {
369         m_context->cleanupAfterGraphicsCall(m_changed);
370     }
371
372 private:
373     WebGLRenderingContext* m_context;
374     bool m_changed;
375 };
376
377 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
378 public:
379     explicit WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_context(cb) { }
380     virtual void onContextLost() { m_context->forceLostContext(WebGLRenderingContext::RealLostContext); }
381     virtual ~WebGLRenderingContextLostCallback() {}
382 private:
383     WebGLRenderingContext* m_context;
384 };
385
386 class WebGLRenderingContextErrorMessageCallback : public GraphicsContext3D::ErrorMessageCallback {
387 public:
388     explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContext* cb) : m_context(cb) { }
389     virtual void onErrorMessage(const String& message, GC3Dint) { m_context->printGLErrorToConsole(message); }
390     virtual ~WebGLRenderingContextErrorMessageCallback() { }
391 private:
392     WebGLRenderingContext* m_context;
393 };
394
395 PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs)
396 {
397     HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow();
398     GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
399
400     if (attributes.antialias) {
401         Page* p = canvas->document()->page();
402         if (p && !p->settings()->openGLMultisamplingEnabled())
403             attributes.antialias = false;
404     }
405
406     attributes.noExtensions = true;
407 #if PLATFORM(CHROMIUM)
408     attributes.shareResources = true;
409 #else
410     attributes.shareResources = false;
411 #endif
412     attributes.preferDiscreteGPU = true;
413
414
415     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
416
417     if (!context || !context->makeContextCurrent()) {
418         canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
419         return nullptr;
420     }
421
422     return adoptPtr(new WebGLRenderingContext(canvas, context, attributes));
423 }
424
425 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
426                                              GraphicsContext3D::Attributes attributes)
427     : CanvasRenderingContext(passedCanvas)
428     , m_context(context)
429     , m_drawingBuffer(0)
430     , m_dispatchContextLostEventTimer(this, &WebGLRenderingContext::dispatchContextLostEvent)
431     , m_restoreAllowed(false)
432     , m_restoreTimer(this, &WebGLRenderingContext::maybeRestoreContext)
433     , m_videoCache(4)
434     , m_contextLost(false)
435     , m_contextLostMode(SyntheticLostContext)
436     , m_attributes(attributes)
437     , m_synthesizedErrorsToConsole(false)
438     , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
439 {
440     ASSERT(m_context);
441     m_contextGroup = WebGLContextGroup::create();
442     m_contextGroup->addContext(this);
443
444     m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
445     m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
446
447 #if PLATFORM(CHROMIUM)
448     // Create the DrawingBuffer and initialize the platform layer.
449     DrawingBuffer::PreserveDrawingBuffer preserve = m_attributes.preserveDrawingBuffer ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
450     DrawingBuffer::AlphaRequirement alpha = m_attributes.alpha ? DrawingBuffer::Alpha : DrawingBuffer::Opaque;
451     m_drawingBuffer = DrawingBuffer::create(m_context.get(), clampedCanvasSize(), preserve, alpha);
452 #endif
453
454     if (m_drawingBuffer)
455         m_drawingBuffer->bind();
456
457     setupFlags();
458     initializeNewContext();
459 }
460
461 void WebGLRenderingContext::initializeNewContext()
462 {
463     ASSERT(!m_contextLost);
464     m_needsUpdate = true;
465     m_markedCanvasDirty = false;
466     m_activeTextureUnit = 0;
467     m_packAlignment = 4;
468     m_unpackAlignment = 4;
469     m_unpackFlipY = false;
470     m_unpackPremultiplyAlpha = false;
471     m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
472     m_boundArrayBuffer = 0;
473     m_currentProgram = 0;
474     m_framebufferBinding = 0;
475     m_renderbufferBinding = 0;
476     m_depthMask = true;
477     m_stencilEnabled = false;
478     m_stencilMask = 0xFFFFFFFF;
479     m_stencilMaskBack = 0xFFFFFFFF;
480     m_stencilFuncRef = 0;
481     m_stencilFuncRefBack = 0;
482     m_stencilFuncMask = 0xFFFFFFFF;
483     m_stencilFuncMaskBack = 0xFFFFFFFF;
484     m_layerCleared = false;
485     m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
486     
487     m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
488     m_scissorEnabled = false;
489     m_clearDepth = 1;
490     m_clearStencil = 0;
491     m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
492
493     GC3Dint numCombinedTextureImageUnits = 0;
494     m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
495     m_textureUnits.clear();
496     m_textureUnits.resize(numCombinedTextureImageUnits);
497
498     GC3Dint numVertexAttribs = 0;
499     m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
500     m_maxVertexAttribs = numVertexAttribs;
501     
502     m_maxTextureSize = 0;
503     m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
504     m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
505     m_maxCubeMapTextureSize = 0;
506     m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
507     m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
508     m_maxRenderbufferSize = 0;
509     m_context->getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
510
511     m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
512     addContextObject(m_defaultVertexArrayObject.get());
513     m_boundVertexArrayObject = m_defaultVertexArrayObject;
514     
515     m_vertexAttribValue.resize(m_maxVertexAttribs);
516
517     if (!isGLES2NPOTStrict())
518         createFallbackBlackTextures1x1();
519     if (!isGLES2Compliant())
520         initVertexAttrib0();
521
522     IntSize canvasSize = clampedCanvasSize();
523     if (m_drawingBuffer)
524         m_drawingBuffer->reset(canvasSize);
525
526     m_context->reshape(canvasSize.width(), canvasSize.height());
527     m_context->viewport(0, 0, canvasSize.width(), canvasSize.height());
528     m_context->scissor(0, 0, canvasSize.width(), canvasSize.height());
529
530     m_context->setContextLostCallback(adoptPtr(new WebGLRenderingContextLostCallback(this)));
531     m_context->setErrorMessageCallback(adoptPtr(new WebGLRenderingContextErrorMessageCallback(this)));
532 }
533
534 void WebGLRenderingContext::setupFlags()
535 {
536     ASSERT(m_context);
537
538     Page* p = canvas()->document()->page();
539     if (p && p->settings()->webGLErrorsToConsoleEnabled())
540         m_synthesizedErrorsToConsole = true;
541
542     m_isGLES2Compliant = m_context->isGLES2Compliant();
543     m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs");
544     m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe");
545     if (m_isGLES2Compliant) {
546         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
547         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
548     } else {
549         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two");
550         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil");
551     }
552 }
553
554 bool WebGLRenderingContext::allowPrivilegedExtensions() const
555 {
556     Page* p = canvas()->document()->page();
557     if (p && p->settings())
558         return p->settings()->privilegedWebGLExtensionsEnabled();
559     return false;
560 }
561
562 void WebGLRenderingContext::addCompressedTextureFormat(GC3Denum format)
563 {
564     if (!m_compressedTextureFormats.contains(format))
565         m_compressedTextureFormats.append(format);
566 }
567
568 WebGLRenderingContext::~WebGLRenderingContext()
569 {
570     // Remove all references to WebGLObjects so if they are the last reference
571     // they will be freed before the last context is removed from the context group.
572     m_boundArrayBuffer = 0;
573     m_defaultVertexArrayObject = 0;
574     m_boundVertexArrayObject = 0;
575     m_vertexAttrib0Buffer = 0;
576     m_currentProgram = 0;
577     m_framebufferBinding = 0;
578     m_renderbufferBinding = 0;
579
580     for (size_t i = 0; i < m_textureUnits.size(); ++i) {
581       m_textureUnits[i].m_texture2DBinding = 0;
582       m_textureUnits[i].m_textureCubeMapBinding = 0;
583     }
584
585     m_blackTexture2D = 0;
586     m_blackTextureCubeMap = 0;
587
588     detachAndRemoveAllObjects();
589     m_context->setContextLostCallback(nullptr);
590     m_context->setErrorMessageCallback(nullptr);
591     m_contextGroup->removeContext(this);
592 }
593
594 void WebGLRenderingContext::markContextChanged()
595 {
596     if (m_framebufferBinding)
597         return;
598
599     m_context->markContextChanged();
600
601     m_layerCleared = false;
602 #if USE(ACCELERATED_COMPOSITING)
603     RenderBox* renderBox = canvas()->renderBox();
604     if (renderBox && renderBox->hasAcceleratedCompositing()) {
605         m_markedCanvasDirty = true;
606         renderBox->contentChanged(CanvasChanged);
607     } else {
608 #endif
609         if (!m_markedCanvasDirty) {
610             m_markedCanvasDirty = true;
611             canvas()->didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize()));
612         }
613 #if USE(ACCELERATED_COMPOSITING)
614     }
615 #endif
616 }
617
618 bool WebGLRenderingContext::clearIfComposited(GC3Dbitfield mask)
619 {
620     if (isContextLost()) 
621         return false;
622
623     if (!m_context->layerComposited() || m_layerCleared
624         || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
625         return false;
626
627     RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
628
629     // Determine if it's possible to combine the clear the user asked for and this clear.
630     bool combinedClear = mask && !m_scissorEnabled;
631
632     m_context->disable(GraphicsContext3D::SCISSOR_TEST);
633     if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
634         m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
635                               m_colorMask[1] ? m_clearColor[1] : 0,
636                               m_colorMask[2] ? m_clearColor[2] : 0,
637                               m_colorMask[3] ? m_clearColor[3] : 0);
638     else
639         m_context->clearColor(0, 0, 0, 0);
640     m_context->colorMask(true, true, true, true);
641     GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
642     if (contextAttributes->depth()) {
643         if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
644             m_context->clearDepth(1.0f);
645         clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
646         m_context->depthMask(true);
647     }
648     if (contextAttributes->stencil()) {
649         if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
650             m_context->clearStencil(m_clearStencil & m_stencilMask);
651         else
652             m_context->clearStencil(0);
653         clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
654         m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
655     }
656     if (m_drawingBuffer)
657         m_drawingBuffer->clearFramebuffers(clearMask);
658     else {
659         if (m_framebufferBinding)
660             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
661         m_context->clear(clearMask);
662     }
663
664     restoreStateAfterClear();
665     if (m_framebufferBinding)
666         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
667     m_layerCleared = true;
668
669     return combinedClear;
670 }
671
672 void WebGLRenderingContext::restoreStateAfterClear()
673 {
674     // Restore the state that the context set.
675     if (m_scissorEnabled)
676         m_context->enable(GraphicsContext3D::SCISSOR_TEST);
677     m_context->clearColor(m_clearColor[0], m_clearColor[1],
678                           m_clearColor[2], m_clearColor[3]);
679     m_context->colorMask(m_colorMask[0], m_colorMask[1],
680                          m_colorMask[2], m_colorMask[3]);
681     m_context->clearDepth(m_clearDepth);
682     m_context->clearStencil(m_clearStencil);
683     m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
684     m_context->depthMask(m_depthMask);
685 }
686
687 void WebGLRenderingContext::markLayerComposited()
688 {
689     m_context->markLayerComposited();
690 }
691
692 void WebGLRenderingContext::paintRenderingResultsToCanvas()
693 {
694     // Until the canvas is written to by the application, the clear that
695     // happened after it was composited should be ignored by the compositor.
696     if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
697         m_context->paintCompositedResultsToCanvas(canvas()->buffer());
698
699 #if USE(ACCELERATED_COMPOSITING) && PLATFORM(CHROMIUM)
700         if (m_drawingBuffer)
701             m_drawingBuffer->paintCompositedResultsToCanvas(canvas()->buffer());
702 #endif
703
704         canvas()->makePresentationCopy();
705     } else
706         canvas()->clearPresentationCopy();
707     clearIfComposited();
708
709     if (!m_markedCanvasDirty && !m_layerCleared)
710         return;
711
712     canvas()->clearCopiedImage();
713     m_markedCanvasDirty = false;
714
715     if (m_drawingBuffer)
716         m_drawingBuffer->commit();
717     m_context->paintRenderingResultsToCanvas(canvas()->buffer(), m_drawingBuffer.get());
718
719     if (m_drawingBuffer) {
720         if (m_framebufferBinding)
721             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
722         else
723             m_drawingBuffer->bind();
724     }
725 }
726
727 PassRefPtr<ImageData> WebGLRenderingContext::paintRenderingResultsToImageData()
728 {
729     clearIfComposited();
730     if (m_drawingBuffer)
731         m_drawingBuffer->commit();
732     RefPtr<ImageData> imageData = m_context->paintRenderingResultsToImageData(m_drawingBuffer.get());
733
734     if (m_drawingBuffer) {
735         if (m_framebufferBinding)
736             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
737         else
738             m_drawingBuffer->bind();
739     }
740
741     return imageData;
742 }
743
744 void WebGLRenderingContext::reshape(int width, int height)
745 {
746     // This is an approximation because at WebGLRenderingContext level we don't
747     // know if the underlying FBO uses textures or renderbuffers.
748     GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
749     // Limit drawing buffer size to 4k to avoid memory exhaustion.
750     const int sizeUpperLimit = 4096;
751     maxSize = std::min(maxSize, sizeUpperLimit);
752     GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
753     GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
754     width = clamp(width, 1, maxWidth);
755     height = clamp(height, 1, maxHeight);
756
757     if (m_needsUpdate) {
758 #if USE(ACCELERATED_COMPOSITING)
759         RenderBox* renderBox = canvas()->renderBox();
760         if (renderBox && renderBox->hasAcceleratedCompositing())
761             renderBox->contentChanged(CanvasChanged);
762 #endif
763         m_needsUpdate = false;
764     }
765
766     // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
767     // clear (and this matches what reshape will do).
768     if (m_drawingBuffer) {
769         m_drawingBuffer->reset(IntSize(width, height));
770         restoreStateAfterClear();
771     } else
772         m_context->reshape(width, height);
773
774     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()));
775     m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
776     if (m_framebufferBinding)
777       m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
778 }
779
780 int WebGLRenderingContext::drawingBufferWidth() const
781 {
782     if (m_drawingBuffer)
783         return m_drawingBuffer->size().width();
784
785     return m_context->getInternalFramebufferSize().width();
786 }
787
788 int WebGLRenderingContext::drawingBufferHeight() const
789 {
790     if (m_drawingBuffer)
791         return m_drawingBuffer->size().height();
792
793     return m_context->getInternalFramebufferSize().height();
794 }
795
796 unsigned int WebGLRenderingContext::sizeInBytes(GC3Denum type)
797 {
798     switch (type) {
799     case GraphicsContext3D::BYTE:
800         return sizeof(GC3Dbyte);
801     case GraphicsContext3D::UNSIGNED_BYTE:
802         return sizeof(GC3Dubyte);
803     case GraphicsContext3D::SHORT:
804         return sizeof(GC3Dshort);
805     case GraphicsContext3D::UNSIGNED_SHORT:
806         return sizeof(GC3Dushort);
807     case GraphicsContext3D::INT:
808         return sizeof(GC3Dint);
809     case GraphicsContext3D::UNSIGNED_INT:
810         return sizeof(GC3Duint);
811     case GraphicsContext3D::FLOAT:
812         return sizeof(GC3Dfloat);
813     }
814     ASSERT_NOT_REACHED();
815     return 0;
816 }
817
818 void WebGLRenderingContext::activeTexture(GC3Denum texture, ExceptionCode& ec)
819 {
820     UNUSED_PARAM(ec);
821     if (isContextLost())
822         return;
823     if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
824         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "activeTexture", "texture unit out of range");
825         return;
826     }
827     m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
828     m_context->activeTexture(texture);
829
830     if (m_drawingBuffer)
831         m_drawingBuffer->setActiveTextureUnit(texture);
832
833     cleanupAfterGraphicsCall(false);
834 }
835
836 void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
837 {
838     UNUSED_PARAM(ec);
839     if (isContextLost() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader))
840         return;
841     if (!program->attachShader(shader)) {
842         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "attachShader", "shader attachment already has shader");
843         return;
844     }
845     m_context->attachShader(objectOrZero(program), objectOrZero(shader));
846     shader->onAttached();
847     cleanupAfterGraphicsCall(false);
848 }
849
850 void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
851 {
852     UNUSED_PARAM(ec);
853     if (isContextLost() || !validateWebGLObject("bindAttribLocation", program))
854         return;
855     if (!validateLocationLength("bindAttribLocation", name))
856         return;
857     if (!validateString("bindAttribLocation", name))
858         return;
859     if (isPrefixReserved(name)) {
860         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindAttribLocation", "reserved prefix");
861         return;
862     }
863     if (index >= m_maxVertexAttribs) {
864         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bindAttribLocation", "index out of range");
865         return;
866     }
867     m_context->bindAttribLocation(objectOrZero(program), index, name);
868     cleanupAfterGraphicsCall(false);
869 }
870
871 bool WebGLRenderingContext::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted)
872 {
873     deleted = false;
874     if (isContextLost())
875         return false;
876     if (object) {
877         if (!object->validate(contextGroup(), this)) {
878             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object not from this context");
879             return false;
880         }
881         deleted = !object->object();
882     }
883     return true;
884 }
885
886 void WebGLRenderingContext::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec)
887 {
888     UNUSED_PARAM(ec);
889     bool deleted;
890     if (!checkObjectToBeBound("bindBuffer", buffer, deleted))
891         return;
892     if (deleted)
893         buffer = 0;
894     if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
895         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets");
896         return;
897     }
898     if (target == GraphicsContext3D::ARRAY_BUFFER)
899         m_boundArrayBuffer = buffer;
900     else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
901         m_boundVertexArrayObject->setElementArrayBuffer(buffer);
902     else {
903         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindBuffer", "invalid target");
904         return;
905     }
906
907     m_context->bindBuffer(target, objectOrZero(buffer));
908     if (buffer)
909         buffer->setTarget(target);
910     cleanupAfterGraphicsCall(false);
911 }
912
913 void WebGLRenderingContext::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec)
914 {
915     UNUSED_PARAM(ec);
916     bool deleted;
917     if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted))
918         return;
919     if (deleted)
920         buffer = 0;
921     if (target != GraphicsContext3D::FRAMEBUFFER) {
922         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindFramebuffer", "invalid target");
923         return;
924     }
925     m_framebufferBinding = buffer;
926     if (m_drawingBuffer)
927         m_drawingBuffer->setFramebufferBinding(objectOrZero(m_framebufferBinding.get()));
928     if (!m_framebufferBinding && m_drawingBuffer) {
929         // Instead of binding fb 0, bind the drawing buffer.
930         m_drawingBuffer->bind();
931     } else
932         m_context->bindFramebuffer(target, objectOrZero(buffer));
933     if (buffer)
934         buffer->setHasEverBeenBound();
935     applyStencilTest();
936     cleanupAfterGraphicsCall(false);
937 }
938
939 void WebGLRenderingContext::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
940 {
941     UNUSED_PARAM(ec);
942     bool deleted;
943     if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
944         return;
945     if (deleted)
946         renderBuffer = 0;
947     if (target != GraphicsContext3D::RENDERBUFFER) {
948         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindRenderbuffer", "invalid target");
949         return;
950     }
951     m_renderbufferBinding = renderBuffer;
952     m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
953     if (renderBuffer)
954         renderBuffer->setHasEverBeenBound();
955     cleanupAfterGraphicsCall(false);
956 }
957
958 void WebGLRenderingContext::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
959 {
960     UNUSED_PARAM(ec);
961     bool deleted;
962     if (!checkObjectToBeBound("bindTexture", texture, deleted))
963         return;
964     if (deleted)
965         texture = 0;
966     if (texture && texture->getTarget() && texture->getTarget() != target) {
967         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
968         return;
969     }
970     GC3Dint maxLevel = 0;
971     if (target == GraphicsContext3D::TEXTURE_2D) {
972         m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
973         maxLevel = m_maxTextureLevel;
974
975         if (m_drawingBuffer && !m_activeTextureUnit)
976             m_drawingBuffer->setTexture2DBinding(objectOrZero(texture));
977
978     } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
979         m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
980         maxLevel = m_maxCubeMapTextureLevel;
981     } else {
982         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindTexture", "invalid target");
983         return;
984     }
985     m_context->bindTexture(target, objectOrZero(texture));
986     if (texture)
987         texture->setTarget(target, maxLevel);
988
989     // Note: previously we used to automatically set the TEXTURE_WRAP_R
990     // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
991     // ES 2.0 doesn't expose this flag (a bug in the specification) and
992     // otherwise the application has no control over the seams in this
993     // dimension. However, it appears that supporting this properly on all
994     // platforms is fairly involved (will require a HashMap from texture ID
995     // in all ports), and we have not had any complaints, so the logic has
996     // been removed.
997
998     cleanupAfterGraphicsCall(false);
999 }
1000
1001 void WebGLRenderingContext::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
1002 {
1003     if (isContextLost())
1004         return;
1005     m_context->blendColor(red, green, blue, alpha);
1006     cleanupAfterGraphicsCall(false);
1007 }
1008
1009 void WebGLRenderingContext::blendEquation(GC3Denum mode)
1010 {
1011     if (isContextLost() || !validateBlendEquation("blendEquation", mode))
1012         return;
1013     m_context->blendEquation(mode);
1014     cleanupAfterGraphicsCall(false);
1015 }
1016
1017 void WebGLRenderingContext::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
1018 {
1019     if (isContextLost() || !validateBlendEquation("blendEquation", modeRGB) || !validateBlendEquation("blendEquation", modeAlpha))
1020         return;
1021     m_context->blendEquationSeparate(modeRGB, modeAlpha);
1022     cleanupAfterGraphicsCall(false);
1023 }
1024
1025
1026 void WebGLRenderingContext::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
1027 {
1028     if (isContextLost() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
1029         return;
1030     m_context->blendFunc(sfactor, dfactor);
1031     cleanupAfterGraphicsCall(false);
1032 }
1033
1034 void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
1035 {
1036     // Note: Alpha does not have the same restrictions as RGB.
1037     if (isContextLost() || !validateBlendFuncFactors("blendFunc", srcRGB, dstRGB))
1038         return;
1039     m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
1040     cleanupAfterGraphicsCall(false);
1041 }
1042
1043 void WebGLRenderingContext::bufferData(GC3Denum target, long long size, GC3Denum usage, ExceptionCode& ec)
1044 {
1045     UNUSED_PARAM(ec);
1046     if (isContextLost())
1047         return;
1048     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1049     if (!buffer)
1050         return;
1051     if (size < 0) {
1052         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size < 0");
1053         return;
1054     }
1055     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1056         if (!buffer->associateBufferData(static_cast<GC3Dsizeiptr>(size))) {
1057             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1058             return;
1059         }
1060     }
1061
1062     m_context->bufferData(target, static_cast<GC3Dsizeiptr>(size), usage);
1063     cleanupAfterGraphicsCall(false);
1064 }
1065
1066 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
1067 {
1068     UNUSED_PARAM(ec);
1069     if (isContextLost())
1070         return;
1071     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1072     if (!buffer)
1073         return;
1074     if (!data) {
1075         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1076         return;
1077     }
1078     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1079         if (!buffer->associateBufferData(data)) {
1080             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1081             return;
1082         }
1083     }
1084
1085     m_context->bufferData(target, data->byteLength(), data->data(), usage);
1086     cleanupAfterGraphicsCall(false);
1087 }
1088
1089 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
1090 {
1091     UNUSED_PARAM(ec);
1092     if (isContextLost())
1093         return;
1094     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1095     if (!buffer)
1096         return;
1097     if (!data) {
1098         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1099         return;
1100     }
1101     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1102         if (!buffer->associateBufferData(data)) {
1103             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1104             return;
1105         }
1106     }
1107
1108     m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
1109     cleanupAfterGraphicsCall(false);
1110 }
1111
1112 void WebGLRenderingContext::bufferSubData(GC3Denum target, long long offset, ArrayBuffer* data, ExceptionCode& ec)
1113 {
1114     UNUSED_PARAM(ec);
1115     if (isContextLost())
1116         return;
1117     WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1118     if (!buffer)
1119         return;
1120     if (offset < 0) {
1121         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1122         return;
1123     }
1124     if (!data)
1125         return;
1126     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1127         if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data)) {
1128             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1129             return;
1130         }
1131     }
1132
1133     m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->data());
1134     cleanupAfterGraphicsCall(false);
1135 }
1136
1137 void WebGLRenderingContext::bufferSubData(GC3Denum target, long long offset, ArrayBufferView* data, ExceptionCode& ec)
1138 {
1139     UNUSED_PARAM(ec);
1140     if (isContextLost())
1141         return;
1142     WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1143     if (!buffer)
1144         return;
1145     if (offset < 0) {
1146         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1147         return;
1148     }
1149     if (!data)
1150         return;
1151     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1152         if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data)) {
1153             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1154             return;
1155         }
1156     }
1157
1158     m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->baseAddress());
1159     cleanupAfterGraphicsCall(false);
1160 }
1161
1162 GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target)
1163 {
1164     if (isContextLost())
1165         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
1166     if (target != GraphicsContext3D::FRAMEBUFFER) {
1167         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "checkFramebufferStatus", "invalid target");
1168         return 0;
1169     }
1170     if (!m_framebufferBinding || !m_framebufferBinding->object())
1171         return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
1172     const char* reason = "framebuffer incomplete";
1173     GC3Denum result = m_framebufferBinding->checkStatus(&reason);
1174     if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
1175         printGLWarningToConsole("checkFramebufferStatus", reason);
1176         return result;
1177     }
1178     result = m_context->checkFramebufferStatus(target);
1179     cleanupAfterGraphicsCall(false);
1180     return result;
1181 }
1182
1183 void WebGLRenderingContext::clear(GC3Dbitfield mask)
1184 {
1185     if (isContextLost())
1186         return;
1187     if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
1188         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "clear", "invalid mask");
1189         return;
1190     }
1191     const char* reason = "framebuffer incomplete";
1192     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1193         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "clear", reason);
1194         return;
1195     }
1196     if (!clearIfComposited(mask))
1197         m_context->clear(mask);
1198     cleanupAfterGraphicsCall(true);
1199 }
1200
1201 void WebGLRenderingContext::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
1202 {
1203     if (isContextLost())
1204         return;
1205     if (isnan(r))
1206         r = 0;
1207     if (isnan(g))
1208         g = 0;
1209     if (isnan(b))
1210         b = 0;
1211     if (isnan(a))
1212         a = 1;
1213     m_clearColor[0] = r;
1214     m_clearColor[1] = g;
1215     m_clearColor[2] = b;
1216     m_clearColor[3] = a;
1217     m_context->clearColor(r, g, b, a);
1218     cleanupAfterGraphicsCall(false);
1219 }
1220
1221 void WebGLRenderingContext::clearDepth(GC3Dfloat depth)
1222 {
1223     if (isContextLost())
1224         return;
1225     m_clearDepth = depth;
1226     m_context->clearDepth(depth);
1227     cleanupAfterGraphicsCall(false);
1228 }
1229
1230 void WebGLRenderingContext::clearStencil(GC3Dint s)
1231 {
1232     if (isContextLost())
1233         return;
1234     m_clearStencil = s;
1235     m_context->clearStencil(s);
1236     cleanupAfterGraphicsCall(false);
1237 }
1238
1239 void WebGLRenderingContext::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1240 {
1241     if (isContextLost())
1242         return;
1243     m_colorMask[0] = red;
1244     m_colorMask[1] = green;
1245     m_colorMask[2] = blue;
1246     m_colorMask[3] = alpha;
1247     m_context->colorMask(red, green, blue, alpha);
1248     cleanupAfterGraphicsCall(false);
1249 }
1250
1251 void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec)
1252 {
1253     UNUSED_PARAM(ec);
1254     if (isContextLost() || !validateWebGLObject("compileShader", shader))
1255         return;
1256     m_context->compileShader(objectOrZero(shader));
1257     cleanupAfterGraphicsCall(false);
1258 }
1259
1260 void WebGLRenderingContext::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width,
1261                                                  GC3Dsizei height, GC3Dint border, ArrayBufferView* data)
1262 {
1263     if (isContextLost())
1264         return;
1265     if (!validateTexFuncLevel("compressedTexImage2D", target, level))
1266         return;
1267
1268     if (!validateCompressedTexFormat(internalformat)) {
1269         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
1270         return;
1271     }
1272     if (border) {
1273         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "border not 0");
1274         return;
1275     }
1276     if (!validateCompressedTexDimensions("compressedTexImage2D", level, width, height, internalformat))
1277         return;
1278     if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
1279         return;
1280
1281     WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
1282     if (!tex)
1283         return;
1284     if (!isGLES2NPOTStrict()) {
1285         if (level && WebGLTexture::isNPOT(width, height)) {
1286             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2");
1287             return;
1288         }
1289     }
1290     graphicsContext3D()->compressedTexImage2D(target, level, internalformat, width, height,
1291                                               border, data->byteLength(), data->baseAddress());
1292     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1293     cleanupAfterGraphicsCall(false);
1294 }
1295
1296 void WebGLRenderingContext::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
1297                                                     GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView* data)
1298 {
1299     if (isContextLost())
1300         return;
1301     if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
1302         return;
1303     if (!validateCompressedTexFormat(format)) {
1304         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
1305         return;
1306     }
1307     if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
1308         return;
1309
1310     WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
1311     if (!tex)
1312         return;
1313
1314     if (format != tex->getInternalFormat(target, level)) {
1315         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
1316         return;
1317     }
1318
1319     if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
1320         return;
1321
1322     graphicsContext3D()->compressedTexSubImage2D(target, level, xoffset, yoffset,
1323                                                  width, height, format, data->byteLength(), data->baseAddress());
1324     cleanupAfterGraphicsCall(false);
1325 }
1326
1327 bool WebGLRenderingContext::validateSettableTexFormat(const char* functionName, GC3Denum format)
1328 {
1329     if (GraphicsContext3D::getClearBitsByFormat(format) & (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
1330         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format can not be set, only rendered to");
1331         return false;
1332     }
1333     return true;
1334 }
1335
1336 void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
1337 {
1338     if (isContextLost())
1339         return;
1340     if (!validateTexFuncParameters("copyTexImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
1341         return;
1342     if (!validateSettableTexFormat("copyTexImage2D", internalformat))
1343         return;
1344     WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true);
1345     if (!tex)
1346         return;
1347     if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1348         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexImage2D", "framebuffer is incompatible format");
1349         return;
1350     }
1351     if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1352         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexImage2D", "level > 0 not power of 2");
1353         return;
1354     }
1355     const char* reason = "framebuffer incomplete";
1356     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1357         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D", reason);
1358         return;
1359     }
1360     clearIfComposited();
1361     if (isResourceSafe()) {
1362         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1363         m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1364     } else {
1365         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1366         GC3Dint clippedX, clippedY;
1367         GC3Dsizei clippedWidth, clippedHeight;
1368         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1369             m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
1370                                               internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment);
1371             if (clippedWidth > 0 && clippedHeight > 0) {
1372                 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
1373                                              clippedX, clippedY, clippedWidth, clippedHeight);
1374             }
1375         } else
1376             m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1377     }
1378     // FIXME: if the framebuffer is not complete, none of the below should be executed.
1379     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1380     cleanupAfterGraphicsCall(false);
1381 }
1382
1383 void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1384 {
1385     if (isContextLost())
1386         return;
1387     if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
1388         return;
1389     WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
1390     if (!tex)
1391         return;
1392     if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
1393         return;
1394     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1395         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
1396         return;
1397     }
1398     GC3Denum internalformat = tex->getInternalFormat(target, level);
1399     if (!validateSettableTexFormat("copyTexSubImage2D", internalformat))
1400         return;
1401     if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1402         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
1403         return;
1404     }
1405     const char* reason = "framebuffer incomplete";
1406     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1407         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", reason);
1408         return;
1409     }
1410     clearIfComposited();
1411     if (isResourceSafe()) {
1412         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1413         m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1414     } else {
1415         GC3Dint clippedX, clippedY;
1416         GC3Dsizei clippedWidth, clippedHeight;
1417         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1418             GC3Denum format = tex->getInternalFormat(target, level);
1419             GC3Denum type = tex->getType(target, level);
1420             OwnArrayPtr<unsigned char> zero;
1421             if (width && height) {
1422                 unsigned int size;
1423                 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1424                 if (error != GraphicsContext3D::NO_ERROR) {
1425                     synthesizeGLError(error, "copyTexSubImage2D", "bad dimensions");
1426                     return;
1427                 }
1428                 zero = adoptArrayPtr(new unsigned char[size]);
1429                 if (!zero) {
1430                     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "out of memory");
1431                     return;
1432                 }
1433                 memset(zero.get(), 0, size);
1434             }
1435             m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1436             if (clippedWidth > 0 && clippedHeight > 0) {
1437                 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1438                 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1439                                              clippedX, clippedY, clippedWidth, clippedHeight);
1440             }
1441         } else {
1442             ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1443             m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1444         }
1445     }
1446     cleanupAfterGraphicsCall(false);
1447 }
1448
1449 PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer()
1450 {
1451     if (isContextLost())
1452         return 0;
1453     RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1454     addSharedObject(o.get());
1455     return o;
1456 }
1457
1458 PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer()
1459 {
1460     if (isContextLost())
1461         return 0;
1462     RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1463     addContextObject(o.get());
1464     return o;
1465 }
1466
1467 PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture()
1468 {
1469     if (isContextLost())
1470         return 0;
1471     RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1472     addSharedObject(o.get());
1473     return o;
1474 }
1475
1476 PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram()
1477 {
1478     if (isContextLost())
1479         return 0;
1480     RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1481     addSharedObject(o.get());
1482     return o;
1483 }
1484
1485 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer()
1486 {
1487     if (isContextLost())
1488         return 0;
1489     RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1490     addSharedObject(o.get());
1491     return o;
1492 }
1493
1494 PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(GC3Denum type, ExceptionCode& ec)
1495 {
1496     UNUSED_PARAM(ec);
1497     if (isContextLost())
1498         return 0;
1499     if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1500         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "createShader", "invalid shader type");
1501         return 0;
1502     }
1503
1504     RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1505     addSharedObject(o.get());
1506     return o;
1507 }
1508
1509 void WebGLRenderingContext::cullFace(GC3Denum mode)
1510 {
1511     if (isContextLost())
1512         return;
1513     m_context->cullFace(mode);
1514     cleanupAfterGraphicsCall(false);
1515 }
1516
1517 bool WebGLRenderingContext::deleteObject(WebGLObject* object)
1518 {
1519     if (isContextLost() || !object)
1520         return false;
1521     if (!object->validate(contextGroup(), this)) {
1522         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "delete", "object does not belong to this context");
1523         return false;
1524     }
1525     if (object->object())
1526         // We need to pass in context here because we want
1527         // things in this context unbound.
1528         object->deleteObject(graphicsContext3D());
1529     return true;
1530 }
1531
1532 void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
1533 {
1534     if (!deleteObject(buffer))
1535         return;
1536     if (m_boundArrayBuffer == buffer)
1537         m_boundArrayBuffer = 0;
1538     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1539     if (elementArrayBuffer == buffer)
1540         m_boundVertexArrayObject->setElementArrayBuffer(0);
1541     if (!isGLES2Compliant()) {
1542         WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
1543         if (buffer == state.bufferBinding) {
1544             state.bufferBinding = m_vertexAttrib0Buffer;
1545             state.bytesPerElement = 0;
1546             state.size = 4;
1547             state.type = GraphicsContext3D::FLOAT;
1548             state.normalized = false;
1549             state.stride = 16;
1550             state.originalStride = 0;
1551             state.offset = 0;
1552         }
1553     }
1554 }
1555
1556 void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1557 {
1558     if (!deleteObject(framebuffer))
1559         return;
1560     if (framebuffer == m_framebufferBinding) {
1561         m_framebufferBinding = 0;
1562         if (m_drawingBuffer) {
1563             m_drawingBuffer->setFramebufferBinding(0);
1564             // Have to call bindFramebuffer here to bind back to internal fbo.
1565             m_drawingBuffer->bind();
1566         } else
1567             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1568     }
1569 }
1570
1571 void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
1572 {
1573     deleteObject(program);
1574     // We don't reset m_currentProgram to 0 here because the deletion of the
1575     // current program is delayed.
1576 }
1577
1578 void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1579 {
1580     if (!deleteObject(renderbuffer))
1581         return;
1582     if (renderbuffer == m_renderbufferBinding)
1583         m_renderbufferBinding = 0;
1584     if (m_framebufferBinding)
1585         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1586 }
1587
1588 void WebGLRenderingContext::deleteShader(WebGLShader* shader)
1589 {
1590     deleteObject(shader);
1591 }
1592
1593 void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
1594 {
1595     if (!deleteObject(texture))
1596         return;
1597     for (size_t i = 0; i < m_textureUnits.size(); ++i) {
1598         if (texture == m_textureUnits[i].m_texture2DBinding)
1599             m_textureUnits[i].m_texture2DBinding = 0;
1600         if (texture == m_textureUnits[i].m_textureCubeMapBinding)
1601             m_textureUnits[i].m_textureCubeMapBinding = 0;
1602     }
1603     if (m_framebufferBinding)
1604         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1605 }
1606
1607 void WebGLRenderingContext::depthFunc(GC3Denum func)
1608 {
1609     if (isContextLost())
1610         return;
1611     m_context->depthFunc(func);
1612     cleanupAfterGraphicsCall(false);
1613 }
1614
1615 void WebGLRenderingContext::depthMask(GC3Dboolean flag)
1616 {
1617     if (isContextLost())
1618         return;
1619     m_depthMask = flag;
1620     m_context->depthMask(flag);
1621     cleanupAfterGraphicsCall(false);
1622 }
1623
1624 void WebGLRenderingContext::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1625 {
1626     if (isContextLost())
1627         return;
1628     if (zNear > zFar) {
1629         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "depthRange", "zNear > zFar");
1630         return;
1631     }
1632     m_context->depthRange(zNear, zFar);
1633     cleanupAfterGraphicsCall(false);
1634 }
1635
1636 void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
1637 {
1638     UNUSED_PARAM(ec);
1639     if (isContextLost() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
1640         return;
1641     if (!program->detachShader(shader)) {
1642         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "detachShader", "shader not attached");
1643         return;
1644     }
1645     m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1646     shader->onDetached(graphicsContext3D());
1647     cleanupAfterGraphicsCall(false);
1648 }
1649
1650 void WebGLRenderingContext::disable(GC3Denum cap)
1651 {
1652     if (isContextLost() || !validateCapability("disable", cap))
1653         return;
1654     if (cap == GraphicsContext3D::STENCIL_TEST) {
1655         m_stencilEnabled = false;
1656         applyStencilTest();
1657         cleanupAfterGraphicsCall(false);
1658         return;
1659     }
1660     if (cap == GraphicsContext3D::SCISSOR_TEST) {
1661         m_scissorEnabled = false;
1662         if (m_drawingBuffer)
1663             m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1664     }
1665     m_context->disable(cap);
1666     cleanupAfterGraphicsCall(false);
1667 }
1668
1669 void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1670 {
1671     UNUSED_PARAM(ec);
1672     if (isContextLost())
1673         return;
1674     if (index >= m_maxVertexAttribs) {
1675         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "disableVertexAttribArray", "index out of range");
1676         return;
1677     }
1678
1679     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1680     state.enabled = false;
1681
1682     if (index > 0 || isGLES2Compliant()) {
1683         m_context->disableVertexAttribArray(index);
1684         cleanupAfterGraphicsCall(false);
1685     }
1686 }
1687
1688 bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1689 {
1690     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1691     
1692     if (!elementArrayBuffer)
1693         return false;
1694
1695     if (offset < 0)
1696         return false;
1697
1698     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1699         // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1700         if (offset % 2)
1701             return false;
1702
1703         // Make uoffset an element offset.
1704         offset /= 2;
1705
1706         GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1707         if (offset > n || count > n - offset)
1708             return false;
1709     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1710         GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1711         if (offset > n || count > n - offset)
1712             return false;
1713     }
1714     return true;
1715 }
1716
1717 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& numElementsRequired)
1718 {
1719     // Performs conservative validation by caching a maximum index of
1720     // the given type per element array buffer. If all of the bound
1721     // array buffers have enough elements to satisfy that maximum
1722     // index, skips the expensive per-draw-call iteration in
1723     // validateIndexArrayPrecise.
1724     
1725     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1726
1727     if (!elementArrayBuffer)
1728         return false;
1729
1730     GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
1731     // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1732     if (!numElements)
1733         return false;
1734     const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
1735     ASSERT(buffer);
1736
1737     int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
1738     if (maxIndex < 0) {
1739         // Compute the maximum index in the entire buffer for the given type of index.
1740         switch (type) {
1741         case GraphicsContext3D::UNSIGNED_BYTE: {
1742             const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
1743             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1744                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1745             break;
1746         }
1747         case GraphicsContext3D::UNSIGNED_SHORT: {
1748             numElements /= sizeof(GC3Dushort);
1749             const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
1750             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1751                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1752             break;
1753         }
1754         default:
1755             return false;
1756         }
1757         elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1758     }
1759
1760     if (maxIndex >= 0) {
1761         // The number of required elements is one more than the maximum
1762         // index that will be accessed.
1763         numElementsRequired = maxIndex + 1;
1764         return true;
1765     }
1766
1767     return false;
1768 }
1769
1770 bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, int& numElementsRequired)
1771 {
1772     ASSERT(count >= 0 && offset >= 0);
1773     int lastIndex = -1;
1774     
1775     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1776
1777     if (!elementArrayBuffer)
1778         return false;
1779
1780     if (!count) {
1781         numElementsRequired = 0;
1782         return true;
1783     }
1784
1785     if (!elementArrayBuffer->elementArrayBuffer())
1786         return false;
1787
1788     unsigned long uoffset = offset;
1789     unsigned long n = count;
1790
1791     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1792         // Make uoffset an element offset.
1793         uoffset /= sizeof(GC3Dushort);
1794         const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1795         while (n-- > 0) {
1796             if (*p > lastIndex)
1797                 lastIndex = *p;
1798             ++p;
1799         }
1800     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1801         const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1802         while (n-- > 0) {
1803             if (*p > lastIndex)
1804                 lastIndex = *p;
1805             ++p;
1806         }
1807     }
1808
1809     // Then set the last index in the index array and make sure it is valid.
1810     numElementsRequired = lastIndex + 1;
1811     return numElementsRequired > 0;
1812 }
1813
1814 bool WebGLRenderingContext::validateRenderingState(int numElementsRequired)
1815 {
1816     if (!m_currentProgram)
1817         return false;
1818
1819     // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1820     for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1821         const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
1822         if (state.enabled
1823             && (!state.bufferBinding || !state.bufferBinding->object()))
1824             return false;
1825     }
1826
1827     if (numElementsRequired <= 0)
1828         return true;
1829
1830     // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
1831     int smallestNumElements = INT_MAX;
1832     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1833     for (int i = 0; i < numActiveAttribLocations; ++i) {
1834         int loc = m_currentProgram->getActiveAttribLocation(i);
1835         if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1836             const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1837             if (state.enabled) {
1838                 // Avoid off-by-one errors in numElements computation.
1839                 // For the last element, we will only touch the data for the
1840                 // element and nothing beyond it.
1841                 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1842                 int numElements = 0;
1843                 ASSERT(state.stride > 0);
1844                 if (bytesRemaining >= state.bytesPerElement)
1845                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1846                 if (numElements < smallestNumElements)
1847                     smallestNumElements = numElements;
1848             }
1849         }
1850     }
1851
1852     if (smallestNumElements == INT_MAX)
1853         smallestNumElements = 0;
1854
1855     return numElementsRequired <= smallestNumElements;
1856 }
1857
1858 bool WebGLRenderingContext::validateWebGLObject(const char* functionName, WebGLObject* object)
1859 {
1860     if (!object || !object->object()) {
1861         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no object or object deleted");
1862         return false;
1863     }
1864     if (!object->validate(contextGroup(), this)) {
1865         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object does not belong to this context");
1866         return false;
1867     }
1868     return true;
1869 }
1870
1871 void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
1872 {
1873     UNUSED_PARAM(ec);
1874
1875     if (isContextLost() || !validateDrawMode("drawArrays", mode))
1876         return;
1877
1878     if (!validateStencilSettings("drawArrays"))
1879         return;
1880
1881     if (first < 0 || count < 0) {
1882         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawArrays", "first or count < 0");
1883         return;
1884     }
1885
1886     if (!count) {
1887         cleanupAfterGraphicsCall(true);
1888         return;
1889     }
1890
1891     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1892         // Ensure we have a valid rendering state
1893         CheckedInt<GC3Dint> checkedFirst(first);
1894         CheckedInt<GC3Dint> checkedCount(count);
1895         CheckedInt<GC3Dint> checkedSum = checkedFirst + checkedCount;
1896         if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) {
1897             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attempt to access out of bounds arrays");
1898             return;
1899         }
1900     } else {
1901         if (!validateRenderingState(0)) {
1902             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attribs not setup correctly");
1903             return;
1904         }
1905     }
1906
1907     const char* reason = "framebuffer incomplete";
1908     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1909         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawArrays", reason);
1910         return;
1911     }
1912
1913     clearIfComposited();
1914
1915     bool vertexAttrib0Simulated = false;
1916     if (!isGLES2Compliant())
1917         vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1918     if (!isGLES2NPOTStrict())
1919         handleNPOTTextures(true);
1920     m_context->drawArrays(mode, first, count);
1921     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1922         restoreStatesAfterVertexAttrib0Simulation();
1923     if (!isGLES2NPOTStrict())
1924         handleNPOTTextures(false);
1925     cleanupAfterGraphicsCall(true);
1926 }
1927
1928 void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode& ec)
1929 {
1930     UNUSED_PARAM(ec);
1931
1932     if (isContextLost() || !validateDrawMode("drawElements", mode))
1933         return;
1934
1935     if (!validateStencilSettings("drawElements"))
1936         return;
1937
1938     switch (type) {
1939     case GraphicsContext3D::UNSIGNED_BYTE:
1940     case GraphicsContext3D::UNSIGNED_SHORT:
1941         break;
1942     default:
1943         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "drawElements", "invalid type");
1944         return;
1945     }
1946
1947     if (count < 0 || offset < 0) {
1948         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawElements", "count or offset < 0");
1949         return;
1950     }
1951
1952     if (!count) {
1953         cleanupAfterGraphicsCall(true);
1954         return;
1955     }
1956
1957     if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1958         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "no ELEMENT_ARRAY_BUFFER bound");
1959         return;
1960     }
1961
1962     int numElements = 0;
1963     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1964         // Ensure we have a valid rendering state
1965         if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
1966             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "request out of bounds for current ELEMENT_ARRAY_BUFFER");
1967             return;
1968         }
1969         if (!count)
1970             return;
1971         if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) {
1972             if (!validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements) || !validateRenderingState(numElements)) {
1973                 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attempt to access out of bounds arrays");
1974                 return;
1975             }
1976         }
1977     } else {
1978         if (!validateRenderingState(0)) {
1979             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attribs not setup correctly");
1980             return;
1981         }
1982     }
1983
1984     const char* reason = "framebuffer incomplete";
1985     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1986         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawElements", reason);
1987         return;
1988     }
1989     clearIfComposited();
1990
1991     bool vertexAttrib0Simulated = false;
1992     if (!isGLES2Compliant()) {
1993         if (!numElements)
1994             validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
1995         vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1996     }
1997     if (!isGLES2NPOTStrict())
1998         handleNPOTTextures(true);
1999     m_context->drawElements(mode, count, type, static_cast<GC3Dintptr>(offset));
2000     if (!isGLES2Compliant() && vertexAttrib0Simulated)
2001         restoreStatesAfterVertexAttrib0Simulation();
2002     if (!isGLES2NPOTStrict())
2003         handleNPOTTextures(false);
2004     cleanupAfterGraphicsCall(true);
2005 }
2006
2007 void WebGLRenderingContext::enable(GC3Denum cap)
2008 {
2009     if (isContextLost() || !validateCapability("enable", cap))
2010         return;
2011     if (cap == GraphicsContext3D::STENCIL_TEST) {
2012         m_stencilEnabled = true;
2013         applyStencilTest();
2014         cleanupAfterGraphicsCall(false);
2015         return;
2016     }
2017     if (cap == GraphicsContext3D::SCISSOR_TEST) {
2018         m_scissorEnabled = true;
2019         if (m_drawingBuffer)
2020             m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
2021     }
2022     m_context->enable(cap);
2023     cleanupAfterGraphicsCall(false);
2024 }
2025
2026 void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
2027 {
2028     UNUSED_PARAM(ec);
2029     if (isContextLost())
2030         return;
2031     if (index >= m_maxVertexAttribs) {
2032         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "enableVertexAttribArray", "index out of range");
2033         return;
2034     }
2035
2036     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2037     state.enabled = true;
2038
2039     m_context->enableVertexAttribArray(index);
2040     cleanupAfterGraphicsCall(false);
2041 }
2042
2043 void WebGLRenderingContext::finish()
2044 {
2045     if (isContextLost())
2046         return;
2047     m_context->finish();
2048     cleanupAfterGraphicsCall(false);
2049 }
2050
2051 void WebGLRenderingContext::flush()
2052 {
2053     if (isContextLost())
2054         return;
2055     m_context->flush();
2056     cleanupAfterGraphicsCall(false);
2057 }
2058
2059 void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
2060 {
2061     UNUSED_PARAM(ec);
2062     if (isContextLost() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
2063         return;
2064     if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
2065         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
2066         return;
2067     }
2068     if (buffer && !buffer->validate(contextGroup(), this)) {
2069         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
2070         return;
2071     }
2072     // Don't allow the default framebuffer to be mutated; all current
2073     // implementations use an FBO internally in place of the default
2074     // FBO.
2075     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2076         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
2077         return;
2078     }
2079     Platform3DObject bufferObject = objectOrZero(buffer);
2080     switch (attachment) {
2081     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2082         m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
2083         m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
2084         break;
2085     case GraphicsContext3D::DEPTH_ATTACHMENT:
2086         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
2087         break;
2088     case GraphicsContext3D::STENCIL_ATTACHMENT:
2089         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
2090         break;
2091     default:
2092         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
2093     }
2094     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
2095     applyStencilTest();
2096     cleanupAfterGraphicsCall(false);
2097 }
2098
2099 void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
2100 {
2101     UNUSED_PARAM(ec);
2102     if (isContextLost() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
2103         return;
2104     if (level) {
2105         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "framebufferTexture2D", "level not 0");
2106         return;
2107     }
2108     if (texture && !texture->validate(contextGroup(), this)) {
2109         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
2110         return;
2111     }
2112     // Don't allow the default framebuffer to be mutated; all current
2113     // implementations use an FBO internally in place of the default
2114     // FBO.
2115     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2116         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
2117         return;
2118     }
2119     Platform3DObject textureObject = objectOrZero(texture);
2120     switch (attachment) {
2121     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2122         m_context->framebufferTexture2D(target, GraphicsContext3D::DEPTH_ATTACHMENT, textarget, textureObject, level);
2123         m_context->framebufferTexture2D(target, GraphicsContext3D::STENCIL_ATTACHMENT, textarget, textureObject, level);
2124         break;
2125     case GraphicsContext3D::DEPTH_ATTACHMENT:
2126         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2127         break;
2128     case GraphicsContext3D::STENCIL_ATTACHMENT:
2129         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2130         break;
2131     default:
2132         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2133     }
2134     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
2135     applyStencilTest();
2136     cleanupAfterGraphicsCall(false);
2137 }
2138
2139 void WebGLRenderingContext::frontFace(GC3Denum mode)
2140 {
2141     if (isContextLost())
2142         return;
2143     m_context->frontFace(mode);
2144     cleanupAfterGraphicsCall(false);
2145 }
2146
2147 void WebGLRenderingContext::generateMipmap(GC3Denum target)
2148 {
2149     if (isContextLost())
2150         return;
2151     WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
2152     if (!tex)
2153         return;
2154     if (!tex->canGenerateMipmaps()) {
2155         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
2156         return;
2157     }
2158     if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0)))
2159         return;
2160
2161     // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
2162     // on Mac.  Remove the hack once this driver bug is fixed.
2163 #if OS(DARWIN)
2164     bool needToResetMinFilter = false;
2165     if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
2166         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
2167         needToResetMinFilter = true;
2168     }
2169 #endif
2170     m_context->generateMipmap(target);
2171 #if OS(DARWIN)
2172     if (needToResetMinFilter)
2173         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
2174 #endif
2175     tex->generateMipmapLevelInfo();
2176     cleanupAfterGraphicsCall(false);
2177 }
2178
2179 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2180 {
2181     UNUSED_PARAM(ec);
2182     if (isContextLost() || !validateWebGLObject("getActiveAttrib", program))
2183         return 0;
2184     ActiveInfo info;
2185     if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
2186         return 0;
2187     return WebGLActiveInfo::create(info.name, info.type, info.size);
2188 }
2189
2190 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2191 {
2192     UNUSED_PARAM(ec);
2193     if (isContextLost() || !validateWebGLObject("getActiveUniform", program))
2194         return 0;
2195     ActiveInfo info;
2196     if (!m_context->getActiveUniform(objectOrZero(program), index, info))
2197         return 0;
2198     if (!isGLES2Compliant())
2199         if (info.size > 1 && !info.name.endsWith("[0]"))
2200             info.name.append("[0]");
2201     return WebGLActiveInfo::create(info.name, info.type, info.size);
2202 }
2203
2204 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader> >& shaderObjects, ExceptionCode& ec)
2205 {
2206     UNUSED_PARAM(ec);
2207     shaderObjects.clear();
2208     if (isContextLost() || !validateWebGLObject("getAttachedShaders", program))
2209         return false;
2210
2211     const GC3Denum shaderType[] = {
2212         GraphicsContext3D::VERTEX_SHADER,
2213         GraphicsContext3D::FRAGMENT_SHADER
2214     };
2215     for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
2216         WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2217         if (shader)
2218             shaderObjects.append(shader);
2219     }
2220     return true;
2221 }
2222
2223 GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
2224 {
2225     if (isContextLost() || !validateWebGLObject("getAttribLocation", program))
2226         return -1;
2227     if (!validateLocationLength("getAttribLocation", name))
2228         return -1;
2229     if (!validateString("getAttribLocation", name))
2230         return -1;
2231     if (isPrefixReserved(name))
2232         return -1;
2233     if (!program->getLinkStatus()) {
2234         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getAttribLocation", "program not linked");
2235         return 0;
2236     }
2237     return m_context->getAttribLocation(objectOrZero(program), name);
2238 }
2239
2240 WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2241 {
2242     UNUSED_PARAM(ec);
2243     if (isContextLost())
2244         return WebGLGetInfo();
2245     if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
2246         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid target");
2247         return WebGLGetInfo();
2248     }
2249
2250     if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
2251         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2252         return WebGLGetInfo();
2253     }
2254
2255     WebGLStateRestorer(this, false);
2256     GC3Dint value = 0;
2257     m_context->getBufferParameteriv(target, pname, &value);
2258     if (pname == GraphicsContext3D::BUFFER_SIZE)
2259         return WebGLGetInfo(value);
2260     return WebGLGetInfo(static_cast<unsigned int>(value));
2261 }
2262
2263 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
2264 {
2265     if (isContextLost())
2266         return 0;
2267     // We always need to return a new WebGLContextAttributes object to
2268     // prevent the user from mutating any cached version.
2269
2270     // Also, we need to enforce requested values of "false" for depth
2271     // and stencil, regardless of the properties of the underlying
2272     // GraphicsContext3D.
2273     RefPtr<WebGLContextAttributes> attributes = WebGLContextAttributes::create(m_context->getContextAttributes());
2274     if (!m_attributes.depth)
2275         attributes->setDepth(false);
2276     if (!m_attributes.stencil)
2277         attributes->setStencil(false);
2278     return attributes.release();
2279 }
2280
2281 GC3Denum WebGLRenderingContext::getError()
2282 {
2283     return m_context->getError();
2284 }
2285
2286 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
2287 {
2288     if (isContextLost())
2289         return 0;
2290
2291     if (equalIgnoringCase(name, "WEBKIT_EXT_texture_filter_anisotropic")
2292         && m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic")) {
2293         if (!m_extTextureFilterAnisotropic) {
2294             m_context->getExtensions()->ensureEnabled("GL_EXT_texture_filter_anisotropic");
2295             m_extTextureFilterAnisotropic = EXTTextureFilterAnisotropic::create(this);
2296         }
2297         return m_extTextureFilterAnisotropic.get();
2298     }
2299     if (equalIgnoringCase(name, "OES_standard_derivatives")
2300         && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
2301         if (!m_oesStandardDerivatives) {
2302             m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
2303             m_oesStandardDerivatives = OESStandardDerivatives::create(this);
2304         }
2305         return m_oesStandardDerivatives.get();
2306     }
2307     if (equalIgnoringCase(name, "OES_texture_float")
2308         && m_context->getExtensions()->supports("GL_OES_texture_float")) {
2309         if (!m_oesTextureFloat) {
2310             m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
2311             m_oesTextureFloat = OESTextureFloat::create(this);
2312         }
2313         return m_oesTextureFloat.get();
2314     }
2315     if (equalIgnoringCase(name, "OES_vertex_array_object")
2316         && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
2317         if (!m_oesVertexArrayObject) {
2318             m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
2319             m_oesVertexArrayObject = OESVertexArrayObject::create(this);
2320         }
2321         return m_oesVertexArrayObject.get();
2322     }
2323     if (equalIgnoringCase(name, "WEBKIT_WEBGL_lose_context")
2324         // FIXME: remove this after a certain grace period.
2325         || equalIgnoringCase(name, "WEBKIT_lose_context")) {
2326         if (!m_webglLoseContext)
2327             m_webglLoseContext = WebGLLoseContext::create(this);
2328         return m_webglLoseContext.get();
2329     }
2330     if (equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_s3tc")) {
2331         // Use WEBKIT_ prefix until extension is official.
2332         if (!m_webglCompressedTextureS3TC)
2333             m_webglCompressedTextureS3TC = WebGLCompressedTextureS3TC::create(this);
2334         return m_webglCompressedTextureS3TC.get();
2335     }
2336     if (equalIgnoringCase(name, "WEBKIT_WEBGL_depth_texture")
2337         && WebGLDepthTexture::supported(graphicsContext3D())) {
2338         if (!m_webglDepthTexture) {
2339             m_context->getExtensions()->ensureEnabled("GL_CHROMIUM_depth_texture");
2340             m_webglDepthTexture = WebGLDepthTexture::create(this);
2341         }
2342         return m_webglDepthTexture.get();
2343     }
2344     if (allowPrivilegedExtensions()) {
2345         if (equalIgnoringCase(name, "WEBGL_debug_renderer_info")) {
2346             if (!m_webglDebugRendererInfo)
2347                 m_webglDebugRendererInfo = WebGLDebugRendererInfo::create(this);
2348             return m_webglDebugRendererInfo.get();
2349         }
2350         if (equalIgnoringCase(name, "WEBGL_debug_shaders")
2351             && m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source")) {
2352             if (!m_webglDebugShaders)
2353                 m_webglDebugShaders = WebGLDebugShaders::create(this);
2354             return m_webglDebugShaders.get();
2355         }
2356     }
2357
2358     return 0;
2359 }
2360
2361 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
2362 {
2363     UNUSED_PARAM(ec);
2364     if (isContextLost() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
2365         return WebGLGetInfo();
2366
2367     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2368         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
2369         return WebGLGetInfo();
2370     }
2371
2372     WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
2373     if (!object) {
2374         if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2375             return WebGLGetInfo(GraphicsContext3D::NONE);
2376         // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
2377         // specifies INVALID_OPERATION.
2378         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
2379         return WebGLGetInfo();
2380     }
2381
2382     ASSERT(object->isTexture() || object->isRenderbuffer());
2383     if (object->isTexture()) {
2384         switch (pname) {
2385         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2386             return WebGLGetInfo(GraphicsContext3D::TEXTURE);
2387         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2388             return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
2389         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2390         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2391             {
2392                 WebGLStateRestorer(this, false);
2393                 GC3Dint value = 0;
2394                 m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2395                 return WebGLGetInfo(value);
2396             }
2397         default:
2398             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
2399             return WebGLGetInfo();
2400         }
2401     } else {
2402         switch (pname) {
2403         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2404             return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
2405         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2406             return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
2407         default:
2408             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
2409             return WebGLGetInfo();
2410         }
2411     }
2412 }
2413
2414 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec)
2415 {
2416     UNUSED_PARAM(ec);
2417     if (isContextLost())
2418         return WebGLGetInfo();
2419     const int intZero = 0;
2420     WebGLStateRestorer(this, false);
2421     switch (pname) {
2422     case GraphicsContext3D::ACTIVE_TEXTURE:
2423         return getUnsignedIntParameter(pname);
2424     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
2425         return getWebGLFloatArrayParameter(pname);
2426     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
2427         return getWebGLFloatArrayParameter(pname);
2428     case GraphicsContext3D::ALPHA_BITS:
2429         return getIntParameter(pname);
2430     case GraphicsContext3D::ARRAY_BUFFER_BINDING:
2431         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2432     case GraphicsContext3D::BLEND:
2433         return getBooleanParameter(pname);
2434     case GraphicsContext3D::BLEND_COLOR:
2435         return getWebGLFloatArrayParameter(pname);
2436     case GraphicsContext3D::BLEND_DST_ALPHA:
2437         return getUnsignedIntParameter(pname);
2438     case GraphicsContext3D::BLEND_DST_RGB:
2439         return getUnsignedIntParameter(pname);
2440     case GraphicsContext3D::BLEND_EQUATION_ALPHA:
2441         return getUnsignedIntParameter(pname);
2442     case GraphicsContext3D::BLEND_EQUATION_RGB:
2443         return getUnsignedIntParameter(pname);
2444     case GraphicsContext3D::BLEND_SRC_ALPHA:
2445         return getUnsignedIntParameter(pname);
2446     case GraphicsContext3D::BLEND_SRC_RGB:
2447         return getUnsignedIntParameter(pname);
2448     case GraphicsContext3D::BLUE_BITS:
2449         return getIntParameter(pname);
2450     case GraphicsContext3D::COLOR_CLEAR_VALUE:
2451         return getWebGLFloatArrayParameter(pname);
2452     case GraphicsContext3D::COLOR_WRITEMASK:
2453         return getBooleanArrayParameter(pname);
2454     case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
2455         return WebGLGetInfo(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()));
2456     case GraphicsContext3D::CULL_FACE:
2457         return getBooleanParameter(pname);
2458     case GraphicsContext3D::CULL_FACE_MODE:
2459         return getUnsignedIntParameter(pname);
2460     case GraphicsContext3D::CURRENT_PROGRAM:
2461         return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2462     case GraphicsContext3D::DEPTH_BITS:
2463         if (!m_framebufferBinding && !m_attributes.depth)
2464             return WebGLGetInfo(intZero);
2465         return getIntParameter(pname);
2466     case GraphicsContext3D::DEPTH_CLEAR_VALUE:
2467         return getFloatParameter(pname);
2468     case GraphicsContext3D::DEPTH_FUNC:
2469         return getUnsignedIntParameter(pname);
2470     case GraphicsContext3D::DEPTH_RANGE:
2471         return getWebGLFloatArrayParameter(pname);
2472     case GraphicsContext3D::DEPTH_TEST:
2473         return getBooleanParameter(pname);
2474     case GraphicsContext3D::DEPTH_WRITEMASK:
2475         return getBooleanParameter(pname);
2476     case GraphicsContext3D::DITHER:
2477         return getBooleanParameter(pname);
2478     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
2479         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
2480     case GraphicsContext3D::FRAMEBUFFER_BINDING:
2481         return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2482     case GraphicsContext3D::FRONT_FACE:
2483         return getUnsignedIntParameter(pname);
2484     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2485         return getUnsignedIntParameter(pname);
2486     case GraphicsContext3D::GREEN_BITS:
2487         return getIntParameter(pname);
2488     case GraphicsContext3D::LINE_WIDTH:
2489         return getFloatParameter(pname);
2490     case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2491         return getIntParameter(pname);
2492     case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
2493         return getIntParameter(pname);
2494     case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
2495         return getIntParameter(pname);
2496     case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
2497         return getIntParameter(pname);
2498     case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
2499         return getIntParameter(pname);
2500     case GraphicsContext3D::MAX_TEXTURE_SIZE:
2501         return getIntParameter(pname);
2502     case GraphicsContext3D::MAX_VARYING_VECTORS:
2503         return getIntParameter(pname);
2504     case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
2505         return getIntParameter(pname);
2506     case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2507         return getIntParameter(pname);
2508     case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
2509         return getIntParameter(pname);
2510     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
2511         return getWebGLIntArrayParameter(pname);
2512     case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
2513         // FIXME: should we always return 0 for this?
2514         return getIntParameter(pname);
2515     case GraphicsContext3D::PACK_ALIGNMENT:
2516         return getIntParameter(pname);
2517     case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
2518         return getFloatParameter(pname);
2519     case GraphicsContext3D::POLYGON_OFFSET_FILL:
2520         return getBooleanParameter(pname);
2521     case GraphicsContext3D::POLYGON_OFFSET_UNITS:
2522         return getFloatParameter(pname);
2523     case GraphicsContext3D::RED_BITS:
2524         return getIntParameter(pname);
2525     case GraphicsContext3D::RENDERBUFFER_BINDING:
2526         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2527     case GraphicsContext3D::RENDERER:
2528         return WebGLGetInfo(String("WebKit WebGL"));
2529     case GraphicsContext3D::SAMPLE_BUFFERS:
2530         return getIntParameter(pname);
2531     case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
2532         return getBooleanParameter(pname);
2533     case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
2534         return getFloatParameter(pname);
2535     case GraphicsContext3D::SAMPLES:
2536         return getIntParameter(pname);
2537     case GraphicsContext3D::SCISSOR_BOX:
2538         return getWebGLIntArrayParameter(pname);
2539     case GraphicsContext3D::SCISSOR_TEST:
2540         return getBooleanParameter(pname);
2541     case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
2542         return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
2543     case GraphicsContext3D::STENCIL_BACK_FAIL:
2544         return getUnsignedIntParameter(pname);
2545     case GraphicsContext3D::STENCIL_BACK_FUNC:
2546         return getUnsignedIntParameter(pname);
2547     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
2548         return getUnsignedIntParameter(pname);
2549     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
2550         return getUnsignedIntParameter(pname);
2551     case GraphicsContext3D::STENCIL_BACK_REF:
2552         return getIntParameter(pname);
2553     case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
2554         return getUnsignedIntParameter(pname);
2555     case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
2556         return getUnsignedIntParameter(pname);
2557     case GraphicsContext3D::STENCIL_BITS:
2558         if (!m_framebufferBinding && !m_attributes.stencil)
2559             return WebGLGetInfo(intZero);
2560         return getIntParameter(pname);
2561     case GraphicsContext3D::STENCIL_CLEAR_VALUE:
2562         return getIntParameter(pname);
2563     case GraphicsContext3D::STENCIL_FAIL:
2564         return getUnsignedIntParameter(pname);
2565     case GraphicsContext3D::STENCIL_FUNC:
2566         return getUnsignedIntParameter(pname);
2567     case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
2568         return getUnsignedIntParameter(pname);
2569     case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
2570         return getUnsignedIntParameter(pname);
2571     case GraphicsContext3D::STENCIL_REF:
2572         return getIntParameter(pname);
2573     case GraphicsContext3D::STENCIL_TEST:
2574         return getBooleanParameter(pname);
2575     case GraphicsContext3D::STENCIL_VALUE_MASK:
2576         return getUnsignedIntParameter(pname);
2577     case GraphicsContext3D::STENCIL_WRITEMASK:
2578         return getUnsignedIntParameter(pname);
2579     case GraphicsContext3D::SUBPIXEL_BITS:
2580         return getIntParameter(pname);
2581     case GraphicsContext3D::TEXTURE_BINDING_2D:
2582         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
2583     case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
2584         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
2585     case GraphicsContext3D::UNPACK_ALIGNMENT:
2586         return getIntParameter(pname);
2587     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2588         return WebGLGetInfo(m_unpackFlipY);
2589     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2590         return WebGLGetInfo(m_unpackPremultiplyAlpha);
2591     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2592         return WebGLGetInfo(m_unpackColorspaceConversion);
2593     case GraphicsContext3D::VENDOR:
2594         return WebGLGetInfo(String("WebKit"));
2595     case GraphicsContext3D::VERSION:
2596         return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
2597     case GraphicsContext3D::VIEWPORT:
2598         return getWebGLIntArrayParameter(pname);
2599     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2600         if (m_oesStandardDerivatives)
2601             return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2602         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
2603         return WebGLGetInfo();
2604     case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
2605         if (m_webglDebugRendererInfo)
2606             return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
2607         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2608         return WebGLGetInfo();
2609     case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
2610         if (m_webglDebugRendererInfo)
2611             return WebGLGetInfo(m_context->getString(GraphicsContext3D::VENDOR));
2612         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2613         return WebGLGetInfo();
2614     case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2615         if (m_oesVertexArrayObject) {
2616             if (!m_boundVertexArrayObject->isDefaultObject())
2617                 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2618             return WebGLGetInfo();
2619         }
2620         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
2621         return WebGLGetInfo();
2622     case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2623         if (m_extTextureFilterAnisotropic)
2624             return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT);
2625         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2626         return WebGLGetInfo();
2627     default:
2628         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name");
2629         return WebGLGetInfo();
2630     }
2631 }
2632
2633 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2634 {
2635     UNUSED_PARAM(ec);
2636     if (isContextLost() || !validateWebGLObject("getProgramParameter", program))
2637         return WebGLGetInfo();
2638
2639     WebGLStateRestorer(this, false);
2640     GC3Dint value = 0;
2641     switch (pname) {
2642     case GraphicsContext3D::DELETE_STATUS:
2643         return WebGLGetInfo(program->isDeleted());
2644     case GraphicsContext3D::VALIDATE_STATUS:
2645         m_context->getProgramiv(objectOrZero(program), pname, &value);
2646         return WebGLGetInfo(static_cast<bool>(value));
2647     case GraphicsContext3D::LINK_STATUS:
2648         return WebGLGetInfo(program->getLinkStatus());
2649     case GraphicsContext3D::ATTACHED_SHADERS:
2650     case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2651     case GraphicsContext3D::ACTIVE_UNIFORMS:
2652         m_context->getProgramiv(objectOrZero(program), pname, &value);
2653         return WebGLGetInfo(value);
2654     default:
2655         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2656         return WebGLGetInfo();
2657     }
2658 }
2659
2660 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2661 {
2662     UNUSED_PARAM(ec);
2663     if (isContextLost())
2664         return String();
2665     if (!validateWebGLObject("getProgramInfoLog", program))
2666         return "";
2667     WebGLStateRestorer(this, false);
2668     return ensureNotNull(m_context->getProgramInfoLog(objectOrZero(program)));
2669 }
2670
2671 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2672 {
2673     UNUSED_PARAM(ec);
2674     if (isContextLost())
2675         return WebGLGetInfo();
2676     if (target != GraphicsContext3D::RENDERBUFFER) {
2677         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2678         return WebGLGetInfo();
2679     }
2680     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2681         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2682         return WebGLGetInfo();
2683     }
2684
2685     if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2686         && !m_renderbufferBinding->isValid()) {
2687         ASSERT(!isDepthStencilSupported());
2688         int value = 0;
2689         switch (pname) {
2690         case GraphicsContext3D::RENDERBUFFER_WIDTH:
2691             value = m_renderbufferBinding->getWidth();
2692             break;
2693         case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2694             value = m_renderbufferBinding->getHeight();
2695             break;
2696         case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2697         case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2698         case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2699         case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2700             value = 0;
2701             break;
2702         case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2703             value = 24;
2704             break;
2705         case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2706             value = 8;
2707             break;
2708         case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2709             return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2710         default:
2711             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2712             return WebGLGetInfo();
2713         }
2714         return WebGLGetInfo(value);
2715     }
2716
2717     WebGLStateRestorer(this, false);
2718     GC3Dint value = 0;
2719     switch (pname) {
2720     case GraphicsContext3D::RENDERBUFFER_WIDTH:
2721     case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2722     case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2723     case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2724     case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2725     case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2726     case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2727     case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2728         m_context->getRenderbufferParameteriv(target, pname, &value);
2729         return WebGLGetInfo(value);
2730     case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2731         return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2732     default:
2733         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2734         return WebGLGetInfo();
2735     }
2736 }
2737
2738 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
2739 {
2740     UNUSED_PARAM(ec);
2741     if (isContextLost() || !validateWebGLObject("getShaderParameter", shader))
2742         return WebGLGetInfo();
2743     WebGLStateRestorer(this, false);
2744     GC3Dint value = 0;
2745     switch (pname) {
2746     case GraphicsContext3D::DELETE_STATUS:
2747         return WebGLGetInfo(shader->isDeleted());
2748     case GraphicsContext3D::COMPILE_STATUS:
2749         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2750         return WebGLGetInfo(static_cast<bool>(value));
2751     case GraphicsContext3D::SHADER_TYPE:
2752         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2753         return WebGLGetInfo(static_cast<unsigned int>(value));
2754     default:
2755         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderParameter", "invalid parameter name");
2756         return WebGLGetInfo();
2757     }
2758 }
2759
2760 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
2761 {
2762     UNUSED_PARAM(ec);
2763     if (isContextLost())
2764         return String();
2765     if (!validateWebGLObject("getShaderInfoLog", shader))
2766         return "";
2767     WebGLStateRestorer(this, false);
2768     return ensureNotNull(m_context->getShaderInfoLog(objectOrZero(shader)));
2769 }
2770
2771 PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContext::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode& ec)
2772 {
2773     UNUSED_PARAM(ec);
2774     if (isContextLost())
2775         return 0;
2776     switch (shaderType) {
2777     case GraphicsContext3D::VERTEX_SHADER:
2778     case GraphicsContext3D::FRAGMENT_SHADER:
2779         break;
2780     default:
2781         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
2782         return 0;
2783     }
2784     switch (precisionType) {
2785     case GraphicsContext3D::LOW_FLOAT:
2786     case GraphicsContext3D::MEDIUM_FLOAT:
2787     case GraphicsContext3D::HIGH_FLOAT:
2788     case GraphicsContext3D::LOW_INT:
2789     case GraphicsContext3D::MEDIUM_INT:
2790     case GraphicsContext3D::HIGH_INT:
2791         break;
2792     default:
2793         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
2794         return 0;
2795     }
2796
2797     GC3Dint range[2] = {0, 0};
2798     GC3Dint precision = 0;
2799 #if !ENABLE(TIZEN_DAILY_UPVERSIONING)
2800     // FIXME: getShaderPrecisionFormat() should be implemented.
2801     m_context->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
2802 #endif
2803     return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
2804 }
2805
2806 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
2807 {
2808     UNUSED_PARAM(ec);
2809     if (isContextLost())
2810         return String();
2811     if (!validateWebGLObject("getShaderSource", shader))
2812         return "";
2813     return ensureNotNull(shader->getSource());
2814 }
2815
2816 Vector<String> WebGLRenderingContext::getSupportedExtensions()
2817 {
2818     Vector<String> result;
2819     if (m_context->getExtensions()->supports("GL_OES_texture_float"))
2820         result.append("OES_texture_float");
2821     if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
2822         result.append("OES_standard_derivatives");
2823     if (m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic"))
2824         result.append("WEBKIT_EXT_texture_filter_anisotropic");
2825     if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
2826         result.append("OES_vertex_array_object");
2827     result.append("WEBKIT_WEBGL_lose_context");
2828     if (WebGLCompressedTextureS3TC::supported(this))
2829         result.append("WEBKIT_WEBGL_compressed_texture_s3tc");
2830     if (WebGLDepthTexture::supported(graphicsContext3D()))
2831         result.append("WEBKIT_WEBGL_depth_texture");
2832
2833     if (allowPrivilegedExtensions()) {
2834         if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
2835             result.append("WEBGL_debug_shaders");
2836         result.append("WEBGL_debug_renderer_info");
2837     }
2838
2839     return result;
2840 }
2841
2842 WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2843 {
2844     UNUSED_PARAM(ec);
2845     if (isContextLost())
2846         return WebGLGetInfo();
2847     WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
2848     if (!tex)
2849         return WebGLGetInfo();
2850     WebGLStateRestorer(this, false);
2851     GC3Dint value = 0;
2852     switch (pname) {
2853     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2854     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2855     case GraphicsContext3D::TEXTURE_WRAP_S:
2856     case GraphicsContext3D::TEXTURE_WRAP_T:
2857         m_context->getTexParameteriv(target, pname, &value);
2858         return WebGLGetInfo(static_cast<unsigned int>(value));
2859     case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2860         if (m_extTextureFilterAnisotropic) {
2861             m_context->getTexParameteriv(target, pname, &value);
2862             return WebGLGetInfo(static_cast<unsigned int>(value));
2863         }
2864         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2865         return WebGLGetInfo();
2866     default:
2867         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name");
2868         return WebGLGetInfo();
2869     }
2870 }
2871
2872 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2873 {
2874     UNUSED_PARAM(ec);
2875     if (isContextLost() || !validateWebGLObject("getUniform", program))
2876         return WebGLGetInfo();
2877     if (!uniformLocation || uniformLocation->program() != program) {
2878         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
2879         return WebGLGetInfo();
2880     }
2881     GC3Dint location = uniformLocation->location();
2882
2883     WebGLStateRestorer(this, false);
2884     // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2885     GC3Dint activeUniforms = 0;
2886     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2887     for (GC3Dint i = 0; i < activeUniforms; i++) {
2888         ActiveInfo info;
2889         if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2890             return WebGLGetInfo();
2891         // Strip "[0]" from the name if it's an array.
2892         if (info.size > 1 && info.name.endsWith("[0]"))
2893             info.name = info.name.left(info.name.length() - 3);
2894         // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2895         for (GC3Dint index = 0; index < info.size; ++index) {
2896             String name = info.name;
2897             if (info.size > 1 && index >= 1) {
2898                 name.append('[');
2899                 name.append(String::number(index));
2900                 name.append(']');
2901             }
2902             // Now need to look this up by name again to find its location
2903             GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name);
2904             if (loc == location) {
2905                 // Found it. Use the type in the ActiveInfo to determine the return type.
2906                 GC3Denum baseType;
2907                 unsigned int length;
2908                 switch (info.type) {
2909                 case GraphicsContext3D::BOOL:
2910                     baseType = GraphicsContext3D::BOOL;
2911                     length = 1;
2912                     break;
2913                 case GraphicsContext3D::BOOL_VEC2:
2914                     baseType = GraphicsContext3D::BOOL;
2915                     length = 2;
2916                     break;
2917                 case GraphicsContext3D::BOOL_VEC3:
2918                     baseType = GraphicsContext3D::BOOL;
2919                     length = 3;
2920                     break;
2921                 case GraphicsContext3D::BOOL_VEC4:
2922                     baseType = GraphicsContext3D::BOOL;
2923                     length = 4;
2924                     break;
2925                 case GraphicsContext3D::INT:
2926                     baseType = GraphicsContext3D::INT;
2927                     length = 1;
2928                     break;
2929                 case GraphicsContext3D::INT_VEC2:
2930                     baseType = GraphicsContext3D::INT;
2931                     length = 2;
2932                     break;
2933                 case GraphicsContext3D::INT_VEC3:
2934                     baseType = GraphicsContext3D::INT;
2935                     length = 3;
2936                     break;
2937                 case GraphicsContext3D::INT_VEC4:
2938                     baseType = GraphicsContext3D::INT;
2939                     length = 4;
2940                     break;
2941                 case GraphicsContext3D::FLOAT:
2942                     baseType = GraphicsContext3D::FLOAT;
2943                     length = 1;
2944                     break;
2945                 case GraphicsContext3D::FLOAT_VEC2:
2946                     baseType = GraphicsContext3D::FLOAT;
2947                     length = 2;
2948                     break;
2949                 case GraphicsContext3D::FLOAT_VEC3:
2950                     baseType = GraphicsContext3D::FLOAT;
2951                     length = 3;
2952                     break;
2953                 case GraphicsContext3D::FLOAT_VEC4:
2954                     baseType = GraphicsContext3D::FLOAT;
2955                     length = 4;
2956                     break;
2957                 case GraphicsContext3D::FLOAT_MAT2:
2958                     baseType = GraphicsContext3D::FLOAT;
2959                     length = 4;
2960                     break;
2961                 case GraphicsContext3D::FLOAT_MAT3:
2962                     baseType = GraphicsContext3D::FLOAT;
2963                     length = 9;
2964                     break;
2965                 case GraphicsContext3D::FLOAT_MAT4:
2966                     baseType = GraphicsContext3D::FLOAT;
2967                     length = 16;
2968                     break;
2969                 case GraphicsContext3D::SAMPLER_2D:
2970                 case GraphicsContext3D::SAMPLER_CUBE:
2971                     baseType = GraphicsContext3D::INT;
2972                     length = 1;
2973                     break;
2974                 default:
2975                     // Can't handle this type
2976                     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unhandled type");
2977                     return WebGLGetInfo();
2978                 }
2979                 switch (baseType) {
2980                 case GraphicsContext3D::FLOAT: {
2981                     GC3Dfloat value[16] = {0};
2982                     m_context->getUniformfv(objectOrZero(program), location, value);
2983                     if (length == 1)
2984                         return WebGLGetInfo(value[0]);
2985                     return WebGLGetInfo(Float32Array::create(value, length));
2986                 }
2987                 case GraphicsContext3D::INT: {
2988                     GC3Dint value[4] = {0};
2989                     m_context->getUniformiv(objectOrZero(program), location, value);
2990                     if (length == 1)
2991                         return WebGLGetInfo(value[0]);
2992                     return WebGLGetInfo(Int32Array::create(value, length));
2993                 }
2994                 case GraphicsContext3D::BOOL: {
2995                     GC3Dint value[4] = {0};
2996                     m_context->getUniformiv(objectOrZero(program), location, value);
2997                     if (length > 1) {
2998                         bool boolValue[16] = {0};
2999                         for (unsigned j = 0; j < length; j++)
3000                             boolValue[j] = static_cast<bool>(value[j]);
3001                         return WebGLGetInfo(boolValue, length);
3002                     }
3003                     return WebGLGetInfo(static_cast<bool>(value[0]));
3004                 }
3005                 default:
3006                     notImplemented();
3007                 }
3008             }
3009         }
3010     }
3011     // If we get here, something went wrong in our unfortunately complex logic above
3012     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unknown error");
3013     return WebGLGetInfo();
3014 }
3015
3016 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
3017 {
3018     UNUSED_PARAM(ec);
3019     if (isContextLost() || !validateWebGLObject("getUniformLocation", program))
3020         return 0;
3021     if (!validateLocationLength("getUniformLocation", name))
3022         return 0;
3023     if (!validateString("getUniformLocation", name))
3024         return 0;
3025     if (isPrefixReserved(name))
3026         return 0;
3027     if (!program->getLinkStatus()) {
3028         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniformLocation", "program not linked");
3029         return 0;
3030     }
3031     WebGLStateRestorer(this, false);
3032     GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
3033     if (uniformLocation == -1)
3034         return 0;
3035     return WebGLUniformLocation::create(program, uniformLocation);
3036 }
3037
3038 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
3039 {
3040     UNUSED_PARAM(ec);
3041     if (isContextLost())
3042         return WebGLGetInfo();
3043     WebGLStateRestorer(this, false);
3044     if (index >= m_maxVertexAttribs) {
3045         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
3046         return WebGLGetInfo();
3047     }
3048     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
3049     switch (pname) {
3050     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
3051         if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
3052             || !state.bufferBinding
3053             || !state.bufferBinding->object())
3054             return WebGLGetInfo();
3055         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
3056     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
3057         return WebGLGetInfo(state.enabled);
3058     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
3059         return WebGLGetInfo(state.normalized);
3060     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
3061         return WebGLGetInfo(state.size);
3062     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
3063         return WebGLGetInfo(state.originalStride);
3064     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
3065         return WebGLGetInfo(state.type);
3066     case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
3067         return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
3068     default:
3069         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
3070         return WebGLGetInfo();
3071     }
3072 }
3073
3074 long long WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
3075 {
3076     if (isContextLost())
3077         return 0;
3078     GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
3079     cleanupAfterGraphicsCall(false);
3080     return static_cast<long long>(result);
3081 }
3082
3083 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
3084 {
3085     if (isContextLost())
3086         return;
3087     bool isValid = false;
3088     switch (target) {
3089     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
3090         isValid = true;
3091         break;
3092     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
3093         if (m_oesStandardDerivatives)
3094             isValid = true;
3095         break;
3096     }
3097     if (!isValid) {
3098         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target");
3099         return;
3100     }
3101     m_context->hint(target, mode);
3102     cleanupAfterGraphicsCall(false);
3103 }
3104
3105 GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
3106 {
3107     if (!buffer || isContextLost())
3108         return 0;
3109
3110     if (!buffer->hasEverBeenBound())
3111         return 0;
3112
3113     return m_context->isBuffer(buffer->object());
3114 }
3115
3116 bool WebGLRenderingContext::isContextLost()
3117 {
3118     return m_contextLost;
3119 }
3120
3121 GC3Dboolean WebGLRenderingContext::isEnabled(GC3Denum cap)
3122 {
3123     if (isContextLost() || !validateCapability("isEnabled", cap))
3124         return 0;
3125     if (cap == GraphicsContext3D::STENCIL_TEST)
3126         return m_stencilEnabled;
3127     return m_context->isEnabled(cap);
3128 }
3129
3130 GC3Dboolean WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer)
3131 {
3132     if (!framebuffer || isContextLost())
3133         return 0;
3134
3135     if (!framebuffer->hasEverBeenBound())
3136         return 0;
3137
3138     return m_context->isFramebuffer(framebuffer->object());
3139 }
3140
3141 GC3Dboolean WebGLRenderingContext::isProgram(WebGLProgram* program)
3142 {
3143     if (!program || isContextLost())
3144         return 0;
3145
3146     return m_context->isProgram(program->object());
3147 }
3148
3149 GC3Dboolean WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
3150 {
3151     if (!renderbuffer || isContextLost())
3152         return 0;
3153
3154     if (!renderbuffer->hasEverBeenBound())
3155         return 0;
3156
3157     return m_context->isRenderbuffer(renderbuffer->object());
3158 }
3159
3160 GC3Dboolean WebGLRenderingContext::isShader(WebGLShader* shader)
3161 {
3162     if (!shader || isContextLost())
3163         return 0;
3164
3165     return m_context->isShader(shader->object());
3166 }
3167
3168 GC3Dboolean WebGLRenderingContext::isTexture(WebGLTexture* texture)
3169 {
3170     if (!texture || isContextLost())
3171         return 0;
3172
3173     if (!texture->hasEverBeenBound())
3174         return 0;
3175
3176     return m_context->isTexture(texture->object());
3177 }
3178
3179 void WebGLRenderingContext::lineWidth(GC3Dfloat width)
3180 {
3181     if (isContextLost())
3182         return;
3183     m_context->lineWidth(width);
3184     cleanupAfterGraphicsCall(false);
3185 }
3186
3187 void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec)
3188 {
3189     UNUSED_PARAM(ec);
3190     if (isContextLost() || !validateWebGLObject("linkProgram", program))
3191         return;
3192     if (!isGLES2Compliant()) {
3193         if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
3194             program->setLinkStatus(false);
3195             return;
3196         }
3197     }
3198
3199     m_context->linkProgram(objectOrZero(program));
3200     program->increaseLinkCount();
3201     cleanupAfterGraphicsCall(false);
3202 }
3203
3204 void WebGLRenderingContext::pixelStorei(GC3Denum pname, GC3Dint param)
3205 {
3206     if (isContextLost())
3207         return;
3208     switch (pname) {
3209     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
3210         m_unpackFlipY = param;
3211         break;
3212     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
3213         m_unpackPremultiplyAlpha = param;
3214         break;
3215     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
3216         if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
3217             m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
3218         else {
3219             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
3220             return;
3221         }
3222         break;
3223     case GraphicsContext3D::PACK_ALIGNMENT:
3224     case GraphicsContext3D::UNPACK_ALIGNMENT:
3225         if (param == 1 || param == 2 || param == 4 || param == 8) {
3226             if (pname == GraphicsContext3D::PACK_ALIGNMENT)
3227                 m_packAlignment = param;
3228             else // GraphicsContext3D::UNPACK_ALIGNMENT:
3229                 m_unpackAlignment = param;
3230             m_context->pixelStorei(pname, param);
3231             cleanupAfterGraphicsCall(false);
3232         } else {
3233             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
3234             return;
3235         }
3236         break;
3237     default:
3238         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "pixelStorei", "invalid parameter name");
3239         return;
3240     }
3241 }
3242
3243 void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
3244 {
3245     if (isContextLost())
3246         return;
3247     m_context->polygonOffset(factor, units);
3248     cleanupAfterGraphicsCall(false);
3249 }
3250
3251 void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&)
3252 {
3253     if (isContextLost())
3254         return;
3255     // Due to WebGL's same-origin restrictions, it is not possible to
3256     // taint the origin using the WebGL API.
3257     ASSERT(canvas()->originClean());
3258     // Validate input parameters.
3259     if (!pixels) {
3260         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "readPixels", "no destination ArrayBufferView");
3261         return;
3262     }
3263     switch (format) {
3264     case GraphicsContext3D::ALPHA:
3265     case GraphicsContext3D::RGB:
3266     case GraphicsContext3D::RGBA:
3267         break;
3268     default:
3269         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid format");
3270         return;
3271     }
3272     switch (type) {
3273     case GraphicsContext3D::UNSIGNED_BYTE:
3274     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
3275     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
3276     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
3277         break;
3278     default:
3279         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid type");
3280         return;
3281     }
3282     if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
3283         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "format not RGBA or type not UNSIGNED_BYTE");
3284         return;
3285     }
3286     // Validate array type against pixel type.
3287     if (pixels->getType() != ArrayBufferView::TypeUint8) {
3288         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not Uint8Array");
3289         return;
3290     }
3291     const char* reason = "framebuffer incomplete";
3292     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
3293         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
3294         return;
3295     }
3296     // Calculate array size, taking into consideration of PACK_ALIGNMENT.
3297     unsigned int totalBytesRequired;
3298     unsigned int padding;
3299     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
3300     if (error != GraphicsContext3D::NO_ERROR) {
3301         synthesizeGLError(error, "readPixels", "invalid dimensions");
3302         return;
3303     }
3304     if (pixels->byteLength() < totalBytesRequired) {
3305         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
3306         return;
3307     }
3308     clearIfComposited();
3309     void* data = pixels->baseAddress();
3310
3311     {
3312         ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
3313         m_context->readPixels(x, y, width, height, format, type, data);
3314     }
3315
3316 #if OS(DARWIN) || OS(QNX) || PLATFORM(EFL)
3317     // FIXME: remove this section when GL driver bug on Mac AND the GLES driver bug
3318     // on QC & Imagination QNX is fixed, i.e., when alpha is off, readPixels should
3319     // set alpha to 255 instead of 0.
3320     if (!m_framebufferBinding && !m_context->getContextAttributes().alpha) {
3321         unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
3322         for (GC3Dsizei iy = 0; iy < height; ++iy) {
3323             for (GC3Dsizei ix = 0; ix < width; ++ix) {
3324                 pixels[3] = 255;
3325                 pixels += 4;
3326             }
3327             pixels += padding;
3328         }
3329     }
3330 #endif
3331     cleanupAfterGraphicsCall(false);
3332 }
3333
3334 void WebGLRenderingContext::releaseShaderCompiler()
3335 {
3336     if (isContextLost())
3337         return;
3338     m_context->releaseShaderCompiler();
3339     cleanupAfterGraphicsCall(false);
3340 }
3341
3342 void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
3343 {
3344     if (isContextLost())
3345         return;
3346     if (target != GraphicsContext3D::RENDERBUFFER) {
3347         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid target");
3348         return;
3349     }
3350     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
3351         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer");
3352         return;
3353     }
3354     if (!validateSize("renderbufferStorage", width, height))
3355         return;
3356     switch (internalformat) {
3357     case GraphicsContext3D::DEPTH_COMPONENT16:
3358     case GraphicsContext3D::RGBA4:
3359     case GraphicsContext3D::RGB5_A1:
3360     case GraphicsContext3D::RGB565:
3361     case GraphicsContext3D::STENCIL_INDEX8:
3362         m_context->renderbufferStorage(target, internalformat, width, height);
3363         m_renderbufferBinding->setInternalFormat(internalformat);
3364         m_renderbufferBinding->setIsValid(true);
3365         m_renderbufferBinding->setSize(width, height);
3366         cleanupAfterGraphicsCall(false);
3367         break;
3368     case GraphicsContext3D::DEPTH_STENCIL:
3369         if (isDepthStencilSupported()) {
3370             m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
3371             cleanupAfterGraphicsCall(false);
3372         }
3373         m_renderbufferBinding->setSize(width, height);
3374         m_renderbufferBinding->setIsValid(isDepthStencilSupported());
3375         m_renderbufferBinding->setInternalFormat(internalformat);
3376         break;
3377     default:
3378         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
3379         return;
3380     }
3381     applyStencilTest();
3382 }
3383
3384 void WebGLRenderingContext::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
3385 {
3386     if (isContextLost())
3387         return;
3388     m_context->sampleCoverage(value, invert);
3389     cleanupAfterGraphicsCall(false);
3390 }
3391
3392 void WebGLRenderingContext::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
3393 {
3394     if (isContextLost())
3395         return;
3396     if (!validateSize("scissor", width, height))
3397         return;
3398     m_context->scissor(x, y, width, height);
3399     cleanupAfterGraphicsCall(false);
3400 }
3401
3402 void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
3403 {
3404     UNUSED_PARAM(ec);
3405     if (isContextLost() || !validateWebGLObject("shaderSource", shader))
3406         return;
3407     String stringWithoutComments = StripComments(string).result();
3408     if (!validateString("shaderSource", stringWithoutComments))
3409         return;
3410     shader->setSource(string);
3411     m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
3412     cleanupAfterGraphicsCall(false);
3413 }
3414
3415 void WebGLRenderingContext::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
3416 {
3417     if (isContextLost())
3418         return;
3419     if (!validateStencilFunc("stencilFunc", func))
3420         return;
3421     m_stencilFuncRef = ref;
3422     m_stencilFuncRefBack = ref;
3423     m_stencilFuncMask = mask;
3424     m_stencilFuncMaskBack = mask;
3425     m_context->stencilFunc(func, ref, mask);
3426     cleanupAfterGraphicsCall(false);
3427 }
3428
3429 void WebGLRenderingContext::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
3430 {
3431     if (isContextLost())
3432         return;
3433     if (!validateStencilFunc("stencilFuncSeparate", func))
3434         return;
3435     switch (face) {
3436     case GraphicsContext3D::FRONT_AND_BACK:
3437         m_stencilFuncRef = ref;
3438         m_stencilFuncRefBack = ref;
3439         m_stencilFuncMask = mask;
3440         m_stencilFuncMaskBack = mask;
3441         break;
3442     case GraphicsContext3D::FRONT:
3443         m_stencilFuncRef = ref;
3444         m_stencilFuncMask = mask;
3445         break;
3446     case GraphicsContext3D::BACK:
3447         m_stencilFuncRefBack = ref;
3448         m_stencilFuncMaskBack = mask;
3449         break;
3450     default:
3451         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilFuncSeparate", "invalid face");
3452         return;
3453     }
3454     m_context->stencilFuncSeparate(face, func, ref, mask);
3455     cleanupAfterGraphicsCall(false);
3456 }
3457
3458 void WebGLRenderingContext::stencilMask(GC3Duint mask)
3459 {
3460     if (isContextLost())
3461         return;
3462     m_stencilMask = mask;
3463     m_stencilMaskBack = mask;
3464     m_context->stencilMask(mask);
3465     cleanupAfterGraphicsCall(false);
3466 }
3467
3468 void WebGLRenderingContext::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
3469 {
3470     if (isContextLost())
3471         return;
3472     switch (face) {
3473     case GraphicsContext3D::FRONT_AND_BACK:
3474         m_stencilMask = mask;
3475         m_stencilMaskBack = mask;
3476         break;
3477     case GraphicsContext3D::FRONT:
3478         m_stencilMask = mask;
3479         break;
3480     case GraphicsContext3D::BACK:
3481         m_stencilMaskBack = mask;
3482         break;
3483     default:
3484         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilMaskSeparate", "invalid face");
3485         return;
3486     }
3487     m_context->stencilMaskSeparate(face, mask);
3488     cleanupAfterGraphicsCall(false);
3489 }
3490
3491 void WebGLRenderingContext::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3492 {
3493     if (isContextLost())
3494         return;
3495     m_context->stencilOp(fail, zfail, zpass);
3496     cleanupAfterGraphicsCall(false);
3497 }
3498
3499 void WebGLRenderingContext::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3500 {
3501     if (isContextLost())
3502         return;
3503     m_context->stencilOpSeparate(face, fail, zfail, zpass);
3504     cleanupAfterGraphicsCall(false);
3505 }
3506
3507 void WebGLRenderingContext::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3508                                            GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3509                                            GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3510 {
3511     // FIXME: For now we ignore any errors returned
3512     ec = 0;
3513     if (!validateTexFuncParameters("texImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, format, type))
3514         return;
3515     WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
3516     if (!tex)
3517         return;
3518     if (!isGLES2NPOTStrict()) {
3519         if (level && WebGLTexture::isNPOT(width, height)) {
3520             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "level > 0 not power of 2");
3521             return;
3522         }
3523     }
3524     if (!pixels) {
3525         // Note: Chromium's OpenGL implementation clears textures and isResourceSafe() is therefore true.
3526         // For other implementations, if they are using ANGLE_depth_texture, ANGLE depth textures
3527         // can not be cleared with texImage2D and must be cleared by binding to an fbo and calling
3528         // clear.
3529         if (isResourceSafe())
3530             m_context->texImage2D(target, level, internalformat, width, height, border, format, type, 0);
3531         else {
3532             bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
3533                                                              border, format, type, m_unpackAlignment);
3534             if (!succeed)
3535                 return;
3536         }
3537     } else {
3538         if (!validateSettableTexFormat("texImage2D", internalformat))
3539             return;
3540         m_context->texImage2D(target, level, internalformat, width, height,
3541                               border, format, type, pixels);
3542     }
3543     tex->setLevelInfo(target, level, internalformat, width, height, type);
3544     cleanupAfterGraphicsCall(false);
3545 }
3546
3547 void WebGLRenderingContext::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3548                                            GC3Denum format, GC3Denum type, Image* image,
3549                                            bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3550 {
3551     ec = 0;
3552     if (!validateSettableTexFormat("texImage2D", internalformat))
3553         return;
3554     Vector<uint8_t> data;
3555     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3556         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3557         return;
3558     }
3559     if (m_unpackAlignment != 1)
3560         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3561 #if ENABLE(TIZEN_JPEG_IMAGE_SCALE_DECODING)
3562     unsigned int componentsPerPixel;
3563     unsigned int bytesPerComponent;
3564     if (!GraphicsContext3D::computeFormatAndTypeParameters(format, type, &componentsPerPixel, &bytesPerComponent)) {
3565         ASSERT_NOT_REACHED();
3566         return;
3567     }
3568     int dataSize = data.size() / (componentsPerPixel * bytesPerComponent);
3569     int imageSize = image->width() * image->height();
3570     if (dataSize != imageSize) {
3571         double scale = sqrt(static_cast<double>(dataSize) / imageSize);
3572         texImage2DBase(target, level, internalformat, image->width()*scale, image->height()*scale, 0,
3573                        format, type, data.data(), ec);
3574     } else
3575 #endif
3576     texImage2DBase(target, level, internalformat, image->width(), image->height(), 0,
3577                    format, type, data.data(), ec);
3578     if (m_unpackAlignment != 1)
3579         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3580 }
3581
3582 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3583                                        GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3584                                        GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3585 {
3586     if (isContextLost() || !validateTexFuncData("texImage2D", level, width, height, format, type, pixels, NullAllowed))
3587         return;
3588     void* data = pixels ? pixels->baseAddress() : 0;
3589     Vector<uint8_t> tempData;
3590     bool changeUnpackAlignment = false;
3591     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3592         if (!m_context->extractTextureData(width, height, format, type,
3593                                            m_unpackAlignment,
3594                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3595                                            data,
3596                                            tempData))
3597             return;
3598         data = tempData.data();
3599         changeUnpackAlignment = true;
3600     }
3601     if (changeUnpackAlignment)
3602         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3603     texImage2DBase(target, level, internalformat, width, height, border,
3604                    format, type, data, ec);
3605     if (changeUnpackAlignment)
3606         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3607 }
3608
3609 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3610                                        GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3611 {
3612     ec = 0;
3613     if (isContextLost())
3614         return;
3615     Vector<uint8_t> data;
3616     if (!pixels)
3617         return;
3618     bool needConversion = true;
3619     // The data from ImageData is always of format RGBA8.
3620     // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3621     if (!m_unpackFlipY && !m_unpackPremultiplyAlpha && format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE)
3622         needConversion = false;
3623     else {
3624         if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3625             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3626             return;
3627         }
3628     }
3629     if (m_unpackAlignment != 1)
3630         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3631     texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, needConversion ? data.data() : pixels->data()->data(), ec);
3632     if (m_unpackAlignment != 1)
3633         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3634 }
3635
3636 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3637                                        GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3638 {
3639     ec = 0;
3640     if (isContextLost())
3641         return;
3642     if (!validateHTMLImageElement("texImage2D", image))
3643         return;
3644     if (wouldTaintOrigin(image)) {
3645         ec = SECURITY_ERR;
3646         return;
3647     }
3648
3649     texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->imageForRenderer(image->renderer()),
3650                    m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3651 }
3652
3653 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3654                                        GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3655 {
3656     ec = 0;
3657     if (isContextLost())
3658         return;
3659     if (!canvas || !canvas->buffer()) {
3660         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "no canvas");
3661         return;
3662     }
3663     if (wouldTaintOrigin(canvas)) {
3664         ec = SECURITY_ERR;
3665         return;
3666     }
3667
3668     WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
3669     // If possible, copy from the canvas element directly to the texture
3670     // via the GPU, without a read-back to system memory.
3671     if (GraphicsContext3D::TEXTURE_2D == target && texture && type == texture->getType(target, level)) {
3672         ImageBuffer* buffer = canvas->buffer();
3673         if (buffer && buffer->copyToPlatformTexture(*m_context.get(), texture->object(), internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3674             texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type);
3675             cleanupAfterGraphicsCall(false);
3676             return;
3677         }
3678     }
3679
3680     RefPtr<ImageData> imageData = canvas->getImageData();
3681     if (imageData)
3682         texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
3683     else
3684         texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(),
3685                        m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3686 }
3687
3688 #if ENABLE(VIDEO)
3689 PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video, ExceptionCode& ec)
3690 {
3691     if (!video || !video->videoWidth() || !video->videoHeight()) {
3692         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "no video");
3693         return 0;
3694     }
3695     IntSize size(video->videoWidth(), video->videoHeight());
3696     ImageBuffer* buf = m_videoCache.imageBuffer(size);
3697     if (!buf) {
3698         synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "texImage2D", "out of memory");
3699         return 0;
3700     }
3701     if (wouldTaintOrigin(video)) {
3702         ec = SECURITY_ERR;
3703         return 0;
3704     }
3705     IntRect destRect(0, 0, size.width(), size.height());
3706     // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
3707     video->paintCurrentFrameInContext(buf->context(), destRect);
3708     return buf->copyImage(CopyBackingStore);
3709 }
3710
3711 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3712                                        GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3713 {
3714     ec = 0;
3715     if (isContextLost())
3716         return;
3717     RefPtr<Image> image = videoFrameToImage(video, ec);
3718     if (!image)
3719         return;
3720     texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3721 }
3722 #endif
3723
3724 void WebGLRenderingContext::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
3725 {
3726     if (isContextLost())
3727         return;
3728     WebGLTexture* tex = validateTextureBinding("texParameter", target, false);
3729     if (!tex)
3730         return;
3731     switch (pname) {
3732     case GraphicsContext3D::TEXTURE_MIN_FILTER:
3733     case GraphicsContext3D::TEXTURE_MAG_FILTER:
3734         break;
3735     case GraphicsContext3D::TEXTURE_WRAP_S:
3736     case GraphicsContext3D::TEXTURE_WRAP_T:
3737         if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT)
3738             || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) {
3739             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter");
3740             return;
3741         }
3742         break;
3743     case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
3744         if (!m_extTextureFilterAnisotropic) {
3745             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter, EXT_texture_filter_anisotropic not enabled");
3746             return;
3747         }
3748         break;
3749     default:
3750         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter name");
3751         return;
3752     }
3753     if (isFloat) {
3754         tex->setParameterf(pname, paramf);
3755         m_context->texParameterf(target, pname, paramf);
3756     } else {
3757         tex->setParameteri(pname, parami);
3758         m_context->texParameteri(target, pname, parami);
3759     }
3760     cleanupAfterGraphicsCall(false);
3761 }
3762
3763 void WebGLRenderingContext::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
3764 {
3765     texParameter(target, pname, param, 0, true);
3766 }
3767
3768 void WebGLRenderingContext::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
3769 {
3770     texParameter(target, pname, 0, param, false);
3771 }
3772
3773 void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3774                                               GC3Dsizei width, GC3Dsizei height,
3775                                               GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3776 {
3777     // FIXME: For now we ignore any errors returned
3778     ec = 0;
3779     if (isContextLost())
3780         return;
3781     if (!validateTexFuncParameters("texSubImage2D", TexSubImage2D, target, level, format, width, height, 0, format, type))
3782         return;
3783     if (!validateSize("texSubImage2D", xoffset, yoffset))
3784         return;
3785     if (!validateSettableTexFormat("texSubImage2D", format))
3786         return;
3787     WebGLTexture* tex = validateTextureBinding("texSubImage2D", target, true);
3788     if (!tex)
3789         return;
3790     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
3791         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "dimensions out of range");
3792         return;
3793     }
3794     if (tex->getInternalFormat(target, level) != format || tex->getType(target, level) != type) {
3795         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "texSubImage2D", "type and format do not match texture");
3796         return;
3797     }
3798     m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
3799     cleanupAfterGraphicsCall(false);
3800 }
3801
3802 void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3803                                               GC3Denum format, GC3Denum type,
3804                                               Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3805 {
3806     ec = 0;
3807     if (isContextLost())
3808         return;
3809     Vector<uint8_t> data;
3810     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3811         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image");
3812         return;
3813     }
3814     if (m_unpackAlignment != 1)
3815         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3816     texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(),
3817                       format, type, data.data(), ec);
3818     if (m_unpackAlignment != 1)
3819         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3820 }
3821
3822 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3823                                           GC3Dsizei width, GC3Dsizei height,
3824                                           GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3825 {
3826     if (isContextLost() || !validateTexFuncData("texSubImage2D", level, width, height, format, type, pixels, NullNotAllowed))
3827         return;
3828     void* data = pixels->baseAddress();
3829     Vector<uint8_t> tempData;
3830     bool changeUnpackAlignment = false;
3831     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3832         if (!m_context->extractTextureData(width, height, format, type,
3833                                            m_unpackAlignment,
3834                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3835                                            data,
3836                                            tempData))
3837             return;
3838         data = tempData.data();
3839         changeUnpackAlignment = true;
3840     }
3841     if (changeUnpackAlignment)
3842         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3843     texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
3844     if (changeUnpackAlignment)
3845         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3846 }
3847
3848 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3849                                           GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3850 {
3851     ec = 0;
3852     if (isContextLost())
3853         return;
3854     if (!pixels)
3855         return;
3856     Vector<uint8_t> data;
3857     bool needConversion = true;
3858     // The data from ImageData is always of format RGBA8.
3859     // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3860     if (format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE && !m_unpackFlipY && !m_unpackPremultiplyAlpha)
3861         needConversion = false;
3862     else {
3863         if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3864             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image data");
3865             return;
3866         }
3867     }
3868     if (m_unpackAlignment != 1)
3869         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3870     texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(), format, type, needConversion ? data.data() : pixels->data()->data(), ec);
3871     if (m_unpackAlignment != 1)
3872         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3873 }
3874
3875 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3876                                           GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3877 {
3878     ec = 0;
3879     if (isContextLost())
3880         return;
3881     if (!validateHTMLImageElement("texSubImage2D", image))
3882         return;
3883     if (wouldTaintOrigin(image)) {
3884         ec = SECURITY_ERR;
3885         return;
3886     }
3887     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image->cachedImage()->imageForRenderer(image->renderer()),
3888                       m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3889 }
3890
3891 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3892                                           GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3893 {
3894     ec = 0;
3895     if (isContextLost())
3896         return;
3897     if (!canvas || !canvas->buffer()) {
3898         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "no canvas");
3899         return;
3900     }
3901     if (wouldTaintOrigin(canvas)) {
3902         ec = SECURITY_ERR;
3903         return;
3904     }
3905     RefPtr<ImageData> imageData = canvas->getImageData();
3906     if (imageData)
3907         texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec);
3908     else
3909         texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(),
3910                           m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3911 }
3912
3913 #if ENABLE(VIDEO)
3914 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3915                                           GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3916 {
3917     ec = 0;
3918     if (isContextLost())
3919         return;
3920     RefPtr<Image> image = videoFrameToImage(video, ec);
3921     if (!image)
3922         return;
3923     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3924 }
3925 #endif
3926
3927 void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode& ec)
3928 {
3929     UNUSED_PARAM(ec);
3930     if (isContextLost() || !location)
3931         return;
3932
3933     if (location->program() != m_currentProgram) {
3934         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform1f", "location not for current program");
3935         return;
3936     }
3937
3938     m_context->uniform1f(location->location(), x);
3939     cleanupAfterGraphicsCall(false);
3940 }
3941
3942 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3943 {
3944     UNUSED_PARAM(ec);
3945     if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, 1))
3946         return;
3947
3948     m_context->uniform1fv(location->location(), v->length(), v->data());
3949     cleanupAfterGraphicsCall(false);
3950 }
3951
3952 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3953 {
3954     UNUSED_PARAM(ec);
3955     if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, size, 1))
3956         return;
3957
3958     m_context->uniform1fv(location->location(), size, v);
3959     cleanupAfterGraphicsCall(false);
3960 }
3961
3962 void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode& ec)
3963 {
3964     UNUSED_PARAM(ec);
3965     if (isContextLost() || !location)
3966         return;
3967
3968     if (location->program() != m_currentProgram) {
3969         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform1i", "location not for current program");
3970         return;
3971     }
3972
3973     m_context->uniform1i(location->location(), x);
3974     cleanupAfterGraphicsCall(false);
3975 }
3976
3977 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3978 {
3979     UNUSED_PARAM(ec);
3980     if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, 1))
3981         return;
3982
3983     m_context->uniform1iv(location->location(), v->length(), v->data());
3984     cleanupAfterGraphicsCall(false);
3985 }
3986
3987 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3988 {
3989     UNUSED_PARAM(ec);
3990     if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, size, 1))
3991         return;
3992
3993     m_context->uniform1iv(location->location(), size, v);
3994     cleanupAfterGraphicsCall(false);
3995 }
3996
3997 void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode& ec)
3998 {
3999     UNUSED_PARAM(ec);
4000     if (isContextLost() || !location)
4001         return;
4002
4003     if (location->program() != m_currentProgram) {
4004         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform2f", "location not for current program");
4005         return;
4006     }
4007
4008     m_context->uniform2f(location->location(), x, y);
4009     cleanupAfterGraphicsCall(false);
4010 }
4011
4012 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
4013 {
4014     UNUSED_PARAM(ec);
4015     if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, 2))
4016         return;
4017
4018     m_context->uniform2fv(location->location(), v->length() / 2, v->data());
4019     cleanupAfterGraphicsCall(false);
4020 }
4021
4022 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4023 {
4024     UNUSED_PARAM(ec);
4025     if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, size, 2))
4026         return;
4027
4028     m_context->uniform2fv(location->location(), size / 2, v);
4029     cleanupAfterGraphicsCall(false);
4030 }
4031
4032 void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode& ec)
4033 {
4034     UNUSED_PARAM(ec);
4035     if (isContextLost() || !location)
4036         return;
4037
4038     if (location->program() != m_currentProgram) {
4039         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform2i", "location not for current program");
4040         return;
4041     }
4042
4043     m_context->uniform2i(location->location(), x, y);
4044     cleanupAfterGraphicsCall(false);
4045 }
4046
4047 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
4048 {
4049     UNUSED_PARAM(ec);
4050     if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, 2))
4051         return;
4052
4053     m_context->uniform2iv(location->location(), v->length() / 2, v->data());
4054     cleanupAfterGraphicsCall(false);
4055 }
4056
4057 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
4058 {
4059     UNUSED_PARAM(ec);
4060     if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, size, 2))
4061         return;
4062
4063     m_context->uniform2iv(location->location(), size / 2, v);
4064     cleanupAfterGraphicsCall(false);
4065 }
4066
4067 void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode& ec)
4068 {
4069     UNUSED_PARAM(ec);
4070     if (isContextLost() || !location)
4071         return;
4072
4073     if (location->program() != m_currentProgram) {
4074         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform3f", "location not for current program");
4075         return;
4076     }
4077
4078     m_context->uniform3f(location->location(), x, y, z);
4079     cleanupAfterGraphicsCall(false);
4080 }
4081
4082 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
4083 {
4084     UNUSED_PARAM(ec);
4085     if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, 3))
4086         return;
4087
4088     m_context->uniform3fv(location->location(), v->length() / 3, v->data());
4089     cleanupAfterGraphicsCall(false);
4090 }
4091
4092 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4093 {
4094     UNUSED_PARAM(ec);
4095     if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, size, 3))
4096         return;
4097
4098     m_context->uniform3fv(location->location(), size / 3, v);
4099     cleanupAfterGraphicsCall(false);
4100 }
4101
4102 void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode& ec)
4103 {
4104     UNUSED_PARAM(ec);
4105     if (isContextLost() || !location)
4106         return;
4107
4108     if (location->program() != m_currentProgram) {
4109         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform3i", "location not for current program");
4110         return;
4111     }
4112
4113     m_context->uniform3i(location->location(), x, y, z);
4114     cleanupAfterGraphicsCall(false);
4115 }
4116
4117 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
4118 {
4119     UNUSED_PARAM(ec);
4120     if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, 3))
4121         return;
4122
4123     m_context->uniform3iv(location->location(), v->length() / 3, v->data());
4124     cleanupAfterGraphicsCall(false);
4125 }
4126
4127 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
4128 {
4129     UNUSED_PARAM(ec);
4130     if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, size, 3))
4131         return;
4132
4133     m_context->uniform3iv(location->location(), size / 3, v);
4134     cleanupAfterGraphicsCall(false);
4135 }
4136
4137 void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode& ec)
4138 {
4139     UNUSED_PARAM(ec);
4140     if (isContextLost() || !location)
4141         return;
4142
4143     if (location->program() != m_currentProgram) {
4144         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform4f", "location not for current program");
4145         return;
4146     }
4147
4148     m_context->uniform4f(location->location(), x, y, z, w);
4149     cleanupAfterGraphicsCall(false);
4150 }
4151
4152 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
4153 {
4154     UNUSED_PARAM(ec);
4155     if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, 4))
4156         return;
4157
4158     m_context->uniform4fv(location->location(), v->length() / 4, v->data());
4159     cleanupAfterGraphicsCall(false);
4160 }
4161
4162 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4163 {
4164     UNUSED_PARAM(ec);
4165     if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, size, 4))
4166         return;
4167
4168     m_context->uniform4fv(location->location(), size / 4, v);
4169     cleanupAfterGraphicsCall(false);
4170 }
4171
4172 void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode& ec)
4173 {
4174     UNUSED_PARAM(ec);
4175     if (isContextLost() || !location)
4176         return;
4177
4178     if (location->program() != m_currentProgram) {
4179         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform4i", "location not for current program");
4180         return;
4181     }
4182
4183     m_context->uniform4i(location->location(), x, y, z, w);
4184     cleanupAfterGraphicsCall(false);
4185 }
4186
4187 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
4188 {
4189     UNUSED_PARAM(ec);
4190     if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, 4))
4191         return;
4192
4193     m_context->uniform4iv(location->location(), v->length() / 4, v->data());
4194     cleanupAfterGraphicsCall(false);
4195 }
4196
4197 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
4198 {
4199     UNUSED_PARAM(ec);
4200     if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, size, 4))
4201         return;
4202
4203     m_context->uniform4iv(location->location(), size / 4, v);
4204     cleanupAfterGraphicsCall(false);
4205 }
4206
4207 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
4208 {
4209     UNUSED_PARAM(ec);
4210     if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, 4))
4211         return;
4212     m_context->uniformMatrix2fv(location->location(), v->length() / 4, transpose, v->data());
4213     cleanupAfterGraphicsCall(false);
4214 }
4215
4216 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4217 {
4218     UNUSED_PARAM(ec);
4219     if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, size, 4))
4220         return;
4221     m_context->uniformMatrix2fv(location->location(), size / 4, transpose, v);
4222     cleanupAfterGraphicsCall(false);
4223 }
4224
4225 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
4226 {
4227     UNUSED_PARAM(ec);
4228     if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, 9))
4229         return;
4230     m_context->uniformMatrix3fv(location->location(), v->length() / 9, transpose, v->data());
4231     cleanupAfterGraphicsCall(false);
4232 }
4233
4234 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4235 {
4236     UNUSED_PARAM(ec);
4237     if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, size, 9))
4238         return;
4239     m_context->uniformMatrix3fv(location->location(), size / 9, transpose, v);
4240     cleanupAfterGraphicsCall(false);
4241 }
4242
4243 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
4244 {
4245     UNUSED_PARAM(ec);
4246     if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, 16))
4247         return;
4248     m_context->uniformMatrix4fv(location->location(), v->length() / 16, transpose, v->data());
4249     cleanupAfterGraphicsCall(false);
4250 }
4251
4252 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4253 {
4254     UNUSED_PARAM(ec);
4255     if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, size, 16))
4256         return;
4257     m_context->uniformMatrix4fv(location->location(), size / 16, transpose, v);
4258     cleanupAfterGraphicsCall(false);
4259 }
4260
4261 void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
4262 {
4263     UNUSED_PARAM(ec);
4264     bool deleted;
4265     if (!checkObjectToBeBound("useProgram", program, deleted))
4266         return;
4267     if (deleted)
4268         program = 0;
4269     if (program && !program->getLinkStatus()) {
4270         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "useProgram", "program not valid");
4271         cleanupAfterGraphicsCall(false);
4272         return;
4273     }
4274     if (m_currentProgram != program) {
4275         if (m_currentProgram)
4276             m_currentProgram->onDetached(graphicsContext3D());
4277         m_currentProgram = program;
4278         m_context->useProgram(objectOrZero(program));
4279         if (program)
4280             program->onAttached();
4281     }
4282     cleanupAfterGraphicsCall(false);
4283 }
4284
4285 void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec)
4286 {
4287     UNUSED_PARAM(ec);
4288     if (isContextLost() || !validateWebGLObject("validateProgram", program))
4289         return;
4290     m_context->validateProgram(objectOrZero(program));
4291     cleanupAfterGraphicsCall(false);
4292 }
4293
4294 void WebGLRenderingContext::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
4295 {
4296     vertexAttribfImpl("vertexAttrib1f", index, 1, v0, 0.0f, 0.0f, 1.0f);
4297 }
4298
4299 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, Float32Array* v)
4300 {
4301     vertexAttribfvImpl("vertexAttrib1fv", index, v, 1);
4302 }
4303
4304 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
4305 {
4306     vertexAttribfvImpl("vertexAttrib1fv", index, v, size, 1);
4307 }
4308
4309 void WebGLRenderingContext::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
4310 {
4311     vertexAttribfImpl("vertexAttrib2f", index, 2, v0, v1, 0.0f, 1.0f);
4312 }
4313
4314 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, Float32Array* v)
4315 {
4316     vertexAttribfvImpl("vertexAttrib2fv", index, v, 2);
4317 }
4318
4319 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
4320 {
4321     vertexAttribfvImpl("vertexAttrib2fv", index, v, size, 2);
4322 }
4323
4324 void WebGLRenderingContext::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
4325 {
4326     vertexAttribfImpl("vertexAttrib3f", index, 3, v0, v1, v2, 1.0f);
4327 }
4328
4329 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, Float32Array* v)
4330 {
4331     vertexAttribfvImpl("vertexAttrib3fv", index, v, 3);
4332 }
4333
4334 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
4335 {
4336     vertexAttribfvImpl("vertexAttrib3fv", index, v, size, 3);
4337 }
4338
4339 void WebGLRenderingContext::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
4340 {
4341     vertexAttribfImpl("vertexAttrib4f", index, 4, v0, v1, v2, v3);
4342 }
4343
4344 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, Float32Array* v)
4345 {
4346     vertexAttribfvImpl("vertexAttrib4fv", index, v, 4);
4347 }
4348
4349 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
4350 {
4351     vertexAttribfvImpl("vertexAttrib4fv", index, v, size, 4);
4352 }
4353
4354 void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, long long offset, ExceptionCode& ec)
4355 {
4356     UNUSED_PARAM(ec);
4357     if (isContextLost())
4358         return;
4359     switch (type) {
4360     case GraphicsContext3D::BYTE:
4361     case GraphicsContext3D::UNSIGNED_BYTE:
4362     case GraphicsContext3D::SHORT:
4363     case GraphicsContext3D::UNSIGNED_SHORT:
4364     case GraphicsContext3D::FLOAT:
4365         break;
4366     default:
4367         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "vertexAttribPointer", "invalid type");
4368         return;
4369     }
4370     if (index >= m_maxVertexAttribs) {
4371         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "vertexAttribPointer", "index out of range");
4372         return;
4373     }
4374     if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) {
4375         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "vertexAttribPointer", "bad size, stride or offset");
4376         return;
4377     }
4378     if (!m_boundArrayBuffer) {
4379         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "vertexAttribPointer", "no bound ARRAY_BUFFER");
4380         return;
4381     }
4382     // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
4383     unsigned int typeSize = sizeInBytes(type);
4384     if (!typeSize) {
4385         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "vertexAttribPointer", "invalid type");
4386         return;
4387     }
4388     if ((stride % typeSize) || (static_cast<GC3Dintptr>(offset) % typeSize)) {
4389         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "vertexAttribPointer", "stride or offset not valid for type");
4390         return;
4391     }
4392     GC3Dsizei bytesPerElement = size * typeSize;
4393
4394     GC3Dsizei validatedStride = stride ? stride : bytesPerElement;
4395
4396     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
4397     state.bufferBinding = m_boundArrayBuffer;
4398     state.bytesPerElement = bytesPerElement;
4399     state.size = size;
4400     state.type = type;
4401     state.normalized = normalized;
4402     state.stride = validatedStride;
4403     state.originalStride = stride;
4404     state.offset = static_cast<GC3Dintptr>(offset);
4405     m_context->vertexAttribPointer(index, size, type, normalized, stride, static_cast<GC3Dintptr>(offset));
4406     cleanupAfterGraphicsCall(false);
4407 }
4408
4409 void WebGLRenderingContext::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
4410 {
4411     if (isContextLost())
4412         return;
4413     if (!validateSize("viewport", width, height))
4414         return;
4415     m_context->viewport(x, y, width, height);
4416     cleanupAfterGraphicsCall(false);
4417 }
4418
4419 void WebGLRenderingContext::forceLostContext(WebGLRenderingContext::LostContextMode mode)
4420 {
4421     if (isContextLost()) {
4422         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "loseContext", "context already lost");
4423         return;
4424     }
4425
4426     m_contextGroup->loseContextGroup(mode);
4427 }
4428
4429 void WebGLRenderingContext::loseContextImpl(WebGLRenderingContext::LostContextMode mode)
4430 {
4431     if (isContextLost())
4432         return;
4433
4434     m_contextLost = true;
4435     m_contextLostMode = mode;
4436
4437     detachAndRemoveAllObjects();
4438
4439     if (m_drawingBuffer) {
4440         // Make absolutely sure we do not refer to an already-deleted texture or framebuffer.
4441         m_drawingBuffer->setTexture2DBinding(0);
4442         m_drawingBuffer->setFramebufferBinding(0);
4443     }
4444
4445     // There is no direct way to clear errors from a GL implementation and
4446     // looping until getError() becomes NO_ERROR might cause an infinite loop if
4447     // the driver or context implementation had a bug. So, loop a reasonably
4448     // large number of times to clear any existing errors.
4449     for (int i = 0; i < 100; ++i) {
4450         if (m_context->getError() == GraphicsContext3D::NO_ERROR)
4451             break;
4452     }
4453     synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL, "loseContext", "context lost");
4454
4455     // Don't allow restoration unless the context lost event has both been
4456     // dispatched and its default behavior prevented.
4457     m_restoreAllowed = false;
4458
4459     // Always defer the dispatch of the context lost event, to implement
4460     // the spec behavior of queueing a task.
4461     m_dispatchContextLostEventTimer.startOneShot(0);
4462 }
4463
4464 void WebGLRenderingContext::forceRestoreContext()
4465 {
4466     if (!isContextLost()) {
4467         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "restoreContext", "context not lost");
4468         return;
4469     }
4470
4471     if (!m_restoreAllowed) {
4472         if (m_contextLostMode == SyntheticLostContext)
4473             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "restoreContext", "context restoration not allowed");
4474         return;
4475     }
4476
4477     if (!m_restoreTimer.isActive())
4478         m_restoreTimer.startOneShot(0);
4479 }
4480
4481 #if USE(ACCELERATED_COMPOSITING)
4482 PlatformLayer* WebGLRenderingContext::platformLayer() const
4483 {
4484 #if PLATFORM(CHROMIUM)
4485     if (m_drawingBuffer)
4486         return m_drawingBuffer->platformLayer();
4487 #endif
4488
4489     return m_context->platformLayer();
4490 }
4491 #endif
4492
4493 void WebGLRenderingContext::removeSharedObject(WebGLSharedObject* object)
4494 {
4495     m_contextGroup->removeObject(object);
4496 }
4497
4498 void WebGLRenderingContext::addSharedObject(WebGLSharedObject* object)
4499 {
4500     ASSERT(!isContextLost());
4501     m_contextGroup->addObject(object);
4502 }
4503
4504 void WebGLRenderingContext::removeContextObject(WebGLContextObject* object)
4505 {
4506     m_contextObjects.remove(object);
4507 }
4508
4509 void WebGLRenderingContext::addContextObject(WebGLContextObject* object)
4510 {
4511     ASSERT(!isContextLost());
4512     m_contextObjects.add(object);
4513 }
4514
4515 void WebGLRenderingContext::detachAndRemoveAllObjects()
4516 {
4517     while (m_contextObjects.size() > 0) {
4518         HashSet<WebGLContextObject*>::iterator it = m_contextObjects.begin();
4519         (*it)->detachContext();
4520     }
4521 }
4522
4523 WebGLGetInfo WebGLRenderingContext::getBooleanParameter(GC3Denum pname)
4524 {
4525     GC3Dboolean value = 0;
4526     m_context->getBooleanv(pname, &value);
4527     return WebGLGetInfo(static_cast<bool>(value));
4528 }
4529
4530 WebGLGetInfo WebGLRenderingContext::getBooleanArrayParameter(GC3Denum pname)
4531 {
4532     if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
4533         notImplemented();
4534         return WebGLGetInfo(0, 0);
4535     }
4536     GC3Dboolean value[4] = {0};
4537     m_context->getBooleanv(pname, value);
4538     bool boolValue[4];
4539     for (int ii = 0; ii < 4; ++ii)
4540         boolValue[ii] = static_cast<bool>(value[ii]);
4541     return WebGLGetInfo(boolValue, 4);
4542 }
4543
4544 WebGLGetInfo WebGLRenderingContext::getFloatParameter(GC3Denum pname)
4545 {
4546     GC3Dfloat value = 0;
4547     m_context->getFloatv(pname, &value);
4548     return WebGLGetInfo(value);
4549 }
4550
4551 WebGLGetInfo WebGLRenderingContext::getIntParameter(GC3Denum pname)
4552 {
4553     GC3Dint value = 0;
4554     m_context->getIntegerv(pname, &value);
4555     return WebGLGetInfo(value);
4556 }
4557
4558 WebGLGetInfo WebGLRenderingContext::getUnsignedIntParameter(GC3Denum pname)
4559 {
4560     GC3Dint value = 0;
4561     m_context->getIntegerv(pname, &value);
4562     return WebGLGetInfo(static_cast<unsigned int>(value));
4563 }
4564
4565 WebGLGetInfo WebGLRenderingContext::getWebGLFloatArrayParameter(GC3Denum pname)
4566 {
4567     GC3Dfloat value[4] = {0};
4568     m_context->getFloatv(pname, value);
4569     unsigned length = 0;
4570     switch (pname) {
4571     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
4572     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
4573     case GraphicsContext3D::DEPTH_RANGE:
4574         length = 2;
4575         break;
4576     case GraphicsContext3D::BLEND_COLOR:
4577     case GraphicsContext3D::COLOR_CLEAR_VALUE:
4578         length = 4;
4579         break;
4580     default:
4581         notImplemented();
4582     }
4583     return WebGLGetInfo(Float32Array::create(value, length));
4584 }
4585
4586 WebGLGetInfo WebGLRenderingContext::getWebGLIntArrayParameter(GC3Denum pname)
4587 {
4588     GC3Dint value[4] = {0};
4589     m_context->getIntegerv(pname, value);
4590     unsigned length = 0;
4591     switch (pname) {
4592     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
4593         length = 2;
4594         break;
4595     case GraphicsContext3D::SCISSOR_BOX:
4596     case GraphicsContext3D::VIEWPORT:
4597         length = 4;
4598         break;
4599     default:
4600         notImplemented();
4601     }
4602     return WebGLGetInfo(Int32Array::create(value, length));
4603 }
4604
4605 void WebGLRenderingContext::handleNPOTTextures(bool prepareToDraw)
4606 {
4607     bool resetActiveUnit = false;
4608     for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) {
4609         if ((m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4610             || (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())) {
4611             if (ii != m_activeTextureUnit) {
4612                 m_context->activeTexture(ii);
4613                 resetActiveUnit = true;
4614             } else if (resetActiveUnit) {
4615                 m_context->activeTexture(ii);
4616                 resetActiveUnit = false;
4617             }
4618             WebGLTexture* tex2D;
4619             WebGLTexture* texCubeMap;
4620             if (prepareToDraw) {
4621                 tex2D = m_blackTexture2D.get();
4622                 texCubeMap = m_blackTextureCubeMap.get();
4623             } else {
4624                 tex2D = m_textureUnits[ii].m_texture2DBinding.get();
4625                 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
4626             }
4627             if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4628                 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D));
4629             if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())
4630                 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
4631         }
4632     }
4633     if (resetActiveUnit)
4634         m_context->activeTexture(m_activeTextureUnit);
4635 }
4636
4637 void WebGLRenderingContext::createFallbackBlackTextures1x1()
4638 {
4639     unsigned char black[] = {0, 0, 0, 255};
4640     m_blackTexture2D = createTexture();
4641     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D->object());
4642     m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1,
4643                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4644     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
4645     m_blackTextureCubeMap = createTexture();
4646     m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
4647     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4648                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4649     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4650                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4651     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4652                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4653     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4654                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4655     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4656                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4657     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4658                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4659     m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0);
4660 }
4661
4662 bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,
4663                                                                            GC3Denum colorBufferFormat)
4664 {
4665     unsigned need = GraphicsContext3D::getChannelBitsByFormat(texInternalFormat);
4666     unsigned have = GraphicsContext3D::getChannelBitsByFormat(colorBufferFormat);
4667     return (need & have) == need;
4668 }
4669
4670 GC3Denum WebGLRenderingContext::getBoundFramebufferColorFormat()
4671 {
4672     if (m_framebufferBinding && m_framebufferBinding->object())
4673         return m_framebufferBinding->getColorBufferFormat();
4674     if (m_attributes.alpha)
4675         return GraphicsContext3D::RGBA;
4676     return GraphicsContext3D::RGB;
4677 }
4678
4679 int WebGLRenderingContext::getBoundFramebufferWidth()
4680 {
4681     if (m_framebufferBinding && m_framebufferBinding->object())
4682         return m_framebufferBinding->getColorBufferWidth();
4683     return m_drawingBuffer ? m_drawingBuffer->size().width() : m_context->getInternalFramebufferSize().width();
4684 }
4685
4686 int WebGLRenderingContext::getBoundFramebufferHeight()
4687 {
4688     if (m_framebufferBinding && m_framebufferBinding->object())
4689         return m_framebufferBinding->getColorBufferHeight();
4690     return m_drawingBuffer ? m_drawingBuffer->size().height() : m_context->getInternalFramebufferSize().height();
4691 }
4692
4693 WebGLTexture* WebGLRenderingContext::validateTextureBinding(const char* functionName, GC3Denum target, bool useSixEnumsForCubeMap)
4694 {
4695     WebGLTexture* tex = 0;
4696     switch (target) {
4697     case GraphicsContext3D::TEXTURE_2D:
4698         tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
4699         break;
4700     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4701     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4702     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4703     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4704     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4705     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4706         if (!useSixEnumsForCubeMap) {
4707             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture target");
4708             return 0;
4709         }
4710         tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4711         break;
4712     case GraphicsContext3D::TEXTURE_CUBE_MAP:
4713         if (useSixEnumsForCubeMap) {
4714             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture target");
4715             return 0;
4716         }
4717         tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4718         break;
4719     default:
4720         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture target");
4721         return 0;
4722     }
4723     if (!tex)
4724         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no texture");
4725     return tex;
4726 }
4727
4728 bool WebGLRenderingContext::validateLocationLength(const char* functionName, const String& string)
4729 {
4730     const unsigned maxWebGLLocationLength = 256;
4731     if (string.length() > maxWebGLLocationLength) {
4732         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "location length > 256");
4733         return false;
4734     }
4735     return true;
4736 }
4737
4738 bool WebGLRenderingContext::validateSize(const char* functionName, GC3Dint x, GC3Dint y)
4739 {
4740     if (x < 0 || y < 0) {
4741         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "size < 0");
4742         return false;
4743     }
4744     return true;
4745 }
4746
4747 bool WebGLRenderingContext::validateString(const char* functionName, const String& string)
4748 {
4749     for (size_t i = 0; i < string.length(); ++i) {
4750         if (!validateCharacter(string[i])) {
4751             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "string not ASCII");
4752             return false;
4753         }
4754     }
4755     return true;
4756 }
4757
4758 bool WebGLRenderingContext::validateTexFuncFormatAndType(const char* functionName, GC3Denum format, GC3Denum type, GC3Dint level)
4759 {
4760     switch (format) {
4761     case GraphicsContext3D::ALPHA:
4762     case GraphicsContext3D::LUMINANCE:
4763     case GraphicsContext3D::LUMINANCE_ALPHA:
4764     case GraphicsContext3D::RGB:
4765     case GraphicsContext3D::RGBA:
4766         break;
4767     case GraphicsContext3D::DEPTH_STENCIL:
4768     case GraphicsContext3D::DEPTH_COMPONENT:
4769         if (m_webglDepthTexture)
4770             break;
4771         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "depth texture formats not enabled");
4772         return false;
4773     default:
4774         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture format");
4775         return false;
4776     }
4777
4778     switch (type) {
4779     case GraphicsContext3D::UNSIGNED_BYTE:
4780     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4781     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4782     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4783         break;
4784     case GraphicsContext3D::FLOAT:
4785         if (m_oesTextureFloat)
4786             break;
4787         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
4788         return false;
4789     case GraphicsContext3D::UNSIGNED_INT:
4790     case GraphicsContext3D::UNSIGNED_INT_24_8:
4791     case GraphicsContext3D::UNSIGNED_SHORT:
4792         if (m_webglDepthTexture)
4793             break;
4794         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
4795         return false;
4796     default:
4797         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
4798         return false;
4799     }
4800
4801     // Verify that the combination of format and type is supported.
4802     switch (format) {
4803     case GraphicsContext3D::ALPHA:
4804     case GraphicsContext3D::LUMINANCE:
4805     case GraphicsContext3D::LUMINANCE_ALPHA:
4806         if (type != GraphicsContext3D::UNSIGNED_BYTE
4807             && type != GraphicsContext3D::FLOAT) {
4808             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for format");
4809             return false;
4810         }
4811         break;
4812     case GraphicsContext3D::RGB:
4813         if (type != GraphicsContext3D::UNSIGNED_BYTE
4814             && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5
4815             && type != GraphicsContext3D::FLOAT) {
4816             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for RGB format");
4817             return false;
4818         }
4819         break;
4820     case GraphicsContext3D::RGBA:
4821         if (type != GraphicsContext3D::UNSIGNED_BYTE
4822             && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4
4823             && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1
4824             && type != GraphicsContext3D::FLOAT) {
4825             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for RGBA format");
4826             return false;
4827         }
4828         break;
4829     case GraphicsContext3D::DEPTH_COMPONENT:
4830         if (!m_webglDepthTexture) {
4831             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format. DEPTH_COMPONENT not enabled");
4832             return false;
4833         }
4834         if (type != GraphicsContext3D::UNSIGNED_SHORT
4835             && type != GraphicsContext3D::UNSIGNED_INT) {
4836             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for DEPTH_COMPONENT format");
4837             return false;
4838         }
4839         if (level > 0) {
4840           synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "level must be 0 for DEPTH_COMPONENT format");
4841           return false;
4842         }
4843         break;
4844     case GraphicsContext3D::DEPTH_STENCIL:
4845         if (!m_webglDepthTexture) {
4846             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format. DEPTH_STENCIL not enabled");
4847             return false;
4848         }
4849         if (type != GraphicsContext3D::UNSIGNED_INT_24_8) {
4850             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for DEPTH_STENCIL format");
4851             return false;
4852         }
4853         if (level > 0) {
4854           synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "level must be 0 for DEPTH_STENCIL format");
4855           return false;
4856         }
4857         break;
4858     default:
4859         ASSERT_NOT_REACHED();
4860     }
4861
4862     return true;
4863 }
4864
4865 bool WebGLRenderingContext::validateTexFuncLevel(const char* functionName, GC3Denum target, GC3Dint level)
4866 {
4867     if (level < 0) {
4868         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level < 0");
4869         return false;
4870     }
4871     switch (target) {
4872     case GraphicsContext3D::TEXTURE_2D:
4873         if (level > m_maxTextureLevel) {
4874             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level out of range");
4875             return false;
4876         }
4877         break;
4878     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4879     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4880     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4881     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4882     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4883     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4884         if (level > m_maxCubeMapTextureLevel) {
4885             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level out of range");
4886             return false;
4887         }
4888         break;
4889     }
4890     // This function only checks if level is legal, so we return true and don't
4891     // generate INVALID_ENUM if target is illegal.
4892     return true;
4893 }
4894
4895 bool WebGLRenderingContext::validateTexFuncParameters(const char* functionName,
4896                                                       TexFuncValidationFunctionType functionType,
4897                                                       GC3Denum target, GC3Dint level,
4898                                                       GC3Denum internalformat,
4899                                                       GC3Dsizei width, GC3Dsizei height, GC3Dint border,
4900                                                       GC3Denum format, GC3Denum type)
4901 {
4902     // We absolutely have to validate the format and type combination.
4903     // The texImage2D entry points taking HTMLImage, etc. will produce
4904     // temporary data based on this combination, so it must be legal.
4905     if (!validateTexFuncFormatAndType(functionName, format, type, level) || !validateTexFuncLevel(functionName, target, level))
4906         return false;
4907
4908     if (width < 0 || height < 0) {
4909         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height < 0");
4910         return false;
4911     }
4912
4913     switch (target) {
4914     case GraphicsContext3D::TEXTURE_2D:
4915         if (width > m_maxTextureSize || height > m_maxTextureSize) {
4916             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range");
4917             return false;
4918         }
4919         break;
4920     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4921     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4922     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4923     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4924     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4925     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4926         if (functionType != TexSubImage2D && width != height) {
4927           synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width != height for cube map");
4928           return false;
4929         }
4930         // No need to check height here. For texImage width == height.
4931         // For texSubImage that will be checked when checking yoffset + height is in range.
4932         if (width > m_maxCubeMapTextureSize) {
4933             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range for cube map");
4934             return false;
4935         }
4936         break;
4937     default:
4938         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
4939         return false;
4940     }
4941
4942     if (format != internalformat) {
4943         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format != internalformat");
4944         return false;
4945     }
4946
4947     if (border) {
4948         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "border != 0");
4949         return false;
4950     }
4951
4952     return true;
4953 }
4954
4955 bool WebGLRenderingContext::validateTexFuncData(const char* functionName, GC3Dint level,
4956                                                 GC3Dsizei width, GC3Dsizei height,
4957                                                 GC3Denum format, GC3Denum type,
4958                                                 ArrayBufferView* pixels,
4959                                                 NullDisposition disposition)
4960 {
4961     if (!pixels) {
4962         if (disposition == NullAllowed)
4963             return true;
4964         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no pixels");
4965         return false;
4966     }
4967
4968     if (!validateTexFuncFormatAndType(functionName, format, type, level))
4969         return false;
4970     if (!validateSettableTexFormat(functionName, format))
4971         return false;
4972
4973     switch (type) {
4974     case GraphicsContext3D::UNSIGNED_BYTE:
4975         if (pixels->getType() != ArrayBufferView::TypeUint8) {
4976             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array");
4977             return false;
4978         }
4979         break;
4980     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4981     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4982     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4983         if (pixels->getType() != ArrayBufferView::TypeUint16) {
4984             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
4985             return false;
4986         }
4987         break;
4988     case GraphicsContext3D::FLOAT: // OES_texture_float
4989         if (pixels->getType() != ArrayBufferView::TypeFloat32) {
4990             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type FLOAT but ArrayBufferView not Float32Array");
4991             return false;
4992         }
4993         break;
4994     default:
4995         ASSERT_NOT_REACHED();
4996     }
4997
4998     unsigned int totalBytesRequired;
4999     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
5000     if (error != GraphicsContext3D::NO_ERROR) {
5001         synthesizeGLError(error, functionName, "invalid texture dimensions");
5002         return false;
5003     }
5004     if (pixels->byteLength() < totalBytesRequired) {
5005         if (m_unpackAlignment != 1) {
5006           error = m_context->computeImageSizeInBytes(format, type, width, height, 1, &totalBytesRequired, 0);
5007           if (pixels->byteLength() == totalBytesRequired) {
5008             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request with UNPACK_ALIGNMENT > 1");
5009             return false;
5010           }
5011         }
5012         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request");
5013         return false;
5014     }
5015     return true;
5016 }
5017
5018 bool WebGLRenderingContext::validateCompressedTexFormat(GC3Denum format)
5019 {
5020     return m_compressedTextureFormats.contains(format);
5021 }
5022
5023 bool WebGLRenderingContext::validateCompressedTexFuncData(const char* functionName,
5024                                                           GC3Dsizei width, GC3Dsizei height,
5025                                                           GC3Denum format, ArrayBufferView* pixels)
5026 {
5027     if (!pixels) {
5028         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no pixels");
5029         return false;
5030     }
5031     if (width < 0 || height < 0) {
5032         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height < 0");
5033         return false;
5034     }
5035
5036     unsigned int bytesRequired = 0;
5037
5038     switch (format) {
5039     case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
5040     case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
5041         {
5042             const int kBlockWidth = 4;
5043             const int kBlockHeight = 4;
5044             const int kBlockSize = 8;
5045             int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
5046             int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
5047             int numBlocks = numBlocksAcross * numBlocksDown;
5048             bytesRequired = numBlocks * kBlockSize;
5049         }
5050         break;
5051     case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
5052     case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT:
5053         {
5054             const int kBlockWidth = 4;
5055             const int kBlockHeight = 4;
5056             const int kBlockSize = 16;
5057             int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
5058             int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
5059             int numBlocks = numBlocksAcross * numBlocksDown;
5060             bytesRequired = numBlocks * kBlockSize;
5061         }
5062         break;
5063     default:
5064         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format");
5065         return false;
5066     }
5067
5068     if (pixels->byteLength() != bytesRequired) {
5069         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "length of ArrayBufferView is not correct for dimensions");
5070         return false;
5071     }
5072
5073     return true;
5074 }
5075
5076 bool WebGLRenderingContext::validateCompressedTexDimensions(const char* functionName, GC3Dint level, GC3Dsizei width, GC3Dsizei height, GC3Denum format)
5077 {
5078     switch (format) {
5079     case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
5080     case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
5081     case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
5082     case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT: {
5083         const int kBlockWidth = 4;
5084         const int kBlockHeight = 4;
5085         bool widthValid = (level && width == 1) || (level && width == 2) || !(width % kBlockWidth);
5086         bool heightValid = (level && height == 1) || (level && height == 2) || !(height % kBlockHeight);
5087         if (!widthValid || !heightValid) {
5088           synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "width or height invalid for level");
5089           return false;
5090         }
5091         return true;
5092     }
5093     default:
5094         return false;
5095     }
5096 }
5097
5098 bool WebGLRenderingContext::validateCompressedTexSubDimensions(const char* functionName, GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
5099                                                                GC3Dsizei width, GC3Dsizei height, GC3Denum format, WebGLTexture* tex)
5100 {
5101     if (xoffset < 0 || yoffset < 0) {
5102       synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "xoffset or yoffset < 0");
5103       return false;
5104     }
5105
5106     switch (format) {
5107     case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
5108     case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
5109     case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
5110     case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT: {
5111         const int kBlockWidth = 4;
5112         const int kBlockHeight = 4;
5113         if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
5114             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "xoffset or yoffset not multiple of 4");
5115             return false;
5116         }
5117         if (width - xoffset > tex->getWidth(target, level)
5118             || height - yoffset > tex->getHeight(target, level)) {
5119             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "dimensions out of range");
5120             return false;
5121         }
5122         return validateCompressedTexDimensions(functionName, level, width, height, format);
5123     }
5124     default:
5125         return false;
5126     }
5127 }
5128
5129 bool WebGLRenderingContext::validateDrawMode(const char* functionName, GC3Denum mode)
5130 {
5131     switch (mode) {
5132     case GraphicsContext3D::POINTS:
5133     case GraphicsContext3D::LINE_STRIP:
5134     case GraphicsContext3D::LINE_LOOP:
5135     case GraphicsContext3D::LINES:
5136     case GraphicsContext3D::TRIANGLE_STRIP:
5137     case GraphicsContext3D::TRIANGLE_FAN:
5138     case GraphicsContext3D::TRIANGLES:
5139         return true;
5140     default:
5141         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid draw mode");
5142         return false;
5143     }
5144 }
5145
5146 bool WebGLRenderingContext::validateStencilSettings(const char* functionName)
5147 {
5148     if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
5149         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "front and back stencils settings do not match");
5150         return false;
5151     }
5152     return true;
5153 }
5154
5155 bool WebGLRenderingContext::validateStencilFunc(const char* functionName, GC3Denum func)
5156 {
5157     switch (func) {
5158     case GraphicsContext3D::NEVER:
5159     case GraphicsContext3D::LESS:
5160     case GraphicsContext3D::LEQUAL:
5161     case GraphicsContext3D::GREATER:
5162     case GraphicsContext3D::GEQUAL:
5163     case GraphicsContext3D::EQUAL:
5164     case GraphicsContext3D::NOTEQUAL:
5165     case GraphicsContext3D::ALWAYS:
5166         return true;
5167     default:
5168         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid function");
5169         return false;
5170     }
5171 }
5172
5173 void WebGLRenderingContext::printGLErrorToConsole(const String& message)
5174 {
5175     if (!m_numGLErrorsToConsoleAllowed)
5176         return;
5177
5178     --m_numGLErrorsToConsoleAllowed;
5179     printWarningToConsole(message);
5180
5181     if (!m_numGLErrorsToConsoleAllowed)
5182         printWarningToConsole("WebGL: too many errors, no more errors will be reported to the console for this context.");
5183 }
5184
5185 void WebGLRenderingContext::printWarningToConsole(const String& message)
5186 {
5187     if (!canvas())
5188         return;
5189     Document* document = canvas()->document();
5190     if (!document)
5191         return;
5192     Frame* frame = document->frame();
5193     if (!frame)
5194         return;
5195     DOMWindow* window = frame->domWindow();
5196     if (!window)
5197         return;
5198     Console* console = window->console();
5199     if (!console)
5200         return;
5201     console->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, message, document->url().string());
5202 }
5203
5204 bool WebGLRenderingContext::validateFramebufferFuncParameters(const char* functionName, GC3Denum target, GC3Denum attachment)
5205 {
5206     if (target != GraphicsContext3D::FRAMEBUFFER) {
5207         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
5208         return false;
5209     }
5210     switch (attachment) {
5211     case GraphicsContext3D::COLOR_ATTACHMENT0:
5212     case GraphicsContext3D::DEPTH_ATTACHMENT:
5213     case GraphicsContext3D::STENCIL_ATTACHMENT:
5214     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
5215         break;
5216     default:
5217         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid attachment");
5218         return false;
5219     }
5220     return true;
5221 }
5222
5223 bool WebGLRenderingContext::validateBlendEquation(const char* functionName, GC3Denum mode)
5224 {
5225     switch (mode) {
5226     case GraphicsContext3D::FUNC_ADD:
5227     case GraphicsContext3D::FUNC_SUBTRACT:
5228     case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
5229         return true;
5230     default:
5231         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode");
5232         return false;
5233     }
5234 }
5235
5236 bool WebGLRenderingContext::validateBlendFuncFactors(const char* functionName, GC3Denum src, GC3Denum dst)
5237 {
5238     if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
5239          && (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))
5240         || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
5241             && (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) {
5242         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "incompatible src and dst");
5243         return false;
5244     }
5245     return true;
5246 }
5247
5248 bool WebGLRenderingContext::validateCapability(const char* functionName, GC3Denum cap)
5249 {
5250     switch (cap) {
5251     case GraphicsContext3D::BLEND:
5252     case GraphicsContext3D::CULL_FACE:
5253     case GraphicsContext3D::DEPTH_TEST:
5254     case GraphicsContext3D::DITHER:
5255     case GraphicsContext3D::POLYGON_OFFSET_FILL:
5256     case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
5257     case GraphicsContext3D::SAMPLE_COVERAGE:
5258     case GraphicsContext3D::SCISSOR_TEST:
5259     case GraphicsContext3D::STENCIL_TEST:
5260         return true;
5261     default:
5262         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid capability");
5263         return false;
5264     }
5265 }
5266
5267 bool WebGLRenderingContext::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Float32Array* v, GC3Dsizei requiredMinSize)
5268 {
5269     if (!v) {
5270         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5271         return false;
5272     }
5273     return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
5274 }
5275
5276 bool WebGLRenderingContext::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Int32Array* v, GC3Dsizei requiredMinSize)
5277 {
5278     if (!v) {
5279         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5280         return false;
5281     }
5282     return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
5283 }
5284
5285 bool WebGLRenderingContext::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
5286 {
5287     return validateUniformMatrixParameters(functionName, location, false, v, size, requiredMinSize);
5288 }
5289
5290 bool WebGLRenderingContext::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, GC3Dsizei requiredMinSize)
5291 {
5292     if (!v) {
5293         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5294         return false;
5295     }
5296     return validateUniformMatrixParameters(functionName, location, transpose, v->data(), v->length(), requiredMinSize);
5297 }
5298
5299 bool WebGLRenderingContext::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GC3Dboolean transpose, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
5300 {
5301     if (!location)
5302         return false;
5303     if (location->program() != m_currentProgram) {
5304         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "location is not from current program");
5305         return false;
5306     }
5307     if (!v) {
5308         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5309         return false;
5310     }
5311     if (transpose) {
5312         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "transpose not FALSE");
5313         return false;
5314     }
5315     if (size < requiredMinSize || (size % requiredMinSize)) {
5316         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "invalid size");
5317         return false;
5318     }
5319     return true;
5320 }
5321
5322 WebGLBuffer* WebGLRenderingContext::validateBufferDataParameters(const char* functionName, GC3Denum target, GC3Denum usage)
5323 {
5324     WebGLBuffer* buffer = 0;
5325     switch (target) {
5326     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
5327         buffer = m_boundVertexArrayObject->getElementArrayBuffer().get();
5328         break;
5329     case GraphicsContext3D::ARRAY_BUFFER:
5330         buffer = m_boundArrayBuffer.get();
5331         break;
5332     default:
5333         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
5334         return 0;
5335     }
5336     if (!buffer) {
5337         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no buffer");
5338         return 0;
5339     }
5340     switch (usage) {
5341     case GraphicsContext3D::STREAM_DRAW:
5342     case GraphicsContext3D::STATIC_DRAW:
5343     case GraphicsContext3D::DYNAMIC_DRAW:
5344         return buffer;
5345     }
5346     synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid usage");
5347     return 0;
5348 }
5349
5350 bool WebGLRenderingContext::validateHTMLImageElement(const char* functionName, HTMLImageElement* image)
5351 {
5352     if (!image || !image->cachedImage()) {
5353         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no image");
5354         return false;
5355     }
5356     const KURL& url = image->cachedImage()->response().url();
5357     if (url.isNull() || url.isEmpty() || !url.isValid()) {
5358         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "invalid image");
5359         return false;
5360     }
5361     return true;
5362 }
5363
5364 void WebGLRenderingContext::vertexAttribfImpl(const char* functionName, GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
5365 {
5366     if (isContextLost())
5367         return;
5368     if (index >= m_maxVertexAttribs) {
5369         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "index out of range");
5370         return;
5371     }
5372     // In GL, we skip setting vertexAttrib0 values.
5373     if (index || isGLES2Compliant()) {
5374         switch (expectedSize) {
5375         case 1:
5376             m_context->vertexAttrib1f(index, v0);
5377             break;
5378         case 2:
5379             m_context->vertexAttrib2f(index, v0, v1);
5380             break;
5381         case 3:
5382             m_context->vertexAttrib3f(index, v0, v1, v2);
5383             break;
5384         case 4:
5385             m_context->vertexAttrib4f(index, v0, v1, v2, v3);
5386             break;
5387         }
5388         cleanupAfterGraphicsCall(false);
5389     }
5390     VertexAttribValue& attribValue = m_vertexAttribValue[index];
5391     attribValue.value[0] = v0;
5392     attribValue.value[1] = v1;
5393     attribValue.value[2] = v2;
5394     attribValue.value[3] = v3;
5395 }
5396
5397 void WebGLRenderingContext::vertexAttribfvImpl(const char* functionName, GC3Duint index, Float32Array* v, GC3Dsizei expectedSize)
5398 {
5399     if (isContextLost())
5400         return;
5401     if (!v) {
5402         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5403         return;
5404     }
5405     vertexAttribfvImpl(functionName, index, v->data(), v->length(), expectedSize);
5406 }
5407
5408 void WebGLRenderingContext::vertexAttribfvImpl(const char* functionName, GC3Duint index, GC3Dfloat* v, GC3Dsizei size, GC3Dsizei expectedSize)
5409 {
5410     if (isContextLost())
5411         return;
5412     if (!v) {
5413         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5414         return;
5415     }
5416     if (size < expectedSize) {
5417         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "invalid size");
5418         return;
5419     }
5420     if (index >= m_maxVertexAttribs) {
5421         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "index out of range");
5422         return;
5423     }
5424     // In GL, we skip setting vertexAttrib0 values.
5425     if (index || isGLES2Compliant()) {
5426         switch (expectedSize) {
5427         case 1:
5428             m_context->vertexAttrib1fv(index, v);
5429             break;
5430         case 2:
5431             m_context->vertexAttrib2fv(index, v);
5432             break;
5433         case 3:
5434             m_context->vertexAttrib3fv(index, v);
5435             break;
5436         case 4:
5437             m_context->vertexAttrib4fv(index, v);
5438             break;
5439         }
5440         cleanupAfterGraphicsCall(false);
5441     }
5442     VertexAttribValue& attribValue = m_vertexAttribValue[index];
5443     attribValue.initValue();
5444     for (int ii = 0; ii < expectedSize; ++ii)
5445         attribValue.value[ii] = v[ii];
5446 }
5447
5448 void WebGLRenderingContext::initVertexAttrib0()
5449 {
5450     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
5451     
5452     m_vertexAttrib0Buffer = createBuffer();
5453     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
5454     m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW);
5455     m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
5456     state.bufferBinding = m_vertexAttrib0Buffer;
5457     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
5458     m_context->enableVertexAttribArray(0);
5459     m_vertexAttrib0BufferSize = 0;
5460     m_vertexAttrib0BufferValue[0] = 0.0f;
5461     m_vertexAttrib0BufferValue[1] = 0.0f;
5462     m_vertexAttrib0BufferValue[2] = 0.0f;
5463     m_vertexAttrib0BufferValue[3] = 1.0f;
5464     m_forceAttrib0BufferRefill = false;
5465     m_vertexAttrib0UsedBefore = false;
5466 }
5467
5468 bool WebGLRenderingContext::simulateVertexAttrib0(GC3Dsizei numVertex)
5469 {
5470     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
5471     const VertexAttribValue& attribValue = m_vertexAttribValue[0];
5472     if (!m_currentProgram)
5473         return false;
5474     bool usingVertexAttrib0 = m_currentProgram->isUsingVertexAttrib0();
5475     if (usingVertexAttrib0)
5476         m_vertexAttrib0UsedBefore = true;
5477     if (state.enabled && usingVertexAttrib0)
5478         return false;
5479     if (!usingVertexAttrib0 && !m_vertexAttrib0UsedBefore)
5480         return false;
5481     m_vertexAttrib0UsedBefore = true;
5482     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
5483     GC3Dsizeiptr bufferDataSize = (numVertex + 1) * 4 * sizeof(GC3Dfloat);
5484     if (bufferDataSize > m_vertexAttrib0BufferSize) {
5485         m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, bufferDataSize, 0, GraphicsContext3D::DYNAMIC_DRAW);
5486         m_vertexAttrib0BufferSize = bufferDataSize;
5487         m_forceAttrib0BufferRefill = true;
5488     }
5489     if (usingVertexAttrib0
5490         && (m_forceAttrib0BufferRefill
5491             || attribValue.value[0] != m_vertexAttrib0BufferValue[0]
5492             || attribValue.value[1] != m_vertexAttrib0BufferValue[1]
5493             || attribValue.value[2] != m_vertexAttrib0BufferValue[2]
5494             || attribValue.value[3] != m_vertexAttrib0BufferValue[3])) {
5495         OwnArrayPtr<GC3Dfloat> bufferData = adoptArrayPtr(new GC3Dfloat[(numVertex + 1) * 4]);
5496         for (GC3Dsizei ii = 0; ii < numVertex + 1; ++ii) {
5497             bufferData[ii * 4] = attribValue.value[0];
5498             bufferData[ii * 4 + 1] = attribValue.value[1];
5499             bufferData[ii * 4 + 2] = attribValue.value[2];
5500             bufferData[ii * 4 + 3] = attribValue.value[3];
5501         }
5502         m_vertexAttrib0BufferValue[0] = attribValue.value[0];
5503         m_vertexAttrib0BufferValue[1] = attribValue.value[1];
5504         m_vertexAttrib0BufferValue[2] = attribValue.value[2];
5505         m_vertexAttrib0BufferValue[3] = attribValue.value[3];
5506         m_forceAttrib0BufferRefill = false;
5507         m_context->bufferSubData(GraphicsContext3D::ARRAY_BUFFER, 0, bufferDataSize, bufferData.get());
5508     }
5509     m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, 0, 0, 0);
5510     return true;
5511 }
5512
5513 void WebGLRenderingContext::restoreStatesAfterVertexAttrib0Simulation()
5514 {
5515     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
5516     if (state.bufferBinding != m_vertexAttrib0Buffer) {
5517         m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(state.bufferBinding.get()));
5518         m_context->vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset);
5519     }
5520     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(m_boundArrayBuffer.get()));
5521 }
5522
5523 void WebGLRenderingContext::dispatchContextLostEvent(Timer<WebGLRenderingContext>*)
5524 {
5525     RefPtr<WebGLContextEvent> event = WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, "");
5526     canvas()->dispatchEvent(event);
5527     m_restoreAllowed = event->defaultPrevented();
5528     if (m_contextLostMode == RealLostContext && m_restoreAllowed)
5529         m_restoreTimer.startOneShot(0);
5530 }
5531
5532 void WebGLRenderingContext::maybeRestoreContext(Timer<WebGLRenderingContext>*)
5533 {
5534     ASSERT(m_contextLost);
5535     if (!m_contextLost)
5536         return;
5537
5538     // The rendering context is not restored unless the default behavior of the
5539     // webglcontextlost event was prevented earlier.
5540     //
5541     // Because of the way m_restoreTimer is set up for real vs. synthetic lost
5542     // context events, we don't have to worry about this test short-circuiting
5543     // the retry loop for real context lost events.
5544     if (!m_restoreAllowed)
5545         return;
5546
5547     int contextLostReason = m_context->getExtensions()->getGraphicsResetStatusARB();
5548
5549     switch (contextLostReason) {
5550     case GraphicsContext3D::NO_ERROR:
5551         // The GraphicsContext3D implementation might not fully
5552         // support GL_ARB_robustness semantics yet. Alternatively, the
5553         // WEBGL_lose_context extension might have been used to force
5554         // a lost context.
5555         break;
5556     case Extensions3D::GUILTY_CONTEXT_RESET_ARB:
5557         // The rendering context is not restored if this context was
5558         // guilty of causing the graphics reset.
5559         printWarningToConsole("WARNING: WebGL content on the page caused the graphics card to reset; not restoring the context");
5560         return;
5561     case Extensions3D::INNOCENT_CONTEXT_RESET_ARB:
5562         // Always allow the context to be restored.
5563         break;
5564     case Extensions3D::UNKNOWN_CONTEXT_RESET_ARB:
5565         // Warn. Ideally, prompt the user telling them that WebGL
5566         // content on the page might have caused the graphics card to
5567         // reset and ask them whether they want to continue running
5568         // the content. Only if they say "yes" should we start
5569         // attempting to restore the context.
5570         printWarningToConsole("WARNING: WebGL content on the page might have caused the graphics card to reset");
5571         break;
5572     }
5573
5574     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, canvas()->document()->view()->root()->hostWindow()));
5575     if (!context) {
5576         if (m_contextLostMode == RealLostContext)
5577             m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
5578         else
5579             // This likely shouldn't happen but is the best way to report it to the WebGL app.
5580             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "", "error restoring context");
5581         return;
5582     }
5583
5584     // Construct a new drawing buffer with the new GraphicsContext3D.
5585     if (m_drawingBuffer) {
5586         m_drawingBuffer->discardResources();
5587         DrawingBuffer::PreserveDrawingBuffer preserve = m_attributes.preserveDrawingBuffer ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
5588         DrawingBuffer::AlphaRequirement alpha = m_attributes.alpha ? DrawingBuffer::Alpha : DrawingBuffer::Opaque;
5589         m_drawingBuffer = DrawingBuffer::create(context.get(), m_drawingBuffer->size(), preserve, alpha);
5590         m_drawingBuffer->bind();
5591     }
5592
5593     m_context = context;
5594     m_contextLost = false;
5595     initializeNewContext();
5596     canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, ""));
5597 }
5598
5599 String WebGLRenderingContext::ensureNotNull(const String& text) const
5600 {
5601     if (text.isNull())
5602         return WTF::emptyString();
5603     return text;
5604 }
5605
5606 WebGLRenderingContext::LRUImageBufferCache::LRUImageBufferCache(int capacity)
5607     : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity]))
5608     , m_capacity(capacity)
5609 {
5610 }
5611
5612 ImageBuffer* WebGLRenderingContext::LRUImageBufferCache::imageBuffer(const IntSize& size)
5613 {
5614     int i;
5615     for (i = 0; i < m_capacity; ++i) {
5616         ImageBuffer* buf = m_buffers[i].get();
5617         if (!buf)
5618             break;
5619         if (buf->logicalSize() != size)
5620             continue;
5621         bubbleToFront(i);
5622         return buf;
5623     }
5624
5625     OwnPtr<ImageBuffer> temp = ImageBuffer::create(size, 1);
5626     if (!temp)
5627         return 0;
5628     i = std::min(m_capacity - 1, i);
5629     m_buffers[i] = temp.release();
5630
5631     ImageBuffer* buf = m_buffers[i].get();
5632     bubbleToFront(i);
5633     return buf;
5634 }
5635
5636 void WebGLRenderingContext::LRUImageBufferCache::bubbleToFront(int idx)
5637 {
5638     for (int i = idx; i > 0; --i)
5639         m_buffers[i].swap(m_buffers[i-1]);
5640 }
5641
5642 namespace {
5643
5644     String GetErrorString(GC3Denum error)
5645     {
5646         switch (error) {
5647         case GraphicsContext3D::INVALID_ENUM:
5648             return "INVALID_ENUM";
5649         case GraphicsContext3D::INVALID_VALUE:
5650             return "INVALID_VALUE";
5651         case GraphicsContext3D::INVALID_OPERATION:
5652             return "INVALID_OPERATION";
5653         case GraphicsContext3D::OUT_OF_MEMORY:
5654             return "OUT_OF_MEMORY";
5655         case GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION:
5656             return "INVALID_FRAMEBUFFER_OPERATION";
5657         case GraphicsContext3D::CONTEXT_LOST_WEBGL:
5658             return "CONTEXT_LOST_WEBGL";
5659         default:
5660             return String::format("WebGL ERROR(%04x)", error);
5661         }
5662     }
5663
5664 } // namespace anonymous
5665
5666 void WebGLRenderingContext::synthesizeGLError(GC3Denum error, const char* functionName, const char* description)
5667 {
5668     if (m_synthesizedErrorsToConsole) {
5669       String str = String("WebGL: ") + GetErrorString(error) +  ": " + String(functionName) + ": " + String(description);
5670       printGLErrorToConsole(str);
5671     }
5672     m_context->synthesizeGLError(error);
5673 }
5674
5675
5676 void WebGLRenderingContext::printGLWarningToConsole(const char* functionName, const char* description)
5677 {
5678     if (m_synthesizedErrorsToConsole) {
5679         String str = String("WebGL: ") + String(functionName) + ": " + String(description);
5680         printGLErrorToConsole(str);
5681     }
5682 }
5683
5684 void WebGLRenderingContext::applyStencilTest()
5685 {
5686     bool haveStencilBuffer = false;
5687
5688     if (m_framebufferBinding)
5689         haveStencilBuffer = m_framebufferBinding->hasStencilBuffer();
5690     else {
5691         RefPtr<WebGLContextAttributes> attributes = getContextAttributes();
5692         haveStencilBuffer = attributes->stencil();
5693     }
5694     enableOrDisable(GraphicsContext3D::STENCIL_TEST,
5695                     m_stencilEnabled && haveStencilBuffer);
5696 }
5697
5698 void WebGLRenderingContext::enableOrDisable(GC3Denum capability, bool enable)
5699 {
5700     if (enable)
5701         m_context->enable(capability);
5702     else
5703         m_context->disable(capability);
5704 }
5705
5706 IntSize WebGLRenderingContext::clampedCanvasSize()
5707 {
5708     return IntSize(clamp(canvas()->width(), 1, m_maxViewportDims[0]),
5709                    clamp(canvas()->height(), 1, m_maxViewportDims[1]));
5710 }
5711
5712 } // namespace WebCore
5713
5714 #endif // ENABLE(WEBGL)