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 
28 #if ENABLE(WEBGL)
29 
30 #include "WebGLRenderingContext.h"
31 
32 #include "CachedImage.h"
33 #include "CanvasPixelArray.h"
34 #include "CheckedInt.h"
35 #include "WebKitLoseContext.h"
36 #include "Console.h"
37 #include "DOMWindow.h"
38 #include "Extensions3D.h"
39 #include "FrameView.h"
40 #include "HTMLCanvasElement.h"
41 #include "HTMLImageElement.h"
42 #include "HTMLVideoElement.h"
43 #include "ImageBuffer.h"
44 #include "ImageData.h"
45 #include "IntSize.h"
46 #include "NotImplemented.h"
47 #include "OESStandardDerivatives.h"
48 #include "OESTextureFloat.h"
49 #include "OESVertexArrayObject.h"
50 #include "RenderBox.h"
51 #include "RenderLayer.h"
52 #include "Settings.h"
53 #include "Uint16Array.h"
54 #include "WebGLActiveInfo.h"
55 #include "WebGLBuffer.h"
56 #include "WebGLContextAttributes.h"
57 #include "WebGLContextEvent.h"
58 #include "WebGLFramebuffer.h"
59 #include "WebGLProgram.h"
60 #include "WebGLRenderbuffer.h"
61 #include "WebGLShader.h"
62 #include "WebGLTexture.h"
63 #include "WebGLUniformLocation.h"
64 
65 #include <wtf/ByteArray.h>
66 #include <wtf/OwnArrayPtr.h>
67 #include <wtf/PassOwnArrayPtr.h>
68 #include <wtf/text/StringBuilder.h>
69 
70 #if PLATFORM(QT)
71 #undef emit
72 #endif
73 
74 namespace WebCore {
75 
76 const double secondsBetweenRestoreAttempts = 1.0;
77 
78 namespace {
79 
objectOrZero(WebGLObject * object)80     Platform3DObject objectOrZero(WebGLObject* object)
81     {
82         return object ? object->object() : 0;
83     }
84 
clip1D(GC3Dint start,GC3Dsizei range,GC3Dsizei sourceRange,GC3Dint * clippedStart,GC3Dsizei * clippedRange)85     void clip1D(GC3Dint start, GC3Dsizei range, GC3Dsizei sourceRange, GC3Dint* clippedStart, GC3Dsizei* clippedRange)
86     {
87         ASSERT(clippedStart && clippedRange);
88         if (start < 0) {
89             range += start;
90             start = 0;
91         }
92         GC3Dint end = start + range;
93         if (end > sourceRange)
94             range -= end - sourceRange;
95         *clippedStart = start;
96         *clippedRange = range;
97     }
98 
99     // Returns false if no clipping is necessary, i.e., x, y, width, height stay the same.
clip2D(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height,GC3Dsizei sourceWidth,GC3Dsizei sourceHeight,GC3Dint * clippedX,GC3Dint * clippedY,GC3Dsizei * clippedWidth,GC3Dsizei * clippedHeight)100     bool clip2D(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height,
101                 GC3Dsizei sourceWidth, GC3Dsizei sourceHeight,
102                 GC3Dint* clippedX, GC3Dint* clippedY, GC3Dsizei* clippedWidth, GC3Dsizei*clippedHeight)
103     {
104         ASSERT(clippedX && clippedY && clippedWidth && clippedHeight);
105         clip1D(x, width, sourceWidth, clippedX, clippedWidth);
106         clip1D(y, height, sourceHeight, clippedY, clippedHeight);
107         return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height);
108     }
109 
110     // Return true if a character belongs to the ASCII subset as defined in
111     // GLSL ES 1.0 spec section 3.1.
validateCharacter(unsigned char c)112     bool validateCharacter(unsigned char c)
113     {
114         // Printing characters are valid except " $ ` @ \ ' DEL.
115         if (c >= 32 && c <= 126
116             && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
117             return true;
118         // Horizontal tab, line feed, vertical tab, form feed, carriage return
119         // are also valid.
120         if (c >= 9 && c <= 13)
121             return true;
122         return false;
123     }
124 
125     // Strips comments from shader text. This allows non-ASCII characters
126     // to be used in comments without potentially breaking OpenGL
127     // implementations not expecting characters outside the GLSL ES set.
128     class StripComments {
129     public:
StripComments(const String & str)130         StripComments(const String& str)
131             : m_parseState(BeginningOfLine)
132             , m_sourceString(str)
133             , m_length(str.length())
134             , m_position(0)
135         {
136             parse();
137         }
138 
result()139         String result()
140         {
141             return m_builder.toString();
142         }
143 
144     private:
hasMoreCharacters()145         bool hasMoreCharacters()
146         {
147             return (m_position < m_length);
148         }
149 
parse()150         void parse()
151         {
152             while (hasMoreCharacters()) {
153                 process(current());
154                 // process() might advance the position.
155                 if (hasMoreCharacters())
156                     advance();
157             }
158         }
159 
160         void process(UChar);
161 
peek(UChar & character)162         bool peek(UChar& character)
163         {
164             if (m_position + 1 >= m_length)
165                 return false;
166             character = m_sourceString[m_position + 1];
167             return true;
168         }
169 
current()170         UChar current()
171         {
172             ASSERT(m_position < m_length);
173             return m_sourceString[m_position];
174         }
175 
advance()176         void advance()
177         {
178             ++m_position;
179         }
180 
isNewline(UChar character)181         bool isNewline(UChar character)
182         {
183             // Don't attempt to canonicalize newline related characters.
184             return (character == '\n' || character == '\r');
185         }
186 
emit(UChar character)187         void emit(UChar character)
188         {
189             m_builder.append(character);
190         }
191 
192         enum ParseState {
193             // Have not seen an ASCII non-whitespace character yet on
194             // this line. Possible that we might see a preprocessor
195             // directive.
196             BeginningOfLine,
197 
198             // Have seen at least one ASCII non-whitespace character
199             // on this line.
200             MiddleOfLine,
201 
202             // Handling a preprocessor directive. Passes through all
203             // characters up to the end of the line. Disables comment
204             // processing.
205             InPreprocessorDirective,
206 
207             // Handling a single-line comment. The comment text is
208             // replaced with a single space.
209             InSingleLineComment,
210 
211             // Handling a multi-line comment. Newlines are passed
212             // through to preserve line numbers.
213             InMultiLineComment
214         };
215 
216         ParseState m_parseState;
217         String m_sourceString;
218         unsigned m_length;
219         unsigned m_position;
220         StringBuilder m_builder;
221     };
222 
process(UChar c)223     void StripComments::process(UChar c)
224     {
225         if (isNewline(c)) {
226             // No matter what state we are in, pass through newlines
227             // so we preserve line numbers.
228             emit(c);
229 
230             if (m_parseState != InMultiLineComment)
231                 m_parseState = BeginningOfLine;
232 
233             return;
234         }
235 
236         UChar temp = 0;
237         switch (m_parseState) {
238         case BeginningOfLine:
239             if (WTF::isASCIISpace(c)) {
240                 emit(c);
241                 break;
242             }
243 
244             if (c == '#') {
245                 m_parseState = InPreprocessorDirective;
246                 emit(c);
247                 break;
248             }
249 
250             // Transition to normal state and re-handle character.
251             m_parseState = MiddleOfLine;
252             process(c);
253             break;
254 
255         case MiddleOfLine:
256             if (c == '/' && peek(temp)) {
257                 if (temp == '/') {
258                     m_parseState = InSingleLineComment;
259                     emit(' ');
260                     advance();
261                     break;
262                 }
263 
264                 if (temp == '*') {
265                     m_parseState = InMultiLineComment;
266                     // Emit the comment start in case the user has
267                     // an unclosed comment and we want to later
268                     // signal an error.
269                     emit('/');
270                     emit('*');
271                     advance();
272                     break;
273                 }
274             }
275 
276             emit(c);
277             break;
278 
279         case InPreprocessorDirective:
280             // No matter what the character is, just pass it
281             // through. Do not parse comments in this state. This
282             // might not be the right thing to do long term, but it
283             // should handle the #error preprocessor directive.
284             emit(c);
285             break;
286 
287         case InSingleLineComment:
288             // The newline code at the top of this function takes care
289             // of resetting our state when we get out of the
290             // single-line comment. Swallow all other characters.
291             break;
292 
293         case InMultiLineComment:
294             if (c == '*' && peek(temp) && temp == '/') {
295                 emit('*');
296                 emit('/');
297                 m_parseState = MiddleOfLine;
298                 advance();
299                 break;
300             }
301 
302             // Swallow all other characters. Unclear whether we may
303             // want or need to just emit a space per character to try
304             // to preserve column numbers for debugging purposes.
305             break;
306         }
307     }
308 } // namespace anonymous
309 
310 class WebGLStateRestorer {
311 public:
WebGLStateRestorer(WebGLRenderingContext * context,bool changed)312     WebGLStateRestorer(WebGLRenderingContext* context,
313                        bool changed)
314         : m_context(context)
315         , m_changed(changed)
316     {
317     }
318 
~WebGLStateRestorer()319     ~WebGLStateRestorer()
320     {
321         m_context->cleanupAfterGraphicsCall(m_changed);
322     }
323 
324 private:
325     WebGLRenderingContext* m_context;
326     bool m_changed;
327 };
328 
fired()329 void WebGLRenderingContext::WebGLRenderingContextRestoreTimer::fired()
330 {
331     // Timer is started when m_contextLost is false.  It will first call
332     // onLostContext, which will set m_contextLost to true.  Then it will keep
333     // calling restoreContext and reschedule itself until m_contextLost is back
334     // to false.
335     if (!m_context->m_contextLost) {
336         m_context->onLostContext();
337         startOneShot(secondsBetweenRestoreAttempts);
338     } else {
339         // The rendering context is not restored if there is no handler for
340         // the context restored event.
341         if (!m_context->canvas()->hasEventListeners(eventNames().webglcontextrestoredEvent))
342             return;
343 
344         m_context->restoreContext();
345         if (m_context->m_contextLost)
346             startOneShot(secondsBetweenRestoreAttempts);
347     }
348 }
349 
350 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
351 public:
WebGLRenderingContextLostCallback(WebGLRenderingContext * cb)352     WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_contextLostCallback(cb) {}
onContextLost()353     virtual void onContextLost() { m_contextLostCallback->forceLostContext(); }
~WebGLRenderingContextLostCallback()354     virtual ~WebGLRenderingContextLostCallback() {}
355 private:
356     WebGLRenderingContext* m_contextLostCallback;
357 };
358 
create(HTMLCanvasElement * canvas,WebGLContextAttributes * attrs)359 PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs)
360 {
361     HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow();
362     GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
363 
364     if (attributes.antialias) {
365         Page* p = canvas->document()->page();
366         if (p && !p->settings()->openGLMultisamplingEnabled())
367             attributes.antialias = false;
368     }
369 
370     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
371 
372     if (!context) {
373         canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
374         return nullptr;
375     }
376 
377     return adoptPtr(new WebGLRenderingContext(canvas, context, attributes));
378 }
379 
WebGLRenderingContext(HTMLCanvasElement * passedCanvas,PassRefPtr<GraphicsContext3D> context,GraphicsContext3D::Attributes attributes)380 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
381                                              GraphicsContext3D::Attributes attributes)
382     : CanvasRenderingContext(passedCanvas)
383     , m_context(context)
384     , m_restoreTimer(this)
385     , m_videoCache(4)
386     , m_contextLost(false)
387     , m_attributes(attributes)
388 {
389     ASSERT(m_context);
390     setupFlags();
391     initializeNewContext();
392 }
393 
initializeNewContext()394 void WebGLRenderingContext::initializeNewContext()
395 {
396     ASSERT(!m_contextLost);
397     m_needsUpdate = true;
398     m_markedCanvasDirty = false;
399     m_activeTextureUnit = 0;
400     m_packAlignment = 4;
401     m_unpackAlignment = 4;
402     m_unpackFlipY = false;
403     m_unpackPremultiplyAlpha = false;
404     m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
405     m_boundArrayBuffer = 0;
406     m_currentProgram = 0;
407     m_framebufferBinding = 0;
408     m_renderbufferBinding = 0;
409     m_depthMask = true;
410     m_stencilMask = 0xFFFFFFFF;
411     m_stencilMaskBack = 0xFFFFFFFF;
412     m_stencilFuncRef = 0;
413     m_stencilFuncRefBack = 0;
414     m_stencilFuncMask = 0xFFFFFFFF;
415     m_stencilFuncMaskBack = 0xFFFFFFFF;
416     m_layerCleared = false;
417 
418     m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
419     m_scissorEnabled = false;
420     m_clearDepth = 1;
421     m_clearStencil = 0;
422     m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
423 
424     GC3Dint numCombinedTextureImageUnits = 0;
425     m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
426     m_textureUnits.clear();
427     m_textureUnits.resize(numCombinedTextureImageUnits);
428 
429     GC3Dint numVertexAttribs = 0;
430     m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
431     m_maxVertexAttribs = numVertexAttribs;
432 
433     m_maxTextureSize = 0;
434     m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
435     m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
436     m_maxCubeMapTextureSize = 0;
437     m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
438     m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
439 
440     m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
441     addObject(m_defaultVertexArrayObject.get());
442     m_boundVertexArrayObject = m_defaultVertexArrayObject;
443 
444     m_vertexAttribValue.resize(m_maxVertexAttribs);
445 
446     if (!isGLES2NPOTStrict())
447         createFallbackBlackTextures1x1();
448     if (!isGLES2Compliant())
449         initVertexAttrib0();
450 
451     m_context->reshape(canvas()->width(), canvas()->height());
452     m_context->viewport(0, 0, canvas()->width(), canvas()->height());
453 
454     m_context->setContextLostCallback(adoptPtr(new WebGLRenderingContextLostCallback(this)));
455 }
456 
setupFlags()457 void WebGLRenderingContext::setupFlags()
458 {
459     ASSERT(m_context);
460 
461     m_isGLES2Compliant = m_context->isGLES2Compliant();
462     m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs");
463     m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe");
464     if (m_isGLES2Compliant) {
465         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
466         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
467     } else {
468         m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two");
469         m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil");
470     }
471 }
472 
~WebGLRenderingContext()473 WebGLRenderingContext::~WebGLRenderingContext()
474 {
475     detachAndRemoveAllObjects();
476     m_context->setContextLostCallback(nullptr);
477 }
478 
markContextChanged()479 void WebGLRenderingContext::markContextChanged()
480 {
481     if (m_framebufferBinding)
482         return;
483     m_context->markContextChanged();
484     m_layerCleared = false;
485 #if USE(ACCELERATED_COMPOSITING)
486     RenderBox* renderBox = canvas()->renderBox();
487     if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing())
488         renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
489     else {
490 #endif
491         if (!m_markedCanvasDirty)
492             canvas()->didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
493 #if USE(ACCELERATED_COMPOSITING)
494     }
495 #endif
496     m_markedCanvasDirty = true;
497 }
498 
clearIfComposited(GC3Dbitfield mask)499 bool WebGLRenderingContext::clearIfComposited(GC3Dbitfield mask)
500 {
501     if (isContextLost())
502         return false;
503 
504     if (!m_context->layerComposited() || m_layerCleared
505         || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
506         return false;
507 
508     RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
509 
510     // Determine if it's possible to combine the clear the user asked for and this clear.
511     bool combinedClear = mask && !m_scissorEnabled;
512 
513     if (m_framebufferBinding)
514         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
515     m_context->disable(GraphicsContext3D::SCISSOR_TEST);
516     if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
517         m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
518                               m_colorMask[1] ? m_clearColor[1] : 0,
519                               m_colorMask[2] ? m_clearColor[2] : 0,
520                               m_colorMask[3] ? m_clearColor[3] : 0);
521     else
522         m_context->clearColor(0, 0, 0, 0);
523     m_context->colorMask(true, true, true, true);
524     GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
525     if (contextAttributes->depth()) {
526         if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
527             m_context->clearDepth(1.0f);
528         clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
529         m_context->depthMask(true);
530     }
531     if (contextAttributes->stencil()) {
532         if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
533             m_context->clearStencil(m_clearStencil & m_stencilMask);
534         else
535             m_context->clearStencil(0);
536         clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
537         m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
538     }
539     m_context->clear(clearMask);
540 
541     // Restore the state that the context set.
542     if (m_scissorEnabled)
543         m_context->enable(GraphicsContext3D::SCISSOR_TEST);
544     m_context->clearColor(m_clearColor[0], m_clearColor[1],
545                           m_clearColor[2], m_clearColor[3]);
546     m_context->colorMask(m_colorMask[0], m_colorMask[1],
547                          m_colorMask[2], m_colorMask[3]);
548     m_context->clearDepth(m_clearDepth);
549     m_context->clearStencil(m_clearStencil);
550     m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
551     m_context->depthMask(m_depthMask);
552     if (m_framebufferBinding)
553         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
554     m_layerCleared = true;
555 
556     return combinedClear;
557 }
558 
markLayerComposited()559 void WebGLRenderingContext::markLayerComposited()
560 {
561     m_context->markLayerComposited();
562 }
563 
paintRenderingResultsToCanvas()564 void WebGLRenderingContext::paintRenderingResultsToCanvas()
565 {
566     // Until the canvas is written to by the application, the clear that
567     // happened after it was composited should be ignored by the compositor.
568     if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer)
569         canvas()->makePresentationCopy();
570     else
571         canvas()->clearPresentationCopy();
572     clearIfComposited();
573     if (!m_markedCanvasDirty && !m_layerCleared)
574         return;
575     canvas()->clearCopiedImage();
576     m_markedCanvasDirty = false;
577     m_context->paintRenderingResultsToCanvas(this);
578 }
579 
paintRenderingResultsToImageData()580 PassRefPtr<ImageData> WebGLRenderingContext::paintRenderingResultsToImageData()
581 {
582     clearIfComposited();
583     return m_context->paintRenderingResultsToImageData();
584 }
585 
paintsIntoCanvasBuffer() const586 bool WebGLRenderingContext::paintsIntoCanvasBuffer() const
587 {
588     return m_context->paintsIntoCanvasBuffer();
589 }
590 
reshape(int width,int height)591 void WebGLRenderingContext::reshape(int width, int height)
592 {
593     if (m_needsUpdate) {
594 #if USE(ACCELERATED_COMPOSITING)
595         RenderBox* renderBox = canvas()->renderBox();
596         if (renderBox && renderBox->hasLayer())
597             renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
598 #endif
599         m_needsUpdate = false;
600     }
601 
602     // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
603     // clear (and this matches what reshape will do).
604     m_context->reshape(width, height);
605 }
606 
sizeInBytes(GC3Denum type)607 unsigned int WebGLRenderingContext::sizeInBytes(GC3Denum type)
608 {
609     switch (type) {
610     case GraphicsContext3D::BYTE:
611         return sizeof(GC3Dbyte);
612     case GraphicsContext3D::UNSIGNED_BYTE:
613         return sizeof(GC3Dubyte);
614     case GraphicsContext3D::SHORT:
615         return sizeof(GC3Dshort);
616     case GraphicsContext3D::UNSIGNED_SHORT:
617         return sizeof(GC3Dushort);
618     case GraphicsContext3D::INT:
619         return sizeof(GC3Dint);
620     case GraphicsContext3D::UNSIGNED_INT:
621         return sizeof(GC3Duint);
622     case GraphicsContext3D::FLOAT:
623         return sizeof(GC3Dfloat);
624     }
625     ASSERT_NOT_REACHED();
626     return 0;
627 }
628 
activeTexture(GC3Denum texture,ExceptionCode & ec)629 void WebGLRenderingContext::activeTexture(GC3Denum texture, ExceptionCode& ec)
630 {
631     UNUSED_PARAM(ec);
632     if (isContextLost())
633         return;
634     if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
635         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
636         return;
637     }
638     m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
639     m_context->activeTexture(texture);
640     cleanupAfterGraphicsCall(false);
641 }
642 
attachShader(WebGLProgram * program,WebGLShader * shader,ExceptionCode & ec)643 void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
644 {
645     UNUSED_PARAM(ec);
646     if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
647         return;
648     if (!program->attachShader(shader)) {
649         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
650         return;
651     }
652     m_context->attachShader(objectOrZero(program), objectOrZero(shader));
653     shader->onAttached();
654     cleanupAfterGraphicsCall(false);
655 }
656 
bindAttribLocation(WebGLProgram * program,GC3Duint index,const String & name,ExceptionCode & ec)657 void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
658 {
659     UNUSED_PARAM(ec);
660     if (isContextLost() || !validateWebGLObject(program))
661         return;
662     if (!validateString(name))
663         return;
664     m_context->bindAttribLocation(objectOrZero(program), index, name);
665     cleanupAfterGraphicsCall(false);
666 }
667 
checkObjectToBeBound(WebGLObject * object,bool & deleted)668 bool WebGLRenderingContext::checkObjectToBeBound(WebGLObject* object, bool& deleted)
669 {
670     deleted = false;
671     if (isContextLost())
672         return false;
673     if (object) {
674         if (object->context() != this) {
675             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
676             return false;
677         }
678         deleted = !object->object();
679     }
680     return true;
681 }
682 
bindBuffer(GC3Denum target,WebGLBuffer * buffer,ExceptionCode & ec)683 void WebGLRenderingContext::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec)
684 {
685     UNUSED_PARAM(ec);
686     bool deleted;
687     if (!checkObjectToBeBound(buffer, deleted))
688         return;
689     if (deleted)
690         buffer = 0;
691     if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
692         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
693         return;
694     }
695     if (target == GraphicsContext3D::ARRAY_BUFFER)
696         m_boundArrayBuffer = buffer;
697     else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
698         m_boundVertexArrayObject->setElementArrayBuffer(buffer);
699     else {
700         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
701         return;
702     }
703 
704     m_context->bindBuffer(target, objectOrZero(buffer));
705     if (buffer)
706         buffer->setTarget(target);
707     cleanupAfterGraphicsCall(false);
708 }
709 
bindFramebuffer(GC3Denum target,WebGLFramebuffer * buffer,ExceptionCode & ec)710 void WebGLRenderingContext::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec)
711 {
712     UNUSED_PARAM(ec);
713     bool deleted;
714     if (!checkObjectToBeBound(buffer, deleted))
715         return;
716     if (deleted)
717         buffer = 0;
718     if (target != GraphicsContext3D::FRAMEBUFFER) {
719         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
720         return;
721     }
722     m_framebufferBinding = buffer;
723     m_context->bindFramebuffer(target, objectOrZero(buffer));
724     if (buffer)
725         buffer->setHasEverBeenBound();
726     cleanupAfterGraphicsCall(false);
727 }
728 
bindRenderbuffer(GC3Denum target,WebGLRenderbuffer * renderBuffer,ExceptionCode & ec)729 void WebGLRenderingContext::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
730 {
731     UNUSED_PARAM(ec);
732     bool deleted;
733     if (!checkObjectToBeBound(renderBuffer, deleted))
734         return;
735     if (deleted)
736         renderBuffer = 0;
737     if (target != GraphicsContext3D::RENDERBUFFER) {
738         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
739         return;
740     }
741     m_renderbufferBinding = renderBuffer;
742     m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
743     if (renderBuffer)
744         renderBuffer->setHasEverBeenBound();
745     cleanupAfterGraphicsCall(false);
746 }
747 
bindTexture(GC3Denum target,WebGLTexture * texture,ExceptionCode & ec)748 void WebGLRenderingContext::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
749 {
750     UNUSED_PARAM(ec);
751     bool deleted;
752     if (!checkObjectToBeBound(texture, deleted))
753         return;
754     if (deleted)
755         texture = 0;
756     if (texture && texture->getTarget() && texture->getTarget() != target) {
757         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
758         return;
759     }
760     GC3Dint maxLevel = 0;
761     if (target == GraphicsContext3D::TEXTURE_2D) {
762         m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
763         maxLevel = m_maxTextureLevel;
764     } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
765         m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
766         maxLevel = m_maxCubeMapTextureLevel;
767     } else {
768         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
769         return;
770     }
771     m_context->bindTexture(target, objectOrZero(texture));
772     if (texture)
773         texture->setTarget(target, maxLevel);
774 
775     // Note: previously we used to automatically set the TEXTURE_WRAP_R
776     // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
777     // ES 2.0 doesn't expose this flag (a bug in the specification) and
778     // otherwise the application has no control over the seams in this
779     // dimension. However, it appears that supporting this properly on all
780     // platforms is fairly involved (will require a HashMap from texture ID
781     // in all ports), and we have not had any complaints, so the logic has
782     // been removed.
783 
784     cleanupAfterGraphicsCall(false);
785 }
786 
blendColor(GC3Dfloat red,GC3Dfloat green,GC3Dfloat blue,GC3Dfloat alpha)787 void WebGLRenderingContext::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
788 {
789     if (isContextLost())
790         return;
791     m_context->blendColor(red, green, blue, alpha);
792     cleanupAfterGraphicsCall(false);
793 }
794 
blendEquation(GC3Denum mode)795 void WebGLRenderingContext::blendEquation(GC3Denum mode)
796 {
797     if (isContextLost() || !validateBlendEquation(mode))
798         return;
799     m_context->blendEquation(mode);
800     cleanupAfterGraphicsCall(false);
801 }
802 
blendEquationSeparate(GC3Denum modeRGB,GC3Denum modeAlpha)803 void WebGLRenderingContext::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
804 {
805     if (isContextLost() || !validateBlendEquation(modeRGB) || !validateBlendEquation(modeAlpha))
806         return;
807     m_context->blendEquationSeparate(modeRGB, modeAlpha);
808     cleanupAfterGraphicsCall(false);
809 }
810 
811 
blendFunc(GC3Denum sfactor,GC3Denum dfactor)812 void WebGLRenderingContext::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
813 {
814     if (isContextLost() || !validateBlendFuncFactors(sfactor, dfactor))
815         return;
816     m_context->blendFunc(sfactor, dfactor);
817     cleanupAfterGraphicsCall(false);
818 }
819 
blendFuncSeparate(GC3Denum srcRGB,GC3Denum dstRGB,GC3Denum srcAlpha,GC3Denum dstAlpha)820 void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
821 {
822     if (isContextLost() || !validateBlendFuncFactors(srcRGB, dstRGB))
823         return;
824     m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
825     cleanupAfterGraphicsCall(false);
826 }
827 
bufferData(GC3Denum target,GC3Dsizeiptr size,GC3Denum usage,ExceptionCode & ec)828 void WebGLRenderingContext::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage, ExceptionCode& ec)
829 {
830     UNUSED_PARAM(ec);
831     if (isContextLost())
832         return;
833     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
834     if (!buffer)
835         return;
836     if (size < 0) {
837         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
838         return;
839     }
840     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
841         if (!buffer->associateBufferData(size)) {
842             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
843             return;
844         }
845     }
846 
847     m_context->bufferData(target, size, usage);
848     cleanupAfterGraphicsCall(false);
849 }
850 
bufferData(GC3Denum target,ArrayBuffer * data,GC3Denum usage,ExceptionCode & ec)851 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
852 {
853     UNUSED_PARAM(ec);
854     if (isContextLost())
855         return;
856     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
857     if (!buffer)
858         return;
859     if (!data) {
860         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
861         return;
862     }
863     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
864         if (!buffer->associateBufferData(data)) {
865             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
866             return;
867         }
868     }
869 
870     m_context->bufferData(target, data->byteLength(), data->data(), usage);
871     cleanupAfterGraphicsCall(false);
872 }
873 
bufferData(GC3Denum target,ArrayBufferView * data,GC3Denum usage,ExceptionCode & ec)874 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
875 {
876     UNUSED_PARAM(ec);
877     if (isContextLost())
878         return;
879     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
880     if (!buffer)
881         return;
882     if (!data) {
883         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
884         return;
885     }
886     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
887         if (!buffer->associateBufferData(data)) {
888             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
889             return;
890         }
891     }
892 
893     m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
894     cleanupAfterGraphicsCall(false);
895 }
896 
bufferSubData(GC3Denum target,GC3Dintptr offset,ArrayBuffer * data,ExceptionCode & ec)897 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBuffer* data, ExceptionCode& ec)
898 {
899     UNUSED_PARAM(ec);
900     if (isContextLost())
901         return;
902     WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
903     if (!buffer)
904         return;
905     if (offset < 0) {
906         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
907         return;
908     }
909     if (!data)
910         return;
911     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
912         if (!buffer->associateBufferSubData(offset, data)) {
913             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
914             return;
915         }
916     }
917 
918     m_context->bufferSubData(target, offset, data->byteLength(), data->data());
919     cleanupAfterGraphicsCall(false);
920 }
921 
bufferSubData(GC3Denum target,GC3Dintptr offset,ArrayBufferView * data,ExceptionCode & ec)922 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBufferView* data, ExceptionCode& ec)
923 {
924     UNUSED_PARAM(ec);
925     if (isContextLost())
926         return;
927     WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
928     if (!buffer)
929         return;
930     if (offset < 0) {
931         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
932         return;
933     }
934     if (!data)
935         return;
936     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
937         if (!buffer->associateBufferSubData(offset, data)) {
938             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
939             return;
940         }
941     }
942 
943     m_context->bufferSubData(target, offset, data->byteLength(), data->baseAddress());
944     cleanupAfterGraphicsCall(false);
945 }
946 
checkFramebufferStatus(GC3Denum target)947 GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target)
948 {
949     if (isContextLost())
950         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
951     if (target != GraphicsContext3D::FRAMEBUFFER) {
952         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
953         return 0;
954     }
955     if (!m_framebufferBinding || !m_framebufferBinding->object())
956         return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
957     if (m_framebufferBinding->isIncomplete(true))
958         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
959     unsigned long result = m_context->checkFramebufferStatus(target);
960     cleanupAfterGraphicsCall(false);
961     return result;
962 }
963 
clear(GC3Dbitfield mask)964 void WebGLRenderingContext::clear(GC3Dbitfield mask)
965 {
966     if (isContextLost())
967         return;
968     if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
969         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
970         return;
971     }
972     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
973         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
974         return;
975     }
976     if (!clearIfComposited(mask))
977         m_context->clear(mask);
978     cleanupAfterGraphicsCall(true);
979 }
980 
clearColor(GC3Dfloat r,GC3Dfloat g,GC3Dfloat b,GC3Dfloat a)981 void WebGLRenderingContext::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
982 {
983     if (isContextLost())
984         return;
985     if (isnan(r))
986         r = 0;
987     if (isnan(g))
988         g = 0;
989     if (isnan(b))
990         b = 0;
991     if (isnan(a))
992         a = 1;
993     m_clearColor[0] = r;
994     m_clearColor[1] = g;
995     m_clearColor[2] = b;
996     m_clearColor[3] = a;
997     m_context->clearColor(r, g, b, a);
998     cleanupAfterGraphicsCall(false);
999 }
1000 
clearDepth(GC3Dfloat depth)1001 void WebGLRenderingContext::clearDepth(GC3Dfloat depth)
1002 {
1003     if (isContextLost())
1004         return;
1005     m_clearDepth = depth;
1006     m_context->clearDepth(depth);
1007     cleanupAfterGraphicsCall(false);
1008 }
1009 
clearStencil(GC3Dint s)1010 void WebGLRenderingContext::clearStencil(GC3Dint s)
1011 {
1012     if (isContextLost())
1013         return;
1014     m_clearStencil = s;
1015     m_context->clearStencil(s);
1016     cleanupAfterGraphicsCall(false);
1017 }
1018 
colorMask(GC3Dboolean red,GC3Dboolean green,GC3Dboolean blue,GC3Dboolean alpha)1019 void WebGLRenderingContext::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1020 {
1021     if (isContextLost())
1022         return;
1023     m_colorMask[0] = red;
1024     m_colorMask[1] = green;
1025     m_colorMask[2] = blue;
1026     m_colorMask[3] = alpha;
1027     m_context->colorMask(red, green, blue, alpha);
1028     cleanupAfterGraphicsCall(false);
1029 }
1030 
compileShader(WebGLShader * shader,ExceptionCode & ec)1031 void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec)
1032 {
1033     UNUSED_PARAM(ec);
1034     if (isContextLost() || !validateWebGLObject(shader))
1035         return;
1036     m_context->compileShader(objectOrZero(shader));
1037     cleanupAfterGraphicsCall(false);
1038 }
1039 
copyTexImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height,GC3Dint border)1040 void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
1041 {
1042     if (isContextLost())
1043         return;
1044     if (!validateTexFuncParameters(target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
1045         return;
1046     WebGLTexture* tex = validateTextureBinding(target, true);
1047     if (!tex)
1048         return;
1049     if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1050         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1051         return;
1052     }
1053     if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1054         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1055         return;
1056     }
1057     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1058         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1059         return;
1060     }
1061     clearIfComposited();
1062     if (isResourceSafe())
1063         m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1064     else {
1065         GC3Dint clippedX, clippedY;
1066         GC3Dsizei clippedWidth, clippedHeight;
1067         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1068             m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
1069                                               internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment);
1070             if (clippedWidth > 0 && clippedHeight > 0) {
1071                 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
1072                                              clippedX, clippedY, clippedWidth, clippedHeight);
1073             }
1074         } else
1075             m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1076     }
1077     // FIXME: if the framebuffer is not complete, none of the below should be executed.
1078     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1079     cleanupAfterGraphicsCall(false);
1080 }
1081 
copyTexSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height)1082 void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1083 {
1084     if (isContextLost())
1085         return;
1086     if (!validateTexFuncLevel(target, level))
1087         return;
1088     WebGLTexture* tex = validateTextureBinding(target, true);
1089     if (!tex)
1090         return;
1091     if (!validateSize(xoffset, yoffset) || !validateSize(width, height))
1092         return;
1093     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1094         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1095         return;
1096     }
1097     if (!isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(target, level), getBoundFramebufferColorFormat())) {
1098         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1099         return;
1100     }
1101     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1102         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1103         return;
1104     }
1105     clearIfComposited();
1106     if (isResourceSafe())
1107         m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1108     else {
1109         GC3Dint clippedX, clippedY;
1110         GC3Dsizei clippedWidth, clippedHeight;
1111         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1112             GC3Denum format = tex->getInternalFormat(target, level);
1113             GC3Denum type = tex->getType(target, level);
1114             OwnArrayPtr<unsigned char> zero;
1115             if (width && height) {
1116                 unsigned int size;
1117                 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1118                 if (error != GraphicsContext3D::NO_ERROR) {
1119                     m_context->synthesizeGLError(error);
1120                     return;
1121                 }
1122                 zero = adoptArrayPtr(new unsigned char[size]);
1123                 if (!zero) {
1124                     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1125                     return;
1126                 }
1127                 memset(zero.get(), 0, size);
1128             }
1129             m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1130             if (clippedWidth > 0 && clippedHeight > 0) {
1131                 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1132                                              clippedX, clippedY, clippedWidth, clippedHeight);
1133             }
1134         } else
1135             m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1136     }
1137     cleanupAfterGraphicsCall(false);
1138 }
1139 
createBuffer()1140 PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer()
1141 {
1142     if (isContextLost())
1143         return 0;
1144     RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1145     addObject(o.get());
1146     return o;
1147 }
1148 
createFramebuffer()1149 PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer()
1150 {
1151     if (isContextLost())
1152         return 0;
1153     RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1154     addObject(o.get());
1155     return o;
1156 }
1157 
createTexture()1158 PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture()
1159 {
1160     if (isContextLost())
1161         return 0;
1162     RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1163     addObject(o.get());
1164     return o;
1165 }
1166 
createProgram()1167 PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram()
1168 {
1169     if (isContextLost())
1170         return 0;
1171     RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1172     addObject(o.get());
1173     return o;
1174 }
1175 
createRenderbuffer()1176 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer()
1177 {
1178     if (isContextLost())
1179         return 0;
1180     RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1181     addObject(o.get());
1182     return o;
1183 }
1184 
createShader(GC3Denum type,ExceptionCode & ec)1185 PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(GC3Denum type, ExceptionCode& ec)
1186 {
1187     UNUSED_PARAM(ec);
1188     if (isContextLost())
1189         return 0;
1190     if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1191         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1192         return 0;
1193     }
1194 
1195     RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1196     addObject(o.get());
1197     return o;
1198 }
1199 
cullFace(GC3Denum mode)1200 void WebGLRenderingContext::cullFace(GC3Denum mode)
1201 {
1202     if (isContextLost())
1203         return;
1204     m_context->cullFace(mode);
1205     cleanupAfterGraphicsCall(false);
1206 }
1207 
deleteObject(WebGLObject * object)1208 bool WebGLRenderingContext::deleteObject(WebGLObject* object)
1209 {
1210     if (isContextLost() || !object)
1211         return false;
1212     if (object->context() != this) {
1213         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1214         return false;
1215     }
1216     if (object->object())
1217         object->deleteObject();
1218     return true;
1219 }
1220 
deleteBuffer(WebGLBuffer * buffer)1221 void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
1222 {
1223     if (!deleteObject(buffer))
1224         return;
1225     if (m_boundArrayBuffer == buffer)
1226         m_boundArrayBuffer = 0;
1227     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1228     if (elementArrayBuffer == buffer)
1229         m_boundVertexArrayObject->setElementArrayBuffer(0);
1230     if (!isGLES2Compliant()) {
1231         WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
1232         if (buffer == state.bufferBinding) {
1233             state.bufferBinding = m_vertexAttrib0Buffer;
1234             state.bytesPerElement = 0;
1235             state.size = 4;
1236             state.type = GraphicsContext3D::FLOAT;
1237             state.normalized = false;
1238             state.stride = 16;
1239             state.originalStride = 0;
1240             state.offset = 0;
1241         }
1242     }
1243 }
1244 
deleteFramebuffer(WebGLFramebuffer * framebuffer)1245 void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1246 {
1247     if (!deleteObject(framebuffer))
1248         return;
1249     if (framebuffer == m_framebufferBinding) {
1250         m_framebufferBinding = 0;
1251         // Have to call bindFramebuffer here to bind back to internal fbo.
1252         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1253     }
1254 }
1255 
deleteProgram(WebGLProgram * program)1256 void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
1257 {
1258     deleteObject(program);
1259     // We don't reset m_currentProgram to 0 here because the deletion of the
1260     // current program is delayed.
1261 }
1262 
deleteRenderbuffer(WebGLRenderbuffer * renderbuffer)1263 void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1264 {
1265     if (!deleteObject(renderbuffer))
1266         return;
1267     if (renderbuffer == m_renderbufferBinding)
1268         m_renderbufferBinding = 0;
1269     if (m_framebufferBinding)
1270         m_framebufferBinding->removeAttachment(renderbuffer);
1271 }
1272 
deleteShader(WebGLShader * shader)1273 void WebGLRenderingContext::deleteShader(WebGLShader* shader)
1274 {
1275     deleteObject(shader);
1276 }
1277 
deleteTexture(WebGLTexture * texture)1278 void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
1279 {
1280     if (!deleteObject(texture))
1281         return;
1282     for (size_t i = 0; i < m_textureUnits.size(); ++i) {
1283         if (texture == m_textureUnits[i].m_texture2DBinding)
1284             m_textureUnits[i].m_texture2DBinding = 0;
1285         if (texture == m_textureUnits[i].m_textureCubeMapBinding)
1286             m_textureUnits[i].m_textureCubeMapBinding = 0;
1287     }
1288     if (m_framebufferBinding)
1289         m_framebufferBinding->removeAttachment(texture);
1290 }
1291 
depthFunc(GC3Denum func)1292 void WebGLRenderingContext::depthFunc(GC3Denum func)
1293 {
1294     if (isContextLost())
1295         return;
1296     m_context->depthFunc(func);
1297     cleanupAfterGraphicsCall(false);
1298 }
1299 
depthMask(GC3Dboolean flag)1300 void WebGLRenderingContext::depthMask(GC3Dboolean flag)
1301 {
1302     if (isContextLost())
1303         return;
1304     m_depthMask = flag;
1305     m_context->depthMask(flag);
1306     cleanupAfterGraphicsCall(false);
1307 }
1308 
depthRange(GC3Dfloat zNear,GC3Dfloat zFar)1309 void WebGLRenderingContext::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1310 {
1311     if (isContextLost())
1312         return;
1313     if (zNear > zFar) {
1314         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1315         return;
1316     }
1317     m_context->depthRange(zNear, zFar);
1318     cleanupAfterGraphicsCall(false);
1319 }
1320 
detachShader(WebGLProgram * program,WebGLShader * shader,ExceptionCode & ec)1321 void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
1322 {
1323     UNUSED_PARAM(ec);
1324     if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
1325         return;
1326     if (!program->detachShader(shader)) {
1327         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1328         return;
1329     }
1330     m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1331     shader->onDetached();
1332     cleanupAfterGraphicsCall(false);
1333 }
1334 
disable(GC3Denum cap)1335 void WebGLRenderingContext::disable(GC3Denum cap)
1336 {
1337     if (isContextLost() || !validateCapability(cap))
1338         return;
1339     if (cap == GraphicsContext3D::SCISSOR_TEST)
1340         m_scissorEnabled = false;
1341     m_context->disable(cap);
1342     cleanupAfterGraphicsCall(false);
1343 }
1344 
disableVertexAttribArray(GC3Duint index,ExceptionCode & ec)1345 void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1346 {
1347     UNUSED_PARAM(ec);
1348     if (isContextLost())
1349         return;
1350     if (index >= m_maxVertexAttribs) {
1351         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1352         return;
1353     }
1354 
1355     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1356     state.enabled = false;
1357 
1358     if (index > 0 || isGLES2Compliant()) {
1359         m_context->disableVertexAttribArray(index);
1360         cleanupAfterGraphicsCall(false);
1361     }
1362 }
1363 
validateElementArraySize(GC3Dsizei count,GC3Denum type,GC3Dintptr offset)1364 bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1365 {
1366     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1367 
1368     if (!elementArrayBuffer)
1369         return false;
1370 
1371     if (offset < 0)
1372         return false;
1373 
1374     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1375         // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1376         if (offset % 2)
1377             return false;
1378 
1379         // Make uoffset an element offset.
1380         offset /= 2;
1381 
1382         GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1383         if (offset > n || count > n - offset)
1384             return false;
1385     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1386         GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1387         if (offset > n || count > n - offset)
1388             return false;
1389     }
1390     return true;
1391 }
1392 
validateIndexArrayConservative(GC3Denum type,int & numElementsRequired)1393 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& numElementsRequired)
1394 {
1395     // Performs conservative validation by caching a maximum index of
1396     // the given type per element array buffer. If all of the bound
1397     // array buffers have enough elements to satisfy that maximum
1398     // index, skips the expensive per-draw-call iteration in
1399     // validateIndexArrayPrecise.
1400 
1401     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1402 
1403     if (!elementArrayBuffer)
1404         return false;
1405 
1406     GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
1407     // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1408     if (!numElements)
1409         return false;
1410     const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
1411     ASSERT(buffer);
1412 
1413     int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
1414     if (maxIndex < 0) {
1415         // Compute the maximum index in the entire buffer for the given type of index.
1416         switch (type) {
1417         case GraphicsContext3D::UNSIGNED_BYTE: {
1418             const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
1419             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1420                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1421             break;
1422         }
1423         case GraphicsContext3D::UNSIGNED_SHORT: {
1424             numElements /= sizeof(GC3Dushort);
1425             const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
1426             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1427                 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1428             break;
1429         }
1430         default:
1431             return false;
1432         }
1433         elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1434     }
1435 
1436     if (maxIndex >= 0) {
1437         // The number of required elements is one more than the maximum
1438         // index that will be accessed.
1439         numElementsRequired = maxIndex + 1;
1440         return true;
1441     }
1442 
1443     return false;
1444 }
1445 
validateIndexArrayPrecise(GC3Dsizei count,GC3Denum type,GC3Dintptr offset,int & numElementsRequired)1446 bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, int& numElementsRequired)
1447 {
1448     ASSERT(count >= 0 && offset >= 0);
1449     int lastIndex = -1;
1450 
1451     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1452 
1453     if (!elementArrayBuffer)
1454         return false;
1455 
1456     if (!count) {
1457         numElementsRequired = 0;
1458         return true;
1459     }
1460 
1461     if (!elementArrayBuffer->elementArrayBuffer())
1462         return false;
1463 
1464     unsigned long uoffset = offset;
1465     unsigned long n = count;
1466 
1467     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1468         // Make uoffset an element offset.
1469         uoffset /= sizeof(GC3Dushort);
1470         const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1471         while (n-- > 0) {
1472             if (*p > lastIndex)
1473                 lastIndex = *p;
1474             ++p;
1475         }
1476     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1477         const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1478         while (n-- > 0) {
1479             if (*p > lastIndex)
1480                 lastIndex = *p;
1481             ++p;
1482         }
1483     }
1484 
1485     // Then set the last index in the index array and make sure it is valid.
1486     numElementsRequired = lastIndex + 1;
1487     return numElementsRequired > 0;
1488 }
1489 
validateRenderingState(int numElementsRequired)1490 bool WebGLRenderingContext::validateRenderingState(int numElementsRequired)
1491 {
1492     if (!m_currentProgram)
1493         return false;
1494 
1495     // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1496     for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1497         const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
1498         if (state.enabled
1499             && (!state.bufferBinding || !state.bufferBinding->object()))
1500             return false;
1501     }
1502 
1503     if (numElementsRequired <= 0)
1504         return true;
1505 
1506     // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
1507     int smallestNumElements = INT_MAX;
1508     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1509     for (int i = 0; i < numActiveAttribLocations; ++i) {
1510         int loc = m_currentProgram->getActiveAttribLocation(i);
1511         if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1512             const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1513             if (state.enabled) {
1514                 // Avoid off-by-one errors in numElements computation.
1515                 // For the last element, we will only touch the data for the
1516                 // element and nothing beyond it.
1517                 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1518                 int numElements = 0;
1519                 ASSERT(state.stride > 0);
1520                 if (bytesRemaining >= state.bytesPerElement)
1521                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1522                 if (numElements < smallestNumElements)
1523                     smallestNumElements = numElements;
1524             }
1525         }
1526     }
1527 
1528     if (smallestNumElements == INT_MAX)
1529         smallestNumElements = 0;
1530 
1531     return numElementsRequired <= smallestNumElements;
1532 }
1533 
validateWebGLObject(WebGLObject * object)1534 bool WebGLRenderingContext::validateWebGLObject(WebGLObject* object)
1535 {
1536     if (!object || !object->object()) {
1537         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1538         return false;
1539     }
1540     if (object->context() != this) {
1541         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1542         return false;
1543     }
1544     return true;
1545 }
1546 
drawArrays(GC3Denum mode,GC3Dint first,GC3Dsizei count,ExceptionCode & ec)1547 void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
1548 {
1549     UNUSED_PARAM(ec);
1550 
1551     if (isContextLost() || !validateDrawMode(mode))
1552         return;
1553 
1554     if (!validateStencilSettings())
1555         return;
1556 
1557     if (first < 0 || count < 0) {
1558         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1559         return;
1560     }
1561 
1562     if (!count)
1563         return;
1564 
1565     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1566         // Ensure we have a valid rendering state
1567         CheckedInt<GC3Dint> checkedFirst(first);
1568         CheckedInt<GC3Dint> checkedCount(count);
1569         CheckedInt<GC3Dint> checkedSum = checkedFirst + checkedCount;
1570         if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) {
1571             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1572             return;
1573         }
1574     } else {
1575         if (!validateRenderingState(0)) {
1576             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1577             return;
1578         }
1579     }
1580 
1581     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1582         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1583         return;
1584     }
1585 
1586     clearIfComposited();
1587 
1588     bool vertexAttrib0Simulated = false;
1589     if (!isGLES2Compliant())
1590         vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1591     if (!isGLES2NPOTStrict())
1592         handleNPOTTextures(true);
1593     m_context->drawArrays(mode, first, count);
1594     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1595         restoreStatesAfterVertexAttrib0Simulation();
1596     if (!isGLES2NPOTStrict())
1597         handleNPOTTextures(false);
1598     cleanupAfterGraphicsCall(true);
1599 }
1600 
drawElements(GC3Denum mode,GC3Dsizei count,GC3Denum type,GC3Dintptr offset,ExceptionCode & ec)1601 void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, ExceptionCode& ec)
1602 {
1603     UNUSED_PARAM(ec);
1604 
1605     if (isContextLost() || !validateDrawMode(mode))
1606         return;
1607 
1608     if (!validateStencilSettings())
1609         return;
1610 
1611     switch (type) {
1612     case GraphicsContext3D::UNSIGNED_BYTE:
1613     case GraphicsContext3D::UNSIGNED_SHORT:
1614         break;
1615     default:
1616         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1617         return;
1618     }
1619 
1620     if (count < 0 || offset < 0) {
1621         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1622         return;
1623     }
1624 
1625     if (!count)
1626         return;
1627 
1628     if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1629         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1630         return;
1631     }
1632 
1633     int numElements = 0;
1634     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1635         // Ensure we have a valid rendering state
1636         if (!validateElementArraySize(count, type, offset)) {
1637             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1638             return;
1639         }
1640         if (!count)
1641             return;
1642         if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) {
1643             if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
1644                 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1645                 return;
1646             }
1647         }
1648     } else {
1649         if (!validateRenderingState(0)) {
1650             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1651             return;
1652         }
1653     }
1654 
1655     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1656         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1657         return;
1658     }
1659     clearIfComposited();
1660 
1661     bool vertexAttrib0Simulated = false;
1662     if (!isGLES2Compliant()) {
1663         if (!numElements)
1664             validateIndexArrayPrecise(count, type, offset, numElements);
1665         vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1666     }
1667     if (!isGLES2NPOTStrict())
1668         handleNPOTTextures(true);
1669     m_context->drawElements(mode, count, type, offset);
1670     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1671         restoreStatesAfterVertexAttrib0Simulation();
1672     if (!isGLES2NPOTStrict())
1673         handleNPOTTextures(false);
1674     cleanupAfterGraphicsCall(true);
1675 }
1676 
enable(GC3Denum cap)1677 void WebGLRenderingContext::enable(GC3Denum cap)
1678 {
1679     if (isContextLost() || !validateCapability(cap))
1680         return;
1681     if (cap == GraphicsContext3D::SCISSOR_TEST)
1682         m_scissorEnabled = true;
1683     m_context->enable(cap);
1684     cleanupAfterGraphicsCall(false);
1685 }
1686 
enableVertexAttribArray(GC3Duint index,ExceptionCode & ec)1687 void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1688 {
1689     UNUSED_PARAM(ec);
1690     if (isContextLost())
1691         return;
1692     if (index >= m_maxVertexAttribs) {
1693         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1694         return;
1695     }
1696 
1697     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1698     state.enabled = true;
1699 
1700     m_context->enableVertexAttribArray(index);
1701     cleanupAfterGraphicsCall(false);
1702 }
1703 
finish()1704 void WebGLRenderingContext::finish()
1705 {
1706     if (isContextLost())
1707         return;
1708     m_context->finish();
1709     cleanupAfterGraphicsCall(false);
1710 }
1711 
flush()1712 void WebGLRenderingContext::flush()
1713 {
1714     if (isContextLost())
1715         return;
1716     m_context->flush();
1717     cleanupAfterGraphicsCall(false);
1718 }
1719 
framebufferRenderbuffer(GC3Denum target,GC3Denum attachment,GC3Denum renderbuffertarget,WebGLRenderbuffer * buffer,ExceptionCode & ec)1720 void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
1721 {
1722     UNUSED_PARAM(ec);
1723     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1724         return;
1725     if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
1726         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1727         return;
1728     }
1729     if (buffer && buffer->context() != this) {
1730         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1731         return;
1732     }
1733     // Don't allow the default framebuffer to be mutated; all current
1734     // implementations use an FBO internally in place of the default
1735     // FBO.
1736     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1737         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1738         return;
1739     }
1740     Platform3DObject bufferObject = objectOrZero(buffer);
1741     bool reattachDepth = false;
1742     bool reattachStencil = false;
1743     bool reattachDepthStencilDepth = false;
1744     bool reattachDepthStencilStencil = false;
1745     switch (attachment) {
1746     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
1747         m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1748         m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
1749         if (!bufferObject) {
1750             reattachDepth = true;
1751             reattachStencil = true;
1752         }
1753         break;
1754     case GraphicsContext3D::DEPTH_ATTACHMENT:
1755         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1756         if (!bufferObject)
1757             reattachDepthStencilDepth = true;
1758         break;
1759     case GraphicsContext3D::STENCIL_ATTACHMENT:
1760         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1761         if (!bufferObject)
1762             reattachDepthStencilStencil = true;
1763         break;
1764     default:
1765         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1766     }
1767     m_framebufferBinding->setAttachment(attachment, buffer);
1768     if (reattachDepth) {
1769         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT));
1770         if (object)
1771             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1772     }
1773     if (reattachStencil) {
1774         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT));
1775         if (object)
1776             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1777     }
1778     if (reattachDepthStencilDepth) {
1779         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1780         if (object)
1781             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1782     }
1783     if (reattachDepthStencilStencil) {
1784         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1785         if (object)
1786             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1787     }
1788     cleanupAfterGraphicsCall(false);
1789 }
1790 
framebufferTexture2D(GC3Denum target,GC3Denum attachment,GC3Denum textarget,WebGLTexture * texture,GC3Dint level,ExceptionCode & ec)1791 void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
1792 {
1793     UNUSED_PARAM(ec);
1794     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1795         return;
1796     if (level) {
1797         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1798         return;
1799     }
1800     if (texture && texture->context() != this) {
1801         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1802         return;
1803     }
1804     // Don't allow the default framebuffer to be mutated; all current
1805     // implementations use an FBO internally in place of the default
1806     // FBO.
1807     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1808         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1809         return;
1810     }
1811     m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level);
1812     m_framebufferBinding->setAttachment(attachment, textarget, texture, level);
1813     cleanupAfterGraphicsCall(false);
1814 }
1815 
frontFace(GC3Denum mode)1816 void WebGLRenderingContext::frontFace(GC3Denum mode)
1817 {
1818     if (isContextLost())
1819         return;
1820     m_context->frontFace(mode);
1821     cleanupAfterGraphicsCall(false);
1822 }
1823 
generateMipmap(GC3Denum target)1824 void WebGLRenderingContext::generateMipmap(GC3Denum target)
1825 {
1826     if (isContextLost())
1827         return;
1828     WebGLTexture* tex = validateTextureBinding(target, false);
1829     if (!tex)
1830         return;
1831     if (!tex->canGenerateMipmaps()) {
1832         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1833         return;
1834     }
1835     // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
1836     // on Mac.  Remove the hack once this driver bug is fixed.
1837 #if OS(DARWIN)
1838     bool needToResetMinFilter = false;
1839     if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
1840         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
1841         needToResetMinFilter = true;
1842     }
1843 #endif
1844     m_context->generateMipmap(target);
1845 #if OS(DARWIN)
1846     if (needToResetMinFilter)
1847         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
1848 #endif
1849     tex->generateMipmapLevelInfo();
1850     cleanupAfterGraphicsCall(false);
1851 }
1852 
getActiveAttrib(WebGLProgram * program,GC3Duint index,ExceptionCode & ec)1853 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
1854 {
1855     UNUSED_PARAM(ec);
1856     if (isContextLost() || !validateWebGLObject(program))
1857         return 0;
1858     ActiveInfo info;
1859     if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
1860         return 0;
1861     return WebGLActiveInfo::create(info.name, info.type, info.size);
1862 }
1863 
getActiveUniform(WebGLProgram * program,GC3Duint index,ExceptionCode & ec)1864 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
1865 {
1866     UNUSED_PARAM(ec);
1867     if (isContextLost() || !validateWebGLObject(program))
1868         return 0;
1869     ActiveInfo info;
1870     if (!m_context->getActiveUniform(objectOrZero(program), index, info))
1871         return 0;
1872     if (!isGLES2Compliant())
1873         if (info.size > 1 && !info.name.endsWith("[0]"))
1874             info.name.append("[0]");
1875     return WebGLActiveInfo::create(info.name, info.type, info.size);
1876 }
1877 
getAttachedShaders(WebGLProgram * program,Vector<WebGLShader * > & shaderObjects,ExceptionCode & ec)1878 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<WebGLShader*>& shaderObjects, ExceptionCode& ec)
1879 {
1880     UNUSED_PARAM(ec);
1881     shaderObjects.clear();
1882     if (isContextLost() || !validateWebGLObject(program))
1883         return false;
1884     GC3Dint numShaders = 0;
1885     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ATTACHED_SHADERS, &numShaders);
1886     if (numShaders) {
1887         OwnArrayPtr<Platform3DObject> shaders = adoptArrayPtr(new Platform3DObject[numShaders]);
1888         GC3Dsizei count = 0;
1889         m_context->getAttachedShaders(objectOrZero(program), numShaders, &count, shaders.get());
1890         if (count != numShaders)
1891             return false;
1892         shaderObjects.resize(numShaders);
1893         for (GC3Dint ii = 0; ii < numShaders; ++ii) {
1894             WebGLShader* shader = findShader(shaders[ii]);
1895             if (!shader) {
1896                 shaderObjects.clear();
1897                 return false;
1898             }
1899             shaderObjects[ii] = shader;
1900         }
1901     }
1902     return true;
1903 }
1904 
getAttribLocation(WebGLProgram * program,const String & name)1905 GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
1906 {
1907     if (isContextLost())
1908         return -1;
1909     if (!validateString(name))
1910         return -1;
1911     return m_context->getAttribLocation(objectOrZero(program), name);
1912 }
1913 
getBufferParameter(GC3Denum target,GC3Denum pname,ExceptionCode & ec)1914 WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
1915 {
1916     UNUSED_PARAM(ec);
1917     if (isContextLost())
1918         return WebGLGetInfo();
1919     if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
1920         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1921         return WebGLGetInfo();
1922     }
1923 
1924     if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
1925         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1926         return WebGLGetInfo();
1927     }
1928 
1929     WebGLStateRestorer(this, false);
1930     GC3Dint value = 0;
1931     m_context->getBufferParameteriv(target, pname, &value);
1932     if (pname == GraphicsContext3D::BUFFER_SIZE)
1933         return WebGLGetInfo(value);
1934     return WebGLGetInfo(static_cast<unsigned int>(value));
1935 }
1936 
getContextAttributes()1937 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
1938 {
1939     if (isContextLost())
1940         return 0;
1941     // We always need to return a new WebGLContextAttributes object to
1942     // prevent the user from mutating any cached version.
1943     return WebGLContextAttributes::create(m_context->getContextAttributes());
1944 }
1945 
getError()1946 GC3Denum WebGLRenderingContext::getError()
1947 {
1948     return m_context->getError();
1949 }
1950 
getExtension(const String & name)1951 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
1952 {
1953     if (isContextLost())
1954         return 0;
1955 
1956     if (equalIgnoringCase(name, "OES_standard_derivatives")
1957         && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
1958         if (!m_oesStandardDerivatives) {
1959             m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
1960             m_oesStandardDerivatives = OESStandardDerivatives::create(this);
1961         }
1962         return m_oesStandardDerivatives.get();
1963     }
1964     if (equalIgnoringCase(name, "OES_texture_float")
1965         && m_context->getExtensions()->supports("GL_OES_texture_float")) {
1966         if (!m_oesTextureFloat) {
1967             m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
1968             m_oesTextureFloat = OESTextureFloat::create(this);
1969         }
1970         return m_oesTextureFloat.get();
1971     }
1972     if (equalIgnoringCase(name, "OES_vertex_array_object")
1973         && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
1974         if (!m_oesVertexArrayObject) {
1975             m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
1976             m_oesVertexArrayObject = OESVertexArrayObject::create(this);
1977         }
1978         return m_oesVertexArrayObject.get();
1979     }
1980     if (equalIgnoringCase(name, "WEBKIT_lose_context")) {
1981         if (!m_webkitLoseContext)
1982             m_webkitLoseContext = WebKitLoseContext::create(this);
1983         return m_webkitLoseContext.get();
1984     }
1985 
1986     return 0;
1987 }
1988 
getFramebufferAttachmentParameter(GC3Denum target,GC3Denum attachment,GC3Denum pname,ExceptionCode & ec)1989 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
1990 {
1991     UNUSED_PARAM(ec);
1992     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1993         return WebGLGetInfo();
1994     switch (pname) {
1995     case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
1996     case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
1997     case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
1998     case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
1999         break;
2000     default:
2001         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2002         return WebGLGetInfo();
2003     }
2004 
2005     if (!m_framebufferBinding || !m_framebufferBinding->object() || m_framebufferBinding->isIncomplete(false)) {
2006         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2007         return WebGLGetInfo();
2008     }
2009 
2010     if (pname != GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
2011         WebGLStateRestorer(this, false);
2012         GC3Dint value = 0;
2013         m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2014         if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2015             return WebGLGetInfo(static_cast<unsigned int>(value));
2016         return WebGLGetInfo(value);
2017     }
2018 
2019     WebGLStateRestorer(this, false);
2020     GC3Dint type = 0;
2021     m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
2022     if (!type)
2023         return WebGLGetInfo();
2024     GC3Dint value = 0;
2025     m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &value);
2026     switch (type) {
2027     case GraphicsContext3D::RENDERBUFFER:
2028         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(findRenderbuffer(static_cast<Platform3DObject>(value))));
2029     case GraphicsContext3D::TEXTURE:
2030         return WebGLGetInfo(PassRefPtr<WebGLTexture>(findTexture(static_cast<Platform3DObject>(value))));
2031     default:
2032         // FIXME: raise exception?
2033         return WebGLGetInfo();
2034     }
2035 }
2036 
getParameter(GC3Denum pname,ExceptionCode & ec)2037 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec)
2038 {
2039     UNUSED_PARAM(ec);
2040     if (isContextLost())
2041         return WebGLGetInfo();
2042     WebGLStateRestorer(this, false);
2043     switch (pname) {
2044     case GraphicsContext3D::ACTIVE_TEXTURE:
2045         return getUnsignedIntParameter(pname);
2046     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
2047         return getWebGLFloatArrayParameter(pname);
2048     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
2049         return getWebGLFloatArrayParameter(pname);
2050     case GraphicsContext3D::ALPHA_BITS:
2051         return getIntParameter(pname);
2052     case GraphicsContext3D::ARRAY_BUFFER_BINDING:
2053         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2054     case GraphicsContext3D::BLEND:
2055         return getBooleanParameter(pname);
2056     case GraphicsContext3D::BLEND_COLOR:
2057         return getWebGLFloatArrayParameter(pname);
2058     case GraphicsContext3D::BLEND_DST_ALPHA:
2059         return getUnsignedIntParameter(pname);
2060     case GraphicsContext3D::BLEND_DST_RGB:
2061         return getUnsignedIntParameter(pname);
2062     case GraphicsContext3D::BLEND_EQUATION_ALPHA:
2063         return getUnsignedIntParameter(pname);
2064     case GraphicsContext3D::BLEND_EQUATION_RGB:
2065         return getUnsignedIntParameter(pname);
2066     case GraphicsContext3D::BLEND_SRC_ALPHA:
2067         return getUnsignedIntParameter(pname);
2068     case GraphicsContext3D::BLEND_SRC_RGB:
2069         return getUnsignedIntParameter(pname);
2070     case GraphicsContext3D::BLUE_BITS:
2071         return getIntParameter(pname);
2072     case GraphicsContext3D::COLOR_CLEAR_VALUE:
2073         return getWebGLFloatArrayParameter(pname);
2074     case GraphicsContext3D::COLOR_WRITEMASK:
2075         return getBooleanArrayParameter(pname);
2076     case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
2077         // Defined as null in the spec
2078         return WebGLGetInfo();
2079     case GraphicsContext3D::CULL_FACE:
2080         return getBooleanParameter(pname);
2081     case GraphicsContext3D::CULL_FACE_MODE:
2082         return getUnsignedIntParameter(pname);
2083     case GraphicsContext3D::CURRENT_PROGRAM:
2084         return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2085     case GraphicsContext3D::DEPTH_BITS:
2086         return getIntParameter(pname);
2087     case GraphicsContext3D::DEPTH_CLEAR_VALUE:
2088         return getFloatParameter(pname);
2089     case GraphicsContext3D::DEPTH_FUNC:
2090         return getUnsignedIntParameter(pname);
2091     case GraphicsContext3D::DEPTH_RANGE:
2092         return getWebGLFloatArrayParameter(pname);
2093     case GraphicsContext3D::DEPTH_TEST:
2094         return getBooleanParameter(pname);
2095     case GraphicsContext3D::DEPTH_WRITEMASK:
2096         return getBooleanParameter(pname);
2097     case GraphicsContext3D::DITHER:
2098         return getBooleanParameter(pname);
2099     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
2100         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
2101     case GraphicsContext3D::FRAMEBUFFER_BINDING:
2102         return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2103     case GraphicsContext3D::FRONT_FACE:
2104         return getUnsignedIntParameter(pname);
2105     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2106         return getUnsignedIntParameter(pname);
2107     case GraphicsContext3D::GREEN_BITS:
2108         return getIntParameter(pname);
2109     case GraphicsContext3D::LINE_WIDTH:
2110         return getFloatParameter(pname);
2111     case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2112         return getIntParameter(pname);
2113     case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
2114         return getIntParameter(pname);
2115     case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
2116         return getIntParameter(pname);
2117     case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
2118         return getIntParameter(pname);
2119     case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
2120         return getIntParameter(pname);
2121     case GraphicsContext3D::MAX_TEXTURE_SIZE:
2122         return getIntParameter(pname);
2123     case GraphicsContext3D::MAX_VARYING_VECTORS:
2124         return getIntParameter(pname);
2125     case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
2126         return getIntParameter(pname);
2127     case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2128         return getIntParameter(pname);
2129     case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
2130         return getIntParameter(pname);
2131     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
2132         return getWebGLIntArrayParameter(pname);
2133     case GraphicsContext3D::NUM_COMPRESSED_TEXTURE_FORMATS:
2134         // WebGL 1.0 specifies that there are no compressed texture formats.
2135         return WebGLGetInfo(static_cast<int>(0));
2136     case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
2137         // FIXME: should we always return 0 for this?
2138         return getIntParameter(pname);
2139     case GraphicsContext3D::PACK_ALIGNMENT:
2140         return getIntParameter(pname);
2141     case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
2142         return getFloatParameter(pname);
2143     case GraphicsContext3D::POLYGON_OFFSET_FILL:
2144         return getBooleanParameter(pname);
2145     case GraphicsContext3D::POLYGON_OFFSET_UNITS:
2146         return getFloatParameter(pname);
2147     case GraphicsContext3D::RED_BITS:
2148         return getIntParameter(pname);
2149     case GraphicsContext3D::RENDERBUFFER_BINDING:
2150         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2151     case GraphicsContext3D::RENDERER:
2152         return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
2153     case GraphicsContext3D::SAMPLE_BUFFERS:
2154         return getIntParameter(pname);
2155     case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
2156         return getBooleanParameter(pname);
2157     case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
2158         return getFloatParameter(pname);
2159     case GraphicsContext3D::SAMPLES:
2160         return getIntParameter(pname);
2161     case GraphicsContext3D::SCISSOR_BOX:
2162         return getWebGLIntArrayParameter(pname);
2163     case GraphicsContext3D::SCISSOR_TEST:
2164         return getBooleanParameter(pname);
2165     case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
2166         return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
2167     case GraphicsContext3D::STENCIL_BACK_FAIL:
2168         return getUnsignedIntParameter(pname);
2169     case GraphicsContext3D::STENCIL_BACK_FUNC:
2170         return getUnsignedIntParameter(pname);
2171     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
2172         return getUnsignedIntParameter(pname);
2173     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
2174         return getUnsignedIntParameter(pname);
2175     case GraphicsContext3D::STENCIL_BACK_REF:
2176         return getIntParameter(pname);
2177     case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
2178         return getUnsignedIntParameter(pname);
2179     case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
2180         return getUnsignedIntParameter(pname);
2181     case GraphicsContext3D::STENCIL_BITS:
2182         return getIntParameter(pname);
2183     case GraphicsContext3D::STENCIL_CLEAR_VALUE:
2184         return getIntParameter(pname);
2185     case GraphicsContext3D::STENCIL_FAIL:
2186         return getUnsignedIntParameter(pname);
2187     case GraphicsContext3D::STENCIL_FUNC:
2188         return getUnsignedIntParameter(pname);
2189     case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
2190         return getUnsignedIntParameter(pname);
2191     case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
2192         return getUnsignedIntParameter(pname);
2193     case GraphicsContext3D::STENCIL_REF:
2194         return getIntParameter(pname);
2195     case GraphicsContext3D::STENCIL_TEST:
2196         return getBooleanParameter(pname);
2197     case GraphicsContext3D::STENCIL_VALUE_MASK:
2198         return getUnsignedIntParameter(pname);
2199     case GraphicsContext3D::STENCIL_WRITEMASK:
2200         return getUnsignedIntParameter(pname);
2201     case GraphicsContext3D::SUBPIXEL_BITS:
2202         return getIntParameter(pname);
2203     case GraphicsContext3D::TEXTURE_BINDING_2D:
2204         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
2205     case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
2206         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
2207     case GraphicsContext3D::UNPACK_ALIGNMENT:
2208         return getIntParameter(pname);
2209     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2210         return WebGLGetInfo(m_unpackFlipY);
2211     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2212         return WebGLGetInfo(m_unpackPremultiplyAlpha);
2213     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2214         return WebGLGetInfo(m_unpackColorspaceConversion);
2215     case GraphicsContext3D::VENDOR:
2216         return WebGLGetInfo("Webkit (" + m_context->getString(GraphicsContext3D::VENDOR) + ")");
2217     case GraphicsContext3D::VERSION:
2218         return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
2219     case GraphicsContext3D::VIEWPORT:
2220         return getWebGLIntArrayParameter(pname);
2221     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2222         if (m_oesStandardDerivatives)
2223             return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2224         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2225         return WebGLGetInfo();
2226     case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2227         if (m_oesVertexArrayObject) {
2228             if (!m_boundVertexArrayObject->isDefaultObject())
2229                 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2230             return WebGLGetInfo();
2231         }
2232         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2233         return WebGLGetInfo();
2234     default:
2235         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2236         return WebGLGetInfo();
2237     }
2238 }
2239 
getProgramParameter(WebGLProgram * program,GC3Denum pname,ExceptionCode & ec)2240 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2241 {
2242     UNUSED_PARAM(ec);
2243     if (isContextLost() || !validateWebGLObject(program))
2244         return WebGLGetInfo();
2245 
2246     WebGLStateRestorer(this, false);
2247     GC3Dint value = 0;
2248     switch (pname) {
2249     case GraphicsContext3D::DELETE_STATUS:
2250         return WebGLGetInfo(program->isDeleted());
2251     case GraphicsContext3D::VALIDATE_STATUS:
2252         m_context->getProgramiv(objectOrZero(program), pname, &value);
2253         return WebGLGetInfo(static_cast<bool>(value));
2254     case GraphicsContext3D::LINK_STATUS:
2255         return WebGLGetInfo(program->getLinkStatus());
2256     case GraphicsContext3D::ATTACHED_SHADERS:
2257     case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2258     case GraphicsContext3D::ACTIVE_UNIFORMS:
2259         m_context->getProgramiv(objectOrZero(program), pname, &value);
2260         return WebGLGetInfo(value);
2261     default:
2262         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2263         return WebGLGetInfo();
2264     }
2265 }
2266 
getProgramInfoLog(WebGLProgram * program,ExceptionCode & ec)2267 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2268 {
2269     UNUSED_PARAM(ec);
2270     if (isContextLost())
2271         return String();
2272     if (!validateWebGLObject(program))
2273         return "";
2274     WebGLStateRestorer(this, false);
2275     return m_context->getProgramInfoLog(objectOrZero(program));
2276 }
2277 
getRenderbufferParameter(GC3Denum target,GC3Denum pname,ExceptionCode & ec)2278 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2279 {
2280     UNUSED_PARAM(ec);
2281     if (isContextLost())
2282         return WebGLGetInfo();
2283     if (target != GraphicsContext3D::RENDERBUFFER) {
2284         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2285         return WebGLGetInfo();
2286     }
2287     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2288         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2289         return WebGLGetInfo();
2290     }
2291 
2292     if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2293         && !m_renderbufferBinding->isValid()) {
2294         ASSERT(!isDepthStencilSupported());
2295         int value = 0;
2296         switch (pname) {
2297         case GraphicsContext3D::RENDERBUFFER_WIDTH:
2298             value = m_renderbufferBinding->getWidth();
2299             break;
2300         case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2301             value = m_renderbufferBinding->getHeight();
2302             break;
2303         case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2304         case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2305         case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2306         case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2307             value = 0;
2308             break;
2309         case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2310             value = 24;
2311             break;
2312         case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2313             value = 8;
2314             break;
2315         case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2316             return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2317         default:
2318             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2319             return WebGLGetInfo();
2320         }
2321         return WebGLGetInfo(value);
2322     }
2323 
2324     WebGLStateRestorer(this, false);
2325     GC3Dint value = 0;
2326     switch (pname) {
2327     case GraphicsContext3D::RENDERBUFFER_WIDTH:
2328     case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2329     case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2330     case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2331     case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2332     case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2333     case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2334     case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2335         m_context->getRenderbufferParameteriv(target, pname, &value);
2336         return WebGLGetInfo(value);
2337     case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2338         return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2339     default:
2340         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2341         return WebGLGetInfo();
2342     }
2343 }
2344 
getShaderParameter(WebGLShader * shader,GC3Denum pname,ExceptionCode & ec)2345 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
2346 {
2347     UNUSED_PARAM(ec);
2348     if (isContextLost() || !validateWebGLObject(shader))
2349         return WebGLGetInfo();
2350     WebGLStateRestorer(this, false);
2351     GC3Dint value = 0;
2352     switch (pname) {
2353     case GraphicsContext3D::DELETE_STATUS:
2354         return WebGLGetInfo(shader->isDeleted());
2355     case GraphicsContext3D::COMPILE_STATUS:
2356         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2357         return WebGLGetInfo(static_cast<bool>(value));
2358     case GraphicsContext3D::SHADER_TYPE:
2359         m_context->getShaderiv(objectOrZero(shader), pname, &value);
2360         return WebGLGetInfo(static_cast<unsigned int>(value));
2361     default:
2362         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2363         return WebGLGetInfo();
2364     }
2365 }
2366 
getShaderInfoLog(WebGLShader * shader,ExceptionCode & ec)2367 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
2368 {
2369     UNUSED_PARAM(ec);
2370     if (isContextLost())
2371         return String();
2372     if (!validateWebGLObject(shader))
2373         return "";
2374     WebGLStateRestorer(this, false);
2375     return m_context->getShaderInfoLog(objectOrZero(shader));
2376 }
2377 
getShaderSource(WebGLShader * shader,ExceptionCode & ec)2378 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
2379 {
2380     UNUSED_PARAM(ec);
2381     if (isContextLost())
2382         return String();
2383     if (!validateWebGLObject(shader))
2384         return "";
2385     return shader->getSource();
2386 }
2387 
getSupportedExtensions()2388 Vector<String> WebGLRenderingContext::getSupportedExtensions()
2389 {
2390     Vector<String> result;
2391     if (m_context->getExtensions()->supports("GL_OES_texture_float"))
2392         result.append("OES_texture_float");
2393     if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
2394         result.append("OES_standard_derivatives");
2395     if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
2396         result.append("OES_vertex_array_object");
2397     result.append("WEBKIT_lose_context");
2398     return result;
2399 }
2400 
getTexParameter(GC3Denum target,GC3Denum pname,ExceptionCode & ec)2401 WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2402 {
2403     UNUSED_PARAM(ec);
2404     if (isContextLost())
2405         return WebGLGetInfo();
2406     WebGLTexture* tex = validateTextureBinding(target, false);
2407     if (!tex)
2408         return WebGLGetInfo();
2409     WebGLStateRestorer(this, false);
2410     GC3Dint value = 0;
2411     switch (pname) {
2412     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2413     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2414     case GraphicsContext3D::TEXTURE_WRAP_S:
2415     case GraphicsContext3D::TEXTURE_WRAP_T:
2416         m_context->getTexParameteriv(target, pname, &value);
2417         return WebGLGetInfo(static_cast<unsigned int>(value));
2418     default:
2419         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2420         return WebGLGetInfo();
2421     }
2422 }
2423 
getUniform(WebGLProgram * program,const WebGLUniformLocation * uniformLocation,ExceptionCode & ec)2424 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2425 {
2426     UNUSED_PARAM(ec);
2427     if (isContextLost() || !validateWebGLObject(program))
2428         return WebGLGetInfo();
2429     if (!uniformLocation || uniformLocation->program() != program) {
2430         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2431         return WebGLGetInfo();
2432     }
2433     GC3Dint location = uniformLocation->location();
2434 
2435     WebGLStateRestorer(this, false);
2436     // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2437     GC3Dint activeUniforms = 0;
2438     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2439     for (GC3Dint i = 0; i < activeUniforms; i++) {
2440         ActiveInfo info;
2441         if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2442             return WebGLGetInfo();
2443         // Strip "[0]" from the name if it's an array.
2444         if (info.size > 1 && info.name.endsWith("[0]"))
2445             info.name = info.name.left(info.name.length() - 3);
2446         // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2447         for (GC3Dint index = 0; index < info.size; ++index) {
2448             String name = info.name;
2449             if (info.size > 1 && index >= 1) {
2450                 name.append('[');
2451                 name.append(String::number(index));
2452                 name.append(']');
2453             }
2454             // Now need to look this up by name again to find its location
2455             GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name);
2456             if (loc == location) {
2457                 // Found it. Use the type in the ActiveInfo to determine the return type.
2458                 GC3Denum baseType;
2459                 unsigned int length;
2460                 switch (info.type) {
2461                 case GraphicsContext3D::BOOL:
2462                     baseType = GraphicsContext3D::BOOL;
2463                     length = 1;
2464                     break;
2465                 case GraphicsContext3D::BOOL_VEC2:
2466                     baseType = GraphicsContext3D::BOOL;
2467                     length = 2;
2468                     break;
2469                 case GraphicsContext3D::BOOL_VEC3:
2470                     baseType = GraphicsContext3D::BOOL;
2471                     length = 3;
2472                     break;
2473                 case GraphicsContext3D::BOOL_VEC4:
2474                     baseType = GraphicsContext3D::BOOL;
2475                     length = 4;
2476                     break;
2477                 case GraphicsContext3D::INT:
2478                     baseType = GraphicsContext3D::INT;
2479                     length = 1;
2480                     break;
2481                 case GraphicsContext3D::INT_VEC2:
2482                     baseType = GraphicsContext3D::INT;
2483                     length = 2;
2484                     break;
2485                 case GraphicsContext3D::INT_VEC3:
2486                     baseType = GraphicsContext3D::INT;
2487                     length = 3;
2488                     break;
2489                 case GraphicsContext3D::INT_VEC4:
2490                     baseType = GraphicsContext3D::INT;
2491                     length = 4;
2492                     break;
2493                 case GraphicsContext3D::FLOAT:
2494                     baseType = GraphicsContext3D::FLOAT;
2495                     length = 1;
2496                     break;
2497                 case GraphicsContext3D::FLOAT_VEC2:
2498                     baseType = GraphicsContext3D::FLOAT;
2499                     length = 2;
2500                     break;
2501                 case GraphicsContext3D::FLOAT_VEC3:
2502                     baseType = GraphicsContext3D::FLOAT;
2503                     length = 3;
2504                     break;
2505                 case GraphicsContext3D::FLOAT_VEC4:
2506                     baseType = GraphicsContext3D::FLOAT;
2507                     length = 4;
2508                     break;
2509                 case GraphicsContext3D::FLOAT_MAT2:
2510                     baseType = GraphicsContext3D::FLOAT;
2511                     length = 4;
2512                     break;
2513                 case GraphicsContext3D::FLOAT_MAT3:
2514                     baseType = GraphicsContext3D::FLOAT;
2515                     length = 9;
2516                     break;
2517                 case GraphicsContext3D::FLOAT_MAT4:
2518                     baseType = GraphicsContext3D::FLOAT;
2519                     length = 16;
2520                     break;
2521                 case GraphicsContext3D::SAMPLER_2D:
2522                 case GraphicsContext3D::SAMPLER_CUBE:
2523                     baseType = GraphicsContext3D::INT;
2524                     length = 1;
2525                     break;
2526                 default:
2527                     // Can't handle this type
2528                     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2529                     return WebGLGetInfo();
2530                 }
2531                 switch (baseType) {
2532                 case GraphicsContext3D::FLOAT: {
2533                     GC3Dfloat value[16] = {0};
2534                     m_context->getUniformfv(objectOrZero(program), location, value);
2535                     if (length == 1)
2536                         return WebGLGetInfo(value[0]);
2537                     return WebGLGetInfo(Float32Array::create(value, length));
2538                 }
2539                 case GraphicsContext3D::INT: {
2540                     GC3Dint value[4] = {0};
2541                     m_context->getUniformiv(objectOrZero(program), location, value);
2542                     if (length == 1)
2543                         return WebGLGetInfo(value[0]);
2544                     return WebGLGetInfo(Int32Array::create(value, length));
2545                 }
2546                 case GraphicsContext3D::BOOL: {
2547                     GC3Dint value[4] = {0};
2548                     m_context->getUniformiv(objectOrZero(program), location, value);
2549                     if (length > 1) {
2550                         bool boolValue[16] = {0};
2551                         for (unsigned j = 0; j < length; j++)
2552                             boolValue[j] = static_cast<bool>(value[j]);
2553                         return WebGLGetInfo(boolValue, length);
2554                     }
2555                     return WebGLGetInfo(static_cast<bool>(value[0]));
2556                 }
2557                 default:
2558                     notImplemented();
2559                 }
2560             }
2561         }
2562     }
2563     // If we get here, something went wrong in our unfortunately complex logic above
2564     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2565     return WebGLGetInfo();
2566 }
2567 
getUniformLocation(WebGLProgram * program,const String & name,ExceptionCode & ec)2568 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
2569 {
2570     UNUSED_PARAM(ec);
2571     if (isContextLost() || !validateWebGLObject(program))
2572         return 0;
2573     if (!validateString(name))
2574         return 0;
2575     WebGLStateRestorer(this, false);
2576     GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2577     if (uniformLocation == -1)
2578         return 0;
2579     return WebGLUniformLocation::create(program, uniformLocation);
2580 }
2581 
getVertexAttrib(GC3Duint index,GC3Denum pname,ExceptionCode & ec)2582 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
2583 {
2584     UNUSED_PARAM(ec);
2585     if (isContextLost())
2586         return WebGLGetInfo();
2587     WebGLStateRestorer(this, false);
2588     if (index >= m_maxVertexAttribs) {
2589         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2590         return WebGLGetInfo();
2591     }
2592     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2593     switch (pname) {
2594     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2595         if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
2596             || !state.bufferBinding
2597             || !state.bufferBinding->object())
2598             return WebGLGetInfo();
2599         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
2600     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
2601         return WebGLGetInfo(state.enabled);
2602     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
2603         return WebGLGetInfo(state.normalized);
2604     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
2605         return WebGLGetInfo(state.size);
2606     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
2607         return WebGLGetInfo(state.originalStride);
2608     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
2609         return WebGLGetInfo(state.type);
2610     case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
2611         return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
2612     default:
2613         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2614         return WebGLGetInfo();
2615     }
2616 }
2617 
getVertexAttribOffset(GC3Duint index,GC3Denum pname)2618 GC3Dsizeiptr WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
2619 {
2620     if (isContextLost())
2621         return 0;
2622     GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
2623     cleanupAfterGraphicsCall(false);
2624     return result;
2625 }
2626 
hint(GC3Denum target,GC3Denum mode)2627 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
2628 {
2629     if (isContextLost())
2630         return;
2631     bool isValid = false;
2632     switch (target) {
2633     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2634         isValid = true;
2635         break;
2636     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2637         if (m_oesStandardDerivatives)
2638             isValid = true;
2639         break;
2640     }
2641     if (!isValid) {
2642         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2643         return;
2644     }
2645     m_context->hint(target, mode);
2646     cleanupAfterGraphicsCall(false);
2647 }
2648 
isBuffer(WebGLBuffer * buffer)2649 GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
2650 {
2651     if (!buffer || isContextLost())
2652         return 0;
2653 
2654     if (!buffer->hasEverBeenBound())
2655         return 0;
2656 
2657     return m_context->isBuffer(buffer->object());
2658 }
2659 
isContextLost()2660 bool WebGLRenderingContext::isContextLost()
2661 {
2662     if (m_restoreTimer.isActive())
2663         return true;
2664 
2665     bool newContextLost = m_context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR;
2666 
2667     if (newContextLost != m_contextLost)
2668         m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
2669 
2670     return m_contextLost;
2671 }
2672 
isEnabled(GC3Denum cap)2673 GC3Dboolean WebGLRenderingContext::isEnabled(GC3Denum cap)
2674 {
2675     if (!validateCapability(cap) || isContextLost())
2676         return 0;
2677     return m_context->isEnabled(cap);
2678 }
2679 
isFramebuffer(WebGLFramebuffer * framebuffer)2680 GC3Dboolean WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer)
2681 {
2682     if (!framebuffer || isContextLost())
2683         return 0;
2684 
2685     if (!framebuffer->hasEverBeenBound())
2686         return 0;
2687 
2688     return m_context->isFramebuffer(framebuffer->object());
2689 }
2690 
isProgram(WebGLProgram * program)2691 GC3Dboolean WebGLRenderingContext::isProgram(WebGLProgram* program)
2692 {
2693     if (!program || isContextLost())
2694         return 0;
2695 
2696     return m_context->isProgram(program->object());
2697 }
2698 
isRenderbuffer(WebGLRenderbuffer * renderbuffer)2699 GC3Dboolean WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2700 {
2701     if (!renderbuffer || isContextLost())
2702         return 0;
2703 
2704     if (!renderbuffer->hasEverBeenBound())
2705         return 0;
2706 
2707     return m_context->isRenderbuffer(renderbuffer->object());
2708 }
2709 
isShader(WebGLShader * shader)2710 GC3Dboolean WebGLRenderingContext::isShader(WebGLShader* shader)
2711 {
2712     if (!shader || isContextLost())
2713         return 0;
2714 
2715     return m_context->isShader(shader->object());
2716 }
2717 
isTexture(WebGLTexture * texture)2718 GC3Dboolean WebGLRenderingContext::isTexture(WebGLTexture* texture)
2719 {
2720     if (!texture || isContextLost())
2721         return 0;
2722 
2723     if (!texture->hasEverBeenBound())
2724         return 0;
2725 
2726     return m_context->isTexture(texture->object());
2727 }
2728 
lineWidth(GC3Dfloat width)2729 void WebGLRenderingContext::lineWidth(GC3Dfloat width)
2730 {
2731     if (isContextLost())
2732         return;
2733     m_context->lineWidth(width);
2734     cleanupAfterGraphicsCall(false);
2735 }
2736 
linkProgram(WebGLProgram * program,ExceptionCode & ec)2737 void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec)
2738 {
2739     UNUSED_PARAM(ec);
2740     if (isContextLost() || !validateWebGLObject(program))
2741         return;
2742     if (!isGLES2Compliant()) {
2743         if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
2744             program->setLinkStatus(false);
2745             return;
2746         }
2747     }
2748 
2749     m_context->linkProgram(objectOrZero(program));
2750     program->increaseLinkCount();
2751     // cache link status
2752     GC3Dint value = 0;
2753     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::LINK_STATUS, &value);
2754     program->setLinkStatus(static_cast<bool>(value));
2755     // Need to cache link status before caching active attribute locations.
2756     program->cacheActiveAttribLocations();
2757     cleanupAfterGraphicsCall(false);
2758 }
2759 
pixelStorei(GC3Denum pname,GC3Dint param)2760 void WebGLRenderingContext::pixelStorei(GC3Denum pname, GC3Dint param)
2761 {
2762     if (isContextLost())
2763         return;
2764     switch (pname) {
2765     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2766         m_unpackFlipY = param;
2767         break;
2768     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2769         m_unpackPremultiplyAlpha = param;
2770         break;
2771     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2772         if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
2773             m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
2774         else {
2775             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2776             return;
2777         }
2778         break;
2779     case GraphicsContext3D::PACK_ALIGNMENT:
2780     case GraphicsContext3D::UNPACK_ALIGNMENT:
2781         if (param == 1 || param == 2 || param == 4 || param == 8) {
2782             if (pname == GraphicsContext3D::PACK_ALIGNMENT)
2783                 m_packAlignment = param;
2784             else // GraphicsContext3D::UNPACK_ALIGNMENT:
2785                 m_unpackAlignment = param;
2786             m_context->pixelStorei(pname, param);
2787             cleanupAfterGraphicsCall(false);
2788         } else {
2789             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2790             return;
2791         }
2792         break;
2793     default:
2794         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2795         return;
2796     }
2797 }
2798 
polygonOffset(GC3Dfloat factor,GC3Dfloat units)2799 void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
2800 {
2801     if (isContextLost())
2802         return;
2803     m_context->polygonOffset(factor, units);
2804     cleanupAfterGraphicsCall(false);
2805 }
2806 
readPixels(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,ArrayBufferView * pixels,ExceptionCode & ec)2807 void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
2808 {
2809     if (isContextLost())
2810         return;
2811     if (!canvas()->originClean()) {
2812         ec = SECURITY_ERR;
2813         return;
2814     }
2815     // Validate input parameters.
2816     if (!pixels) {
2817         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2818         return;
2819     }
2820     switch (format) {
2821     case GraphicsContext3D::ALPHA:
2822     case GraphicsContext3D::RGB:
2823     case GraphicsContext3D::RGBA:
2824         break;
2825     default:
2826         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2827         return;
2828     }
2829     switch (type) {
2830     case GraphicsContext3D::UNSIGNED_BYTE:
2831     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
2832     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
2833     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
2834         break;
2835     default:
2836         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2837         return;
2838     }
2839     if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
2840         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2841         return;
2842     }
2843     // Validate array type against pixel type.
2844     if (!pixels->isUnsignedByteArray()) {
2845         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2846         return;
2847     }
2848     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
2849         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
2850         return;
2851     }
2852     // Calculate array size, taking into consideration of PACK_ALIGNMENT.
2853     unsigned int totalBytesRequired;
2854     unsigned int padding;
2855     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
2856     if (error != GraphicsContext3D::NO_ERROR) {
2857         m_context->synthesizeGLError(error);
2858         return;
2859     }
2860     if (pixels->byteLength() < totalBytesRequired) {
2861         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2862         return;
2863     }
2864     clearIfComposited();
2865     void* data = pixels->baseAddress();
2866     m_context->readPixels(x, y, width, height, format, type, data);
2867 #if OS(DARWIN)
2868     // FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
2869     // when alpha is off, readPixels should set alpha to 255 instead of 0.
2870     if (!m_context->getContextAttributes().alpha) {
2871         unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
2872         for (GC3Dsizei iy = 0; iy < height; ++iy) {
2873             for (GC3Dsizei ix = 0; ix < width; ++ix) {
2874                 pixels[3] = 255;
2875                 pixels += 4;
2876             }
2877             pixels += padding;
2878         }
2879     }
2880 #endif
2881     cleanupAfterGraphicsCall(false);
2882 }
2883 
releaseShaderCompiler()2884 void WebGLRenderingContext::releaseShaderCompiler()
2885 {
2886     if (isContextLost())
2887         return;
2888     m_context->releaseShaderCompiler();
2889     cleanupAfterGraphicsCall(false);
2890 }
2891 
renderbufferStorage(GC3Denum target,GC3Denum internalformat,GC3Dsizei width,GC3Dsizei height)2892 void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
2893 {
2894     if (isContextLost())
2895         return;
2896     if (target != GraphicsContext3D::RENDERBUFFER) {
2897         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2898         return;
2899     }
2900     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2901         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2902         return;
2903     }
2904     if (!validateSize(width, height))
2905         return;
2906     switch (internalformat) {
2907     case GraphicsContext3D::DEPTH_COMPONENT16:
2908     case GraphicsContext3D::RGBA4:
2909     case GraphicsContext3D::RGB5_A1:
2910     case GraphicsContext3D::RGB565:
2911     case GraphicsContext3D::STENCIL_INDEX8:
2912         m_context->renderbufferStorage(target, internalformat, width, height);
2913         m_renderbufferBinding->setInternalFormat(internalformat);
2914         m_renderbufferBinding->setIsValid(true);
2915         m_renderbufferBinding->setSize(width, height);
2916         cleanupAfterGraphicsCall(false);
2917         break;
2918     case GraphicsContext3D::DEPTH_STENCIL:
2919         if (isDepthStencilSupported()) {
2920             m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
2921             cleanupAfterGraphicsCall(false);
2922         }
2923         m_renderbufferBinding->setSize(width, height);
2924         m_renderbufferBinding->setIsValid(isDepthStencilSupported());
2925         m_renderbufferBinding->setInternalFormat(internalformat);
2926         break;
2927     default:
2928         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2929     }
2930 }
2931 
sampleCoverage(GC3Dfloat value,GC3Dboolean invert)2932 void WebGLRenderingContext::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
2933 {
2934     if (isContextLost())
2935         return;
2936     m_context->sampleCoverage(value, invert);
2937     cleanupAfterGraphicsCall(false);
2938 }
2939 
scissor(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height)2940 void WebGLRenderingContext::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
2941 {
2942     if (isContextLost())
2943         return;
2944     if (!validateSize(width, height))
2945         return;
2946     m_context->scissor(x, y, width, height);
2947     cleanupAfterGraphicsCall(false);
2948 }
2949 
shaderSource(WebGLShader * shader,const String & string,ExceptionCode & ec)2950 void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
2951 {
2952     UNUSED_PARAM(ec);
2953     if (isContextLost() || !validateWebGLObject(shader))
2954         return;
2955     String stringWithoutComments = StripComments(string).result();
2956     if (!validateString(stringWithoutComments))
2957         return;
2958     shader->setSource(string);
2959     m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
2960     cleanupAfterGraphicsCall(false);
2961 }
2962 
stencilFunc(GC3Denum func,GC3Dint ref,GC3Duint mask)2963 void WebGLRenderingContext::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
2964 {
2965     if (isContextLost())
2966         return;
2967     if (!validateStencilFunc(func))
2968         return;
2969     m_stencilFuncRef = ref;
2970     m_stencilFuncRefBack = ref;
2971     m_stencilFuncMask = mask;
2972     m_stencilFuncMaskBack = mask;
2973     m_context->stencilFunc(func, ref, mask);
2974     cleanupAfterGraphicsCall(false);
2975 }
2976 
stencilFuncSeparate(GC3Denum face,GC3Denum func,GC3Dint ref,GC3Duint mask)2977 void WebGLRenderingContext::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
2978 {
2979     if (isContextLost())
2980         return;
2981     if (!validateStencilFunc(func))
2982         return;
2983     switch (face) {
2984     case GraphicsContext3D::FRONT_AND_BACK:
2985         m_stencilFuncRef = ref;
2986         m_stencilFuncRefBack = ref;
2987         m_stencilFuncMask = mask;
2988         m_stencilFuncMaskBack = mask;
2989         break;
2990     case GraphicsContext3D::FRONT:
2991         m_stencilFuncRef = ref;
2992         m_stencilFuncMask = mask;
2993         break;
2994     case GraphicsContext3D::BACK:
2995         m_stencilFuncRefBack = ref;
2996         m_stencilFuncMaskBack = mask;
2997         break;
2998     default:
2999         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3000         return;
3001     }
3002     m_context->stencilFuncSeparate(face, func, ref, mask);
3003     cleanupAfterGraphicsCall(false);
3004 }
3005 
stencilMask(GC3Duint mask)3006 void WebGLRenderingContext::stencilMask(GC3Duint mask)
3007 {
3008     if (isContextLost())
3009         return;
3010     m_stencilMask = mask;
3011     m_stencilMaskBack = mask;
3012     m_context->stencilMask(mask);
3013     cleanupAfterGraphicsCall(false);
3014 }
3015 
stencilMaskSeparate(GC3Denum face,GC3Duint mask)3016 void WebGLRenderingContext::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
3017 {
3018     if (isContextLost())
3019         return;
3020     switch (face) {
3021     case GraphicsContext3D::FRONT_AND_BACK:
3022         m_stencilMask = mask;
3023         m_stencilMaskBack = mask;
3024         break;
3025     case GraphicsContext3D::FRONT:
3026         m_stencilMask = mask;
3027         break;
3028     case GraphicsContext3D::BACK:
3029         m_stencilMaskBack = mask;
3030         break;
3031     default:
3032         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3033         return;
3034     }
3035     m_context->stencilMaskSeparate(face, mask);
3036     cleanupAfterGraphicsCall(false);
3037 }
3038 
stencilOp(GC3Denum fail,GC3Denum zfail,GC3Denum zpass)3039 void WebGLRenderingContext::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3040 {
3041     if (isContextLost())
3042         return;
3043     m_context->stencilOp(fail, zfail, zpass);
3044     cleanupAfterGraphicsCall(false);
3045 }
3046 
stencilOpSeparate(GC3Denum face,GC3Denum fail,GC3Denum zfail,GC3Denum zpass)3047 void WebGLRenderingContext::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3048 {
3049     if (isContextLost())
3050         return;
3051     m_context->stencilOpSeparate(face, fail, zfail, zpass);
3052     cleanupAfterGraphicsCall(false);
3053 }
3054 
texImage2DBase(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Dsizei width,GC3Dsizei height,GC3Dint border,GC3Denum format,GC3Denum type,void * pixels,ExceptionCode & ec)3055 void WebGLRenderingContext::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3056                                            GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3057                                            GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3058 {
3059     // FIXME: For now we ignore any errors returned
3060     ec = 0;
3061     if (!validateTexFuncParameters(target, level, internalformat, width, height, border, format, type))
3062         return;
3063     WebGLTexture* tex = validateTextureBinding(target, true);
3064     if (!tex)
3065         return;
3066     if (!isGLES2NPOTStrict()) {
3067         if (level && WebGLTexture::isNPOT(width, height)) {
3068             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3069             return;
3070         }
3071     }
3072     if (!pixels && !isResourceSafe()) {
3073         bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
3074                                                          border, format, type, m_unpackAlignment);
3075         if (!succeed)
3076             return;
3077     } else {
3078         m_context->texImage2D(target, level, internalformat, width, height,
3079                               border, format, type, pixels);
3080     }
3081     tex->setLevelInfo(target, level, internalformat, width, height, type);
3082     cleanupAfterGraphicsCall(false);
3083 }
3084 
texImage2DImpl(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,Image * image,bool flipY,bool premultiplyAlpha,ExceptionCode & ec)3085 void WebGLRenderingContext::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3086                                            GC3Denum format, GC3Denum type, Image* image,
3087                                            bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3088 {
3089     ec = 0;
3090     Vector<uint8_t> data;
3091     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3092         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3093         return;
3094     }
3095     if (m_unpackAlignment != 1)
3096         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3097     texImage2DBase(target, level, internalformat, image->width(), image->height(), 0,
3098                    format, type, data.data(), ec);
3099     if (m_unpackAlignment != 1)
3100         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3101 }
3102 
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Dsizei width,GC3Dsizei height,GC3Dint border,GC3Denum format,GC3Denum type,ArrayBufferView * pixels,ExceptionCode & ec)3103 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3104                                        GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3105                                        GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3106 {
3107     if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
3108         return;
3109     void* data = pixels ? pixels->baseAddress() : 0;
3110     Vector<uint8_t> tempData;
3111     bool changeUnpackAlignment = false;
3112     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3113         if (!m_context->extractTextureData(width, height, format, type,
3114                                            m_unpackAlignment,
3115                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3116                                            data,
3117                                            tempData))
3118             return;
3119         data = tempData.data();
3120         changeUnpackAlignment = true;
3121     }
3122     if (changeUnpackAlignment)
3123         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3124     texImage2DBase(target, level, internalformat, width, height, border,
3125                    format, type, data, ec);
3126     if (changeUnpackAlignment)
3127         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3128 }
3129 
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,ImageData * pixels,ExceptionCode & ec)3130 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3131                                        GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3132 {
3133     ec = 0;
3134     if (isContextLost())
3135         return;
3136     Vector<uint8_t> data;
3137     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3138         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3139         return;
3140     }
3141     if (m_unpackAlignment != 1)
3142         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3143     texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0,
3144                    format, type, data.data(), ec);
3145     if (m_unpackAlignment != 1)
3146         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3147 }
3148 
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,HTMLImageElement * image,ExceptionCode & ec)3149 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3150                                        GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3151 {
3152     ec = 0;
3153     if (isContextLost())
3154         return;
3155     if (!validateHTMLImageElement(image))
3156         return;
3157     checkOrigin(image);
3158     texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->image(),
3159                    m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3160 }
3161 
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,HTMLCanvasElement * canvas,ExceptionCode & ec)3162 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3163                                        GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3164 {
3165     ec = 0;
3166     if (isContextLost())
3167         return;
3168     if (!canvas || !canvas->buffer()) {
3169         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3170         return;
3171     }
3172     checkOrigin(canvas);
3173     RefPtr<ImageData> imageData = canvas->getImageData();
3174     if (imageData)
3175         texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
3176     else
3177         texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(),
3178                        m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3179 }
3180 
3181 #if ENABLE(VIDEO)
videoFrameToImage(HTMLVideoElement * video)3182 PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video)
3183 {
3184     if (!video || !video->videoWidth() || !video->videoHeight()) {
3185         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3186         return 0;
3187     }
3188     IntSize size(video->videoWidth(), video->videoHeight());
3189     ImageBuffer* buf = m_videoCache.imageBuffer(size);
3190     if (!buf) {
3191         m_context->synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY);
3192         return 0;
3193     }
3194     checkOrigin(video);
3195     IntRect destRect(0, 0, size.width(), size.height());
3196     // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
3197     video->paintCurrentFrameInContext(buf->context(), destRect);
3198     return buf->copyImage();
3199 }
3200 
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,HTMLVideoElement * video,ExceptionCode & ec)3201 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3202                                        GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3203 {
3204     ec = 0;
3205     if (isContextLost())
3206         return;
3207     RefPtr<Image> image = videoFrameToImage(video);
3208     if (!video)
3209         return;
3210     texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3211 }
3212 #endif
3213 
texParameter(GC3Denum target,GC3Denum pname,GC3Dfloat paramf,GC3Dint parami,bool isFloat)3214 void WebGLRenderingContext::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
3215 {
3216     if (isContextLost())
3217         return;
3218     WebGLTexture* tex = validateTextureBinding(target, false);
3219     if (!tex)
3220         return;
3221     switch (pname) {
3222     case GraphicsContext3D::TEXTURE_MIN_FILTER:
3223     case GraphicsContext3D::TEXTURE_MAG_FILTER:
3224         break;
3225     case GraphicsContext3D::TEXTURE_WRAP_S:
3226     case GraphicsContext3D::TEXTURE_WRAP_T:
3227         if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT)
3228             || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) {
3229             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3230             return;
3231         }
3232         break;
3233     default:
3234         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3235         return;
3236     }
3237     if (isFloat) {
3238         tex->setParameterf(pname, paramf);
3239         m_context->texParameterf(target, pname, paramf);
3240     } else {
3241         tex->setParameteri(pname, parami);
3242         m_context->texParameteri(target, pname, parami);
3243     }
3244     cleanupAfterGraphicsCall(false);
3245 }
3246 
texParameterf(GC3Denum target,GC3Denum pname,GC3Dfloat param)3247 void WebGLRenderingContext::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
3248 {
3249     texParameter(target, pname, param, 0, true);
3250 }
3251 
texParameteri(GC3Denum target,GC3Denum pname,GC3Dint param)3252 void WebGLRenderingContext::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
3253 {
3254     texParameter(target, pname, 0, param, false);
3255 }
3256 
texSubImage2DBase(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,void * pixels,ExceptionCode & ec)3257 void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3258                                               GC3Dsizei width, GC3Dsizei height,
3259                                               GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3260 {
3261     // FIXME: For now we ignore any errors returned
3262     ec = 0;
3263     if (isContextLost())
3264         return;
3265     if (!validateTexFuncParameters(target, level, format, width, height, 0, format, type))
3266         return;
3267     if (!validateSize(xoffset, yoffset))
3268         return;
3269     WebGLTexture* tex = validateTextureBinding(target, true);
3270     if (!tex)
3271         return;
3272     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
3273         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3274         return;
3275     }
3276     if (tex->getInternalFormat(target, level) != format || tex->getType(target, level) != type) {
3277         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3278         return;
3279     }
3280     m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
3281     cleanupAfterGraphicsCall(false);
3282 }
3283 
texSubImage2DImpl(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,Image * image,bool flipY,bool premultiplyAlpha,ExceptionCode & ec)3284 void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3285                                               GC3Denum format, GC3Denum type,
3286                                               Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3287 {
3288     ec = 0;
3289     if (isContextLost())
3290         return;
3291     Vector<uint8_t> data;
3292     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3293         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3294         return;
3295     }
3296     texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(),
3297                       format, type, data.data(), ec);
3298 }
3299 
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,ArrayBufferView * pixels,ExceptionCode & ec)3300 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3301                                           GC3Dsizei width, GC3Dsizei height,
3302                                           GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3303 {
3304     if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
3305         return;
3306     void* data = pixels ? pixels->baseAddress() : 0;
3307     Vector<uint8_t> tempData;
3308     bool changeUnpackAlignment = false;
3309     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3310         if (!m_context->extractTextureData(width, height, format, type,
3311                                            m_unpackAlignment,
3312                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
3313                                            data,
3314                                            tempData))
3315             return;
3316         data = tempData.data();
3317         changeUnpackAlignment = true;
3318     }
3319     if (changeUnpackAlignment)
3320         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3321     texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
3322     if (changeUnpackAlignment)
3323         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3324 }
3325 
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,ImageData * pixels,ExceptionCode & ec)3326 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3327                                           GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3328 {
3329     ec = 0;
3330     if (isContextLost())
3331         return;
3332     Vector<uint8_t> data;
3333     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3334         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3335         return;
3336     }
3337     texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(),
3338                       format, type, data.data(), ec);
3339 }
3340 
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,HTMLImageElement * image,ExceptionCode & ec)3341 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3342                                           GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3343 {
3344     ec = 0;
3345     if (isContextLost())
3346         return;
3347     if (!validateHTMLImageElement(image))
3348         return;
3349     checkOrigin(image);
3350     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image->cachedImage()->image(),
3351                       m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3352 }
3353 
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,HTMLCanvasElement * canvas,ExceptionCode & ec)3354 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3355                                           GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3356 {
3357     ec = 0;
3358     if (isContextLost())
3359         return;
3360     if (!canvas || !canvas->buffer()) {
3361         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3362         return;
3363     }
3364     checkOrigin(canvas);
3365     RefPtr<ImageData> imageData = canvas->getImageData();
3366     if (imageData)
3367         texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec);
3368     else
3369         texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(),
3370                           m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3371 }
3372 
3373 #if ENABLE(VIDEO)
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,HTMLVideoElement * video,ExceptionCode & ec)3374 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3375                                           GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3376 {
3377     ec = 0;
3378     if (isContextLost())
3379         return;
3380     RefPtr<Image> image = videoFrameToImage(video);
3381     if (!video)
3382         return;
3383     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3384 }
3385 #endif
3386 
uniform1f(const WebGLUniformLocation * location,GC3Dfloat x,ExceptionCode & ec)3387 void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode& ec)
3388 {
3389     UNUSED_PARAM(ec);
3390     if (isContextLost() || !location)
3391         return;
3392 
3393     if (location->program() != m_currentProgram) {
3394         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3395         return;
3396     }
3397 
3398     m_context->uniform1f(location->location(), x);
3399     cleanupAfterGraphicsCall(false);
3400 }
3401 
uniform1fv(const WebGLUniformLocation * location,Float32Array * v,ExceptionCode & ec)3402 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3403 {
3404     UNUSED_PARAM(ec);
3405     if (isContextLost() || !validateUniformParameters(location, v, 1))
3406         return;
3407 
3408     m_context->uniform1fv(location->location(), v->data(), v->length());
3409     cleanupAfterGraphicsCall(false);
3410 }
3411 
uniform1fv(const WebGLUniformLocation * location,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3412 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3413 {
3414     UNUSED_PARAM(ec);
3415     if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3416         return;
3417 
3418     m_context->uniform1fv(location->location(), v, size);
3419     cleanupAfterGraphicsCall(false);
3420 }
3421 
uniform1i(const WebGLUniformLocation * location,GC3Dint x,ExceptionCode & ec)3422 void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode& ec)
3423 {
3424     UNUSED_PARAM(ec);
3425     if (isContextLost() || !location)
3426         return;
3427 
3428     if (location->program() != m_currentProgram) {
3429         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3430         return;
3431     }
3432 
3433     m_context->uniform1i(location->location(), x);
3434     cleanupAfterGraphicsCall(false);
3435 }
3436 
uniform1iv(const WebGLUniformLocation * location,Int32Array * v,ExceptionCode & ec)3437 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3438 {
3439     UNUSED_PARAM(ec);
3440     if (isContextLost() || !validateUniformParameters(location, v, 1))
3441         return;
3442 
3443     m_context->uniform1iv(location->location(), v->data(), v->length());
3444     cleanupAfterGraphicsCall(false);
3445 }
3446 
uniform1iv(const WebGLUniformLocation * location,GC3Dint * v,GC3Dsizei size,ExceptionCode & ec)3447 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3448 {
3449     UNUSED_PARAM(ec);
3450     if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3451         return;
3452 
3453     m_context->uniform1iv(location->location(), v, size);
3454     cleanupAfterGraphicsCall(false);
3455 }
3456 
uniform2f(const WebGLUniformLocation * location,GC3Dfloat x,GC3Dfloat y,ExceptionCode & ec)3457 void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode& ec)
3458 {
3459     UNUSED_PARAM(ec);
3460     if (isContextLost() || !location)
3461         return;
3462 
3463     if (location->program() != m_currentProgram) {
3464         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3465         return;
3466     }
3467 
3468     m_context->uniform2f(location->location(), x, y);
3469     cleanupAfterGraphicsCall(false);
3470 }
3471 
uniform2fv(const WebGLUniformLocation * location,Float32Array * v,ExceptionCode & ec)3472 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3473 {
3474     UNUSED_PARAM(ec);
3475     if (isContextLost() || !validateUniformParameters(location, v, 2))
3476         return;
3477 
3478     m_context->uniform2fv(location->location(), v->data(), v->length() / 2);
3479     cleanupAfterGraphicsCall(false);
3480 }
3481 
uniform2fv(const WebGLUniformLocation * location,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3482 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3483 {
3484     UNUSED_PARAM(ec);
3485     if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3486         return;
3487 
3488     m_context->uniform2fv(location->location(), v, size / 2);
3489     cleanupAfterGraphicsCall(false);
3490 }
3491 
uniform2i(const WebGLUniformLocation * location,GC3Dint x,GC3Dint y,ExceptionCode & ec)3492 void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode& ec)
3493 {
3494     UNUSED_PARAM(ec);
3495     if (isContextLost() || !location)
3496         return;
3497 
3498     if (location->program() != m_currentProgram) {
3499         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3500         return;
3501     }
3502 
3503     m_context->uniform2i(location->location(), x, y);
3504     cleanupAfterGraphicsCall(false);
3505 }
3506 
uniform2iv(const WebGLUniformLocation * location,Int32Array * v,ExceptionCode & ec)3507 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3508 {
3509     UNUSED_PARAM(ec);
3510     if (isContextLost() || !validateUniformParameters(location, v, 2))
3511         return;
3512 
3513     m_context->uniform2iv(location->location(), v->data(), v->length() / 2);
3514     cleanupAfterGraphicsCall(false);
3515 }
3516 
uniform2iv(const WebGLUniformLocation * location,GC3Dint * v,GC3Dsizei size,ExceptionCode & ec)3517 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3518 {
3519     UNUSED_PARAM(ec);
3520     if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3521         return;
3522 
3523     m_context->uniform2iv(location->location(), v, size / 2);
3524     cleanupAfterGraphicsCall(false);
3525 }
3526 
uniform3f(const WebGLUniformLocation * location,GC3Dfloat x,GC3Dfloat y,GC3Dfloat z,ExceptionCode & ec)3527 void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode& ec)
3528 {
3529     UNUSED_PARAM(ec);
3530     if (isContextLost() || !location)
3531         return;
3532 
3533     if (location->program() != m_currentProgram) {
3534         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3535         return;
3536     }
3537 
3538     m_context->uniform3f(location->location(), x, y, z);
3539     cleanupAfterGraphicsCall(false);
3540 }
3541 
uniform3fv(const WebGLUniformLocation * location,Float32Array * v,ExceptionCode & ec)3542 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3543 {
3544     UNUSED_PARAM(ec);
3545     if (isContextLost() || !validateUniformParameters(location, v, 3))
3546         return;
3547 
3548     m_context->uniform3fv(location->location(), v->data(), v->length() / 3);
3549     cleanupAfterGraphicsCall(false);
3550 }
3551 
uniform3fv(const WebGLUniformLocation * location,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3552 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3553 {
3554     UNUSED_PARAM(ec);
3555     if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3556         return;
3557 
3558     m_context->uniform3fv(location->location(), v, size / 3);
3559     cleanupAfterGraphicsCall(false);
3560 }
3561 
uniform3i(const WebGLUniformLocation * location,GC3Dint x,GC3Dint y,GC3Dint z,ExceptionCode & ec)3562 void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode& ec)
3563 {
3564     UNUSED_PARAM(ec);
3565     if (isContextLost() || !location)
3566         return;
3567 
3568     if (location->program() != m_currentProgram) {
3569         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3570         return;
3571     }
3572 
3573     m_context->uniform3i(location->location(), x, y, z);
3574     cleanupAfterGraphicsCall(false);
3575 }
3576 
uniform3iv(const WebGLUniformLocation * location,Int32Array * v,ExceptionCode & ec)3577 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3578 {
3579     UNUSED_PARAM(ec);
3580     if (isContextLost() || !validateUniformParameters(location, v, 3))
3581         return;
3582 
3583     m_context->uniform3iv(location->location(), v->data(), v->length() / 3);
3584     cleanupAfterGraphicsCall(false);
3585 }
3586 
uniform3iv(const WebGLUniformLocation * location,GC3Dint * v,GC3Dsizei size,ExceptionCode & ec)3587 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3588 {
3589     UNUSED_PARAM(ec);
3590     if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3591         return;
3592 
3593     m_context->uniform3iv(location->location(), v, size / 3);
3594     cleanupAfterGraphicsCall(false);
3595 }
3596 
uniform4f(const WebGLUniformLocation * location,GC3Dfloat x,GC3Dfloat y,GC3Dfloat z,GC3Dfloat w,ExceptionCode & ec)3597 void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode& ec)
3598 {
3599     UNUSED_PARAM(ec);
3600     if (isContextLost() || !location)
3601         return;
3602 
3603     if (location->program() != m_currentProgram) {
3604         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3605         return;
3606     }
3607 
3608     m_context->uniform4f(location->location(), x, y, z, w);
3609     cleanupAfterGraphicsCall(false);
3610 }
3611 
uniform4fv(const WebGLUniformLocation * location,Float32Array * v,ExceptionCode & ec)3612 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3613 {
3614     UNUSED_PARAM(ec);
3615     if (isContextLost() || !validateUniformParameters(location, v, 4))
3616         return;
3617 
3618     m_context->uniform4fv(location->location(), v->data(), v->length() / 4);
3619     cleanupAfterGraphicsCall(false);
3620 }
3621 
uniform4fv(const WebGLUniformLocation * location,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3622 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3623 {
3624     UNUSED_PARAM(ec);
3625     if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3626         return;
3627 
3628     m_context->uniform4fv(location->location(), v, size / 4);
3629     cleanupAfterGraphicsCall(false);
3630 }
3631 
uniform4i(const WebGLUniformLocation * location,GC3Dint x,GC3Dint y,GC3Dint z,GC3Dint w,ExceptionCode & ec)3632 void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode& ec)
3633 {
3634     UNUSED_PARAM(ec);
3635     if (isContextLost() || !location)
3636         return;
3637 
3638     if (location->program() != m_currentProgram) {
3639         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3640         return;
3641     }
3642 
3643     m_context->uniform4i(location->location(), x, y, z, w);
3644     cleanupAfterGraphicsCall(false);
3645 }
3646 
uniform4iv(const WebGLUniformLocation * location,Int32Array * v,ExceptionCode & ec)3647 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3648 {
3649     UNUSED_PARAM(ec);
3650     if (isContextLost() || !validateUniformParameters(location, v, 4))
3651         return;
3652 
3653     m_context->uniform4iv(location->location(), v->data(), v->length() / 4);
3654     cleanupAfterGraphicsCall(false);
3655 }
3656 
uniform4iv(const WebGLUniformLocation * location,GC3Dint * v,GC3Dsizei size,ExceptionCode & ec)3657 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3658 {
3659     UNUSED_PARAM(ec);
3660     if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3661         return;
3662 
3663     m_context->uniform4iv(location->location(), v, size / 4);
3664     cleanupAfterGraphicsCall(false);
3665 }
3666 
uniformMatrix2fv(const WebGLUniformLocation * location,GC3Dboolean transpose,Float32Array * v,ExceptionCode & ec)3667 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3668 {
3669     UNUSED_PARAM(ec);
3670     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 4))
3671         return;
3672     m_context->uniformMatrix2fv(location->location(), transpose, v->data(), v->length() / 4);
3673     cleanupAfterGraphicsCall(false);
3674 }
3675 
uniformMatrix2fv(const WebGLUniformLocation * location,GC3Dboolean transpose,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3676 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3677 {
3678     UNUSED_PARAM(ec);
3679     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 4))
3680         return;
3681     m_context->uniformMatrix2fv(location->location(), transpose, v, size / 4);
3682     cleanupAfterGraphicsCall(false);
3683 }
3684 
uniformMatrix3fv(const WebGLUniformLocation * location,GC3Dboolean transpose,Float32Array * v,ExceptionCode & ec)3685 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3686 {
3687     UNUSED_PARAM(ec);
3688     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 9))
3689         return;
3690     m_context->uniformMatrix3fv(location->location(), transpose, v->data(), v->length() / 9);
3691     cleanupAfterGraphicsCall(false);
3692 }
3693 
uniformMatrix3fv(const WebGLUniformLocation * location,GC3Dboolean transpose,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3694 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3695 {
3696     UNUSED_PARAM(ec);
3697     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 9))
3698         return;
3699     m_context->uniformMatrix3fv(location->location(), transpose, v, size / 9);
3700     cleanupAfterGraphicsCall(false);
3701 }
3702 
uniformMatrix4fv(const WebGLUniformLocation * location,GC3Dboolean transpose,Float32Array * v,ExceptionCode & ec)3703 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3704 {
3705     UNUSED_PARAM(ec);
3706     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 16))
3707         return;
3708     m_context->uniformMatrix4fv(location->location(), transpose, v->data(), v->length() / 16);
3709     cleanupAfterGraphicsCall(false);
3710 }
3711 
uniformMatrix4fv(const WebGLUniformLocation * location,GC3Dboolean transpose,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3712 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3713 {
3714     UNUSED_PARAM(ec);
3715     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 16))
3716         return;
3717     m_context->uniformMatrix4fv(location->location(), transpose, v, size / 16);
3718     cleanupAfterGraphicsCall(false);
3719 }
3720 
useProgram(WebGLProgram * program,ExceptionCode & ec)3721 void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
3722 {
3723     UNUSED_PARAM(ec);
3724     bool deleted;
3725     if (!checkObjectToBeBound(program, deleted))
3726         return;
3727     if (deleted)
3728         program = 0;
3729     if (program && !program->getLinkStatus()) {
3730         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3731         cleanupAfterGraphicsCall(false);
3732         return;
3733     }
3734     if (m_currentProgram != program) {
3735         if (m_currentProgram)
3736             m_currentProgram->onDetached();
3737         m_currentProgram = program;
3738         m_context->useProgram(objectOrZero(program));
3739         if (program)
3740             program->onAttached();
3741     }
3742     cleanupAfterGraphicsCall(false);
3743 }
3744 
validateProgram(WebGLProgram * program,ExceptionCode & ec)3745 void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec)
3746 {
3747     UNUSED_PARAM(ec);
3748     if (isContextLost() || !validateWebGLObject(program))
3749         return;
3750     m_context->validateProgram(objectOrZero(program));
3751     cleanupAfterGraphicsCall(false);
3752 }
3753 
vertexAttrib1f(GC3Duint index,GC3Dfloat v0)3754 void WebGLRenderingContext::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
3755 {
3756     vertexAttribfImpl(index, 1, v0, 0.0f, 0.0f, 1.0f);
3757 }
3758 
vertexAttrib1fv(GC3Duint index,Float32Array * v)3759 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, Float32Array* v)
3760 {
3761     vertexAttribfvImpl(index, v, 1);
3762 }
3763 
vertexAttrib1fv(GC3Duint index,GC3Dfloat * v,GC3Dsizei size)3764 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3765 {
3766     vertexAttribfvImpl(index, v, size, 1);
3767 }
3768 
vertexAttrib2f(GC3Duint index,GC3Dfloat v0,GC3Dfloat v1)3769 void WebGLRenderingContext::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
3770 {
3771     vertexAttribfImpl(index, 2, v0, v1, 0.0f, 1.0f);
3772 }
3773 
vertexAttrib2fv(GC3Duint index,Float32Array * v)3774 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, Float32Array* v)
3775 {
3776     vertexAttribfvImpl(index, v, 2);
3777 }
3778 
vertexAttrib2fv(GC3Duint index,GC3Dfloat * v,GC3Dsizei size)3779 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3780 {
3781     vertexAttribfvImpl(index, v, size, 2);
3782 }
3783 
vertexAttrib3f(GC3Duint index,GC3Dfloat v0,GC3Dfloat v1,GC3Dfloat v2)3784 void WebGLRenderingContext::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
3785 {
3786     vertexAttribfImpl(index, 3, v0, v1, v2, 1.0f);
3787 }
3788 
vertexAttrib3fv(GC3Duint index,Float32Array * v)3789 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, Float32Array* v)
3790 {
3791     vertexAttribfvImpl(index, v, 3);
3792 }
3793 
vertexAttrib3fv(GC3Duint index,GC3Dfloat * v,GC3Dsizei size)3794 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3795 {
3796     vertexAttribfvImpl(index, v, size, 3);
3797 }
3798 
vertexAttrib4f(GC3Duint index,GC3Dfloat v0,GC3Dfloat v1,GC3Dfloat v2,GC3Dfloat v3)3799 void WebGLRenderingContext::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
3800 {
3801     vertexAttribfImpl(index, 4, v0, v1, v2, v3);
3802 }
3803 
vertexAttrib4fv(GC3Duint index,Float32Array * v)3804 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, Float32Array* v)
3805 {
3806     vertexAttribfvImpl(index, v, 4);
3807 }
3808 
vertexAttrib4fv(GC3Duint index,GC3Dfloat * v,GC3Dsizei size)3809 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3810 {
3811     vertexAttribfvImpl(index, v, size, 4);
3812 }
3813 
vertexAttribPointer(GC3Duint index,GC3Dint size,GC3Denum type,GC3Dboolean normalized,GC3Dsizei stride,GC3Dintptr offset,ExceptionCode & ec)3814 void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset, ExceptionCode& ec)
3815 {
3816     UNUSED_PARAM(ec);
3817     if (isContextLost())
3818         return;
3819     switch (type) {
3820     case GraphicsContext3D::BYTE:
3821     case GraphicsContext3D::UNSIGNED_BYTE:
3822     case GraphicsContext3D::SHORT:
3823     case GraphicsContext3D::UNSIGNED_SHORT:
3824     case GraphicsContext3D::FLOAT:
3825         break;
3826     default:
3827         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3828         return;
3829     }
3830     if (index >= m_maxVertexAttribs) {
3831         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3832         return;
3833     }
3834     if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) {
3835         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3836         return;
3837     }
3838     if (!m_boundArrayBuffer) {
3839         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3840         return;
3841     }
3842     // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
3843     unsigned int typeSize = sizeInBytes(type);
3844     if (!typeSize) {
3845         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3846         return;
3847     }
3848     if ((stride % typeSize) || (offset % typeSize)) {
3849         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3850         return;
3851     }
3852     GC3Dsizei bytesPerElement = size * typeSize;
3853 
3854     GC3Dsizei validatedStride = stride ? stride : bytesPerElement;
3855 
3856     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
3857     state.bufferBinding = m_boundArrayBuffer;
3858     state.bytesPerElement = bytesPerElement;
3859     state.size = size;
3860     state.type = type;
3861     state.normalized = normalized;
3862     state.stride = validatedStride;
3863     state.originalStride = stride;
3864     state.offset = offset;
3865     m_context->vertexAttribPointer(index, size, type, normalized, stride, offset);
3866     cleanupAfterGraphicsCall(false);
3867 }
3868 
viewport(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height)3869 void WebGLRenderingContext::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
3870 {
3871     if (isContextLost())
3872         return;
3873     if (isnan(x))
3874         x = 0;
3875     if (isnan(y))
3876         y = 0;
3877     if (isnan(width))
3878         width = 100;
3879     if (isnan(height))
3880         height = 100;
3881     if (!validateSize(width, height))
3882         return;
3883     m_context->viewport(x, y, width, height);
3884     cleanupAfterGraphicsCall(false);
3885 }
3886 
forceLostContext()3887 void WebGLRenderingContext::forceLostContext()
3888 {
3889     if (isContextLost()) {
3890         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3891         return;
3892     }
3893 
3894     m_restoreTimer.startOneShot(0);
3895 }
3896 
onLostContext()3897 void WebGLRenderingContext::onLostContext()
3898 {
3899     m_contextLost = true;
3900 
3901     detachAndRemoveAllObjects();
3902 
3903     // There is no direct way to clear errors from a GL implementation and
3904     // looping until getError() becomes NO_ERROR might cause an infinite loop if
3905     // the driver or context implementation had a bug.  So, loop a reasonably
3906     // large number of times to clear any existing errors.
3907     for (int i = 0; i < 100; ++i) {
3908         if (m_context->getError() == GraphicsContext3D::NO_ERROR)
3909             break;
3910     }
3911     m_context->synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL);
3912 
3913     canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, ""));
3914 }
3915 
restoreContext()3916 void WebGLRenderingContext::restoreContext()
3917 {
3918     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, canvas()->document()->view()->root()->hostWindow()));
3919     if (!context)
3920         return;
3921 
3922     m_context = context;
3923     m_contextLost = false;
3924     initializeNewContext();
3925     canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, ""));
3926 }
3927 
removeObject(WebGLObject * object)3928 void WebGLRenderingContext::removeObject(WebGLObject* object)
3929 {
3930     m_canvasObjects.remove(object);
3931 }
3932 
addObject(WebGLObject * object)3933 void WebGLRenderingContext::addObject(WebGLObject* object)
3934 {
3935     ASSERT(!isContextLost());
3936     removeObject(object);
3937     m_canvasObjects.add(object);
3938 }
3939 
detachAndRemoveAllObjects()3940 void WebGLRenderingContext::detachAndRemoveAllObjects()
3941 {
3942     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3943     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it)
3944         (*it)->detachContext();
3945 
3946     m_canvasObjects.clear();
3947 }
3948 
findTexture(Platform3DObject obj)3949 WebGLTexture* WebGLRenderingContext::findTexture(Platform3DObject obj)
3950 {
3951     if (!obj)
3952         return 0;
3953     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3954     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3955         if ((*it)->isTexture() && (*it)->object() == obj)
3956             return reinterpret_cast<WebGLTexture*>((*it).get());
3957     }
3958     return 0;
3959 }
3960 
findRenderbuffer(Platform3DObject obj)3961 WebGLRenderbuffer* WebGLRenderingContext::findRenderbuffer(Platform3DObject obj)
3962 {
3963     if (!obj)
3964         return 0;
3965     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3966     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3967         if ((*it)->isRenderbuffer() && (*it)->object() == obj)
3968             return reinterpret_cast<WebGLRenderbuffer*>((*it).get());
3969     }
3970     return 0;
3971 }
3972 
findBuffer(Platform3DObject obj)3973 WebGLBuffer* WebGLRenderingContext::findBuffer(Platform3DObject obj)
3974 {
3975     if (!obj)
3976         return 0;
3977     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3978     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3979         if ((*it)->isBuffer() && (*it)->object() == obj)
3980             return reinterpret_cast<WebGLBuffer*>((*it).get());
3981     }
3982     return 0;
3983 }
3984 
findShader(Platform3DObject obj)3985 WebGLShader* WebGLRenderingContext::findShader(Platform3DObject obj)
3986 {
3987     if (!obj)
3988         return 0;
3989     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3990     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3991         if ((*it)->isShader() && (*it)->object() == obj)
3992             return reinterpret_cast<WebGLShader*>((*it).get());
3993     }
3994     return 0;
3995 }
3996 
getBooleanParameter(GC3Denum pname)3997 WebGLGetInfo WebGLRenderingContext::getBooleanParameter(GC3Denum pname)
3998 {
3999     GC3Dboolean value = 0;
4000     m_context->getBooleanv(pname, &value);
4001     return WebGLGetInfo(static_cast<bool>(value));
4002 }
4003 
getBooleanArrayParameter(GC3Denum pname)4004 WebGLGetInfo WebGLRenderingContext::getBooleanArrayParameter(GC3Denum pname)
4005 {
4006     if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
4007         notImplemented();
4008         return WebGLGetInfo(0, 0);
4009     }
4010     GC3Dboolean value[4] = {0};
4011     m_context->getBooleanv(pname, value);
4012     bool boolValue[4];
4013     for (int ii = 0; ii < 4; ++ii)
4014         boolValue[ii] = static_cast<bool>(value[ii]);
4015     return WebGLGetInfo(boolValue, 4);
4016 }
4017 
getFloatParameter(GC3Denum pname)4018 WebGLGetInfo WebGLRenderingContext::getFloatParameter(GC3Denum pname)
4019 {
4020     GC3Dfloat value = 0;
4021     m_context->getFloatv(pname, &value);
4022     return WebGLGetInfo(value);
4023 }
4024 
getIntParameter(GC3Denum pname)4025 WebGLGetInfo WebGLRenderingContext::getIntParameter(GC3Denum pname)
4026 {
4027     GC3Dint value = 0;
4028     m_context->getIntegerv(pname, &value);
4029     return WebGLGetInfo(value);
4030 }
4031 
getUnsignedIntParameter(GC3Denum pname)4032 WebGLGetInfo WebGLRenderingContext::getUnsignedIntParameter(GC3Denum pname)
4033 {
4034     GC3Dint value = 0;
4035     m_context->getIntegerv(pname, &value);
4036     return WebGLGetInfo(static_cast<unsigned int>(value));
4037 }
4038 
getWebGLFloatArrayParameter(GC3Denum pname)4039 WebGLGetInfo WebGLRenderingContext::getWebGLFloatArrayParameter(GC3Denum pname)
4040 {
4041     GC3Dfloat value[4] = {0};
4042     m_context->getFloatv(pname, value);
4043     unsigned length = 0;
4044     switch (pname) {
4045     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
4046     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
4047     case GraphicsContext3D::DEPTH_RANGE:
4048         length = 2;
4049         break;
4050     case GraphicsContext3D::BLEND_COLOR:
4051     case GraphicsContext3D::COLOR_CLEAR_VALUE:
4052         length = 4;
4053         break;
4054     default:
4055         notImplemented();
4056     }
4057     return WebGLGetInfo(Float32Array::create(value, length));
4058 }
4059 
getWebGLIntArrayParameter(GC3Denum pname)4060 WebGLGetInfo WebGLRenderingContext::getWebGLIntArrayParameter(GC3Denum pname)
4061 {
4062     GC3Dint value[4] = {0};
4063     m_context->getIntegerv(pname, value);
4064     unsigned length = 0;
4065     switch (pname) {
4066     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
4067         length = 2;
4068         break;
4069     case GraphicsContext3D::SCISSOR_BOX:
4070     case GraphicsContext3D::VIEWPORT:
4071         length = 4;
4072         break;
4073     default:
4074         notImplemented();
4075     }
4076     return WebGLGetInfo(Int32Array::create(value, length));
4077 }
4078 
handleNPOTTextures(bool prepareToDraw)4079 void WebGLRenderingContext::handleNPOTTextures(bool prepareToDraw)
4080 {
4081     bool resetActiveUnit = false;
4082     for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) {
4083         if ((m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4084             || (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())) {
4085             if (ii != m_activeTextureUnit) {
4086                 m_context->activeTexture(ii);
4087                 resetActiveUnit = true;
4088             } else if (resetActiveUnit) {
4089                 m_context->activeTexture(ii);
4090                 resetActiveUnit = false;
4091             }
4092             WebGLTexture* tex2D;
4093             WebGLTexture* texCubeMap;
4094             if (prepareToDraw) {
4095                 tex2D = m_blackTexture2D.get();
4096                 texCubeMap = m_blackTextureCubeMap.get();
4097             } else {
4098                 tex2D = m_textureUnits[ii].m_texture2DBinding.get();
4099                 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
4100             }
4101             if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4102                 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D));
4103             if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())
4104                 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
4105         }
4106     }
4107     if (resetActiveUnit)
4108         m_context->activeTexture(m_activeTextureUnit);
4109 }
4110 
createFallbackBlackTextures1x1()4111 void WebGLRenderingContext::createFallbackBlackTextures1x1()
4112 {
4113     unsigned char black[] = {0, 0, 0, 255};
4114     m_blackTexture2D = createTexture();
4115     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D->object());
4116     m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1,
4117                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4118     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
4119     m_blackTextureCubeMap = createTexture();
4120     m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
4121     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4122                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4123     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4124                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4125     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4126                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4127     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4128                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4129     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4130                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4131     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4132                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4133     m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0);
4134 }
4135 
isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,GC3Denum colorBufferFormat)4136 bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,
4137                                                                            GC3Denum colorBufferFormat)
4138 {
4139     switch (colorBufferFormat) {
4140     case GraphicsContext3D::ALPHA:
4141         if (texInternalFormat == GraphicsContext3D::ALPHA)
4142             return true;
4143         break;
4144     case GraphicsContext3D::RGB:
4145         if (texInternalFormat == GraphicsContext3D::LUMINANCE
4146             || texInternalFormat == GraphicsContext3D::RGB)
4147             return true;
4148         break;
4149     case GraphicsContext3D::RGBA:
4150         return true;
4151     }
4152     return false;
4153 }
4154 
getBoundFramebufferColorFormat()4155 GC3Denum WebGLRenderingContext::getBoundFramebufferColorFormat()
4156 {
4157     if (m_framebufferBinding && m_framebufferBinding->object())
4158         return m_framebufferBinding->getColorBufferFormat();
4159     if (m_attributes.alpha)
4160         return GraphicsContext3D::RGBA;
4161     return GraphicsContext3D::RGB;
4162 }
4163 
getBoundFramebufferWidth()4164 int WebGLRenderingContext::getBoundFramebufferWidth()
4165 {
4166     if (m_framebufferBinding && m_framebufferBinding->object())
4167         return m_framebufferBinding->getWidth();
4168     return m_context->getInternalFramebufferSize().width();
4169 }
4170 
getBoundFramebufferHeight()4171 int WebGLRenderingContext::getBoundFramebufferHeight()
4172 {
4173     if (m_framebufferBinding && m_framebufferBinding->object())
4174         return m_framebufferBinding->getHeight();
4175     return m_context->getInternalFramebufferSize().height();
4176 }
4177 
validateTextureBinding(GC3Denum target,bool useSixEnumsForCubeMap)4178 WebGLTexture* WebGLRenderingContext::validateTextureBinding(GC3Denum target, bool useSixEnumsForCubeMap)
4179 {
4180     WebGLTexture* tex = 0;
4181     switch (target) {
4182     case GraphicsContext3D::TEXTURE_2D:
4183         tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
4184         break;
4185     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4186     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4187     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4188     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4189     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4190     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4191         if (!useSixEnumsForCubeMap) {
4192             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4193             return 0;
4194         }
4195         tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4196         break;
4197     case GraphicsContext3D::TEXTURE_CUBE_MAP:
4198         if (useSixEnumsForCubeMap) {
4199             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4200             return 0;
4201         }
4202         tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4203         break;
4204     default:
4205         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4206         return 0;
4207     }
4208     if (!tex)
4209         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4210     return tex;
4211 }
4212 
validateSize(GC3Dint x,GC3Dint y)4213 bool WebGLRenderingContext::validateSize(GC3Dint x, GC3Dint y)
4214 {
4215     if (x < 0 || y < 0) {
4216         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4217         return false;
4218     }
4219     return true;
4220 }
4221 
validateString(const String & string)4222 bool WebGLRenderingContext::validateString(const String& string)
4223 {
4224     for (size_t i = 0; i < string.length(); ++i) {
4225         if (!validateCharacter(string[i])) {
4226             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4227             return false;
4228         }
4229     }
4230     return true;
4231 }
4232 
validateTexFuncFormatAndType(GC3Denum format,GC3Denum type)4233 bool WebGLRenderingContext::validateTexFuncFormatAndType(GC3Denum format, GC3Denum type)
4234 {
4235     switch (format) {
4236     case GraphicsContext3D::ALPHA:
4237     case GraphicsContext3D::LUMINANCE:
4238     case GraphicsContext3D::LUMINANCE_ALPHA:
4239     case GraphicsContext3D::RGB:
4240     case GraphicsContext3D::RGBA:
4241         break;
4242     default:
4243         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4244         return false;
4245     }
4246 
4247     switch (type) {
4248     case GraphicsContext3D::UNSIGNED_BYTE:
4249     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4250     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4251     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4252         break;
4253     case GraphicsContext3D::FLOAT:
4254         if (m_oesTextureFloat)
4255             break;
4256         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4257         return false;
4258     default:
4259         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4260         return false;
4261     }
4262 
4263     // Verify that the combination of format and type is supported.
4264     switch (format) {
4265     case GraphicsContext3D::ALPHA:
4266     case GraphicsContext3D::LUMINANCE:
4267     case GraphicsContext3D::LUMINANCE_ALPHA:
4268         if (type != GraphicsContext3D::UNSIGNED_BYTE
4269             && type != GraphicsContext3D::FLOAT) {
4270             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4271             return false;
4272         }
4273         break;
4274     case GraphicsContext3D::RGB:
4275         if (type != GraphicsContext3D::UNSIGNED_BYTE
4276             && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5
4277             && type != GraphicsContext3D::FLOAT) {
4278             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4279             return false;
4280         }
4281         break;
4282     case GraphicsContext3D::RGBA:
4283         if (type != GraphicsContext3D::UNSIGNED_BYTE
4284             && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4
4285             && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1
4286             && type != GraphicsContext3D::FLOAT) {
4287             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4288             return false;
4289         }
4290         break;
4291     default:
4292         ASSERT_NOT_REACHED();
4293     }
4294 
4295     return true;
4296 }
4297 
validateTexFuncLevel(GC3Denum target,GC3Dint level)4298 bool WebGLRenderingContext::validateTexFuncLevel(GC3Denum target, GC3Dint level)
4299 {
4300     if (level < 0) {
4301         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4302         return false;
4303     }
4304     switch (target) {
4305     case GraphicsContext3D::TEXTURE_2D:
4306         if (level > m_maxTextureLevel) {
4307             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4308             return false;
4309         }
4310         break;
4311     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4312     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4313     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4314     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4315     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4316     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4317         if (level > m_maxCubeMapTextureLevel) {
4318             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4319             return false;
4320         }
4321         break;
4322     }
4323     // This function only checks if level is legal, so we return true and don't
4324     // generate INVALID_ENUM if target is illegal.
4325     return true;
4326 }
4327 
validateTexFuncParameters(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Dsizei width,GC3Dsizei height,GC3Dint border,GC3Denum format,GC3Denum type)4328 bool WebGLRenderingContext::validateTexFuncParameters(GC3Denum target, GC3Dint level,
4329                                                       GC3Denum internalformat,
4330                                                       GC3Dsizei width, GC3Dsizei height, GC3Dint border,
4331                                                       GC3Denum format, GC3Denum type)
4332 {
4333     // We absolutely have to validate the format and type combination.
4334     // The texImage2D entry points taking HTMLImage, etc. will produce
4335     // temporary data based on this combination, so it must be legal.
4336     if (!validateTexFuncFormatAndType(format, type) || !validateTexFuncLevel(target, level))
4337         return false;
4338 
4339     if (width < 0 || height < 0) {
4340         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4341         return false;
4342     }
4343 
4344     switch (target) {
4345     case GraphicsContext3D::TEXTURE_2D:
4346         if (width > m_maxTextureSize || height > m_maxTextureSize) {
4347             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4348             return false;
4349         }
4350         break;
4351     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4352     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4353     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4354     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4355     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4356     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4357         if (width != height || width > m_maxCubeMapTextureSize) {
4358             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4359             return false;
4360         }
4361         break;
4362     default:
4363         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4364         return false;
4365     }
4366 
4367     if (format != internalformat) {
4368         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4369         return false;
4370     }
4371 
4372     if (border) {
4373         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4374         return false;
4375     }
4376 
4377     return true;
4378 }
4379 
validateTexFuncData(GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,ArrayBufferView * pixels)4380 bool WebGLRenderingContext::validateTexFuncData(GC3Dsizei width, GC3Dsizei height,
4381                                                 GC3Denum format, GC3Denum type,
4382                                                 ArrayBufferView* pixels)
4383 {
4384     if (!pixels)
4385         return true;
4386 
4387     if (!validateTexFuncFormatAndType(format, type))
4388         return false;
4389 
4390     switch (type) {
4391     case GraphicsContext3D::UNSIGNED_BYTE:
4392         if (!pixels->isUnsignedByteArray()) {
4393             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4394             return false;
4395         }
4396         break;
4397     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4398     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4399     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4400         if (!pixels->isUnsignedShortArray()) {
4401             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4402             return false;
4403         }
4404         break;
4405     case GraphicsContext3D::FLOAT: // OES_texture_float
4406         if (!pixels->isFloatArray()) {
4407             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4408             return false;
4409         }
4410         break;
4411     default:
4412         ASSERT_NOT_REACHED();
4413     }
4414 
4415     unsigned int totalBytesRequired;
4416     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
4417     if (error != GraphicsContext3D::NO_ERROR) {
4418         m_context->synthesizeGLError(error);
4419         return false;
4420     }
4421     if (pixels->byteLength() < totalBytesRequired) {
4422         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4423         return false;
4424     }
4425     return true;
4426 }
4427 
validateDrawMode(GC3Denum mode)4428 bool WebGLRenderingContext::validateDrawMode(GC3Denum mode)
4429 {
4430     switch (mode) {
4431     case GraphicsContext3D::POINTS:
4432     case GraphicsContext3D::LINE_STRIP:
4433     case GraphicsContext3D::LINE_LOOP:
4434     case GraphicsContext3D::LINES:
4435     case GraphicsContext3D::TRIANGLE_STRIP:
4436     case GraphicsContext3D::TRIANGLE_FAN:
4437     case GraphicsContext3D::TRIANGLES:
4438         return true;
4439     default:
4440         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4441         return false;
4442     }
4443 }
4444 
validateStencilSettings()4445 bool WebGLRenderingContext::validateStencilSettings()
4446 {
4447     if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
4448         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4449         return false;
4450     }
4451     return true;
4452 }
4453 
validateStencilFunc(GC3Denum func)4454 bool WebGLRenderingContext::validateStencilFunc(GC3Denum func)
4455 {
4456     switch (func) {
4457     case GraphicsContext3D::NEVER:
4458     case GraphicsContext3D::LESS:
4459     case GraphicsContext3D::LEQUAL:
4460     case GraphicsContext3D::GREATER:
4461     case GraphicsContext3D::GEQUAL:
4462     case GraphicsContext3D::EQUAL:
4463     case GraphicsContext3D::NOTEQUAL:
4464     case GraphicsContext3D::ALWAYS:
4465         return true;
4466     default:
4467         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4468         return false;
4469     }
4470 }
4471 
printWarningToConsole(const String & message)4472 void WebGLRenderingContext::printWarningToConsole(const String& message)
4473 {
4474     canvas()->document()->frame()->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel,
4475                                                                       message, 0, canvas()->document()->url().string());
4476 }
4477 
validateFramebufferFuncParameters(GC3Denum target,GC3Denum attachment)4478 bool WebGLRenderingContext::validateFramebufferFuncParameters(GC3Denum target, GC3Denum attachment)
4479 {
4480     if (target != GraphicsContext3D::FRAMEBUFFER) {
4481         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4482         return false;
4483     }
4484     switch (attachment) {
4485     case GraphicsContext3D::COLOR_ATTACHMENT0:
4486     case GraphicsContext3D::DEPTH_ATTACHMENT:
4487     case GraphicsContext3D::STENCIL_ATTACHMENT:
4488     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
4489         break;
4490     default:
4491         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4492         return false;
4493     }
4494     return true;
4495 }
4496 
validateBlendEquation(GC3Denum mode)4497 bool WebGLRenderingContext::validateBlendEquation(GC3Denum mode)
4498 {
4499     switch (mode) {
4500     case GraphicsContext3D::FUNC_ADD:
4501     case GraphicsContext3D::FUNC_SUBTRACT:
4502     case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
4503         return true;
4504     default:
4505         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4506         return false;
4507     }
4508 }
4509 
validateBlendFuncFactors(GC3Denum src,GC3Denum dst)4510 bool WebGLRenderingContext::validateBlendFuncFactors(GC3Denum src, GC3Denum dst)
4511 {
4512     if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
4513          && (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))
4514         || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
4515             && (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) {
4516         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4517         return false;
4518     }
4519     return true;
4520 }
4521 
validateCapability(GC3Denum cap)4522 bool WebGLRenderingContext::validateCapability(GC3Denum cap)
4523 {
4524     switch (cap) {
4525     case GraphicsContext3D::BLEND:
4526     case GraphicsContext3D::CULL_FACE:
4527     case GraphicsContext3D::DEPTH_TEST:
4528     case GraphicsContext3D::DITHER:
4529     case GraphicsContext3D::POLYGON_OFFSET_FILL:
4530     case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
4531     case GraphicsContext3D::SAMPLE_COVERAGE:
4532     case GraphicsContext3D::SCISSOR_TEST:
4533     case GraphicsContext3D::STENCIL_TEST:
4534         return true;
4535     default:
4536         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4537         return false;
4538     }
4539 }
4540 
validateUniformParameters(const WebGLUniformLocation * location,Float32Array * v,GC3Dsizei requiredMinSize)4541 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Float32Array* v, GC3Dsizei requiredMinSize)
4542 {
4543     if (!v) {
4544         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4545         return false;
4546     }
4547     return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
4548 }
4549 
validateUniformParameters(const WebGLUniformLocation * location,Int32Array * v,GC3Dsizei requiredMinSize)4550 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Int32Array* v, GC3Dsizei requiredMinSize)
4551 {
4552     if (!v) {
4553         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4554         return false;
4555     }
4556     return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
4557 }
4558 
validateUniformParameters(const WebGLUniformLocation * location,void * v,GC3Dsizei size,GC3Dsizei requiredMinSize)4559 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
4560 {
4561     return validateUniformMatrixParameters(location, false, v, size, requiredMinSize);
4562 }
4563 
validateUniformMatrixParameters(const WebGLUniformLocation * location,GC3Dboolean transpose,Float32Array * v,GC3Dsizei requiredMinSize)4564 bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, GC3Dsizei requiredMinSize)
4565 {
4566     if (!v) {
4567         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4568         return false;
4569     }
4570     return validateUniformMatrixParameters(location, transpose, v->data(), v->length(), requiredMinSize);
4571 }
4572 
validateUniformMatrixParameters(const WebGLUniformLocation * location,GC3Dboolean transpose,void * v,GC3Dsizei size,GC3Dsizei requiredMinSize)4573 bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
4574 {
4575     if (!location)
4576         return false;
4577     if (location->program() != m_currentProgram) {
4578         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4579         return false;
4580     }
4581     if (!v) {
4582         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4583         return false;
4584     }
4585     if (transpose) {
4586         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4587         return false;
4588     }
4589     if (size < requiredMinSize || (size % requiredMinSize)) {
4590         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4591         return false;
4592     }
4593     return true;
4594 }
4595 
validateBufferDataParameters(GC3Denum target,GC3Denum usage)4596 WebGLBuffer* WebGLRenderingContext::validateBufferDataParameters(GC3Denum target, GC3Denum usage)
4597 {
4598     WebGLBuffer* buffer = 0;
4599     switch (target) {
4600     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
4601         buffer = m_boundVertexArrayObject->getElementArrayBuffer().get();
4602         break;
4603     case GraphicsContext3D::ARRAY_BUFFER:
4604         buffer = m_boundArrayBuffer.get();
4605         break;
4606     default:
4607         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4608         return 0;
4609     }
4610     if (!buffer) {
4611         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4612         return 0;
4613     }
4614     switch (usage) {
4615     case GraphicsContext3D::STREAM_DRAW:
4616     case GraphicsContext3D::STATIC_DRAW:
4617     case GraphicsContext3D::DYNAMIC_DRAW:
4618         return buffer;
4619     }
4620     m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4621     return 0;
4622 }
4623 
validateHTMLImageElement(HTMLImageElement * image)4624 bool WebGLRenderingContext::validateHTMLImageElement(HTMLImageElement* image)
4625 {
4626     if (!image || !image->cachedImage()) {
4627         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4628         return false;
4629     }
4630     const KURL& url = image->cachedImage()->response().url();
4631     if (url.isNull() || url.isEmpty() || !url.isValid()) {
4632         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4633         return false;
4634     }
4635     return true;
4636 }
4637 
vertexAttribfImpl(GC3Duint index,GC3Dsizei expectedSize,GC3Dfloat v0,GC3Dfloat v1,GC3Dfloat v2,GC3Dfloat v3)4638 void WebGLRenderingContext::vertexAttribfImpl(GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
4639 {
4640     if (isContextLost())
4641         return;
4642     if (index >= m_maxVertexAttribs) {
4643         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4644         return;
4645     }
4646     // In GL, we skip setting vertexAttrib0 values.
4647     if (index || isGLES2Compliant()) {
4648         switch (expectedSize) {
4649         case 1:
4650             m_context->vertexAttrib1f(index, v0);
4651             break;
4652         case 2:
4653             m_context->vertexAttrib2f(index, v0, v1);
4654             break;
4655         case 3:
4656             m_context->vertexAttrib3f(index, v0, v1, v2);
4657             break;
4658         case 4:
4659             m_context->vertexAttrib4f(index, v0, v1, v2, v3);
4660             break;
4661         }
4662         cleanupAfterGraphicsCall(false);
4663     }
4664     VertexAttribValue& attribValue = m_vertexAttribValue[index];
4665     attribValue.value[0] = v0;
4666     attribValue.value[1] = v1;
4667     attribValue.value[2] = v2;
4668     attribValue.value[3] = v3;
4669 }
4670 
vertexAttribfvImpl(GC3Duint index,Float32Array * v,GC3Dsizei expectedSize)4671 void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, Float32Array* v, GC3Dsizei expectedSize)
4672 {
4673     if (isContextLost())
4674         return;
4675     if (!v) {
4676         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4677         return;
4678     }
4679     vertexAttribfvImpl(index, v->data(), v->length(), expectedSize);
4680 }
4681 
vertexAttribfvImpl(GC3Duint index,GC3Dfloat * v,GC3Dsizei size,GC3Dsizei expectedSize)4682 void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, GC3Dfloat* v, GC3Dsizei size, GC3Dsizei expectedSize)
4683 {
4684     if (isContextLost())
4685         return;
4686     if (!v) {
4687         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4688         return;
4689     }
4690     if (size < expectedSize) {
4691         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4692         return;
4693     }
4694     if (index >= m_maxVertexAttribs) {
4695         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4696         return;
4697     }
4698     // In GL, we skip setting vertexAttrib0 values.
4699     if (index || isGLES2Compliant()) {
4700         switch (expectedSize) {
4701         case 1:
4702             m_context->vertexAttrib1fv(index, v);
4703             break;
4704         case 2:
4705             m_context->vertexAttrib2fv(index, v);
4706             break;
4707         case 3:
4708             m_context->vertexAttrib3fv(index, v);
4709             break;
4710         case 4:
4711             m_context->vertexAttrib4fv(index, v);
4712             break;
4713         }
4714         cleanupAfterGraphicsCall(false);
4715     }
4716     VertexAttribValue& attribValue = m_vertexAttribValue[index];
4717     attribValue.initValue();
4718     for (int ii = 0; ii < expectedSize; ++ii)
4719         attribValue.value[ii] = v[ii];
4720 }
4721 
initVertexAttrib0()4722 void WebGLRenderingContext::initVertexAttrib0()
4723 {
4724     WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4725 
4726     m_vertexAttrib0Buffer = createBuffer();
4727     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
4728     m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW);
4729     m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
4730     state.bufferBinding = m_vertexAttrib0Buffer;
4731     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
4732     m_context->enableVertexAttribArray(0);
4733     m_vertexAttrib0BufferSize = 0;
4734     m_vertexAttrib0BufferValue[0] = 0.0f;
4735     m_vertexAttrib0BufferValue[1] = 0.0f;
4736     m_vertexAttrib0BufferValue[2] = 0.0f;
4737     m_vertexAttrib0BufferValue[3] = 1.0f;
4738     m_forceAttrib0BufferRefill = false;
4739     m_vertexAttrib0UsedBefore = false;
4740 }
4741 
simulateVertexAttrib0(GC3Dsizei numVertex)4742 bool WebGLRenderingContext::simulateVertexAttrib0(GC3Dsizei numVertex)
4743 {
4744     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4745     const VertexAttribValue& attribValue = m_vertexAttribValue[0];
4746     if (!m_currentProgram)
4747         return false;
4748     bool usingVertexAttrib0 = m_currentProgram->isUsingVertexAttrib0();
4749     if (usingVertexAttrib0)
4750         m_vertexAttrib0UsedBefore = true;
4751     if (state.enabled && usingVertexAttrib0)
4752         return false;
4753     if (!usingVertexAttrib0 && !m_vertexAttrib0UsedBefore)
4754         return false;
4755     m_vertexAttrib0UsedBefore = true;
4756     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
4757     GC3Dsizeiptr bufferDataSize = (numVertex + 1) * 4 * sizeof(GC3Dfloat);
4758     if (bufferDataSize > m_vertexAttrib0BufferSize) {
4759         m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, bufferDataSize, 0, GraphicsContext3D::DYNAMIC_DRAW);
4760         m_vertexAttrib0BufferSize = bufferDataSize;
4761         m_forceAttrib0BufferRefill = true;
4762     }
4763     if (usingVertexAttrib0
4764         && (m_forceAttrib0BufferRefill
4765             || attribValue.value[0] != m_vertexAttrib0BufferValue[0]
4766             || attribValue.value[1] != m_vertexAttrib0BufferValue[1]
4767             || attribValue.value[2] != m_vertexAttrib0BufferValue[2]
4768             || attribValue.value[3] != m_vertexAttrib0BufferValue[3])) {
4769         OwnArrayPtr<GC3Dfloat> bufferData = adoptArrayPtr(new GC3Dfloat[(numVertex + 1) * 4]);
4770         for (GC3Dsizei ii = 0; ii < numVertex + 1; ++ii) {
4771             bufferData[ii * 4] = attribValue.value[0];
4772             bufferData[ii * 4 + 1] = attribValue.value[1];
4773             bufferData[ii * 4 + 2] = attribValue.value[2];
4774             bufferData[ii * 4 + 3] = attribValue.value[3];
4775         }
4776         m_vertexAttrib0BufferValue[0] = attribValue.value[0];
4777         m_vertexAttrib0BufferValue[1] = attribValue.value[1];
4778         m_vertexAttrib0BufferValue[2] = attribValue.value[2];
4779         m_vertexAttrib0BufferValue[3] = attribValue.value[3];
4780         m_forceAttrib0BufferRefill = false;
4781         m_context->bufferSubData(GraphicsContext3D::ARRAY_BUFFER, 0, bufferDataSize, bufferData.get());
4782     }
4783     m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, 0, 0, 0);
4784     return true;
4785 }
4786 
restoreStatesAfterVertexAttrib0Simulation()4787 void WebGLRenderingContext::restoreStatesAfterVertexAttrib0Simulation()
4788 {
4789     const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4790     if (state.bufferBinding != m_vertexAttrib0Buffer) {
4791         m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(state.bufferBinding.get()));
4792         m_context->vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset);
4793     }
4794     m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(m_boundArrayBuffer.get()));
4795 }
4796 
LRUImageBufferCache(int capacity)4797 WebGLRenderingContext::LRUImageBufferCache::LRUImageBufferCache(int capacity)
4798     : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity]))
4799     , m_capacity(capacity)
4800 {
4801 }
4802 
imageBuffer(const IntSize & size)4803 ImageBuffer* WebGLRenderingContext::LRUImageBufferCache::imageBuffer(const IntSize& size)
4804 {
4805     int i;
4806     for (i = 0; i < m_capacity; ++i) {
4807         ImageBuffer* buf = m_buffers[i].get();
4808         if (!buf)
4809             break;
4810         if (buf->size() != size)
4811             continue;
4812         bubbleToFront(i);
4813         return buf;
4814     }
4815 
4816     OwnPtr<ImageBuffer> temp = ImageBuffer::create(size);
4817     if (!temp)
4818         return 0;
4819     i = std::min(m_capacity - 1, i);
4820     m_buffers[i] = temp.release();
4821 
4822     ImageBuffer* buf = m_buffers[i].get();
4823     bubbleToFront(i);
4824     return buf;
4825 }
4826 
bubbleToFront(int idx)4827 void WebGLRenderingContext::LRUImageBufferCache::bubbleToFront(int idx)
4828 {
4829     for (int i = idx; i > 0; --i)
4830         m_buffers[i].swap(m_buffers[i-1]);
4831 }
4832 
4833 } // namespace WebCore
4834 
4835 #endif // ENABLE(WEBGL)
4836