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