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