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