summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/html/canvas/WebGLRenderingContext.cpp')
-rw-r--r--Source/WebCore/html/canvas/WebGLRenderingContext.cpp523
1 files changed, 331 insertions, 192 deletions
diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
index 933d37f..7e7bfe3 100644
--- a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
+++ b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012 Sony Ericsson Mobile Communications AB
+ * Copyright (C) 2012 Sony Mobile Communications AB
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -51,6 +53,7 @@
#include "RenderLayer.h"
#include "Settings.h"
#include "Uint16Array.h"
+#include "Uint32Array.h"
#include "WebGLActiveInfo.h"
#include "WebGLBuffer.h"
#include "WebGLContextAttributes.h"
@@ -328,29 +331,14 @@ private:
void WebGLRenderingContext::WebGLRenderingContextRestoreTimer::fired()
{
- // Timer is started when m_contextLost is false. It will first call
- // onLostContext, which will set m_contextLost to true. Then it will keep
- // calling restoreContext and reschedule itself until m_contextLost is back
- // to false.
- if (!m_context->m_contextLost) {
- m_context->onLostContext();
- startOneShot(secondsBetweenRestoreAttempts);
- } else {
- // The rendering context is not restored if there is no handler for
- // the context restored event.
- if (!m_context->canvas()->hasEventListeners(eventNames().webglcontextrestoredEvent))
- return;
-
- m_context->restoreContext();
- if (m_context->m_contextLost)
- startOneShot(secondsBetweenRestoreAttempts);
- }
+ m_context->maybeRestoreContext(RealLostContext);
}
class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
public:
WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_contextLostCallback(cb) {}
- virtual void onContextLost() { m_contextLostCallback->forceLostContext(); }
+ virtual void onContextLost() {
+ m_contextLostCallback->forceLostContext(WebGLRenderingContext::RealLostContext); }
virtual ~WebGLRenderingContextLostCallback() {}
private:
WebGLRenderingContext* m_contextLostCallback;
@@ -367,7 +355,11 @@ PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElemen
attributes.antialias = false;
}
+#if PLATFORM(ANDROID)
+ RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(canvas, attributes, 0));
+#else
RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
+#endif
if (!context) {
canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
@@ -381,6 +373,7 @@ WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, Pa
GraphicsContext3D::Attributes attributes)
: CanvasRenderingContext(passedCanvas)
, m_context(context)
+ , m_restoreAllowed(false)
, m_restoreTimer(this)
, m_videoCache(4)
, m_contextLost(false)
@@ -554,9 +547,10 @@ void WebGLRenderingContext::paintRenderingResultsToCanvas()
{
// Until the canvas is written to by the application, the clear that
// happened after it was composited should be ignored by the compositor.
- if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer)
+ if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
+ m_context->paintCompositedResultsToCanvas(this);
canvas()->makePresentationCopy();
- else
+ } else
canvas()->clearPresentationCopy();
clearIfComposited();
if (!m_markedCanvasDirty && !m_layerCleared)
@@ -577,6 +571,18 @@ bool WebGLRenderingContext::paintsIntoCanvasBuffer() const
return m_context->paintsIntoCanvasBuffer();
}
+#if PLATFORM(ANDROID)
+void WebGLRenderingContext::recreateSurface()
+{
+ m_context->recreateSurface();
+}
+
+void WebGLRenderingContext::releaseSurface()
+{
+ m_context->releaseSurface();
+}
+#endif
+
void WebGLRenderingContext::reshape(int width, int height)
{
if (m_needsUpdate) {
@@ -593,6 +599,20 @@ void WebGLRenderingContext::reshape(int width, int height)
m_context->reshape(width, height);
}
+GC3Dsizei WebGLRenderingContext::drawingBufferWidth()
+{
+ if (isContextLost())
+ return 0;
+ return m_context->getInternalFramebufferSize().width();
+}
+
+GC3Dsizei WebGLRenderingContext::drawingBufferHeight()
+{
+ if (isContextLost())
+ return 0;
+ return m_context->getInternalFramebufferSize().height();
+}
+
unsigned int WebGLRenderingContext::sizeInBytes(GC3Denum type)
{
switch (type) {
@@ -648,6 +668,8 @@ void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, GC3Duint i
UNUSED_PARAM(ec);
if (isContextLost() || !validateWebGLObject(program))
return;
+ if (!validateLocationLength(name))
+ return;
if (!validateString(name))
return;
m_context->bindAttribLocation(objectOrZero(program), index, name);
@@ -814,7 +836,7 @@ void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB,
cleanupAfterGraphicsCall(false);
}
-void WebGLRenderingContext::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage, ExceptionCode& ec)
+void WebGLRenderingContext::bufferData(GC3Denum target, long long size, GC3Denum usage, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
if (isContextLost())
@@ -827,13 +849,13 @@ void WebGLRenderingContext::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3De
return;
}
if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
- if (!buffer->associateBufferData(size)) {
+ if (!buffer->associateBufferData(static_cast<GC3Dsizeiptr>(size))) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
}
- m_context->bufferData(target, size, usage);
+ m_context->bufferData(target, static_cast<GC3Dsizeiptr>(size), usage);
cleanupAfterGraphicsCall(false);
}
@@ -856,7 +878,9 @@ void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3De
}
}
- m_context->bufferData(target, data->byteLength(), data->data(), usage);
+ // Some platforms incorrectly signal GL_OUT_OF_MEMORY if size == 0
+ if (data->byteLength() > 0)
+ m_context->bufferData(target, data->byteLength(), data->data(), usage);
cleanupAfterGraphicsCall(false);
}
@@ -879,11 +903,13 @@ void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, G
}
}
- m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
+ // Some platforms incorrectly signal GL_OUT_OF_MEMORY if size == 0
+ if (data->byteLength() > 0)
+ m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
cleanupAfterGraphicsCall(false);
}
-void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBuffer* data, ExceptionCode& ec)
+void WebGLRenderingContext::bufferSubData(GC3Denum target, long long offset, ArrayBuffer* data, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
if (isContextLost())
@@ -898,17 +924,17 @@ void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, Ar
if (!data)
return;
if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
- if (!buffer->associateBufferSubData(offset, data)) {
+ if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
}
- m_context->bufferSubData(target, offset, data->byteLength(), data->data());
+ m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->data());
cleanupAfterGraphicsCall(false);
}
-void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBufferView* data, ExceptionCode& ec)
+void WebGLRenderingContext::bufferSubData(GC3Denum target, long long offset, ArrayBufferView* data, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
if (isContextLost())
@@ -923,13 +949,13 @@ void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, Ar
if (!data)
return;
if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
- if (!buffer->associateBufferSubData(offset, data)) {
+ if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
}
- m_context->bufferSubData(target, offset, data->byteLength(), data->baseAddress());
+ m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->baseAddress());
cleanupAfterGraphicsCall(false);
}
@@ -943,9 +969,10 @@ GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target)
}
if (!m_framebufferBinding || !m_framebufferBinding->object())
return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
- if (m_framebufferBinding->isIncomplete(true))
- return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
- unsigned long result = m_context->checkFramebufferStatus(target);
+ GC3Denum result = m_framebufferBinding->checkStatus();
+ if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
+ return result;
+ result = m_context->checkFramebufferStatus(target);
cleanupAfterGraphicsCall(false);
return result;
}
@@ -1026,6 +1053,34 @@ void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec
cleanupAfterGraphicsCall(false);
}
+void WebGLRenderingContext::compressedTexImage2D(GC3Denum target, GC3Dint level,
+ GC3Denum internalformat, GC3Dsizei width,
+ GC3Dsizei height, GC3Dint border,
+ ArrayBufferView* data)
+{
+ if (isContextLost())
+ return;
+ if (!validateTexFuncLevel(target, level))
+ return;
+
+ // Currently, we have no support for compressed textures:
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+}
+
+void WebGLRenderingContext::compressedTexSubImage2D(GC3Denum target, GC3Dint level,
+ GC3Dint xoffset, GC3Dint yoffset,
+ GC3Dsizei width, GC3Dsizei height,
+ GC3Denum format, ArrayBufferView* data)
+{
+ if (isContextLost())
+ return;
+ if (!validateTexFuncLevel(target, level))
+ return;
+
+ // Currently, we have no support for compressed textures:
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+}
+
void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
{
if (isContextLost())
@@ -1048,8 +1103,10 @@ void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3De
return;
}
clearIfComposited();
- if (isResourceSafe())
- m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
+ if (isResourceSafe()) {
+ if (width > 0 && height > 0)
+ m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
+ }
else {
GC3Dint clippedX, clippedY;
GC3Dsizei clippedWidth, clippedHeight;
@@ -1060,8 +1117,11 @@ void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3De
m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
clippedX, clippedY, clippedWidth, clippedHeight);
}
- } else
- m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
+ } else {
+ if (width > 0 && height > 0)
+ m_context->copyTexImage2D(target, level, internalformat,
+ x, y, width, height, border);
+ }
}
// FIXME: if the framebuffer is not complete, none of the below should be executed.
tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
@@ -1256,7 +1316,7 @@ void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
if (renderbuffer == m_renderbufferBinding)
m_renderbufferBinding = 0;
if (m_framebufferBinding)
- m_framebufferBinding->removeAttachment(renderbuffer);
+ m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
}
void WebGLRenderingContext::deleteShader(WebGLShader* shader)
@@ -1275,7 +1335,7 @@ void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
m_textureUnits[i].m_textureCubeMapBinding = 0;
}
if (m_framebufferBinding)
- m_framebufferBinding->removeAttachment(texture);
+ m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
}
void WebGLRenderingContext::depthFunc(GC3Denum func)
@@ -1586,7 +1646,7 @@ void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei c
cleanupAfterGraphicsCall(true);
}
-void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, ExceptionCode& ec)
+void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
@@ -1621,14 +1681,14 @@ void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denu
int numElements = 0;
if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
// Ensure we have a valid rendering state
- if (!validateElementArraySize(count, type, offset)) {
+ if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
if (!count)
return;
if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) {
- if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
+ if (!validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements) || !validateRenderingState(numElements)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
@@ -1649,12 +1709,12 @@ void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denu
bool vertexAttrib0Simulated = false;
if (!isGLES2Compliant()) {
if (!numElements)
- validateIndexArrayPrecise(count, type, offset, numElements);
+ validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
}
if (!isGLES2NPOTStrict())
handleNPOTTextures(true);
- m_context->drawElements(mode, count, type, offset);
+ m_context->drawElements(mode, count, type, static_cast<GC3Dintptr>(offset));
if (!isGLES2Compliant() && vertexAttrib0Simulated)
restoreStatesAfterVertexAttrib0Simulation();
if (!isGLES2NPOTStrict())
@@ -1752,7 +1812,7 @@ void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum at
default:
m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
}
- m_framebufferBinding->setAttachment(attachment, buffer);
+ m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
if (reattachDepth) {
Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT));
if (object)
@@ -1797,7 +1857,7 @@ void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attac
return;
}
m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level);
- m_framebufferBinding->setAttachment(attachment, textarget, texture, level);
+ m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
cleanupAfterGraphicsCall(false);
}
@@ -1869,23 +1929,15 @@ bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<Web
shaderObjects.clear();
if (isContextLost() || !validateWebGLObject(program))
return false;
- GC3Dint numShaders = 0;
- m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ATTACHED_SHADERS, &numShaders);
- if (numShaders) {
- OwnArrayPtr<Platform3DObject> shaders = adoptArrayPtr(new Platform3DObject[numShaders]);
- GC3Dsizei count = 0;
- m_context->getAttachedShaders(objectOrZero(program), numShaders, &count, shaders.get());
- if (count != numShaders)
- return false;
- shaderObjects.resize(numShaders);
- for (GC3Dint ii = 0; ii < numShaders; ++ii) {
- WebGLShader* shader = findShader(shaders[ii]);
- if (!shader) {
- shaderObjects.clear();
- return false;
- }
- shaderObjects[ii] = shader;
- }
+
+ const GC3Denum shaderType[] = {
+ GraphicsContext3D::VERTEX_SHADER,
+ GraphicsContext3D::FRAGMENT_SHADER
+ };
+ for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
+ WebGLShader* shader = program->getAttachedShader(shaderType[i]);
+ if (shader)
+ shaderObjects.append(shader);
}
return true;
}
@@ -1894,6 +1946,8 @@ GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const St
{
if (isContextLost())
return -1;
+ if (!validateLocationLength(name))
+ return -1;
if (!validateString(name))
return -1;
return m_context->getAttribLocation(objectOrZero(program), name);
@@ -1914,6 +1968,12 @@ WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum
return WebGLGetInfo();
}
+ // Some platforms fail to raise INVALID_OPERATION if no array buffer is bound
+ if (target == GraphicsContext3D::ARRAY_BUFFER && !m_boundArrayBuffer) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return WebGLGetInfo();
+ }
+
WebGLStateRestorer(this, false);
GC3Dint value = 0;
m_context->getBufferParameteriv(target, pname, &value);
@@ -1979,46 +2039,51 @@ WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum t
UNUSED_PARAM(ec);
if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
return WebGLGetInfo();
- switch (pname) {
- case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
- case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
- case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
- case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
- break;
- default:
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
- return WebGLGetInfo();
- }
- if (!m_framebufferBinding || !m_framebufferBinding->object() || m_framebufferBinding->isIncomplete(false)) {
+ if (!m_framebufferBinding || !m_framebufferBinding->object()) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return WebGLGetInfo();
}
- if (pname != GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
- WebGLStateRestorer(this, false);
- GC3Dint value = 0;
- m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
+ WebGLObject* object = m_framebufferBinding->getAttachment(attachment);
+ if (!object) {
if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
- return WebGLGetInfo(static_cast<unsigned int>(value));
- return WebGLGetInfo(value);
+ return WebGLGetInfo(static_cast<unsigned int>(GraphicsContext3D::NONE));
+ // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
+ // specifies INVALID_OPERATION.
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return WebGLGetInfo();
}
- WebGLStateRestorer(this, false);
- GC3Dint type = 0;
- m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
- if (!type)
- return WebGLGetInfo();
- GC3Dint value = 0;
- m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &value);
- switch (type) {
- case GraphicsContext3D::RENDERBUFFER:
- return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(findRenderbuffer(static_cast<Platform3DObject>(value))));
- case GraphicsContext3D::TEXTURE:
- return WebGLGetInfo(PassRefPtr<WebGLTexture>(findTexture(static_cast<Platform3DObject>(value))));
- default:
- // FIXME: raise exception?
- return WebGLGetInfo();
+ ASSERT(object->isTexture() || object->isRenderbuffer());
+ if (object->isTexture()) {
+ switch (pname) {
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ return WebGLGetInfo(static_cast<unsigned int>(GraphicsContext3D::TEXTURE));
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+ {
+ WebGLStateRestorer(this, false);
+ GC3Dint value = 0;
+ m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
+ return WebGLGetInfo(value);
+ }
+ default:
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return WebGLGetInfo();
+ }
+ } else {
+ switch (pname) {
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ return WebGLGetInfo(static_cast<unsigned int>(GraphicsContext3D::RENDERBUFFER));
+ case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
+ default:
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return WebGLGetInfo();
+ }
}
}
@@ -2062,8 +2127,8 @@ WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode&
case GraphicsContext3D::COLOR_WRITEMASK:
return getBooleanArrayParameter(pname);
case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
- // Defined as null in the spec
- return WebGLGetInfo();
+ // Currently, we have no support for compressed textures:
+ return WebGLGetInfo(Uint32Array::create(0, 0));
case GraphicsContext3D::CULL_FACE:
return getBooleanParameter(pname);
case GraphicsContext3D::CULL_FACE_MODE:
@@ -2558,6 +2623,8 @@ PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGL
UNUSED_PARAM(ec);
if (isContextLost() || !validateWebGLObject(program))
return 0;
+ if (!validateLocationLength(name))
+ return 0;
if (!validateString(name))
return 0;
WebGLStateRestorer(this, false);
@@ -2603,13 +2670,13 @@ WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pna
}
}
-GC3Dsizeiptr WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
+long long WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
{
if (isContextLost())
return 0;
GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
cleanupAfterGraphicsCall(false);
- return result;
+ return static_cast<long long>(result);
}
void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
@@ -2647,14 +2714,6 @@ GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
bool WebGLRenderingContext::isContextLost()
{
- if (m_restoreTimer.isActive())
- return true;
-
- bool newContextLost = m_context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR;
-
- if (newContextLost != m_contextLost)
- m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
-
return m_contextLost;
}
@@ -2736,12 +2795,6 @@ void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec
m_context->linkProgram(objectOrZero(program));
program->increaseLinkCount();
- // cache link status
- GC3Dint value = 0;
- m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::LINK_STATUS, &value);
- program->setLinkStatus(static_cast<bool>(value));
- // Need to cache link status before caching active attribute locations.
- program->cacheActiveAttribLocations();
cleanupAfterGraphicsCall(false);
}
@@ -2792,14 +2845,13 @@ void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
cleanupAfterGraphicsCall(false);
}
-void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
+void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&)
{
if (isContextLost())
return;
- if (!canvas()->originClean()) {
- ec = SECURITY_ERR;
- return;
- }
+ // Due to WebGL's same-origin restrictions, it is not possible to
+ // taint the origin using the WebGL API.
+ ASSERT(canvas()->originClean());
// Validate input parameters.
if (!pixels) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
@@ -2851,7 +2903,51 @@ void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC
}
clearIfComposited();
void* data = pixels->baseAddress();
- m_context->readPixels(x, y, width, height, format, type, data);
+
+ // WebGL requires that areas lying outside the frame buffer should be filled with 0.
+ // Most OpenGL platforms do not support this directly.
+ GC3Dint clippedX, clippedY;
+ GC3Dsizei clippedWidth, clippedHeight;
+ if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(),
+ &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
+ unsigned int padding = 0;
+ m_context->computeImageSizeInBytes(format, type, clippedWidth, clippedHeight,
+ m_packAlignment, &totalBytesRequired, &padding);
+ char *tmp = (char *)fastMalloc(totalBytesRequired);
+ // Some platforms incorrectly signal GL_INVALID_VALUE if width == 0 || height == 0
+ if (clippedWidth > 0 && clippedHeight > 0)
+ m_context->readPixels(clippedX, clippedY, clippedWidth,
+ clippedHeight, format, type, tmp);
+
+ unsigned int bytesPerComponent, componentsPerPixel;
+ m_context->computeFormatAndTypeParameters(format, type, &componentsPerPixel,
+ &bytesPerComponent);
+ int clippedRowBytes = bytesPerComponent * componentsPerPixel * clippedWidth;
+ int clippedStride = clippedRowBytes + padding;
+ int rowBytes = bytesPerComponent * componentsPerPixel * width;
+ int stride = rowBytes + padding;
+ char *src = tmp;
+ char *dst = (char *)data;
+ int xdelta = (clippedX - x) * bytesPerComponent * componentsPerPixel;
+ for (int r = y; r < y + height; r++) {
+ if (r < y + height - 1)
+ memset(dst, 0, stride);
+ else
+ memset(dst, 0, rowBytes);
+ if (r >= clippedY && r < clippedY + clippedHeight) {
+ memcpy(dst + xdelta, src, clippedRowBytes);
+ src += clippedStride;
+ }
+ dst += stride;
+ }
+ fastFree(tmp);
+ }
+ else {
+ // Some platforms incorrectly signal GL_INVALID_VALUE if width == 0 || height == 0
+ if (width > 0 && height > 0)
+ m_context->readPixels(x, y, width, height, format, type, data);
+ }
+
#if OS(DARWIN)
// FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
// when alpha is off, readPixels should set alpha to 255 instead of 0.
@@ -3142,7 +3238,11 @@ void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum
return;
if (!validateHTMLImageElement(image))
return;
- checkOrigin(image);
+ if (wouldTaintOrigin(image)) {
+ ec = SECURITY_ERR;
+ return;
+ }
+
texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->image(),
m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
}
@@ -3157,7 +3257,10 @@ void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
- checkOrigin(canvas);
+ if (wouldTaintOrigin(canvas)) {
+ ec = SECURITY_ERR;
+ return;
+ }
RefPtr<ImageData> imageData = canvas->getImageData();
if (imageData)
texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
@@ -3167,7 +3270,7 @@ void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum
}
#if ENABLE(VIDEO)
-PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video)
+PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video, ExceptionCode& ec)
{
if (!video || !video->videoWidth() || !video->videoHeight()) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
@@ -3179,7 +3282,10 @@ PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* vid
m_context->synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY);
return 0;
}
- checkOrigin(video);
+ if (wouldTaintOrigin(video)) {
+ ec = SECURITY_ERR;
+ return 0;
+ }
IntRect destRect(0, 0, size.width(), size.height());
// FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
video->paintCurrentFrameInContext(buf->context(), destRect);
@@ -3192,8 +3298,8 @@ void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum
ec = 0;
if (isContextLost())
return;
- RefPtr<Image> image = videoFrameToImage(video);
- if (!video)
+ RefPtr<Image> image = videoFrameToImage(video, ec);
+ if (!image)
return;
texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
}
@@ -3334,7 +3440,10 @@ void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Din
return;
if (!validateHTMLImageElement(image))
return;
- checkOrigin(image);
+ if (wouldTaintOrigin(image)) {
+ ec = SECURITY_ERR;
+ return;
+ }
texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image->cachedImage()->image(),
m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
}
@@ -3349,7 +3458,10 @@ void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Din
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
- checkOrigin(canvas);
+ if (wouldTaintOrigin(canvas)) {
+ ec = SECURITY_ERR;
+ return;
+ }
RefPtr<ImageData> imageData = canvas->getImageData();
if (imageData)
texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec);
@@ -3365,8 +3477,8 @@ void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Din
ec = 0;
if (isContextLost())
return;
- RefPtr<Image> image = videoFrameToImage(video);
- if (!video)
+ RefPtr<Image> image = videoFrameToImage(video, ec);
+ if (!image)
return;
texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
}
@@ -3799,7 +3911,7 @@ void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsi
vertexAttribfvImpl(index, v, size, 4);
}
-void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset, ExceptionCode& ec)
+void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, long long offset, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
if (isContextLost())
@@ -3833,7 +3945,7 @@ void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC
m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
return;
}
- if ((stride % typeSize) || (offset % typeSize)) {
+ if ((stride % typeSize) || (static_cast<GC3Dintptr>(offset) % typeSize)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
@@ -3849,8 +3961,8 @@ void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC
state.normalized = normalized;
state.stride = validatedStride;
state.originalStride = stride;
- state.offset = offset;
- m_context->vertexAttribPointer(index, size, type, normalized, stride, offset);
+ state.offset = static_cast<GC3Dintptr>(offset);
+ m_context->vertexAttribPointer(index, size, type, normalized, stride, static_cast<GC3Dintptr>(offset));
cleanupAfterGraphicsCall(false);
}
@@ -3872,17 +3984,30 @@ void WebGLRenderingContext::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3D
cleanupAfterGraphicsCall(false);
}
-void WebGLRenderingContext::forceLostContext()
+void WebGLRenderingContext::forceLostContext(WebGLRenderingContext::LostContextMode mode)
{
if (isContextLost()) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
- m_restoreTimer.startOneShot(0);
+ loseContext();
+
+ if (mode == RealLostContext)
+ m_restoreTimer.startOneShot(0);
}
-void WebGLRenderingContext::onLostContext()
+void WebGLRenderingContext::forceRestoreContext()
+{
+ if (!isContextLost()) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
+
+ maybeRestoreContext(SyntheticLostContext);
+}
+
+void WebGLRenderingContext::loseContext()
{
m_contextLost = true;
@@ -3890,7 +4015,7 @@ void WebGLRenderingContext::onLostContext()
// There is no direct way to clear errors from a GL implementation and
// looping until getError() becomes NO_ERROR might cause an infinite loop if
- // the driver or context implementation had a bug. So, loop a reasonably
+ // the driver or context implementation had a bug. So, loop a reasonably
// large number of times to clear any existing errors.
for (int i = 0; i < 100; ++i) {
if (m_context->getError() == GraphicsContext3D::NO_ERROR)
@@ -3898,14 +4023,67 @@ void WebGLRenderingContext::onLostContext()
}
m_context->synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL);
- canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, ""));
+ RefPtr<WebGLContextEvent> event = WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, "");
+ canvas()->dispatchEvent(event);
+ m_restoreAllowed = event->defaultPrevented();
}
-void WebGLRenderingContext::restoreContext()
+void WebGLRenderingContext::maybeRestoreContext(WebGLRenderingContext::LostContextMode mode)
{
+ if (!m_contextLost) {
+ ASSERT(mode == SyntheticLostContext);
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
+
+ // The rendering context is not restored unless the default
+ // behavior of the webglcontextlost event was prevented earlier.
+ if (!m_restoreAllowed) {
+ if (mode == SyntheticLostContext)
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
+
+ int contextLostReason = m_context->getExtensions()->getGraphicsResetStatusARB();
+
+ switch (contextLostReason) {
+ case GraphicsContext3D::NO_ERROR:
+ // The GraphicsContext3D implementation might not fully
+ // support GL_ARB_robustness semantics yet. Alternatively, the
+ // WebGL WEBKIT_lose_context extension might have been used to
+ // force a lost context.
+ break;
+ case Extensions3D::GUILTY_CONTEXT_RESET_ARB:
+ // The rendering context is not restored if this context was
+ // guilty of causing the graphics reset.
+ printWarningToConsole("WARNING: WebGL content on the page caused the graphics card to reset; not restoring the context");
+ return;
+ case Extensions3D::INNOCENT_CONTEXT_RESET_ARB:
+ // Always allow the context to be restored.
+ break;
+ case Extensions3D::UNKNOWN_CONTEXT_RESET_ARB:
+ // Warn. Ideally, prompt the user telling them that WebGL
+ // content on the page might have caused the graphics card to
+ // reset and ask them whether they want to continue running
+ // the content. Only if they say "yes" should we start
+ // attempting to restore the context.
+ printWarningToConsole("WARNING: WebGL content on the page might have caused the graphics card to reset");
+ break;
+ }
+
+#if PLATFORM(ANDROID)
+ RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(canvas(), m_attributes, 0));
+#else
RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, canvas()->document()->view()->root()->hostWindow()));
- if (!context)
+#endif
+ if (!context) {
+ if (mode == RealLostContext)
+ m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
+ else
+ // This likely shouldn't happen but is the best way to report it to the WebGL app.
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
+ }
m_context = context;
m_contextLost = false;
@@ -3927,59 +4105,10 @@ void WebGLRenderingContext::addObject(WebGLObject* object)
void WebGLRenderingContext::detachAndRemoveAllObjects()
{
- HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
- for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it)
+ while (m_canvasObjects.size() > 0) {
+ HashSet<WebGLObject*>::iterator it = m_canvasObjects.begin();
(*it)->detachContext();
-
- m_canvasObjects.clear();
-}
-
-WebGLTexture* WebGLRenderingContext::findTexture(Platform3DObject obj)
-{
- if (!obj)
- return 0;
- HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
- for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
- if ((*it)->isTexture() && (*it)->object() == obj)
- return reinterpret_cast<WebGLTexture*>((*it).get());
}
- return 0;
-}
-
-WebGLRenderbuffer* WebGLRenderingContext::findRenderbuffer(Platform3DObject obj)
-{
- if (!obj)
- return 0;
- HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
- for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
- if ((*it)->isRenderbuffer() && (*it)->object() == obj)
- return reinterpret_cast<WebGLRenderbuffer*>((*it).get());
- }
- return 0;
-}
-
-WebGLBuffer* WebGLRenderingContext::findBuffer(Platform3DObject obj)
-{
- if (!obj)
- return 0;
- HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
- for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
- if ((*it)->isBuffer() && (*it)->object() == obj)
- return reinterpret_cast<WebGLBuffer*>((*it).get());
- }
- return 0;
-}
-
-WebGLShader* WebGLRenderingContext::findShader(Platform3DObject obj)
-{
- if (!obj)
- return 0;
- HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
- for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
- if ((*it)->isShader() && (*it)->object() == obj)
- return reinterpret_cast<WebGLShader*>((*it).get());
- }
- return 0;
}
WebGLGetInfo WebGLRenderingContext::getBooleanParameter(GC3Denum pname)
@@ -4198,6 +4327,16 @@ WebGLTexture* WebGLRenderingContext::validateTextureBinding(GC3Denum target, boo
return tex;
}
+bool WebGLRenderingContext::validateLocationLength(const String& string)
+{
+ const unsigned maxWebGLLocationLength = 256;
+ if (string.length() > maxWebGLLocationLength) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return false;
+ }
+ return true;
+}
+
bool WebGLRenderingContext::validateSize(GC3Dint x, GC3Dint y)
{
if (x < 0 || y < 0) {