diff options
author | Pierre-Antoine LaFayette <plafayet@codeaurora.org> | 2011-12-29 15:13:33 +0100 |
---|---|---|
committer | Steve Kondik <shade@chemlab.org> | 2013-01-20 18:38:26 -0800 |
commit | 70f026a42cf1bee061389fa6ce790ea1186f0703 (patch) | |
tree | b0de5b5676433d2382e7cf1307b54edc19fc42a5 /Source/WebCore/html/canvas/WebGLRenderingContext.cpp | |
parent | a815c626d7df7e24ba9e0df27c27735d4e069ffd (diff) | |
download | external_webkit-70f026a42cf1bee061389fa6ce790ea1186f0703.zip external_webkit-70f026a42cf1bee061389fa6ce790ea1186f0703.tar.gz external_webkit-70f026a42cf1bee061389fa6ce790ea1186f0703.tar.bz2 |
WebGL implementation for Android
Implementation of WebGL in Android WebKit. Exposes a low level 3D
graphics API based on OpenGL ES 2.0 to JavaScript. WebGL is not compiled
by default. It can be enabled by setting ENABLE_WEBGL = true in your
device BoardConfig.mk or directly in external/webkit/Android.mk.
Includes runtime enablement through Browser Settings -> Labs menu.
Enable WebGL debug logs and FPS timing with: adb shell setprop debug.webgl 1
Includes Cross-origin resource sharing support.
Includes fixes for the following Khronos WebGL 1.0.1. tests:
- premultiplyalpha-test.html
- struct-nesting-exceeds-maximum.html
- index-validation.html
- context-attributes-alpha-depth-stencil-antialias.html
- program-test.html
- object-deletion-behaviour.html
Squashed patches:
-----------------------------------------------------------
WebGL implementation for Android
Implementation of WebGL in Android WebKit. Exposes a low level 3D
graphics API based on OpenGL ES 2.0 to JavaScript. WebGL is not compiled
by default. It can be enabled by setting ENABLE_WEBGL = true in your
device BoardConfig.mk or directly in external/webkit/Android.mk. It is
also disabled by default (in WebSettings.cpp) as required by Khronos
until it reaches 100% conformance.
--
From: Anders Edenbrandt <anders.edenbrandt@sonyericsson.com>
Date: Thu, 26 Jan 2012 11:48:41 +0100
WebGL bug fixes and updates
Some updates:
- stability fixes
- image decoder
- redesign of how the FBOs are used
- other bug fixes
--
From: Anders Edenbrandt <anders.edenbrandt@sonyericsson.com>
Date: Tue, 31 Jan 2012 17:20:13 +0100
WebGL code cleanup and bug fixes
--
From: Anders Edenbrandt <anders.edenbrandt@sonyericsson.com>
Date: Thu Mar 15 10:15:33 2012 +0100
More improvements and bug fixes
Updates:
- cleaned up buffer handling, allowing for arbitrary number of buffers
- removed rect from invalidation
- removed screen update request from drawGL
- releasing buffers when the browser is paused
- added missing method 'slice' for typed arrays
- fixed bug in bindFramebuffer
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=c72ff2aa562941d94ceb51ba685d60809ca882a6
Updates to fix some test failures in Khronos Conformance Test Suite:
- Increase max identifier length in shaders to 256
- Add length check on uniforms and attributes
- Add minimal support for compressed textures
(that is, just return the correct error codes)
- Add support for Uint8ClampedByteArray
- Modify how error checking is done on framebuffer operations
- Activate the GL_OES_packed_depth_stencil extension
- Activate the GL_OES_texture_float extension
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=5bfe05848c12a2894697fbb503cfa79981eb96bd
Fix WebGL 1.0.1 premultiplyalpha-test conformance test
Fixing bug with toDataURL when called against a Canvas in which WebGL
content is being rendered and make sure paintRenderingResultsToImageData
isn't used for the premultiplied case.
ihttps://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=5834a1e00f89d898a7a0039d47916b196e40a2c8
Update ANGLE to r1009 to fix WebGL 1.0.1 conformance test
Fixes struct-nesting-exceeds-maximum Khronos WebGL conformance test.
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=ae2392db6360b41a5717f3770a9e63b1bcea45d6
vertexAttribPointer needs to reject large negative offsets
https://bugs.webkit.org/show_bug.cgi?id=85117
Reviewed by Kenneth Russell.
Source/WebCore:
* html/canvas/WebGLRenderingContext.cpp: Use long long for GLsizeiptr and GLintptr
(WebCore):
(WebCore::WebGLRenderingContext::bufferData):
(WebCore::WebGLRenderingContext::bufferSubData):
(WebCore::WebGLRenderingContext::drawElements):
(WebCore::WebGLRenderingContext::getVertexAttribOffset):
(WebCore::WebGLRenderingContext::vertexAttribPointer):
* html/canvas/WebGLRenderingContext.h: Ditto
(WebGLRenderingContext):
* html/canvas/WebGLRenderingContext.idl: Ditto
LayoutTests:
* fast/canvas/webgl/index-validation-expected.txt:
* fast/canvas/webgl/index-validation.html: Add a test case for large negative offset.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@116374 268f45cc-cd09-0410-ab3c-d52691b4dbfc
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=b3a02a0942a0e2c44d23961382145fad6016b2ef
Fix for context-attributes-alpha-depth-stencil-antialias
Support for alpha, depth and stencil to fix WebGL Khronos 1.0.1
conformance test. Report back that antialiasing is not supported on our
platform.
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=22e98195ac73e7e12a59d5b9a42dfc4e2252b475
WebGLRenderingContext should defer caching program info
https://bugs.webkit.org/show_bug.cgi?id=83513
Reviewed by Kenneth Russell.
* html/canvas/WebGLProgram.cpp:
(WebCore::WebGLProgram::WebGLProgram):
(WebCore::WebGLProgram::numActiveAttribLocations): call cacheInfoIfNeeded();
(WebCore::WebGLProgram::getActiveAttribLocation): Ditto.
(WebCore::WebGLProgram::isUsingVertexAttrib0): Ditto.
(WebCore::WebGLProgram::getLinkStatus): Ditto.
(WebCore):
(WebCore::WebGLProgram::cacheActiveAttribLocations):
(WebCore::WebGLProgram::cacheInfoIfNeeded): Cache link status, active attire locations, etc if needed.
(WebCore::WebGLProgram::increaseLinkCount): also invalidate cached info.
* html/canvas/WebGLProgram.h:
(WebGLProgram):
* html/canvas/WebGLRenderingContext.cpp:
(WebCore):
(WebCore::WebGLRenderingContext::linkProgram): Do not cache program info immediately.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@113915 268f45cc-cd09-0410-ab3c-d52691b4dbfc
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=66bc9c1b9eb5151b1b236199d0eeb17df0557b47
Runtime enablement of WebGL
Hooks up with the Java side to enable/disable WebGL through the debug
menu.
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=75aab57859de45a0aaec5a7cad41a12111e9a82e
Support the usage of CORS for WebGL and the 2D canvas
Factor CORS request preparation out of DocumentThreadableLoader
https://bugs.webkit.org/show_bug.cgi?id=61209
2011-05-20 Adam Barth <abarth@webkit.org>
Reviewed by Alexey Proskuryakov.
Factor CORS request preparation out of DocumentThreadableLoader
https://bugs.webkit.org/show_bug.cgi?id=61209
DocumentThreadableLoader has two jobs:
1) Proxy loads between threads.
2) Run the CORS state machine.
This patch begins the work of separating those concerns, allowing CORS
to be used elsewhere in the loading pipeline. In particular, this
patch moves knowledge of how to prepare CORS requests out of
DocumentThreadableLoder.
* loader/CrossOriginAccessControl.cpp:
(WebCore::isOnAccessControlSimpleRequestHeaderWhitelist):
(WebCore::updateRequestForAccessControl):
(WebCore::createAccessControlPreflightRequest):
* loader/CrossOriginAccessControl.h:
* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::DocumentThreadableLoader):
(WebCore::DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest):
(WebCore::DocumentThreadableLoader::makeCrossOriginAccessRequestWithPreflight):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@86980 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Add rel type prerender to distinguish prerender from prefetch
https://bugs.webkit.org/show_bug.cgi?id=61079
2011-05-21 Gavin Peters <gavinp@chromium.org>
Reviewed by Adam Barth.
Add rel type prerender to distinguish prerender from prefetch
https://bugs.webkit.org/show_bug.cgi?id=61079
Chrome right now uses <link rel=prefetch ...> for one of two things,
to warm the cache in the same way as firefox, or to launch a speculative
rendering of a web page, for faster "loading" when the user navigates to it.
This new rel type will let us distinguish the two cases; the rel type prerender
isn't used on the web today, but the Google Web Search example prerendering application
is ready to experiment with it.
* fast/dom/HTMLLinkElement/prerender-expected.txt: Added.
* fast/dom/HTMLLinkElement/prerender.html: Added.
* platform/gtk/Skipped:
* platform/mac/Skipped:
* platform/qt/Skipped:
* platform/win/Skipped:
2011-05-21 Gavin Peters <gavinp@chromium.org>
Reviewed by Adam Barth.
Add rel type prerender to distinguish prerender from prefetch
https://bugs.webkit.org/show_bug.cgi?id=61079
Chrome right now uses <link rel=prefetch ...> for one of two things,
to warm the cache in the same way as firefox, or to launch a speculative
rendering of a web page, for faster "loading" when the user navigates to it.
This new rel type will let us distinguish the two cases; the rel type prerender
isn't used on the web today, but the Google Web Search example prerendering application
is ready to experiment with it.
Test: fast/dom/HTMLLinkElement/prerender.html
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::tokenizeRelAttribute):
(WebCore::HTMLLinkElement::process):
* html/HTMLLinkElement.h:
(WebCore::HTMLLinkElement::RelAttribute::RelAttribute):
* loader/cache/CachedResource.cpp:
(WebCore::defaultPriorityForResourceType):
* loader/cache/CachedResource.h:
(WebCore::CachedResource::isLinkResource):
* loader/cache/CachedResourceLoader.cpp:
(WebCore::createResource):
(WebCore::CachedResourceLoader::requestLinkResource):
(WebCore::CachedResourceLoader::canRequest):
* loader/cache/CachedResourceLoader.h:
* loader/cache/CachedResourceRequest.cpp:
(WebCore::cachedResourceTypeToTargetType):
(WebCore::CachedResourceRequest::load):
* platform/network/ResourceRequestBase.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87020 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Make CachedResource take a ResourceRequest instead of just a url string.
2011-05-24 Nate Chapin <japhet@chromium.org>
Reviewed by Adam Barth.
Change CachedResources to take a ResourceRequest instead of
a url in their constructors and provide a very minimal set of
cases for avoiding reusing a CachedResource. The ResourceRequest
part of this change requires pushing responsibility
for calling Document::completeURL() to the caller, instead of
CachedResourceLoader, since ResourceRequest ASSERTs if it
is constructed with an invalid url.
https://bugs.webkit.org/show_bug.cgi?id=61318
Refactor, no new tests.
* css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::addFontFaceRule):
* css/CSSImageValue.cpp:
(WebCore::CSSImageValue::cachedImage):
* css/CSSImportRule.cpp:
(WebCore::CSSImportRule::insertedIntoParent):
* dom/ProcessingInstruction.cpp:
(WebCore::ProcessingInstruction::checkStyleSheet):
* dom/ScriptElement.cpp:
(WebCore::ScriptElement::requestScript):
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::process):
* loader/ImageLoader.cpp:
(WebCore::ImageLoader::updateFromElement):
* loader/cache/CachedCSSStyleSheet.cpp:
(WebCore::CachedCSSStyleSheet::CachedCSSStyleSheet):
(WebCore::CachedCSSStyleSheet::didAddClient):
(WebCore::CachedCSSStyleSheet::checkNotify):
* loader/cache/CachedCSSStyleSheet.h:
* loader/cache/CachedFont.cpp:
(WebCore::CachedFont::CachedFont):
* loader/cache/CachedFont.h:
* loader/cache/CachedImage.cpp:
(WebCore::CachedImage::CachedImage):
(WebCore::CachedImage::checkShouldPaintBrokenImage):
* loader/cache/CachedImage.h:
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::CachedResource):
(WebCore::reuseRequest):
(WebCore::CachedResource::allowReuseOfRequest):
(WebCore::CachedResource::removeClient):
(WebCore::CachedResource::canUseCacheValidator):
* loader/cache/CachedResource.h:
(WebCore::CachedResource::resourceRequest):
(WebCore::CachedResource::url):
* loader/cache/CachedResourceLoader.cpp:
* loader/cache/CachedResourceLoader.h:
* loader/cache/CachedResourceRequest.cpp:
(WebCore::CachedResourceRequest::load):
* loader/cache/CachedScript.cpp:
(WebCore::CachedScript::CachedScript):
* loader/cache/CachedScript.h:
* loader/cache/CachedXSLStyleSheet.cpp:
(WebCore::CachedXSLStyleSheet::CachedXSLStyleSheet):
(WebCore::CachedXSLStyleSheet::didAddClient):
(WebCore::CachedXSLStyleSheet::checkNotify):
* loader/cache/CachedXSLStyleSheet.h:
* svg/SVGFEImageElement.cpp:
(WebCore::SVGFEImageElement::requestImageResource):
* svg/SVGFontFaceUriElement.cpp:
(WebCore::SVGFontFaceUriElement::loadFont):
* xml/XSLImportRule.cpp:
(WebCore::XSLImportRule::loadSheet):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87239 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Support cross-origin property for images
2011-05-26 Adam Barth <abarth@webkit.org>
Reviewed by Eric Seidel.
Support cross-origin property for images
https://bugs.webkit.org/show_bug.cgi?id=61015
Test various cases involving CORS requests and canvas tainting.
* http/tests/security/canvas-remote-read-remote-image-allowed-expected.txt: Added.
* http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials-expected.txt: Added.
* http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials.html: Added.
* http/tests/security/canvas-remote-read-remote-image-allowed.html: Added.
* http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin-expected.txt: Added.
* http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin.html: Added.
* http/tests/security/resources/abe-allow-credentials.php: Added.
* http/tests/security/resources/abe-allow-star.php: Added.
2011-05-26 Adam Barth <abarth@webkit.org>
Reviewed by Eric Seidel.
Support cross-origin property for images
https://bugs.webkit.org/show_bug.cgi?id=61015
This patch add support for the crossorigin attribute of images and
teaches 2D canvas to respect that flag and not taint a canvas if the
image drawn on the canvas is allowed by CORS.
While I was editing this code, I couldn't resist a couple touch-up
changes.
Tests: http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials.html
http/tests/security/canvas-remote-read-remote-image-allowed.html
http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin.html
* html/HTMLAttributeNames.in:
* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::securityOrigin):
* html/HTMLCanvasElement.h:
* html/HTMLImageElement.idl:
* html/canvas/CanvasRenderingContext.cpp:
(WebCore::CanvasRenderingContext::checkOrigin):
* html/canvas/CanvasRenderingContext2D.cpp:
(WebCore::CanvasRenderingContext2D::createPattern):
* loader/ImageLoader.cpp:
(WebCore::ImageLoader::updateFromElement):
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::passesAccessControlCheck):
* loader/cache/CachedResource.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87473 268f45cc-cd09-0410-ab3c-d52691b4dbfc
HTMLVideoElement::currentSrc() should return a KURL
2011-05-27 Adam Barth <abarth@webkit.org>
Reviewed by Eric Seidel.
HTMLVideoElement::currentSrc() should return a KURL
https://bugs.webkit.org/show_bug.cgi?id=61578
I suspect we got into this mess because the author of this code didn't
know about the URL attribute in WebKit IDL, which is super useful!
Bad news: The line of code in question seems to have another bug, which
I've documented in a FIXME. Let the yak shaving continue!
* html/HTMLMediaElement.cpp:
(WebCore::urlForLogging):
(WebCore::HTMLMediaElement::loadResource):
(WebCore::HTMLMediaElement::isSafeToLoadURL):
(WebCore::HTMLMediaElement::selectNextSourceChild):
(WebCore::HTMLMediaElement::getPluginProxyParams):
* html/HTMLMediaElement.h:
(WebCore::HTMLMediaElement::currentSrc):
(WebCore::HTMLMediaElement::currentURL):
* html/canvas/CanvasRenderingContext.cpp:
(WebCore::CanvasRenderingContext::checkOrigin):
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::absoluteMediaURL):
- This complete URL call was unnecessary because currentSrc is
already absolute.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87539 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Disallow use of cross-domain media (images, video) in WebGL
2011-06-09 Kenneth Russell <kbr@google.com>
Reviewed by Adam Barth.
Disallow use of cross-domain media (images, video) in WebGL
https://bugs.webkit.org/show_bug.cgi?id=62257
Updated WebGL implementation to track recent spec updates in this area.
Tests: http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html
http/tests/security/webgl-remote-read-remote-image-allowed.html
http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin.html
* html/canvas/CanvasRenderingContext.cpp:
(WebCore::CanvasRenderingContext::wouldTaintOrigin):
(WebCore::CanvasRenderingContext::checkOrigin):
* html/canvas/CanvasRenderingContext.h:
(WebCore::CanvasRenderingContext::checkOrigin):
* html/canvas/WebGLRenderingContext.cpp:
(WebCore::WebGLRenderingContext::readPixels):
(WebCore::WebGLRenderingContext::texImage2D):
(WebCore::WebGLRenderingContext::videoFrameToImage):
(WebCore::WebGLRenderingContext::texSubImage2D):
* html/canvas/WebGLRenderingContext.h:
2011-06-09 Kenneth Russell <kbr@google.com>
Reviewed by Adam Barth.
Disallow use of cross-domain media (images, video) in WebGL
https://bugs.webkit.org/show_bug.cgi?id=62257
Updated origin-clean-conformance.html to track upstream version in
Khronos repository. Added new layout tests mirroring those added
in bug 61015 which verify that new CORS support for images is
working in the context of WebGL.
Verified new tests in WebKit and Chromium. Skipped tests on
platforms where WebGL is disabled.
* http/tests/canvas/webgl/origin-clean-conformance-expected.txt:
* http/tests/canvas/webgl/origin-clean-conformance.html:
* http/tests/security/webgl-remote-read-remote-image-allowed-expected.txt: Added.
* http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials-expected.txt: Added.
* http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html: Added.
* http/tests/security/webgl-remote-read-remote-image-allowed.html: Added.
* http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin-expected.txt: Added.
* http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin.html: Added.
* platform/gtk/Skipped:
* platform/mac-leopard/Skipped:
* platform/mac-wk2/Skipped:
* platform/qt/Skipped:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@88489 268f45cc-cd09-0410-ab3c-d52691b4dbfc
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=0ddd7c1d91c08fbee6c99b79fa9971a7ac914384
Runtime enablement of WebGL logs
Allows enabling WebGL method level logging using:
adb shell setprop debug.webgl 1
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=307d4a2b5b20f2609497ceaea1eca2e29a8a781f
Adding WebGL FPS timing to logs
Samples WebGL average FPS every 15 frames and outputs to WebGL debug log.
TODO: Add setting to browser debug settings that overlays FPS on web
pages.
Postpone deleteRenderbuffer/deleteTexture until all framebuffer attachment points are removed.
https://bugs.webkit.org/show_bug.cgi?id=74741
Reviewed by Kenneth Russell.
Source/WebCore:
Use WebGLObject's attachment count mechanism to track if a renderbuffer/texture
is still attached to framebuffers, and if its deletion should be delated or not.
* html/canvas/WebGLFramebuffer.cpp:
(WebCore::WebGLFramebuffer::setAttachmentForBoundFramebuffer):
(WebCore::WebGLFramebuffer::getAttachment):
(WebCore::WebGLFramebuffer::removeAttachmentFromBoundFramebuffer):
(WebCore::WebGLFramebuffer::deleteObjectImpl):
(WebCore::WebGLFramebuffer::isBound):
* html/canvas/WebGLFramebuffer.h:
LayoutTests:
* fast/canvas/webgl/object-deletion-behaviour-expected.txt:
* fast/canvas/webgl/object-deletion-behaviour.html: synced with khronos side.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@103272 268f45cc-cd09-0410-ab3c-d52691b4dbfc
https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=9def386340c74f2a745fb041b1cb11daa30d1a82
-----------------------------------------------------------
(cherry-picked from commit 6d9d732ff06a6b265d02b18d7034068a68ef0fde)
Conflicts:
Android.mk
Source/WebCore/ChangeLog
Change-Id: I3bbf993fe5a3d6cea53e019c8fa3912ecd2bd429
Diffstat (limited to 'Source/WebCore/html/canvas/WebGLRenderingContext.cpp')
-rw-r--r-- | Source/WebCore/html/canvas/WebGLRenderingContext.cpp | 434 |
1 files changed, 320 insertions, 114 deletions
diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp index 933d37f..30a88fa 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); } @@ -1894,6 +1954,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 +1976,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); @@ -1990,35 +2058,50 @@ WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum t 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 +2145,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 +2641,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 +2688,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 +2732,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 +2813,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 +2863,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 +2921,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 +3256,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 +3275,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 +3288,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 +3300,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 +3316,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 +3458,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 +3476,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 +3495,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 +3929,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 +3963,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 +3979,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 +4002,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::forceRestoreContext() +{ + if (!isContextLost()) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return; + } + + maybeRestoreContext(SyntheticLostContext); } -void WebGLRenderingContext::onLostContext() +void WebGLRenderingContext::loseContext() { m_contextLost = true; @@ -3890,7 +4033,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 +4041,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; @@ -4198,6 +4394,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) { |