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