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