Index: third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
index 81cd3abc1cd0eca2654cb88649430961c3f67a18..43cecb80cf7d1dea7439344d236cedbc0d454db0 100644 |
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp |
@@ -873,6 +873,7 @@ WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCa |
, m_dispatchContextLostEventTimer(this, &WebGLRenderingContextBase::dispatchContextLostEvent) |
, m_restoreAllowed(false) |
, m_restoreTimer(this, &WebGLRenderingContextBase::maybeRestoreContext) |
+ , m_preservedDefaultVAOObjectWrapper(false) |
, m_generatedImageCache(4) |
, m_requestedAttributes(requestedAttributes) |
, m_synthesizedErrorsToConsole(true) |
@@ -993,6 +994,12 @@ void WebGLRenderingContextBase::initializeNewContext() |
m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectBase::VaoTypeDefault); |
} |
addContextObject(m_defaultVertexArrayObject.get()); |
+ // It's not convenient or necessary to pass a ScriptState this far down; while one is available |
+ // during WebGLRenderingContext construction, the wrapper for the context itself hasn't been |
+ // created yet. It's simpler to instead lazily instantiate and preserve the JavaScript wrapper |
+ // for the default VAO. (This object is never exposed to JavaScript, but we need to link other |
+ // JavaScript wrappers to it.) |
+ m_preservedDefaultVAOObjectWrapper = false; |
m_boundVertexArrayObject = m_defaultVertexArrayObject; |
m_vertexAttribValue.resize(m_maxVertexAttribs); |
@@ -1364,7 +1371,7 @@ void WebGLRenderingContextBase::activeTexture(GLenum texture) |
} |
-void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader) |
+void WebGLRenderingContextBase::attachShader(ScriptState* scriptState, WebGLProgram* program, WebGLShader* shader) |
{ |
if (isContextLost() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader)) |
return; |
@@ -1374,6 +1381,7 @@ void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* |
} |
webContext()->attachShader(objectOrZero(program), objectOrZero(shader)); |
shader->onAttached(); |
+ preserveObjectWrapper(scriptState, program, "shader", shader->type(), shader); |
} |
void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GLuint index, const String& name) |
@@ -1437,7 +1445,7 @@ bool WebGLRenderingContextBase::validateAndUpdateBufferBindTarget(const char* fu |
return true; |
} |
-void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer) |
+void WebGLRenderingContextBase::bindBuffer(ScriptState* scriptState, GLenum target, WebGLBuffer* buffer) |
{ |
bool deleted; |
if (!checkObjectToBeBound("bindBuffer", buffer, deleted)) |
@@ -1448,9 +1456,11 @@ void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer) |
return; |
webContext()->bindBuffer(target, objectOrZero(buffer)); |
+ preserveObjectWrapper(scriptState, this, "buffer", target, buffer); |
+ maybePreserveDefaultVAOObjectWrapper(scriptState); |
} |
-void WebGLRenderingContextBase::bindFramebuffer(GLenum target, WebGLFramebuffer* buffer) |
+void WebGLRenderingContextBase::bindFramebuffer(ScriptState* scriptState, GLenum target, WebGLFramebuffer* buffer) |
{ |
bool deleted; |
if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted)) |
@@ -1465,9 +1475,13 @@ void WebGLRenderingContextBase::bindFramebuffer(GLenum target, WebGLFramebuffer* |
} |
setFramebuffer(target, buffer); |
+ // This is called both internally and externally (from JavaScript). We only update which wrapper |
+ // is preserved when it's called from JavaScript. |
+ if (scriptState) |
+ preserveObjectWrapper(scriptState, this, "framebuffer", 0, buffer); |
} |
-void WebGLRenderingContextBase::bindRenderbuffer(GLenum target, WebGLRenderbuffer* renderBuffer) |
+void WebGLRenderingContextBase::bindRenderbuffer(ScriptState* scriptState, GLenum target, WebGLRenderbuffer* renderBuffer) |
{ |
bool deleted; |
if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted)) |
@@ -1480,11 +1494,12 @@ void WebGLRenderingContextBase::bindRenderbuffer(GLenum target, WebGLRenderbuffe |
} |
m_renderbufferBinding = renderBuffer; |
webContext()->bindRenderbuffer(target, objectOrZero(renderBuffer)); |
+ preserveObjectWrapper(scriptState, this, "renderbuffer", 0, renderBuffer); |
if (renderBuffer) |
renderBuffer->setHasEverBeenBound(); |
} |
-void WebGLRenderingContextBase::bindTexture(GLenum target, WebGLTexture* texture) |
+void WebGLRenderingContextBase::bindTexture(ScriptState* scriptState, GLenum target, WebGLTexture* texture) |
{ |
bool deleted; |
if (!checkObjectToBeBound("bindTexture", texture, deleted)) |
@@ -1495,23 +1510,34 @@ void WebGLRenderingContextBase::bindTexture(GLenum target, WebGLTexture* texture |
synthesizeGLError(GL_INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets"); |
return; |
} |
+ |
+ const char* bindingPointName = nullptr; |
if (target == GL_TEXTURE_2D) { |
m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture; |
if (!m_activeTextureUnit) |
drawingBuffer()->setTexture2DBinding(objectOrZero(texture)); |
+ bindingPointName = "texture_2d"; |
} else if (target == GL_TEXTURE_CUBE_MAP) { |
m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture; |
+ bindingPointName = "texture_cube_map"; |
} else if (isWebGL2OrHigher() && target == GL_TEXTURE_2D_ARRAY) { |
m_textureUnits[m_activeTextureUnit].m_texture2DArrayBinding = texture; |
+ bindingPointName = "texture_2d_array"; |
} else if (isWebGL2OrHigher() && target == GL_TEXTURE_3D) { |
m_textureUnits[m_activeTextureUnit].m_texture3DBinding = texture; |
+ bindingPointName = "texture_3d"; |
} else { |
synthesizeGLError(GL_INVALID_ENUM, "bindTexture", "invalid target"); |
return; |
} |
webContext()->bindTexture(target, objectOrZero(texture)); |
+ // This is called both internally and externally (from JavaScript). We only update which wrapper |
+ // is preserved when it's called from JavaScript. |
+ if (scriptState) { |
+ preserveObjectWrapper(scriptState, this, bindingPointName, m_activeTextureUnit, texture); |
+ } |
if (texture) { |
texture->setTarget(target, getMaxTextureLevelForTarget(target)); |
m_onePlusMaxNonDefaultTextureUnit = max(m_activeTextureUnit + 1, m_onePlusMaxNonDefaultTextureUnit); |
@@ -1945,6 +1971,16 @@ WebGLRenderbuffer* WebGLRenderingContextBase::ensureEmulatedStencilBuffer(GLenum |
return renderbuffer->emulatedStencilBuffer(); |
} |
+void WebGLRenderingContextBase::setBoundVertexArrayObject(ScriptState* scriptState, WebGLVertexArrayObjectBase* arrayObject) |
+{ |
+ if (arrayObject) |
+ m_boundVertexArrayObject = arrayObject; |
+ else |
+ m_boundVertexArrayObject = m_defaultVertexArrayObject; |
+ |
+ preserveObjectWrapper(scriptState, this, "boundvao", 0, arrayObject); |
+} |
+ |
WebGLShader* WebGLRenderingContextBase::createShader(GLenum type) |
{ |
if (isContextLost()) |
@@ -2101,7 +2137,7 @@ void WebGLRenderingContextBase::depthRange(GLfloat zNear, GLfloat zFar) |
webContext()->depthRange(zNear, zFar); |
} |
-void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader) |
+void WebGLRenderingContextBase::detachShader(ScriptState* scriptState, WebGLProgram* program, WebGLShader* shader) |
{ |
if (isContextLost() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader)) |
return; |
@@ -2111,6 +2147,7 @@ void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* |
} |
webContext()->detachShader(objectOrZero(program), objectOrZero(shader)); |
shader->onDetached(webContext()); |
+ preserveObjectWrapper(scriptState, program, "shader", shader->type(), nullptr); |
} |
void WebGLRenderingContextBase::disable(GLenum cap) |
@@ -2270,7 +2307,7 @@ void WebGLRenderingContextBase::flush() |
webContext()->flush(); |
} |
-void WebGLRenderingContextBase::framebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, WebGLRenderbuffer* buffer) |
+void WebGLRenderingContextBase::framebufferRenderbuffer(ScriptState* scriptState, GLenum target, GLenum attachment, GLenum renderbuffertarget, WebGLRenderbuffer* buffer) |
{ |
if (isContextLost() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment)) |
return; |
@@ -2318,9 +2355,10 @@ void WebGLRenderingContextBase::framebufferRenderbuffer(GLenum target, GLenum at |
framebufferBinding->setAttachmentForBoundFramebuffer(target, attachment, buffer); |
} |
applyStencilTest(); |
+ preserveObjectWrapper(scriptState, framebufferBinding, "renderbuffer", attachment, buffer); |
} |
-void WebGLRenderingContextBase::framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, WebGLTexture* texture, GLint level) |
+void WebGLRenderingContextBase::framebufferTexture2D(ScriptState* scriptState, GLenum target, GLenum attachment, GLenum textarget, WebGLTexture* texture, GLint level) |
{ |
if (isContextLost() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment)) |
return; |
@@ -2360,6 +2398,7 @@ void WebGLRenderingContextBase::framebufferTexture2D(GLenum target, GLenum attac |
} |
framebufferBinding->setAttachmentForBoundFramebuffer(target, attachment, textarget, texture, level); |
applyStencilTest(); |
+ preserveObjectWrapper(scriptState, framebufferBinding, "texture2d", attachment, texture); |
} |
void WebGLRenderingContextBase::frontFace(GLenum mode) |
@@ -2564,6 +2603,7 @@ bool WebGLRenderingContextBase::extensionSupportedAndAllowed(const ExtensionTrac |
ScriptValue WebGLRenderingContextBase::getExtension(ScriptState* scriptState, const String& name) |
{ |
WebGLExtension* extension = nullptr; |
+ bool linkContextToExtension = false; |
if (!isContextLost()) { |
for (size_t i = 0; i < m_extensions.size(); ++i) { |
@@ -2571,15 +2611,27 @@ ScriptValue WebGLRenderingContextBase::getExtension(ScriptState* scriptState, co |
if (tracker->matchesNameWithPrefixes(name)) { |
if (extensionSupportedAndAllowed(tracker)) { |
extension = tracker->getExtension(this); |
- if (extension) |
- m_extensionEnabled[extension->name()] = true; |
+ if (extension) { |
+ if (!m_extensionEnabled[extension->name()]) { |
+ linkContextToExtension = true; |
+ m_extensionEnabled[extension->name()] = true; |
+ } |
+ } |
} |
break; |
} |
} |
} |
- return ScriptValue(scriptState, toV8(extension, scriptState->context()->Global(), scriptState->isolate())); |
+ v8::Local<v8::Value> wrappedExtension = toV8(extension, scriptState->context()->Global(), scriptState->isolate()); |
+ |
+ if (linkContextToExtension) { |
+ // Keep the extension's JavaScript wrapper alive as long as the context is alive, so that |
+ // expando properties that are added to the extension persist. |
+ preserveObjectWrapper(scriptState, this, "extension", static_cast<unsigned long>(extension->name()), extension); |
+ } |
+ |
+ return ScriptValue(scriptState, wrappedExtension); |
} |
ScriptValue WebGLRenderingContextBase::getFramebufferAttachmentParameter(ScriptState* scriptState, GLenum target, GLenum attachment, GLenum pname) |
@@ -4857,7 +4909,7 @@ void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* loc |
webContext()->uniformMatrix4fv(location->location(), v.size() >> 4, transpose, v.data()); |
} |
-void WebGLRenderingContextBase::useProgram(WebGLProgram* program) |
+void WebGLRenderingContextBase::useProgram(ScriptState* scriptState, WebGLProgram* program) |
{ |
bool deleted; |
if (!checkObjectToBeBound("useProgram", program, deleted)) |
@@ -4875,6 +4927,7 @@ void WebGLRenderingContextBase::useProgram(WebGLProgram* program) |
webContext()->useProgram(objectOrZero(program)); |
if (program) |
program->onAttached(); |
+ preserveObjectWrapper(scriptState, this, "program", 0, program); |
} |
} |
@@ -4945,7 +4998,7 @@ void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index, const Vector<GLflo |
vertexAttribfvImpl("vertexAttrib4fv", index, v.data(), v.size(), 4); |
} |
-void WebGLRenderingContextBase::vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, long long offset) |
+void WebGLRenderingContextBase::vertexAttribPointer(ScriptState* scriptState, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, long long offset) |
{ |
if (isContextLost()) |
return; |
@@ -4984,6 +5037,8 @@ void WebGLRenderingContextBase::vertexAttribPointer(GLuint index, GLint size, GL |
m_boundVertexArrayObject->setVertexAttribState(index, bytesPerElement, size, type, normalized, stride, static_cast<GLintptr>(offset), m_boundArrayBuffer); |
webContext()->vertexAttribPointer(index, size, type, normalized, stride, static_cast<GLintptr>(offset)); |
+ maybePreserveDefaultVAOObjectWrapper(scriptState); |
+ preserveObjectWrapper(scriptState, m_boundVertexArrayObject, "arraybuffer", index, m_boundArrayBuffer); |
} |
void WebGLRenderingContextBase::vertexAttribDivisorANGLE(GLuint index, GLuint divisor) |
@@ -6646,12 +6701,12 @@ void WebGLRenderingContextBase::setFramebuffer(GLenum target, WebGLFramebuffer* |
void WebGLRenderingContextBase::restoreCurrentFramebuffer() |
{ |
- bindFramebuffer(GL_FRAMEBUFFER, m_framebufferBinding.get()); |
+ bindFramebuffer(nullptr, GL_FRAMEBUFFER, m_framebufferBinding.get()); |
} |
void WebGLRenderingContextBase::restoreCurrentTexture2D() |
{ |
- bindTexture(GL_TEXTURE_2D, m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()); |
+ bindTexture(nullptr, GL_TEXTURE_2D, m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()); |
} |
void WebGLRenderingContextBase::multisamplingChanged(bool enabled) |
@@ -6676,6 +6731,52 @@ void WebGLRenderingContextBase::findNewMaxNonDefaultTextureUnit() |
m_onePlusMaxNonDefaultTextureUnit = 0; |
} |
+void WebGLRenderingContextBase::preserveObjectWrapper(ScriptState* scriptState, ScriptWrappable* sourceObject, const char* baseName, unsigned long index, ScriptWrappable* targetObject) |
+{ |
+ ASSERT(scriptState); |
+ |
+ v8::Local<v8::Value> value; |
+ v8::Isolate* isolate = scriptState->isolate(); |
+ |
+ // TODO (kbr): move this logic to V8HiddenValue. The difficulty in doing so is that the index |
+ // may vary, so it'd be necessary to lazily instantiate the V8 internalized strings, and have |
+ // efficient lookup for already-created ones. |
+ StringBuilder builder; |
+ builder.append(baseName); |
+ builder.appendNumber(static_cast<unsigned>(index)); |
+ CString name = builder.toString().utf8(); |
+ v8::Local<v8::String> jsName = v8::String::NewFromUtf8( |
+ isolate, |
+ name.data(), |
+ v8::NewStringType::kNormal, |
+ name.length()).ToLocalChecked(); |
+ if (targetObject) { |
+ V8HiddenValue::setHiddenValue( |
+ isolate, |
+ sourceObject->newLocalWrapper(isolate), |
+ jsName, |
+ targetObject->newLocalWrapper(isolate)); |
+ } else { |
+ V8HiddenValue::deleteHiddenValue( |
+ isolate, |
+ sourceObject->newLocalWrapper(isolate), |
+ jsName); |
+ } |
+} |
+ |
+void WebGLRenderingContextBase::maybePreserveDefaultVAOObjectWrapper(ScriptState* scriptState) |
+{ |
+ ASSERT(scriptState); |
+ |
+ if (!m_preservedDefaultVAOObjectWrapper) { |
+ // The default VAO does not have a JavaScript wrapper created for it, but one is needed to |
+ // link up the WebGLBuffers associated with the vertex attributes. |
+ toV8(m_defaultVertexArrayObject, scriptState->context()->Global(), scriptState->isolate()); |
+ preserveObjectWrapper(scriptState, this, "defaultvao", 0, m_defaultVertexArrayObject); |
+ m_preservedDefaultVAOObjectWrapper = true; |
+ } |
+} |
+ |
DEFINE_TRACE(WebGLRenderingContextBase::TextureUnitState) |
{ |
visitor->trace(m_texture2DBinding); |