Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: Source/core/html/canvas/WebGLRenderingContext.cpp

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

Powered by Google App Engine
This is Rietveld 408576698