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