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