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