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