summaryrefslogtreecommitdiffstats
path: root/android_webview/native
diff options
context:
space:
mode:
authorleandrogracia@chromium.org <leandrogracia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-15 21:45:52 +0000
committerleandrogracia@chromium.org <leandrogracia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-15 21:45:52 +0000
commitf35e232a94af088f5a1a231f2489a5b06460bffe (patch)
tree124388157fbe8e64db6181a9b5467a3ca3fc8be0 /android_webview/native
parent3ff3a45baf225760a1ceab36868e333010f555ee (diff)
downloadchromium_src-f35e232a94af088f5a1a231f2489a5b06460bffe.zip
chromium_src-f35e232a94af088f5a1a231f2489a5b06460bffe.tar.gz
chromium_src-f35e232a94af088f5a1a231f2489a5b06460bffe.tar.bz2
[Android WebView] Tie together Chrome's browser compositor with the Android View system.
This patch introduces a new feature to the compositor: - A setting to enable cleaning the framebuffer, disabled by default. This prevents destroying data below us when rendering non-rectangular views (e.g. during a rotation). A second required feature will be added by a later patch: - A device scissor rect that intersects any scissor calculation. Used to ensure we never render outside where the Android View System tells us. There are also some issues with the Android View side regarding the restoration of the GL state. This patch introduces a temporary workaround by reading and manually restoring the state changed by the compositor. This will go out as soon as the problem is fixed in the Android side. BUG=161409,154180 Review URL: https://chromiumcodereview.appspot.com/11316310 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173324 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview/native')
-rw-r--r--android_webview/native/DEPS1
-rw-r--r--android_webview/native/aw_contents.cc231
-rw-r--r--android_webview/native/aw_contents.h14
-rw-r--r--android_webview/native/webview_native.gyp1
4 files changed, 224 insertions, 23 deletions
diff --git a/android_webview/native/DEPS b/android_webview/native/DEPS
index 04c6a9d..4f94198 100644
--- a/android_webview/native/DEPS
+++ b/android_webview/native/DEPS
@@ -2,4 +2,5 @@ include_rules = [
"+cc",
"+content/public/browser",
"+ui/gfx",
+ "+ui/gl",
]
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 7cbcbc9..74edfa1 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -18,6 +18,7 @@
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/debug/trace_event.h"
#include "base/message_loop.h"
#include "base/pickle.h"
#include "base/supports_user_data.h"
@@ -33,6 +34,18 @@
#include "jni/AwContents_jni.h"
#include "net/base/x509_certificate.h"
#include "ui/gfx/transform.h"
+#include "ui/gl/gl_bindings.h"
+
+// TODO(leandrogracia): remove when crbug.com/164140 is closed.
+// Borrowed from gl2ext.h. Cannot be included due to conflicts with
+// gl_bindings.h and the EGL library methods (eglGetCurrentContext).
+#ifndef GL_TEXTURE_EXTERNAL_OES
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#endif
+
+#ifndef GL_TEXTURE_BINDING_EXTERNAL_OES
+#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
+#endif
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF16;
@@ -109,6 +122,7 @@ class NullCompositor : public content::Compositor {
virtual void DeleteTexture(WebKit::WebGLId texture_id) OVERRIDE {}
virtual void CopyTextureToBitmap(WebKit::WebGLId texture_id,
gfx::JavaBitmap& bitmap) OVERRIDE {}
+ virtual void SetHasTransparentBackground(bool flag) OVERRIDE {}
};
} // namespace
@@ -127,7 +141,8 @@ AwContents::AwContents(JNIEnv* env,
new AwWebContentsDelegate(env, web_contents_delegate)),
view_visible_(false),
compositor_visible_(false),
- is_composite_pending_(false) {
+ is_composite_pending_(false),
+ last_frame_context_(NULL) {
android_webview::AwBrowserDependencyFactory* dependency_factory =
android_webview::AwBrowserDependencyFactory::GetInstance();
@@ -137,6 +152,17 @@ AwContents::AwContents(JNIEnv* env,
SetWebContents(dependency_factory->CreateWebContents(private_browsing));
}
+void AwContents::ResetCompositor() {
+ if (UseCompositorDirectDraw()) {
+ compositor_.reset(content::Compositor::Create(this));
+ if (webview_layer_.get())
+ AttachWebViewLayer();
+ } else {
+ LOG(WARNING) << "Running on unsupported device: using null Compositor";
+ compositor_.reset(new NullCompositor);
+ }
+}
+
void AwContents::SetWebContents(content::WebContents* web_contents) {
web_contents_.reset(web_contents);
web_contents_->SetUserData(kAwContentsUserDataKey,
@@ -144,12 +170,7 @@ void AwContents::SetWebContents(content::WebContents* web_contents) {
web_contents_->SetDelegate(web_contents_delegate_.get());
render_view_host_ext_.reset(new AwRenderViewHostExt(web_contents_.get()));
- if (UseCompositorDirectDraw()) {
- compositor_.reset(content::Compositor::Create(this));
- } else {
- LOG(WARNING) << "Running on unsupported device: using null Compositor";
- compositor_.reset(new NullCompositor);
- }
+ ResetCompositor();
}
void AwContents::SetWebContents(JNIEnv* env, jobject obj, jint new_wc) {
@@ -164,24 +185,178 @@ AwContents::~AwContents() {
}
void AwContents::DrawGL(AwDrawGLInfo* draw_info) {
- // TODO(joth): Use the |draw_info| parameters.
- DLOG(INFO) << "Unimplemented AwContents::DrawGL params"
- << " clip_left=" << draw_info->clip_left
- << " clip_top=" << draw_info->clip_top
- << " clip_right=" << draw_info->clip_right
- << " clip_bottom=" << draw_info->clip_bottom;
- if (compositor_visible_ != view_visible_) {
- compositor_visible_ = view_visible_;
- compositor_->SetVisible(compositor_visible_);
- }
- if (!compositor_visible_ || draw_info->mode == AwDrawGLInfo::kModeProcess)
+ TRACE_EVENT0("AwContents", "AwContents::DrawGL");
+
+ if (!webview_layer_.get() || draw_info->mode == AwDrawGLInfo::kModeProcess)
return;
DCHECK_EQ(draw_info->mode, AwDrawGLInfo::kModeDraw);
+ SetCompositorVisibility(view_visible_);
+ if (!compositor_visible_)
+ return;
+
+ // TODO(leandrogracia): remove when crbug.com/164140 is closed.
+ // ---------------------------------------------------------------------------
+ GLint texture_external_oes_binding;
+ glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_external_oes_binding);
+
+ GLint vertex_array_buffer_binding;
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vertex_array_buffer_binding);
+
+ GLint index_array_buffer_binding;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &index_array_buffer_binding);
+
+ GLint pack_alignment;
+ glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment);
+
+ GLint unpack_alignment;
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
+
+ struct {
+ GLint enabled;
+ GLint size;
+ GLint type;
+ GLint normalized;
+ GLint stride;
+ GLvoid* pointer;
+ } vertex_attrib[3];
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib); ++i) {
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED,
+ &vertex_attrib[i].enabled);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE,
+ &vertex_attrib[i].size);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE,
+ &vertex_attrib[i].type);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
+ &vertex_attrib[i].normalized);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE,
+ &vertex_attrib[i].stride);
+ glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER,
+ &vertex_attrib[i].pointer);
+ }
+
+ GLboolean depth_test;
+ glGetBooleanv(GL_DEPTH_TEST, &depth_test);
+
+ GLboolean cull_face;
+ glGetBooleanv(GL_CULL_FACE, &cull_face);
+
+ GLboolean color_mask[4];
+ glGetBooleanv(GL_COLOR_WRITEMASK, color_mask);
+
+ GLboolean blend_enabled;
+ glGetBooleanv(GL_BLEND, &blend_enabled);
+
+ GLint blend_src_rgb;
+ glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb);
+
+ GLint blend_src_alpha;
+ glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha);
+
+ GLint blend_dest_rgb;
+ glGetIntegerv(GL_BLEND_DST_RGB, &blend_dest_rgb);
+
+ GLint blend_dest_alpha;
+ glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dest_alpha);
+
+ GLint active_texture;
+ glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
+
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+
+ GLboolean scissor_test;
+ glGetBooleanv(GL_SCISSOR_TEST, &scissor_test);
+
+ GLint scissor_box[4];
+ glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
+
+ GLint current_program;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &current_program);
+ // ---------------------------------------------------------------------------
+
+ // We need to watch if the current Android context has changed and enforce
+ // a clean-up in the compositor.
+ EGLContext current_context = eglGetCurrentContext();
+ if (!current_context) {
+ LOG(WARNING) << "No current context attached. Skipping composite.";
+ return;
+ }
+
+ if (last_frame_context_ != current_context) {
+ if (last_frame_context_)
+ ResetCompositor();
+ last_frame_context_ = current_context;
+ }
+
+ compositor_->SetWindowBounds(gfx::Size(draw_info->width, draw_info->height));
+ compositor_->SetHasTransparentBackground(!draw_info->is_layer);
+
+ gfx::Transform transform;
+ transform.matrix().setColMajorf(draw_info->transform);
+ webview_layer_->setTransform(transform);
+
compositor_->Composite();
is_composite_pending_ = false;
+
+ // TODO(leandrogracia): remove when crbug.com/164140 is closed.
+ // ---------------------------------------------------------------------------
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_external_oes_binding);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_array_buffer_binding);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_buffer_binding);
+
+ glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib); ++i) {
+ glVertexAttribPointer(i, vertex_attrib[i].size,
+ vertex_attrib[i].type, vertex_attrib[i].normalized,
+ vertex_attrib[i].stride, vertex_attrib[i].pointer);
+
+ if (vertex_attrib[i].enabled)
+ glEnableVertexAttribArray(i);
+ else
+ glDisableVertexAttribArray(i);
+ }
+
+ if (depth_test)
+ glEnable(GL_DEPTH_TEST);
+ else
+ glDisable(GL_DEPTH_TEST);
+
+ if (cull_face)
+ glEnable(GL_CULL_FACE);
+ else
+ glDisable(GL_CULL_FACE);
+
+ glColorMask(color_mask[0], color_mask[1], color_mask[2],
+ color_mask[3]);
+
+ if (blend_enabled)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+
+ glBlendFuncSeparate(blend_src_rgb, blend_dest_rgb,
+ blend_src_alpha, blend_dest_alpha);
+
+ glActiveTexture(active_texture);
+
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+ if (scissor_test)
+ glEnable(GL_SCISSOR_TEST);
+ else
+ glDisable(GL_SCISSOR_TEST);
+
+ glScissor(scissor_box[0], scissor_box[1], scissor_box[2],
+ scissor_box[3]);
+
+ glUseProgram(current_program);
+ // ---------------------------------------------------------------------------
}
jint AwContents::GetWebContents(JNIEnv* env, jobject obj) {
@@ -192,7 +367,14 @@ void AwContents::DidInitializeContentViewCore(JNIEnv* env, jobject obj,
jint content_view_core) {
ContentViewCore* core = reinterpret_cast<ContentViewCore*>(content_view_core);
DCHECK(core == ContentViewCore::FromWebContents(web_contents_.get()));
- compositor_->SetRootLayer(core->GetLayer());
+ webview_layer_ = cc::Layer::create();
+ webview_layer_->addChild(core->GetLayer());
+ AttachWebViewLayer();
+}
+
+void AwContents::AttachWebViewLayer() {
+ DCHECK(webview_layer_.get());
+ compositor_->SetRootLayer(webview_layer_.get());
Invalidate();
}
@@ -403,7 +585,7 @@ void AwContents::OnFindResultReceived(int active_ordinal,
}
void AwContents::ScheduleComposite() {
- // TODO(joth): Call back out to framework attachFunctor (Java side) from here.
+ TRACE_EVENT0("AwContents", "AwContents::ScheduleComposite");
Invalidate();
}
@@ -421,6 +603,13 @@ void AwContents::Invalidate() {
Java_AwContents_invalidate(env, obj.obj());
}
+void AwContents::SetCompositorVisibility(bool visible) {
+ if (compositor_visible_ != visible) {
+ compositor_visible_ = visible;
+ compositor_->SetVisible(compositor_visible_);
+ }
+}
+
void AwContents::OnSwapBuffersCompleted() {
}
@@ -505,7 +694,7 @@ void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) {
void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) {
view_visible_ = false;
- // TODO(joth): Request a DrawGL (kModeProcess) call, to tell the compositor.
+ SetCompositorVisibility(false);
}
base::android::ScopedJavaLocalRef<jbyteArray>
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 6a542c9..410f5d5 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -16,6 +16,7 @@
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/javascript_dialogs.h"
+typedef void* EGLContext;
class TabContents;
namespace cc {
@@ -121,18 +122,27 @@ class AwContents : public FindHelper::Listener,
private:
void Invalidate();
void SetWebContents(content::WebContents* web_contents);
+ void SetCompositorVisibility(bool visible);
+ void ResetCompositor();
+ void AttachWebViewLayer();
JavaObjectWeakGlobalRef java_ref_;
scoped_ptr<content::WebContents> web_contents_;
scoped_ptr<AwWebContentsDelegate> web_contents_delegate_;
scoped_ptr<AwRenderViewHostExt> render_view_host_ext_;
scoped_ptr<FindHelper> find_helper_;
+ scoped_ptr<content::WebContents> pending_contents_;
+
+ // Compositor-specific state.
scoped_ptr<content::Compositor> compositor_;
- // State to track if the view is visible, and if the compositor knows yet.
+ scoped_refptr<cc::Layer> webview_layer_;
bool view_visible_;
bool compositor_visible_;
bool is_composite_pending_;
- scoped_ptr<content::WebContents> pending_contents_;
+
+ // Used only for detecting Android View System context changes.
+ // Not to be used between draw calls.
+ EGLContext last_frame_context_;
DISALLOW_COPY_AND_ASSIGN(AwContents);
};
diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp
index 865b870..a4b62f6 100644
--- a/android_webview/native/webview_native.gyp
+++ b/android_webview/native/webview_native.gyp
@@ -13,6 +13,7 @@
'../../base/base.gyp:base_static',
'../../content/content.gyp:web_contents_delegate_android',
'../../skia/skia.gyp:skia',
+ '../../ui/gl/gl.gyp:gl',
'android_webview_native_jni',
],
'include_dirs': [