1330b1fd29025c166872938e18cca636547a3b94
[WebKit-https.git] / WebCore / html / canvas / WebGLRenderingContext.cpp
1 /*
2  * Copyright (C) 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(3D_CANVAS)
29
30 #include "WebGLRenderingContext.h"
31
32 #include "CachedImage.h"
33 #include "CanvasPixelArray.h"
34 #include "CheckedInt.h"
35 #include "Console.h"
36 #include "DOMWindow.h"
37 #include "Extensions3D.h"
38 #include "FrameView.h"
39 #include "HTMLCanvasElement.h"
40 #include "HTMLImageElement.h"
41 #include "HTMLVideoElement.h"
42 #include "ImageBuffer.h"
43 #include "ImageData.h"
44 #include "IntSize.h"
45 #include "NotImplemented.h"
46 #include "OESTextureFloat.h"
47 #include "RenderBox.h"
48 #include "RenderLayer.h"
49 #include "Uint16Array.h"
50 #include "WebGLActiveInfo.h"
51 #include "WebGLBuffer.h"
52 #include "WebGLContextAttributes.h"
53 #include "WebGLContextEvent.h"
54 #include "WebGLFramebuffer.h"
55 #include "WebGLProgram.h"
56 #include "WebGLRenderbuffer.h"
57 #include "WebGLShader.h"
58 #include "WebGLTexture.h"
59 #include "WebGLUniformLocation.h"
60
61 #include <wtf/ByteArray.h>
62 #include <wtf/OwnArrayPtr.h>
63 #include <wtf/PassOwnArrayPtr.h>
64
65 namespace WebCore {
66
67 const double secondsBetweenRestoreAttempts = 1.0;
68
69 namespace {
70
71     Platform3DObject objectOrZero(WebGLObject* object)
72     {
73         return object ? object->object() : 0;
74     }
75
76     void clip1D(long start, long range, long sourceRange, long* clippedStart, long* clippedRange)
77     {
78         ASSERT(clippedStart && clippedRange);
79         if (start < 0) {
80             range += start;
81             start = 0;
82         }
83         long end = start + range;
84         if (end > sourceRange)
85             range -= end - sourceRange;
86         *clippedStart = start;
87         *clippedRange = range;
88     }
89
90     // Returns false if no clipping is necessary, i.e., x, y, width, height stay the same.
91     bool clip2D(long x, long y, long width, long height,
92                 long sourceWidth, long sourceHeight,
93                 long* clippedX, long* clippedY, long* clippedWidth, long*clippedHeight)
94     {
95         ASSERT(clippedX && clippedY && clippedWidth && clippedHeight);
96         clip1D(x, width, sourceWidth, clippedX, clippedWidth);
97         clip1D(y, height, sourceHeight, clippedY, clippedHeight);
98         return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height);
99     }
100
101     // Return true if a character belongs to the ASCII subset as defined in
102     // GLSL ES 1.0 spec section 3.1.
103     bool validateCharacter(unsigned char c)
104     {
105         // Printing characters are valid except " $ ` @ \ ' DEL.
106         if (c >= 32 && c <= 126
107             && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
108             return true;
109         // Horizontal tab, line feed, vertical tab, form feed, carriage return
110         // are also valid.
111         if (c >= 9 && c <= 13)
112             return true;
113         return false;
114     }
115
116 } // namespace anonymous
117
118 class WebGLStateRestorer {
119 public:
120     WebGLStateRestorer(WebGLRenderingContext* context,
121                        bool changed)
122         : m_context(context)
123         , m_changed(changed)
124     {
125     }
126
127     ~WebGLStateRestorer()
128     {
129         m_context->cleanupAfterGraphicsCall(m_changed);
130     }
131
132 private:
133     WebGLRenderingContext* m_context;
134     bool m_changed;
135 };
136
137 void WebGLRenderingContext::WebGLRenderingContextRestoreTimer::fired()
138 {
139     // Timer is started when m_contextLost is false.  It will first call
140     // loseContext, which will set m_contextLost to true.  Then it will keep
141     // calling restoreContext and reschedule itself until m_contextLost is back
142     // to false.
143     if (!m_context->m_contextLost) {
144         m_context->loseContext();
145         startOneShot(secondsBetweenRestoreAttempts);
146     } else {
147         // The rendering context is not restored if there is no handler for
148         // the context restored event.
149         if (!m_context->canvas()->hasEventListeners(eventNames().webglcontextrestoredEvent))
150             return;
151
152         m_context->restoreContext();
153         if (m_context->m_contextLost)
154             startOneShot(secondsBetweenRestoreAttempts);
155     }
156 }
157
158 PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs)
159 {
160     HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow();
161     GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
162     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
163
164     if (!context) {
165         canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
166         return 0;
167     }
168         
169     return new WebGLRenderingContext(canvas, context, attributes);
170 }
171
172 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
173                                              GraphicsContext3D::Attributes attributes)
174     : CanvasRenderingContext(passedCanvas)
175     , m_context(context)
176     , m_restoreTimer(this)
177     , m_videoCache(4)
178     , m_contextLost(false)
179     , m_attributes(attributes)
180 {
181     ASSERT(m_context);
182     setupFlags();
183     initializeNewContext();
184 }
185
186 void WebGLRenderingContext::initializeNewContext()
187 {
188     ASSERT(!m_contextLost);
189     m_needsUpdate = true;
190     m_markedCanvasDirty = false;
191     m_activeTextureUnit = 0;
192     m_packAlignment = 4;
193     m_unpackAlignment = 4;
194     m_unpackFlipY = false;
195     m_unpackPremultiplyAlpha = false;
196     m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
197     m_boundArrayBuffer = 0;
198     m_boundElementArrayBuffer = 0;
199     m_currentProgram = 0;
200     m_framebufferBinding = 0;
201     m_renderbufferBinding = 0;
202     m_stencilMask = 0xFFFFFFFF;
203     m_stencilMaskBack = 0xFFFFFFFF;
204     m_stencilFuncRef = 0;
205     m_stencilFuncRefBack = 0;
206     m_stencilFuncMask = 0xFFFFFFFF;
207     m_stencilFuncMaskBack = 0xFFFFFFFF;
208     m_vertexAttribState.clear();
209
210     int numCombinedTextureImageUnits = 0;
211     m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
212     m_textureUnits.clear();
213     m_textureUnits.resize(numCombinedTextureImageUnits);
214
215     int numVertexAttribs = 0;
216     m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
217     m_maxVertexAttribs = numVertexAttribs;
218
219     m_maxTextureSize = 0;
220     m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
221     m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
222     m_maxCubeMapTextureSize = 0;
223     m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
224     m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
225
226     if (!isGLES2NPOTStrict())
227         createFallbackBlackTextures1x1();
228     if (!isGLES2Compliant())
229         initVertexAttrib0();
230
231     m_context->reshape(canvas()->width(), canvas()->height());
232     m_context->viewport(0, 0, canvas()->width(), canvas()->height());
233 }
234
235 void WebGLRenderingContext::setupFlags()
236 {
237     ASSERT(m_context);
238
239     m_isGLES2Compliant = m_context->isGLES2Compliant();
240     m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->supports("GL_CHROMIUM_strict_attribs");
241     m_isResourceSafe = m_context->getExtensions()->supports("GL_CHROMIUM_resource_safe");
242     if (m_isGLES2Compliant) {
243         m_isGLES2NPOTStrict = !m_context->getExtensions()->supports("GL_OES_texture_npot");
244         m_isDepthStencilSupported = m_context->getExtensions()->supports("GL_OES_packed_depth_stencil");
245     } else {
246         m_isGLES2NPOTStrict = !m_context->getExtensions()->supports("GL_ARB_texture_non_power_of_two");
247         m_isDepthStencilSupported = m_context->getExtensions()->supports("GL_EXT_packed_depth_stencil");
248     }
249 }
250
251 WebGLRenderingContext::~WebGLRenderingContext()
252 {
253     detachAndRemoveAllObjects();
254 }
255
256 void WebGLRenderingContext::markContextChanged()
257 {
258 #if USE(ACCELERATED_COMPOSITING)
259     RenderBox* renderBox = canvas()->renderBox();
260     if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing())
261         renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
262     else {
263 #endif
264         if (!m_markedCanvasDirty)
265             canvas()->didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
266 #if USE(ACCELERATED_COMPOSITING)
267     }
268 #endif
269     m_markedCanvasDirty = true;
270 }
271
272 void WebGLRenderingContext::paintRenderingResultsToCanvas()
273 {
274     if (!m_markedCanvasDirty)
275         return;
276     canvas()->clearCopiedImage();
277     m_markedCanvasDirty = false;
278     m_context->paintRenderingResultsToCanvas(this);
279 }
280
281 bool WebGLRenderingContext::paintsIntoCanvasBuffer() const
282 {
283     return m_context->paintsIntoCanvasBuffer();
284 }
285
286 void WebGLRenderingContext::reshape(int width, int height)
287 {
288     if (m_needsUpdate) {
289 #if USE(ACCELERATED_COMPOSITING)
290         RenderBox* renderBox = canvas()->renderBox();
291         if (renderBox && renderBox->hasLayer())
292             renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
293 #endif
294         m_needsUpdate = false;
295     }
296
297     // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
298     // clear (and this matches what reshape will do).
299     m_context->reshape(width, height);
300 }
301
302 int WebGLRenderingContext::sizeInBytes(int type)
303 {
304     return m_context->sizeInBytes(type);
305 }
306
307 void WebGLRenderingContext::activeTexture(unsigned long texture, ExceptionCode& ec)
308 {
309     UNUSED_PARAM(ec);
310     if (isContextLost())
311         return;
312     if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
313         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
314         return;
315     }
316     m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
317     m_context->activeTexture(texture);
318     cleanupAfterGraphicsCall(false);
319 }
320
321 void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
322 {
323     UNUSED_PARAM(ec);
324     if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
325         return;
326     if (!program->attachShader(shader)) {
327         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
328         return;
329     }
330     m_context->attachShader(objectOrZero(program), objectOrZero(shader));
331     shader->onAttached();
332     cleanupAfterGraphicsCall(false);
333 }
334
335 void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, unsigned long index, const String& name, ExceptionCode& ec)
336 {
337     UNUSED_PARAM(ec);
338     if (isContextLost() || !validateWebGLObject(program))
339         return;
340     if (!validateString(name))
341         return;
342     m_context->bindAttribLocation(objectOrZero(program), index, name);
343     cleanupAfterGraphicsCall(false);
344 }
345
346 void WebGLRenderingContext::bindBuffer(unsigned long target, WebGLBuffer* buffer, ExceptionCode& ec)
347 {
348     UNUSED_PARAM(ec);
349     if (isContextLost())
350         return;
351     if (buffer && buffer->context() != this) {
352         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
353         return;
354     }
355     if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
356         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
357         return;
358     }
359
360     if (target == GraphicsContext3D::ARRAY_BUFFER)
361         m_boundArrayBuffer = buffer;
362     else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
363         m_boundElementArrayBuffer = buffer;
364     else {
365         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
366         return;
367     }
368
369     m_context->bindBuffer(target, objectOrZero(buffer));
370     if (buffer)
371         buffer->setTarget(target);
372     cleanupAfterGraphicsCall(false);
373 }
374
375
376 void WebGLRenderingContext::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer, ExceptionCode& ec)
377 {
378     UNUSED_PARAM(ec);
379     if (isContextLost())
380         return;
381     if (buffer && buffer->context() != this) {
382         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
383         return;
384     }
385     if (target != GraphicsContext3D::FRAMEBUFFER) {
386         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
387         return;
388     }
389     m_framebufferBinding = buffer;
390     m_context->bindFramebuffer(target, objectOrZero(buffer));
391     if (buffer)
392         buffer->setHasEverBeenBound();
393     cleanupAfterGraphicsCall(false);
394 }
395
396 void WebGLRenderingContext::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
397 {
398     UNUSED_PARAM(ec);
399     if (isContextLost())
400         return;
401     if (renderBuffer && renderBuffer->context() != this) {
402         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
403         return;
404     }
405     if (target != GraphicsContext3D::RENDERBUFFER) {
406         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
407         return;
408     }
409     m_renderbufferBinding = renderBuffer;
410     m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
411     if (renderBuffer)
412         renderBuffer->setHasEverBeenBound();
413     cleanupAfterGraphicsCall(false);
414 }
415
416
417 void WebGLRenderingContext::bindTexture(unsigned long target, WebGLTexture* texture, ExceptionCode& ec)
418 {
419     UNUSED_PARAM(ec);
420     if (isContextLost())
421         return;
422     if (texture && texture->context() != this) {
423         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
424         return;
425     }
426     int maxLevel = 0;
427     if (target == GraphicsContext3D::TEXTURE_2D) {
428         m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
429         maxLevel = m_maxTextureLevel;
430     } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
431         m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
432         maxLevel = m_maxCubeMapTextureLevel;
433     } else {
434         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
435         return;
436     }
437     m_context->bindTexture(target, objectOrZero(texture));
438     if (texture)
439         texture->setTarget(target, maxLevel);
440
441     // Note: previously we used to automatically set the TEXTURE_WRAP_R
442     // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
443     // ES 2.0 doesn't expose this flag (a bug in the specification) and
444     // otherwise the application has no control over the seams in this
445     // dimension. However, it appears that supporting this properly on all
446     // platforms is fairly involved (will require a HashMap from texture ID
447     // in all ports), and we have not had any complaints, so the logic has
448     // been removed.
449
450     cleanupAfterGraphicsCall(false);
451 }
452
453 void WebGLRenderingContext::blendColor(float red, float green, float blue, float alpha)
454 {
455     if (isContextLost())
456         return;
457     m_context->blendColor(red, green, blue, alpha);
458     cleanupAfterGraphicsCall(false);
459 }
460
461 void WebGLRenderingContext::blendEquation(unsigned long mode)
462 {
463     if (isContextLost() || !validateBlendEquation(mode))
464         return;
465     m_context->blendEquation(mode);
466     cleanupAfterGraphicsCall(false);
467 }
468
469 void WebGLRenderingContext::blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha)
470 {
471     if (isContextLost() || !validateBlendEquation(modeRGB) || !validateBlendEquation(modeAlpha))
472         return;
473     m_context->blendEquationSeparate(modeRGB, modeAlpha);
474     cleanupAfterGraphicsCall(false);
475 }
476
477
478 void WebGLRenderingContext::blendFunc(unsigned long sfactor, unsigned long dfactor)
479 {
480     if (isContextLost() || !validateBlendFuncFactors(sfactor, dfactor))
481         return;
482     m_context->blendFunc(sfactor, dfactor);
483     cleanupAfterGraphicsCall(false);
484 }       
485
486 void WebGLRenderingContext::blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha)
487 {
488     if (isContextLost() || !validateBlendFuncFactors(srcRGB, dstRGB))
489         return;
490     m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
491     cleanupAfterGraphicsCall(false);
492 }
493
494 void WebGLRenderingContext::bufferData(unsigned long target, int size, unsigned long usage, ExceptionCode& ec)
495 {
496     UNUSED_PARAM(ec);
497     if (isContextLost())
498         return;
499     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
500     if (!buffer)
501         return;
502     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
503         if (!buffer->associateBufferData(size)) {
504             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
505             return;
506         }
507     }
508
509     m_context->bufferData(target, size, usage);
510     cleanupAfterGraphicsCall(false);
511 }
512
513 void WebGLRenderingContext::bufferData(unsigned long target, ArrayBuffer* data, unsigned long usage, ExceptionCode& ec)
514 {
515     UNUSED_PARAM(ec);
516     if (isContextLost())
517         return;
518     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
519     if (!buffer)
520         return;
521     if (!data) {
522         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
523         return;
524     }
525     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
526         if (!buffer->associateBufferData(data)) {
527             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
528             return;
529         }
530     }
531
532     m_context->bufferData(target, data->byteLength(), data->data(), usage);
533     cleanupAfterGraphicsCall(false);
534 }
535
536 void WebGLRenderingContext::bufferData(unsigned long target, ArrayBufferView* data, unsigned long usage, ExceptionCode& ec)
537 {
538     UNUSED_PARAM(ec);
539     if (isContextLost())
540         return;
541     WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
542     if (!buffer)
543         return;
544     if (!data) {
545         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
546         return;
547     }
548     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
549         if (!buffer->associateBufferData(data)) {
550             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
551             return;
552         }
553     }
554
555     m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
556     cleanupAfterGraphicsCall(false);
557 }
558
559 void WebGLRenderingContext::bufferSubData(unsigned long target, long offset, ArrayBuffer* data, ExceptionCode& ec)
560 {
561     UNUSED_PARAM(ec);
562     if (isContextLost())
563         return;
564     WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
565     if (!buffer)
566         return;
567     if (!data)
568         return;
569     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
570         if (!buffer->associateBufferSubData(offset, data)) {
571             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
572             return;
573         }
574     }
575
576     m_context->bufferSubData(target, offset, data->byteLength(), data->data());
577     cleanupAfterGraphicsCall(false);
578 }
579
580 void WebGLRenderingContext::bufferSubData(unsigned long target, long offset, ArrayBufferView* data, ExceptionCode& ec)
581 {
582     UNUSED_PARAM(ec);
583     if (isContextLost())
584         return;
585     WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
586     if (!buffer)
587         return;
588     if (!data)
589         return;
590     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
591         if (!buffer->associateBufferSubData(offset, data)) {
592             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
593             return;
594         }
595     }
596
597     m_context->bufferSubData(target, offset, data->byteLength(), data->baseAddress());
598     cleanupAfterGraphicsCall(false);
599 }
600
601 unsigned long WebGLRenderingContext::checkFramebufferStatus(unsigned long target)
602 {
603     if (isContextLost())
604         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
605     if (target != GraphicsContext3D::FRAMEBUFFER) {
606         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
607         return 0;
608     }
609     if (!m_framebufferBinding || !m_framebufferBinding->object())
610         return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
611     if (m_framebufferBinding->isIncomplete(true))
612         return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
613     unsigned long result = m_context->checkFramebufferStatus(target);
614     cleanupAfterGraphicsCall(false);
615     return result;
616 }
617
618 void WebGLRenderingContext::clear(unsigned long mask)
619 {
620     if (isContextLost())
621         return;
622     if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
623         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
624         return;
625     }
626     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
627         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
628         return;
629     }
630     m_context->clear(mask);
631     cleanupAfterGraphicsCall(true);
632 }
633
634 void WebGLRenderingContext::clearColor(float r, float g, float b, float a)
635 {
636     if (isContextLost())
637         return;
638     if (isnan(r))
639         r = 0;
640     if (isnan(g))
641         g = 0;
642     if (isnan(b))
643         b = 0;
644     if (isnan(a))
645         a = 1;
646     m_context->clearColor(r, g, b, a);
647     cleanupAfterGraphicsCall(false);
648 }
649
650 void WebGLRenderingContext::clearDepth(float depth)
651 {
652     if (isContextLost())
653         return;
654     m_context->clearDepth(depth);
655     cleanupAfterGraphicsCall(false);
656 }
657
658 void WebGLRenderingContext::clearStencil(long s)
659 {
660     if (isContextLost())
661         return;
662     m_context->clearStencil(s);
663     cleanupAfterGraphicsCall(false);
664 }
665
666 void WebGLRenderingContext::colorMask(bool red, bool green, bool blue, bool alpha)
667 {
668     if (isContextLost())
669         return;
670     m_context->colorMask(red, green, blue, alpha);
671     cleanupAfterGraphicsCall(false);
672 }
673
674 void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec)
675 {
676     UNUSED_PARAM(ec);
677     if (isContextLost() || !validateWebGLObject(shader))
678         return;
679     m_context->compileShader(objectOrZero(shader));
680     cleanupAfterGraphicsCall(false);
681 }
682
683 void WebGLRenderingContext::copyTexImage2D(unsigned long target, long level, unsigned long internalformat, long x, long y, long width, long height, long border)
684 {
685     if (isContextLost())
686         return;
687     if (!validateTexFuncParameters(target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
688         return;
689     WebGLTexture* tex = validateTextureBinding(target, true);
690     if (!tex)
691         return;
692     if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
693         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
694         return;
695     }
696     if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
697         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
698         return;
699     }
700     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
701         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
702         return;
703     }
704     if (isResourceSafe())
705         m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
706     else {
707         long clippedX, clippedY, clippedWidth, clippedHeight;
708         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
709             m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
710                                               internalformat, GraphicsContext3D::UNSIGNED_BYTE);
711             if (clippedWidth > 0 && clippedHeight > 0) {
712                 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
713                                              clippedX, clippedY, clippedWidth, clippedHeight);
714             }
715         } else
716             m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
717     }
718     // FIXME: if the framebuffer is not complete, none of the below should be executed.
719     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
720     cleanupAfterGraphicsCall(false);
721 }
722
723 void WebGLRenderingContext::copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, long x, long y, long width, long height)
724 {
725     if (isContextLost())
726         return;
727     if (!validateTexFuncLevel(target, level))
728         return;
729     WebGLTexture* tex = validateTextureBinding(target, true);
730     if (!tex)
731         return;
732     if (!validateSize(xoffset, yoffset) || !validateSize(width, height))
733         return;
734     if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
735         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
736         return;
737     }
738     if (!isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(target, level), getBoundFramebufferColorFormat())) {
739         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
740         return;
741     }
742     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
743         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
744         return;
745     }
746     if (isResourceSafe())
747         m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
748     else {
749         long clippedX, clippedY, clippedWidth, clippedHeight;
750         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
751             unsigned long format = tex->getInternalFormat(target, level);
752             unsigned long type = tex->getType(target, level);
753             unsigned int componentsPerPixel = 0;
754             unsigned int bytesPerComponent = 0;
755             bool valid = m_context->computeFormatAndTypeParameters(format, type, &componentsPerPixel, &bytesPerComponent);
756             if (!valid) {
757                 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
758                 return;
759             }
760             OwnArrayPtr<unsigned char> zero;
761             if (width && height) {
762                 unsigned long size = componentsPerPixel * bytesPerComponent * width * height;
763                 zero = adoptArrayPtr(new unsigned char[size]);
764                 if (!zero) {
765                     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
766                     return;
767                 }
768                 memset(zero.get(), 0, size);
769             }
770             if (zero)
771                 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
772             m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
773             if (zero)
774                 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
775             if (clippedWidth > 0 && clippedHeight > 0) {
776                 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
777                                              clippedX, clippedY, clippedWidth, clippedHeight);
778             }
779         } else
780             m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
781     }
782     cleanupAfterGraphicsCall(false);
783 }
784
785 PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer()
786 {
787     if (isContextLost())
788         return 0;
789     RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
790     addObject(o.get());
791     return o;
792 }
793         
794 PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer()
795 {
796     if (isContextLost())
797         return 0;
798     RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
799     addObject(o.get());
800     return o;
801 }
802
803 PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture()
804 {
805     if (isContextLost())
806         return 0;
807     RefPtr<WebGLTexture> o = WebGLTexture::create(this);
808     addObject(o.get());
809     return o;
810 }
811
812 PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram()
813 {
814     if (isContextLost())
815         return 0;
816     RefPtr<WebGLProgram> o = WebGLProgram::create(this);
817     addObject(o.get());
818     return o;
819 }
820
821 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer()
822 {
823     if (isContextLost())
824         return 0;
825     RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
826     addObject(o.get());
827     return o;
828 }
829
830 PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(unsigned long type, ExceptionCode& ec)
831 {
832     UNUSED_PARAM(ec);
833     if (isContextLost())
834         return 0;
835     if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
836         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
837         return 0;
838     }
839     
840     RefPtr<WebGLShader> o = WebGLShader::create(this, static_cast<GraphicsContext3D::WebGLEnumType>(type));
841     addObject(o.get());
842     return o;
843 }
844
845 void WebGLRenderingContext::cullFace(unsigned long mode)
846 {
847     if (isContextLost())
848         return;
849     m_context->cullFace(mode);
850     cleanupAfterGraphicsCall(false);
851 }
852
853 void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
854 {
855     if (isContextLost() || !buffer)
856         return;
857     
858     buffer->deleteObject();
859
860     if (!isGLES2Compliant()) {
861         VertexAttribState& state = m_vertexAttribState[0];
862         if (buffer == state.bufferBinding) {
863             state.bufferBinding = m_vertexAttrib0Buffer;
864             state.bytesPerElement = 0;
865             state.size = 4;
866             state.type = GraphicsContext3D::FLOAT;
867             state.normalized = false;
868             state.stride = 16;
869             state.originalStride = 0;
870             state.offset = 0;
871         }
872     }
873 }
874
875 void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
876 {
877     if (isContextLost() || !framebuffer)
878         return;
879     if (framebuffer == m_framebufferBinding) {
880         m_framebufferBinding = 0;
881         // Have to call bindFramebuffer here to bind back to internal fbo.
882         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
883     }
884     framebuffer->deleteObject();
885 }
886
887 void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
888 {
889     if (isContextLost() || !program)
890         return;
891     if (program->context() != this) {
892         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
893         return;
894     }
895     if (!program->object())
896         return;
897     program->deleteObject();
898 }
899
900 void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
901 {
902     if (isContextLost() || !renderbuffer)
903         return;
904     if (renderbuffer == m_renderbufferBinding)
905         m_renderbufferBinding = 0;
906     renderbuffer->deleteObject();
907     if (m_framebufferBinding)
908         m_framebufferBinding->removeAttachment(renderbuffer);
909 }
910
911 void WebGLRenderingContext::deleteShader(WebGLShader* shader)
912 {
913     if (isContextLost() || !shader)
914         return;
915     
916     shader->deleteObject();
917 }
918
919 void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
920 {
921     if (isContextLost() || !texture)
922         return;
923     
924     texture->deleteObject();
925     if (m_framebufferBinding)
926         m_framebufferBinding->removeAttachment(texture);
927 }
928
929 void WebGLRenderingContext::depthFunc(unsigned long func)
930 {
931     if (isContextLost())
932         return;
933     m_context->depthFunc(func);
934     cleanupAfterGraphicsCall(false);
935 }
936
937 void WebGLRenderingContext::depthMask(bool flag)
938 {
939     if (isContextLost())
940         return;
941     m_context->depthMask(flag);
942     cleanupAfterGraphicsCall(false);
943 }
944
945 void WebGLRenderingContext::depthRange(float zNear, float zFar)
946 {
947     if (isContextLost())
948         return;
949     if (zNear > zFar) {
950         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
951         return;
952     }
953     m_context->depthRange(zNear, zFar);
954     cleanupAfterGraphicsCall(false);
955 }
956
957 void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
958 {
959     UNUSED_PARAM(ec);
960     if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
961         return;
962     if (!program->detachShader(shader)) {
963         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
964         return;
965     }
966     m_context->detachShader(objectOrZero(program), objectOrZero(shader));
967     shader->onDetached();
968     cleanupAfterGraphicsCall(false);
969 }
970
971
972 void WebGLRenderingContext::disable(unsigned long cap)
973 {
974     if (isContextLost() || !validateCapability(cap))
975         return;
976     m_context->disable(cap);
977     cleanupAfterGraphicsCall(false);
978 }
979
980 void WebGLRenderingContext::disableVertexAttribArray(unsigned long index, ExceptionCode& ec)
981 {
982     UNUSED_PARAM(ec);
983     if (isContextLost())
984         return;
985     if (index >= m_maxVertexAttribs) {
986         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
987         return;
988     }
989     
990     if (index < m_vertexAttribState.size())
991         m_vertexAttribState[index].enabled = false;
992
993     if (index > 0 || isGLES2Compliant()) {
994         m_context->disableVertexAttribArray(index);
995         cleanupAfterGraphicsCall(false);
996     }
997 }
998
999 bool WebGLRenderingContext::validateElementArraySize(unsigned long count, unsigned long type, long offset)
1000 {
1001     if (!m_boundElementArrayBuffer)
1002         return false;
1003
1004     if (offset < 0)
1005         return false;
1006
1007     unsigned long uoffset = static_cast<unsigned long>(offset);
1008
1009     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1010         // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1011         if (uoffset & 1)
1012             return false;
1013
1014         // Make uoffset an element offset.
1015         uoffset /= 2;
1016
1017         unsigned long n = m_boundElementArrayBuffer->byteLength() / 2;
1018         if (uoffset > n || count > n - uoffset)
1019             return false;
1020     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1021         unsigned long n = m_boundElementArrayBuffer->byteLength();
1022         if (uoffset > n || count > n - uoffset)
1023             return false;
1024     }
1025     return true;
1026 }
1027
1028 bool WebGLRenderingContext::validateIndexArrayConservative(unsigned long type, long& numElementsRequired)
1029 {
1030     // Performs conservative validation by caching a maximum index of
1031     // the given type per element array buffer. If all of the bound
1032     // array buffers have enough elements to satisfy that maximum
1033     // index, skips the expensive per-draw-call iteration in
1034     // validateIndexArrayPrecise.
1035
1036     if (!m_boundElementArrayBuffer)
1037         return false;
1038
1039     unsigned numElements = m_boundElementArrayBuffer->byteLength();
1040     // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1041     if (!numElements)
1042         return false;
1043     const ArrayBuffer* buffer = m_boundElementArrayBuffer->elementArrayBuffer();
1044     ASSERT(buffer);
1045
1046     long maxIndex = m_boundElementArrayBuffer->getCachedMaxIndex(type);
1047     if (maxIndex < 0) {
1048         // Compute the maximum index in the entire buffer for the given type of index.
1049         switch (type) {
1050         case GraphicsContext3D::UNSIGNED_BYTE: {
1051             const unsigned char* p = static_cast<const unsigned char*>(buffer->data());
1052             for (unsigned i = 0; i < numElements; i++)
1053                 maxIndex = max(maxIndex, static_cast<long>(p[i]));
1054             break;
1055         }
1056         case GraphicsContext3D::UNSIGNED_SHORT: {
1057             numElements /= sizeof(unsigned short);
1058             const unsigned short* p = static_cast<const unsigned short*>(buffer->data());
1059             for (unsigned i = 0; i < numElements; i++)
1060                 maxIndex = max(maxIndex, static_cast<long>(p[i]));
1061             break;
1062         }
1063         default:
1064             return false;
1065         }
1066         m_boundElementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1067     }
1068
1069     if (maxIndex >= 0) {
1070         // The number of required elements is one more than the maximum
1071         // index that will be accessed.
1072         numElementsRequired = maxIndex + 1;
1073         return true;
1074     }
1075
1076     return false;
1077 }
1078
1079 bool WebGLRenderingContext::validateIndexArrayPrecise(unsigned long count, unsigned long type, long offset, long& numElementsRequired)
1080 {
1081     long lastIndex = -1;
1082
1083     if (!m_boundElementArrayBuffer)
1084         return false;
1085
1086     if (!count) {
1087         numElementsRequired = 0;
1088         return true;
1089     }
1090
1091     if (!m_boundElementArrayBuffer->elementArrayBuffer())
1092         return false;
1093
1094     unsigned long uoffset = static_cast<unsigned long>(offset);
1095     unsigned long n = count;
1096
1097     if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1098         // Make uoffset an element offset.
1099         uoffset /= 2;
1100         const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1101         while (n-- > 0) {
1102             if (*p > lastIndex)
1103                 lastIndex = *p;
1104             ++p;
1105         }
1106     } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1107         const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1108         while (n-- > 0) {
1109             if (*p > lastIndex)
1110                 lastIndex = *p;
1111             ++p;
1112         }
1113     }    
1114         
1115     // Then set the last index in the index array and make sure it is valid.
1116     numElementsRequired = lastIndex + 1;
1117     return numElementsRequired > 0;
1118 }
1119
1120 bool WebGLRenderingContext::validateRenderingState(long numElementsRequired)
1121 {
1122     if (!m_currentProgram)
1123         return false;
1124
1125     int numAttribStates = static_cast<int>(m_vertexAttribState.size());
1126
1127     // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1128     for (int i = 0; i < numAttribStates; ++i) {
1129         if (m_vertexAttribState[i].enabled
1130             && (!m_vertexAttribState[i].bufferBinding || !m_vertexAttribState[i].bufferBinding->object()))
1131             return false;
1132     }
1133
1134     if (numElementsRequired <= 0)
1135         return true;
1136
1137     // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
1138     long smallestNumElements = LONG_MAX;
1139     int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1140     for (int i = 0; i < numActiveAttribLocations; ++i) {
1141         int loc = m_currentProgram->getActiveAttribLocation(i);
1142         if (loc >=0 && loc < numAttribStates) {
1143             const VertexAttribState& state = m_vertexAttribState[loc];
1144             if (state.enabled) {
1145                 // Avoid off-by-one errors in numElements computation.
1146                 // For the last element, we will only touch the data for the
1147                 // element and nothing beyond it.
1148                 long bytesRemaining = state.bufferBinding->byteLength() - state.offset;
1149                 long numElements = 0;
1150                 if (bytesRemaining >= state.bytesPerElement)
1151                     numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1152                 if (numElements < smallestNumElements)
1153                     smallestNumElements = numElements;
1154             }
1155         }
1156     }
1157     
1158     if (smallestNumElements == LONG_MAX)
1159         smallestNumElements = 0;
1160     
1161     return numElementsRequired <= smallestNumElements;
1162 }
1163
1164 bool WebGLRenderingContext::validateWebGLObject(WebGLObject* object)
1165 {
1166     if (!object || !object->object()) {
1167         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1168         return false;
1169     }
1170     if (object->context() != this) {
1171         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1172         return false;
1173     }
1174     return true;
1175 }
1176
1177 void WebGLRenderingContext::drawArrays(unsigned long mode, long first, long count, ExceptionCode& ec)
1178 {
1179     UNUSED_PARAM(ec);
1180
1181     if (isContextLost() || !validateDrawMode(mode))
1182         return;
1183
1184     if (!validateStencilSettings())
1185         return;
1186
1187     if (first < 0 || count < 0) {
1188         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1189         return;
1190     }
1191
1192     if (!count)
1193         return;
1194
1195     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1196         // Ensure we have a valid rendering state
1197         CheckedInt<int32_t> checkedFirst(first);
1198         CheckedInt<int32_t> checkedCount(count);
1199         CheckedInt<int32_t> checkedSum = checkedFirst + checkedCount;
1200         if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) {
1201             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1202             return;
1203         }
1204     } else {
1205         if (!validateRenderingState(0)) {
1206             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1207             return;
1208         }
1209     }
1210
1211     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1212         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1213         return;
1214     }
1215
1216     bool vertexAttrib0Simulated = false;
1217     if (!isGLES2Compliant())
1218         vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1219     if (!isGLES2NPOTStrict())
1220         handleNPOTTextures(true);
1221     m_context->drawArrays(mode, first, count);
1222     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1223         restoreStatesAfterVertexAttrib0Simulation();
1224     if (!isGLES2NPOTStrict())
1225         handleNPOTTextures(false);
1226     cleanupAfterGraphicsCall(true);
1227 }
1228
1229 void WebGLRenderingContext::drawElements(unsigned long mode, long count, unsigned long type, long offset, ExceptionCode& ec)
1230 {
1231     UNUSED_PARAM(ec);
1232
1233     if (isContextLost() || !validateDrawMode(mode))
1234         return;
1235
1236     if (!validateStencilSettings())
1237         return;
1238
1239     switch (type) {
1240     case GraphicsContext3D::UNSIGNED_BYTE:
1241     case GraphicsContext3D::UNSIGNED_SHORT:
1242         break;
1243     default:
1244         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1245         return;
1246     }
1247
1248     if (count < 0 || offset < 0) {
1249         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1250         return;
1251     }
1252
1253     if (!count)
1254         return;
1255
1256     long numElements = 0;
1257     if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1258         // Ensure we have a valid rendering state
1259         if (!validateElementArraySize(count, type, offset)) {
1260             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1261             return;
1262         }
1263         if (!count)
1264             return;
1265         if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) {
1266             if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
1267                 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1268                 return;
1269             }
1270         }
1271     } else {
1272         if (!validateRenderingState(0)) {
1273             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1274             return;
1275         }
1276     }
1277
1278     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1279         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1280         return;
1281     }
1282
1283     bool vertexAttrib0Simulated = false;
1284     if (!isGLES2Compliant()) {
1285         if (!numElements)
1286             validateIndexArrayPrecise(count, type, offset, numElements);
1287         vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1288     }
1289     if (!isGLES2NPOTStrict())
1290         handleNPOTTextures(true);
1291     m_context->drawElements(mode, count, type, offset);
1292     if (!isGLES2Compliant() && vertexAttrib0Simulated)
1293         restoreStatesAfterVertexAttrib0Simulation();
1294     if (!isGLES2NPOTStrict())
1295         handleNPOTTextures(false);
1296     cleanupAfterGraphicsCall(true);
1297 }
1298
1299 void WebGLRenderingContext::enable(unsigned long cap)
1300 {
1301     if (isContextLost() || !validateCapability(cap))
1302         return;
1303     m_context->enable(cap);
1304     cleanupAfterGraphicsCall(false);
1305 }
1306
1307 void WebGLRenderingContext::enableVertexAttribArray(unsigned long index, ExceptionCode& ec)
1308 {
1309     UNUSED_PARAM(ec);
1310     if (isContextLost())
1311         return;
1312     if (index >= m_maxVertexAttribs) {
1313         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1314         return;
1315     }
1316     
1317     if (index >= m_vertexAttribState.size())
1318         m_vertexAttribState.resize(index + 1);
1319         
1320     m_vertexAttribState[index].enabled = true;
1321     
1322     m_context->enableVertexAttribArray(index);
1323     cleanupAfterGraphicsCall(false);
1324 }
1325
1326 void WebGLRenderingContext::finish()
1327 {
1328     if (isContextLost())
1329         return;
1330     m_context->finish();
1331     cleanupAfterGraphicsCall(true);
1332 }
1333
1334
1335 void WebGLRenderingContext::flush()
1336 {
1337     if (isContextLost())
1338         return;
1339     m_context->flush();
1340     cleanupAfterGraphicsCall(true);
1341 }
1342
1343 void WebGLRenderingContext::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
1344 {
1345     UNUSED_PARAM(ec);
1346     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1347         return;
1348     if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
1349         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1350         return;
1351     }
1352     if (buffer && buffer->context() != this) {
1353         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1354         return;
1355     }
1356     // Don't allow the default framebuffer to be mutated; all current
1357     // implementations use an FBO internally in place of the default
1358     // FBO.
1359     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1360         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1361         return;
1362     }
1363     Platform3DObject bufferObject = objectOrZero(buffer);
1364     bool reattachDepth = false;
1365     bool reattachStencil = false;
1366     bool reattachDepthStencilDepth = false;
1367     bool reattachDepthStencilStencil = false;
1368     switch (attachment) {
1369     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
1370         m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1371         m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
1372         if (!bufferObject) {
1373             reattachDepth = true;
1374             reattachStencil = true;
1375         }
1376         break;
1377     case GraphicsContext3D::DEPTH_ATTACHMENT:
1378         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1379         if (!bufferObject)
1380             reattachDepthStencilDepth = true;
1381         break;
1382     case GraphicsContext3D::STENCIL_ATTACHMENT:
1383         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1384         if (!bufferObject)
1385             reattachDepthStencilStencil = true;
1386         break;
1387     default:
1388         m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1389     }
1390     m_framebufferBinding->setAttachment(attachment, buffer);
1391     if (reattachDepth) {
1392         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT));
1393         if (object)
1394             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1395     }
1396     if (reattachStencil) {
1397         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT));
1398         if (object)
1399             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1400     }
1401     if (reattachDepthStencilDepth) {
1402         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1403         if (object)
1404             m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1405     }
1406     if (reattachDepthStencilStencil) {
1407         Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1408         if (object)
1409             m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1410     }
1411     cleanupAfterGraphicsCall(false);
1412 }
1413
1414 void WebGLRenderingContext::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture* texture, long level, ExceptionCode& ec)
1415 {
1416     UNUSED_PARAM(ec);
1417     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1418         return;
1419     if (level) {
1420         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1421         return;
1422     }
1423     if (texture && texture->context() != this) {
1424         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1425         return;
1426     }
1427     // Don't allow the default framebuffer to be mutated; all current
1428     // implementations use an FBO internally in place of the default
1429     // FBO.
1430     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1431         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1432         return;
1433     }
1434     m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level);
1435     m_framebufferBinding->setAttachment(attachment, textarget, texture, level);
1436     cleanupAfterGraphicsCall(false);
1437 }
1438
1439 void WebGLRenderingContext::frontFace(unsigned long mode)
1440 {
1441     if (isContextLost())
1442         return;
1443     m_context->frontFace(mode);
1444     cleanupAfterGraphicsCall(false);
1445 }
1446
1447 void WebGLRenderingContext::generateMipmap(unsigned long target)
1448 {
1449     if (isContextLost())
1450         return;
1451     WebGLTexture* tex = validateTextureBinding(target, false);
1452     if (!tex)
1453         return;
1454     if (!tex->canGenerateMipmaps()) {
1455         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1456         return;
1457     }
1458     // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
1459     // on Mac.  Remove the hack once this driver bug is fixed.
1460 #if OS(DARWIN)
1461     bool needToResetMinFilter = false;
1462     if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
1463         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
1464         needToResetMinFilter = true;
1465     }
1466 #endif
1467     m_context->generateMipmap(target);
1468 #if OS(DARWIN)
1469     if (needToResetMinFilter)
1470         m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
1471 #endif
1472     tex->generateMipmapLevelInfo();
1473     cleanupAfterGraphicsCall(false);
1474 }
1475
1476 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, unsigned long index, ExceptionCode& ec)
1477 {
1478     UNUSED_PARAM(ec);
1479     if (isContextLost() || !validateWebGLObject(program))
1480         return 0;
1481     ActiveInfo info;
1482     if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
1483         return 0;
1484     return WebGLActiveInfo::create(info.name, info.type, info.size);
1485 }
1486
1487 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, unsigned long index, ExceptionCode& ec)
1488 {
1489     UNUSED_PARAM(ec);
1490     if (isContextLost() || !validateWebGLObject(program))
1491         return 0;
1492     ActiveInfo info;
1493     if (!m_context->getActiveUniform(objectOrZero(program), index, info))
1494         return 0;
1495     if (!isGLES2Compliant())
1496         if (info.size > 1 && !info.name.endsWith("[0]"))
1497             info.name.append("[0]");
1498     return WebGLActiveInfo::create(info.name, info.type, info.size);
1499 }
1500
1501 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<WebGLShader*>& shaderObjects, ExceptionCode& ec)
1502 {
1503     UNUSED_PARAM(ec);
1504     shaderObjects.clear();
1505     if (isContextLost() || !validateWebGLObject(program))
1506         return false;
1507     int numShaders = 0;
1508     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ATTACHED_SHADERS, &numShaders);
1509     if (numShaders) {
1510         OwnArrayPtr<unsigned int> shaders(new unsigned int[numShaders]);
1511         int count = 0;
1512         m_context->getAttachedShaders(objectOrZero(program), numShaders, &count, shaders.get());
1513         if (count != numShaders)
1514             return false;
1515         shaderObjects.resize(numShaders);
1516         for (int ii = 0; ii < numShaders; ++ii) {
1517             WebGLShader* shader = findShader(shaders[ii]);
1518             if (!shader) {
1519                 shaderObjects.clear();
1520                 return false;
1521             }
1522             shaderObjects[ii] = shader;
1523         }
1524     }
1525     return true;
1526 }
1527
1528 int WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
1529 {
1530     if (isContextLost())
1531         return -1;
1532     if (!validateString(name))
1533         return -1;
1534     return m_context->getAttribLocation(objectOrZero(program), name);
1535 }
1536
1537 WebGLGetInfo WebGLRenderingContext::getBufferParameter(unsigned long target, unsigned long pname, ExceptionCode& ec)
1538 {
1539     UNUSED_PARAM(ec);
1540     if (isContextLost())
1541         return WebGLGetInfo();
1542     if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
1543         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1544         return WebGLGetInfo();
1545     }
1546
1547     if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
1548         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1549         return WebGLGetInfo();
1550     }
1551
1552     WebGLStateRestorer(this, false);
1553     int value = 0;
1554     m_context->getBufferParameteriv(target, pname, &value);
1555     if (pname == GraphicsContext3D::BUFFER_SIZE)
1556         return WebGLGetInfo(static_cast<long>(value));
1557     return WebGLGetInfo(static_cast<unsigned long>(value));
1558 }
1559
1560 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
1561 {
1562     if (isContextLost())
1563         return 0;
1564     // We always need to return a new WebGLContextAttributes object to
1565     // prevent the user from mutating any cached version.
1566     return WebGLContextAttributes::create(m_context->getContextAttributes());
1567 }
1568
1569 unsigned long WebGLRenderingContext::getError()
1570 {
1571     return m_context->getError();
1572 }
1573
1574 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
1575 {
1576     if (equalIgnoringCase(name, "OES_texture_float")
1577         && m_context->getExtensions()->supports("GL_OES_texture_float")) {
1578         if (!m_oesTextureFloat) {
1579             m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
1580             m_oesTextureFloat = OESTextureFloat::create();
1581         }
1582         return m_oesTextureFloat.get();
1583     }
1584
1585     return 0;
1586 }
1587
1588 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(unsigned long target, unsigned long attachment, unsigned long pname, ExceptionCode& ec)
1589 {
1590     UNUSED_PARAM(ec);
1591     if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1592         return WebGLGetInfo();
1593     switch (pname) {
1594     case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
1595     case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
1596     case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
1597     case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
1598         break;
1599     default:
1600         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1601         return WebGLGetInfo();
1602     }
1603
1604     if (!m_framebufferBinding || !m_framebufferBinding->object() || m_framebufferBinding->isIncomplete(false)) {
1605         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1606         return WebGLGetInfo();
1607     }
1608
1609     if (pname != GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
1610         WebGLStateRestorer(this, false);
1611         int value = 0;
1612         m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
1613         if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
1614             return WebGLGetInfo(static_cast<unsigned long>(value));
1615         return WebGLGetInfo(static_cast<long>(value));
1616     }
1617
1618     WebGLStateRestorer(this, false);
1619     int type = 0;
1620     m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
1621     if (!type)
1622         return WebGLGetInfo();
1623     int value = 0;
1624     m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &value);
1625     switch (type) {
1626     case GraphicsContext3D::RENDERBUFFER:
1627         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(findRenderbuffer(static_cast<Platform3DObject>(value))));
1628     case GraphicsContext3D::TEXTURE:
1629         return WebGLGetInfo(PassRefPtr<WebGLTexture>(findTexture(static_cast<Platform3DObject>(value))));
1630     default:
1631         // FIXME: raise exception?
1632         return WebGLGetInfo();
1633     }
1634 }
1635
1636 WebGLGetInfo WebGLRenderingContext::getParameter(unsigned long pname, ExceptionCode& ec)
1637 {
1638     UNUSED_PARAM(ec);
1639     if (isContextLost())
1640         return WebGLGetInfo();
1641     WebGLStateRestorer(this, false);
1642     switch (pname) {
1643     case GraphicsContext3D::ACTIVE_TEXTURE:
1644         return getUnsignedLongParameter(pname);
1645     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
1646         return getWebGLFloatArrayParameter(pname);
1647     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
1648         return getWebGLFloatArrayParameter(pname);
1649     case GraphicsContext3D::ALPHA_BITS:
1650         return getLongParameter(pname);
1651     case GraphicsContext3D::ARRAY_BUFFER_BINDING:
1652         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
1653     case GraphicsContext3D::BLEND:
1654         return getBooleanParameter(pname);
1655     case GraphicsContext3D::BLEND_COLOR:
1656         return getWebGLFloatArrayParameter(pname);
1657     case GraphicsContext3D::BLEND_DST_ALPHA:
1658         return getUnsignedLongParameter(pname);
1659     case GraphicsContext3D::BLEND_DST_RGB:
1660         return getUnsignedLongParameter(pname);
1661     case GraphicsContext3D::BLEND_EQUATION_ALPHA:
1662         return getUnsignedLongParameter(pname);
1663     case GraphicsContext3D::BLEND_EQUATION_RGB:
1664         return getUnsignedLongParameter(pname);
1665     case GraphicsContext3D::BLEND_SRC_ALPHA:
1666         return getUnsignedLongParameter(pname);
1667     case GraphicsContext3D::BLEND_SRC_RGB:
1668         return getUnsignedLongParameter(pname);
1669     case GraphicsContext3D::BLUE_BITS:
1670         return getLongParameter(pname);
1671     case GraphicsContext3D::COLOR_CLEAR_VALUE:
1672         return getWebGLFloatArrayParameter(pname);
1673     case GraphicsContext3D::COLOR_WRITEMASK:
1674         return getBooleanArrayParameter(pname);
1675     case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
1676         // Defined as null in the spec
1677         return WebGLGetInfo();
1678     case GraphicsContext3D::CULL_FACE:
1679         return getBooleanParameter(pname);
1680     case GraphicsContext3D::CULL_FACE_MODE:
1681         return getUnsignedLongParameter(pname);
1682     case GraphicsContext3D::CURRENT_PROGRAM:
1683         return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
1684     case GraphicsContext3D::DEPTH_BITS:
1685         return getLongParameter(pname);
1686     case GraphicsContext3D::DEPTH_CLEAR_VALUE:
1687         return getFloatParameter(pname);
1688     case GraphicsContext3D::DEPTH_FUNC:
1689         return getUnsignedLongParameter(pname);
1690     case GraphicsContext3D::DEPTH_RANGE:
1691         return getWebGLFloatArrayParameter(pname);
1692     case GraphicsContext3D::DEPTH_TEST:
1693         return getBooleanParameter(pname);
1694     case GraphicsContext3D::DEPTH_WRITEMASK:
1695         return getBooleanParameter(pname);
1696     case GraphicsContext3D::DITHER:
1697         return getBooleanParameter(pname);
1698     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
1699         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundElementArrayBuffer));
1700     case GraphicsContext3D::FRAMEBUFFER_BINDING:
1701         return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
1702     case GraphicsContext3D::FRONT_FACE:
1703         return getUnsignedLongParameter(pname);
1704     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
1705         return getUnsignedLongParameter(pname);
1706     case GraphicsContext3D::GREEN_BITS:
1707         return getLongParameter(pname);
1708     case GraphicsContext3D::LINE_WIDTH:
1709         return getFloatParameter(pname);
1710     case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
1711         return getLongParameter(pname);
1712     case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
1713         return getLongParameter(pname);
1714     case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
1715         return getLongParameter(pname);
1716     case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
1717         return getLongParameter(pname);
1718     case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
1719         return getLongParameter(pname);
1720     case GraphicsContext3D::MAX_TEXTURE_SIZE:
1721         return getLongParameter(pname);
1722     case GraphicsContext3D::MAX_VARYING_VECTORS:
1723         return getLongParameter(pname);
1724     case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
1725         return getLongParameter(pname);
1726     case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
1727         return getLongParameter(pname);
1728     case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
1729         return getLongParameter(pname);
1730     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
1731         return getWebGLIntArrayParameter(pname);
1732     case GraphicsContext3D::NUM_COMPRESSED_TEXTURE_FORMATS:
1733         // WebGL 1.0 specifies that there are no compressed texture formats.
1734         return WebGLGetInfo(static_cast<long>(0));
1735     case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
1736         // FIXME: should we always return 0 for this?
1737         return getLongParameter(pname);
1738     case GraphicsContext3D::PACK_ALIGNMENT:
1739         return getLongParameter(pname);
1740     case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
1741         return getFloatParameter(pname);
1742     case GraphicsContext3D::POLYGON_OFFSET_FILL:
1743         return getBooleanParameter(pname);
1744     case GraphicsContext3D::POLYGON_OFFSET_UNITS:
1745         return getFloatParameter(pname);
1746     case GraphicsContext3D::RED_BITS:
1747         return getLongParameter(pname);
1748     case GraphicsContext3D::RENDERBUFFER_BINDING:
1749         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
1750     case GraphicsContext3D::RENDERER:
1751         return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
1752     case GraphicsContext3D::SAMPLE_BUFFERS:
1753         return getLongParameter(pname);
1754     case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
1755         return getBooleanParameter(pname);
1756     case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
1757         return getFloatParameter(pname);
1758     case GraphicsContext3D::SAMPLES:
1759         return getLongParameter(pname);
1760     case GraphicsContext3D::SCISSOR_BOX:
1761         return getWebGLIntArrayParameter(pname);
1762     case GraphicsContext3D::SCISSOR_TEST:
1763         return getBooleanParameter(pname);
1764     case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
1765         return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
1766     case GraphicsContext3D::STENCIL_BACK_FAIL:
1767         return getUnsignedLongParameter(pname);
1768     case GraphicsContext3D::STENCIL_BACK_FUNC:
1769         return getUnsignedLongParameter(pname);
1770     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
1771         return getUnsignedLongParameter(pname);
1772     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
1773         return getUnsignedLongParameter(pname);
1774     case GraphicsContext3D::STENCIL_BACK_REF:
1775         return getLongParameter(pname);
1776     case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
1777         return getUnsignedLongParameter(pname);
1778     case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
1779         return getUnsignedLongParameter(pname);
1780     case GraphicsContext3D::STENCIL_BITS:
1781         return getLongParameter(pname);
1782     case GraphicsContext3D::STENCIL_CLEAR_VALUE:
1783         return getLongParameter(pname);
1784     case GraphicsContext3D::STENCIL_FAIL:
1785         return getUnsignedLongParameter(pname);
1786     case GraphicsContext3D::STENCIL_FUNC:
1787         return getUnsignedLongParameter(pname);
1788     case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
1789         return getUnsignedLongParameter(pname);
1790     case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
1791         return getUnsignedLongParameter(pname);
1792     case GraphicsContext3D::STENCIL_REF:
1793         return getLongParameter(pname);
1794     case GraphicsContext3D::STENCIL_TEST:
1795         return getBooleanParameter(pname);
1796     case GraphicsContext3D::STENCIL_VALUE_MASK:
1797         return getUnsignedLongParameter(pname);
1798     case GraphicsContext3D::STENCIL_WRITEMASK:
1799         return getUnsignedLongParameter(pname);
1800     case GraphicsContext3D::SUBPIXEL_BITS:
1801         return getLongParameter(pname);
1802     case GraphicsContext3D::TEXTURE_BINDING_2D:
1803         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
1804     case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
1805         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
1806     case GraphicsContext3D::UNPACK_ALIGNMENT:
1807         // FIXME: should this be "long" in the spec?
1808         return getIntParameter(pname);
1809     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
1810         return WebGLGetInfo(m_unpackFlipY);
1811     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
1812         return WebGLGetInfo(m_unpackPremultiplyAlpha);
1813     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
1814         return WebGLGetInfo(m_unpackColorspaceConversion);
1815     case GraphicsContext3D::VENDOR:
1816         return WebGLGetInfo("Webkit (" + m_context->getString(GraphicsContext3D::VENDOR) + ")");
1817     case GraphicsContext3D::VERSION:
1818         return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
1819     case GraphicsContext3D::VIEWPORT:
1820         return getWebGLIntArrayParameter(pname);
1821     default:
1822         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1823         return WebGLGetInfo();
1824     }
1825 }
1826
1827 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, unsigned long pname, ExceptionCode& ec)
1828 {
1829     UNUSED_PARAM(ec);
1830     if (isContextLost() || !validateWebGLObject(program))
1831         return WebGLGetInfo();
1832
1833     WebGLStateRestorer(this, false);
1834     int value = 0;
1835     switch (pname) {
1836     case GraphicsContext3D::DELETE_STATUS:
1837         return WebGLGetInfo(program->isDeleted());
1838     case GraphicsContext3D::VALIDATE_STATUS:
1839         m_context->getProgramiv(objectOrZero(program), pname, &value);
1840         return WebGLGetInfo(static_cast<bool>(value));
1841     case GraphicsContext3D::LINK_STATUS:
1842         return WebGLGetInfo(program->getLinkStatus());
1843     case GraphicsContext3D::INFO_LOG_LENGTH:
1844     case GraphicsContext3D::ATTACHED_SHADERS:
1845     case GraphicsContext3D::ACTIVE_ATTRIBUTES:
1846     case GraphicsContext3D::ACTIVE_ATTRIBUTE_MAX_LENGTH:
1847     case GraphicsContext3D::ACTIVE_UNIFORMS:
1848     case GraphicsContext3D::ACTIVE_UNIFORM_MAX_LENGTH:
1849         m_context->getProgramiv(objectOrZero(program), pname, &value);
1850         return WebGLGetInfo(static_cast<long>(value));
1851     default:
1852         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1853         return WebGLGetInfo();
1854     }
1855 }
1856
1857 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
1858 {
1859     UNUSED_PARAM(ec);
1860     if (isContextLost())
1861         return String();
1862     if (!validateWebGLObject(program))
1863         return "";
1864     WebGLStateRestorer(this, false);
1865     return m_context->getProgramInfoLog(objectOrZero(program));
1866 }
1867
1868 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(unsigned long target, unsigned long pname, ExceptionCode& ec)
1869 {
1870     UNUSED_PARAM(ec);
1871     if (isContextLost())
1872         return WebGLGetInfo();
1873     if (target != GraphicsContext3D::RENDERBUFFER) {
1874         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1875         return WebGLGetInfo();
1876     }
1877     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
1878         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1879         return WebGLGetInfo();
1880     }
1881
1882     if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
1883         && !m_renderbufferBinding->isValid()) {
1884         ASSERT(!isDepthStencilSupported());
1885         long value = 0;
1886         switch (pname) {
1887         case GraphicsContext3D::RENDERBUFFER_WIDTH:
1888             value = static_cast<long>(m_renderbufferBinding->getWidth());
1889             break;
1890         case GraphicsContext3D::RENDERBUFFER_HEIGHT:
1891             value = static_cast<long>(m_renderbufferBinding->getHeight());
1892             break;
1893         case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
1894         case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
1895         case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
1896         case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
1897             value = 0;
1898             break;
1899         case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
1900             value = 24;
1901             break;
1902         case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
1903             value = 8;
1904             break;
1905         case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
1906             return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
1907         default:
1908             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1909             return WebGLGetInfo();
1910         }
1911         return WebGLGetInfo(value);
1912     }
1913
1914     WebGLStateRestorer(this, false);
1915     int value = 0;
1916     switch (pname) {
1917     case GraphicsContext3D::RENDERBUFFER_WIDTH:
1918     case GraphicsContext3D::RENDERBUFFER_HEIGHT:
1919     case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
1920     case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
1921     case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
1922     case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
1923     case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
1924     case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
1925         m_context->getRenderbufferParameteriv(target, pname, &value);
1926         return WebGLGetInfo(static_cast<long>(value));
1927     case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
1928         return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
1929     default:
1930         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1931         return WebGLGetInfo();
1932     }
1933 }
1934
1935 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, unsigned long pname, ExceptionCode& ec)
1936 {
1937     UNUSED_PARAM(ec);
1938     if (isContextLost() || !validateWebGLObject(shader))
1939         return WebGLGetInfo();
1940     WebGLStateRestorer(this, false);
1941     int value = 0;
1942     switch (pname) {
1943     case GraphicsContext3D::DELETE_STATUS:
1944         return WebGLGetInfo(shader->isDeleted());
1945     case GraphicsContext3D::COMPILE_STATUS:
1946         m_context->getShaderiv(objectOrZero(shader), pname, &value);
1947         return WebGLGetInfo(static_cast<bool>(value));
1948     case GraphicsContext3D::SHADER_TYPE:
1949         m_context->getShaderiv(objectOrZero(shader), pname, &value);
1950         return WebGLGetInfo(static_cast<unsigned long>(value));
1951     case GraphicsContext3D::INFO_LOG_LENGTH:
1952     case GraphicsContext3D::SHADER_SOURCE_LENGTH:
1953         m_context->getShaderiv(objectOrZero(shader), pname, &value);
1954         return WebGLGetInfo(static_cast<long>(value));
1955     default:
1956         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1957         return WebGLGetInfo();
1958     }
1959 }
1960
1961 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
1962 {
1963     UNUSED_PARAM(ec);
1964     if (isContextLost())
1965         return String();
1966     if (!validateWebGLObject(shader))
1967         return "";
1968     WebGLStateRestorer(this, false);
1969     return m_context->getShaderInfoLog(objectOrZero(shader));
1970 }
1971
1972 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
1973 {
1974     UNUSED_PARAM(ec);
1975     if (isContextLost())
1976         return String();
1977     if (!validateWebGLObject(shader))
1978         return "";
1979     WebGLStateRestorer(this, false);
1980     return m_context->getShaderSource(objectOrZero(shader));
1981 }
1982
1983 Vector<String> WebGLRenderingContext::getSupportedExtensions()
1984 {
1985     Vector<String> result;
1986     if (m_context->getExtensions()->supports("GL_OES_texture_float"))
1987         result.append("OES_texture_float");
1988     return result;
1989 }
1990
1991 WebGLGetInfo WebGLRenderingContext::getTexParameter(unsigned long target, unsigned long pname, ExceptionCode& ec)
1992 {
1993     UNUSED_PARAM(ec);
1994     if (isContextLost())
1995         return WebGLGetInfo();
1996     WebGLTexture* tex = validateTextureBinding(target, false);
1997     if (!tex)
1998         return WebGLGetInfo();
1999     WebGLStateRestorer(this, false);
2000     int value = 0;
2001     switch (pname) {
2002     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2003     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2004     case GraphicsContext3D::TEXTURE_WRAP_S:
2005     case GraphicsContext3D::TEXTURE_WRAP_T:
2006         m_context->getTexParameteriv(target, pname, &value);
2007         return WebGLGetInfo(static_cast<unsigned long>(value));
2008     default:
2009         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2010         return WebGLGetInfo();
2011     }
2012 }
2013
2014 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2015 {
2016     UNUSED_PARAM(ec);
2017     if (isContextLost() || !validateWebGLObject(program))
2018         return WebGLGetInfo();
2019     if (!uniformLocation || uniformLocation->program() != program) {
2020         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2021         return WebGLGetInfo();
2022     }
2023     long location = uniformLocation->location();
2024     
2025     WebGLStateRestorer(this, false);
2026     // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2027     int activeUniforms = 0;
2028     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2029     for (int i = 0; i < activeUniforms; i++) {
2030         ActiveInfo info;
2031         if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2032             return WebGLGetInfo();
2033         // Strip "[0]" from the name if it's an array.
2034         if (info.size > 1)
2035             info.name = info.name.left(info.name.length() - 3);
2036         // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2037         for (int index = 0; index < info.size; ++index) {
2038             String name = info.name;
2039             if (info.size > 1 && index >= 1) {
2040                 name.append('[');
2041                 name.append(String::number(index));
2042                 name.append(']');
2043             }
2044             // Now need to look this up by name again to find its location
2045             long loc = m_context->getUniformLocation(objectOrZero(program), name);
2046             if (loc == location) {
2047                 // Found it. Use the type in the ActiveInfo to determine the return type.
2048                 GraphicsContext3D::WebGLEnumType baseType;
2049                 unsigned length;
2050                 switch (info.type) {
2051                 case GraphicsContext3D::BOOL:
2052                     baseType = GraphicsContext3D::BOOL;
2053                     length = 1;
2054                     break;
2055                 case GraphicsContext3D::BOOL_VEC2:
2056                     baseType = GraphicsContext3D::BOOL;
2057                     length = 2;
2058                     break;
2059                 case GraphicsContext3D::BOOL_VEC3:
2060                     baseType = GraphicsContext3D::BOOL;
2061                     length = 3;
2062                     break;
2063                 case GraphicsContext3D::BOOL_VEC4:
2064                     baseType = GraphicsContext3D::BOOL;
2065                     length = 4;
2066                     break;
2067                 case GraphicsContext3D::INT:
2068                     baseType = GraphicsContext3D::INT;
2069                     length = 1;
2070                     break;
2071                 case GraphicsContext3D::INT_VEC2:
2072                     baseType = GraphicsContext3D::INT;
2073                     length = 2;
2074                     break;
2075                 case GraphicsContext3D::INT_VEC3:
2076                     baseType = GraphicsContext3D::INT;
2077                     length = 3;
2078                     break;
2079                 case GraphicsContext3D::INT_VEC4:
2080                     baseType = GraphicsContext3D::INT;
2081                     length = 4;
2082                     break;
2083                 case GraphicsContext3D::FLOAT:
2084                     baseType = GraphicsContext3D::FLOAT;
2085                     length = 1;
2086                     break;
2087                 case GraphicsContext3D::FLOAT_VEC2:
2088                     baseType = GraphicsContext3D::FLOAT;
2089                     length = 2;
2090                     break;
2091                 case GraphicsContext3D::FLOAT_VEC3:
2092                     baseType = GraphicsContext3D::FLOAT;
2093                     length = 3;
2094                     break;
2095                 case GraphicsContext3D::FLOAT_VEC4:
2096                     baseType = GraphicsContext3D::FLOAT;
2097                     length = 4;
2098                     break;
2099                 case GraphicsContext3D::FLOAT_MAT2:
2100                     baseType = GraphicsContext3D::FLOAT;
2101                     length = 4;
2102                     break;
2103                 case GraphicsContext3D::FLOAT_MAT3:
2104                     baseType = GraphicsContext3D::FLOAT;
2105                     length = 9;
2106                     break;
2107                 case GraphicsContext3D::FLOAT_MAT4:
2108                     baseType = GraphicsContext3D::FLOAT;
2109                     length = 16;
2110                     break;
2111                 default:
2112                     // Can't handle this type
2113                     // FIXME: what to do about samplers?
2114                     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2115                     return WebGLGetInfo();
2116                 }
2117                 switch (baseType) {
2118                 case GraphicsContext3D::FLOAT: {
2119                     float value[16] = {0};
2120                     m_context->getUniformfv(objectOrZero(program), location, value);
2121                     if (length == 1)
2122                         return WebGLGetInfo(value[0]);
2123                     return WebGLGetInfo(Float32Array::create(value, length));
2124                 }
2125                 case GraphicsContext3D::INT: {
2126                     int value[4] = {0};
2127                     m_context->getUniformiv(objectOrZero(program), location, value);
2128                     if (length == 1)
2129                         return WebGLGetInfo(static_cast<long>(value[0]));
2130                     return WebGLGetInfo(Int32Array::create(value, length));
2131                 }
2132                 case GraphicsContext3D::BOOL: {
2133                     int value[4] = {0};
2134                     m_context->getUniformiv(objectOrZero(program), location, value);
2135                     if (length > 1) {
2136                         bool boolValue[16] = {0};
2137                         for (unsigned j = 0; j < length; j++)
2138                             boolValue[j] = static_cast<bool>(value[j]);
2139                         return WebGLGetInfo(boolValue, length);
2140                     }
2141                     return WebGLGetInfo(static_cast<bool>(value[0]));
2142                 }
2143                 default:
2144                     notImplemented();
2145                 }
2146             }
2147         }
2148     }
2149     // If we get here, something went wrong in our unfortunately complex logic above
2150     m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2151     return WebGLGetInfo();
2152 }
2153
2154 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
2155 {
2156     UNUSED_PARAM(ec);
2157     if (isContextLost() || !validateWebGLObject(program))
2158         return 0;
2159     if (!validateString(name))
2160         return 0;
2161     WebGLStateRestorer(this, false);
2162     long uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2163     if (uniformLocation == -1)
2164         return 0;
2165     return WebGLUniformLocation::create(program, uniformLocation);
2166 }
2167
2168 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(unsigned long index, unsigned long pname, ExceptionCode& ec)
2169 {
2170     UNUSED_PARAM(ec);
2171     if (isContextLost())
2172         return WebGLGetInfo();
2173     WebGLStateRestorer(this, false);
2174     if (index >= m_maxVertexAttribs) {
2175         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2176         return WebGLGetInfo();
2177     }
2178     switch (pname) {
2179     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2180         if ((!isGLES2Compliant() && !index && m_vertexAttribState[0].bufferBinding == m_vertexAttrib0Buffer)
2181             || index >= m_vertexAttribState.size()
2182             || !m_vertexAttribState[index].bufferBinding
2183             || !m_vertexAttribState[index].bufferBinding->object())
2184             return WebGLGetInfo();
2185         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_vertexAttribState[index].bufferBinding));
2186     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
2187         if (index >= m_vertexAttribState.size())
2188             return WebGLGetInfo(false);
2189         return WebGLGetInfo(m_vertexAttribState[index].enabled);
2190     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
2191         if (index >= m_vertexAttribState.size())
2192             return WebGLGetInfo(false);
2193         return WebGLGetInfo(m_vertexAttribState[index].normalized);
2194     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
2195         if (index >= m_vertexAttribState.size())
2196             return WebGLGetInfo(static_cast<long>(4));
2197         return WebGLGetInfo(m_vertexAttribState[index].size);
2198     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
2199         if (index >= m_vertexAttribState.size())
2200             return WebGLGetInfo(static_cast<long>(0));
2201         return WebGLGetInfo(m_vertexAttribState[index].originalStride);
2202     case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
2203         if (index >= m_vertexAttribState.size())
2204             return WebGLGetInfo(static_cast<unsigned long>(GraphicsContext3D::FLOAT));
2205         return WebGLGetInfo(m_vertexAttribState[index].type);
2206     case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
2207         if (index >= m_vertexAttribState.size()) {
2208             float value[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
2209             return WebGLGetInfo(Float32Array::create(value, 4));
2210         }
2211         return WebGLGetInfo(Float32Array::create(m_vertexAttribState[index].value, 4));
2212     default:
2213         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2214         return WebGLGetInfo();
2215     }
2216 }
2217
2218 long WebGLRenderingContext::getVertexAttribOffset(unsigned long index, unsigned long pname)
2219 {
2220     if (isContextLost())
2221         return 0;
2222     long result = m_context->getVertexAttribOffset(index, pname);
2223     cleanupAfterGraphicsCall(false);
2224     return result;
2225 }
2226
2227 void WebGLRenderingContext::hint(unsigned long target, unsigned long mode)
2228 {
2229     if (isContextLost())
2230         return;
2231     if (target != GraphicsContext3D::GENERATE_MIPMAP_HINT) {
2232         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2233         return;
2234     }
2235     m_context->hint(target, mode);
2236     cleanupAfterGraphicsCall(false);
2237 }
2238
2239 bool WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
2240 {
2241     if (!buffer || isContextLost())
2242         return false;
2243
2244     if (!buffer->hasEverBeenBound())
2245         return false;
2246
2247     return m_context->isBuffer(buffer->object());
2248 }
2249
2250 bool WebGLRenderingContext::isContextLost()
2251 {
2252     if (m_restoreTimer.isActive())
2253         return true;
2254
2255     bool newContextLost = m_context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR;
2256
2257     if (newContextLost != m_contextLost)
2258         m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
2259
2260     return m_contextLost;
2261 }
2262
2263 bool WebGLRenderingContext::isEnabled(unsigned long cap)
2264 {
2265     if (!validateCapability(cap) || isContextLost())
2266         return false;
2267     return m_context->isEnabled(cap);
2268 }
2269
2270 bool WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer)
2271 {
2272     if (!framebuffer || isContextLost())
2273         return false;
2274
2275     if (!framebuffer->hasEverBeenBound())
2276         return false;
2277
2278     return m_context->isFramebuffer(framebuffer->object());
2279 }
2280
2281 bool WebGLRenderingContext::isProgram(WebGLProgram* program)
2282 {
2283     if (!program || isContextLost())
2284         return false;
2285
2286     return m_context->isProgram(program->object());
2287 }
2288
2289 bool WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2290 {
2291     if (!renderbuffer || isContextLost())
2292         return false;
2293
2294     if (!renderbuffer->hasEverBeenBound())
2295         return false;
2296
2297     return m_context->isRenderbuffer(renderbuffer->object());
2298 }
2299
2300 bool WebGLRenderingContext::isShader(WebGLShader* shader)
2301 {
2302     if (!shader || isContextLost())
2303         return false;
2304
2305     return m_context->isShader(shader->object());
2306 }
2307
2308 bool WebGLRenderingContext::isTexture(WebGLTexture* texture)
2309 {
2310     if (!texture || isContextLost())
2311         return false;
2312
2313     if (!texture->hasEverBeenBound())
2314         return false;
2315
2316     return m_context->isTexture(texture->object());
2317 }
2318
2319 void WebGLRenderingContext::lineWidth(float width)
2320 {
2321     if (isContextLost())
2322         return;
2323     m_context->lineWidth((float) width);
2324     cleanupAfterGraphicsCall(false);
2325 }
2326
2327 void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec)
2328 {
2329     UNUSED_PARAM(ec);
2330     if (isContextLost() || !validateWebGLObject(program))
2331         return;
2332     if (!isGLES2Compliant()) {
2333         if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
2334             program->setLinkStatus(false);
2335             return;
2336         }
2337     }
2338
2339     m_context->linkProgram(objectOrZero(program));
2340     program->increaseLinkCount();
2341     // cache link status
2342     int value = 0;
2343     m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::LINK_STATUS, &value);
2344     program->setLinkStatus(static_cast<bool>(value));
2345     // Need to cache link status before caching active attribute locations.
2346     program->cacheActiveAttribLocations();
2347     cleanupAfterGraphicsCall(false);
2348 }
2349
2350 void WebGLRenderingContext::pixelStorei(unsigned long pname, long param)
2351 {
2352     if (isContextLost())
2353         return;
2354     switch (pname) {
2355     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2356         m_unpackFlipY = param;
2357         break;
2358     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2359         m_unpackPremultiplyAlpha = param;
2360         break;
2361     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2362         if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
2363             m_unpackColorspaceConversion = static_cast<unsigned long>(param);
2364         else {
2365             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2366             return;
2367         }
2368         break;
2369     case GraphicsContext3D::PACK_ALIGNMENT:
2370     case GraphicsContext3D::UNPACK_ALIGNMENT:
2371         if (param == 1 || param == 2 || param == 4 || param == 8) {
2372             if (pname == GraphicsContext3D::PACK_ALIGNMENT)
2373                 m_packAlignment = static_cast<int>(param);
2374             else // GraphicsContext3D::UNPACK_ALIGNMENT:
2375                 m_unpackAlignment = static_cast<int>(param);
2376             m_context->pixelStorei(pname, param);
2377             cleanupAfterGraphicsCall(false);
2378         } else {
2379             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2380             return;
2381         }
2382         break;
2383     default:
2384         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2385         return;
2386     }
2387 }
2388
2389 void WebGLRenderingContext::polygonOffset(float factor, float units)
2390 {
2391     if (isContextLost())
2392         return;
2393     m_context->polygonOffset((float) factor, (float) units);
2394     cleanupAfterGraphicsCall(false);
2395 }
2396
2397 void WebGLRenderingContext::readPixels(long x, long y, long width, long height, unsigned long format, unsigned long type, ArrayBufferView* pixels, ExceptionCode& ec)
2398 {
2399     if (isContextLost())
2400         return;
2401     if (!canvas()->originClean()) {
2402         ec = SECURITY_ERR;
2403         return;
2404     }
2405     // Validate input parameters.
2406     unsigned int componentsPerPixel, bytesPerComponent;
2407     if (!m_context->computeFormatAndTypeParameters(format, type, &componentsPerPixel, &bytesPerComponent)) {
2408         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2409         return;
2410     }
2411     if (!pixels) {
2412         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2413         return;
2414     }
2415     if (width < 0 || height < 0) {
2416         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2417         return;
2418     }
2419     if (format != GraphicsContext3D::RGBA && type != GraphicsContext3D::UNSIGNED_BYTE) {
2420         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2421         return;
2422     }
2423     if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
2424         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2425         return;
2426     }
2427     // Validate array type against pixel type.
2428     if ((type == GraphicsContext3D::UNSIGNED_BYTE && !pixels->isUnsignedByteArray())
2429         || (type != GraphicsContext3D::UNSIGNED_BYTE && !pixels->isUnsignedShortArray())) {
2430         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2431         return;
2432     }
2433     if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
2434         m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
2435         return;
2436     }
2437     // Calculate array size, taking into consideration of PACK_ALIGNMENT.
2438     unsigned long bytesPerRow = componentsPerPixel * bytesPerComponent * width;
2439     unsigned long padding = 0;
2440     unsigned long residualBytes = bytesPerRow % m_packAlignment;
2441     if (residualBytes) {
2442         padding = m_packAlignment - residualBytes;
2443         bytesPerRow += padding;
2444     }
2445     // The last row needs no padding.
2446     unsigned long totalBytes = bytesPerRow * height - padding;
2447     unsigned long num = totalBytes / bytesPerComponent;
2448     if (pixels->byteLength() / bytesPerComponent < num) {
2449         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2450         return;
2451     }
2452     void* data = pixels->baseAddress();
2453     m_context->readPixels(x, y, width, height, format, type, data);
2454 #if PLATFORM(CG)
2455     // FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
2456     // when alpha is off, readPixels should set alpha to 255 instead of 0.
2457     if ((format == GraphicsContext3D::ALPHA || format == GraphicsContext3D::RGBA) && !m_context->getContextAttributes().alpha) {
2458         if (type == GraphicsContext3D::UNSIGNED_BYTE) {
2459             unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
2460             for (long iy = 0; iy < height; ++iy) {
2461                 for (long ix = 0; ix < width; ++ix) {
2462                     pixels[componentsPerPixel - 1] = 255;
2463                     pixels += componentsPerPixel;
2464                 }
2465                 pixels += padding;
2466             }
2467         }
2468         // FIXME: check whether we need to do the same with UNSIGNED_SHORT.
2469     }
2470 #endif
2471     cleanupAfterGraphicsCall(false);
2472 }
2473
2474 void WebGLRenderingContext::releaseShaderCompiler()
2475 {
2476     if (isContextLost())
2477         return;
2478     m_context->releaseShaderCompiler();
2479     cleanupAfterGraphicsCall(false);
2480 }
2481
2482 void WebGLRenderingContext::renderbufferStorage(unsigned long target, unsigned long internalformat, long width, long height)
2483 {
2484     if (isContextLost())
2485         return;
2486     if (target != GraphicsContext3D::RENDERBUFFER) {
2487         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2488         return;
2489     }
2490     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2491         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2492         return;
2493     }
2494     if (!validateSize(width, height))
2495         return;
2496     switch (internalformat) {
2497     case GraphicsContext3D::DEPTH_COMPONENT16:
2498     case GraphicsContext3D::RGBA4:
2499     case GraphicsContext3D::RGB5_A1:
2500     case GraphicsContext3D::RGB565:
2501     case GraphicsContext3D::STENCIL_INDEX8:
2502         m_context->renderbufferStorage(target, internalformat, width, height);
2503         m_renderbufferBinding->setInternalFormat(internalformat);
2504         m_renderbufferBinding->setIsValid(true);
2505         m_renderbufferBinding->setSize(width, height);
2506         cleanupAfterGraphicsCall(false);
2507         break;
2508     case GraphicsContext3D::DEPTH_STENCIL:
2509         if (isDepthStencilSupported()) {
2510             m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
2511             cleanupAfterGraphicsCall(false);
2512         }
2513         m_renderbufferBinding->setSize(width, height);
2514         m_renderbufferBinding->setIsValid(isDepthStencilSupported());
2515         m_renderbufferBinding->setInternalFormat(internalformat);
2516         break;
2517     default:
2518         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2519     }
2520 }
2521
2522 void WebGLRenderingContext::sampleCoverage(float value, bool invert)
2523 {
2524     if (isContextLost())
2525         return;
2526     m_context->sampleCoverage((float) value, invert);
2527     cleanupAfterGraphicsCall(false);
2528 }
2529
2530 void WebGLRenderingContext::scissor(long x, long y, long width, long height)
2531 {
2532     if (isContextLost())
2533         return;
2534     if (!validateSize(width, height))
2535         return;
2536     m_context->scissor(x, y, width, height);
2537     cleanupAfterGraphicsCall(false);
2538 }
2539
2540 void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
2541 {
2542     UNUSED_PARAM(ec);
2543     if (isContextLost() || !validateWebGLObject(shader))
2544         return;
2545     if (!validateString(string))
2546         return;
2547     m_context->shaderSource(objectOrZero(shader), string);
2548     cleanupAfterGraphicsCall(false);
2549 }
2550
2551 void WebGLRenderingContext::stencilFunc(unsigned long func, long ref, unsigned long mask)
2552 {
2553     if (isContextLost())
2554         return;
2555     if (!validateStencilFunc(func))
2556         return;
2557     m_stencilFuncRef = ref;
2558     m_stencilFuncRefBack = ref;
2559     m_stencilFuncMask = mask;
2560     m_stencilFuncMaskBack = mask;
2561     m_context->stencilFunc(func, ref, mask);
2562     cleanupAfterGraphicsCall(false);
2563 }
2564
2565 void WebGLRenderingContext::stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask)
2566 {
2567     if (isContextLost())
2568         return;
2569     if (!validateStencilFunc(func))
2570         return;
2571     switch (face) {
2572     case GraphicsContext3D::FRONT_AND_BACK:
2573         m_stencilFuncRef = ref;
2574         m_stencilFuncRefBack = ref;
2575         m_stencilFuncMask = mask;
2576         m_stencilFuncMaskBack = mask;
2577         break;
2578     case GraphicsContext3D::FRONT:
2579         m_stencilFuncRef = ref;
2580         m_stencilFuncMask = mask;
2581         break;
2582     case GraphicsContext3D::BACK:
2583         m_stencilFuncRefBack = ref;
2584         m_stencilFuncMaskBack = mask;
2585         break;
2586     default:
2587         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2588         return;
2589     }
2590     m_context->stencilFuncSeparate(face, func, ref, mask);
2591     cleanupAfterGraphicsCall(false);
2592 }
2593
2594 void WebGLRenderingContext::stencilMask(unsigned long mask)
2595 {
2596     if (isContextLost())
2597         return;
2598     m_stencilMask = mask;
2599     m_stencilMaskBack = mask;
2600     m_context->stencilMask(mask);
2601     cleanupAfterGraphicsCall(false);
2602 }
2603
2604 void WebGLRenderingContext::stencilMaskSeparate(unsigned long face, unsigned long mask)
2605 {
2606     if (isContextLost())
2607         return;
2608     switch (face) {
2609     case GraphicsContext3D::FRONT_AND_BACK:
2610         m_stencilMask = mask;
2611         m_stencilMaskBack = mask;
2612         break;
2613     case GraphicsContext3D::FRONT:
2614         m_stencilMask = mask;
2615         break;
2616     case GraphicsContext3D::BACK:
2617         m_stencilMaskBack = mask;
2618         break;
2619     default:
2620         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2621         return;
2622     }
2623     m_context->stencilMaskSeparate(face, mask);
2624     cleanupAfterGraphicsCall(false);
2625 }
2626
2627 void WebGLRenderingContext::stencilOp(unsigned long fail, unsigned long zfail, unsigned long zpass)
2628 {
2629     if (isContextLost())
2630         return;
2631     m_context->stencilOp(fail, zfail, zpass);
2632     cleanupAfterGraphicsCall(false);
2633 }
2634
2635 void WebGLRenderingContext::stencilOpSeparate(unsigned long face, unsigned long fail, unsigned long zfail, unsigned long zpass)
2636 {
2637     if (isContextLost())
2638         return;
2639     m_context->stencilOpSeparate(face, fail, zfail, zpass);
2640     cleanupAfterGraphicsCall(false);
2641 }
2642
2643 void WebGLRenderingContext::texImage2DBase(unsigned target, unsigned level, unsigned internalformat,
2644                                            int width, int height, unsigned border,
2645                                            unsigned format, unsigned type, void* pixels, ExceptionCode& ec)
2646 {
2647     // FIXME: For now we ignore any errors returned
2648     ec = 0;
2649     if (!validateTexFuncParameters(target, level, internalformat, width, height, border, format, type))
2650         return;
2651     WebGLTexture* tex = validateTextureBinding(target, true);
2652     if (!tex)
2653         return;
2654     if (!isGLES2NPOTStrict()) {
2655         if (level && WebGLTexture::isNPOT(width, height)) {
2656             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2657             return;
2658         }
2659     }
2660     if (!pixels && !isResourceSafe()) {
2661         bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
2662                                                          border, format, type);
2663         if (!succeed)
2664             return;
2665     } else {
2666         m_context->texImage2D(target, level, internalformat, width, height,
2667                               border, format, type, pixels);
2668     }
2669     tex->setLevelInfo(target, level, internalformat, width, height, type);
2670     cleanupAfterGraphicsCall(false);
2671 }
2672
2673 void WebGLRenderingContext::texImage2DImpl(unsigned target, unsigned level, unsigned internalformat,
2674                                            unsigned format, unsigned type, Image* image,
2675                                            bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
2676 {
2677     ec = 0;
2678     Vector<uint8_t> data;
2679     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
2680         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2681         return;
2682     }
2683     if (m_unpackAlignment != 1)
2684         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
2685     texImage2DBase(target, level, internalformat, image->width(), image->height(), 0,
2686                    format, type, data.data(), ec);
2687     if (m_unpackAlignment != 1)
2688         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
2689 }
2690
2691 void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned internalformat,
2692                                        int width, int height, unsigned border,
2693                                        unsigned format, unsigned type, ArrayBufferView* pixels, ExceptionCode& ec)
2694 {
2695     if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
2696         return;
2697     void* data = pixels ? pixels->baseAddress() : 0;
2698     Vector<uint8_t> tempData;
2699     bool changeUnpackAlignment = false;
2700     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
2701         if (!m_context->extractTextureData(width, height, format, type,
2702                                            m_unpackAlignment,
2703                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
2704                                            data,
2705                                            tempData))
2706             return;
2707         data = tempData.data();
2708         changeUnpackAlignment = true;
2709     }
2710     if (changeUnpackAlignment)
2711         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
2712     texImage2DBase(target, level, internalformat, width, height, border,
2713                    format, type, data, ec);
2714     if (changeUnpackAlignment)
2715         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
2716 }
2717
2718 void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned internalformat,
2719                                        unsigned format, unsigned type, ImageData* pixels, ExceptionCode& ec)
2720 {
2721     ec = 0;
2722     if (isContextLost())
2723         return;
2724     Vector<uint8_t> data;
2725     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
2726         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2727         return;
2728     }
2729     if (m_unpackAlignment != 1)
2730         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
2731     texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0,
2732                    format, type, data.data(), ec);
2733     if (m_unpackAlignment != 1)
2734         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
2735 }
2736
2737 void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned internalformat,
2738                                        unsigned format, unsigned type, HTMLImageElement* image, ExceptionCode& ec)
2739 {
2740     ec = 0;
2741     if (isContextLost())
2742         return;
2743     if (!image || !image->cachedImage()) {
2744         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2745         return;
2746     }
2747     checkOrigin(image);
2748     texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->image(),
2749                    m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
2750 }
2751
2752 void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned internalformat,
2753                                        unsigned format, unsigned type, HTMLCanvasElement* canvas, ExceptionCode& ec)
2754 {
2755     ec = 0;
2756     if (isContextLost())
2757         return;
2758     if (!canvas || !canvas->buffer()) {
2759         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2760         return;
2761     }
2762     checkOrigin(canvas);
2763     texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(),
2764                    m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
2765 }
2766
2767 PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video)
2768 {
2769     if (!video || !video->videoWidth() || !video->videoHeight()) {
2770         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2771         return 0;
2772     }
2773     IntSize size(video->videoWidth(), video->videoHeight());
2774     ImageBuffer* buf = m_videoCache.imageBuffer(size);
2775     if (!buf) {
2776         m_context->synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY);
2777         return 0;
2778     }
2779     checkOrigin(video);
2780     IntRect destRect(0, 0, size.width(), size.height());
2781     // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
2782     video->paintCurrentFrameInContext(buf->context(), destRect);
2783     return buf->copyImage();
2784 }
2785
2786 void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned internalformat,
2787                                        unsigned format, unsigned type, HTMLVideoElement* video, ExceptionCode& ec)
2788 {
2789     ec = 0;
2790     if (isContextLost())
2791         return;
2792     RefPtr<Image> image = videoFrameToImage(video);
2793     if (!video)
2794         return;
2795     texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
2796 }
2797
2798 void WebGLRenderingContext::texParameter(unsigned long target, unsigned long pname, float paramf, int parami, bool isFloat)
2799 {
2800     if (isContextLost())
2801         return;
2802     WebGLTexture* tex = validateTextureBinding(target, false);
2803     if (!tex)
2804         return;
2805     switch (pname) {
2806     case GraphicsContext3D::TEXTURE_MIN_FILTER:
2807     case GraphicsContext3D::TEXTURE_MAG_FILTER:
2808         break;
2809     case GraphicsContext3D::TEXTURE_WRAP_S:
2810     case GraphicsContext3D::TEXTURE_WRAP_T:
2811         if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT)
2812             || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) {
2813             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2814             return;
2815         }
2816         break;
2817     default:
2818         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2819         return;
2820     }
2821     if (isFloat) {
2822         tex->setParameterf(pname, paramf);
2823         m_context->texParameterf(target, pname, paramf);
2824     } else {
2825         tex->setParameteri(pname, parami);
2826         m_context->texParameteri(target, pname, parami);
2827     }
2828     cleanupAfterGraphicsCall(false);
2829 }
2830
2831 void WebGLRenderingContext::texParameterf(unsigned target, unsigned pname, float param)
2832 {
2833     texParameter(target, pname, param, 0, true);
2834 }
2835
2836 void WebGLRenderingContext::texParameteri(unsigned target, unsigned pname, int param)
2837 {
2838     texParameter(target, pname, 0, param, false);
2839 }
2840
2841 void WebGLRenderingContext::texSubImage2DBase(unsigned target, unsigned level, int xoffset, int yoffset,
2842                                               int width, int height,
2843                                               unsigned format, unsigned type, void* pixels, ExceptionCode& ec)
2844 {
2845     // FIXME: For now we ignore any errors returned
2846     ec = 0;
2847     if (isContextLost())
2848         return;
2849     if (!validateTexFuncFormatAndType(format, type))
2850         return;
2851     if (!validateTextureBinding(target, true))
2852         return;
2853     if (!validateSize(xoffset, yoffset) || !validateSize(width, height))
2854         return;
2855     m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
2856     cleanupAfterGraphicsCall(false);
2857 }
2858
2859 void WebGLRenderingContext::texSubImage2DImpl(unsigned target, unsigned level, int xoffset, int yoffset,
2860                                               unsigned format, unsigned type,
2861                                               Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
2862 {
2863     ec = 0;
2864     if (isContextLost())
2865         return;
2866     Vector<uint8_t> data;
2867     if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
2868         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2869         return;
2870     }
2871     texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(),
2872                       format, type, data.data(), ec);
2873 }
2874
2875 void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, int xoffset, int yoffset,
2876                                           int width, int height,
2877                                           unsigned format, unsigned type, ArrayBufferView* pixels, ExceptionCode& ec)
2878 {
2879     if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
2880         return;
2881     void* data = pixels ? pixels->baseAddress() : 0;
2882     Vector<uint8_t> tempData;
2883     bool changeUnpackAlignment = false;
2884     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
2885         if (!m_context->extractTextureData(width, height, format, type,
2886                                            m_unpackAlignment,
2887                                            m_unpackFlipY, m_unpackPremultiplyAlpha,
2888                                            data,
2889                                            tempData))
2890             return;
2891         data = tempData.data();
2892         changeUnpackAlignment = true;
2893     }
2894     if (changeUnpackAlignment)
2895         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
2896     texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
2897     if (changeUnpackAlignment)
2898         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
2899 }
2900
2901 void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, int xoffset, int yoffset,
2902                                           unsigned format, unsigned type, ImageData* pixels, ExceptionCode& ec)
2903 {
2904     ec = 0;
2905     if (isContextLost())
2906         return;
2907     Vector<uint8_t> data;
2908     if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
2909         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2910         return;
2911     }
2912     texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(),
2913                       format, type, data.data(), ec);
2914 }
2915
2916 void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, int xoffset, int yoffset,
2917                                           unsigned format, unsigned type, HTMLImageElement* image, ExceptionCode& ec)
2918 {
2919     ec = 0;
2920     if (isContextLost())
2921         return;
2922     if (!image || !image->cachedImage()) {
2923         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2924         return;
2925     }
2926     checkOrigin(image);
2927     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image->cachedImage()->image(),
2928                       m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
2929 }
2930
2931 void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, int xoffset, int yoffset,
2932                                           unsigned format, unsigned type, HTMLCanvasElement* canvas, ExceptionCode& ec)
2933 {
2934     ec = 0;
2935     if (isContextLost())
2936         return;
2937     if (!canvas || !canvas->buffer()) {
2938         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2939         return;
2940     }
2941     checkOrigin(canvas);
2942     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(),
2943                       m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
2944 }
2945
2946 void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, int xoffset, int yoffset,
2947                                           unsigned format, unsigned type, HTMLVideoElement* video, ExceptionCode& ec)
2948 {
2949     ec = 0;
2950     if (isContextLost())
2951         return;
2952     RefPtr<Image> image = videoFrameToImage(video);
2953     if (!video)
2954         return;
2955     texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
2956 }
2957
2958 void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, float x, ExceptionCode& ec)
2959 {
2960     UNUSED_PARAM(ec);
2961     if (isContextLost() || !location)
2962         return;
2963
2964     if (location->program() != m_currentProgram) {
2965         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2966         return;
2967     }
2968
2969     m_context->uniform1f(location->location(), x);
2970     cleanupAfterGraphicsCall(false);
2971 }
2972
2973 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
2974 {
2975     UNUSED_PARAM(ec);
2976     if (isContextLost() || !validateUniformParameters(location, v, 1))
2977         return;
2978
2979     m_context->uniform1fv(location->location(), v->data(), v->length());
2980     cleanupAfterGraphicsCall(false);
2981 }
2982
2983 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec)
2984 {
2985     UNUSED_PARAM(ec);
2986     if (isContextLost() || !validateUniformParameters(location, v, size, 1))
2987         return;
2988
2989     m_context->uniform1fv(location->location(), v, size);
2990     cleanupAfterGraphicsCall(false);
2991 }
2992
2993 void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, int x, ExceptionCode& ec)
2994 {
2995     UNUSED_PARAM(ec);
2996     if (isContextLost() || !location)
2997         return;
2998
2999     if (location->program() != m_currentProgram) {
3000         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3001         return;
3002     }
3003
3004     m_context->uniform1i(location->location(), x);
3005     cleanupAfterGraphicsCall(false);
3006 }
3007
3008 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3009 {
3010     UNUSED_PARAM(ec);
3011     if (isContextLost() || !validateUniformParameters(location, v, 1))
3012         return;
3013
3014     m_context->uniform1iv(location->location(), v->data(), v->length());
3015     cleanupAfterGraphicsCall(false);
3016 }
3017
3018 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec)
3019 {
3020     UNUSED_PARAM(ec);
3021     if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3022         return;
3023
3024     m_context->uniform1iv(location->location(), v, size);
3025     cleanupAfterGraphicsCall(false);
3026 }
3027
3028 void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, float x, float y, ExceptionCode& ec)
3029 {
3030     UNUSED_PARAM(ec);
3031     if (isContextLost() || !location)
3032         return;
3033
3034     if (location->program() != m_currentProgram) {
3035         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3036         return;
3037     }
3038
3039     m_context->uniform2f(location->location(), x, y);
3040     cleanupAfterGraphicsCall(false);
3041 }
3042
3043 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3044 {
3045     UNUSED_PARAM(ec);
3046     if (isContextLost() || !validateUniformParameters(location, v, 2))
3047         return;
3048
3049     m_context->uniform2fv(location->location(), v->data(), v->length() / 2);
3050     cleanupAfterGraphicsCall(false);
3051 }
3052
3053 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec)
3054 {
3055     UNUSED_PARAM(ec);
3056     if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3057         return;
3058
3059     m_context->uniform2fv(location->location(), v, size / 2);
3060     cleanupAfterGraphicsCall(false);
3061 }
3062
3063 void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, int x, int y, ExceptionCode& ec)
3064 {
3065     UNUSED_PARAM(ec);
3066     if (isContextLost() || !location)
3067         return;
3068
3069     if (location->program() != m_currentProgram) {
3070         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3071         return;
3072     }
3073
3074     m_context->uniform2i(location->location(), x, y);
3075     cleanupAfterGraphicsCall(false);
3076 }
3077
3078 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3079 {
3080     UNUSED_PARAM(ec);
3081     if (isContextLost() || !validateUniformParameters(location, v, 2))
3082         return;
3083
3084     m_context->uniform2iv(location->location(), v->data(), v->length() / 2);
3085     cleanupAfterGraphicsCall(false);
3086 }
3087
3088 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec)
3089 {
3090     UNUSED_PARAM(ec);
3091     if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3092         return;
3093
3094     m_context->uniform2iv(location->location(), v, size / 2);
3095     cleanupAfterGraphicsCall(false);
3096 }
3097
3098 void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, float x, float y, float z, ExceptionCode& ec)
3099 {
3100     UNUSED_PARAM(ec);
3101     if (isContextLost() || !location)
3102         return;
3103
3104     if (location->program() != m_currentProgram) {
3105         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3106         return;
3107     }
3108
3109     m_context->uniform3f(location->location(), x, y, z);
3110     cleanupAfterGraphicsCall(false);
3111 }
3112
3113 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3114 {
3115     UNUSED_PARAM(ec);
3116     if (isContextLost() || !validateUniformParameters(location, v, 3))
3117         return;
3118
3119     m_context->uniform3fv(location->location(), v->data(), v->length() / 3);
3120     cleanupAfterGraphicsCall(false);
3121 }
3122
3123 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec)
3124 {
3125     UNUSED_PARAM(ec);
3126     if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3127         return;
3128
3129     m_context->uniform3fv(location->location(), v, size / 3);
3130     cleanupAfterGraphicsCall(false);
3131 }
3132
3133 void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, int x, int y, int z, ExceptionCode& ec)
3134 {
3135     UNUSED_PARAM(ec);
3136     if (isContextLost() || !location)
3137         return;
3138
3139     if (location->program() != m_currentProgram) {
3140         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3141         return;
3142     }
3143
3144     m_context->uniform3i(location->location(), x, y, z);
3145     cleanupAfterGraphicsCall(false);
3146 }
3147
3148 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3149 {
3150     UNUSED_PARAM(ec);
3151     if (isContextLost() || !validateUniformParameters(location, v, 3))
3152         return;
3153
3154     m_context->uniform3iv(location->location(), v->data(), v->length() / 3);
3155     cleanupAfterGraphicsCall(false);
3156 }
3157
3158 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec)
3159 {
3160     UNUSED_PARAM(ec);
3161     if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3162         return;
3163
3164     m_context->uniform3iv(location->location(), v, size / 3);
3165     cleanupAfterGraphicsCall(false);
3166 }
3167
3168 void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, float x, float y, float z, float w, ExceptionCode& ec)
3169 {
3170     UNUSED_PARAM(ec);
3171     if (isContextLost() || !location)
3172         return;
3173
3174     if (location->program() != m_currentProgram) {
3175         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3176         return;
3177     }
3178
3179     m_context->uniform4f(location->location(), x, y, z, w);
3180     cleanupAfterGraphicsCall(false);
3181 }
3182
3183 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3184 {
3185     UNUSED_PARAM(ec);
3186     if (isContextLost() || !validateUniformParameters(location, v, 4))
3187         return;
3188
3189     m_context->uniform4fv(location->location(), v->data(), v->length() / 4);
3190     cleanupAfterGraphicsCall(false);
3191 }
3192
3193 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec)
3194 {
3195     UNUSED_PARAM(ec);
3196     if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3197         return;
3198
3199     m_context->uniform4fv(location->location(), v, size / 4);
3200     cleanupAfterGraphicsCall(false);
3201 }
3202
3203 void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, int x, int y, int z, int w, ExceptionCode& ec)
3204 {
3205     UNUSED_PARAM(ec);
3206     if (isContextLost() || !location)
3207         return;
3208
3209     if (location->program() != m_currentProgram) {
3210         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3211         return;
3212     }
3213
3214     m_context->uniform4i(location->location(), x, y, z, w);
3215     cleanupAfterGraphicsCall(false);
3216 }
3217
3218 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3219 {
3220     UNUSED_PARAM(ec);
3221     if (isContextLost() || !validateUniformParameters(location, v, 4))
3222         return;
3223
3224     m_context->uniform4iv(location->location(), v->data(), v->length() / 4);
3225     cleanupAfterGraphicsCall(false);
3226 }
3227
3228 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec)
3229 {
3230     UNUSED_PARAM(ec);
3231     if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3232         return;
3233
3234     m_context->uniform4iv(location->location(), v, size / 4);
3235     cleanupAfterGraphicsCall(false);
3236 }
3237
3238 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, bool transpose, Float32Array* v, ExceptionCode& ec)
3239 {
3240     UNUSED_PARAM(ec);
3241     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 4))
3242         return;
3243     m_context->uniformMatrix2fv(location->location(), transpose, v->data(), v->length() / 4);
3244     cleanupAfterGraphicsCall(false);
3245 }
3246
3247 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, bool transpose, float* v, int size, ExceptionCode& ec)
3248 {
3249     UNUSED_PARAM(ec);
3250     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 4))
3251         return;
3252     m_context->uniformMatrix2fv(location->location(), transpose, v, size / 4);
3253     cleanupAfterGraphicsCall(false);
3254 }
3255
3256 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, bool transpose, Float32Array* v, ExceptionCode& ec)
3257 {
3258     UNUSED_PARAM(ec);
3259     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 9))
3260         return;
3261     m_context->uniformMatrix3fv(location->location(), transpose, v->data(), v->length() / 9);
3262     cleanupAfterGraphicsCall(false);
3263 }
3264
3265 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, bool transpose, float* v, int size, ExceptionCode& ec)
3266 {
3267     UNUSED_PARAM(ec);
3268     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 9))
3269         return;
3270     m_context->uniformMatrix3fv(location->location(), transpose, v, size / 9);
3271     cleanupAfterGraphicsCall(false);
3272 }
3273
3274 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, bool transpose, Float32Array* v, ExceptionCode& ec)
3275 {
3276     UNUSED_PARAM(ec);
3277     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 16))
3278         return;
3279     m_context->uniformMatrix4fv(location->location(), transpose, v->data(), v->length() / 16);
3280     cleanupAfterGraphicsCall(false);
3281 }
3282
3283 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, bool transpose, float* v, int size, ExceptionCode& ec)
3284 {
3285     UNUSED_PARAM(ec);
3286     if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 16))
3287         return;
3288     m_context->uniformMatrix4fv(location->location(), transpose, v, size / 16);
3289     cleanupAfterGraphicsCall(false);
3290 }
3291
3292 void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
3293 {
3294     UNUSED_PARAM(ec);
3295     if (isContextLost())
3296         return;
3297     if (program && program->context() != this) {
3298         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3299         return;
3300     }
3301     if (program && program->object() && !program->getLinkStatus()) {
3302         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3303         cleanupAfterGraphicsCall(false);
3304         return;
3305     }
3306     if (m_currentProgram != program) {
3307         if (m_currentProgram)
3308             m_currentProgram->onDetached();
3309         m_currentProgram = program;
3310         m_context->useProgram(objectOrZero(program));
3311         if (program && program->object())
3312             program->onAttached();
3313     }
3314     cleanupAfterGraphicsCall(false);
3315 }
3316
3317 void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec)
3318 {
3319     UNUSED_PARAM(ec);
3320     if (isContextLost() || !validateWebGLObject(program))
3321         return;
3322     m_context->validateProgram(objectOrZero(program));
3323     cleanupAfterGraphicsCall(false);
3324 }
3325
3326 void WebGLRenderingContext::vertexAttrib1f(unsigned long index, float v0)
3327 {
3328     vertexAttribfImpl(index, 1, v0, 0.0f, 0.0f, 1.0f);
3329 }
3330
3331 void WebGLRenderingContext::vertexAttrib1fv(unsigned long index, Float32Array* v)
3332 {
3333     vertexAttribfvImpl(index, v, 1);
3334 }
3335
3336 void WebGLRenderingContext::vertexAttrib1fv(unsigned long index, float* v, int size)
3337 {
3338     vertexAttribfvImpl(index, v, size, 1);
3339 }
3340
3341 void WebGLRenderingContext::vertexAttrib2f(unsigned long index, float v0, float v1)
3342 {
3343     vertexAttribfImpl(index, 2, v0, v1, 0.0f, 1.0f);
3344 }
3345
3346 void WebGLRenderingContext::vertexAttrib2fv(unsigned long index, Float32Array* v)
3347 {
3348     vertexAttribfvImpl(index, v, 2);
3349 }
3350
3351 void WebGLRenderingContext::vertexAttrib2fv(unsigned long index, float* v, int size)
3352 {
3353     vertexAttribfvImpl(index, v, size, 2);
3354 }
3355
3356 void WebGLRenderingContext::vertexAttrib3f(unsigned long index, float v0, float v1, float v2)
3357 {
3358     vertexAttribfImpl(index, 3, v0, v1, v2, 1.0f);
3359 }
3360
3361 void WebGLRenderingContext::vertexAttrib3fv(unsigned long index, Float32Array* v)
3362 {
3363     vertexAttribfvImpl(index, v, 3);
3364 }
3365
3366 void WebGLRenderingContext::vertexAttrib3fv(unsigned long index, float* v, int size)
3367 {
3368     vertexAttribfvImpl(index, v, size, 3);
3369 }
3370
3371 void WebGLRenderingContext::vertexAttrib4f(unsigned long index, float v0, float v1, float v2, float v3)
3372 {
3373     vertexAttribfImpl(index, 4, v0, v1, v2, v3);
3374 }
3375
3376 void WebGLRenderingContext::vertexAttrib4fv(unsigned long index, Float32Array* v)
3377 {
3378     vertexAttribfvImpl(index, v, 4);
3379 }
3380
3381 void WebGLRenderingContext::vertexAttrib4fv(unsigned long index, float* v, int size)
3382 {
3383     vertexAttribfvImpl(index, v, size, 4);
3384 }
3385
3386 void WebGLRenderingContext::vertexAttribPointer(unsigned long index, long size, unsigned long type, bool normalized, long stride, long offset, ExceptionCode& ec)
3387 {
3388     UNUSED_PARAM(ec);
3389     if (isContextLost())
3390         return;
3391     switch (type) {
3392     case GraphicsContext3D::BYTE:
3393     case GraphicsContext3D::UNSIGNED_BYTE:
3394     case GraphicsContext3D::SHORT:
3395     case GraphicsContext3D::UNSIGNED_SHORT:
3396     case GraphicsContext3D::FLOAT:
3397         break;
3398     default:
3399         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3400         return;
3401     }
3402     if (index >= m_maxVertexAttribs) {
3403         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3404         return;
3405     }
3406     if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) {
3407         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3408         return;
3409     }
3410     if (!m_boundArrayBuffer) {
3411         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3412         return;
3413     }
3414     // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
3415     long typeSize = sizeInBytes(type);
3416     if (typeSize <= 0) {
3417         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3418         return;
3419     }
3420     if ((stride % typeSize) || (offset % typeSize)) {
3421         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3422         return;
3423     }
3424     long bytesPerElement = size * typeSize;
3425
3426     if (index >= m_vertexAttribState.size())
3427         m_vertexAttribState.resize(index + 1);
3428
3429     long validatedStride = stride ? stride : bytesPerElement;
3430
3431     m_vertexAttribState[index].bufferBinding = m_boundArrayBuffer;
3432     m_vertexAttribState[index].bytesPerElement = bytesPerElement;
3433     m_vertexAttribState[index].size = size;
3434     m_vertexAttribState[index].type = type;
3435     m_vertexAttribState[index].normalized = normalized;
3436     m_vertexAttribState[index].stride = validatedStride;
3437     m_vertexAttribState[index].originalStride = stride;
3438     m_vertexAttribState[index].offset = offset;
3439     m_context->vertexAttribPointer(index, size, type, normalized, stride, offset);
3440     cleanupAfterGraphicsCall(false);
3441 }
3442
3443 void WebGLRenderingContext::viewport(long x, long y, long width, long height)
3444 {
3445     if (isContextLost())
3446         return;
3447     if (isnan(x))
3448         x = 0;
3449     if (isnan(y))
3450         y = 0;
3451     if (isnan(width))
3452         width = 100;
3453     if (isnan(height))
3454         height = 100;
3455     if (!validateSize(width, height))
3456         return;
3457     m_context->viewport(x, y, width, height);
3458     cleanupAfterGraphicsCall(false);
3459 }
3460
3461 void WebGLRenderingContext::loseContext()
3462 {
3463     m_contextLost = true;
3464
3465     detachAndRemoveAllObjects();
3466
3467     // There is no direct way to clear errors from a GL implementation and
3468     // looping until getError() becomes NO_ERROR might cause an infinite loop if
3469     // the driver or context implementation had a bug.  So, loop a reasonably
3470     // large number of times to clear any existing errors.
3471     for (int i = 0; i < 100; ++i) {
3472         if (m_context->getError() == GraphicsContext3D::NO_ERROR)
3473             break;
3474     }
3475     m_context->synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL);
3476
3477     canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, ""));
3478 }
3479
3480 void WebGLRenderingContext::restoreContext()
3481 {
3482     RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, canvas()->document()->view()->root()->hostWindow()));
3483     if (!context)
3484         return;
3485
3486     m_context = context;
3487     m_contextLost = false;
3488     initializeNewContext();
3489     canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, ""));
3490 }
3491
3492 void WebGLRenderingContext::removeObject(WebGLObject* object)
3493 {
3494     m_canvasObjects.remove(object);
3495 }
3496
3497 void WebGLRenderingContext::addObject(WebGLObject* object)
3498 {
3499     ASSERT(!isContextLost());
3500     removeObject(object);
3501     m_canvasObjects.add(object);
3502 }
3503
3504 void WebGLRenderingContext::detachAndRemoveAllObjects()
3505 {
3506     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3507     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it)
3508         (*it)->detachContext();
3509         
3510     m_canvasObjects.clear();
3511 }
3512
3513 WebGLTexture* WebGLRenderingContext::findTexture(Platform3DObject obj)
3514 {
3515     if (!obj)
3516         return 0;
3517     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3518     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3519         if ((*it)->isTexture() && (*it)->object() == obj)
3520             return reinterpret_cast<WebGLTexture*>((*it).get());
3521     }
3522     return 0;
3523 }
3524
3525 WebGLRenderbuffer* WebGLRenderingContext::findRenderbuffer(Platform3DObject obj)
3526 {
3527     if (!obj)
3528         return 0;
3529     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3530     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3531         if ((*it)->isRenderbuffer() && (*it)->object() == obj)
3532             return reinterpret_cast<WebGLRenderbuffer*>((*it).get());
3533     }
3534     return 0;
3535 }
3536
3537 WebGLBuffer* WebGLRenderingContext::findBuffer(Platform3DObject obj)
3538 {
3539     if (!obj)
3540         return 0;
3541     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3542     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3543         if ((*it)->isBuffer() && (*it)->object() == obj)
3544             return reinterpret_cast<WebGLBuffer*>((*it).get());
3545     }
3546     return 0;
3547 }
3548
3549 WebGLShader* WebGLRenderingContext::findShader(Platform3DObject obj)
3550 {
3551     if (!obj)
3552         return 0;
3553     HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3554     for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3555         if ((*it)->isShader() && (*it)->object() == obj)
3556             return reinterpret_cast<WebGLShader*>((*it).get());
3557     }
3558     return 0;
3559 }
3560
3561 WebGLGetInfo WebGLRenderingContext::getBooleanParameter(unsigned long pname)
3562 {
3563     unsigned char value = 0;
3564     m_context->getBooleanv(pname, &value);
3565     return WebGLGetInfo(static_cast<bool>(value));
3566 }
3567
3568 WebGLGetInfo WebGLRenderingContext::getBooleanArrayParameter(unsigned long pname)
3569 {
3570     if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
3571         notImplemented();
3572         return WebGLGetInfo(0, 0);
3573     }
3574     unsigned char value[4] = {0};
3575     m_context->getBooleanv(pname, value);
3576     bool boolValue[4];
3577     for (int ii = 0; ii < 4; ++ii)
3578         boolValue[ii] = static_cast<bool>(value[ii]);
3579     return WebGLGetInfo(boolValue, 4);
3580 }
3581
3582 WebGLGetInfo WebGLRenderingContext::getFloatParameter(unsigned long pname)
3583 {
3584     float value = 0;
3585     m_context->getFloatv(pname, &value);
3586     return WebGLGetInfo(static_cast<float>(value));
3587 }
3588
3589 WebGLGetInfo WebGLRenderingContext::getIntParameter(unsigned long pname)
3590 {
3591     return getLongParameter(pname);
3592 }
3593
3594 WebGLGetInfo WebGLRenderingContext::getLongParameter(unsigned long pname)
3595 {
3596     int value = 0;
3597     m_context->getIntegerv(pname, &value);
3598     return WebGLGetInfo(static_cast<long>(value));
3599 }
3600
3601 WebGLGetInfo WebGLRenderingContext::getUnsignedLongParameter(unsigned long pname)
3602 {
3603     int value = 0;
3604     m_context->getIntegerv(pname, &value);
3605     unsigned int uValue = static_cast<unsigned int>(value);
3606     return WebGLGetInfo(static_cast<unsigned long>(uValue));
3607 }
3608
3609 WebGLGetInfo WebGLRenderingContext::getWebGLFloatArrayParameter(unsigned long pname)
3610 {
3611     float value[4] = {0};
3612     m_context->getFloatv(pname, value);
3613     unsigned length = 0;
3614     switch (pname) {
3615     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
3616     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
3617     case GraphicsContext3D::DEPTH_RANGE:
3618         length = 2;
3619         break;
3620     case GraphicsContext3D::BLEND_COLOR:
3621     case GraphicsContext3D::COLOR_CLEAR_VALUE:
3622         length = 4;
3623         break;
3624     default:
3625         notImplemented();
3626     }
3627     return WebGLGetInfo(Float32Array::create(value, length));
3628 }
3629
3630 WebGLGetInfo WebGLRenderingContext::getWebGLIntArrayParameter(unsigned long pname)
3631 {
3632     int value[4] = {0};
3633     m_context->getIntegerv(pname, value);
3634     unsigned length = 0;
3635     switch (pname) {
3636     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
3637         length = 2;
3638         break;
3639     case GraphicsContext3D::SCISSOR_BOX:
3640     case GraphicsContext3D::VIEWPORT:
3641         length = 4;
3642         break;
3643     default:
3644         notImplemented();
3645     }
3646     return WebGLGetInfo(Int32Array::create(value, length));
3647 }
3648
3649 void WebGLRenderingContext::handleNPOTTextures(bool prepareToDraw)
3650 {
3651     bool resetActiveUnit = false;
3652     for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) {
3653         if ((m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
3654             || (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())) {
3655             if (ii != m_activeTextureUnit) {
3656                 m_context->activeTexture(ii);
3657                 resetActiveUnit = true;
3658             } else if (resetActiveUnit) {
3659                 m_context->activeTexture(ii);
3660                 resetActiveUnit = false;
3661             }
3662             WebGLTexture* tex2D;
3663             WebGLTexture* texCubeMap;
3664             if (prepareToDraw) {
3665                 tex2D = m_blackTexture2D.get();
3666                 texCubeMap = m_blackTextureCubeMap.get();
3667             } else {
3668                 tex2D = m_textureUnits[ii].m_texture2DBinding.get();
3669                 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
3670             }
3671             if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
3672                 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D));
3673             if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())
3674                 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
3675         }
3676     }
3677     if (resetActiveUnit)
3678         m_context->activeTexture(m_activeTextureUnit);
3679 }
3680
3681 void WebGLRenderingContext::createFallbackBlackTextures1x1()
3682 {
3683     unsigned char black[] = {0, 0, 0, 255};
3684     m_blackTexture2D = createTexture();
3685     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D->object());
3686     m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1,
3687                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
3688     m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
3689     m_blackTextureCubeMap = createTexture();
3690     m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
3691     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
3692                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
3693     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
3694                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
3695     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
3696                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
3697     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
3698                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
3699     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
3700                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
3701     m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
3702                           0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
3703     m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0);
3704 }
3705
3706 bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(unsigned long texInternalFormat,
3707                                                                            unsigned long colorBufferFormat)
3708 {
3709     switch (colorBufferFormat) {
3710     case GraphicsContext3D::ALPHA:
3711         if (texInternalFormat == GraphicsContext3D::ALPHA)
3712             return true;
3713         break;
3714     case GraphicsContext3D::RGB:
3715         if (texInternalFormat == GraphicsContext3D::LUMINANCE
3716             || texInternalFormat == GraphicsContext3D::RGB)
3717             return true;
3718         break;
3719     case GraphicsContext3D::RGBA:
3720         return true;
3721     }
3722     return false;
3723 }
3724
3725 unsigned long WebGLRenderingContext::getBoundFramebufferColorFormat()
3726 {
3727     if (m_framebufferBinding && m_framebufferBinding->object())
3728         return m_framebufferBinding->getColorBufferFormat();
3729     if (m_attributes.alpha)
3730         return GraphicsContext3D::RGBA;
3731     return GraphicsContext3D::RGB;
3732 }
3733
3734 int WebGLRenderingContext::getBoundFramebufferWidth()
3735 {
3736     if (m_framebufferBinding && m_framebufferBinding->object())
3737         return m_framebufferBinding->getWidth();
3738     return m_context->getInternalFramebufferSize().width();
3739 }
3740
3741 int WebGLRenderingContext::getBoundFramebufferHeight()
3742 {
3743     if (m_framebufferBinding && m_framebufferBinding->object())
3744         return m_framebufferBinding->getHeight();
3745     return m_context->getInternalFramebufferSize().height();
3746 }
3747
3748 WebGLTexture* WebGLRenderingContext::validateTextureBinding(unsigned long target, bool useSixEnumsForCubeMap)
3749 {
3750     WebGLTexture* tex = 0;
3751     switch (target) {
3752     case GraphicsContext3D::TEXTURE_2D:
3753         tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
3754         break;
3755     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
3756     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
3757     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
3758     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
3759     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
3760     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
3761         if (!useSixEnumsForCubeMap) {
3762             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3763             return 0;
3764         }
3765         tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
3766         break;
3767     case GraphicsContext3D::TEXTURE_CUBE_MAP:
3768         if (useSixEnumsForCubeMap) {
3769             m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3770             return 0;
3771         }
3772         tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
3773         break;
3774     default:
3775         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3776         return 0;
3777     }
3778     if (!tex)
3779         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3780     return tex;
3781 }
3782
3783 bool WebGLRenderingContext::validateSize(long x, long y)
3784 {
3785     if (x < 0 || y < 0) {
3786         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3787         return false;
3788     }
3789     return true;
3790 }
3791
3792 bool WebGLRenderingContext::validateString(const String& string)
3793 {
3794     for (size_t i = 0; i < string.length(); ++i) {
3795         if (!validateCharacter(string[i])) {
3796             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3797             return false;
3798         }
3799     }
3800     return true;
3801 }
3802
3803 bool WebGLRenderingContext::validateTexFuncFormatAndType(unsigned long format, unsigned long type)
3804 {
3805     switch (format) {
3806     case GraphicsContext3D::ALPHA:
3807     case GraphicsContext3D::LUMINANCE:
3808     case GraphicsContext3D::LUMINANCE_ALPHA:
3809     case GraphicsContext3D::RGB:
3810     case GraphicsContext3D::RGBA:
3811         break;
3812     default:
3813         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3814         return false;
3815     }
3816
3817     switch (type) {
3818     case GraphicsContext3D::UNSIGNED_BYTE:
3819     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
3820     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
3821     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
3822         break;
3823     case GraphicsContext3D::FLOAT:
3824         if (m_oesTextureFloat)
3825             break;
3826         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3827         return false;
3828     default:
3829         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3830         return false;
3831     }
3832
3833     // Verify that the combination of format and type is supported.
3834     switch (format) {
3835     case GraphicsContext3D::ALPHA:
3836     case GraphicsContext3D::LUMINANCE:
3837     case GraphicsContext3D::LUMINANCE_ALPHA:
3838         if (type != GraphicsContext3D::UNSIGNED_BYTE
3839             && type != GraphicsContext3D::FLOAT) {
3840             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3841             return false;
3842         }
3843         break;
3844     case GraphicsContext3D::RGB:
3845         if (type != GraphicsContext3D::UNSIGNED_BYTE
3846             && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5
3847             && type != GraphicsContext3D::FLOAT) {
3848             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3849             return false;
3850         }
3851         break;
3852     case GraphicsContext3D::RGBA:
3853         if (type != GraphicsContext3D::UNSIGNED_BYTE
3854             && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4
3855             && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1
3856             && type != GraphicsContext3D::FLOAT) {
3857             m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3858             return false;
3859         }
3860         break;
3861     default:
3862         ASSERT_NOT_REACHED();
3863     }
3864
3865     return true;
3866 }
3867
3868 bool WebGLRenderingContext::validateTexFuncLevel(unsigned long target, long level)
3869 {
3870     if (level < 0) {
3871         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3872         return false;
3873     }
3874     switch (target) {
3875     case GraphicsContext3D::TEXTURE_2D:
3876         if (level > m_maxTextureLevel) {
3877             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3878             return false;
3879         }
3880         break;
3881     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
3882     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
3883     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
3884     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
3885     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
3886     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
3887         if (level > m_maxCubeMapTextureLevel) {
3888             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3889             return false;
3890         }
3891         break;
3892     }
3893     // This function only checks if level is legal, so we return true and don't
3894     // generate INVALID_ENUM if target is illegal.
3895     return true;
3896 }
3897
3898 bool WebGLRenderingContext::validateTexFuncParameters(unsigned long target, long level,
3899                                                       unsigned long internalformat,
3900                                                       long width, long height, long border,
3901                                                       unsigned long format, unsigned long type)
3902 {
3903     // We absolutely have to validate the format and type combination.
3904     // The texImage2D entry points taking HTMLImage, etc. will produce
3905     // temporary data based on this combination, so it must be legal.
3906     if (!validateTexFuncFormatAndType(format, type) || !validateTexFuncLevel(target, level))
3907         return false;
3908
3909     if (width < 0 || height < 0) {
3910         m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3911         return false;
3912     }
3913
3914     switch (target) {
3915     case GraphicsContext3D::TEXTURE_2D:
3916         if (width > m_maxTextureSize || height > m_maxTextureSize) {
3917             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3918             return false;
3919         }
3920         break;
3921     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
3922     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
3923     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
3924     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
3925     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
3926     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
3927         if (width != height || width > m_maxCubeMapTextureSize) {
3928             m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3929             return false;
3930         }
3931         break;
3932     default:
3933         m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3934         return false;
3935     }
3936
3937     if (format != internalformat) {
3938         m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);