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