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