WebGLRenderingContext.cpp revision 2bde8e466a4451c7319e3a072d118917957d6554
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()->supports("GL_CHROMIUM_strict_attribs");
462    m_isResourceSafe = m_context->getExtensions()->supports("GL_CHROMIUM_resource_safe");
463    if (m_isGLES2Compliant) {
464        m_isGLES2NPOTStrict = !m_context->getExtensions()->supports("GL_OES_texture_npot");
465        m_isDepthStencilSupported = m_context->getExtensions()->supports("GL_OES_packed_depth_stencil");
466    } else {
467        m_isGLES2NPOTStrict = !m_context->getExtensions()->supports("GL_ARB_texture_non_power_of_two");
468        m_isDepthStencilSupported = m_context->getExtensions()->supports("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    RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
506
507    if (!m_context->layerComposited() || m_layerCleared
508        || m_attributes.preserveDrawingBuffer || m_framebufferBinding)
509        return false;
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 (!image || !image->cachedImage()) {
3144        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3145        return;
3146    }
3147    checkOrigin(image);
3148    texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->image(),
3149                   m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3150}
3151
3152void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3153                                       GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3154{
3155    ec = 0;
3156    if (isContextLost())
3157        return;
3158    if (!canvas || !canvas->buffer()) {
3159        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3160        return;
3161    }
3162    checkOrigin(canvas);
3163    RefPtr<ImageData> imageData = canvas->getImageData();
3164    if (imageData)
3165        texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
3166    else
3167        texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(),
3168                       m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3169}
3170
3171#if ENABLE(VIDEO)
3172PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video)
3173{
3174    if (!video || !video->videoWidth() || !video->videoHeight()) {
3175        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3176        return 0;
3177    }
3178    IntSize size(video->videoWidth(), video->videoHeight());
3179    ImageBuffer* buf = m_videoCache.imageBuffer(size);
3180    if (!buf) {
3181        m_context->synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY);
3182        return 0;
3183    }
3184    checkOrigin(video);
3185    IntRect destRect(0, 0, size.width(), size.height());
3186    // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
3187    video->paintCurrentFrameInContext(buf->context(), destRect);
3188    return buf->copyImage();
3189}
3190
3191void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3192                                       GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3193{
3194    ec = 0;
3195    if (isContextLost())
3196        return;
3197    RefPtr<Image> image = videoFrameToImage(video);
3198    if (!video)
3199        return;
3200    texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3201}
3202#endif
3203
3204void WebGLRenderingContext::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
3205{
3206    if (isContextLost())
3207        return;
3208    WebGLTexture* tex = validateTextureBinding(target, false);
3209    if (!tex)
3210        return;
3211    switch (pname) {
3212    case GraphicsContext3D::TEXTURE_MIN_FILTER:
3213    case GraphicsContext3D::TEXTURE_MAG_FILTER:
3214        break;
3215    case GraphicsContext3D::TEXTURE_WRAP_S:
3216    case GraphicsContext3D::TEXTURE_WRAP_T:
3217        if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT)
3218            || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) {
3219            m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3220            return;
3221        }
3222        break;
3223    default:
3224        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3225        return;
3226    }
3227    if (isFloat) {
3228        tex->setParameterf(pname, paramf);
3229        m_context->texParameterf(target, pname, paramf);
3230    } else {
3231        tex->setParameteri(pname, parami);
3232        m_context->texParameteri(target, pname, parami);
3233    }
3234    cleanupAfterGraphicsCall(false);
3235}
3236
3237void WebGLRenderingContext::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
3238{
3239    texParameter(target, pname, param, 0, true);
3240}
3241
3242void WebGLRenderingContext::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
3243{
3244    texParameter(target, pname, 0, param, false);
3245}
3246
3247void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3248                                              GC3Dsizei width, GC3Dsizei height,
3249                                              GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3250{
3251    // FIXME: For now we ignore any errors returned
3252    ec = 0;
3253    if (isContextLost())
3254        return;
3255    if (!validateTexFuncParameters(target, level, format, width, height, 0, format, type))
3256        return;
3257    if (!validateSize(xoffset, yoffset))
3258        return;
3259    WebGLTexture* tex = validateTextureBinding(target, true);
3260    if (!tex)
3261        return;
3262    if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
3263        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3264        return;
3265    }
3266    if (tex->getInternalFormat(target, level) != format || tex->getType(target, level) != type) {
3267        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3268        return;
3269    }
3270    m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
3271    cleanupAfterGraphicsCall(false);
3272}
3273
3274void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3275                                              GC3Denum format, GC3Denum type,
3276                                              Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3277{
3278    ec = 0;
3279    if (isContextLost())
3280        return;
3281    Vector<uint8_t> data;
3282    if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3283        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3284        return;
3285    }
3286    texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(),
3287                      format, type, data.data(), ec);
3288}
3289
3290void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3291                                          GC3Dsizei width, GC3Dsizei height,
3292                                          GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3293{
3294    if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
3295        return;
3296    void* data = pixels ? pixels->baseAddress() : 0;
3297    Vector<uint8_t> tempData;
3298    bool changeUnpackAlignment = false;
3299    if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3300        if (!m_context->extractTextureData(width, height, format, type,
3301                                           m_unpackAlignment,
3302                                           m_unpackFlipY, m_unpackPremultiplyAlpha,
3303                                           data,
3304                                           tempData))
3305            return;
3306        data = tempData.data();
3307        changeUnpackAlignment = true;
3308    }
3309    if (changeUnpackAlignment)
3310        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3311    texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
3312    if (changeUnpackAlignment)
3313        m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3314}
3315
3316void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3317                                          GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3318{
3319    ec = 0;
3320    if (isContextLost())
3321        return;
3322    Vector<uint8_t> data;
3323    if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3324        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3325        return;
3326    }
3327    texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(),
3328                      format, type, data.data(), ec);
3329}
3330
3331void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3332                                          GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3333{
3334    ec = 0;
3335    if (isContextLost())
3336        return;
3337    if (!image || !image->cachedImage()) {
3338        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3339        return;
3340    }
3341    checkOrigin(image);
3342    texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image->cachedImage()->image(),
3343                      m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3344}
3345
3346void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3347                                          GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3348{
3349    ec = 0;
3350    if (isContextLost())
3351        return;
3352    if (!canvas || !canvas->buffer()) {
3353        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3354        return;
3355    }
3356    checkOrigin(canvas);
3357    RefPtr<ImageData> imageData = canvas->getImageData();
3358    if (imageData)
3359        texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec);
3360    else
3361        texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(),
3362                          m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3363}
3364
3365#if ENABLE(VIDEO)
3366void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3367                                          GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3368{
3369    ec = 0;
3370    if (isContextLost())
3371        return;
3372    RefPtr<Image> image = videoFrameToImage(video);
3373    if (!video)
3374        return;
3375    texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3376}
3377#endif
3378
3379void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode& ec)
3380{
3381    UNUSED_PARAM(ec);
3382    if (isContextLost() || !location)
3383        return;
3384
3385    if (location->program() != m_currentProgram) {
3386        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3387        return;
3388    }
3389
3390    m_context->uniform1f(location->location(), x);
3391    cleanupAfterGraphicsCall(false);
3392}
3393
3394void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3395{
3396    UNUSED_PARAM(ec);
3397    if (isContextLost() || !validateUniformParameters(location, v, 1))
3398        return;
3399
3400    m_context->uniform1fv(location->location(), v->data(), v->length());
3401    cleanupAfterGraphicsCall(false);
3402}
3403
3404void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3405{
3406    UNUSED_PARAM(ec);
3407    if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3408        return;
3409
3410    m_context->uniform1fv(location->location(), v, size);
3411    cleanupAfterGraphicsCall(false);
3412}
3413
3414void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode& ec)
3415{
3416    UNUSED_PARAM(ec);
3417    if (isContextLost() || !location)
3418        return;
3419
3420    if (location->program() != m_currentProgram) {
3421        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3422        return;
3423    }
3424
3425    m_context->uniform1i(location->location(), x);
3426    cleanupAfterGraphicsCall(false);
3427}
3428
3429void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3430{
3431    UNUSED_PARAM(ec);
3432    if (isContextLost() || !validateUniformParameters(location, v, 1))
3433        return;
3434
3435    m_context->uniform1iv(location->location(), v->data(), v->length());
3436    cleanupAfterGraphicsCall(false);
3437}
3438
3439void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3440{
3441    UNUSED_PARAM(ec);
3442    if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3443        return;
3444
3445    m_context->uniform1iv(location->location(), v, size);
3446    cleanupAfterGraphicsCall(false);
3447}
3448
3449void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode& ec)
3450{
3451    UNUSED_PARAM(ec);
3452    if (isContextLost() || !location)
3453        return;
3454
3455    if (location->program() != m_currentProgram) {
3456        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3457        return;
3458    }
3459
3460    m_context->uniform2f(location->location(), x, y);
3461    cleanupAfterGraphicsCall(false);
3462}
3463
3464void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3465{
3466    UNUSED_PARAM(ec);
3467    if (isContextLost() || !validateUniformParameters(location, v, 2))
3468        return;
3469
3470    m_context->uniform2fv(location->location(), v->data(), v->length() / 2);
3471    cleanupAfterGraphicsCall(false);
3472}
3473
3474void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3475{
3476    UNUSED_PARAM(ec);
3477    if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3478        return;
3479
3480    m_context->uniform2fv(location->location(), v, size / 2);
3481    cleanupAfterGraphicsCall(false);
3482}
3483
3484void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode& ec)
3485{
3486    UNUSED_PARAM(ec);
3487    if (isContextLost() || !location)
3488        return;
3489
3490    if (location->program() != m_currentProgram) {
3491        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3492        return;
3493    }
3494
3495    m_context->uniform2i(location->location(), x, y);
3496    cleanupAfterGraphicsCall(false);
3497}
3498
3499void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3500{
3501    UNUSED_PARAM(ec);
3502    if (isContextLost() || !validateUniformParameters(location, v, 2))
3503        return;
3504
3505    m_context->uniform2iv(location->location(), v->data(), v->length() / 2);
3506    cleanupAfterGraphicsCall(false);
3507}
3508
3509void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3510{
3511    UNUSED_PARAM(ec);
3512    if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3513        return;
3514
3515    m_context->uniform2iv(location->location(), v, size / 2);
3516    cleanupAfterGraphicsCall(false);
3517}
3518
3519void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode& ec)
3520{
3521    UNUSED_PARAM(ec);
3522    if (isContextLost() || !location)
3523        return;
3524
3525    if (location->program() != m_currentProgram) {
3526        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3527        return;
3528    }
3529
3530    m_context->uniform3f(location->location(), x, y, z);
3531    cleanupAfterGraphicsCall(false);
3532}
3533
3534void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3535{
3536    UNUSED_PARAM(ec);
3537    if (isContextLost() || !validateUniformParameters(location, v, 3))
3538        return;
3539
3540    m_context->uniform3fv(location->location(), v->data(), v->length() / 3);
3541    cleanupAfterGraphicsCall(false);
3542}
3543
3544void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3545{
3546    UNUSED_PARAM(ec);
3547    if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3548        return;
3549
3550    m_context->uniform3fv(location->location(), v, size / 3);
3551    cleanupAfterGraphicsCall(false);
3552}
3553
3554void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode& ec)
3555{
3556    UNUSED_PARAM(ec);
3557    if (isContextLost() || !location)
3558        return;
3559
3560    if (location->program() != m_currentProgram) {
3561        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3562        return;
3563    }
3564
3565    m_context->uniform3i(location->location(), x, y, z);
3566    cleanupAfterGraphicsCall(false);
3567}
3568
3569void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3570{
3571    UNUSED_PARAM(ec);
3572    if (isContextLost() || !validateUniformParameters(location, v, 3))
3573        return;
3574
3575    m_context->uniform3iv(location->location(), v->data(), v->length() / 3);
3576    cleanupAfterGraphicsCall(false);
3577}
3578
3579void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3580{
3581    UNUSED_PARAM(ec);
3582    if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3583        return;
3584
3585    m_context->uniform3iv(location->location(), v, size / 3);
3586    cleanupAfterGraphicsCall(false);
3587}
3588
3589void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode& ec)
3590{
3591    UNUSED_PARAM(ec);
3592    if (isContextLost() || !location)
3593        return;
3594
3595    if (location->program() != m_currentProgram) {
3596        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3597        return;
3598    }
3599
3600    m_context->uniform4f(location->location(), x, y, z, w);
3601    cleanupAfterGraphicsCall(false);
3602}
3603
3604void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3605{
3606    UNUSED_PARAM(ec);
3607    if (isContextLost() || !validateUniformParameters(location, v, 4))
3608        return;
3609
3610    m_context->uniform4fv(location->location(), v->data(), v->length() / 4);
3611    cleanupAfterGraphicsCall(false);
3612}
3613
3614void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3615{
3616    UNUSED_PARAM(ec);
3617    if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3618        return;
3619
3620    m_context->uniform4fv(location->location(), v, size / 4);
3621    cleanupAfterGraphicsCall(false);
3622}
3623
3624void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode& ec)
3625{
3626    UNUSED_PARAM(ec);
3627    if (isContextLost() || !location)
3628        return;
3629
3630    if (location->program() != m_currentProgram) {
3631        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3632        return;
3633    }
3634
3635    m_context->uniform4i(location->location(), x, y, z, w);
3636    cleanupAfterGraphicsCall(false);
3637}
3638
3639void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3640{
3641    UNUSED_PARAM(ec);
3642    if (isContextLost() || !validateUniformParameters(location, v, 4))
3643        return;
3644
3645    m_context->uniform4iv(location->location(), v->data(), v->length() / 4);
3646    cleanupAfterGraphicsCall(false);
3647}
3648
3649void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3650{
3651    UNUSED_PARAM(ec);
3652    if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3653        return;
3654
3655    m_context->uniform4iv(location->location(), v, size / 4);
3656    cleanupAfterGraphicsCall(false);
3657}
3658
3659void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3660{
3661    UNUSED_PARAM(ec);
3662    if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 4))
3663        return;
3664    m_context->uniformMatrix2fv(location->location(), transpose, v->data(), v->length() / 4);
3665    cleanupAfterGraphicsCall(false);
3666}
3667
3668void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3669{
3670    UNUSED_PARAM(ec);
3671    if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 4))
3672        return;
3673    m_context->uniformMatrix2fv(location->location(), transpose, v, size / 4);
3674    cleanupAfterGraphicsCall(false);
3675}
3676
3677void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3678{
3679    UNUSED_PARAM(ec);
3680    if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 9))
3681        return;
3682    m_context->uniformMatrix3fv(location->location(), transpose, v->data(), v->length() / 9);
3683    cleanupAfterGraphicsCall(false);
3684}
3685
3686void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3687{
3688    UNUSED_PARAM(ec);
3689    if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 9))
3690        return;
3691    m_context->uniformMatrix3fv(location->location(), transpose, v, size / 9);
3692    cleanupAfterGraphicsCall(false);
3693}
3694
3695void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3696{
3697    UNUSED_PARAM(ec);
3698    if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 16))
3699        return;
3700    m_context->uniformMatrix4fv(location->location(), transpose, v->data(), v->length() / 16);
3701    cleanupAfterGraphicsCall(false);
3702}
3703
3704void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3705{
3706    UNUSED_PARAM(ec);
3707    if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 16))
3708        return;
3709    m_context->uniformMatrix4fv(location->location(), transpose, v, size / 16);
3710    cleanupAfterGraphicsCall(false);
3711}
3712
3713void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
3714{
3715    UNUSED_PARAM(ec);
3716    bool deleted;
3717    if (!checkObjectToBeBound(program, deleted))
3718        return;
3719    if (deleted)
3720        program = 0;
3721    if (program && !program->getLinkStatus()) {
3722        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3723        cleanupAfterGraphicsCall(false);
3724        return;
3725    }
3726    if (m_currentProgram != program) {
3727        if (m_currentProgram)
3728            m_currentProgram->onDetached();
3729        m_currentProgram = program;
3730        m_context->useProgram(objectOrZero(program));
3731        if (program)
3732            program->onAttached();
3733    }
3734    cleanupAfterGraphicsCall(false);
3735}
3736
3737void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec)
3738{
3739    UNUSED_PARAM(ec);
3740    if (isContextLost() || !validateWebGLObject(program))
3741        return;
3742    m_context->validateProgram(objectOrZero(program));
3743    cleanupAfterGraphicsCall(false);
3744}
3745
3746void WebGLRenderingContext::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
3747{
3748    vertexAttribfImpl(index, 1, v0, 0.0f, 0.0f, 1.0f);
3749}
3750
3751void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, Float32Array* v)
3752{
3753    vertexAttribfvImpl(index, v, 1);
3754}
3755
3756void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3757{
3758    vertexAttribfvImpl(index, v, size, 1);
3759}
3760
3761void WebGLRenderingContext::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
3762{
3763    vertexAttribfImpl(index, 2, v0, v1, 0.0f, 1.0f);
3764}
3765
3766void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, Float32Array* v)
3767{
3768    vertexAttribfvImpl(index, v, 2);
3769}
3770
3771void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3772{
3773    vertexAttribfvImpl(index, v, size, 2);
3774}
3775
3776void WebGLRenderingContext::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
3777{
3778    vertexAttribfImpl(index, 3, v0, v1, v2, 1.0f);
3779}
3780
3781void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, Float32Array* v)
3782{
3783    vertexAttribfvImpl(index, v, 3);
3784}
3785
3786void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3787{
3788    vertexAttribfvImpl(index, v, size, 3);
3789}
3790
3791void WebGLRenderingContext::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
3792{
3793    vertexAttribfImpl(index, 4, v0, v1, v2, v3);
3794}
3795
3796void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, Float32Array* v)
3797{
3798    vertexAttribfvImpl(index, v, 4);
3799}
3800
3801void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3802{
3803    vertexAttribfvImpl(index, v, size, 4);
3804}
3805
3806void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset, ExceptionCode& ec)
3807{
3808    UNUSED_PARAM(ec);
3809    if (isContextLost())
3810        return;
3811    switch (type) {
3812    case GraphicsContext3D::BYTE:
3813    case GraphicsContext3D::UNSIGNED_BYTE:
3814    case GraphicsContext3D::SHORT:
3815    case GraphicsContext3D::UNSIGNED_SHORT:
3816    case GraphicsContext3D::FLOAT:
3817        break;
3818    default:
3819        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3820        return;
3821    }
3822    if (index >= m_maxVertexAttribs) {
3823        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3824        return;
3825    }
3826    if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) {
3827        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3828        return;
3829    }
3830    if (!m_boundArrayBuffer) {
3831        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3832        return;
3833    }
3834    // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
3835    unsigned int typeSize = sizeInBytes(type);
3836    if (!typeSize) {
3837        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3838        return;
3839    }
3840    if ((stride % typeSize) || (offset % typeSize)) {
3841        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3842        return;
3843    }
3844    GC3Dsizei bytesPerElement = size * typeSize;
3845
3846    GC3Dsizei validatedStride = stride ? stride : bytesPerElement;
3847
3848    WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
3849    state.bufferBinding = m_boundArrayBuffer;
3850    state.bytesPerElement = bytesPerElement;
3851    state.size = size;
3852    state.type = type;
3853    state.normalized = normalized;
3854    state.stride = validatedStride;
3855    state.originalStride = stride;
3856    state.offset = offset;
3857    m_context->vertexAttribPointer(index, size, type, normalized, stride, offset);
3858    cleanupAfterGraphicsCall(false);
3859}
3860
3861void WebGLRenderingContext::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
3862{
3863    if (isContextLost())
3864        return;
3865    if (isnan(x))
3866        x = 0;
3867    if (isnan(y))
3868        y = 0;
3869    if (isnan(width))
3870        width = 100;
3871    if (isnan(height))
3872        height = 100;
3873    if (!validateSize(width, height))
3874        return;
3875    m_context->viewport(x, y, width, height);
3876    cleanupAfterGraphicsCall(false);
3877}
3878
3879void WebGLRenderingContext::forceLostContext()
3880{
3881    if (isContextLost()) {
3882        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3883        return;
3884    }
3885
3886    m_restoreTimer.startOneShot(0);
3887}
3888
3889void WebGLRenderingContext::onLostContext()
3890{
3891    m_contextLost = true;
3892
3893    detachAndRemoveAllObjects();
3894
3895    // There is no direct way to clear errors from a GL implementation and
3896    // looping until getError() becomes NO_ERROR might cause an infinite loop if
3897    // the driver or context implementation had a bug.  So, loop a reasonably
3898    // large number of times to clear any existing errors.
3899    for (int i = 0; i < 100; ++i) {
3900        if (m_context->getError() == GraphicsContext3D::NO_ERROR)
3901            break;
3902    }
3903    m_context->synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL);
3904
3905    canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, ""));
3906}
3907
3908void WebGLRenderingContext::restoreContext()
3909{
3910    RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, canvas()->document()->view()->root()->hostWindow()));
3911    if (!context)
3912        return;
3913
3914    m_context = context;
3915    m_contextLost = false;
3916    initializeNewContext();
3917    canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, ""));
3918}
3919
3920void WebGLRenderingContext::removeObject(WebGLObject* object)
3921{
3922    m_canvasObjects.remove(object);
3923}
3924
3925void WebGLRenderingContext::addObject(WebGLObject* object)
3926{
3927    ASSERT(!isContextLost());
3928    removeObject(object);
3929    m_canvasObjects.add(object);
3930}
3931
3932void WebGLRenderingContext::detachAndRemoveAllObjects()
3933{
3934    HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3935    for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it)
3936        (*it)->detachContext();
3937
3938    m_canvasObjects.clear();
3939}
3940
3941WebGLTexture* WebGLRenderingContext::findTexture(Platform3DObject obj)
3942{
3943    if (!obj)
3944        return 0;
3945    HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3946    for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3947        if ((*it)->isTexture() && (*it)->object() == obj)
3948            return reinterpret_cast<WebGLTexture*>((*it).get());
3949    }
3950    return 0;
3951}
3952
3953WebGLRenderbuffer* WebGLRenderingContext::findRenderbuffer(Platform3DObject obj)
3954{
3955    if (!obj)
3956        return 0;
3957    HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3958    for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3959        if ((*it)->isRenderbuffer() && (*it)->object() == obj)
3960            return reinterpret_cast<WebGLRenderbuffer*>((*it).get());
3961    }
3962    return 0;
3963}
3964
3965WebGLBuffer* WebGLRenderingContext::findBuffer(Platform3DObject obj)
3966{
3967    if (!obj)
3968        return 0;
3969    HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3970    for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3971        if ((*it)->isBuffer() && (*it)->object() == obj)
3972            return reinterpret_cast<WebGLBuffer*>((*it).get());
3973    }
3974    return 0;
3975}
3976
3977WebGLShader* WebGLRenderingContext::findShader(Platform3DObject obj)
3978{
3979    if (!obj)
3980        return 0;
3981    HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3982    for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3983        if ((*it)->isShader() && (*it)->object() == obj)
3984            return reinterpret_cast<WebGLShader*>((*it).get());
3985    }
3986    return 0;
3987}
3988
3989WebGLGetInfo WebGLRenderingContext::getBooleanParameter(GC3Denum pname)
3990{
3991    GC3Dboolean value = 0;
3992    m_context->getBooleanv(pname, &value);
3993    return WebGLGetInfo(static_cast<bool>(value));
3994}
3995
3996WebGLGetInfo WebGLRenderingContext::getBooleanArrayParameter(GC3Denum pname)
3997{
3998    if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
3999        notImplemented();
4000        return WebGLGetInfo(0, 0);
4001    }
4002    GC3Dboolean value[4] = {0};
4003    m_context->getBooleanv(pname, value);
4004    bool boolValue[4];
4005    for (int ii = 0; ii < 4; ++ii)
4006        boolValue[ii] = static_cast<bool>(value[ii]);
4007    return WebGLGetInfo(boolValue, 4);
4008}
4009
4010WebGLGetInfo WebGLRenderingContext::getFloatParameter(GC3Denum pname)
4011{
4012    GC3Dfloat value = 0;
4013    m_context->getFloatv(pname, &value);
4014    return WebGLGetInfo(value);
4015}
4016
4017WebGLGetInfo WebGLRenderingContext::getIntParameter(GC3Denum pname)
4018{
4019    GC3Dint value = 0;
4020    m_context->getIntegerv(pname, &value);
4021    return WebGLGetInfo(value);
4022}
4023
4024WebGLGetInfo WebGLRenderingContext::getUnsignedIntParameter(GC3Denum pname)
4025{
4026    GC3Dint value = 0;
4027    m_context->getIntegerv(pname, &value);
4028    return WebGLGetInfo(static_cast<unsigned int>(value));
4029}
4030
4031WebGLGetInfo WebGLRenderingContext::getWebGLFloatArrayParameter(GC3Denum pname)
4032{
4033    GC3Dfloat value[4] = {0};
4034    m_context->getFloatv(pname, value);
4035    unsigned length = 0;
4036    switch (pname) {
4037    case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
4038    case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
4039    case GraphicsContext3D::DEPTH_RANGE:
4040        length = 2;
4041        break;
4042    case GraphicsContext3D::BLEND_COLOR:
4043    case GraphicsContext3D::COLOR_CLEAR_VALUE:
4044        length = 4;
4045        break;
4046    default:
4047        notImplemented();
4048    }
4049    return WebGLGetInfo(Float32Array::create(value, length));
4050}
4051
4052WebGLGetInfo WebGLRenderingContext::getWebGLIntArrayParameter(GC3Denum pname)
4053{
4054    GC3Dint value[4] = {0};
4055    m_context->getIntegerv(pname, value);
4056    unsigned length = 0;
4057    switch (pname) {
4058    case GraphicsContext3D::MAX_VIEWPORT_DIMS:
4059        length = 2;
4060        break;
4061    case GraphicsContext3D::SCISSOR_BOX:
4062    case GraphicsContext3D::VIEWPORT:
4063        length = 4;
4064        break;
4065    default:
4066        notImplemented();
4067    }
4068    return WebGLGetInfo(Int32Array::create(value, length));
4069}
4070
4071void WebGLRenderingContext::handleNPOTTextures(bool prepareToDraw)
4072{
4073    bool resetActiveUnit = false;
4074    for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) {
4075        if ((m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4076            || (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())) {
4077            if (ii != m_activeTextureUnit) {
4078                m_context->activeTexture(ii);
4079                resetActiveUnit = true;
4080            } else if (resetActiveUnit) {
4081                m_context->activeTexture(ii);
4082                resetActiveUnit = false;
4083            }
4084            WebGLTexture* tex2D;
4085            WebGLTexture* texCubeMap;
4086            if (prepareToDraw) {
4087                tex2D = m_blackTexture2D.get();
4088                texCubeMap = m_blackTextureCubeMap.get();
4089            } else {
4090                tex2D = m_textureUnits[ii].m_texture2DBinding.get();
4091                texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
4092            }
4093            if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4094                m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D));
4095            if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())
4096                m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
4097        }
4098    }
4099    if (resetActiveUnit)
4100        m_context->activeTexture(m_activeTextureUnit);
4101}
4102
4103void WebGLRenderingContext::createFallbackBlackTextures1x1()
4104{
4105    unsigned char black[] = {0, 0, 0, 255};
4106    m_blackTexture2D = createTexture();
4107    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D->object());
4108    m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1,
4109                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4110    m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
4111    m_blackTextureCubeMap = createTexture();
4112    m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
4113    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4114                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4115    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4116                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4117    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4118                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4119    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4120                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4121    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4122                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4123    m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4124                          0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4125    m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0);
4126}
4127
4128bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,
4129                                                                           GC3Denum colorBufferFormat)
4130{
4131    switch (colorBufferFormat) {
4132    case GraphicsContext3D::ALPHA:
4133        if (texInternalFormat == GraphicsContext3D::ALPHA)
4134            return true;
4135        break;
4136    case GraphicsContext3D::RGB:
4137        if (texInternalFormat == GraphicsContext3D::LUMINANCE
4138            || texInternalFormat == GraphicsContext3D::RGB)
4139            return true;
4140        break;
4141    case GraphicsContext3D::RGBA:
4142        return true;
4143    }
4144    return false;
4145}
4146
4147GC3Denum WebGLRenderingContext::getBoundFramebufferColorFormat()
4148{
4149    if (m_framebufferBinding && m_framebufferBinding->object())
4150        return m_framebufferBinding->getColorBufferFormat();
4151    if (m_attributes.alpha)
4152        return GraphicsContext3D::RGBA;
4153    return GraphicsContext3D::RGB;
4154}
4155
4156int WebGLRenderingContext::getBoundFramebufferWidth()
4157{
4158    if (m_framebufferBinding && m_framebufferBinding->object())
4159        return m_framebufferBinding->getWidth();
4160    return m_context->getInternalFramebufferSize().width();
4161}
4162
4163int WebGLRenderingContext::getBoundFramebufferHeight()
4164{
4165    if (m_framebufferBinding && m_framebufferBinding->object())
4166        return m_framebufferBinding->getHeight();
4167    return m_context->getInternalFramebufferSize().height();
4168}
4169
4170WebGLTexture* WebGLRenderingContext::validateTextureBinding(GC3Denum target, bool useSixEnumsForCubeMap)
4171{
4172    WebGLTexture* tex = 0;
4173    switch (target) {
4174    case GraphicsContext3D::TEXTURE_2D:
4175        tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
4176        break;
4177    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4178    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4179    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4180    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4181    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4182    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4183        if (!useSixEnumsForCubeMap) {
4184            m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4185            return 0;
4186        }
4187        tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4188        break;
4189    case GraphicsContext3D::TEXTURE_CUBE_MAP:
4190        if (useSixEnumsForCubeMap) {
4191            m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4192            return 0;
4193        }
4194        tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4195        break;
4196    default:
4197        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4198        return 0;
4199    }
4200    if (!tex)
4201        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4202    return tex;
4203}
4204
4205bool WebGLRenderingContext::validateSize(GC3Dint x, GC3Dint y)
4206{
4207    if (x < 0 || y < 0) {
4208        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4209        return false;
4210    }
4211    return true;
4212}
4213
4214bool WebGLRenderingContext::validateString(const String& string)
4215{
4216    for (size_t i = 0; i < string.length(); ++i) {
4217        if (!validateCharacter(string[i])) {
4218            m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4219            return false;
4220        }
4221    }
4222    return true;
4223}
4224
4225bool WebGLRenderingContext::validateTexFuncFormatAndType(GC3Denum format, GC3Denum type)
4226{
4227    switch (format) {
4228    case GraphicsContext3D::ALPHA:
4229    case GraphicsContext3D::LUMINANCE:
4230    case GraphicsContext3D::LUMINANCE_ALPHA:
4231    case GraphicsContext3D::RGB:
4232    case GraphicsContext3D::RGBA:
4233        break;
4234    default:
4235        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4236        return false;
4237    }
4238
4239    switch (type) {
4240    case GraphicsContext3D::UNSIGNED_BYTE:
4241    case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4242    case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4243    case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4244        break;
4245    case GraphicsContext3D::FLOAT:
4246        if (m_oesTextureFloat)
4247            break;
4248        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4249        return false;
4250    default:
4251        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4252        return false;
4253    }
4254
4255    // Verify that the combination of format and type is supported.
4256    switch (format) {
4257    case GraphicsContext3D::ALPHA:
4258    case GraphicsContext3D::LUMINANCE:
4259    case GraphicsContext3D::LUMINANCE_ALPHA:
4260        if (type != GraphicsContext3D::UNSIGNED_BYTE
4261            && type != GraphicsContext3D::FLOAT) {
4262            m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4263            return false;
4264        }
4265        break;
4266    case GraphicsContext3D::RGB:
4267        if (type != GraphicsContext3D::UNSIGNED_BYTE
4268            && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5
4269            && type != GraphicsContext3D::FLOAT) {
4270            m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4271            return false;
4272        }
4273        break;
4274    case GraphicsContext3D::RGBA:
4275        if (type != GraphicsContext3D::UNSIGNED_BYTE
4276            && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4
4277            && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1
4278            && type != GraphicsContext3D::FLOAT) {
4279            m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4280            return false;
4281        }
4282        break;
4283    default:
4284        ASSERT_NOT_REACHED();
4285    }
4286
4287    return true;
4288}
4289
4290bool WebGLRenderingContext::validateTexFuncLevel(GC3Denum target, GC3Dint level)
4291{
4292    if (level < 0) {
4293        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4294        return false;
4295    }
4296    switch (target) {
4297    case GraphicsContext3D::TEXTURE_2D:
4298        if (level > m_maxTextureLevel) {
4299            m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4300            return false;
4301        }
4302        break;
4303    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4304    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4305    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4306    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4307    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4308    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4309        if (level > m_maxCubeMapTextureLevel) {
4310            m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4311            return false;
4312        }
4313        break;
4314    }
4315    // This function only checks if level is legal, so we return true and don't
4316    // generate INVALID_ENUM if target is illegal.
4317    return true;
4318}
4319
4320bool WebGLRenderingContext::validateTexFuncParameters(GC3Denum target, GC3Dint level,
4321                                                      GC3Denum internalformat,
4322                                                      GC3Dsizei width, GC3Dsizei height, GC3Dint border,
4323                                                      GC3Denum format, GC3Denum type)
4324{
4325    // We absolutely have to validate the format and type combination.
4326    // The texImage2D entry points taking HTMLImage, etc. will produce
4327    // temporary data based on this combination, so it must be legal.
4328    if (!validateTexFuncFormatAndType(format, type) || !validateTexFuncLevel(target, level))
4329        return false;
4330
4331    if (width < 0 || height < 0) {
4332        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4333        return false;
4334    }
4335
4336    switch (target) {
4337    case GraphicsContext3D::TEXTURE_2D:
4338        if (width > m_maxTextureSize || height > m_maxTextureSize) {
4339            m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4340            return false;
4341        }
4342        break;
4343    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4344    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4345    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4346    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4347    case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4348    case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4349        if (width != height || width > m_maxCubeMapTextureSize) {
4350            m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4351            return false;
4352        }
4353        break;
4354    default:
4355        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4356        return false;
4357    }
4358
4359    if (format != internalformat) {
4360        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4361        return false;
4362    }
4363
4364    if (border) {
4365        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4366        return false;
4367    }
4368
4369    return true;
4370}
4371
4372bool WebGLRenderingContext::validateTexFuncData(GC3Dsizei width, GC3Dsizei height,
4373                                                GC3Denum format, GC3Denum type,
4374                                                ArrayBufferView* pixels)
4375{
4376    if (!pixels)
4377        return true;
4378
4379    if (!validateTexFuncFormatAndType(format, type))
4380        return false;
4381
4382    switch (type) {
4383    case GraphicsContext3D::UNSIGNED_BYTE:
4384        if (!pixels->isUnsignedByteArray()) {
4385            m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4386            return false;
4387        }
4388        break;
4389    case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4390    case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4391    case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4392        if (!pixels->isUnsignedShortArray()) {
4393            m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4394            return false;
4395        }
4396        break;
4397    case GraphicsContext3D::FLOAT: // OES_texture_float
4398        if (!pixels->isFloatArray()) {
4399            m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4400            return false;
4401        }
4402        break;
4403    default:
4404        ASSERT_NOT_REACHED();
4405    }
4406
4407    unsigned int totalBytesRequired;
4408    GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
4409    if (error != GraphicsContext3D::NO_ERROR) {
4410        m_context->synthesizeGLError(error);
4411        return false;
4412    }
4413    if (pixels->byteLength() < totalBytesRequired) {
4414        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4415        return false;
4416    }
4417    return true;
4418}
4419
4420bool WebGLRenderingContext::validateDrawMode(GC3Denum mode)
4421{
4422    switch (mode) {
4423    case GraphicsContext3D::POINTS:
4424    case GraphicsContext3D::LINE_STRIP:
4425    case GraphicsContext3D::LINE_LOOP:
4426    case GraphicsContext3D::LINES:
4427    case GraphicsContext3D::TRIANGLE_STRIP:
4428    case GraphicsContext3D::TRIANGLE_FAN:
4429    case GraphicsContext3D::TRIANGLES:
4430        return true;
4431    default:
4432        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4433        return false;
4434    }
4435}
4436
4437bool WebGLRenderingContext::validateStencilSettings()
4438{
4439    if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
4440        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4441        return false;
4442    }
4443    return true;
4444}
4445
4446bool WebGLRenderingContext::validateStencilFunc(GC3Denum func)
4447{
4448    switch (func) {
4449    case GraphicsContext3D::NEVER:
4450    case GraphicsContext3D::LESS:
4451    case GraphicsContext3D::LEQUAL:
4452    case GraphicsContext3D::GREATER:
4453    case GraphicsContext3D::GEQUAL:
4454    case GraphicsContext3D::EQUAL:
4455    case GraphicsContext3D::NOTEQUAL:
4456    case GraphicsContext3D::ALWAYS:
4457        return true;
4458    default:
4459        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4460        return false;
4461    }
4462}
4463
4464void WebGLRenderingContext::printWarningToConsole(const String& message)
4465{
4466    canvas()->document()->frame()->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel,
4467                                                                      message, 0, canvas()->document()->url().string());
4468}
4469
4470bool WebGLRenderingContext::validateFramebufferFuncParameters(GC3Denum target, GC3Denum attachment)
4471{
4472    if (target != GraphicsContext3D::FRAMEBUFFER) {
4473        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4474        return false;
4475    }
4476    switch (attachment) {
4477    case GraphicsContext3D::COLOR_ATTACHMENT0:
4478    case GraphicsContext3D::DEPTH_ATTACHMENT:
4479    case GraphicsContext3D::STENCIL_ATTACHMENT:
4480    case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
4481        break;
4482    default:
4483        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4484        return false;
4485    }
4486    return true;
4487}
4488
4489bool WebGLRenderingContext::validateBlendEquation(GC3Denum mode)
4490{
4491    switch (mode) {
4492    case GraphicsContext3D::FUNC_ADD:
4493    case GraphicsContext3D::FUNC_SUBTRACT:
4494    case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
4495        return true;
4496    default:
4497        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4498        return false;
4499    }
4500}
4501
4502bool WebGLRenderingContext::validateBlendFuncFactors(GC3Denum src, GC3Denum dst)
4503{
4504    if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
4505         && (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))
4506        || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
4507            && (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) {
4508        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4509        return false;
4510    }
4511    return true;
4512}
4513
4514bool WebGLRenderingContext::validateCapability(GC3Denum cap)
4515{
4516    switch (cap) {
4517    case GraphicsContext3D::BLEND:
4518    case GraphicsContext3D::CULL_FACE:
4519    case GraphicsContext3D::DEPTH_TEST:
4520    case GraphicsContext3D::DITHER:
4521    case GraphicsContext3D::POLYGON_OFFSET_FILL:
4522    case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
4523    case GraphicsContext3D::SAMPLE_COVERAGE:
4524    case GraphicsContext3D::SCISSOR_TEST:
4525    case GraphicsContext3D::STENCIL_TEST:
4526        return true;
4527    default:
4528        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4529        return false;
4530    }
4531}
4532
4533bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Float32Array* v, GC3Dsizei requiredMinSize)
4534{
4535    if (!v) {
4536        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4537        return false;
4538    }
4539    return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
4540}
4541
4542bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Int32Array* v, GC3Dsizei requiredMinSize)
4543{
4544    if (!v) {
4545        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4546        return false;
4547    }
4548    return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
4549}
4550
4551bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
4552{
4553    return validateUniformMatrixParameters(location, false, v, size, requiredMinSize);
4554}
4555
4556bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, GC3Dsizei requiredMinSize)
4557{
4558    if (!v) {
4559        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4560        return false;
4561    }
4562    return validateUniformMatrixParameters(location, transpose, v->data(), v->length(), requiredMinSize);
4563}
4564
4565bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
4566{
4567    if (!location)
4568        return false;
4569    if (location->program() != m_currentProgram) {
4570        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4571        return false;
4572    }
4573    if (!v) {
4574        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4575        return false;
4576    }
4577    if (transpose) {
4578        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4579        return false;
4580    }
4581    if (size < requiredMinSize || (size % requiredMinSize)) {
4582        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4583        return false;
4584    }
4585    return true;
4586}
4587
4588WebGLBuffer* WebGLRenderingContext::validateBufferDataParameters(GC3Denum target, GC3Denum usage)
4589{
4590    WebGLBuffer* buffer = 0;
4591    switch (target) {
4592    case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
4593        buffer = m_boundVertexArrayObject->getElementArrayBuffer().get();
4594        break;
4595    case GraphicsContext3D::ARRAY_BUFFER:
4596        buffer = m_boundArrayBuffer.get();
4597        break;
4598    default:
4599        m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4600        return 0;
4601    }
4602    if (!buffer) {
4603        m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4604        return 0;
4605    }
4606    switch (usage) {
4607    case GraphicsContext3D::STREAM_DRAW:
4608    case GraphicsContext3D::STATIC_DRAW:
4609    case GraphicsContext3D::DYNAMIC_DRAW:
4610        return buffer;
4611    }
4612    m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4613    return 0;
4614}
4615
4616void WebGLRenderingContext::vertexAttribfImpl(GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
4617{
4618    if (isContextLost())
4619        return;
4620    if (index >= m_maxVertexAttribs) {
4621        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4622        return;
4623    }
4624    // In GL, we skip setting vertexAttrib0 values.
4625    if (index || isGLES2Compliant()) {
4626        switch (expectedSize) {
4627        case 1:
4628            m_context->vertexAttrib1f(index, v0);
4629            break;
4630        case 2:
4631            m_context->vertexAttrib2f(index, v0, v1);
4632            break;
4633        case 3:
4634            m_context->vertexAttrib3f(index, v0, v1, v2);
4635            break;
4636        case 4:
4637            m_context->vertexAttrib4f(index, v0, v1, v2, v3);
4638            break;
4639        }
4640        cleanupAfterGraphicsCall(false);
4641    }
4642    VertexAttribValue& attribValue = m_vertexAttribValue[index];
4643    attribValue.value[0] = v0;
4644    attribValue.value[1] = v1;
4645    attribValue.value[2] = v2;
4646    attribValue.value[3] = v3;
4647}
4648
4649void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, Float32Array* v, GC3Dsizei expectedSize)
4650{
4651    if (isContextLost())
4652        return;
4653    if (!v) {
4654        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4655        return;
4656    }
4657    vertexAttribfvImpl(index, v->data(), v->length(), expectedSize);
4658}
4659
4660void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, GC3Dfloat* v, GC3Dsizei size, GC3Dsizei expectedSize)
4661{
4662    if (isContextLost())
4663        return;
4664    if (!v) {
4665        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4666        return;
4667    }
4668    if (size < expectedSize) {
4669        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4670        return;
4671    }
4672    if (index >= m_maxVertexAttribs) {
4673        m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4674        return;
4675    }
4676    // In GL, we skip setting vertexAttrib0 values.
4677    if (index || isGLES2Compliant()) {
4678        switch (expectedSize) {
4679        case 1:
4680            m_context->vertexAttrib1fv(index, v);
4681            break;
4682        case 2:
4683            m_context->vertexAttrib2fv(index, v);
4684            break;
4685        case 3:
4686            m_context->vertexAttrib3fv(index, v);
4687            break;
4688        case 4:
4689            m_context->vertexAttrib4fv(index, v);
4690            break;
4691        }
4692        cleanupAfterGraphicsCall(false);
4693    }
4694    VertexAttribValue& attribValue = m_vertexAttribValue[index];
4695    attribValue.initValue();
4696    for (int ii = 0; ii < expectedSize; ++ii)
4697        attribValue.value[ii] = v[ii];
4698}
4699
4700void WebGLRenderingContext::initVertexAttrib0()
4701{
4702    WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4703
4704    m_vertexAttrib0Buffer = createBuffer();
4705    m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
4706    m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW);
4707    m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
4708    state.bufferBinding = m_vertexAttrib0Buffer;
4709    m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
4710    m_context->enableVertexAttribArray(0);
4711    m_vertexAttrib0BufferSize = 0;
4712    m_vertexAttrib0BufferValue[0] = 0.0f;
4713    m_vertexAttrib0BufferValue[1] = 0.0f;
4714    m_vertexAttrib0BufferValue[2] = 0.0f;
4715    m_vertexAttrib0BufferValue[3] = 1.0f;
4716    m_forceAttrib0BufferRefill = false;
4717    m_vertexAttrib0UsedBefore = false;
4718}
4719
4720bool WebGLRenderingContext::simulateVertexAttrib0(GC3Dsizei numVertex)
4721{
4722    const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4723    const VertexAttribValue& attribValue = m_vertexAttribValue[0];
4724    if (!m_currentProgram)
4725        return false;
4726    bool usingVertexAttrib0 = m_currentProgram->isUsingVertexAttrib0();
4727    if (usingVertexAttrib0)
4728        m_vertexAttrib0UsedBefore = true;
4729    if (state.enabled && usingVertexAttrib0)
4730        return false;
4731    if (!usingVertexAttrib0 && !m_vertexAttrib0UsedBefore)
4732        return false;
4733    m_vertexAttrib0UsedBefore = true;
4734    m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
4735    GC3Dsizeiptr bufferDataSize = (numVertex + 1) * 4 * sizeof(GC3Dfloat);
4736    if (bufferDataSize > m_vertexAttrib0BufferSize) {
4737        m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, bufferDataSize, 0, GraphicsContext3D::DYNAMIC_DRAW);
4738        m_vertexAttrib0BufferSize = bufferDataSize;
4739        m_forceAttrib0BufferRefill = true;
4740    }
4741    if (usingVertexAttrib0
4742        && (m_forceAttrib0BufferRefill
4743            || attribValue.value[0] != m_vertexAttrib0BufferValue[0]
4744            || attribValue.value[1] != m_vertexAttrib0BufferValue[1]
4745            || attribValue.value[2] != m_vertexAttrib0BufferValue[2]
4746            || attribValue.value[3] != m_vertexAttrib0BufferValue[3])) {
4747        OwnArrayPtr<GC3Dfloat> bufferData = adoptArrayPtr(new GC3Dfloat[(numVertex + 1) * 4]);
4748        for (GC3Dsizei ii = 0; ii < numVertex + 1; ++ii) {
4749            bufferData[ii * 4] = attribValue.value[0];
4750            bufferData[ii * 4 + 1] = attribValue.value[1];
4751            bufferData[ii * 4 + 2] = attribValue.value[2];
4752            bufferData[ii * 4 + 3] = attribValue.value[3];
4753        }
4754        m_vertexAttrib0BufferValue[0] = attribValue.value[0];
4755        m_vertexAttrib0BufferValue[1] = attribValue.value[1];
4756        m_vertexAttrib0BufferValue[2] = attribValue.value[2];
4757        m_vertexAttrib0BufferValue[3] = attribValue.value[3];
4758        m_forceAttrib0BufferRefill = false;
4759        m_context->bufferSubData(GraphicsContext3D::ARRAY_BUFFER, 0, bufferDataSize, bufferData.get());
4760    }
4761    m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, 0, 0, 0);
4762    return true;
4763}
4764
4765void WebGLRenderingContext::restoreStatesAfterVertexAttrib0Simulation()
4766{
4767    const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4768    if (state.bufferBinding != m_vertexAttrib0Buffer) {
4769        m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(state.bufferBinding.get()));
4770        m_context->vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset);
4771    }
4772    m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(m_boundArrayBuffer.get()));
4773}
4774
4775int WebGLRenderingContext::getNumberOfExtensions()
4776{
4777    return (m_oesVertexArrayObject ? 1 : 0) + (m_oesStandardDerivatives ? 1 : 0) + (m_webkitLoseContext ? 1 : 0) + (m_oesTextureFloat ? 1 : 0);
4778}
4779
4780WebGLExtension* WebGLRenderingContext::getExtensionNumber(int i)
4781{
4782    if (m_oesVertexArrayObject) {
4783        if (!i)
4784            return m_oesVertexArrayObject.get();
4785        --i;
4786    }
4787    if (m_oesStandardDerivatives) {
4788        if (!i)
4789            return m_oesStandardDerivatives.get();
4790        --i;
4791    }
4792    if (m_webkitLoseContext) {
4793        if (!i)
4794            return m_webkitLoseContext.get();
4795        --i;
4796    }
4797    if (m_oesTextureFloat) {
4798        if (!i)
4799            return m_oesTextureFloat.get();
4800        --i;
4801    }
4802    // Similar tests for other extensions would go here.
4803    return 0;
4804}
4805
4806WebGLRenderingContext::LRUImageBufferCache::LRUImageBufferCache(int capacity)
4807    : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity]))
4808    , m_capacity(capacity)
4809{
4810}
4811
4812ImageBuffer* WebGLRenderingContext::LRUImageBufferCache::imageBuffer(const IntSize& size)
4813{
4814    int i;
4815    for (i = 0; i < m_capacity; ++i) {
4816        ImageBuffer* buf = m_buffers[i].get();
4817        if (!buf)
4818            break;
4819        if (buf->size() != size)
4820            continue;
4821        bubbleToFront(i);
4822        return buf;
4823    }
4824
4825    OwnPtr<ImageBuffer> temp = ImageBuffer::create(size);
4826    if (!temp)
4827        return 0;
4828    i = std::min(m_capacity - 1, i);
4829    m_buffers[i] = temp.release();
4830
4831    ImageBuffer* buf = m_buffers[i].get();
4832    bubbleToFront(i);
4833    return buf;
4834}
4835
4836void WebGLRenderingContext::LRUImageBufferCache::bubbleToFront(int idx)
4837{
4838    for (int i = idx; i > 0; --i)
4839        m_buffers[i].swap(m_buffers[i-1]);
4840}
4841
4842} // namespace WebCore
4843
4844#endif // ENABLE(WEBGL)
4845