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