WebGLRenderingContextBase.texSubImage2D() should use a union instead of overloading
[WebKit-https.git] / Source / WebCore / html / canvas / WebGLRenderingContext.cpp
1 /*
2  * Copyright (C) 2015 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 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 INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(WEBGL)
29 #include "WebGLRenderingContext.h"
30
31 #include "ANGLEInstancedArrays.h"
32 #include "CachedImage.h"
33 #include "EXTBlendMinMax.h"
34 #include "EXTFragDepth.h"
35 #include "EXTShaderTextureLOD.h"
36 #include "EXTTextureFilterAnisotropic.h"
37 #include "EXTsRGB.h"
38 #include "Extensions3D.h"
39 #include "HTMLCanvasElement.h"
40 #include "HTMLImageElement.h"
41 #include "HTMLVideoElement.h"
42 #include "ImageData.h"
43 #include "OESElementIndexUint.h"
44 #include "OESStandardDerivatives.h"
45 #include "OESTextureFloat.h"
46 #include "OESTextureFloatLinear.h"
47 #include "OESTextureHalfFloat.h"
48 #include "OESTextureHalfFloatLinear.h"
49 #include "OESVertexArrayObject.h"
50 #include "RenderBox.h"
51 #include "WebGLCompressedTextureATC.h"
52 #include "WebGLCompressedTexturePVRTC.h"
53 #include "WebGLCompressedTextureS3TC.h"
54 #include "WebGLDebugRendererInfo.h"
55 #include "WebGLDebugShaders.h"
56 #include "WebGLDepthTexture.h"
57 #include "WebGLDrawBuffers.h"
58 #include "WebGLLoseContext.h"
59 #include "WebGLVertexArrayObjectOES.h"
60 #include <JavaScriptCore/GenericTypedArrayViewInlines.h>
61 #include <JavaScriptCore/JSCJSValueInlines.h>
62 #include <JavaScriptCore/JSCellInlines.h>
63 #include <JavaScriptCore/JSGenericTypedArrayViewInlines.h>
64
65 namespace WebCore {
66
67 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, GraphicsContext3D::Attributes attributes)
68     : WebGLRenderingContextBase(passedCanvas, attributes)
69 {
70 }
71
72 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
73     GraphicsContext3D::Attributes attributes) : WebGLRenderingContextBase(passedCanvas, context, attributes)
74 {
75     initializeVertexArrayObjects();
76 }
77
78 void WebGLRenderingContext::initializeVertexArrayObjects()
79 {
80     m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VAOTypeDefault);
81     addContextObject(m_defaultVertexArrayObject.get());
82     m_boundVertexArrayObject = m_defaultVertexArrayObject;
83     if (!isGLES2Compliant())
84         initVertexAttrib0();
85 }
86
87 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
88 {
89     if (isContextLostOrPending())
90         return nullptr;
91     
92     if (equalIgnoringASCIICase(name, "EXT_blend_minmax")
93         && m_context->getExtensions()->supports("GL_EXT_blend_minmax")) {
94         if (!m_extBlendMinMax) {
95             m_context->getExtensions()->ensureEnabled("GL_EXT_blend_minmax");
96             m_extBlendMinMax = std::make_unique<EXTBlendMinMax>(this);
97         }
98         return m_extBlendMinMax.get();
99     }
100     if (equalIgnoringASCIICase(name, "EXT_sRGB")
101         && m_context->getExtensions()->supports("GL_EXT_sRGB")) {
102         if (!m_extsRGB) {
103             m_context->getExtensions()->ensureEnabled("GL_EXT_sRGB");
104             m_extsRGB = std::make_unique<EXTsRGB>(this);
105         }
106         return m_extsRGB.get();
107     }
108     if (equalIgnoringASCIICase(name, "EXT_frag_depth")
109         && m_context->getExtensions()->supports("GL_EXT_frag_depth")) {
110         if (!m_extFragDepth) {
111             m_context->getExtensions()->ensureEnabled("GL_EXT_frag_depth");
112             m_extFragDepth = std::make_unique<EXTFragDepth>(this);
113         }
114         return m_extFragDepth.get();
115     }
116     if (equalIgnoringASCIICase(name, "EXT_shader_texture_lod")
117         && (m_context->getExtensions()->supports("GL_EXT_shader_texture_lod") || m_context->getExtensions()->supports("GL_ARB_shader_texture_lod"))) {
118         if (!m_extShaderTextureLOD) {
119             m_context->getExtensions()->ensureEnabled("GL_EXT_shader_texture_lod");
120             m_extShaderTextureLOD = std::make_unique<EXTShaderTextureLOD>(this);
121         }
122         return m_extShaderTextureLOD.get();
123     }
124     if ((equalIgnoringASCIICase(name, "EXT_texture_filter_anisotropic") || equalIgnoringASCIICase(name, "WEBKIT_EXT_texture_filter_anisotropic"))
125         && m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic")) {
126         if (!m_extTextureFilterAnisotropic) {
127             m_context->getExtensions()->ensureEnabled("GL_EXT_texture_filter_anisotropic");
128             m_extTextureFilterAnisotropic = std::make_unique<EXTTextureFilterAnisotropic>(this);
129         }
130         return m_extTextureFilterAnisotropic.get();
131     }
132     if (equalIgnoringASCIICase(name, "OES_standard_derivatives")
133         && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
134         if (!m_oesStandardDerivatives) {
135             m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
136             m_oesStandardDerivatives = std::make_unique<OESStandardDerivatives>(this);
137         }
138         return m_oesStandardDerivatives.get();
139     }
140     if (equalIgnoringASCIICase(name, "OES_texture_float")
141         && m_context->getExtensions()->supports("GL_OES_texture_float")) {
142         if (!m_oesTextureFloat) {
143             m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
144             m_oesTextureFloat = std::make_unique<OESTextureFloat>(this);
145         }
146         return m_oesTextureFloat.get();
147     }
148     if (equalIgnoringASCIICase(name, "OES_texture_float_linear")
149         && m_context->getExtensions()->supports("GL_OES_texture_float_linear")) {
150         if (!m_oesTextureFloatLinear) {
151             m_context->getExtensions()->ensureEnabled("GL_OES_texture_float_linear");
152             m_oesTextureFloatLinear = std::make_unique<OESTextureFloatLinear>(this);
153         }
154         return m_oesTextureFloatLinear.get();
155     }
156     if (equalIgnoringASCIICase(name, "OES_texture_half_float")
157         && m_context->getExtensions()->supports("GL_OES_texture_half_float")) {
158         if (!m_oesTextureHalfFloat) {
159             m_context->getExtensions()->ensureEnabled("GL_OES_texture_half_float");
160             m_oesTextureHalfFloat = std::make_unique<OESTextureHalfFloat>(this);
161         }
162         return m_oesTextureHalfFloat.get();
163     }
164     if (equalIgnoringASCIICase(name, "OES_texture_half_float_linear")
165         && m_context->getExtensions()->supports("GL_OES_texture_half_float_linear")) {
166         if (!m_oesTextureHalfFloatLinear) {
167             m_context->getExtensions()->ensureEnabled("GL_OES_texture_half_float_linear");
168             m_oesTextureHalfFloatLinear = std::make_unique<OESTextureHalfFloatLinear>(this);
169         }
170         return m_oesTextureHalfFloatLinear.get();
171     }
172     if (equalIgnoringASCIICase(name, "OES_vertex_array_object")
173         && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
174         if (!m_oesVertexArrayObject) {
175             m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
176             m_oesVertexArrayObject = std::make_unique<OESVertexArrayObject>(*this);
177         }
178         return m_oesVertexArrayObject.get();
179     }
180     if (equalIgnoringASCIICase(name, "OES_element_index_uint")
181         && m_context->getExtensions()->supports("GL_OES_element_index_uint")) {
182         if (!m_oesElementIndexUint) {
183             m_context->getExtensions()->ensureEnabled("GL_OES_element_index_uint");
184             m_oesElementIndexUint = std::make_unique<OESElementIndexUint>(this);
185         }
186         return m_oesElementIndexUint.get();
187     }
188     if (equalIgnoringASCIICase(name, "WEBGL_lose_context")) {
189         if (!m_webglLoseContext)
190             m_webglLoseContext = std::make_unique<WebGLLoseContext>(this);
191         return m_webglLoseContext.get();
192     }
193     if ((equalIgnoringASCIICase(name, "WEBKIT_WEBGL_compressed_texture_atc"))
194         && WebGLCompressedTextureATC::supported(this)) {
195         if (!m_webglCompressedTextureATC)
196             m_webglCompressedTextureATC = std::make_unique<WebGLCompressedTextureATC>(this);
197         return m_webglCompressedTextureATC.get();
198     }
199     if ((equalIgnoringASCIICase(name, "WEBKIT_WEBGL_compressed_texture_pvrtc"))
200         && WebGLCompressedTexturePVRTC::supported(this)) {
201         if (!m_webglCompressedTexturePVRTC)
202             m_webglCompressedTexturePVRTC = std::make_unique<WebGLCompressedTexturePVRTC>(this);
203         return m_webglCompressedTexturePVRTC.get();
204     }
205     if (equalIgnoringASCIICase(name, "WEBGL_compressed_texture_s3tc")
206         && WebGLCompressedTextureS3TC::supported(this)) {
207         if (!m_webglCompressedTextureS3TC)
208             m_webglCompressedTextureS3TC = std::make_unique<WebGLCompressedTextureS3TC>(this);
209         return m_webglCompressedTextureS3TC.get();
210     }
211     if (equalIgnoringASCIICase(name, "WEBGL_depth_texture")
212         && WebGLDepthTexture::supported(graphicsContext3D())) {
213         if (!m_webglDepthTexture) {
214             m_context->getExtensions()->ensureEnabled("GL_CHROMIUM_depth_texture");
215             m_webglDepthTexture = std::make_unique<WebGLDepthTexture>(this);
216         }
217         return m_webglDepthTexture.get();
218     }
219     if (equalIgnoringASCIICase(name, "WEBGL_draw_buffers") && supportsDrawBuffers()) {
220         if (!m_webglDrawBuffers) {
221             m_context->getExtensions()->ensureEnabled("GL_EXT_draw_buffers");
222             m_webglDrawBuffers = std::make_unique<WebGLDrawBuffers>(this);
223         }
224         return m_webglDrawBuffers.get();
225     }
226     if (equalIgnoringASCIICase(name, "ANGLE_instanced_arrays") && ANGLEInstancedArrays::supported(this)) {
227         if (!m_angleInstancedArrays) {
228             m_context->getExtensions()->ensureEnabled("GL_ANGLE_instanced_arrays");
229             m_angleInstancedArrays = std::make_unique<ANGLEInstancedArrays>(this);
230         }
231         return m_angleInstancedArrays.get();
232     }
233     if (equalIgnoringASCIICase(name, "WEBGL_debug_renderer_info")) {
234         if (!m_webglDebugRendererInfo)
235             m_webglDebugRendererInfo = std::make_unique<WebGLDebugRendererInfo>(this);
236         return m_webglDebugRendererInfo.get();
237     }
238     if (equalIgnoringASCIICase(name, "WEBGL_debug_shaders")
239         && m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source")) {
240         if (!m_webglDebugShaders)
241             m_webglDebugShaders = std::make_unique<WebGLDebugShaders>(this);
242         return m_webglDebugShaders.get();
243     }
244
245     return nullptr;
246 }
247
248 Vector<String> WebGLRenderingContext::getSupportedExtensions()
249 {
250     Vector<String> result;
251     
252     if (m_isPendingPolicyResolution)
253         return result;
254     
255     if (m_context->getExtensions()->supports("GL_EXT_blend_minmax"))
256         result.append("EXT_blend_minmax");
257     if (m_context->getExtensions()->supports("GL_EXT_sRGB"))
258         result.append("EXT_sRGB");
259     if (m_context->getExtensions()->supports("GL_EXT_frag_depth"))
260         result.append("EXT_frag_depth");
261     if (m_context->getExtensions()->supports("GL_OES_texture_float"))
262         result.append("OES_texture_float");
263     if (m_context->getExtensions()->supports("GL_OES_texture_float_linear"))
264         result.append("OES_texture_float_linear");
265     if (m_context->getExtensions()->supports("GL_OES_texture_half_float"))
266         result.append("OES_texture_half_float");
267     if (m_context->getExtensions()->supports("GL_OES_texture_half_float_linear"))
268         result.append("OES_texture_half_float_linear");
269     if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
270         result.append("OES_standard_derivatives");
271     if (m_context->getExtensions()->supports("GL_EXT_shader_texture_lod") || m_context->getExtensions()->supports("GL_ARB_shader_texture_lod"))
272         result.append("EXT_shader_texture_lod");
273     if (m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic"))
274         result.append("EXT_texture_filter_anisotropic");
275     if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
276         result.append("OES_vertex_array_object");
277     if (m_context->getExtensions()->supports("GL_OES_element_index_uint"))
278         result.append("OES_element_index_uint");
279     result.append("WEBGL_lose_context");
280     if (WebGLCompressedTextureATC::supported(this))
281         result.append("WEBKIT_WEBGL_compressed_texture_atc");
282     if (WebGLCompressedTexturePVRTC::supported(this))
283         result.append("WEBKIT_WEBGL_compressed_texture_pvrtc");
284     if (WebGLCompressedTextureS3TC::supported(this))
285         result.append("WEBGL_compressed_texture_s3tc");
286     if (WebGLDepthTexture::supported(graphicsContext3D()))
287         result.append("WEBGL_depth_texture");
288     if (supportsDrawBuffers())
289         result.append("WEBGL_draw_buffers");
290     if (ANGLEInstancedArrays::supported(this))
291         result.append("ANGLE_instanced_arrays");
292     if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
293         result.append("WEBGL_debug_shaders");
294     result.append("WEBGL_debug_renderer_info");
295
296     return result;
297 }
298
299 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname)
300 {
301     if (isContextLostOrPending() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
302         return WebGLGetInfo();
303     
304     if (!m_framebufferBinding || !m_framebufferBinding->object()) {
305         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
306         return WebGLGetInfo();
307     }
308     
309     WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
310     if (!object) {
311         if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
312             return WebGLGetInfo(GraphicsContext3D::NONE);
313         // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
314         // specifies INVALID_OPERATION.
315         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
316         return WebGLGetInfo();
317     }
318     
319     ASSERT(object->isTexture() || object->isRenderbuffer());
320     if (object->isTexture()) {
321         switch (pname) {
322         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
323             return WebGLGetInfo(GraphicsContext3D::TEXTURE);
324         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
325             return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
326         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
327         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
328         case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: {
329             GC3Dint value = 0;
330             m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
331             return WebGLGetInfo(value);
332         }
333         default:
334             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
335             return WebGLGetInfo();
336         }
337     } else {
338         switch (pname) {
339         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
340             return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
341         case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
342             return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
343         case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: {
344             if (!m_extsRGB) {
345                 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
346                 return WebGLGetInfo();
347             }
348             WebGLRenderbuffer* renderBuffer = reinterpret_cast<WebGLRenderbuffer*>(object);
349             GC3Denum renderBufferFormat = renderBuffer->getInternalFormat();
350             ASSERT(renderBufferFormat != Extensions3D::SRGB_EXT && renderBufferFormat != Extensions3D::SRGB_ALPHA_EXT);
351             if (renderBufferFormat == Extensions3D::SRGB8_ALPHA8_EXT)
352                 return WebGLGetInfo(Extensions3D::SRGB_EXT);
353             return WebGLGetInfo(GraphicsContext3D::LINEAR);
354         }
355         default:
356             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
357             return WebGLGetInfo();
358         }
359     }
360 }
361
362 bool WebGLRenderingContext::validateFramebufferFuncParameters(const char* functionName, GC3Denum target, GC3Denum attachment)
363 {
364     if (target != GraphicsContext3D::FRAMEBUFFER) {
365         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
366         return false;
367     }
368     switch (attachment) {
369     case GraphicsContext3D::COLOR_ATTACHMENT0:
370     case GraphicsContext3D::DEPTH_ATTACHMENT:
371     case GraphicsContext3D::STENCIL_ATTACHMENT:
372     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
373         break;
374     default:
375         if (m_webglDrawBuffers
376             && attachment > GraphicsContext3D::COLOR_ATTACHMENT0
377             && attachment < static_cast<GC3Denum>(GraphicsContext3D::COLOR_ATTACHMENT0 + getMaxColorAttachments()))
378             break;
379         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid attachment");
380         return false;
381     }
382     return true;
383 }
384     
385 void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
386 {
387     if (isContextLostOrPending())
388         return;
389     if (target != GraphicsContext3D::RENDERBUFFER) {
390         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid target");
391         return;
392     }
393     if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
394         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer");
395         return;
396     }
397     if (!validateSize("renderbufferStorage", width, height))
398         return;
399     switch (internalformat) {
400     case GraphicsContext3D::DEPTH_COMPONENT16:
401     case GraphicsContext3D::RGBA4:
402     case GraphicsContext3D::RGB5_A1:
403     case GraphicsContext3D::RGB565:
404     case GraphicsContext3D::STENCIL_INDEX8:
405     case Extensions3D::SRGB8_ALPHA8_EXT:
406         if (internalformat == Extensions3D::SRGB8_ALPHA8_EXT && !m_extsRGB) {
407             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
408             return;
409         }
410         m_context->renderbufferStorage(target, internalformat, width, height);
411         m_renderbufferBinding->setInternalFormat(internalformat);
412         m_renderbufferBinding->setIsValid(true);
413         m_renderbufferBinding->setSize(width, height);
414         break;
415     case GraphicsContext3D::DEPTH_STENCIL:
416         if (isDepthStencilSupported())
417             m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
418         m_renderbufferBinding->setSize(width, height);
419         m_renderbufferBinding->setIsValid(isDepthStencilSupported());
420         m_renderbufferBinding->setInternalFormat(internalformat);
421         break;
422     default:
423         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
424         return;
425     }
426     applyStencilTest();
427 }
428
429 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
430 {
431     if (isContextLostOrPending())
432         return;
433     bool isValid = false;
434     switch (target) {
435     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
436         isValid = true;
437         break;
438     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
439         if (m_oesStandardDerivatives)
440             isValid = true;
441         break;
442     }
443     if (!isValid) {
444         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target");
445         return;
446     }
447     m_context->hint(target, mode);
448 }
449     
450 void WebGLRenderingContext::clear(GC3Dbitfield mask)
451 {
452     if (isContextLostOrPending())
453         return;
454     if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
455         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "clear", "invalid mask");
456         return;
457     }
458     const char* reason = "framebuffer incomplete";
459     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
460         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "clear", reason);
461         return;
462     }
463     if (!clearIfComposited(mask))
464         m_context->clear(mask);
465     markContextChanged();
466 }
467
468 void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
469 {
470     if (isContextLostOrPending())
471         return;
472     if (!validateTexFuncParameters("copyTexImage2D", CopyTexImage, target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
473         return;
474     if (!validateSettableTexFormat("copyTexImage2D", internalformat))
475         return;
476     WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true);
477     if (!tex)
478         return;
479     if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
480         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexImage2D", "framebuffer is incompatible format");
481         return;
482     }
483     if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
484         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexImage2D", "level > 0 not power of 2");
485         return;
486     }
487     const char* reason = "framebuffer incomplete";
488     if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
489         synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D", reason);
490         return;
491     }
492     clearIfComposited();
493     if (isResourceSafe())
494         m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
495     else {
496         GC3Dint clippedX, clippedY;
497         GC3Dsizei clippedWidth, clippedHeight;
498         if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
499             m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
500                 internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment);
501             if (clippedWidth > 0 && clippedHeight > 0) {
502                 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
503                     clippedX, clippedY, clippedWidth, clippedHeight);
504             }
505         } else
506             m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
507     }
508     // FIXME: if the framebuffer is not complete, none of the below should be executed.
509     tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
510 }
511
512 void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum internalformat, GC3Denum format, GC3Denum type, const void* pixels)
513 {
514     UNUSED_PARAM(internalformat);
515     ASSERT(!isContextLost());
516     ASSERT(validateTexFuncParameters("texSubImage2D", TexSubImage, target, level, format, width, height, 0, format, type));
517     ASSERT(validateSize("texSubImage2D", xoffset, yoffset));
518     ASSERT(validateSettableTexFormat("texSubImage2D", format));
519     WebGLTexture* tex = validateTextureBinding("texSubImage2D", target, true);
520     if (!tex) {
521         ASSERT_NOT_REACHED();
522         return;
523     }
524     ASSERT((xoffset + width) >= 0);
525     ASSERT((yoffset + height) >= 0);
526     ASSERT(tex->getWidth(target, level) >= (xoffset + width));
527     ASSERT(tex->getHeight(target, level) >= (yoffset + height));
528     ASSERT(tex->getInternalFormat(target, level) == format);
529     ASSERT(tex->getType(target, level) == type);
530     m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
531 }
532
533 void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha)
534 {
535     Vector<uint8_t> data;
536     GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);
537     if (!imageExtractor.extractSucceeded()) {
538         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image");
539         return;
540     }
541     GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
542     GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
543     const void* imagePixelData = imageExtractor.imagePixelData();
544     
545     bool needConversion = true;
546     if (type == GraphicsContext3D::UNSIGNED_BYTE && sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 && format == GraphicsContext3D::RGBA && alphaOp == GraphicsContext3D::AlphaDoNothing && !flipY)
547         needConversion = false;
548     else {
549         if (!m_context->packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
550             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
551             return;
552         }
553     }
554     
555     if (m_unpackAlignment != 1)
556         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
557
558     texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(), format, format, type, needConversion ? data.data() : imagePixelData);
559     if (m_unpackAlignment != 1)
560         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
561 }
562
563 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, RefPtr<ArrayBufferView>&& pixels)
564 {
565     if (isContextLostOrPending() || !validateTexFuncData("texSubImage2D", level, width, height, format, format, type, pixels.get(), NullNotAllowed) || !validateTexFunc("texSubImage2D", TexSubImage, SourceArrayBufferView, target, level, format, width, height, 0, format, type, xoffset, yoffset))
566         return;
567     
568     void* data = pixels->baseAddress();
569     Vector<uint8_t> tempData;
570     bool changeUnpackAlignment = false;
571     if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
572         if (!m_context->extractTextureData(width, height, format, type,
573             m_unpackAlignment,
574             m_unpackFlipY, m_unpackPremultiplyAlpha,
575             data,
576             tempData))
577             return;
578         data = tempData.data();
579         changeUnpackAlignment = true;
580     }
581     if (changeUnpackAlignment)
582         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
583
584     texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, format, type, data);
585     if (changeUnpackAlignment)
586         m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
587 }
588
589 ExceptionOr<void> WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Denum format, GC3Denum type, Optional<TexImageSource>&& source)
590 {
591     if (!source) {
592         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "source is null");
593         return { };
594     }
595
596     auto visitor = WTF::makeVisitor([&](const RefPtr<ImageData>& pixels) -> ExceptionOr<void> {
597         if (isContextLostOrPending() || !validateTexFunc("texSubImage2D", TexSubImage, SourceImageData, target, level, format,  pixels->width(), pixels->height(), 0, format, type, xoffset, yoffset))
598             return { };
599
600         Vector<uint8_t> data;
601         bool needConversion = true;
602         // The data from ImageData is always of format RGBA8.
603         // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
604         if (format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE && !m_unpackFlipY && !m_unpackPremultiplyAlpha)
605             needConversion = false;
606         else {
607             if (!m_context->extractImageData(pixels.get(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
608                 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image data");
609                 return { };
610             }
611         }
612         if (m_unpackAlignment != 1)
613             m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
614
615         texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(), format, format, type, needConversion ? data.data() : pixels->data()->data());
616         if (m_unpackAlignment != 1)
617             m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
618
619         return { };
620     } , [&](const RefPtr<HTMLImageElement>& image) -> ExceptionOr<void> {
621         if (wouldTaintOrigin(image.get()))
622             return Exception { SECURITY_ERR };
623         if (isContextLostOrPending() || !validateHTMLImageElement("texSubImage2D", image.get()))
624             return { };
625
626         RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
627         if (!imageForRender)
628             return { };
629
630         if (imageForRender->isSVGImage())
631             imageForRender = drawImageIntoBuffer(*imageForRender, image->width(), image->height(), 1);
632
633         if (!imageForRender || !validateTexFunc("texSubImage2D", TexSubImage, SourceHTMLImageElement, target, level, format, imageForRender->width(), imageForRender->height(), 0, format, type, xoffset, yoffset))
634             return { };
635
636         texSubImage2DImpl(target, level, xoffset, yoffset, format, type, imageForRender.get(), GraphicsContext3D::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha);
637         return { };
638     }, [&](const RefPtr<HTMLCanvasElement>& canvas) -> ExceptionOr<void> {
639         if (wouldTaintOrigin(canvas.get()))
640             return Exception { SECURITY_ERR };
641         if (isContextLostOrPending() || !validateHTMLCanvasElement("texSubImage2D", canvas.get())
642             || !validateTexFunc("texSubImage2D", TexSubImage, SourceHTMLCanvasElement, target, level, format, canvas->width(), canvas->height(), 0, format, type, xoffset, yoffset))
643             return { };
644
645         RefPtr<ImageData> imageData = canvas->getImageData();
646         if (imageData)
647             texSubImage2D(target, level, xoffset, yoffset, format, type, TexImageSource(imageData.get()));
648         else
649             texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(), GraphicsContext3D::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha);
650         return { };
651     }, [&](const RefPtr<HTMLVideoElement>& video) -> ExceptionOr<void> {
652         if (wouldTaintOrigin(video.get()))
653             return Exception { SECURITY_ERR };
654         if (isContextLostOrPending() || !validateHTMLVideoElement("texSubImage2D", video.get())
655             || !validateTexFunc("texSubImage2D", TexSubImage, SourceHTMLVideoElement, target, level, format, video->videoWidth(), video->videoHeight(), 0, format, type, xoffset, yoffset))
656             return { };
657
658         RefPtr<Image> image = videoFrameToImage(video.get(), ImageBuffer::fastCopyImageMode());
659         if (!image)
660             return { };
661         texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), GraphicsContext3D::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha);
662         return { };
663     });
664
665     return WTF::visit(visitor, source.value());
666 }
667
668 bool WebGLRenderingContext::validateTexFuncParameters(const char* functionName,
669     TexFuncValidationFunctionType functionType,
670     GC3Denum target, GC3Dint level,
671     GC3Denum internalformat,
672     GC3Dsizei width, GC3Dsizei height, GC3Dint border,
673     GC3Denum format, GC3Denum type)
674 {
675     // We absolutely have to validate the format and type combination.
676     // The texImage2D entry points taking HTMLImage, etc. will produce
677     // temporary data based on this combination, so it must be legal.
678     if (!validateTexFuncFormatAndType(functionName, internalformat, format, type, level) || !validateTexFuncLevel(functionName, target, level))
679         return false;
680     
681     if (width < 0 || height < 0) {
682         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height < 0");
683         return false;
684     }
685     
686     GC3Dint maxTextureSizeForLevel = pow(2.0, m_maxTextureLevel - 1 - level);
687     switch (target) {
688     case GraphicsContext3D::TEXTURE_2D:
689         if (width > maxTextureSizeForLevel || height > maxTextureSizeForLevel) {
690             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range");
691             return false;
692         }
693         break;
694     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
695     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
696     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
697     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
698     case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
699     case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
700         if (functionType != TexSubImage && width != height) {
701             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width != height for cube map");
702             return false;
703         }
704         // No need to check height here. For texImage width == height.
705         // For texSubImage that will be checked when checking yoffset + height is in range.
706         if (width > maxTextureSizeForLevel) {
707             synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range for cube map");
708             return false;
709         }
710         break;
711     default:
712         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
713         return false;
714     }
715
716     if (format != internalformat) {
717         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format != internalformat");
718         return false;
719     }
720     
721     if (border) {
722         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "border != 0");
723         return false;
724     }
725     
726     return true;
727 }
728
729 bool WebGLRenderingContext::validateTexFuncFormatAndType(const char* functionName, GC3Denum internalformat, GC3Denum format, GC3Denum type, GC3Dint level)
730 {
731     UNUSED_PARAM(internalformat);
732     switch (format) {
733     case GraphicsContext3D::ALPHA:
734     case GraphicsContext3D::LUMINANCE:
735     case GraphicsContext3D::LUMINANCE_ALPHA:
736     case GraphicsContext3D::RGB:
737     case GraphicsContext3D::RGBA:
738         break;
739     case GraphicsContext3D::DEPTH_STENCIL:
740     case GraphicsContext3D::DEPTH_COMPONENT:
741         if (m_webglDepthTexture)
742             break;
743         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "depth texture formats not enabled");
744         return false;
745     case Extensions3D::SRGB_EXT:
746     case Extensions3D::SRGB_ALPHA_EXT:
747     default:
748         if ((format == Extensions3D::SRGB_EXT || format == Extensions3D::SRGB_ALPHA_EXT)
749             && m_extsRGB)
750             break;
751         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture format");
752         return false;
753     }
754     
755     switch (type) {
756     case GraphicsContext3D::UNSIGNED_BYTE:
757     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
758     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
759     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
760         break;
761     case GraphicsContext3D::FLOAT:
762         if (m_oesTextureFloat)
763             break;
764         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
765         return false;
766     case GraphicsContext3D::HALF_FLOAT_OES:
767         if (m_oesTextureHalfFloat)
768             break;
769         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
770         return false;
771     case GraphicsContext3D::UNSIGNED_INT:
772     case GraphicsContext3D::UNSIGNED_INT_24_8:
773     case GraphicsContext3D::UNSIGNED_SHORT:
774         if (m_webglDepthTexture)
775             break;
776         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
777         return false;
778     default:
779         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
780         return false;
781     }
782     
783     // Verify that the combination of format and type is supported.
784     switch (format) {
785     case GraphicsContext3D::ALPHA:
786     case GraphicsContext3D::LUMINANCE:
787     case GraphicsContext3D::LUMINANCE_ALPHA:
788         if (type != GraphicsContext3D::UNSIGNED_BYTE
789             && type != GraphicsContext3D::FLOAT
790             && type != GraphicsContext3D::HALF_FLOAT_OES) {
791             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for format");
792             return false;
793         }
794         break;
795     case GraphicsContext3D::RGB:
796     case Extensions3D::SRGB_EXT:
797         if (type != GraphicsContext3D::UNSIGNED_BYTE
798             && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5
799             && type != GraphicsContext3D::FLOAT
800             && type != GraphicsContext3D::HALF_FLOAT_OES) {
801             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for RGB format");
802             return false;
803         }
804         break;
805     case GraphicsContext3D::RGBA:
806     case Extensions3D::SRGB_ALPHA_EXT:
807         if (type != GraphicsContext3D::UNSIGNED_BYTE
808             && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4
809             && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1
810             && type != GraphicsContext3D::FLOAT
811             && type != GraphicsContext3D::HALF_FLOAT_OES) {
812             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for RGBA format");
813             return false;
814         }
815         break;
816     case GraphicsContext3D::DEPTH_COMPONENT:
817         if (!m_webglDepthTexture) {
818             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format. DEPTH_COMPONENT not enabled");
819             return false;
820         }
821         if (type != GraphicsContext3D::UNSIGNED_SHORT
822             && type != GraphicsContext3D::UNSIGNED_INT) {
823             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for DEPTH_COMPONENT format");
824             return false;
825         }
826         if (level > 0) {
827             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "level must be 0 for DEPTH_COMPONENT format");
828             return false;
829         }
830         break;
831     case GraphicsContext3D::DEPTH_STENCIL:
832         if (!m_webglDepthTexture) {
833             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format. DEPTH_STENCIL not enabled");
834             return false;
835         }
836         if (type != GraphicsContext3D::UNSIGNED_INT_24_8) {
837             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for DEPTH_STENCIL format");
838             return false;
839         }
840         if (level > 0) {
841             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "level must be 0 for DEPTH_STENCIL format");
842             return false;
843         }
844         break;
845     default:
846         ASSERT_NOT_REACHED();
847     }
848     
849     return true;
850 }
851
852 bool WebGLRenderingContext::validateTexFuncData(const char* functionName, GC3Dint level, GC3Dsizei width, GC3Dsizei height, GC3Denum internalformat, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, NullDisposition disposition)
853 {
854     if (!pixels) {
855         if (disposition == NullAllowed)
856             return true;
857         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no pixels");
858         return false;
859     }
860
861     if (!validateTexFuncFormatAndType(functionName, internalformat, format, type, level))
862         return false;
863     if (!validateSettableTexFormat(functionName, format))
864         return false;
865     
866     switch (type) {
867     case GraphicsContext3D::UNSIGNED_BYTE:
868         if (pixels->getType() != JSC::TypeUint8) {
869             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array");
870             return false;
871         }
872         break;
873     case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
874     case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
875     case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
876         if (pixels->getType() != JSC::TypeUint16) {
877             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
878             return false;
879         }
880         break;
881     case GraphicsContext3D::FLOAT: // OES_texture_float
882         if (pixels->getType() != JSC::TypeFloat32) {
883             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type FLOAT but ArrayBufferView not Float32Array");
884             return false;
885         }
886         break;
887     case GraphicsContext3D::HALF_FLOAT_OES: // OES_texture_half_float
888         // As per the specification, ArrayBufferView should be null when
889         // OES_texture_half_float is enabled.
890         if (pixels) {
891             synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type HALF_FLOAT_OES but ArrayBufferView is not NULL");
892             return false;
893         }
894         break;
895     default:
896         ASSERT_NOT_REACHED();
897     }
898     
899     unsigned totalBytesRequired;
900     GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
901     if (error != GraphicsContext3D::NO_ERROR) {
902         synthesizeGLError(error, functionName, "invalid texture dimensions");
903         return false;
904     }
905     if (pixels->byteLength() < totalBytesRequired) {
906         if (m_unpackAlignment != 1) {
907             m_context->computeImageSizeInBytes(format, type, width, height, 1, &totalBytesRequired, 0);
908             if (pixels->byteLength() == totalBytesRequired) {
909                 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request with UNPACK_ALIGNMENT > 1");
910                 return false;
911             }
912         }
913         synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request");
914         return false;
915     }
916     return true;
917 }
918
919 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname)
920 {
921     if (isContextLostOrPending())
922         return WebGLGetInfo();
923     const int intZero = 0;
924     switch (pname) {
925     case GraphicsContext3D::ACTIVE_TEXTURE:
926         return getUnsignedIntParameter(pname);
927     case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
928         return getWebGLFloatArrayParameter(pname);
929     case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
930         return getWebGLFloatArrayParameter(pname);
931     case GraphicsContext3D::ALPHA_BITS:
932         return getIntParameter(pname);
933     case GraphicsContext3D::ARRAY_BUFFER_BINDING:
934         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
935     case GraphicsContext3D::BLEND:
936         return getBooleanParameter(pname);
937     case GraphicsContext3D::BLEND_COLOR:
938         return getWebGLFloatArrayParameter(pname);
939     case GraphicsContext3D::BLEND_DST_ALPHA:
940         return getUnsignedIntParameter(pname);
941     case GraphicsContext3D::BLEND_DST_RGB:
942         return getUnsignedIntParameter(pname);
943     case GraphicsContext3D::BLEND_EQUATION_ALPHA:
944         return getUnsignedIntParameter(pname);
945     case GraphicsContext3D::BLEND_EQUATION_RGB:
946         return getUnsignedIntParameter(pname);
947     case GraphicsContext3D::BLEND_SRC_ALPHA:
948         return getUnsignedIntParameter(pname);
949     case GraphicsContext3D::BLEND_SRC_RGB:
950         return getUnsignedIntParameter(pname);
951     case GraphicsContext3D::BLUE_BITS:
952         return getIntParameter(pname);
953     case GraphicsContext3D::COLOR_CLEAR_VALUE:
954         return getWebGLFloatArrayParameter(pname);
955     case GraphicsContext3D::COLOR_WRITEMASK:
956         return getBooleanArrayParameter(pname);
957     case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
958         return WebGLGetInfo(PassRefPtr<Uint32Array>(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size())));
959     case GraphicsContext3D::CULL_FACE:
960         return getBooleanParameter(pname);
961     case GraphicsContext3D::CULL_FACE_MODE:
962         return getUnsignedIntParameter(pname);
963     case GraphicsContext3D::CURRENT_PROGRAM:
964         return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
965     case GraphicsContext3D::DEPTH_BITS:
966         if (!m_framebufferBinding && !m_attributes.depth)
967             return WebGLGetInfo(intZero);
968         return getIntParameter(pname);
969     case GraphicsContext3D::DEPTH_CLEAR_VALUE:
970         return getFloatParameter(pname);
971     case GraphicsContext3D::DEPTH_FUNC:
972         return getUnsignedIntParameter(pname);
973     case GraphicsContext3D::DEPTH_RANGE:
974         return getWebGLFloatArrayParameter(pname);
975     case GraphicsContext3D::DEPTH_TEST:
976         return getBooleanParameter(pname);
977     case GraphicsContext3D::DEPTH_WRITEMASK:
978         return getBooleanParameter(pname);
979     case GraphicsContext3D::DITHER:
980         return getBooleanParameter(pname);
981     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
982         return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
983     case GraphicsContext3D::FRAMEBUFFER_BINDING:
984         return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
985     case GraphicsContext3D::FRONT_FACE:
986         return getUnsignedIntParameter(pname);
987     case GraphicsContext3D::GENERATE_MIPMAP_HINT:
988         return getUnsignedIntParameter(pname);
989     case GraphicsContext3D::GREEN_BITS:
990         return getIntParameter(pname);
991     case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_FORMAT:
992         return getIntParameter(pname);
993     case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_TYPE:
994         return getIntParameter(pname);
995     case GraphicsContext3D::LINE_WIDTH:
996         return getFloatParameter(pname);
997     case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
998         return getIntParameter(pname);
999     case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
1000         return getIntParameter(pname);
1001     case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
1002         return getIntParameter(pname);
1003     case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
1004         return getIntParameter(pname);
1005     case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
1006         return getIntParameter(pname);
1007     case GraphicsContext3D::MAX_TEXTURE_SIZE:
1008         return getIntParameter(pname);
1009     case GraphicsContext3D::MAX_VARYING_VECTORS:
1010         return getIntParameter(pname);
1011     case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
1012         return getIntParameter(pname);
1013     case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
1014         return getIntParameter(pname);
1015     case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
1016         return getIntParameter(pname);
1017     case GraphicsContext3D::MAX_VIEWPORT_DIMS:
1018         return getWebGLIntArrayParameter(pname);
1019     case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
1020         return getIntParameter(pname);
1021     case GraphicsContext3D::PACK_ALIGNMENT:
1022         return getIntParameter(pname);
1023     case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
1024         return getFloatParameter(pname);
1025     case GraphicsContext3D::POLYGON_OFFSET_FILL:
1026         return getBooleanParameter(pname);
1027     case GraphicsContext3D::POLYGON_OFFSET_UNITS:
1028         return getFloatParameter(pname);
1029     case GraphicsContext3D::RED_BITS:
1030         return getIntParameter(pname);
1031     case GraphicsContext3D::RENDERBUFFER_BINDING:
1032         return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
1033     case GraphicsContext3D::RENDERER:
1034         return WebGLGetInfo(String("WebKit WebGL"));
1035     case GraphicsContext3D::SAMPLE_BUFFERS:
1036         return getIntParameter(pname);
1037     case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
1038         return getBooleanParameter(pname);
1039     case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
1040         return getFloatParameter(pname);
1041     case GraphicsContext3D::SAMPLES:
1042         return getIntParameter(pname);
1043     case GraphicsContext3D::SCISSOR_BOX:
1044         return getWebGLIntArrayParameter(pname);
1045     case GraphicsContext3D::SCISSOR_TEST:
1046         return getBooleanParameter(pname);
1047     case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
1048         return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
1049     case GraphicsContext3D::STENCIL_BACK_FAIL:
1050         return getUnsignedIntParameter(pname);
1051     case GraphicsContext3D::STENCIL_BACK_FUNC:
1052         return getUnsignedIntParameter(pname);
1053     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
1054         return getUnsignedIntParameter(pname);
1055     case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
1056         return getUnsignedIntParameter(pname);
1057     case GraphicsContext3D::STENCIL_BACK_REF:
1058         return getIntParameter(pname);
1059     case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
1060         return getUnsignedIntParameter(pname);
1061     case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
1062         return getUnsignedIntParameter(pname);
1063     case GraphicsContext3D::STENCIL_BITS:
1064         if (!m_framebufferBinding && !m_attributes.stencil)
1065             return WebGLGetInfo(intZero);
1066         return getIntParameter(pname);
1067     case GraphicsContext3D::STENCIL_CLEAR_VALUE:
1068         return getIntParameter(pname);
1069     case GraphicsContext3D::STENCIL_FAIL:
1070         return getUnsignedIntParameter(pname);
1071     case GraphicsContext3D::STENCIL_FUNC:
1072         return getUnsignedIntParameter(pname);
1073     case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
1074         return getUnsignedIntParameter(pname);
1075     case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
1076         return getUnsignedIntParameter(pname);
1077     case GraphicsContext3D::STENCIL_REF:
1078         return getIntParameter(pname);
1079     case GraphicsContext3D::STENCIL_TEST:
1080         return getBooleanParameter(pname);
1081     case GraphicsContext3D::STENCIL_VALUE_MASK:
1082         return getUnsignedIntParameter(pname);
1083     case GraphicsContext3D::STENCIL_WRITEMASK:
1084         return getUnsignedIntParameter(pname);
1085     case GraphicsContext3D::SUBPIXEL_BITS:
1086         return getIntParameter(pname);
1087     case GraphicsContext3D::TEXTURE_BINDING_2D:
1088         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].texture2DBinding));
1089     case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
1090         return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].textureCubeMapBinding));
1091     case GraphicsContext3D::UNPACK_ALIGNMENT:
1092         return getIntParameter(pname);
1093     case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
1094         return WebGLGetInfo(m_unpackFlipY);
1095     case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
1096         return WebGLGetInfo(m_unpackPremultiplyAlpha);
1097     case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
1098         return WebGLGetInfo(m_unpackColorspaceConversion);
1099     case GraphicsContext3D::VENDOR:
1100         return WebGLGetInfo(String("WebKit"));
1101     case GraphicsContext3D::VERSION:
1102         return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
1103     case GraphicsContext3D::VIEWPORT:
1104         return getWebGLIntArrayParameter(pname);
1105     case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
1106         if (m_oesStandardDerivatives)
1107             return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
1108         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
1109         return WebGLGetInfo();
1110     case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
1111         if (m_webglDebugRendererInfo)
1112             return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
1113         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
1114         return WebGLGetInfo();
1115     case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
1116         if (m_webglDebugRendererInfo)
1117             return WebGLGetInfo(m_context->getString(GraphicsContext3D::VENDOR));
1118         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
1119         return WebGLGetInfo();
1120     case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
1121         if (m_oesVertexArrayObject) {
1122             if (!m_boundVertexArrayObject->isDefaultObject())
1123                 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(static_cast<WebGLVertexArrayObjectOES*>(m_boundVertexArrayObject.get())));
1124             return WebGLGetInfo();
1125         }
1126         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
1127         return WebGLGetInfo();
1128     case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
1129         if (m_extTextureFilterAnisotropic)
1130             return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT);
1131         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
1132         return WebGLGetInfo();
1133     case Extensions3D::MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN
1134         if (m_webglDrawBuffers)
1135             return WebGLGetInfo(getMaxColorAttachments());
1136         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
1137         return WebGLGetInfo();
1138     case Extensions3D::MAX_DRAW_BUFFERS_EXT:
1139         if (m_webglDrawBuffers)
1140             return WebGLGetInfo(getMaxDrawBuffers());
1141         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
1142         return WebGLGetInfo();
1143     default:
1144         if (m_webglDrawBuffers
1145             && pname >= Extensions3D::DRAW_BUFFER0_EXT
1146             && pname < static_cast<GC3Denum>(Extensions3D::DRAW_BUFFER0_EXT + getMaxDrawBuffers())) {
1147             GC3Dint value = GraphicsContext3D::NONE;
1148             if (m_framebufferBinding)
1149                 value = m_framebufferBinding->getDrawBuffer(pname);
1150             else // emulated backbuffer
1151                 value = m_backDrawBuffer;
1152             return WebGLGetInfo(value);
1153         }
1154         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name");
1155         return WebGLGetInfo();
1156     }
1157 }
1158
1159 GC3Dint WebGLRenderingContext::getMaxDrawBuffers()
1160 {
1161     if (!supportsDrawBuffers())
1162         return 0;
1163     if (!m_maxDrawBuffers)
1164         m_context->getIntegerv(Extensions3D::MAX_DRAW_BUFFERS_EXT, &m_maxDrawBuffers);
1165     if (!m_maxColorAttachments)
1166         m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
1167     // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
1168     return std::min(m_maxDrawBuffers, m_maxColorAttachments);
1169 }
1170
1171 GC3Dint WebGLRenderingContext::getMaxColorAttachments()
1172 {
1173     if (!supportsDrawBuffers())
1174         return 0;
1175     if (!m_maxColorAttachments)
1176         m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
1177     return m_maxColorAttachments;
1178 }
1179     
1180 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, unsigned& numElementsRequired)
1181 {
1182     // Performs conservative validation by caching a maximum index of
1183     // the given type per element array buffer. If all of the bound
1184     // array buffers have enough elements to satisfy that maximum
1185     // index, skips the expensive per-draw-call iteration in
1186     // validateIndexArrayPrecise.
1187     
1188     RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1189     
1190     if (!elementArrayBuffer)
1191         return false;
1192     
1193     GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
1194     // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1195     if (!numElements)
1196         return false;
1197     const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
1198     ASSERT(buffer);
1199     
1200     int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
1201     if (maxIndex < 0) {
1202         // Compute the maximum index in the entire buffer for the given type of index.
1203         switch (type) {
1204         case GraphicsContext3D::UNSIGNED_BYTE: {
1205             const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
1206             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1207                 maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
1208             break;
1209         }
1210         case GraphicsContext3D::UNSIGNED_SHORT: {
1211             numElements /= sizeof(GC3Dushort);
1212             const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
1213             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1214                 maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
1215             break;
1216         }
1217         case GraphicsContext3D::UNSIGNED_INT: {
1218             if (!m_oesElementIndexUint)
1219                 return false;
1220             numElements /= sizeof(GC3Duint);
1221             const GC3Duint* p = static_cast<const GC3Duint*>(buffer->data());
1222             for (GC3Dsizeiptr i = 0; i < numElements; i++)
1223                 maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
1224             break;
1225         }
1226         default:
1227             return false;
1228     }
1229     elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1230     }
1231     
1232     if (maxIndex >= 0) {
1233         // The number of required elements is one more than the maximum
1234         // index that will be accessed.
1235         numElementsRequired = maxIndex + 1;
1236         return true;
1237     }
1238     
1239     return false;
1240 }
1241
1242 bool WebGLRenderingContext::validateBlendEquation(const char* functionName, GC3Denum mode)
1243 {
1244     switch (mode) {
1245     case GraphicsContext3D::FUNC_ADD:
1246     case GraphicsContext3D::FUNC_SUBTRACT:
1247     case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
1248     case Extensions3D::MIN_EXT:
1249     case Extensions3D::MAX_EXT:
1250         if ((mode == Extensions3D::MIN_EXT || mode == Extensions3D::MAX_EXT) && !m_extBlendMinMax) {
1251             synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode");
1252             return false;
1253         }
1254         return true;
1255         break;
1256     default:
1257         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode");
1258         return false;
1259     }
1260 }
1261
1262 bool WebGLRenderingContext::validateCapability(const char* functionName, GC3Denum cap)
1263 {
1264     switch (cap) {
1265     case GraphicsContext3D::BLEND:
1266     case GraphicsContext3D::CULL_FACE:
1267     case GraphicsContext3D::DEPTH_TEST:
1268     case GraphicsContext3D::DITHER:
1269     case GraphicsContext3D::POLYGON_OFFSET_FILL:
1270     case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
1271     case GraphicsContext3D::SAMPLE_COVERAGE:
1272     case GraphicsContext3D::SCISSOR_TEST:
1273     case GraphicsContext3D::STENCIL_TEST:
1274         return true;
1275     default:
1276         synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid capability");
1277         return false;
1278     }
1279 }
1280
1281 } // namespace WebCore
1282
1283 #endif // ENABLE(WEBGL)