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