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