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