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