Disabling WebGL2 should mean no context is created
[WebKit-https.git] / Source / WebCore / html / canvas / WebGLRenderingContextBase.cpp
1 /*
2  * Copyright (C) 2015-2016 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 #include "WebGLRenderingContextBase.h"
30
31 #include "ANGLEInstancedArrays.h"
32 #include "CachedImage.h"
33 #include "DOMWindow.h"
34 #include "Document.h"
35 #include "EXTBlendMinMax.h"
36 #include "EXTFragDepth.h"
37 #include "EXTShaderTextureLOD.h"
38 #include "EXTTextureFilterAnisotropic.h"
39 #include "EXTsRGB.h"
40 #include "ExceptionCode.h"
41 #include "Extensions3D.h"
42 #include "Frame.h"
43 #include "FrameLoader.h"
44 #include "FrameLoaderClient.h"
45 #include "FrameView.h"
46 #include "GraphicsContext.h"
47 #include "HTMLCanvasElement.h"
48 #include "HTMLImageElement.h"
49 #include "HTMLVideoElement.h"
50 #include "ImageBuffer.h"
51 #include "ImageData.h"
52 #include "IntSize.h"
53 #include "Logging.h"
54 #include "MainFrame.h"
55 #include "NotImplemented.h"
56 #include "OESElementIndexUint.h"
57 #include "OESStandardDerivatives.h"
58 #include "OESTextureFloat.h"
59 #include "OESTextureFloatLinear.h"
60 #include "OESTextureHalfFloat.h"
61 #include "OESTextureHalfFloatLinear.h"
62 #include "OESVertexArrayObject.h"
63 #include "Page.h"
64 #include "RenderBox.h"
65 #include "RuntimeEnabledFeatures.h"
66 #include "Settings.h"
67 #include "WebGL2RenderingContext.h"
68 #include "WebGLActiveInfo.h"
69 #include "WebGLBuffer.h"
70 #include "WebGLCompressedTextureATC.h"
71 #include "WebGLCompressedTexturePVRTC.h"
72 #include "WebGLCompressedTextureS3TC.h"
73 #include "WebGLContextAttributes.h"
74 #include "WebGLContextEvent.h"
75 #include "WebGLContextGroup.h"
76 #include "WebGLDebugRendererInfo.h"
77 #include "WebGLDebugShaders.h"
78 #include "WebGLDepthTexture.h"
79 #include "WebGLDrawBuffers.h"
80 #include "WebGLFramebuffer.h"
81 #include "WebGLLoseContext.h"
82 #include "WebGLProgram.h"
83 #include "WebGLRenderbuffer.h"
84 #include "WebGLRenderingContext.h"
85 #include "WebGLShader.h"
86 #include "WebGLShaderPrecisionFormat.h"
87 #include "WebGLTexture.h"
88 #include "WebGLUniformLocation.h"
89
90 #include <runtime/JSCInlines.h>
91 #include <runtime/TypedArrayInlines.h>
92 #include <runtime/Uint32Array.h>
93 #include <wtf/CheckedArithmetic.h>
94 #include <wtf/StdLibExtras.h>
95 #include <wtf/text/CString.h>
96 #include <wtf/text/StringBuilder.h>
97
98 namespace WebCore {
99
100 const double secondsBetweenRestoreAttempts = 1.0;
101 const int maxGLErrorsAllowedToConsole = 256;
102
103 namespace {
104     
105     Platform3DObject objectOrZero(WebGLObject* object)
106     {
107         return object ? object->object() : 0;
108     }
109
110     GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
111     {
112         if (value < min)
113             value = min;
114         if (value > max)
115             value = max;
116         return value;
117     }
118
119     // Return true if a character belongs to the ASCII subset as defined in
120     // GLSL ES 1.0 spec section 3.1.
121     bool validateCharacter(unsigned char c)
122     {
123         // Printing characters are valid except " $ ` @ \ ' DEL.
124         if (c >= 32 && c <= 126
125             && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
126             return true;
127         // Horizontal tab, line feed, vertical tab, form feed, carriage return
128         // are also valid.
129         if (c >= 9 && c <= 13)
130             return true;
131         return false;
132     }
133
134     bool isPrefixReserved(const String& name)
135     {
136         if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_"))
137             return true;
138         return false;
139     }
140
141     // Strips comments from shader text. This allows non-ASCII characters
142     // to be used in comments without potentially breaking OpenGL
143     // implementations not expecting characters outside the GLSL ES set.
144     class StripComments {
145     public:
146         StripComments(const String& str)
147             : m_parseState(BeginningOfLine)
148             , m_sourceString(str)
149             , m_length(str.length())
150             , m_position(0)
151         {
152             parse();
153         }
154
155         String result()
156         {
157             return m_builder.toString();
158         }
159
160     private:
161         bool hasMoreCharacters() const
162         {
163             return (m_position < m_length);
164         }
165
166         void parse()
167         {
168             while (hasMoreCharacters()) {
169                 process(current());
170                 // process() might advance the position.
171                 if (hasMoreCharacters())
172                     advance();
173             }
174         }
175
176         void process(UChar);
177
178         bool peek(UChar& character) const
179         {
180             if (m_position + 1 >= m_length)
181                 return false;
182             character = m_sourceString[m_position + 1];
183             return true;
184         }
185
186         UChar current() const
187         {
188             ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length);
189             return m_sourceString[m_position];
190         }
191
192         void advance()
193         {
194             ++m_position;
195         }
196
197         bool isNewline(UChar character) const
198         {
199             // Don't attempt to canonicalize newline related characters.
200             return (character == '\n' || character == '\r');
201         }
202
203         void emit(UChar character)
204         {
205             m_builder.append(character);
206         }
207
208         enum ParseState {
209             // Have not seen an ASCII non-whitespace character yet on
210             // this line. Possible that we might see a preprocessor
211             // directive.
212             BeginningOfLine,
213
214             // Have seen at least one ASCII non-whitespace character
215             // on this line.
216             MiddleOfLine,
217
218             // Handling a preprocessor directive. Passes through all
219             // characters up to the end of the line. Disables comment
220             // processing.
221             InPreprocessorDirective,
222
223             // Handling a single-line comment. The comment text is
224             // replaced with a single space.
225             InSingleLineComment,
226
227             // Handling a multi-line comment. Newlines are passed
228             // through to preserve line numbers.
229             InMultiLineComment
230         };
231
232         ParseState m_parseState;
233         String m_sourceString;
234         unsigned m_length;
235         unsigned m_position;
236         StringBuilder m_builder;
237     };
238
239     void StripComments::process(UChar c)
240     {
241         if (isNewline(c)) {
242             // No matter what state we are in, pass through newlines
243             // so we preserve line numbers.
244             emit(c);
245
246             if (m_parseState != InMultiLineComment)
247                 m_parseState = BeginningOfLine;
248
249             return;
250         }
251
252         UChar temp = 0;
253         switch (m_parseState) {
254         case BeginningOfLine:
255             if (WTF::isASCIISpace(c)) {
256                 emit(c);
257                 break;
258             }
259
260             if (c == '#') {
261                 m_parseState = InPreprocessorDirective;
262                 emit(c);
263                 break;
264             }
265
266             // Transition to normal state and re-handle character.
267             m_parseState = MiddleOfLine;
268             process(c);
269             break;
270
271         case MiddleOfLine:
272             if (c == '/' && peek(temp)) {
273                 if (temp == '/') {
274                     m_parseState = InSingleLineComment;
275                     emit(' ');
276                     advance();
277                     break;
278                 }
279
280                 if (temp == '*') {
281                     m_parseState = InMultiLineComment;
282                     // Emit the comment start in case the user has
283                     // an unclosed comment and we want to later
284                     // signal an error.
285                     emit('/');
286                     emit('*');
287                     advance();
288                     break;
289                 }
290             }
291
292             emit(c);
293             break;
294
295         case InPreprocessorDirective:
296             // No matter what the character is, just pass it
297             // through. Do not parse comments in this state. This
298             // might not be the right thing to do long term, but it
299             // should handle the #error preprocessor directive.
300             emit(c);
301             break;
302
303         case InSingleLineComment:
304             // The newline code at the top of this function takes care
305             // of resetting our state when we get out of the
306             // single-line comment. Swallow all other characters.
307             break;
308
309         case InMultiLineComment:
310             if (c == '*' && peek(temp) && temp == '/') {
311                 emit('*');
312                 emit('/');
313                 m_parseState = MiddleOfLine;
314                 advance();
315                 break;
316             }
317
318             // Swallow all other characters. Unclear whether we may
319             // want or need to just emit a space per character to try
320             // to preserve column numbers for debugging purposes.
321             break;
322         }
323     }
324 } // namespace anonymous
325
326 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
327     WTF_MAKE_FAST_ALLOCATED;
328 public:
329     explicit WebGLRenderingContextLostCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
330     void onContextLost() override { m_context->forceLostContext(WebGLRenderingContext::RealLostContext); }
331     virtual ~WebGLRenderingContextLostCallback() {}
332 private:
333     WebGLRenderingContextBase* m_context;
334 };
335
336 class WebGLRenderingContextErrorMessageCallback : public GraphicsContext3D::ErrorMessageCallback {
337     WTF_MAKE_FAST_ALLOCATED;
338 public:
339     explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
340     void onErrorMessage(const String& message, GC3Dint) override
341     {
342         if (m_context->m_synthesizedErrorsToConsole)
343             m_context->printGLErrorToConsole(message);
344     }
345     virtual ~WebGLRenderingContextErrorMessageCallback() { }
346 private:
347     WebGLRenderingContextBase* m_context;
348 };
349
350 std::unique_ptr<WebGLRenderingContextBase> WebGLRenderingContextBase::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs, const String& type)
351 {
352 #if ENABLE(WEBGL2)
353     if (type == "webgl2" && !RuntimeEnabledFeatures::sharedFeatures().webGL2Enabled())
354         return nullptr;
355 #else
356     UNUSED_PARAM(type);
357 #endif
358
359     Document& document = canvas->document();
360     Frame* frame = document.frame();
361     if (!frame)
362         return nullptr;
363
364     // The FrameLoaderClient might block creation of a new WebGL context despite the page settings; in
365     // particular, if WebGL contexts were lost one or more times via the GL_ARB_robustness extension.
366     if (!frame->loader().client().allowWebGL(frame->settings().webGLEnabled())) {
367         canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Web page was not allowed to create a WebGL context."));
368         return nullptr;
369     }
370
371     bool isPendingPolicyResolution = false;
372     Document& topDocument = document.topDocument();
373     Page* page = topDocument.page();
374     bool forcingPendingPolicy = frame->settings().isForcePendingWebGLPolicy();
375
376     if (forcingPendingPolicy || (page && !topDocument.url().isLocalFile())) {
377         WebGLLoadPolicy policy = forcingPendingPolicy ? WebGLPendingCreation : page->mainFrame().loader().client().webGLPolicyForURL(topDocument.url());
378
379         if (policy == WebGLBlockCreation) {
380             LOG(WebGL, "The policy for this URL (%s) is to block WebGL.", topDocument.url().host().utf8().data());
381             return nullptr;
382         }
383
384         if (policy == WebGLPendingCreation) {
385             LOG(WebGL, "WebGL policy is pending. May need to be resolved later.");
386             isPendingPolicyResolution = true;
387         }
388     }
389
390     GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
391
392     if (attributes.antialias) {
393         if (!frame->settings().openGLMultisamplingEnabled())
394             attributes.antialias = false;
395     }
396
397     attributes.noExtensions = true;
398     attributes.shareResources = false;
399     attributes.preferDiscreteGPU = true;
400
401     if (frame->settings().forceSoftwareWebGLRendering())
402         attributes.forceSoftwareRenderer = true;
403
404     if (page)
405         attributes.devicePixelRatio = page->deviceScaleFactor();
406
407 #if ENABLE(WEBGL2)
408     if (type == "webgl2")
409         attributes.useGLES3 = true;
410 #endif
411
412     if (isPendingPolicyResolution) {
413         LOG(WebGL, "Create a WebGL context that looks real, but will require a policy resolution if used.");
414         std::unique_ptr<WebGLRenderingContextBase> renderingContext = nullptr;
415 #if ENABLE(WEBGL2)
416         if (type == "webgl2")
417             renderingContext = std::unique_ptr<WebGL2RenderingContext>(new WebGL2RenderingContext(canvas, attributes));
418         else
419 #endif
420             renderingContext = std::unique_ptr<WebGLRenderingContext>(new WebGLRenderingContext(canvas, attributes));
421         renderingContext->suspendIfNeeded();
422         return renderingContext;
423     }
424
425     HostWindow* hostWindow = document.view()->root()->hostWindow();
426     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
427
428     if (!context || !context->makeContextCurrent()) {
429         canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
430         return nullptr;
431     }
432
433     Extensions3D* extensions = context->getExtensions();
434     if (extensions->supports("GL_EXT_debug_marker"))
435         extensions->pushGroupMarkerEXT("WebGLRenderingContext");
436
437     std::unique_ptr<WebGLRenderingContextBase> renderingContext = nullptr;
438 #if ENABLE(WEBGL2)
439     if (type == "webgl2")
440         renderingContext = std::unique_ptr<WebGL2RenderingContext>(new WebGL2RenderingContext(canvas, WTFMove(context), attributes));
441     else
442 #endif
443         renderingContext = std::unique_ptr<WebGLRenderingContext>(new WebGLRenderingContext(canvas, WTFMove(context), attributes));
444     renderingContext->suspendIfNeeded();
445
446     return renderingContext;
447 }
448
449 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, GraphicsContext3D::Attributes attributes)
450     : CanvasRenderingContext(passedCanvas)
451     , ActiveDOMObject(&passedCanvas->document())
452     , m_context(nullptr)
453     , m_dispatchContextLostEventTimer(*this, &WebGLRenderingContextBase::dispatchContextLostEvent)
454     , m_restoreAllowed(false)
455     , m_restoreTimer(*this, &WebGLRenderingContextBase::maybeRestoreContext)
456     , m_generatedImageCache(0)
457     , m_contextLost(false)
458     , m_contextLostMode(SyntheticLostContext)
459     , m_attributes(attributes)
460     , m_synthesizedErrorsToConsole(true)
461     , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
462     , m_isPendingPolicyResolution(true)
463     , m_hasRequestedPolicyResolution(false)
464 {
465 }
466
467 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, RefPtr<GraphicsContext3D>&& context, GraphicsContext3D::Attributes attributes)
468     : CanvasRenderingContext(passedCanvas)
469     , ActiveDOMObject(&passedCanvas->document())
470     , m_context(WTFMove(context))
471     , m_dispatchContextLostEventTimer(*this, &WebGLRenderingContextBase::dispatchContextLostEvent)
472     , m_restoreAllowed(false)
473     , m_restoreTimer(*this, &WebGLRenderingContextBase::maybeRestoreContext)
474     , m_generatedImageCache(4)
475     , m_contextLost(false)
476     , m_contextLostMode(SyntheticLostContext)
477     , m_attributes(attributes)
478     , m_synthesizedErrorsToConsole(true)
479     , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
480     , m_isPendingPolicyResolution(false)
481     , m_hasRequestedPolicyResolution(false)
482 {
483     ASSERT(m_context);
484     m_contextGroup = WebGLContextGroup::create();
485     m_contextGroup->addContext(this);
486     
487     m_context->setWebGLContext(this);
488
489     m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
490     m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
491
492     setupFlags();
493     initializeNewContext();
494 }
495
496 void WebGLRenderingContextBase::initializeNewContext()
497 {
498     ASSERT(!m_contextLost);
499     m_needsUpdate = true;
500     m_markedCanvasDirty = false;
501     m_activeTextureUnit = 0;
502     m_packAlignment = 4;
503     m_unpackAlignment = 4;
504     m_unpackFlipY = false;
505     m_unpackPremultiplyAlpha = false;
506     m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
507     m_boundArrayBuffer = nullptr;
508     m_currentProgram = nullptr;
509     m_framebufferBinding = nullptr;
510     m_renderbufferBinding = nullptr;
511     m_depthMask = true;
512     m_stencilEnabled = false;
513     m_stencilMask = 0xFFFFFFFF;
514     m_stencilMaskBack = 0xFFFFFFFF;
515     m_stencilFuncRef = 0;
516     m_stencilFuncRefBack = 0;
517     m_stencilFuncMask = 0xFFFFFFFF;
518     m_stencilFuncMaskBack = 0xFFFFFFFF;
519     m_layerCleared = false;
520     m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
521     
522     m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
523     m_scissorEnabled = false;
524     m_clearDepth = 1;
525     m_clearStencil = 0;
526     m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
527
528     GC3Dint numCombinedTextureImageUnits = 0;
529     m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
530     m_textureUnits.clear();
531     m_textureUnits.resize(numCombinedTextureImageUnits);
532     for (GC3Dint i = 0; i < numCombinedTextureImageUnits; ++i)
533         m_unrenderableTextureUnits.add(i);
534
535     GC3Dint numVertexAttribs = 0;
536     m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
537     m_maxVertexAttribs = numVertexAttribs;
538     
539     m_maxTextureSize = 0;
540     m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
541     m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
542     m_maxCubeMapTextureSize = 0;
543     m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
544     m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
545     m_maxRenderbufferSize = 0;
546     m_context->getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
547
548     // These two values from EXT_draw_buffers are lazily queried.
549     m_maxDrawBuffers = 0;
550     m_maxColorAttachments = 0;
551
552     m_backDrawBuffer = GraphicsContext3D::BACK;
553     m_drawBuffersWebGLRequirementsChecked = false;
554     m_drawBuffersSupported = false;
555     
556     m_vertexAttribValue.resize(m_maxVertexAttribs);
557
558     if (!isGLES2NPOTStrict())
559         createFallbackBlackTextures1x1();
560
561     IntSize canvasSize = clampedCanvasSize();
562     m_context->reshape(canvasSize.width(), canvasSize.height());
563     m_context->viewport(0, 0, canvasSize.width(), canvasSize.height());
564     m_context->scissor(0, 0, canvasSize.width(), canvasSize.height());
565
566     m_context->setContextLostCallback(std::make_unique<WebGLRenderingContextLostCallback>(this));
567     m_context->setErrorMessageCallback(std::make_unique<WebGLRenderingContextErrorMessageCallback>(this));
568 }
569
570 void WebGLRenderingContextBase::setupFlags()
571 {
572     ASSERT(m_context);
573
574     if (Page* page = canvas()->document().page())
575         m_synthesizedErrorsToConsole = page->settings().webGLErrorsToConsoleEnabled();
576
577     m_isGLES2Compliant = m_context->isGLES2Compliant();
578     m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs");
579     m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe");
580     if (m_isGLES2Compliant) {
581         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
582         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
583     } else {
584         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two");
585         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil");
586     }
587     m_isRobustnessEXTSupported = m_context->getExtensions()->isEnabled("GL_EXT_robustness");
588 }
589
590 void WebGLRenderingContextBase::addCompressedTextureFormat(GC3Denum format)
591 {
592     if (!m_compressedTextureFormats.contains(format))
593         m_compressedTextureFormats.append(format);
594 }
595
596 WebGLRenderingContextBase::~WebGLRenderingContextBase()
597 {
598     // Remove all references to WebGLObjects so if they are the last reference
599     // they will be freed before the last context is removed from the context group.
600     m_boundArrayBuffer = nullptr;
601     m_defaultVertexArrayObject = nullptr;
602     m_boundVertexArrayObject = nullptr;
603     m_vertexAttrib0Buffer = nullptr;
604     m_currentProgram = nullptr;
605     m_framebufferBinding = nullptr;
606     m_renderbufferBinding = nullptr;
607
608     for (auto& textureUnit : m_textureUnits) {
609         textureUnit.texture2DBinding = nullptr;
610         textureUnit.textureCubeMapBinding = nullptr;
611     }
612
613     m_blackTexture2D = nullptr;
614     m_blackTextureCubeMap = nullptr;
615
616     if (!m_isPendingPolicyResolution) {
617         detachAndRemoveAllObjects();
618         destroyGraphicsContext3D();
619         m_contextGroup->removeContext(this);
620     }
621 }
622
623 void WebGLRenderingContextBase::destroyGraphicsContext3D()
624 {
625     if (m_isPendingPolicyResolution)
626         return;
627
628     if (m_context) {
629         m_context->setContextLostCallback(nullptr);
630         m_context->setErrorMessageCallback(nullptr);
631         m_context = nullptr;
632     }
633 }
634
635 void WebGLRenderingContextBase::markContextChanged()
636 {
637     if (m_framebufferBinding)
638         return;
639
640     m_context->markContextChanged();
641
642     m_layerCleared = false;
643     RenderBox* renderBox = canvas()->renderBox();
644     if (isAccelerated() && renderBox && renderBox->hasAcceleratedCompositing()) {
645         m_markedCanvasDirty = true;
646         canvas()->clearCopiedImage();
647         renderBox->contentChanged(CanvasChanged);
648     } else {
649         if (!m_markedCanvasDirty) {
650             m_markedCanvasDirty = true;
651             canvas()->didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize()));
652         }
653     }
654 }
655
656 bool WebGLRenderingContextBase::clearIfComposited(GC3Dbitfield mask)
657 {
658     if (isContextLostOrPending())
659         return false;
660
661     if (!m_context->layerComposited() || m_layerCleared
662         || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
663         return false;
664
665     RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
666
667     // Determine if it's possible to combine the clear the user asked for and this clear.
668     bool combinedClear = mask && !m_scissorEnabled;
669
670     m_context->disable(GraphicsContext3D::SCISSOR_TEST);
671     if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
672         m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
673                               m_colorMask[1] ? m_clearColor[1] : 0,
674                               m_colorMask[2] ? m_clearColor[2] : 0,
675                               m_colorMask[3] ? m_clearColor[3] : 0);
676     else
677         m_context->clearColor(0, 0, 0, 0);
678     m_context->colorMask(true, true, true, true);
679     GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
680     if (contextAttributes->depth()) {
681         if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
682             m_context->clearDepth(1.0f);
683         clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
684         m_context->depthMask(true);
685     }
686     if (contextAttributes->stencil()) {
687         if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
688             m_context->clearStencil(m_clearStencil & m_stencilMask);
689         else
690             m_context->clearStencil(0);
691         clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
692         m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
693     }
694     if (m_framebufferBinding)
695         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
696     m_context->clear(clearMask);
697
698     restoreStateAfterClear();
699     if (m_framebufferBinding)
700         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
701     m_layerCleared = true;
702
703     return combinedClear;
704 }
705
706 void WebGLRenderingContextBase::restoreStateAfterClear()
707 {
708     // Restore the state that the context set.
709     if (m_scissorEnabled)
710         m_context->enable(GraphicsContext3D::SCISSOR_TEST);
711     m_context->clearColor(m_clearColor[0], m_clearColor[1],
712                           m_clearColor[2], m_clearColor[3]);
713     m_context->colorMask(m_colorMask[0], m_colorMask[1],
714                          m_colorMask[2], m_colorMask[3]);
715     m_context->clearDepth(m_clearDepth);
716     m_context->clearStencil(m_clearStencil);
717     m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
718     m_context->depthMask(m_depthMask);
719 }
720
721 void WebGLRenderingContextBase::markLayerComposited()
722 {
723     if (isContextLostOrPending())
724         return;
725     m_context->markLayerComposited();
726 }
727
728 void WebGLRenderingContextBase::paintRenderingResultsToCanvas()
729 {
730     if (isContextLostOrPending())
731         return;
732
733     if (canvas()->document().printing())
734         canvas()->clearPresentationCopy();
735
736     // Until the canvas is written to by the application, the clear that
737     // happened after it was composited should be ignored by the compositor.
738     if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
739         m_context->paintCompositedResultsToCanvas(canvas()->buffer());
740
741         canvas()->makePresentationCopy();
742     } else
743         canvas()->clearPresentationCopy();
744     clearIfComposited();
745
746     if (!m_markedCanvasDirty && !m_layerCleared)
747         return;
748
749     canvas()->clearCopiedImage();
750     m_markedCanvasDirty = false;
751
752     m_context->paintRenderingResultsToCanvas(canvas()->buffer());
753 }
754
755 PassRefPtr<ImageData> WebGLRenderingContextBase::paintRenderingResultsToImageData()
756 {
757     if (isContextLostOrPending())
758         return nullptr;
759     clearIfComposited();
760     return m_context->paintRenderingResultsToImageData();
761 }
762
763 WebGLTexture::TextureExtensionFlag WebGLRenderingContextBase::textureExtensionFlags() const
764 {
765     return static_cast<WebGLTexture::TextureExtensionFlag>((m_oesTextureFloatLinear ? WebGLTexture::TextureExtensionFloatLinearEnabled : 0) | (m_oesTextureHalfFloatLinear ? WebGLTexture::TextureExtensionHalfFloatLinearEnabled : 0));
766 }
767
768 void WebGLRenderingContextBase::reshape(int width, int height)
769 {
770     if (isContextLostOrPending())
771         return;
772
773     // This is an approximation because at WebGLRenderingContext level we don't
774     // know if the underlying FBO uses textures or renderbuffers.
775     GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
776     // Limit drawing buffer size to 4k to avoid memory exhaustion.
777     const int sizeUpperLimit = 4096;
778     maxSize = std::min(maxSize, sizeUpperLimit);
779     GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
780     GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
781     width = clamp(width, 1, maxWidth);
782     height = clamp(height, 1, maxHeight);
783
784     if (m_needsUpdate) {
785         RenderBox* renderBox = canvas()->renderBox();
786         if (renderBox && renderBox->hasAcceleratedCompositing())
787             renderBox->contentChanged(CanvasChanged);
788         m_needsUpdate = false;
789     }
790
791     // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
792     // clear (and this matches what reshape will do).
793     m_context->reshape(width, height);
794
795     auto& textureUnit = m_textureUnits[m_activeTextureUnit];
796     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(textureUnit.texture2DBinding.get()));
797     if (textureUnit.texture2DBinding && textureUnit.texture2DBinding->needToUseBlackTexture(textureExtensionFlags()))
798         m_unrenderableTextureUnits.add(m_activeTextureUnit);
799     m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
800     if (m_framebufferBinding)
801       m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
802 }
803
804 int WebGLRenderingContextBase::drawingBufferWidth() const
805 {
806     if (m_isPendingPolicyResolution && !m_hasRequestedPolicyResolution)
807         return 0;
808
809     return m_context->getInternalFramebufferSize().width();
810 }
811
812 int WebGLRenderingContextBase::drawingBufferHeight() const
813 {
814     if (m_isPendingPolicyResolution && !m_hasRequestedPolicyResolution)
815         return 0;
816
817     return m_context->getInternalFramebufferSize().height();
818 }
819
820 unsigned WebGLRenderingContextBase::sizeInBytes(GC3Denum type)
821 {
822     switch (type) {
823     case GraphicsContext3D::BYTE:
824         return sizeof(GC3Dbyte);
825     case GraphicsContext3D::UNSIGNED_BYTE:
826         return sizeof(GC3Dubyte);
827     case GraphicsContext3D::SHORT:
828         return sizeof(GC3Dshort);
829     case GraphicsContext3D::UNSIGNED_SHORT:
830         return sizeof(GC3Dushort);
831     case GraphicsContext3D::INT:
832         return sizeof(GC3Dint);
833     case GraphicsContext3D::UNSIGNED_INT:
834         return sizeof(GC3Duint);
835     case GraphicsContext3D::FLOAT:
836         return sizeof(GC3Dfloat);
837     }
838     ASSERT_NOT_REACHED();
839     return 0;
840 }
841
842 void WebGLRenderingContextBase::activeTexture(GC3Denum texture, ExceptionCode&)
843 {
844     if (isContextLostOrPending())
845         return;
846     if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
847         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "activeTexture", "texture unit out of range");
848         return;
849     }
850     m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
851     m_context->activeTexture(texture);
852 }
853
854 void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode&)
855 {
856     if (isContextLostOrPending() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader))
857         return;
858     if (!program->attachShader(shader)) {
859         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "attachShader", "shader attachment already has shader");
860         return;
861     }
862     m_context->attachShader(objectOrZero(program), objectOrZero(shader));
863     shader->onAttached();
864 }
865
866 void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode&)
867 {
868     if (isContextLostOrPending() || !validateWebGLObject("bindAttribLocation", program))
869         return;
870     if (!validateLocationLength("bindAttribLocation", name))
871         return;
872     if (!validateString("bindAttribLocation", name))
873         return;
874     if (isPrefixReserved(name)) {
875         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindAttribLocation", "reserved prefix");
876         return;
877     }
878     if (index >= m_maxVertexAttribs) {
879         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bindAttribLocation", "index out of range");
880         return;
881     }
882     m_context->bindAttribLocation(objectOrZero(program), index, name);
883 }
884
885 bool WebGLRenderingContextBase::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted)
886 {
887     deleted = false;
888     if (isContextLostOrPending())
889         return false;
890     if (object) {
891         if (!object->validate(contextGroup(), this)) {
892             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object not from this context");
893             return false;
894         }
895         deleted = !object->object();
896     }
897     return true;
898 }
899
900 void WebGLRenderingContextBase::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode&)
901 {
902     bool deleted;
903     if (!checkObjectToBeBound("bindBuffer", buffer, deleted))
904         return;
905     if (deleted)
906         buffer = 0;
907     if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
908         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets");
909         return;
910     }
911     if (target == GraphicsContext3D::ARRAY_BUFFER)
912         m_boundArrayBuffer = buffer;
913     else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
914         m_boundVertexArrayObject->setElementArrayBuffer(buffer);
915     else {
916         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindBuffer", "invalid target");
917         return;
918     }
919
920     m_context->bindBuffer(target, objectOrZero(buffer));
921     if (buffer)
922         buffer->setTarget(target);
923 }
924
925 void WebGLRenderingContextBase::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode&)
926 {
927     bool deleted;
928     if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted))
929         return;
930     if (deleted)
931         buffer = 0;
932     if (target != GraphicsContext3D::FRAMEBUFFER) {
933         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindFramebuffer", "invalid target");
934         return;
935     }
936     m_framebufferBinding = buffer;
937     m_context->bindFramebuffer(target, objectOrZero(buffer));
938     if (buffer)
939         buffer->setHasEverBeenBound();
940     applyStencilTest();
941 }
942
943 void WebGLRenderingContextBase::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode&)
944 {
945     bool deleted;
946     if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
947         return;
948     if (deleted)
949         renderBuffer = 0;
950     if (target != GraphicsContext3D::RENDERBUFFER) {
951         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindRenderbuffer", "invalid target");
952         return;
953     }
954     m_renderbufferBinding = renderBuffer;
955     m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
956     if (renderBuffer)
957         renderBuffer->setHasEverBeenBound();
958 }
959
960 void WebGLRenderingContextBase::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode&)
961 {
962     bool deleted;
963     if (!checkObjectToBeBound("bindTexture", texture, deleted))
964         return;
965     if (deleted)
966         texture = nullptr;
967     if (texture && texture->getTarget() && texture->getTarget() != target) {
968         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
969         return;
970     }
971     GC3Dint maxLevel = 0;
972     auto& textureUnit = m_textureUnits[m_activeTextureUnit];
973     if (target == GraphicsContext3D::TEXTURE_2D) {
974         textureUnit.texture2DBinding = texture;
975         maxLevel = m_maxTextureLevel;
976         if (texture && texture->needToUseBlackTexture(textureExtensionFlags()))
977             m_unrenderableTextureUnits.add(m_activeTextureUnit);
978         else
979             m_unrenderableTextureUnits.remove(m_activeTextureUnit);
980     } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
981         textureUnit.textureCubeMapBinding = texture;
982         maxLevel = m_maxCubeMapTextureLevel;
983         if (texture && texture->needToUseBlackTexture(textureExtensionFlags()))
984             m_unrenderableTextureUnits.add(m_activeTextureUnit);
985         else
986             m_unrenderableTextureUnits.remove(m_activeTextureUnit);
987     } else {
988         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindTexture", "invalid target");
989         return;
990     }
991     m_context->bindTexture(target, objectOrZero(texture));
992     if (texture)
993         texture->setTarget(target, maxLevel);
994
995     // Note: previously we used to automatically set the TEXTURE_WRAP_R
996     // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
997     // ES 2.0 doesn't expose this flag (a bug in the specification) and
998     // otherwise the application has no control over the seams in this
999     // dimension. However, it appears that supporting this properly on all
1000     // platforms is fairly involved (will require a HashMap from texture ID
1001     // in all ports), and we have not had any complaints, so the logic has
1002     // been removed.
1003 }
1004
1005 void WebGLRenderingContextBase::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
1006 {
1007     if (isContextLostOrPending())
1008         return;
1009     m_context->blendColor(red, green, blue, alpha);
1010 }
1011
1012 void WebGLRenderingContextBase::blendEquation(GC3Denum mode)
1013 {
1014     if (isContextLostOrPending() || !validateBlendEquation("blendEquation", mode))
1015         return;
1016     m_context->blendEquation(mode);
1017 }
1018
1019 void WebGLRenderingContextBase::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
1020 {
1021     if (isContextLostOrPending() || !validateBlendEquation("blendEquation", modeRGB) || !validateBlendEquation("blendEquation", modeAlpha))
1022         return;
1023     m_context->blendEquationSeparate(modeRGB, modeAlpha);
1024 }
1025
1026
1027 void WebGLRenderingContextBase::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
1028 {
1029     if (isContextLostOrPending() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
1030         return;
1031     m_context->blendFunc(sfactor, dfactor);
1032 }
1033
1034 void WebGLRenderingContextBase::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
1035 {
1036     // Note: Alpha does not have the same restrictions as RGB.
1037     if (isContextLostOrPending() || !validateBlendFuncFactors("blendFunc", srcRGB, dstRGB))
1038         return;
1039     m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
1040 }
1041
1042 void WebGLRenderingContextBase::bufferData(GC3Denum target, long long size, GC3Denum usage, ExceptionCode&)
1043 {
1044     if (isContextLostOrPending())
1045         return;
1046     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1047     if (!buffer)
1048         return;
1049     if (size < 0) {
1050         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size < 0");
1051         return;
1052     }
1053     if (!size) {
1054         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size == 0");
1055         return;
1056     }
1057     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1058         if (!buffer->associateBufferData(static_cast<GC3Dsizeiptr>(size))) {
1059             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1060             return;
1061         }
1062     }
1063
1064     m_context->moveErrorsToSyntheticErrorList();
1065     m_context->bufferData(target, static_cast<GC3Dsizeiptr>(size), usage);
1066     if (m_context->moveErrorsToSyntheticErrorList()) {
1067         // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1068         buffer->disassociateBufferData();
1069     }
1070 }
1071
1072 void WebGLRenderingContextBase::bufferData(GC3Denum target, ArrayBuffer& data, GC3Denum usage, ExceptionCode&)
1073 {
1074     if (isContextLostOrPending())
1075         return;
1076     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1077     if (!buffer)
1078         return;
1079     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1080         if (!buffer->associateBufferData(&data)) {
1081             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1082             return;
1083         }
1084     }
1085
1086     m_context->moveErrorsToSyntheticErrorList();
1087     m_context->bufferData(target, data.byteLength(), data.data(), usage);
1088     if (m_context->moveErrorsToSyntheticErrorList()) {
1089         // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1090         buffer->disassociateBufferData();
1091     }
1092 }
1093
1094 void WebGLRenderingContextBase::bufferData(GC3Denum target, ArrayBufferView& data, GC3Denum usage, ExceptionCode&)
1095 {
1096     if (isContextLostOrPending())
1097         return;
1098     WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1099     if (!buffer)
1100         return;
1101     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1102         if (!buffer->associateBufferData(&data)) {
1103             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1104             return;
1105         }
1106     }
1107
1108     m_context->moveErrorsToSyntheticErrorList();
1109     m_context->bufferData(target, data.byteLength(), data.baseAddress(), usage);
1110     if (m_context->moveErrorsToSyntheticErrorList()) {
1111         // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1112         buffer->disassociateBufferData();
1113     }
1114 }
1115
1116 void WebGLRenderingContextBase::bufferSubData(GC3Denum target, long long offset, ArrayBuffer* data, ExceptionCode&)
1117 {
1118     if (isContextLostOrPending())
1119         return;
1120     WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1121     if (!buffer)
1122         return;
1123     if (offset < 0) {
1124         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1125         return;
1126     }
1127     if (!data)
1128         return;
1129     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1130         if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data)) {
1131             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1132             return;
1133         }
1134     }
1135
1136     m_context->moveErrorsToSyntheticErrorList();
1137     m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->data());
1138     if (m_context->moveErrorsToSyntheticErrorList()) {
1139         // The bufferSubData function failed. Tell the buffer it doesn't have the data it thinks it does.
1140         buffer->disassociateBufferData();
1141     }
1142 }
1143
1144 void WebGLRenderingContextBase::bufferSubData(GC3Denum target, long long offset, RefPtr<ArrayBufferView>&& data, ExceptionCode&)
1145 {
1146     if (isContextLostOrPending())
1147         return;
1148     WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1149     if (!buffer)
1150         return;
1151     if (offset < 0) {
1152         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1153         return;
1154     }
1155     if (!data)
1156         return;
1157     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1158         if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data.get())) {
1159             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1160             return;
1161         }
1162     }
1163
1164     m_context->moveErrorsToSyntheticErrorList();
1165     m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->baseAddress());
1166     if (m_context->moveErrorsToSyntheticErrorList()) {
1167         // The bufferSubData function failed. Tell the buffer it doesn't have the data it thinks it does.
1168         buffer->disassociateBufferData();
1169     }
1170 }
1171
1172 GC3Denum WebGLRenderingContextBase::checkFramebufferStatus(GC3Denum target)
1173 {
1174     if (isContextLostOrPending())
1175         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
1176     if (target != GraphicsContext3D::FRAMEBUFFER) {
1177         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "checkFramebufferStatus", "invalid target");
1178         return 0;
1179     }
1180     if (!m_framebufferBinding || !m_framebufferBinding->object())
1181         return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
1182     const char* reason = "framebuffer incomplete";
1183     GC3Denum result = m_framebufferBinding->checkStatus(&reason);
1184     if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
1185         printGLWarningToConsole("checkFramebufferStatus", reason);
1186         return result;
1187     }
1188     result = m_context->checkFramebufferStatus(target);
1189     return result;
1190 }
1191
1192 void WebGLRenderingContextBase::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
1193 {
1194     if (isContextLostOrPending())
1195         return;
1196     if (std::isnan(r))
1197         r = 0;
1198     if (std::isnan(g))
1199         g = 0;
1200     if (std::isnan(b))
1201         b = 0;
1202     if (std::isnan(a))
1203         a = 1;
1204     m_clearColor[0] = r;
1205     m_clearColor[1] = g;
1206     m_clearColor[2] = b;
1207     m_clearColor[3] = a;
1208     m_context->clearColor(r, g, b, a);
1209 }
1210
1211 void WebGLRenderingContextBase::clearDepth(GC3Dfloat depth)
1212 {
1213     if (isContextLostOrPending())
1214         return;
1215     m_clearDepth = depth;
1216     m_context->clearDepth(depth);
1217 }
1218
1219 void WebGLRenderingContextBase::clearStencil(GC3Dint s)
1220 {
1221     if (isContextLostOrPending())
1222         return;
1223     m_clearStencil = s;
1224     m_context->clearStencil(s);
1225 }
1226
1227 void WebGLRenderingContextBase::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1228 {
1229     if (isContextLostOrPending())
1230         return;
1231     m_colorMask[0] = red;
1232     m_colorMask[1] = green;
1233     m_colorMask[2] = blue;
1234     m_colorMask[3] = alpha;
1235     m_context->colorMask(red, green, blue, alpha);
1236 }
1237
1238 void WebGLRenderingContextBase::compileShader(WebGLShader* shader, ExceptionCode&)
1239 {
1240     if (isContextLostOrPending() || !validateWebGLObject("compileShader", shader))
1241         return;
1242     m_context->compileShader(objectOrZero(shader));
1243     GC3Dint value;
1244     m_context->getShaderiv(objectOrZero(shader), GraphicsContext3D::COMPILE_STATUS, &value);
1245     shader->setValid(value);
1246 }
1247
1248 void WebGLRenderingContextBase::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, ArrayBufferView& data)
1249 {
1250     if (isContextLostOrPending())
1251         return;
1252     if (!validateTexFuncLevel("compressedTexImage2D", target, level))
1253         return;
1254
1255     if (!validateCompressedTexFormat(internalformat)) {
1256         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
1257         return;
1258     }
1259     if (border) {
1260         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "border not 0");
1261         return;
1262     }
1263     if (!validateCompressedTexDimensions("compressedTexImage2D", target, level, width, height, internalformat))
1264         return;
1265     if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
1266         return;
1267
1268     WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
1269     if (!tex)
1270         return;
1271     if (!validateNPOTTextureLevel(width, height, level, "compressedTexImage2D"))
1272         return;
1273     m_context->moveErrorsToSyntheticErrorList();
1274     m_context->compressedTexImage2D(target, level, internalformat, width, height,
1275         border, data.byteLength(), data.baseAddress());
1276     if (m_context->moveErrorsToSyntheticErrorList()) {
1277         // The compressedTexImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
1278         tex->markInvalid(target, level);
1279         return;
1280     }
1281
1282     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1283     tex->setCompressed();
1284 }
1285
1286 void WebGLRenderingContextBase::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView& data)
1287 {
1288     if (isContextLostOrPending())
1289         return;
1290     if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
1291         return;
1292     if (!validateCompressedTexFormat(format)) {
1293         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
1294         return;
1295     }
1296     if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
1297         return;
1298
1299     WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
1300     if (!tex)
1301         return;
1302
1303     if (format != tex->getInternalFormat(target, level)) {
1304         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
1305         return;
1306     }
1307
1308     if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
1309         return;
1310
1311     graphicsContext3D()->compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, data.byteLength(), data.baseAddress());
1312     tex->setCompressed();
1313 }
1314
1315 bool WebGLRenderingContextBase::validateSettableTexFormat(const char* functionName, GC3Denum format)
1316 {
1317     if (GraphicsContext3D::getClearBitsByFormat(format) & (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
1318         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format can not be set, only rendered to");
1319         return false;
1320     }
1321     return true;
1322 }
1323
1324 void WebGLRenderingContextBase::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1325 {
1326     if (isContextLostOrPending())
1327         return;
1328     if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
1329         return;
1330     WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
1331     if (!tex)
1332         return;
1333     if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
1334         return;
1335     // Before checking if it is in the range, check if overflow happens first.
1336     if (xoffset + width < 0 || yoffset + height < 0) {
1337         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "bad dimensions");
1338         return;
1339     }
1340     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1341         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
1342         return;
1343     }
1344     GC3Denum internalformat = tex->getInternalFormat(target, level);
1345     if (!validateSettableTexFormat("copyTexSubImage2D", internalformat))
1346         return;
1347     if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1348         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
1349         return;
1350     }
1351     const char* reason = "framebuffer incomplete";
1352     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1353         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", reason);
1354         return;
1355     }
1356     clearIfComposited();
1357     if (isResourceSafe())
1358         m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1359     else {
1360         GC3Dint clippedX, clippedY;
1361         GC3Dsizei clippedWidth, clippedHeight;
1362         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1363             GC3Denum format = tex->getInternalFormat(target, level);
1364             GC3Denum type = tex->getType(target, level);
1365             std::unique_ptr<unsigned char[]> zero;
1366             if (width && height) {
1367                 unsigned int size;
1368                 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1369                 if (error != GraphicsContext3D::NO_ERROR) {
1370                     synthesizeGLError(error, "copyTexSubImage2D", "bad dimensions");
1371                     return;
1372                 }
1373                 zero = std::make_unique<unsigned char[]>(size);
1374                 if (!zero) {
1375                     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "out of memory");
1376                     return;
1377                 }
1378                 memset(zero.get(), 0, size);
1379             }
1380             m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1381             if (clippedWidth > 0 && clippedHeight > 0)
1382                 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1383                                              clippedX, clippedY, clippedWidth, clippedHeight);
1384         } else
1385             m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1386     }
1387 }
1388
1389 PassRefPtr<WebGLBuffer> WebGLRenderingContextBase::createBuffer()
1390 {
1391     if (isContextLostOrPending())
1392         return nullptr;
1393     RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1394     addSharedObject(o.get());
1395     return o;
1396 }
1397
1398 PassRefPtr<WebGLFramebuffer> WebGLRenderingContextBase::createFramebuffer()
1399 {
1400     if (isContextLostOrPending())
1401         return nullptr;
1402     RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1403     addContextObject(o.get());
1404     return o;
1405 }
1406
1407 PassRefPtr<WebGLTexture> WebGLRenderingContextBase::createTexture()
1408 {
1409     if (isContextLostOrPending())
1410         return nullptr;
1411     RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1412     addSharedObject(o.get());
1413     return o;
1414 }
1415
1416 PassRefPtr<WebGLProgram> WebGLRenderingContextBase::createProgram()
1417 {
1418     if (isContextLostOrPending())
1419         return nullptr;
1420     RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1421     addSharedObject(o.get());
1422     return o;
1423 }
1424
1425 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContextBase::createRenderbuffer()
1426 {
1427     if (isContextLostOrPending())
1428         return nullptr;
1429     RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1430     addSharedObject(o.get());
1431     return o;
1432 }
1433
1434 PassRefPtr<WebGLShader> WebGLRenderingContextBase::createShader(GC3Denum type, ExceptionCode&)
1435 {
1436     if (isContextLostOrPending())
1437         return nullptr;
1438     if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1439         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "createShader", "invalid shader type");
1440         return nullptr;
1441     }
1442
1443     RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1444     addSharedObject(o.get());
1445     return o;
1446 }
1447
1448 void WebGLRenderingContextBase::cullFace(GC3Denum mode)
1449 {
1450     if (isContextLostOrPending())
1451         return;
1452     m_context->cullFace(mode);
1453 }
1454
1455 bool WebGLRenderingContextBase::deleteObject(WebGLObject* object)
1456 {
1457     if (isContextLostOrPending() || !object)
1458         return false;
1459     if (!object->validate(contextGroup(), this)) {
1460         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "delete", "object does not belong to this context");
1461         return false;
1462     }
1463     if (object->object())
1464         // We need to pass in context here because we want
1465         // things in this context unbound.
1466         object->deleteObject(graphicsContext3D());
1467     return true;
1468 }
1469
1470 void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer)
1471 {
1472     if (!deleteObject(buffer))
1473         return;
1474     if (m_boundArrayBuffer == buffer)
1475         m_boundArrayBuffer = nullptr;
1476
1477     m_boundVertexArrayObject->unbindBuffer(buffer);
1478 }
1479
1480 void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1481 {
1482     if (!deleteObject(framebuffer))
1483         return;
1484     if (framebuffer == m_framebufferBinding) {
1485         m_framebufferBinding = nullptr;
1486         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1487     }
1488 }
1489
1490 void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program)
1491 {
1492     deleteObject(program);
1493     // We don't reset m_currentProgram to 0 here because the deletion of the
1494     // current program is delayed.
1495 }
1496
1497 void WebGLRenderingContextBase::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1498 {
1499     if (!deleteObject(renderbuffer))
1500         return;
1501     if (renderbuffer == m_renderbufferBinding)
1502         m_renderbufferBinding = nullptr;
1503     if (m_framebufferBinding)
1504         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1505 }
1506
1507 void WebGLRenderingContextBase::deleteShader(WebGLShader* shader)
1508 {
1509     deleteObject(shader);
1510 }
1511
1512 void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture)
1513 {
1514     if (!deleteObject(texture))
1515         return;
1516
1517     unsigned current = 0;
1518     for (auto& textureUnit : m_textureUnits) {
1519         if (texture == textureUnit.texture2DBinding) {
1520             textureUnit.texture2DBinding = nullptr;
1521             m_unrenderableTextureUnits.remove(current);
1522         }
1523         if (texture == textureUnit.textureCubeMapBinding) {
1524             textureUnit.textureCubeMapBinding = nullptr;
1525             m_unrenderableTextureUnits.remove(current);
1526         }
1527         ++current;
1528     }
1529     if (m_framebufferBinding)
1530         m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1531 }
1532
1533 void WebGLRenderingContextBase::depthFunc(GC3Denum func)
1534 {
1535     if (isContextLostOrPending())
1536         return;
1537     m_context->depthFunc(func);
1538 }
1539
1540 void WebGLRenderingContextBase::depthMask(GC3Dboolean flag)
1541 {
1542     if (isContextLostOrPending())
1543         return;
1544     m_depthMask = flag;
1545     m_context->depthMask(flag);
1546 }
1547
1548 void WebGLRenderingContextBase::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1549 {
1550     if (isContextLostOrPending())
1551         return;
1552     if (zNear > zFar) {
1553         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "depthRange", "zNear > zFar");
1554         return;
1555     }
1556     m_context->depthRange(zNear, zFar);
1557 }
1558
1559 void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode&)
1560 {
1561     if (isContextLostOrPending() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
1562         return;
1563     if (!program->detachShader(shader)) {
1564         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "detachShader", "shader not attached");
1565         return;
1566     }
1567     m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1568     shader->onDetached(graphicsContext3D());
1569 }
1570
1571 void WebGLRenderingContextBase::disable(GC3Denum cap)
1572 {
1573     if (isContextLostOrPending() || !validateCapability("disable", cap))
1574         return;
1575     if (cap == GraphicsContext3D::STENCIL_TEST) {
1576         m_stencilEnabled = false;
1577         applyStencilTest();
1578         return;
1579     }
1580     if (cap == GraphicsContext3D::SCISSOR_TEST)
1581         m_scissorEnabled = false;
1582     m_context->disable(cap);
1583 }
1584
1585 void WebGLRenderingContextBase::disableVertexAttribArray(GC3Duint index, ExceptionCode&)
1586 {
1587     if (isContextLostOrPending())
1588         return;
1589     if (index >= m_maxVertexAttribs) {
1590         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "disableVertexAttribArray", "index out of range");
1591         return;
1592     }
1593
1594     WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1595     state.enabled = false;
1596
1597     if (index > 0 || isGLES2Compliant())
1598         m_context->disableVertexAttribArray(index);
1599 }
1600
1601 bool WebGLRenderingContextBase::validateNPOTTextureLevel(GC3Dsizei width, GC3Dsizei height, GC3Dint level, const char* functionName)
1602 {
1603     if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1604         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level > 0 not power of 2");
1605         return false;
1606     }
1607
1608     return true;
1609 }
1610
1611 bool WebGLRenderingContextBase::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1612 {
1613     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1614     
1615     if (!elementArrayBuffer)
1616         return false;
1617
1618     if (offset < 0)
1619         return false;
1620
1621     if (type == GraphicsContext3D::UNSIGNED_INT) {
1622         // For an unsigned int array, offset must be divisible by 4 for alignment reasons.
1623         if (offset % 4)
1624             return false;
1625
1626         // Make uoffset an element offset.
1627         offset /= 4;
1628
1629         GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 4;
1630         if (offset > n || count > n - offset)
1631             return false;
1632     } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1633         // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1634         if (offset % 2)
1635             return false;
1636
1637         // Make uoffset an element offset.
1638         offset /= 2;
1639
1640         GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1641         if (offset > n || count > n - offset)
1642             return false;
1643     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1644         GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1645         if (offset > n || count > n - offset)
1646             return false;
1647     }
1648     return true;
1649 }
1650
1651 bool WebGLRenderingContextBase::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, unsigned& numElementsRequired)
1652 {
1653     ASSERT(count >= 0 && offset >= 0);
1654     unsigned lastIndex = 0;
1655     
1656     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1657
1658     if (!elementArrayBuffer)
1659         return false;
1660
1661     if (!count) {
1662         numElementsRequired = 0;
1663         return true;
1664     }
1665
1666     if (!elementArrayBuffer->elementArrayBuffer())
1667         return false;
1668
1669     unsigned long uoffset = offset;
1670     unsigned long n = count;
1671
1672     if (type == GraphicsContext3D::UNSIGNED_INT) {
1673         // Make uoffset an element offset.
1674         uoffset /= sizeof(GC3Duint);
1675         const GC3Duint* p = static_cast<const GC3Duint*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1676         while (n-- > 0) {
1677             if (*p > lastIndex)
1678                 lastIndex = *p;
1679             ++p;
1680         }
1681     } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1682         // Make uoffset an element offset.
1683         uoffset /= sizeof(GC3Dushort);
1684         const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1685         while (n-- > 0) {
1686             if (*p > lastIndex)
1687                 lastIndex = *p;
1688             ++p;
1689         }
1690     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1691         const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1692         while (n-- > 0) {
1693             if (*p > lastIndex)
1694                 lastIndex = *p;
1695             ++p;
1696         }
1697     }
1698
1699     // Then set the last index in the index array and make sure it is valid.
1700     numElementsRequired = lastIndex + 1;
1701     return numElementsRequired > 0;
1702 }
1703
1704 bool WebGLRenderingContextBase::validateVertexAttributes(unsigned elementCount, unsigned primitiveCount)
1705 {
1706     if (!m_currentProgram)
1707         return false;
1708
1709     // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1710     for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1711         if (!m_boundVertexArrayObject->getVertexAttribState(i).validateBinding())
1712             return false;
1713     }
1714
1715     if (elementCount <= 0)
1716         return true;
1717
1718     // Look in each consumed vertex attrib (by the current program).
1719     bool sawNonInstancedAttrib = false;
1720     bool sawEnabledAttrib = false;
1721     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1722     for (int i = 0; i < numActiveAttribLocations; ++i) {
1723         int loc = m_currentProgram->getActiveAttribLocation(i);
1724         if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1725             const WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1726             if (state.enabled) {
1727                 sawEnabledAttrib = true;
1728                 // Avoid off-by-one errors in numElements computation.
1729                 // For the last element, we will only touch the data for the
1730                 // element and nothing beyond it.
1731                 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1732                 unsigned numElements = 0;
1733                 ASSERT(state.stride > 0);
1734                 if (bytesRemaining >= state.bytesPerElement)
1735                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1736                 unsigned instancesRequired = 0;
1737                 if (state.divisor) {
1738                     instancesRequired = ceil(static_cast<float>(primitiveCount) / state.divisor);
1739                     if (instancesRequired > numElements)
1740                         return false;
1741                 } else {
1742                     sawNonInstancedAttrib = true;
1743                     if (elementCount > numElements)
1744                         return false;
1745                 }
1746             }
1747         }
1748     }
1749
1750     if (!sawNonInstancedAttrib && sawEnabledAttrib)
1751         return false;
1752
1753     // Guard against access into non-existent buffers.
1754     if (elementCount && !sawEnabledAttrib && !m_currentProgram->isUsingVertexAttrib0())
1755         return false;
1756
1757     return true;
1758 }
1759
1760 bool WebGLRenderingContextBase::validateWebGLObject(const char* functionName, WebGLObject* object)
1761 {
1762     if (!object || !object->object()) {
1763         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no object or object deleted");
1764         return false;
1765     }
1766     if (!object->validate(contextGroup(), this)) {
1767         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object does not belong to this context");
1768         return false;
1769     }
1770     return true;
1771 }
1772
1773 bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primitiveCount)
1774 {
1775     if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
1776         return false;
1777
1778     if (!validateStencilSettings(functionName))
1779         return false;
1780
1781     if (first < 0 || count < 0) {
1782         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "first or count < 0");
1783         return false;
1784     }
1785
1786     if (!count) {
1787         markContextChanged();
1788         return false;
1789     }
1790
1791     if (primitiveCount < 0) {
1792         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
1793         return false;
1794     }
1795
1796     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1797         // Ensure we have a valid rendering state
1798         Checked<GC3Dint, RecordOverflow> checkedFirst(first);
1799         Checked<GC3Dint, RecordOverflow> checkedCount(count);
1800         Checked<GC3Dint, RecordOverflow> checkedSum = checkedFirst + checkedCount;
1801         Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
1802         if (checkedSum.hasOverflowed() || checkedPrimitiveCount.hasOverflowed() || !validateVertexAttributes(checkedSum.unsafeGet(), checkedPrimitiveCount.unsafeGet())) {
1803             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
1804             return false;
1805         }
1806         if (!validateSimulatedVertexAttrib0(checkedSum.unsafeGet() - 1)) {
1807             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access outside the bounds of the simulated vertexAttrib0 array");
1808             return false;
1809         }
1810     } else {
1811         if (!validateVertexAttributes(0)) {
1812             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
1813             return false;
1814         }
1815     }
1816
1817     const char* reason = "framebuffer incomplete";
1818     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1819         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
1820         return false;
1821     }
1822
1823     return true;
1824 }
1825
1826 bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primitiveCount)
1827 {
1828     if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
1829         return false;
1830     
1831     if (!validateStencilSettings(functionName))
1832         return false;
1833     
1834     switch (type) {
1835     case GraphicsContext3D::UNSIGNED_BYTE:
1836     case GraphicsContext3D::UNSIGNED_SHORT:
1837         break;
1838     case GraphicsContext3D::UNSIGNED_INT:
1839         if (m_oesElementIndexUint || isWebGL2())
1840             break;
1841         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
1842         return false;
1843     default:
1844         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
1845         return false;
1846     }
1847     
1848     if (count < 0 || offset < 0) {
1849         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "count or offset < 0");
1850         return false;
1851     }
1852     
1853     if (!count) {
1854         markContextChanged();
1855         return false;
1856     }
1857     
1858     if (primitiveCount < 0) {
1859         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
1860         return false;
1861     }
1862     
1863     if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1864         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
1865         return false;
1866     }
1867     
1868     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1869         // Ensure we have a valid rendering state
1870         if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
1871             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "request out of bounds for current ELEMENT_ARRAY_BUFFER");
1872             return false;
1873         }
1874         if (!count)
1875             return false;
1876         
1877         Checked<GC3Dint, RecordOverflow> checkedCount(count);
1878         Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
1879         if (checkedCount.hasOverflowed() || checkedPrimitiveCount.hasOverflowed()) {
1880             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
1881             return false;
1882         }
1883         
1884         if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
1885             if (!validateIndexArrayPrecise(checkedCount.unsafeGet(), type, static_cast<GC3Dintptr>(offset), numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
1886                 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
1887                 return false;
1888             }
1889         }
1890
1891         if (!validateSimulatedVertexAttrib0(numElements)) {
1892             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access outside the bounds of the simulated vertexAttrib0 array");
1893             return false;
1894         }
1895
1896     } else {
1897         if (!validateVertexAttributes(0)) {
1898             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
1899             return false;
1900         }
1901     }
1902     
1903     const char* reason = "framebuffer incomplete";
1904     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1905         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
1906         return false;
1907     }
1908     
1909     return true;
1910 }
1911
1912 void WebGLRenderingContextBase::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode&)
1913 {
1914     if (!validateDrawArrays("drawArrays", mode, first, count, 0))
1915         return;
1916
1917     clearIfComposited();
1918
1919     bool vertexAttrib0Simulated = false;
1920     if (!isGLES2Compliant())
1921         vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1922     bool usesFallbackTexture = false;
1923     if (!isGLES2NPOTStrict())
1924         usesFallbackTexture = checkTextureCompleteness("drawArrays", true);
1925
1926     m_context->drawArrays(mode, first, count);
1927
1928     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1929         restoreStatesAfterVertexAttrib0Simulation();
1930     if (usesFallbackTexture)
1931         checkTextureCompleteness("drawArrays", false);
1932     markContextChanged();
1933 }
1934
1935 void WebGLRenderingContextBase::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode&)
1936 {
1937     unsigned numElements = 0;
1938     if (!validateDrawElements("drawElements", mode, count, type, offset, numElements, 0))
1939         return;
1940
1941     clearIfComposited();
1942
1943     bool vertexAttrib0Simulated = false;
1944     if (!isGLES2Compliant()) {
1945         if (!numElements)
1946             validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
1947         vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1948     }
1949
1950     bool usesFallbackTexture = false;
1951     if (!isGLES2NPOTStrict())
1952         usesFallbackTexture = checkTextureCompleteness("drawElements", true);
1953
1954     m_context->drawElements(mode, count, type, static_cast<GC3Dintptr>(offset));
1955
1956     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1957         restoreStatesAfterVertexAttrib0Simulation();
1958     if (usesFallbackTexture)
1959         checkTextureCompleteness("drawElements", false);
1960     markContextChanged();
1961 }
1962
1963 void WebGLRenderingContextBase::enable(GC3Denum cap)
1964 {
1965     if (isContextLostOrPending() || !validateCapability("enable", cap))
1966         return;
1967     if (cap == GraphicsContext3D::STENCIL_TEST) {
1968         m_stencilEnabled = true;
1969         applyStencilTest();
1970         return;
1971     }
1972     if (cap == GraphicsContext3D::SCISSOR_TEST)
1973         m_scissorEnabled = true;
1974     m_context->enable(cap);
1975 }
1976
1977 void WebGLRenderingContextBase::enableVertexAttribArray(GC3Duint index, ExceptionCode&)
1978 {
1979     if (isContextLostOrPending())
1980         return;
1981     if (index >= m_maxVertexAttribs) {
1982         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "enableVertexAttribArray", "index out of range");
1983         return;
1984     }
1985
1986     WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1987     state.enabled = true;
1988
1989     m_context->enableVertexAttribArray(index);
1990 }
1991
1992 void WebGLRenderingContextBase::finish()
1993 {
1994     if (isContextLostOrPending())
1995         return;
1996     m_context->finish();
1997 }
1998
1999 void WebGLRenderingContextBase::flush()
2000 {
2001     if (isContextLostOrPending())
2002         return;
2003     m_context->flush();
2004 }
2005
2006 void WebGLRenderingContextBase::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode&)
2007 {
2008     if (isContextLostOrPending() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
2009         return;
2010     if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
2011         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
2012         return;
2013     }
2014     if (buffer && !buffer->validate(contextGroup(), this)) {
2015         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
2016         return;
2017     }
2018     // Don't allow the default framebuffer to be mutated; all current
2019     // implementations use an FBO internally in place of the default
2020     // FBO.
2021     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2022         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
2023         return;
2024     }
2025     Platform3DObject bufferObject = objectOrZero(buffer);
2026     switch (attachment) {
2027     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2028         m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
2029         m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
2030         break;
2031     default:
2032         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
2033     }
2034     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
2035     applyStencilTest();
2036 }
2037
2038 void WebGLRenderingContextBase::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode&)
2039 {
2040     if (isContextLostOrPending() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
2041         return;
2042     if (level) {
2043         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "framebufferTexture2D", "level not 0");
2044         return;
2045     }
2046     if (texture && !texture->validate(contextGroup(), this)) {
2047         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
2048         return;
2049     }
2050     // Don't allow the default framebuffer to be mutated; all current
2051     // implementations use an FBO internally in place of the default
2052     // FBO.
2053     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2054         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
2055         return;
2056     }
2057     Platform3DObject textureObject = objectOrZero(texture);
2058     switch (attachment) {
2059     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2060         m_context->framebufferTexture2D(target, GraphicsContext3D::DEPTH_ATTACHMENT, textarget, textureObject, level);
2061         m_context->framebufferTexture2D(target, GraphicsContext3D::STENCIL_ATTACHMENT, textarget, textureObject, level);
2062         break;
2063     case GraphicsContext3D::DEPTH_ATTACHMENT:
2064         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2065         break;
2066     case GraphicsContext3D::STENCIL_ATTACHMENT:
2067         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2068         break;
2069     default:
2070         m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2071     }
2072     m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
2073     applyStencilTest();
2074 }
2075
2076 void WebGLRenderingContextBase::frontFace(GC3Denum mode)
2077 {
2078     if (isContextLostOrPending())
2079         return;
2080     m_context->frontFace(mode);
2081 }
2082
2083 void WebGLRenderingContextBase::generateMipmap(GC3Denum target)
2084 {
2085     if (isContextLostOrPending())
2086         return;
2087     WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
2088     if (!tex)
2089         return;
2090     if (!tex->canGenerateMipmaps()) {
2091         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
2092         return;
2093     }
2094     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=123916. Compressed textures should be allowed in WebGL 2:
2095     if (tex->isCompressed()) {
2096         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "trying to generate mipmaps from compressed texture");
2097         return;
2098     }
2099     if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0)))
2100         return;
2101
2102     // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
2103     // on Mac.  Remove the hack once this driver bug is fixed.
2104 #if OS(DARWIN)
2105     bool needToResetMinFilter = false;
2106     if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
2107         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
2108         needToResetMinFilter = true;
2109     }
2110 #endif
2111     m_context->generateMipmap(target);
2112 #if OS(DARWIN)
2113     if (needToResetMinFilter)
2114         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
2115 #endif
2116     tex->generateMipmapLevelInfo();
2117 }
2118
2119 PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode&)
2120 {
2121     if (isContextLostOrPending() || !validateWebGLObject("getActiveAttrib", program))
2122         return nullptr;
2123     ActiveInfo info;
2124     if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
2125         return nullptr;
2126
2127     LOG(WebGL, "Returning active attribute %d: %s", index, info.name.utf8().data());
2128
2129     return WebGLActiveInfo::create(info.name, info.type, info.size);
2130 }
2131
2132 PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode&)
2133 {
2134     if (isContextLostOrPending() || !validateWebGLObject("getActiveUniform", program))
2135         return 0;
2136     ActiveInfo info;
2137     if (!m_context->getActiveUniform(objectOrZero(program), index, info))
2138         return nullptr;
2139     if (!isGLES2Compliant())
2140         if (info.size > 1 && !info.name.endsWith("[0]"))
2141             info.name.append("[0]");
2142
2143     LOG(WebGL, "Returning active uniform %d: %s", index, info.name.utf8().data());
2144
2145     return WebGLActiveInfo::create(info.name, info.type, info.size);
2146 }
2147
2148 bool WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader>>& shaderObjects, ExceptionCode&)
2149 {
2150     shaderObjects.clear();
2151     if (isContextLostOrPending() || !validateWebGLObject("getAttachedShaders", program))
2152         return false;
2153
2154     const GC3Denum shaderType[] = {
2155         GraphicsContext3D::VERTEX_SHADER,
2156         GraphicsContext3D::FRAGMENT_SHADER
2157     };
2158     for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
2159         WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2160         if (shader)
2161             shaderObjects.append(shader);
2162     }
2163     return true;
2164 }
2165
2166 GC3Dint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String& name)
2167 {
2168     if (isContextLostOrPending() || !validateWebGLObject("getAttribLocation", program))
2169         return -1;
2170     if (!validateLocationLength("getAttribLocation", name))
2171         return -1;
2172     if (!validateString("getAttribLocation", name))
2173         return -1;
2174     if (isPrefixReserved(name))
2175         return -1;
2176     if (!program->getLinkStatus()) {
2177         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getAttribLocation", "program not linked");
2178         return -1;
2179     }
2180     return m_context->getAttribLocation(objectOrZero(program), name);
2181 }
2182
2183 WebGLGetInfo WebGLRenderingContextBase::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode&)
2184 {
2185     if (isContextLostOrPending())
2186         return WebGLGetInfo();
2187     if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
2188         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid target");
2189         return WebGLGetInfo();
2190     }
2191
2192     if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
2193         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2194         return WebGLGetInfo();
2195     }
2196
2197     GC3Dint value = 0;
2198     m_context->getBufferParameteriv(target, pname, &value);
2199     if (pname == GraphicsContext3D::BUFFER_SIZE)
2200         return WebGLGetInfo(value);
2201     return WebGLGetInfo(static_cast<unsigned int>(value));
2202 }
2203
2204 PassRefPtr<WebGLContextAttributes> WebGLRenderingContextBase::getContextAttributes()
2205 {
2206     if (isContextLostOrPending())
2207         return nullptr;
2208     // We always need to return a new WebGLContextAttributes object to
2209     // prevent the user from mutating any cached version.
2210
2211     // Also, we need to enforce requested values of "false" for depth
2212     // and stencil, regardless of the properties of the underlying
2213     // GraphicsContext3D.
2214     RefPtr<WebGLContextAttributes> attributes = WebGLContextAttributes::create(m_context->getContextAttributes());
2215     if (!m_attributes.depth)
2216         attributes->setDepth(false);
2217     if (!m_attributes.stencil)
2218         attributes->setStencil(false);
2219     return attributes.release();
2220 }
2221
2222 GC3Denum WebGLRenderingContextBase::getError()
2223 {
2224     if (m_isPendingPolicyResolution)
2225         return GraphicsContext3D::NO_ERROR;
2226     return m_context->getError();
2227 }
2228
2229 WebGLGetInfo WebGLRenderingContextBase::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode&)
2230 {
2231     if (isContextLostOrPending() || !validateWebGLObject("getProgramParameter", program))
2232         return WebGLGetInfo();
2233
2234     GC3Dint value = 0;
2235     switch (pname) {
2236     case GraphicsContext3D::DELETE_STATUS:
2237         return WebGLGetInfo(program->isDeleted());
2238     case GraphicsContext3D::VALIDATE_STATUS:
2239         m_context->getProgramiv(objectOrZero(program), pname, &value);
2240         return WebGLGetInfo(static_cast<bool>(value));
2241     case GraphicsContext3D::LINK_STATUS:
2242         return WebGLGetInfo(program->getLinkStatus());
2243     case GraphicsContext3D::ATTACHED_SHADERS:
2244         m_context->getProgramiv(objectOrZero(program), pname, &value);
2245         return WebGLGetInfo(value);
2246     case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2247     case GraphicsContext3D::ACTIVE_UNIFORMS:
2248         m_context->getNonBuiltInActiveSymbolCount(objectOrZero(program), pname, &value);
2249         return WebGLGetInfo(value);
2250     default:
2251         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2252         return WebGLGetInfo();
2253     }
2254 }
2255
2256 String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program, ExceptionCode&)
2257 {
2258     if (isContextLostOrPending() || !validateWebGLObject("getProgramInfoLog", program))
2259         return String();
2260     return ensureNotNull(m_context->getProgramInfoLog(objectOrZero(program)));
2261 }
2262
2263 WebGLGetInfo WebGLRenderingContextBase::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode&)
2264 {
2265     if (isContextLostOrPending())
2266         return WebGLGetInfo();
2267     if (target != GraphicsContext3D::RENDERBUFFER) {
2268         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2269         return WebGLGetInfo();
2270     }
2271     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2272         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2273         return WebGLGetInfo();
2274     }
2275
2276     if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2277         && !m_renderbufferBinding->isValid()) {
2278         ASSERT(!isDepthStencilSupported());
2279         int value = 0;
2280         switch (pname) {
2281         case GraphicsContext3D::RENDERBUFFER_WIDTH:
2282             value = m_renderbufferBinding->getWidth();
2283             break;
2284         case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2285             value = m_renderbufferBinding->getHeight();
2286             break;
2287         case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2288         case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2289         case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2290         case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2291             value = 0;
2292             break;
2293         case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2294             value = 24;
2295             break;
2296         case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2297             value = 8;
2298             break;
2299         case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2300             return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2301         default:
2302             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2303             return WebGLGetInfo();
2304         }
2305         return WebGLGetInfo(value);
2306     }
2307
2308     GC3Dint value = 0;
2309     switch (pname) {
2310     case GraphicsContext3D::RENDERBUFFER_WIDTH:
2311     case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2312     case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2313     case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2314     case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2315     case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2316     case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2317     case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2318         m_context->getRenderbufferParameteriv(target, pname, &value);
2319         return WebGLGetInfo(value);
2320     case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2321         return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2322     default:
2323         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2324         return WebGLGetInfo();
2325     }
2326 }
2327
2328 WebGLGetInfo WebGLRenderingContextBase::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode&)
2329 {
2330     if (isContextLostOrPending() || !validateWebGLObject("getShaderParameter", shader))
2331         return WebGLGetInfo();
2332     GC3Dint value = 0;
2333     switch (pname) {
2334     case GraphicsContext3D::DELETE_STATUS:
2335         return WebGLGetInfo(shader->isDeleted());
2336     case GraphicsContext3D::COMPILE_STATUS:
2337         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2338         return WebGLGetInfo(static_cast<bool>(value));
2339     case GraphicsContext3D::SHADER_TYPE:
2340         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2341         return WebGLGetInfo(static_cast<unsigned int>(value));
2342     default:
2343         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderParameter", "invalid parameter name");
2344         return WebGLGetInfo();
2345     }
2346 }
2347
2348 String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader, ExceptionCode&)
2349 {
2350     if (isContextLostOrPending() || !validateWebGLObject("getShaderInfoLog", shader))
2351         return String();
2352     return ensureNotNull(m_context->getShaderInfoLog(objectOrZero(shader)));
2353 }
2354
2355 PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContextBase::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode&)
2356 {
2357     if (isContextLostOrPending())
2358         return nullptr;
2359     switch (shaderType) {
2360     case GraphicsContext3D::VERTEX_SHADER:
2361     case GraphicsContext3D::FRAGMENT_SHADER:
2362         break;
2363     default:
2364         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
2365         return nullptr;
2366     }
2367     switch (precisionType) {
2368     case GraphicsContext3D::LOW_FLOAT:
2369     case GraphicsContext3D::MEDIUM_FLOAT:
2370     case GraphicsContext3D::HIGH_FLOAT:
2371     case GraphicsContext3D::LOW_INT:
2372     case GraphicsContext3D::MEDIUM_INT:
2373     case GraphicsContext3D::HIGH_INT:
2374         break;
2375     default:
2376         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
2377         return nullptr;
2378     }
2379
2380     GC3Dint range[2] = {0, 0};
2381     GC3Dint precision = 0;
2382     m_context->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
2383     return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
2384 }
2385
2386 String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader, ExceptionCode&)
2387 {
2388     if (isContextLostOrPending() || !validateWebGLObject("getShaderSource", shader))
2389         return String();
2390     return ensureNotNull(shader->getSource());
2391 }
2392
2393 WebGLGetInfo WebGLRenderingContextBase::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode&)
2394 {
2395     if (isContextLostOrPending())
2396         return WebGLGetInfo();
2397     WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
2398     if (!tex)
2399         return WebGLGetInfo();
2400     GC3Dint value = 0;
2401     switch (pname) {
2402     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2403     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2404     case GraphicsContext3D::TEXTURE_WRAP_S:
2405     case GraphicsContext3D::TEXTURE_WRAP_T:
2406         m_context->getTexParameteriv(target, pname, &value);
2407         return WebGLGetInfo(static_cast<unsigned int>(value));
2408     case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2409         if (m_extTextureFilterAnisotropic) {
2410             m_context->getTexParameteriv(target, pname, &value);
2411             return WebGLGetInfo(static_cast<unsigned int>(value));
2412         }
2413         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2414         return WebGLGetInfo();
2415     default:
2416         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name");
2417         return WebGLGetInfo();
2418     }
2419 }
2420
2421 WebGLGetInfo WebGLRenderingContextBase::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode&)
2422 {
2423     if (isContextLostOrPending() || !validateWebGLObject("getUniform", program))
2424         return WebGLGetInfo();
2425     if (!uniformLocation || uniformLocation->program() != program) {
2426         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
2427         return WebGLGetInfo();
2428     }
2429     GC3Dint location = uniformLocation->location();
2430
2431     GC3Denum baseType;
2432     unsigned length;
2433     switch (uniformLocation->type()) {
2434     case GraphicsContext3D::BOOL:
2435         baseType = GraphicsContext3D::BOOL;
2436         length = 1;
2437         break;
2438     case GraphicsContext3D::BOOL_VEC2:
2439         baseType = GraphicsContext3D::BOOL;
2440         length = 2;
2441         break;
2442     case GraphicsContext3D::BOOL_VEC3:
2443         baseType = GraphicsContext3D::BOOL;
2444         length = 3;
2445         break;
2446     case GraphicsContext3D::BOOL_VEC4:
2447         baseType = GraphicsContext3D::BOOL;
2448         length = 4;
2449         break;
2450     case GraphicsContext3D::INT:
2451         baseType = GraphicsContext3D::INT;
2452         length = 1;
2453         break;
2454     case GraphicsContext3D::INT_VEC2:
2455         baseType = GraphicsContext3D::INT;
2456         length = 2;
2457         break;
2458     case GraphicsContext3D::INT_VEC3:
2459         baseType = GraphicsContext3D::INT;
2460         length = 3;
2461         break;
2462     case GraphicsContext3D::INT_VEC4:
2463         baseType = GraphicsContext3D::INT;
2464         length = 4;
2465         break;
2466     case GraphicsContext3D::FLOAT:
2467         baseType = GraphicsContext3D::FLOAT;
2468         length = 1;
2469         break;
2470     case GraphicsContext3D::FLOAT_VEC2:
2471         baseType = GraphicsContext3D::FLOAT;
2472         length = 2;
2473         break;
2474     case GraphicsContext3D::FLOAT_VEC3:
2475         baseType = GraphicsContext3D::FLOAT;
2476         length = 3;
2477         break;
2478     case GraphicsContext3D::FLOAT_VEC4:
2479         baseType = GraphicsContext3D::FLOAT;
2480         length = 4;
2481         break;
2482     case GraphicsContext3D::FLOAT_MAT2:
2483         baseType = GraphicsContext3D::FLOAT;
2484         length = 4;
2485         break;
2486     case GraphicsContext3D::FLOAT_MAT3:
2487         baseType = GraphicsContext3D::FLOAT;
2488         length = 9;
2489         break;
2490     case GraphicsContext3D::FLOAT_MAT4:
2491         baseType = GraphicsContext3D::FLOAT;
2492         length = 16;
2493         break;
2494     case GraphicsContext3D::SAMPLER_2D:
2495     case GraphicsContext3D::SAMPLER_CUBE:
2496         baseType = GraphicsContext3D::INT;
2497         length = 1;
2498         break;
2499     default:
2500         // Can't handle this type
2501         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unhandled type");
2502         return WebGLGetInfo();
2503     }
2504     switch (baseType) {
2505     case GraphicsContext3D::FLOAT: {
2506         GC3Dfloat value[16] = {0};
2507         if (m_isRobustnessEXTSupported)
2508             m_context->getExtensions()->getnUniformfvEXT(objectOrZero(program), location, 16 * sizeof(GC3Dfloat), value);
2509         else
2510             m_context->getUniformfv(objectOrZero(program), location, value);
2511         if (length == 1)
2512             return WebGLGetInfo(value[0]);
2513         return WebGLGetInfo(Float32Array::create(value, length).release());
2514     }
2515     case GraphicsContext3D::INT: {
2516         GC3Dint value[4] = {0};
2517         if (m_isRobustnessEXTSupported)
2518             m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
2519         else
2520             m_context->getUniformiv(objectOrZero(program), location, value);
2521         if (length == 1)
2522             return WebGLGetInfo(value[0]);
2523         return WebGLGetInfo(Int32Array::create(value, length).release());
2524     }
2525     case GraphicsContext3D::BOOL: {
2526         GC3Dint value[4] = {0};
2527         if (m_isRobustnessEXTSupported)
2528             m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
2529         else
2530             m_context->getUniformiv(objectOrZero(program), location, value);
2531         if (length > 1) {
2532             bool boolValue[16] = {0};
2533             for (unsigned j = 0; j < length; j++)
2534                 boolValue[j] = static_cast<bool>(value[j]);
2535             return WebGLGetInfo(boolValue, length);
2536         }
2537         return WebGLGetInfo(static_cast<bool>(value[0]));
2538     }
2539     default:
2540         notImplemented();
2541     }
2542
2543     // If we get here, something went wrong in our unfortunately complex logic above
2544     synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unknown error");
2545     return WebGLGetInfo();
2546 }
2547
2548 PassRefPtr<WebGLUniformLocation> WebGLRenderingContextBase::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode&)
2549 {
2550     if (isContextLostOrPending() || !validateWebGLObject("getUniformLocation", program))
2551         return nullptr;
2552     if (!validateLocationLength("getUniformLocation", name))
2553         return nullptr;
2554     if (!validateString("getUniformLocation", name))
2555         return nullptr;
2556     if (isPrefixReserved(name))
2557         return nullptr;
2558     if (!program->getLinkStatus()) {
2559         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniformLocation", "program not linked");
2560         return nullptr;
2561     }
2562     GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2563     if (uniformLocation == -1)
2564         return nullptr;
2565
2566     GC3Dint activeUniforms = 0;
2567     m_context->getNonBuiltInActiveSymbolCount(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2568     for (GC3Dint i = 0; i < activeUniforms; i++) {
2569         ActiveInfo info;
2570         if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2571             return nullptr;
2572         // Strip "[0]" from the name if it's an array.
2573         if (info.name.endsWith("[0]"))
2574             info.name = info.name.left(info.name.length() - 3);
2575         // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2576         for (GC3Dint index = 0; index < info.size; ++index) {
2577             String uniformName = info.name + "[" + String::number(index) + "]";
2578
2579             if (name == uniformName || name == info.name)
2580                 return WebGLUniformLocation::create(program, uniformLocation, info.type);
2581         }
2582     }
2583     return nullptr;
2584 }
2585
2586 WebGLGetInfo WebGLRenderingContextBase::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode&)
2587 {
2588     if (isContextLostOrPending())
2589         return WebGLGetInfo();
2590
2591     if (index >= m_maxVertexAttribs) {
2592         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
2593         return WebGLGetInfo();
2594     }
2595
2596     const WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2597
2598     if ((isWebGL2() || m_angleInstancedArrays) && pname == GraphicsContext3D::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)
2599         return WebGLGetInfo(state.divisor);
2600
2601     switch (pname) {
2602     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2603         if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
2604             || !state.bufferBinding
2605             || !state.bufferBinding->object())
2606             return WebGLGetInfo();
2607         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
2608     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
2609         return WebGLGetInfo(state.enabled);
2610     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
2611         return WebGLGetInfo(state.normalized);
2612     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
2613         return WebGLGetInfo(state.size);
2614     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
2615         return WebGLGetInfo(state.originalStride);
2616     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
2617         return WebGLGetInfo(state.type);
2618     case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
2619         return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4).release());
2620     default:
2621         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
2622         return WebGLGetInfo();
2623     }
2624 }
2625
2626 long long WebGLRenderingContextBase::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
2627 {
2628     if (isContextLostOrPending())
2629         return 0;
2630     GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
2631     return static_cast<long long>(result);
2632 }
2633
2634 GC3Dboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer)
2635 {
2636     if (!buffer || isContextLostOrPending())
2637         return 0;
2638
2639     if (!buffer->hasEverBeenBound())
2640         return 0;
2641
2642     return m_context->isBuffer(buffer->object());
2643 }
2644
2645 bool WebGLRenderingContextBase::isContextLost() const
2646 {
2647     return m_contextLost;
2648 }
2649
2650 bool WebGLRenderingContextBase::isContextLostOrPending()
2651 {
2652     if (m_isPendingPolicyResolution && !m_hasRequestedPolicyResolution) {
2653         LOG(WebGL, "Context is being used. Attempt to resolve the policy.");
2654         Document& document = canvas()->document().topDocument();
2655         Page* page = document.page();
2656         if (page && !document.url().isLocalFile())
2657             page->mainFrame().loader().client().resolveWebGLPolicyForURL(document.url());
2658         // FIXME: We don't currently do anything with the result from resolution. A more
2659         // complete implementation might try to construct a real context, etc and proceed
2660         // with normal operation.
2661         // https://bugs.webkit.org/show_bug.cgi?id=129122
2662         m_hasRequestedPolicyResolution = true;
2663     }
2664
2665     return m_contextLost || m_isPendingPolicyResolution;
2666 }
2667
2668 GC3Dboolean WebGLRenderingContextBase::isEnabled(GC3Denum cap)
2669 {
2670     if (isContextLostOrPending() || !validateCapability("isEnabled", cap))
2671         return 0;
2672     if (cap == GraphicsContext3D::STENCIL_TEST)
2673         return m_stencilEnabled;
2674     return m_context->isEnabled(cap);
2675 }
2676
2677 GC3Dboolean WebGLRenderingContextBase::isFramebuffer(WebGLFramebuffer* framebuffer)
2678 {
2679     if (!framebuffer || isContextLostOrPending())
2680         return 0;
2681
2682     if (!framebuffer->hasEverBeenBound())
2683         return 0;
2684
2685     return m_context->isFramebuffer(framebuffer->object());
2686 }
2687
2688 GC3Dboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program)
2689 {
2690     if (!program || isContextLostOrPending())
2691         return 0;
2692
2693     return m_context->isProgram(program->object());
2694 }
2695
2696 GC3Dboolean WebGLRenderingContextBase::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2697 {
2698     if (!renderbuffer || isContextLostOrPending())
2699         return 0;
2700
2701     if (!renderbuffer->hasEverBeenBound())
2702         return 0;
2703
2704     return m_context->isRenderbuffer(renderbuffer->object());
2705 }
2706
2707 GC3Dboolean WebGLRenderingContextBase::isShader(WebGLShader* shader)
2708 {
2709     if (!shader || isContextLostOrPending())
2710         return 0;
2711
2712     return m_context->isShader(shader->object());
2713 }
2714
2715 GC3Dboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture)
2716 {
2717     if (!texture || isContextLostOrPending())
2718         return 0;
2719
2720     if (!texture->hasEverBeenBound())
2721         return 0;
2722
2723     return m_context->isTexture(texture->object());
2724 }
2725
2726 void WebGLRenderingContextBase::lineWidth(GC3Dfloat width)
2727 {
2728     if (isContextLostOrPending())
2729         return;
2730     m_context->lineWidth(width);
2731 }
2732
2733 void WebGLRenderingContextBase::linkProgram(WebGLProgram* program, ExceptionCode&)
2734 {
2735     if (isContextLostOrPending() || !validateWebGLObject("linkProgram", program))
2736         return;
2737     WebGLShader* vertexShader = program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER);
2738     WebGLShader* fragmentShader = program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER);
2739     if (!vertexShader || !vertexShader->isValid() || !fragmentShader || !fragmentShader->isValid() || !m_context->precisionsMatch(objectOrZero(vertexShader), objectOrZero(fragmentShader)) || !m_context->checkVaryingsPacking(objectOrZero(vertexShader), objectOrZero(fragmentShader))) {
2740         program->setLinkStatus(false);
2741         return;
2742     }
2743
2744     m_context->linkProgram(objectOrZero(program));
2745     program->increaseLinkCount();
2746 }
2747
2748 void WebGLRenderingContextBase::pixelStorei(GC3Denum pname, GC3Dint param)
2749 {
2750     if (isContextLostOrPending())
2751         return;
2752     switch (pname) {
2753     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2754         m_unpackFlipY = param;
2755         break;
2756     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2757         m_unpackPremultiplyAlpha = param;
2758         break;
2759     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2760         if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
2761             m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
2762         else {
2763             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
2764             return;
2765         }
2766         break;
2767     case GraphicsContext3D::PACK_ALIGNMENT:
2768     case GraphicsContext3D::UNPACK_ALIGNMENT:
2769         if (param == 1 || param == 2 || param == 4 || param == 8) {
2770             if (pname == GraphicsContext3D::PACK_ALIGNMENT)
2771                 m_packAlignment = param;
2772             else // GraphicsContext3D::UNPACK_ALIGNMENT:
2773                 m_unpackAlignment = param;
2774             m_context->pixelStorei(pname, param);
2775         } else {
2776             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
2777             return;
2778         }
2779         break;
2780     default:
2781         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "pixelStorei", "invalid parameter name");
2782         return;
2783     }
2784 }
2785
2786 void WebGLRenderingContextBase::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
2787 {
2788     if (isContextLostOrPending())
2789         return;
2790     m_context->polygonOffset(factor, units);
2791 }
2792
2793 void WebGLRenderingContextBase::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView& pixels, ExceptionCode&)
2794 {
2795     if (isContextLostOrPending())
2796         return;
2797     // Due to WebGL's same-origin restrictions, it is not possible to
2798     // taint the origin using the WebGL API.
2799     ASSERT(canvas()->originClean());
2800     // Validate input parameters.
2801     switch (format) {
2802     case GraphicsContext3D::ALPHA:
2803     case GraphicsContext3D::RGB:
2804     case GraphicsContext3D::RGBA:
2805         break;
2806     default:
2807         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid format");
2808         return;
2809     }
2810     switch (type) {
2811     case GraphicsContext3D::UNSIGNED_BYTE:
2812     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
2813     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
2814     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
2815         break;
2816     default:
2817         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid type");
2818         return;
2819     }
2820     if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
2821         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "format not RGBA or type not UNSIGNED_BYTE");
2822         return;
2823     }
2824     // Validate array type against pixel type.
2825     if (pixels.getType() != JSC::TypeUint8) {
2826         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not Uint8Array");
2827         return;
2828     }
2829     const char* reason = "framebuffer incomplete";
2830     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
2831         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
2832         return;
2833     }
2834     // Calculate array size, taking into consideration of PACK_ALIGNMENT.
2835     unsigned int totalBytesRequired = 0;
2836     unsigned int padding = 0;
2837     if (!m_isRobustnessEXTSupported) {
2838         GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
2839         if (error != GraphicsContext3D::NO_ERROR) {
2840             synthesizeGLError(error, "readPixels", "invalid dimensions");
2841             return;
2842         }
2843         if (pixels.byteLength() < totalBytesRequired) {
2844             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
2845             return;
2846         }
2847     }
2848
2849     clearIfComposited();
2850     void* data = pixels.baseAddress();
2851
2852     {
2853         if (m_isRobustnessEXTSupported)
2854             m_context->getExtensions()->readnPixelsEXT(x, y, width, height, format, type, pixels.byteLength(), data);
2855         else
2856             m_context->readPixels(x, y, width, height, format, type, data);
2857     }
2858
2859 #if OS(DARWIN)
2860     if (m_isRobustnessEXTSupported) // we haven't computed padding
2861         m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
2862     // FIXME: remove this section when GL driver bug on Mac AND the GLES driver bug
2863     // on QC is fixed, i.e., when alpha is off, readPixels should
2864     // set alpha to 255 instead of 0.
2865     if (!m_framebufferBinding && !m_context->getContextAttributes().alpha) {
2866         unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
2867         for (GC3Dsizei iy = 0; iy < height; ++iy) {
2868             for (GC3Dsizei ix = 0; ix < width; ++ix) {
2869                 pixels[3] = 255;
2870                 pixels += 4;
2871             }
2872             pixels += padding;
2873         }
2874     }
2875 #endif
2876 }
2877
2878 void WebGLRenderingContextBase::releaseShaderCompiler()
2879 {
2880     if (isContextLostOrPending())
2881         return;
2882     m_context->releaseShaderCompiler();
2883 }
2884
2885 void WebGLRenderingContextBase::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
2886 {
2887     if (isContextLostOrPending())
2888         return;
2889     m_context->sampleCoverage(value, invert);
2890 }
2891
2892 void WebGLRenderingContextBase::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
2893 {
2894     if (isContextLostOrPending())
2895         return;
2896     if (!validateSize("scissor", width, height))
2897         return;
2898     m_context->scissor(x, y, width, height);
2899 }
2900
2901 void WebGLRenderingContextBase::shaderSource(WebGLShader* shader, const String& string, ExceptionCode&)
2902 {
2903     if (isContextLostOrPending() || !validateWebGLObject("shaderSource", shader))
2904         return;
2905     String stringWithoutComments = StripComments(string).result();
2906     if (!validateString("shaderSource", stringWithoutComments))
2907         return;
2908     shader->setSource(string);
2909     m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
2910 }
2911
2912 void WebGLRenderingContextBase::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
2913 {
2914     if (isContextLostOrPending())
2915         return;
2916     if (!validateStencilFunc("stencilFunc", func))
2917         return;
2918     m_stencilFuncRef = ref;
2919     m_stencilFuncRefBack = ref;
2920     m_stencilFuncMask = mask;
2921     m_stencilFuncMaskBack = mask;
2922     m_context->stencilFunc(func, ref, mask);
2923 }
2924
2925 void WebGLRenderingContextBase::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
2926 {
2927     if (isContextLostOrPending())
2928         return;
2929     if (!validateStencilFunc("stencilFuncSeparate", func))
2930         return;
2931     switch (face) {
2932     case GraphicsContext3D::FRONT_AND_BACK:
2933         m_stencilFuncRef = ref;
2934         m_stencilFuncRefBack = ref;
2935         m_stencilFuncMask = mask;
2936         m_stencilFuncMaskBack = mask;
2937         break;
2938     case GraphicsContext3D::FRONT:
2939         m_stencilFuncRef = ref;
2940         m_stencilFuncMask = mask;
2941         break;
2942     case GraphicsContext3D::BACK:
2943         m_stencilFuncRefBack = ref;
2944         m_stencilFuncMaskBack = mask;
2945         break;
2946     default:
2947         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilFuncSeparate", "invalid face");
2948         return;
2949     }
2950     m_context->stencilFuncSeparate(face, func, ref, mask);
2951 }
2952
2953 void WebGLRenderingContextBase::stencilMask(GC3Duint mask)
2954 {
2955     if (isContextLostOrPending())
2956         return;
2957     m_stencilMask = mask;
2958     m_stencilMaskBack = mask;
2959     m_context->stencilMask(mask);
2960 }
2961
2962 void WebGLRenderingContextBase::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
2963 {
2964     if (isContextLostOrPending())
2965         return;
2966     switch (face) {
2967     case GraphicsContext3D::FRONT_AND_BACK:
2968         m_stencilMask = mask;
2969         m_stencilMaskBack = mask;
2970         break;
2971     case GraphicsContext3D::FRONT:
2972         m_stencilMask = mask;
2973         break;
2974     case GraphicsContext3D::BACK:
2975         m_stencilMaskBack = mask;
2976         break;
2977     default:
2978         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilMaskSeparate", "invalid face");
2979         return;
2980     }
2981     m_context->stencilMaskSeparate(face, mask);
2982 }
2983
2984 void WebGLRenderingContextBase::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
2985 {
2986     if (isContextLostOrPending())
2987         return;
2988     m_context->stencilOp(fail, zfail, zpass);
2989 }
2990
2991 void WebGLRenderingContextBase::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
2992 {
2993     if (isContextLostOrPending())
2994         return;
2995     m_context->stencilOpSeparate(face, fail, zfail, zpass);
2996 }
2997
2998 void WebGLRenderingContextBase::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode& ec)
2999 {
3000     // FIXME: For now we ignore any errors returned.
3001     ec = 0;
3002     WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
3003     ASSERT(validateTexFuncParameters("texImage2D", TexImage, target, level, internalformat, width, height, border, format, type));
3004     ASSERT(tex);
3005     ASSERT(validateNPOTTextureLevel(width, height, level, "texImage2D"));
3006     if (!pixels) {
3007         // Note: Chromium's OpenGL implementation clears textures and isResourceSafe() is therefore true.
3008         // For other implementations, if they are using ANGLE_depth_texture, ANGLE depth textures
3009         // can not be cleared with texImage2D and must be cleared by binding to an fbo and calling
3010         // clear.
3011         if (isResourceSafe())
3012             m_context->texImage2D(target, level, internalformat, width, height, border, format, type, nullptr);
3013         else {
3014             bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
3015                                                              border, format, type, m_unpackAlignment);
3016             if (!succeed)
3017                 return;
3018         }
3019     } else {
3020         ASSERT(validateSettableTexFormat("texImage2D", internalformat));
3021         m_context->moveErrorsToSyntheticErrorList();
3022         m_context->texImage2D(target, level, internalformat, width, height,
3023                               border, format, type, pixels);
3024         if (m_context->moveErrorsToSyntheticErrorList()) {
3025             // The texImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
3026             tex->markInvalid(target, level);
3027             return;
3028         }
3029     }
3030     tex->setLevelInfo(target, level, internalformat, width, height, type);
3031 }
3032
3033 void WebGLRenderingContextBase::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3034 {
3035     ec = 0;
3036     Vector<uint8_t> data;
3037     GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);
3038     if (!imageExtractor.extractSucceeded()) {
3039         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3040         return;
3041     }
3042     GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
3043     GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
3044     const void* imagePixelData = imageExtractor.imagePixelData();
3045
3046     bool needConversion = true;
3047     if (type == GraphicsContext3D::UNSIGNED_BYTE && sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 && format == GraphicsContext3D::RGBA && alphaOp == GraphicsContext3D::AlphaDoNothing && !flipY)
3048         needConversion = false;
3049     else {
3050         if (!m_context->packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
3051             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "packImage error");
3052             return;
3053         }
3054     }
3055
3056     if (m_unpackAlignment != 1)
3057         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3058     texImage2DBase(target, level, internalformat, image->width(), image->height(), 0, format, type, needConversion ? data.data() : imagePixelData, ec);
3059     if (m_unpackAlignment != 1)
3060         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3061 }
3062
3063 bool WebGLRenderingContextBase::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)
3064 {
3065     if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, border, format, type))
3066         return false;
3067
3068     WebGLTexture* texture = validateTextureBinding(functionName, target, true);
3069     if (!texture)
3070         return false;
3071
3072     if (functionType != TexSubImage) {
3073         if (!validateNPOTTextureLevel(width, height, level, functionName))
3074             return false;
3075         // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat
3076         // by checking if the ArrayBufferView is null or not.
3077         if (sourceType != SourceArrayBufferView) {
3078             if (!validateSettableTexFormat(functionName, format))
3079                 return false;
3080         }
3081     } else {
3082         if (!validateSettableTexFormat(functionName, format))
3083             return false;
3084         if (!validateSize(functionName, xoffset, yoffset))
3085             return false;
3086         // Before checking if it is in the range, check if overflow happens first.
3087         if (xoffset + width < 0 || yoffset + height < 0) {
3088             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "bad dimensions");
3089             return false;
3090         }
3091         if (xoffset + width > texture->getWidth(target, level) || yoffset + height > texture->getHeight(target, level)) {
3092             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "dimensions out of range");
3093             return false;
3094         }
3095         if (texture->getInternalFormat(target, level) != format || texture->getType(target, level) != type) {
3096             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type and format do not match texture");
3097             return false;
3098         }
3099     }
3100
3101     return true;
3102 }
3103
3104 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, RefPtr<ArrayBufferView>&& pixels, ExceptionCode& ec)
3105 {
3106     if (isContextLostOrPending() || !validateTexFuncData("texImage2D", level, width, height, internalformat, format, type, pixels.get(), NullAllowed)
3107         || !validateTexFunc("texImage2D", TexImage, SourceArrayBufferView, target, level, internalformat, width, height, border, format, type, 0, 0))
3108         return;
3109     void* data = pixels ? pixels->baseAddress() : 0;
3110     Vector<uint8_t> tempData;
3111     bool changeUnpackAlignment = false;
3112     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3113         if (!m_context->extractTextureData(width, height, format, type,
3114                                            m_unpackAlignment,
3115                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3116                                            data,
3117                                            tempData))
3118             return;
3119         data = tempData.data();
3120         changeUnpackAlignment = true;
3121     }
3122     if (changeUnpackAlignment)
3123         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3124     texImage2DBase(target, level, internalformat, width, height, border,
3125                    format, type, data, ec);
3126     if (changeUnpackAlignment)
3127         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3128 }
3129
3130 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3131                                        GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3132 {
3133     ec = 0;
3134     if (isContextLostOrPending() || !pixels || !validateTexFunc("texImage2D", TexImage, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, 0, 0))
3135         return;
3136     Vector<uint8_t> data;
3137     bool needConversion = true;
3138     // The data from ImageData is always of format RGBA8.
3139     // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3140     if (!m_unpackFlipY && !m_unpackPremultiplyAlpha && format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE)
3141         needConversion = false;
3142     else {
3143         if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3144             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3145             return;
3146         }
3147     }
3148     if (m_unpackAlignment != 1)
3149         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3150     texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, needConversion ? data.data() : pixels->data()->data(), ec);
3151     if (m_unpackAlignment != 1)
3152         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3153 }
3154
3155 PassRefPtr<Image> WebGLRenderingContextBase::drawImageIntoBuffer(Image& image, int width, int height, int deviceScaleFactor)
3156 {
3157     IntSize size(width, height);
3158     size.scale(deviceScaleFactor);
3159     ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
3160     if (!buf) {
3161         synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "texImage2D", "out of memory");
3162         return nullptr;
3163     }
3164
3165     FloatRect srcRect(FloatPoint(), image.size());
3166     FloatRect destRect(FloatPoint(), size);
3167     buf->context().drawImage(image, destRect, srcRect);
3168     return buf->copyImage(ImageBuffer::fastCopyImageMode());
3169 }
3170
3171 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3172                                        GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3173 {
3174     ec = 0;
3175     if (isContextLostOrPending() || !validateHTMLImageElement("texImage2D", image, ec))
3176         return;
3177
3178     RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
3179     if (!imageForRender)
3180         return;
3181
3182     if (imageForRender->isSVGImage())
3183         imageForRender = drawImageIntoBuffer(*imageForRender, image->width(), image->height(), 1);
3184
3185     if (!imageForRender || !validateTexFunc("texImage2D", TexImage, SourceHTMLImageElement, target, level, internalformat, imageForRender->width(), imageForRender->height(), 0, format, type, 0, 0))
3186         return;
3187
3188     texImage2DImpl(target, level, internalformat, format, type, imageForRender.get(), GraphicsContext3D::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3189 }
3190
3191 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3192                                        GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3193 {
3194     ec = 0;
3195     if (isContextLostOrPending() || !validateHTMLCanvasElement("texImage2D", canvas, ec) || !validateTexFunc("texImage2D", TexImage, SourceHTMLCanvasElement, target, level, internalformat, canvas->width(), canvas->height(), 0, format, type, 0, 0))
3196         return;
3197
3198     WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
3199     // If possible, copy from the canvas element directly to the texture
3200     // via the GPU, without a read-back to system memory.
3201     //
3202     // FIXME: restriction of (RGB || RGBA)/UNSIGNED_BYTE should be lifted when
3203     // ImageBuffer::copyToPlatformTexture implementations are fully functional.
3204     if (texture
3205         && (format == GraphicsContext3D::RGB || format == GraphicsContext3D::RGBA)
3206         && type == GraphicsContext3D::UNSIGNED_BYTE
3207         && (texture->getType(target, level) == GraphicsContext3D::UNSIGNED_BYTE || !texture->isValid(target, level))) {
3208         ImageBuffer* buffer = canvas->buffer();
3209         if (buffer && buffer->copyToPlatformTexture(*m_context.get(), target, texture->object(), internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3210             texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type);
3211             return;
3212         }
3213     }
3214
3215     RefPtr<ImageData> imageData = canvas->getImageData();
3216     if (imageData)
3217         texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
3218     else
3219         texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(), GraphicsContext3D::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3220 }
3221
3222 #if ENABLE(VIDEO)
3223 PassRefPtr<Image> WebGLRenderingContextBase::videoFrameToImage(HTMLVideoElement* video, BackingStoreCopy backingStoreCopy, ExceptionCode&)
3224 {
3225     IntSize size(video->videoWidth(), video->videoHeight());
3226     ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
3227     if (!buf) {