diff options
author | leandrogracia@chromium.org <leandrogracia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-15 15:47:22 +0000 |
---|---|---|
committer | leandrogracia@chromium.org <leandrogracia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-15 15:47:22 +0000 |
commit | ee01711d4e8721a6f1df0179475eac506331a13f (patch) | |
tree | 42cc3cbe94d18d098f6cc6e896d152f3135317df /android_webview | |
parent | 1597b71e45ad1438d3b399d3297c8515b3015e56 (diff) | |
download | chromium_src-ee01711d4e8721a6f1df0179475eac506331a13f.zip chromium_src-ee01711d4e8721a6f1df0179475eac506331a13f.tar.gz chromium_src-ee01711d4e8721a6f1df0179475eac506331a13f.tar.bz2 |
[Android WebView] Migrate the rendering code to a separate set of classes.
It takes from https://codereview.chromium.org/11823027/
and assumes SW rendering and Capture Picture to be ready and enabled.
Most changes just move around code. The major structural changes are:
- Introduce a browser-layer view renderer interface and move the code to its implementation.
- Take out the rendering-related IPC to its own separate set of host/renderer classes.
- Change the way the view hierarchy and the compositor are initialized. Now they are created and set on BrowserViewRendererImpl construction.
- Content is now provided via a ContentViewCore object when initialized, updating the layer to use and the WebContents to observe.
- Remove/update the DEPS and gyp changes introduced to support rendering in the native layer.
BUG=167913,167908,161409
NOTRY=true
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=182710
Review URL: https://chromiumcodereview.appspot.com/12041009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182717 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview')
24 files changed, 1259 insertions, 714 deletions
diff --git a/android_webview/DEPS b/android_webview/DEPS index d5e52b5..02d8ca9 100644 --- a/android_webview/DEPS +++ b/android_webview/DEPS @@ -8,7 +8,6 @@ include_rules = [ "-android_webview/lib", "!chrome/browser/component", - "+cc", "+content/public/common", "+jni", "+net", diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp index 195782b..8010ba8 100644 --- a/android_webview/android_webview.gyp +++ b/android_webview/android_webview.gyp @@ -107,6 +107,7 @@ '../components/components.gyp:web_contents_delegate_android', '../content/content.gyp:content', '../skia/skia.gyp:skia', + '../ui/gl/gl.gyp:gl', 'android_webview_pak', ], 'include_dirs': [ @@ -135,6 +136,9 @@ 'browser/aw_request_interceptor.cc', 'browser/aw_request_interceptor.h', 'browser/aw_result_codes.h', + 'browser/browser_view_renderer.h', + 'browser/browser_view_renderer_impl.cc', + 'browser/browser_view_renderer_impl.h', 'browser/find_helper.cc', 'browser/find_helper.h', 'browser/icon_helper.cc', @@ -158,6 +162,8 @@ 'browser/renderer_host/aw_render_view_host_ext.h', 'browser/renderer_host/aw_resource_dispatcher_host_delegate.cc', 'browser/renderer_host/aw_resource_dispatcher_host_delegate.h', + 'browser/renderer_host/view_renderer_host.cc', + 'browser/renderer_host/view_renderer_host.h', 'browser/scoped_allow_wait_for_legacy_web_view_api.h', 'browser/scoped_allow_wait_for_legacy_web_view_api.h', 'common/android_webview_message_generator.cc', @@ -184,6 +190,8 @@ 'renderer/aw_render_process_observer.h', 'renderer/aw_render_view_ext.cc', 'renderer/aw_render_view_ext.h', + 'renderer/view_renderer.cc', + 'renderer/view_renderer.h', ], }, { diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS index 2caa535..c48c8f4 100644 --- a/android_webview/browser/DEPS +++ b/android_webview/browser/DEPS @@ -2,6 +2,9 @@ include_rules = [ "-android_webview", "+android_webview/browser", "+android_webview/common", + "+android_webview/public/browser", + + "+cc", "+components/auto_login_parser", "+components/navigation_interception", @@ -9,6 +12,9 @@ include_rules = [ "+content/public/browser", + "+ui/gfx", + "+ui/gl", + # Temporary until we bundle our own favicon. See # AwContentBrowserClient::GetDefaultFavicon "!grit/ui_resources.h", diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h new file mode 100644 index 0000000..02f47bc --- /dev/null +++ b/android_webview/browser/browser_view_renderer.h @@ -0,0 +1,95 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_BROWSER_BROWSER_VIEW_RENDERER_H_ +#define ANDROID_WEBVIEW_BROWSER_BROWSER_VIEW_RENDERER_H_ + +#include "base/android/scoped_java_ref.h" + +struct AwDrawGLInfo; + +namespace content { +class ContentViewCore; +} + +namespace gfx { +class Rect; +} + +namespace android_webview { + +// Interface for all the WebView-specific content rendering operations. +// Provides software and hardware rendering and the Capture Picture API. +class BrowserViewRenderer { + public: + class Client { + public: + // Called to trigger view invalidations. + virtual void Invalidate() = 0; + + // Called when a new Picture is available. Needs to be enabled + // via the EnableOnNewPicture method. + virtual void OnNewPicture( + const base::android::JavaRef<jobject>& picture) = 0; + + protected: + virtual ~Client() {} + }; + + // Delegate to perform rendering actions involving Java objects. + class JavaHelper { + public: + // Creates a RGBA_8888 Java Bitmap object of the requested size. + virtual base::android::ScopedJavaLocalRef<jobject> CreateBitmap( + JNIEnv* env, + int width, + int height) = 0; + + // Draws the provided Java Bitmap into the provided Java Canvas. + virtual void DrawBitmapIntoCanvas( + JNIEnv* env, + const base::android::JavaRef<jobject>& jbitmap, + const base::android::JavaRef<jobject>& jcanvas) = 0; + + // Creates a Java Picture object that records drawing the provided Bitmap. + virtual base::android::ScopedJavaLocalRef<jobject> RecordBitmapIntoPicture( + JNIEnv* env, + const base::android::JavaRef<jobject>& jbitmap) = 0; + + protected: + virtual ~JavaHelper() {} + }; + + enum OnNewPictureMode { + kOnNewPictureDisabled = 0, + kOnNewPictureEnabled, + kOnNewPictureInvalidationOnly, + }; + + // Content control methods. + virtual void SetContents(content::ContentViewCore* content_view_core) = 0; + + // Hardware rendering methods. + virtual void DrawGL(AwDrawGLInfo* draw_info) = 0; + virtual void SetScrollForHWFrame(int x, int y) = 0; + + // Software rendering methods. + virtual bool DrawSW(jobject java_canvas, const gfx::Rect& clip_bounds) = 0; + + // CapturePicture API methods. + virtual base::android::ScopedJavaLocalRef<jobject> CapturePicture() = 0; + virtual void EnableOnNewPicture(OnNewPictureMode mode) = 0; + + // View update notifications. + virtual void OnVisibilityChanged(bool view_visible, bool window_visible) = 0; + virtual void OnSizeChanged(int width, int height) = 0; + virtual void OnAttachedToWindow(int width, int height) = 0; + virtual void OnDetachedFromWindow() = 0; + + virtual ~BrowserViewRenderer() {} +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_BROWSER_BROWSER_VIEW_RENDERER_H_ diff --git a/android_webview/browser/browser_view_renderer_impl.cc b/android_webview/browser/browser_view_renderer_impl.cc new file mode 100644 index 0000000..250cdb0 --- /dev/null +++ b/android_webview/browser/browser_view_renderer_impl.cc @@ -0,0 +1,596 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "android_webview/browser/browser_view_renderer_impl.h" + +#include <android/bitmap.h> +#include <sys/system_properties.h> + +#include "android_webview/common/renderer_picture_map.h" +#include "android_webview/public/browser/draw_gl.h" +#include "android_webview/public/browser/draw_sw.h" +#include "base/android/jni_android.h" +#include "base/debug/trace_event.h" +#include "base/logging.h" +#include "cc/layer.h" +#include "content/public/browser/android/content_view_core.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/web_contents.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkDevice.h" +#include "third_party/skia/include/core/SkGraphics.h" +#include "ui/gfx/size.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::JavaRef; +using base::android::ScopedJavaLocalRef; +using content::Compositor; +using content::ContentViewCore; + +namespace { + +// Provides software rendering functions from the Android glue layer. +// Allows preventing extra copies of data when rendering. +AwDrawSWFunctionTable* g_sw_draw_functions = NULL; + +// Tells if the Skia library versions in Android and Chromium are compatible. +// If they are then it's possible to pass Skia objects like SkPictures to the +// Android glue layer via the SW rendering functions. +// If they are not, then additional copies and rasterizations are required +// as a fallback mechanism, which will have an important performance impact. +bool g_is_skia_version_compatible = false; + +typedef base::Callback<bool(SkCanvas*)> RenderMethod; + +static bool RasterizeIntoBitmap(JNIEnv* env, + const JavaRef<jobject>& jbitmap, + int scroll_x, + int scroll_y, + const RenderMethod& renderer) { + DCHECK(jbitmap.obj()); + + AndroidBitmapInfo bitmap_info; + if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) { + LOG(ERROR) << "Error getting java bitmap info."; + return false; + } + + void* pixels = NULL; + if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) { + LOG(ERROR) << "Error locking java bitmap pixels."; + return false; + } + + bool succeeded; + { + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, + bitmap_info.width, + bitmap_info.height, + bitmap_info.stride); + bitmap.setPixels(pixels); + + SkDevice device(bitmap); + SkCanvas canvas(&device); + canvas.translate(-scroll_x, -scroll_y); + succeeded = renderer.Run(&canvas); + } + + if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) { + LOG(ERROR) << "Error unlocking java bitmap pixels."; + return false; + } + + return succeeded; +} + +} // namespace + +namespace android_webview { + +// static +BrowserViewRendererImpl* BrowserViewRendererImpl::Create( + BrowserViewRenderer::Client* client, + JavaHelper* java_helper) { + return new BrowserViewRendererImpl(client, java_helper); +} + +BrowserViewRendererImpl::BrowserViewRendererImpl( + BrowserViewRenderer::Client* client, + JavaHelper* java_helper) + : client_(client), + java_helper_(java_helper), + ALLOW_THIS_IN_INITIALIZER_LIST(compositor_(Compositor::Create(this))), + view_clip_layer_(cc::Layer::create()), + transform_layer_(cc::Layer::create()), + scissor_clip_layer_(cc::Layer::create()), + view_visible_(false), + compositor_visible_(false), + is_composite_pending_(false), + dpi_scale_(1.0f), + on_new_picture_mode_(kOnNewPictureDisabled), + last_frame_context_(NULL), + web_contents_(NULL) { + DCHECK(java_helper); + + // Define the view hierarchy. + transform_layer_->addChild(view_clip_layer_); + scissor_clip_layer_->addChild(transform_layer_); + compositor_->SetRootLayer(scissor_clip_layer_); + + RendererPictureMap::CreateInstance(); +} + +BrowserViewRendererImpl::~BrowserViewRendererImpl() { +} + +// static +void BrowserViewRendererImpl::SetAwDrawSWFunctionTable( + AwDrawSWFunctionTable* table) { + g_sw_draw_functions = table; + g_is_skia_version_compatible = + g_sw_draw_functions->is_skia_version_compatible(&SkGraphics::GetVersion); + LOG_IF(WARNING, !g_is_skia_version_compatible) + << "Skia versions are not compatible, rendering performance will suffer."; +} + +void BrowserViewRendererImpl::SetContents(ContentViewCore* content_view_core) { + dpi_scale_ = content_view_core->GetDpiScale(); + web_contents_ = content_view_core->GetWebContents(); + if (!view_renderer_host_) + view_renderer_host_.reset(new ViewRendererHost(web_contents_, this)); + else + view_renderer_host_->Observe(web_contents_); + + view_clip_layer_->removeAllChildren(); + view_clip_layer_->addChild(content_view_core->GetLayer()); + Invalidate(); +} + +void BrowserViewRendererImpl::DrawGL(AwDrawGLInfo* draw_info) { + TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::DrawGL"); + + if (view_size_.IsEmpty() || !scissor_clip_layer_ || + 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, ¤t_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)); + + if (draw_info->is_layer) { + // When rendering into a separate layer no view clipping, transform, + // scissoring or background transparency need to be handled. + // The Android framework will composite us afterwards. + compositor_->SetHasTransparentBackground(false); + view_clip_layer_->setMasksToBounds(false); + transform_layer_->setTransform(gfx::Transform()); + scissor_clip_layer_->setMasksToBounds(false); + scissor_clip_layer_->setPosition(gfx::PointF()); + scissor_clip_layer_->setBounds(gfx::Size()); + scissor_clip_layer_->setSublayerTransform(gfx::Transform()); + + } else { + compositor_->SetHasTransparentBackground(true); + + gfx::Rect clip_rect(draw_info->clip_left, draw_info->clip_top, + draw_info->clip_right - draw_info->clip_left, + draw_info->clip_bottom - draw_info->clip_top); + + scissor_clip_layer_->setPosition(clip_rect.origin()); + scissor_clip_layer_->setBounds(clip_rect.size()); + scissor_clip_layer_->setMasksToBounds(true); + + // The compositor clipping architecture enforces us to have the clip layer + // as an ancestor of the area we want to clip, but this makes the transform + // become relative to the clip area rather than the full surface. The clip + // position offset needs to be undone before applying the transform. + gfx::Transform undo_clip_position; + undo_clip_position.Translate(-clip_rect.x(), -clip_rect.y()); + scissor_clip_layer_->setSublayerTransform(undo_clip_position); + + gfx::Transform transform; + transform.matrix().setColMajorf(draw_info->transform); + + // The scrolling values of the Android Framework affect the transformation + // matrix. This needs to be undone to let the compositor handle scrolling. + // TODO(leandrogracia): when scrolling becomes synchronous we should undo + // or override the translation in the compositor, not the one coming from + // the Android View System, as it could be out of bounds for overscrolling. + transform.Translate(hw_rendering_scroll_.x(), hw_rendering_scroll_.y()); + transform_layer_->setTransform(transform); + + view_clip_layer_->setMasksToBounds(true); + } + + compositor_->Composite(); + is_composite_pending_ = false; + + // TODO(leandrogracia): remove when crbug.com/164140 is closed. + // --------------------------------------------------------------------------- + char no_gl_restore_prop[PROP_VALUE_MAX]; + __system_property_get("webview.chromium_no_gl_restore", no_gl_restore_prop); + if (!strcmp(no_gl_restore_prop, "true")) { + LOG(WARNING) << "Android GL functor not restoring the previous GL state."; + } else { + 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); + } + // --------------------------------------------------------------------------- +} + +void BrowserViewRendererImpl::SetScrollForHWFrame(int x, int y) { + hw_rendering_scroll_ = gfx::Point(x, y); +} + +bool BrowserViewRendererImpl::DrawSW(jobject java_canvas, + const gfx::Rect& clip) { + TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::DrawSW"); + + if (clip.IsEmpty()) + return true; + + AwPixelInfo* pixels; + JNIEnv* env = AttachCurrentThread(); + + // Render into an auxiliary bitmap if pixel info is not available. + if (!g_sw_draw_functions || + (pixels = g_sw_draw_functions->access_pixels(env, java_canvas)) == NULL) { + ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap( + env, clip.width(), clip.height())); + if (!jbitmap.obj()) + return false; + + if (!RasterizeIntoBitmap(env, jbitmap, clip.x(), clip.y(), + base::Bind(&BrowserViewRendererImpl::RenderSW, + base::Unretained(this)))) { + return false; + } + + ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas); + java_helper_->DrawBitmapIntoCanvas(env, jbitmap, jcanvas); + return true; + } + + // Draw in a SkCanvas built over the pixel information. + bool succeeded = false; + { + SkBitmap bitmap; + bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config), + pixels->width, + pixels->height, + pixels->row_bytes); + bitmap.setPixels(pixels->pixels); + SkDevice device(bitmap); + SkCanvas canvas(&device); + SkMatrix matrix; + for (int i = 0; i < 9; i++) + matrix.set(i, pixels->matrix[i]); + canvas.setMatrix(matrix); + + SkRegion clip; + if (pixels->clip_region_size) { + size_t bytes_read = clip.readFromMemory(pixels->clip_region); + DCHECK_EQ(pixels->clip_region_size, bytes_read); + canvas.setClipRegion(clip); + } else { + clip.setRect(SkIRect::MakeWH(pixels->width, pixels->height)); + } + + succeeded = RenderSW(&canvas); + } + + g_sw_draw_functions->release_pixels(pixels); + return succeeded; +} + +ScopedJavaLocalRef<jobject> BrowserViewRendererImpl::CapturePicture() { + skia::RefPtr<SkPicture> picture = GetLastCapturedPicture(); + if (!picture || !g_sw_draw_functions) + return ScopedJavaLocalRef<jobject>(); + + JNIEnv* env = AttachCurrentThread(); + if (g_is_skia_version_compatible) { + return ScopedJavaLocalRef<jobject>(env, + g_sw_draw_functions->create_picture(env, picture->clone())); + } + + // If Skia versions are not compatible, workaround it by rasterizing the + // picture into a bitmap and drawing it into a new Java picture. + ScopedJavaLocalRef<jobject> jbitmap(java_helper_->CreateBitmap( + env, picture->width(), picture->height())); + if (!jbitmap.obj()) + return ScopedJavaLocalRef<jobject>(); + + if (!RasterizeIntoBitmap(env, jbitmap, 0, 0, + base::Bind(&BrowserViewRendererImpl::RenderPicture, + base::Unretained(this)))) { + return ScopedJavaLocalRef<jobject>(); + } + + return java_helper_->RecordBitmapIntoPicture(env, jbitmap); +} + +void BrowserViewRendererImpl::EnableOnNewPicture(OnNewPictureMode mode) { + on_new_picture_mode_ = mode; + + // TODO(leandrogracia): when SW rendering uses the compositor rather than + // picture rasterization, send update the renderer side with the correct + // listener state. (For now, we always leave render picture listener enabled). + // render_view_host_ext_->EnableCapturePictureCallback(enabled); + //DCHECK(view_renderer_host_); + //view_renderer_host_->EnableCapturePictureCallback( + // on_new_picture_mode_ == kOnNewPictureEnabled); +} + +void BrowserViewRendererImpl::OnVisibilityChanged(bool view_visible, + bool window_visible) { + view_visible_ = window_visible && view_visible; + Invalidate(); +} + +void BrowserViewRendererImpl::OnSizeChanged(int width, int height) { + view_size_ = gfx::Size(width, height); + view_clip_layer_->setBounds(view_size_); +} + +void BrowserViewRendererImpl::OnAttachedToWindow(int width, int height) { + view_size_ = gfx::Size(width, height); + view_clip_layer_->setBounds(view_size_); +} + +void BrowserViewRendererImpl::OnDetachedFromWindow() { + view_visible_ = false; + SetCompositorVisibility(false); +} + +void BrowserViewRendererImpl::ScheduleComposite() { + TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::ScheduleComposite"); + + if (is_composite_pending_) + return; + + is_composite_pending_ = true; + Invalidate(); +} + +skia::RefPtr<SkPicture> BrowserViewRendererImpl::GetLastCapturedPicture() { + // Use the latest available picture if the listener callback is enabled. + skia::RefPtr<SkPicture> picture; + if (on_new_picture_mode_ == kOnNewPictureEnabled) + picture = RendererPictureMap::GetInstance()->GetRendererPicture( + web_contents_->GetRoutingID()); + + // If not available or not in listener mode get it synchronously. + if (!picture) { + DCHECK(view_renderer_host_); + view_renderer_host_->CapturePictureSync(); + picture = RendererPictureMap::GetInstance()->GetRendererPicture( + web_contents_->GetRoutingID()); + } + + return picture; +} + +void BrowserViewRendererImpl::OnPictureUpdated(int process_id, + int render_view_id) { + CHECK_EQ(web_contents_->GetRenderProcessHost()->GetID(), process_id); + if (render_view_id != web_contents_->GetRoutingID()) + return; + + // TODO(leandrogracia): this can be made unconditional once software rendering + // uses Ubercompositor. Until then this path is required for SW invalidations. + if (on_new_picture_mode_ == kOnNewPictureEnabled) + client_->OnNewPicture(CapturePicture()); + + // TODO(leandrogracia): delete when sw rendering uses Ubercompositor. + // Invalidation should be provided by the compositor only. + Invalidate(); +} + +void BrowserViewRendererImpl::SetCompositorVisibility(bool visible) { + if (compositor_visible_ != visible) { + compositor_visible_ = visible; + compositor_->SetVisible(compositor_visible_); + } +} + +void BrowserViewRendererImpl::ResetCompositor() { + compositor_.reset(content::Compositor::Create(this)); + compositor_->SetRootLayer(scissor_clip_layer_); +} + +void BrowserViewRendererImpl::Invalidate() { + if (view_visible_) + client_->Invalidate(); + + // When not in invalidation-only mode onNewPicture will be triggered + // from the OnPictureUpdated callback. + if (on_new_picture_mode_ == kOnNewPictureInvalidationOnly) + client_->OnNewPicture(ScopedJavaLocalRef<jobject>()); +} + +bool BrowserViewRendererImpl::RenderSW(SkCanvas* canvas) { + // TODO(leandrogracia): once Ubercompositor is ready and we support software + // rendering mode, we should avoid this as much as we can, ideally always. + // This includes finding a proper replacement for onDraw calls in hardware + // mode with software canvases. http://crbug.com/170086. + return RenderPicture(canvas); +} + +bool BrowserViewRendererImpl::RenderPicture(SkCanvas* canvas) { + skia::RefPtr<SkPicture> picture = GetLastCapturedPicture(); + if (!picture) + return false; + + // Correct device scale. + canvas->scale(dpi_scale_, dpi_scale_); + + picture->draw(canvas); + return true; +} + +} // namespace android_webview diff --git a/android_webview/browser/browser_view_renderer_impl.h b/android_webview/browser/browser_view_renderer_impl.h new file mode 100644 index 0000000..323ddcb --- /dev/null +++ b/android_webview/browser/browser_view_renderer_impl.h @@ -0,0 +1,115 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_BROWSER_BROWSER_VIEW_RENDERER_IMPL_H_ +#define ANDROID_WEBVIEW_BROWSER_BROWSER_VIEW_RENDERER_IMPL_H_ + +#include "android_webview/browser/browser_view_renderer.h" +#include "android_webview/browser/renderer_host/view_renderer_host.h" +#include "content/public/browser/android/compositor.h" +#include "content/public/browser/web_contents_observer.h" +#include "skia/ext/refptr.h" +#include "ui/gfx/point.h" +#include "ui/gfx/size.h" + +typedef void* EGLContext; +struct AwDrawSWFunctionTable; +struct AwDrawGLInfo; +class SkCanvas; +class SkPicture; + +namespace content { +class WebContents; +} + +namespace android_webview { + +class BrowserViewRendererImpl + : public BrowserViewRenderer, + public ViewRendererHost::Client, + public content::Compositor::Client { + public: + static BrowserViewRendererImpl* Create(BrowserViewRenderer::Client* client, + JavaHelper* java_helper); + virtual ~BrowserViewRendererImpl(); + + // Platform methods. + static void SetAwDrawSWFunctionTable(AwDrawSWFunctionTable* table); + + // BrowserViewRenderer implementation. + virtual void SetContents( + content::ContentViewCore* content_view_core) OVERRIDE; + virtual void DrawGL(AwDrawGLInfo* draw_info) OVERRIDE; + virtual void SetScrollForHWFrame(int x, int y) OVERRIDE; + virtual bool DrawSW(jobject java_canvas, const gfx::Rect& clip) OVERRIDE; + virtual base::android::ScopedJavaLocalRef<jobject> CapturePicture() OVERRIDE; + virtual void EnableOnNewPicture(OnNewPictureMode mode) OVERRIDE; + virtual void OnVisibilityChanged( + bool view_visible, bool window_visible) OVERRIDE; + virtual void OnSizeChanged(int width, int height) OVERRIDE; + virtual void OnAttachedToWindow(int width, int height) OVERRIDE; + virtual void OnDetachedFromWindow() OVERRIDE; + + // content::Compositor::Client implementation. + virtual void ScheduleComposite() OVERRIDE; + + // ViewRendererHost::Client implementation. + virtual void OnPictureUpdated(int process_id, int render_view_id) OVERRIDE; + + protected: + BrowserViewRendererImpl(BrowserViewRenderer::Client* client, + JavaHelper* java_helper); + + private: + // Returns the latest locally available picture if any. + // If none is available will synchronously request the latest one + // and block until the result is received. + skia::RefPtr<SkPicture> GetLastCapturedPicture(); + void OnPictureUpdated(); + + void SetCompositorVisibility(bool visible); + void ResetCompositor(); + void Invalidate(); + bool RenderSW(SkCanvas* canvas); + bool RenderPicture(SkCanvas* canvas); + + BrowserViewRenderer::Client* client_; + BrowserViewRenderer::JavaHelper* java_helper_; + + scoped_ptr<ViewRendererHost> view_renderer_host_; + scoped_ptr<content::Compositor> compositor_; + + // Ensures content keeps clipped within the view during transformations. + scoped_refptr<cc::Layer> view_clip_layer_; + + // Applies the transformation matrix. + scoped_refptr<cc::Layer> transform_layer_; + + // Ensures content is drawn within the scissor clip rect provided by the + // Android framework. + scoped_refptr<cc::Layer> scissor_clip_layer_; + + // Last View scroll before hardware rendering is triggered. + gfx::Point hw_rendering_scroll_; + + bool view_visible_; + bool compositor_visible_; + bool is_composite_pending_; + float dpi_scale_; + gfx::Size view_size_; + OnNewPictureMode on_new_picture_mode_; + + // Used only for detecting Android View System context changes. + // Not to be used between draw calls. + EGLContext last_frame_context_; + + // Set via SetContents. Used to recognize updates to the local WebView. + content::WebContents* web_contents_; + + DISALLOW_COPY_AND_ASSIGN(BrowserViewRendererImpl); +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_BROWSER_BROWSER_VIEW_RENDERER_IMPL_H_ diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc index d76c7e9..0c7f082 100644 --- a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc +++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc @@ -18,11 +18,9 @@ namespace android_webview { -AwRenderViewHostExt::AwRenderViewHostExt(content::WebContents* contents, - Client* client) +AwRenderViewHostExt::AwRenderViewHostExt(content::WebContents* contents) : content::WebContentsObserver(contents), - has_new_hit_test_data_(false), - client_(client) { + has_new_hit_test_data_(false) { } AwRenderViewHostExt::~AwRenderViewHostExt() {} @@ -65,11 +63,6 @@ const AwHitTestData& AwRenderViewHostExt::GetLastHitTestData() const { return last_hit_test_data_; } -void AwRenderViewHostExt::EnableCapturePictureCallback(bool enabled) { - Send(new AwViewMsg_EnableCapturePictureCallback( - web_contents()->GetRoutingID(), enabled)); -} - void AwRenderViewHostExt::SetTextZoomLevel(double level) { DCHECK(CalledOnValidThread()); Send(new AwViewMsg_SetTextZoomLevel(web_contents()->GetRoutingID(), level)); @@ -101,8 +94,6 @@ bool AwRenderViewHostExt::OnMessageReceived(const IPC::Message& message) { OnDocumentHasImagesResponse) IPC_MESSAGE_HANDLER(AwViewHostMsg_UpdateHitTestData, OnUpdateHitTestData) - IPC_MESSAGE_HANDLER(AwViewHostMsg_PictureUpdated, - OnPictureUpdated) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -129,24 +120,4 @@ void AwRenderViewHostExt::OnUpdateHitTestData( has_new_hit_test_data_ = true; } -void AwRenderViewHostExt::OnPictureUpdated() { - if (client_) - client_->OnPictureUpdated(web_contents()->GetRenderProcessHost()->GetID(), - routing_id()); -} - -bool AwRenderViewHostExt::IsRenderViewReady() const { - return web_contents()->GetRenderProcessHost()->HasConnection() && - web_contents()->GetRenderViewHost() && - web_contents()->GetRenderViewHost()->IsRenderViewLive(); -} - -void AwRenderViewHostExt::CapturePictureSync() { - if (!IsRenderViewReady()) - return; - - ScopedAllowWaitForLegacyWebViewApi wait; - Send(new AwViewMsg_CapturePictureSync(web_contents()->GetRoutingID())); -} - } // namespace android_webview diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.h b/android_webview/browser/renderer_host/aw_render_view_host_ext.h index 678ef1a..fae35e9 100644 --- a/android_webview/browser/renderer_host/aw_render_view_host_ext.h +++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.h @@ -25,17 +25,9 @@ namespace android_webview { class AwRenderViewHostExt : public content::WebContentsObserver, public base::NonThreadSafe { public: - class Client { - public: - virtual void OnPictureUpdated(int process_id, int render_view_id) = 0; - - protected: - virtual ~Client() {} - }; - // To send receive messages to a RenderView we take the WebContents instance, // as it internally handles RenderViewHost instances changing underneath us. - AwRenderViewHostExt(content::WebContents* contents, Client* client); + AwRenderViewHostExt(content::WebContents* contents); virtual ~AwRenderViewHostExt(); // |result| will be invoked with the outcome of the request. @@ -58,14 +50,6 @@ class AwRenderViewHostExt : public content::WebContentsObserver, // the corresponding public WebView API is as well. const AwHitTestData& GetLastHitTestData() const; - // Enables updating picture piles on every new frame. - // OnPictureUpdated is called when a new picture is available, - // stored by renderer id in RendererPictureMap. - void EnableCapturePictureCallback(bool enabled); - - // Captures the latest available picture pile synchronously. - void CapturePictureSync(); - // Sets the zoom level for text only. Used in layout modes other than // Text Autosizing. void SetTextZoomLevel(double level); @@ -93,8 +77,6 @@ class AwRenderViewHostExt : public content::WebContentsObserver, bool has_new_hit_test_data_; - Client* client_; - DISALLOW_COPY_AND_ASSIGN(AwRenderViewHostExt); }; diff --git a/android_webview/browser/renderer_host/view_renderer_host.cc b/android_webview/browser/renderer_host/view_renderer_host.cc new file mode 100644 index 0000000..3b8e654 --- /dev/null +++ b/android_webview/browser/renderer_host/view_renderer_host.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "android_webview/browser/renderer_host/view_renderer_host.h" + +#include "android_webview/browser/scoped_allow_wait_for_legacy_web_view_api.h" +#include "android_webview/common/render_view_messages.h" +#include "android_webview/common/renderer_picture_map.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" + +namespace android_webview { + +ViewRendererHost::ViewRendererHost(content::WebContents* contents, + Client* client) + : content::WebContentsObserver(contents), + client_(client) { +} + +ViewRendererHost::~ViewRendererHost() { +} + +void ViewRendererHost::CapturePictureSync() { + if (!IsRenderViewReady()) + return; + + ScopedAllowWaitForLegacyWebViewApi wait; + Send(new AwViewMsg_CapturePictureSync(web_contents()->GetRoutingID())); +} + +void ViewRendererHost::EnableCapturePictureCallback(bool enabled) { + Send(new AwViewMsg_EnableCapturePictureCallback( + web_contents()->GetRoutingID(), enabled)); +} + +void ViewRendererHost::OnPictureUpdated() { + if (client_) { + client_->OnPictureUpdated(web_contents()->GetRenderProcessHost()->GetID(), + routing_id()); + } +} + +void ViewRendererHost::RenderViewGone(base::TerminationStatus status) { + DCHECK(CalledOnValidThread()); + RendererPictureMap::GetInstance()->ClearRendererPicture( + web_contents()->GetRoutingID()); +} + +bool ViewRendererHost::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ViewRendererHost, message) + IPC_MESSAGE_HANDLER(AwViewHostMsg_PictureUpdated, + OnPictureUpdated) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled ? true : WebContentsObserver::OnMessageReceived(message); +} + +bool ViewRendererHost::IsRenderViewReady() const { + return web_contents()->GetRenderProcessHost()->HasConnection() && + web_contents()->GetRenderViewHost() && + web_contents()->GetRenderViewHost()->IsRenderViewLive(); +} + +} // namespace android_webview diff --git a/android_webview/browser/renderer_host/view_renderer_host.h b/android_webview/browser/renderer_host/view_renderer_host.h new file mode 100644 index 0000000..aaaad5d --- /dev/null +++ b/android_webview/browser/renderer_host/view_renderer_host.h @@ -0,0 +1,52 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_BROWSER_RENDER_HOST_VIEW_RENDERER_HOST_H_ +#define ANDROID_WEBVIEW_BROWSER_RENDER_HOST_VIEW_RENDERER_HOST_H_ + +#include "base/threading/non_thread_safe.h" +#include "content/public/browser/web_contents_observer.h" + +namespace android_webview { + +// Provides RenderViewHost wrapper functionality for sending WebView-specific +// IPC messages to the renderer and from there to WebKit. +class ViewRendererHost : public content::WebContentsObserver, + public base::NonThreadSafe { + public: + class Client { + public: + virtual void OnPictureUpdated(int process_id, int render_view_id) = 0; + + protected: + virtual ~Client() {} + }; + + ViewRendererHost(content::WebContents* contents, Client* client); + virtual ~ViewRendererHost(); + + // Captures the latest available picture pile synchronously. + void CapturePictureSync(); + + // Enables updating picture piles on every new frame. + // OnPictureUpdated is called when a new picture is available, + // stored by renderer id in RendererPictureMap. + void EnableCapturePictureCallback(bool enabled); + + using content::WebContentsObserver::Observe; + + private: + // content::WebContentsObserver implementation. + virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + void OnPictureUpdated(); + bool IsRenderViewReady() const; + + Client* client_; +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_BROWSER_RENDER_HOST_VIEW_RENDERER_HOST_H_ diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index a0027c3..adf23f9 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -320,8 +320,8 @@ public class AwContents { public int getAwDrawGLViewContext() { // Using the native pointer as the returned viewContext. This is matched by the - // reinterpret_cast back to AwContents pointer in the native DrawGLFunction. - return mNativeAwContents; + // reinterpret_cast back to BrowserViewRenderer pointer in the native DrawGLFunction. + return nativeGetAwDrawGLViewContext(mNativeAwContents); } public boolean onPrepareDrawGL(Canvas canvas) { @@ -998,38 +998,6 @@ public class AwContents { return null; } - /** - * Provides a Bitmap object with a given width and height used for auxiliary rasterization. - */ - @CalledByNative - private static Bitmap createBitmap(int width, int height) { - return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - } - - /** - * Draws a provided bitmap into a canvas. - * Used for convenience from the native side and other static helper methods. - */ - @CalledByNative - private static void drawBitmapIntoCanvas(Bitmap bitmap, Canvas canvas) { - canvas.drawBitmap(bitmap, 0, 0, null); - } - - /** - * Creates a new Picture that records drawing a provided bitmap. - * Will return an empty Picture if the Bitmap is null. - */ - @CalledByNative - private static Picture recordBitmapIntoPicture(Bitmap bitmap) { - Picture picture = new Picture(); - if (bitmap != null) { - Canvas recordingCanvas = picture.beginRecording(bitmap.getWidth(), bitmap.getHeight()); - drawBitmapIntoCanvas(bitmap, recordingCanvas); - picture.endRecording(); - } - return picture; - } - @CalledByNative private void handleJsAlert(String url, String message, JsResultReceiver receiver) { mContentsClient.handleJsAlert(url, message, receiver); @@ -1075,8 +1043,6 @@ public class AwContents { private native void nativeAddVisitedLinks(int nativeAwContents, String[] visitedLinks); - private native boolean nativeDrawSW(int nativeAwContents, Canvas canvas, int clipX, int clipY, - int clipW, int clipH); private native void nativeSetScrollForHWFrame(int nativeAwContents, int scrollX, int scrollY); private native int nativeFindAllSync(int nativeAwContents, String searchString); private native void nativeFindAllAsync(int nativeAwContents, String searchString); @@ -1105,6 +1071,9 @@ public class AwContents { private native void nativeSetWebContents(int nativeAwContents, int nativeNewWebContents); private native void nativeFocusFirstNode(int nativeAwContents); + private native boolean nativeDrawSW(int nativeAwContents, Canvas canvas, int clipX, int clipY, + int clipW, int clipH); + private native int nativeGetAwDrawGLViewContext(int nativeAwContents); private native Picture nativeCapturePicture(int nativeAwContents); private native void nativeEnableOnNewPicture(int nativeAwContents, boolean enabled, boolean invalidationOnly); diff --git a/android_webview/java/src/org/chromium/android_webview/JavaBrowserViewRendererHelper.java b/android_webview/java/src/org/chromium/android_webview/JavaBrowserViewRendererHelper.java new file mode 100644 index 0000000..d4e79c8 --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/JavaBrowserViewRendererHelper.java @@ -0,0 +1,56 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.android_webview; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Picture; + +import org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; + +/** + * Provides auxiliary methods related to Picture objects and native SkPictures. + */ +@JNINamespace("android_webview") +public class JavaBrowserViewRendererHelper { + + /** + * Provides a Bitmap object with a given width and height used for auxiliary rasterization. + */ + @CalledByNative + private static Bitmap createBitmap(int width, int height) { + return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + } + + /** + * Draws a provided bitmap into a canvas. + * Used for convenience from the native side and other static helper methods. + */ + @CalledByNative + private static void drawBitmapIntoCanvas(Bitmap bitmap, Canvas canvas) { + canvas.drawBitmap(bitmap, 0, 0, null); + } + + /** + * Creates a new Picture that records drawing a provided bitmap. + * Will return an empty Picture if the Bitmap is null. + */ + @CalledByNative + private static Picture recordBitmapIntoPicture(Bitmap bitmap) { + Picture picture = new Picture(); + if (bitmap != null) { + Canvas recordingCanvas = picture.beginRecording(bitmap.getWidth(), bitmap.getHeight()); + drawBitmapIntoCanvas(bitmap, recordingCanvas); + picture.endRecording(); + } + return picture; + } + + // Should never be instantiated. + private JavaBrowserViewRendererHelper() { + } +} diff --git a/android_webview/native/DEPS b/android_webview/native/DEPS index 6693d30..56fbdec 100644 --- a/android_webview/native/DEPS +++ b/android_webview/native/DEPS @@ -1,12 +1,8 @@ include_rules = [ "+content/public/browser", "+ui/gfx", - "+ui/gl", # Components that Android WebView depends on. "+components/navigation_interception", "+components/web_contents_delegate_android", - - # TODO(joth): Remove if we can move the compositor driver into ../browser/ - "+third_party/skia/include", ] diff --git a/android_webview/native/android_webview_jni_registrar.cc b/android_webview/native/android_webview_jni_registrar.cc index 33dfff0..47c7373 100644 --- a/android_webview/native/android_webview_jni_registrar.cc +++ b/android_webview/native/android_webview_jni_registrar.cc @@ -14,6 +14,7 @@ #include "android_webview/native/cookie_manager.h" #include "android_webview/native/input_stream_impl.h" #include "android_webview/native/intercepted_request_data_impl.h" +#include "android_webview/native/java_browser_view_renderer_helper.h" #include "android_webview/native/js_result_handler.h" #include "base/android/jni_android.h" #include "base/android/jni_registrar.h" @@ -32,6 +33,7 @@ static base::android::RegistrationMethod kWebViewRegisteredMethods[] = { { "CookieManager", RegisterCookieManager }, { "InterceptedRequestDataImpl", RegisterInterceptedRequestData }, { "InputStream", RegisterInputStream }, + { "JavaBrowserViewRendererHelper", RegisterJavaBrowserViewRendererHelper }, { "JsResultHandler", RegisterJsResultHandler }, }; diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc index 7b429f2..6bef690 100644 --- a/android_webview/native/aw_contents.cc +++ b/android_webview/native/aw_contents.cc @@ -4,32 +4,28 @@ #include "android_webview/native/aw_contents.h" -#include <android/bitmap.h> -#include <sys/system_properties.h> - #include "android_webview/browser/aw_browser_context.h" #include "android_webview/browser/aw_browser_main_parts.h" +#include "android_webview/browser/browser_view_renderer_impl.h" #include "android_webview/browser/net_disk_cache_remover.h" #include "android_webview/browser/renderer_host/aw_render_view_host_ext.h" #include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h" #include "android_webview/common/aw_hit_test_data.h" -#include "android_webview/common/renderer_picture_map.h" #include "android_webview/native/aw_browser_dependency_factory.h" #include "android_webview/native/aw_contents_io_thread_client_impl.h" #include "android_webview/native/aw_web_contents_delegate.h" +#include "android_webview/native/java_browser_view_renderer_helper.h" #include "android_webview/native/state_serializer.h" -#include "android_webview/public/browser/draw_sw.h" +#include "android_webview/public/browser/draw_gl.h" #include "base/android/jni_android.h" #include "base/android/jni_array.h" #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/string16.h" #include "base/supports_user_data.h" -#include "cc/layer.h" #include "components/navigation_interception/intercept_navigation_delegate.h" #include "content/public/browser/android/content_view_core.h" #include "content/public/browser/browser_thread.h" @@ -41,25 +37,9 @@ #include "content/public/common/ssl_status.h" #include "jni/AwContents_jni.h" #include "net/base/x509_certificate.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkDevice.h" -#include "third_party/skia/include/core/SkGraphics.h" -#include "third_party/skia/include/core/SkPicture.h" #include "ui/gfx/android/java_bitmap.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 +struct AwDrawSWFunctionTable; using base::android::AttachCurrentThread; using base::android::ConvertJavaStringToUTF16; @@ -81,61 +61,16 @@ static void DrawGLFunction(int view_context, void* spare) { // |view_context| is the value that was returned from the java // AwContents.onPrepareDrawGL; this cast must match the code there. - reinterpret_cast<android_webview::AwContents*>(view_context)->DrawGL( + reinterpret_cast<android_webview::BrowserViewRenderer*>(view_context)->DrawGL( draw_info); } - -typedef base::Callback<bool(SkCanvas*)> RenderMethod; - -static bool RasterizeIntoBitmap(JNIEnv* env, - jobject jbitmap, - int scroll_x, - int scroll_y, - const RenderMethod& renderer) { - DCHECK(jbitmap); - - AndroidBitmapInfo bitmap_info; - if (AndroidBitmap_getInfo(env, jbitmap, &bitmap_info) < 0) { - LOG(WARNING) << "Error getting java bitmap info."; - return false; - } - - void* pixels = NULL; - if (AndroidBitmap_lockPixels(env, jbitmap, &pixels) < 0) { - LOG(WARNING) << "Error locking java bitmap pixels."; - return false; - } - - bool succeeded = false; - { - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, - bitmap_info.width, - bitmap_info.height, - bitmap_info.stride); - bitmap.setPixels(pixels); - - SkDevice device(bitmap); - SkCanvas canvas(&device); - canvas.translate(-scroll_x, -scroll_y); - succeeded = renderer.Run(&canvas); - } - - if (AndroidBitmap_unlockPixels(env, jbitmap) < 0) { - LOG(WARNING) << "Error unlocking java bitmap pixels."; - return false; - } - - return succeeded; -} } namespace android_webview { namespace { -AwDrawSWFunctionTable* g_draw_sw_functions = NULL; -bool g_is_skia_version_compatible = false; +static JavaBrowserViewRendererHelper java_renderer_helper; const void* kAwContentsUserDataKey = &kAwContentsUserDataKey; @@ -180,13 +115,8 @@ AwContents::AwContents(JNIEnv* env, : java_ref_(env, obj), web_contents_delegate_( new AwWebContentsDelegate(env, web_contents_delegate)), - view_visible_(false), - compositor_visible_(false), - is_composite_pending_(false), - dpi_scale_(1.0f), - on_new_picture_mode_(kOnNewPictureDisabled), - last_frame_context_(NULL) { - RendererPictureMap::CreateInstance(); + ALLOW_THIS_IN_INITIALIZER_LIST(browser_view_renderer_( + BrowserViewRendererImpl::Create(this, &java_renderer_helper))) { android_webview::AwBrowserDependencyFactory* dependency_factory = android_webview::AwBrowserDependencyFactory::GetInstance(); @@ -196,12 +126,6 @@ AwContents::AwContents(JNIEnv* env, SetWebContents(dependency_factory->CreateWebContents()); } -void AwContents::ResetCompositor() { - compositor_.reset(content::Compositor::Create(this)); - if (scissor_clip_layer_.get()) - AttachLayerTree(); -} - void AwContents::SetWebContents(content::WebContents* web_contents) { web_contents_.reset(web_contents); if (find_helper_.get()) { @@ -211,11 +135,8 @@ void AwContents::SetWebContents(content::WebContents* web_contents) { icon_helper_->SetListener(this); web_contents_->SetUserData(kAwContentsUserDataKey, new AwContentsUserData(this)); - web_contents_->SetDelegate(web_contents_delegate_.get()); - render_view_host_ext_.reset(new AwRenderViewHostExt(web_contents_.get(), - this)); - ResetCompositor(); + render_view_host_ext_.reset(new AwRenderViewHostExt(web_contents_.get())); } void AwContents::SetWebContents(JNIEnv* env, jobject obj, jint new_wc) { @@ -231,287 +152,6 @@ AwContents::~AwContents() { icon_helper_->SetListener(NULL); } -void AwContents::DrawGL(AwDrawGLInfo* draw_info) { - - TRACE_EVENT0("AwContents", "AwContents::DrawGL"); - - if (view_size_.IsEmpty() || !scissor_clip_layer_ || - 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, ¤t_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)); - - if (draw_info->is_layer) { - // When rendering into a separate layer no view clipping, transform, - // scissoring or background transparency need to be handled. - // The Android framework will composite us afterwards. - compositor_->SetHasTransparentBackground(false); - view_clip_layer_->setMasksToBounds(false); - transform_layer_->setTransform(gfx::Transform()); - scissor_clip_layer_->setMasksToBounds(false); - scissor_clip_layer_->setPosition(gfx::PointF()); - scissor_clip_layer_->setBounds(gfx::Size()); - scissor_clip_layer_->setSublayerTransform(gfx::Transform()); - - } else { - compositor_->SetHasTransparentBackground(true); - - gfx::Rect clip_rect(draw_info->clip_left, draw_info->clip_top, - draw_info->clip_right - draw_info->clip_left, - draw_info->clip_bottom - draw_info->clip_top); - - scissor_clip_layer_->setPosition(clip_rect.origin()); - scissor_clip_layer_->setBounds(clip_rect.size()); - scissor_clip_layer_->setMasksToBounds(true); - - // The compositor clipping architecture enforces us to have the clip layer - // as an ancestor of the area we want to clip, but this makes the transform - // become relative to the clip area rather than the full surface. The clip - // position offset needs to be undone before applying the transform. - gfx::Transform undo_clip_position; - undo_clip_position.Translate(-clip_rect.x(), -clip_rect.y()); - scissor_clip_layer_->setSublayerTransform(undo_clip_position); - - gfx::Transform transform; - transform.matrix().setColMajorf(draw_info->transform); - - // The scrolling values of the Android Framework affect the transformation - // matrix. This needs to be undone to let the compositor handle scrolling. - transform.Translate(hw_rendering_scroll_.x(), hw_rendering_scroll_.y()); - transform_layer_->setTransform(transform); - - view_clip_layer_->setMasksToBounds(true); - } - - compositor_->Composite(); - is_composite_pending_ = false; - - // TODO(leandrogracia): remove when crbug.com/164140 is closed. - // --------------------------------------------------------------------------- - char no_gl_restore_prop[PROP_VALUE_MAX]; - __system_property_get("webview.chromium_no_gl_restore", no_gl_restore_prop); - if (!strcmp(no_gl_restore_prop, "true")) { - LOG(WARNING) << "Android GL functor not restoring the previous GL state."; - } else { - 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); - } - // --------------------------------------------------------------------------- -} - -bool AwContents::DrawSW(JNIEnv* env, - jobject obj, - jobject java_canvas, - jint clip_x, - jint clip_y, - jint clip_w, - jint clip_h) { - TRACE_EVENT0("AwContents", "AwContents::DrawSW"); - - if (clip_w <= 0 || clip_h <= 0) - return true; - - AwPixelInfo* pixels; - - // Render into an auxiliary bitmap if pixel info is not available. - if (!g_draw_sw_functions || - (pixels = g_draw_sw_functions->access_pixels(env, java_canvas)) == NULL) { - ScopedJavaLocalRef<jobject> jbitmap(Java_AwContents_createBitmap( - env, clip_w, clip_h)); - if (!jbitmap.obj()) - return false; - - if (!RasterizeIntoBitmap(env, jbitmap.obj(), clip_x, clip_y, - base::Bind(&AwContents::RenderSW, base::Unretained(this)))) - return false; - - Java_AwContents_drawBitmapIntoCanvas(env, jbitmap.obj(), java_canvas); - return true; - } - - // Draw in a SkCanvas built over the pixel information. - bool succeeded = false; - { - SkBitmap bitmap; - bitmap.setConfig(static_cast<SkBitmap::Config>(pixels->config), - pixels->width, - pixels->height, - pixels->row_bytes); - bitmap.setPixels(pixels->pixels); - SkDevice device(bitmap); - SkCanvas canvas(&device); - SkMatrix matrix; - for (int i = 0; i < 9; i++) - matrix.set(i, pixels->matrix[i]); - canvas.setMatrix(matrix); - - SkRegion clip; - if (pixels->clip_region_size) { - size_t bytes_read = clip.readFromMemory(pixels->clip_region); - DCHECK_EQ(pixels->clip_region_size, bytes_read); - canvas.setClipRegion(clip); - } else { - clip.setRect(SkIRect::MakeWH(pixels->width, pixels->height)); - } - - succeeded = RenderSW(&canvas); - } - - g_draw_sw_functions->release_pixels(pixels); - return succeeded; -} - jint AwContents::GetWebContents(JNIEnv* env, jobject obj) { return reinterpret_cast<jint>(web_contents_.get()); } @@ -520,30 +160,7 @@ 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())); - - dpi_scale_ = core->GetDpiScale(); - - // Ensures content keeps clipped within the view during transformations. - view_clip_layer_ = cc::Layer::create(); - view_clip_layer_->setBounds(view_size_); - view_clip_layer_->addChild(core->GetLayer()); - - // Applies the transformation matrix. - transform_layer_ = cc::Layer::create(); - transform_layer_->addChild(view_clip_layer_); - - // Ensures content is drawn within the scissor clip rect provided by the - // Android framework. - scissor_clip_layer_ = cc::Layer::create(); - scissor_clip_layer_->addChild(transform_layer_); - - AttachLayerTree(); -} - -void AwContents::AttachLayerTree() { - DCHECK(scissor_clip_layer_.get()); - compositor_->SetRootLayer(scissor_clip_layer_); - Invalidate(); + browser_view_renderer_->SetContents(core); } void AwContents::Destroy(JNIEnv* env, jobject obj) { @@ -552,12 +169,8 @@ void AwContents::Destroy(JNIEnv* env, jobject obj) { // static void SetAwDrawSWFunctionTable(JNIEnv* env, jclass, jint function_table) { - g_draw_sw_functions = - reinterpret_cast<AwDrawSWFunctionTable*>(function_table); - g_is_skia_version_compatible = - g_draw_sw_functions->is_skia_version_compatible(&SkGraphics::GetVersion); - LOG_IF(WARNING, !g_is_skia_version_compatible) << - "Skia native versions are not compatible."; + BrowserViewRendererImpl::SetAwDrawSWFunctionTable( + reinterpret_cast<AwDrawSWFunctionTable*>(function_table)); } // static @@ -565,6 +178,10 @@ jint GetAwDrawGLFunction(JNIEnv* env, jclass) { return reinterpret_cast<jint>(&DrawGLFunction); } +jint AwContents::GetAwDrawGLViewContext(JNIEnv* env, jobject obj) { + return reinterpret_cast<jint>(browser_view_renderer_.get()); +} + namespace { void DocumentHasImagesCallback(const ScopedJavaGlobalRef<jobject>& message, bool has_images) { @@ -890,39 +507,18 @@ void AwContents::OnReceivedTouchIconUrl(const std::string& url, env, obj.obj(), ConvertUTF8ToJavaString(env, url).obj(), precomposed); } -void AwContents::ScheduleComposite() { - TRACE_EVENT0("AwContents", "AwContents::ScheduleComposite"); - - if (is_composite_pending_) - return; - - is_composite_pending_ = true; - Invalidate(); -} - void AwContents::Invalidate() { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); - if (obj.is_null()) - return; - - if (view_visible_) + if (!obj.is_null()) Java_AwContents_invalidate(env, obj.obj()); - - // When not in invalidation-only mode onNewPicture will be triggered - // from the OnPictureUpdated callback. - if (on_new_picture_mode_ == kOnNewPictureInvalidationOnly) - Java_AwContents_onNewPicture(env, obj.obj(), NULL); -} - -void AwContents::SetCompositorVisibility(bool visible) { - if (compositor_visible_ != visible) { - compositor_visible_ = visible; - compositor_->SetVisible(compositor_visible_); - } } -void AwContents::OnSwapBuffersCompleted() { +void AwContents::OnNewPicture(const JavaRef<jobject>& picture) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (!obj.is_null()) + Java_AwContents_onNewPicture(env, obj.obj(), picture.obj()); } base::android::ScopedJavaLocalRef<jbyteArray> @@ -986,27 +582,21 @@ void AwContents::UpdateLastHitTestData(JNIEnv* env, jobject obj) { void AwContents::OnSizeChanged(JNIEnv* env, jobject obj, int w, int h, int ow, int oh) { - view_size_ = gfx::Size(w, h); - if (view_clip_layer_.get()) - view_clip_layer_->setBounds(view_size_); + browser_view_renderer_->OnSizeChanged(w, h); } void AwContents::SetWindowViewVisibility(JNIEnv* env, jobject obj, bool window_visible, bool view_visible) { - view_visible_ = window_visible && view_visible; - Invalidate(); + browser_view_renderer_->OnVisibilityChanged(window_visible, view_visible); } void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) { - view_size_ = gfx::Size(w, h); - if (view_clip_layer_.get()) - view_clip_layer_->setBounds(view_size_); + browser_view_renderer_->OnAttachedToWindow(w, h); } void AwContents::OnDetachedFromWindow(JNIEnv* env, jobject obj) { - view_visible_ = false; - SetCompositorVisibility(false); + browser_view_renderer_->OnDetachedFromWindow(); } base::android::ScopedJavaLocalRef<jbyteArray> @@ -1039,9 +629,20 @@ jboolean AwContents::RestoreFromOpaqueState( return RestoreFromPickle(&iterator, web_contents_.get()); } +bool AwContents::DrawSW(JNIEnv* env, + jobject obj, + jobject canvas, + jint clip_x, + jint clip_y, + jint clip_w, + jint clip_h) { + return browser_view_renderer_->DrawSW( + canvas, gfx::Rect(clip_x, clip_y, clip_w, clip_h)); +} + void AwContents::SetScrollForHWFrame(JNIEnv* env, jobject obj, int scroll_x, int scroll_y) { - hw_rendering_scroll_ = gfx::Point(scroll_x, scroll_y); + browser_view_renderer_->SetScrollForHWFrame(scroll_x, scroll_y); } void AwContents::SetPendingWebContentsForPopup( @@ -1066,106 +667,22 @@ jint AwContents::ReleasePopupWebContents(JNIEnv* env, jobject obj) { ScopedJavaLocalRef<jobject> AwContents::CapturePicture(JNIEnv* env, jobject obj) { - skia::RefPtr<SkPicture> picture = GetLastCapturedPicture(); - if (!picture || !g_draw_sw_functions) - return ScopedJavaLocalRef<jobject>(); - - if (g_is_skia_version_compatible) - return ScopedJavaLocalRef<jobject>(env, - g_draw_sw_functions->create_picture(env, picture->clone())); - - // If Skia versions are not compatible, workaround it by rasterizing the - // picture into a bitmap and drawing it into a new Java picture. - ScopedJavaLocalRef<jobject> jbitmap(Java_AwContents_createBitmap( - env, picture->width(), picture->height())); - if (!jbitmap.obj()) - return ScopedJavaLocalRef<jobject>(); - - if (!RasterizeIntoBitmap(env, jbitmap.obj(), 0, 0, - base::Bind(&AwContents::RenderPicture, base::Unretained(this)))) - return ScopedJavaLocalRef<jobject>(); - - return Java_AwContents_recordBitmapIntoPicture(env, jbitmap.obj()); -} - -bool AwContents::RenderSW(SkCanvas* canvas) { - // TODO(leandrogracia): once Ubercompositor is ready and we support software - // rendering mode, we should avoid this as much as we can, ideally always. - // This includes finding a proper replacement for onDraw calls in hardware - // mode with software canvases. http://crbug.com/170086. - return RenderPicture(canvas); -} - -bool AwContents::RenderPicture(SkCanvas* canvas) { - skia::RefPtr<SkPicture> picture = GetLastCapturedPicture(); - if (!picture) - return false; - - // Correct device scale. - canvas->scale(dpi_scale_, dpi_scale_); - - picture->draw(canvas); - return true; + return browser_view_renderer_->CapturePicture(); } void AwContents::EnableOnNewPicture(JNIEnv* env, jobject obj, jboolean enabled, jboolean invalidation_only) { + BrowserViewRenderer::OnNewPictureMode mode = + BrowserViewRenderer::kOnNewPictureDisabled; if (enabled) { - on_new_picture_mode_ = invalidation_only ? kOnNewPictureInvalidationOnly : - kOnNewPictureEnabled; - } else { - on_new_picture_mode_ = kOnNewPictureDisabled; - } - - // If onNewPicture is triggered only on invalidation do not capture - // pictures on every new frame. - if (on_new_picture_mode_ == kOnNewPictureInvalidationOnly) - enabled = false; - - // TODO(leandrogracia): when SW rendering uses the compositor rather than - // picture rasterization, send update the renderer side with the correct - // listener state. (For now, we always leave render picture listener enabled). - // render_view_host_ext_->EnableCapturePictureCallback(enabled); -} - -void AwContents::OnPictureUpdated(int process_id, int render_view_id) { - CHECK_EQ(web_contents_->GetRenderProcessHost()->GetID(), process_id); - if (render_view_id != web_contents_->GetRoutingID()) - return; - - // TODO(leandrogracia): this can be made unconditional once software rendering - // uses Ubercompositor. Until then this path is required for SW invalidations. - if (on_new_picture_mode_ == kOnNewPictureEnabled) { - JNIEnv* env = AttachCurrentThread(); - ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); - if (!obj.is_null()) { - ScopedJavaLocalRef<jobject> picture = CapturePicture(env, obj.obj()); - Java_AwContents_onNewPicture(env, obj.obj(), picture.obj()); - } - } - - // TODO(leandrogracia): delete when sw rendering uses Ubercompositor. - // Invalidation should be provided by the compositor only. - Invalidate(); -} - -skia::RefPtr<SkPicture> AwContents::GetLastCapturedPicture() { - // Use the latest available picture if the listener callback is enabled. - skia::RefPtr<SkPicture> picture; - if (on_new_picture_mode_ == kOnNewPictureEnabled) - picture = RendererPictureMap::GetInstance()->GetRendererPicture( - web_contents_->GetRoutingID()); - - // If not available or not in listener mode get it synchronously. - if (!picture) { - render_view_host_ext_->CapturePictureSync(); - picture = RendererPictureMap::GetInstance()->GetRendererPicture( - web_contents_->GetRoutingID()); + mode = invalidation_only ? + BrowserViewRenderer::kOnNewPictureInvalidationOnly : + BrowserViewRenderer::kOnNewPictureEnabled; } - return picture; + browser_view_renderer_->EnableOnNewPicture(mode); } } // namespace android_webview diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h index 78ababc..889aaa8 100644 --- a/android_webview/native/aw_contents.h +++ b/android_webview/native/aw_contents.h @@ -10,29 +10,20 @@ #include <string> #include <utility> +#include "android_webview/browser/browser_view_renderer.h" #include "android_webview/browser/find_helper.h" #include "android_webview/browser/icon_helper.h" #include "android_webview/browser/renderer_host/aw_render_view_host_ext.h" -#include "android_webview/public/browser/draw_gl.h" #include "base/android/scoped_java_ref.h" #include "base/android/jni_helper.h" #include "base/callback_forward.h" #include "base/memory/scoped_ptr.h" -#include "content/public/browser/android/compositor.h" #include "content/public/browser/javascript_dialog_manager.h" -#include "skia/ext/refptr.h" -#include "third_party/skia/include/core/SkPicture.h" -typedef void* EGLContext; class SkBitmap; class TabContents; -namespace cc { -class Layer; -} - namespace content { -class Compositor; class WebContents; } @@ -47,8 +38,7 @@ class AwWebContentsDelegate; // level of indirection provided by the AwContentsContainer abstraction. class AwContents : public FindHelper::Listener, public IconHelper::Listener, - public content::Compositor::Client, - public AwRenderViewHostExt::Client { + public BrowserViewRenderer::Client { public: enum OnNewPictureMode { kOnNewPictureDisabled = 0, @@ -72,15 +62,6 @@ class AwContents : public FindHelper::Listener, return render_view_host_ext_.get(); } - void DrawGL(AwDrawGLInfo* draw_info); - bool DrawSW(JNIEnv* env, - jobject obj, - jobject canvas, - jint clip_x, - jint clip_y, - jint clip_w, - jint clip_h); - void RunJavaScriptDialog( content::JavaScriptMessageType message_type, const GURL& origin_url, @@ -127,9 +108,17 @@ class AwContents : public FindHelper::Listener, base::android::ScopedJavaLocalRef<jbyteArray> GetOpaqueState( JNIEnv* env, jobject obj); jboolean RestoreFromOpaqueState(JNIEnv* env, jobject obj, jbyteArray state); + void FocusFirstNode(JNIEnv* env, jobject obj); + bool DrawSW(JNIEnv* env, + jobject obj, + jobject canvas, + jint clip_x, + jint clip_y, + jint clip_w, + jint clip_h); void SetScrollForHWFrame(JNIEnv* env, jobject obj, int scroll_x, int scroll_y); - void FocusFirstNode(JNIEnv* env, jobject obj); + jint GetAwDrawGLViewContext(JNIEnv* env, jobject obj); base::android::ScopedJavaLocalRef<jobject> CapturePicture(JNIEnv* env, jobject obj); void EnableOnNewPicture(JNIEnv* env, @@ -150,8 +139,6 @@ class AwContents : public FindHelper::Listener, void FindAllAsync(JNIEnv* env, jobject obj, jstring search_string); void FindNext(JNIEnv* env, jobject obj, jboolean forward); void ClearMatches(JNIEnv* env, jobject obj); - void ClearCache(JNIEnv* env, jobject obj, jboolean include_disk_files); - FindHelper* GetFindHelper(); // FindHelper::Listener implementation. @@ -163,29 +150,17 @@ class AwContents : public FindHelper::Listener, virtual void OnReceivedTouchIconUrl(const std::string& url, const bool precomposed) OVERRIDE; - // content::Compositor::Client implementation. - virtual void ScheduleComposite() OVERRIDE; - virtual void OnSwapBuffersCompleted() OVERRIDE; + // BrowserViewRenderer::Client implementation. + virtual void Invalidate() OVERRIDE; + virtual void OnNewPicture( + const base::android::JavaRef<jobject>& picture) OVERRIDE; + void ClearCache(JNIEnv* env, jobject obj, jboolean include_disk_files); void SetPendingWebContentsForPopup(scoped_ptr<content::WebContents> pending); jint ReleasePopupWebContents(JNIEnv* env, jobject obj); - // AwRenderViewHostExt::Client implementation. - virtual void OnPictureUpdated(int process_id, int render_view_id) OVERRIDE; - - // Returns the latest locally available picture if any. - // If none is available will synchronously request the latest one - // and block until the result is received. - skia::RefPtr<SkPicture> GetLastCapturedPicture(); - private: - void Invalidate(); void SetWebContents(content::WebContents* web_contents); - void SetCompositorVisibility(bool visible); - void ResetCompositor(); - void AttachLayerTree(); - bool RenderSW(SkCanvas* canvas); - bool RenderPicture(SkCanvas* canvas); JavaObjectWeakGlobalRef java_ref_; scoped_ptr<content::WebContents> web_contents_; @@ -194,6 +169,7 @@ class AwContents : public FindHelper::Listener, scoped_ptr<FindHelper> find_helper_; scoped_ptr<IconHelper> icon_helper_; scoped_ptr<content::WebContents> pending_contents_; + scoped_ptr<BrowserViewRenderer> browser_view_renderer_; // GURL is supplied by the content layer as requesting frame. // Callback is supplied by the content layer, and is invoked with the result @@ -202,23 +178,6 @@ class AwContents : public FindHelper::Listener, // The first element in the list is always the currently pending request. std::list<OriginCallback> pending_geolocation_prompts_; - // Compositor-specific state. - scoped_ptr<content::Compositor> compositor_; - scoped_refptr<cc::Layer> scissor_clip_layer_; - scoped_refptr<cc::Layer> transform_layer_; - scoped_refptr<cc::Layer> view_clip_layer_; - gfx::Point hw_rendering_scroll_; - gfx::Size view_size_; - bool view_visible_; - bool compositor_visible_; - bool is_composite_pending_; - float dpi_scale_; - OnNewPictureMode on_new_picture_mode_; - - // 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/java_browser_view_renderer_helper.cc b/android_webview/native/java_browser_view_renderer_helper.cc new file mode 100644 index 0000000..1dfd9b2 --- /dev/null +++ b/android_webview/native/java_browser_view_renderer_helper.cc @@ -0,0 +1,47 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "android_webview/native/java_browser_view_renderer_helper.h" + +#include "jni/JavaBrowserViewRendererHelper_jni.h" + +using base::android::JavaRef; +using base::android::ScopedJavaLocalRef; + +namespace android_webview { + +JavaBrowserViewRendererHelper::JavaBrowserViewRendererHelper() { +} + +JavaBrowserViewRendererHelper::~JavaBrowserViewRendererHelper() { +} + +ScopedJavaLocalRef<jobject> JavaBrowserViewRendererHelper::CreateBitmap( + JNIEnv* env, + int width, + int height) { + return Java_JavaBrowserViewRendererHelper_createBitmap(env, width, height); +} + +void JavaBrowserViewRendererHelper::DrawBitmapIntoCanvas( + JNIEnv* env, + const JavaRef<jobject>& jbitmap, + const JavaRef<jobject>& jcanvas) { + Java_JavaBrowserViewRendererHelper_drawBitmapIntoCanvas( + env, jbitmap.obj(), jcanvas.obj()); +} + +ScopedJavaLocalRef<jobject> +JavaBrowserViewRendererHelper::RecordBitmapIntoPicture( + JNIEnv* env, + const JavaRef<jobject>& jbitmap) { + return Java_JavaBrowserViewRendererHelper_recordBitmapIntoPicture( + env, jbitmap.obj()); +} + +bool RegisterJavaBrowserViewRendererHelper(JNIEnv* env) { + return RegisterNativesImpl(env) >= 0; +} + +} // namespace android_webview diff --git a/android_webview/native/java_browser_view_renderer_helper.h b/android_webview/native/java_browser_view_renderer_helper.h new file mode 100644 index 0000000..d29be80 --- /dev/null +++ b/android_webview/native/java_browser_view_renderer_helper.h @@ -0,0 +1,39 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_NATIVE_JAVA_BROWSER_VIEW_RENDERER_HELPER_H_ +#define ANDROID_WEBVIEW_NATIVE_JAVA_BROWSER_VIEW_RENDERER_HELPER_H_ + +#include "android_webview/browser/browser_view_renderer.h" +#include "base/android/scoped_java_ref.h" +#include "base/compiler_specific.h" + +namespace android_webview { + +// Native side of java-class of same name. +// Provides utility methods for rendering involving with Java objects. +class JavaBrowserViewRendererHelper : public BrowserViewRenderer::JavaHelper { + public: + JavaBrowserViewRendererHelper(); + virtual ~JavaBrowserViewRendererHelper(); + + // BrowserViewRenderer::JavaHelper implementation. + virtual base::android::ScopedJavaLocalRef<jobject> CreateBitmap( + JNIEnv* env, + int width, + int height) OVERRIDE; + virtual void DrawBitmapIntoCanvas( + JNIEnv* env, + const base::android::JavaRef<jobject>& jbitmap, + const base::android::JavaRef<jobject>& jcanvas) OVERRIDE; + virtual base::android::ScopedJavaLocalRef<jobject> RecordBitmapIntoPicture( + JNIEnv* env, + const base::android::JavaRef<jobject>& jbitmap) OVERRIDE; +}; + +bool RegisterJavaBrowserViewRendererHelper(JNIEnv* env); + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_NATIVE_JAVA_BROWSER_VIEW_RENDERER_HELPER_H_ diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp index 1290683..cb9562a 100644 --- a/android_webview/native/webview_native.gyp +++ b/android_webview/native/webview_native.gyp @@ -13,7 +13,6 @@ '../../base/base.gyp:base_static', '../../components/components.gyp:web_contents_delegate_android', '../../skia/skia.gyp:skia', - '../../ui/gl/gl.gyp:gl', 'android_webview_native_jni', ], 'include_dirs': [ @@ -52,6 +51,8 @@ 'input_stream_impl.h', 'intercepted_request_data_impl.cc', 'intercepted_request_data_impl.h', + 'java_browser_view_renderer_helper.cc', + 'java_browser_view_renderer_helper.h', 'js_result_handler.cc', 'js_result_handler.h', 'net_init_native_callback.cc', @@ -82,6 +83,7 @@ '../java/src/org/chromium/android_webview/AwSettings.java', '../java/src/org/chromium/android_webview/AwWebContentsDelegate.java', '../java/src/org/chromium/android_webview/InterceptedRequestData.java', + '../java/src/org/chromium/android_webview/JavaBrowserViewRendererHelper.java', '../java/src/org/chromium/android_webview/JsResultHandler.java', ], 'variables': { diff --git a/android_webview/renderer/aw_content_renderer_client.cc b/android_webview/renderer/aw_content_renderer_client.cc index 9a8b21c..a1995a3 100644 --- a/android_webview/renderer/aw_content_renderer_client.cc +++ b/android_webview/renderer/aw_content_renderer_client.cc @@ -7,6 +7,7 @@ #include "android_webview/common/aw_resource.h" #include "android_webview/common/url_constants.h" #include "android_webview/renderer/aw_render_view_ext.h" +#include "android_webview/renderer/view_renderer.h" #include "base/utf_string_conversions.h" #include "components/visitedlink/renderer/visitedlink_slave.h" #include "content/public/renderer/render_thread.h" @@ -42,6 +43,7 @@ void AwContentRendererClient::RenderThreadStarted() { void AwContentRendererClient::RenderViewCreated( content::RenderView* render_view) { AwRenderViewExt::RenderViewCreated(render_view); + ViewRenderer::RenderViewCreated(render_view); } std::string AwContentRendererClient::GetDefaultEncoding() { diff --git a/android_webview/renderer/aw_render_view_ext.cc b/android_webview/renderer/aw_render_view_ext.cc index 462553e39..c895ed47 100644 --- a/android_webview/renderer/aw_render_view_ext.cc +++ b/android_webview/renderer/aw_render_view_ext.cc @@ -129,14 +129,9 @@ void PopulateHitTestData(const GURL& absolute_link_url, AwRenderViewExt::AwRenderViewExt(content::RenderView* render_view) : content::RenderViewObserver(render_view) { render_view->GetWebView()->setPermissionClient(this); - // TODO(leandrogracia): remove when SW rendering uses Ubercompositor. - // Until then we need the callback enabled for SW mode invalidation. - // http://crbug.com/170086. - capture_picture_enabled_ = true; } AwRenderViewExt::~AwRenderViewExt() { - RendererPictureMap::GetInstance()->ClearRendererPicture(routing_id()); } // static @@ -149,10 +144,6 @@ bool AwRenderViewExt::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(AwRenderViewExt, message) IPC_MESSAGE_HANDLER(AwViewMsg_DocumentHasImages, OnDocumentHasImagesRequest) IPC_MESSAGE_HANDLER(AwViewMsg_DoHitTest, OnDoHitTest) - IPC_MESSAGE_HANDLER(AwViewMsg_EnableCapturePictureCallback, - OnEnableCapturePictureCallback) - IPC_MESSAGE_HANDLER(AwViewMsg_CapturePictureSync, - OnCapturePictureSync) IPC_MESSAGE_HANDLER(AwViewMsg_SetTextZoomLevel, OnSetTextZoomLevel) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -227,15 +218,6 @@ void AwRenderViewExt::FocusedNodeChanged(const WebKit::WebNode& node) { Send(new AwViewHostMsg_UpdateHitTestData(routing_id(), data)); } -void AwRenderViewExt::DidCommitCompositorFrame() { - if (!capture_picture_enabled_) - return; - - skia::RefPtr<SkPicture> picture = render_view()->CapturePicture(); - RendererPictureMap::GetInstance()->SetRendererPicture(routing_id(), picture); - Send(new AwViewHostMsg_PictureUpdated(routing_id())); -} - void AwRenderViewExt::OnDoHitTest(int view_x, int view_y) { if (!render_view() || !render_view()->GetWebView()) return; @@ -257,15 +239,6 @@ void AwRenderViewExt::OnDoHitTest(int view_x, int view_y) { Send(new AwViewHostMsg_UpdateHitTestData(routing_id(), data)); } -void AwRenderViewExt::OnEnableCapturePictureCallback(bool enable) { - capture_picture_enabled_ = enable; -} - -void AwRenderViewExt::OnCapturePictureSync() { - RendererPictureMap::GetInstance()->SetRendererPicture( - routing_id(), render_view()->CapturePicture()); -} - void AwRenderViewExt::OnSetTextZoomLevel(double zoom_level) { if (!render_view() || !render_view()->GetWebView()) return; diff --git a/android_webview/renderer/aw_render_view_ext.h b/android_webview/renderer/aw_render_view_ext.h index 49cee36..8cea6e4 100644 --- a/android_webview/renderer/aw_render_view_ext.h +++ b/android_webview/renderer/aw_render_view_ext.h @@ -7,7 +7,6 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" -#include "base/memory/weak_ptr.h" #include "content/public/renderer/render_view_observer.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPermissionClient.h" @@ -28,9 +27,6 @@ class AwRenderViewExt : public content::RenderViewObserver, public: static void RenderViewCreated(content::RenderView* render_view); - // Required to be public by IPC_MESSAGE_HANDLER for sync messages. - using content::RenderViewObserver::Send; - private: AwRenderViewExt(content::RenderView* render_view); virtual ~AwRenderViewExt(); @@ -40,16 +36,11 @@ class AwRenderViewExt : public content::RenderViewObserver, virtual void DidCommitProvisionalLoad(WebKit::WebFrame* frame, bool is_new_navigation) OVERRIDE; virtual void FocusedNodeChanged(const WebKit::WebNode& node) OVERRIDE; - virtual void DidCommitCompositorFrame() OVERRIDE; void OnDocumentHasImagesRequest(int id); void OnDoHitTest(int view_x, int view_y); - void OnEnableCapturePictureCallback(bool enable); - - void OnCapturePictureSync(); - void OnSetTextZoomLevel(double zoom_level); // WebKit::WebPermissionClient implementation. diff --git a/android_webview/renderer/view_renderer.cc b/android_webview/renderer/view_renderer.cc new file mode 100644 index 0000000..dd0d7e7 --- /dev/null +++ b/android_webview/renderer/view_renderer.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "android_webview/renderer/view_renderer.h" + +#include "android_webview/common/render_view_messages.h" +#include "android_webview/common/renderer_picture_map.h" +#include "content/public/renderer/render_view.h" +#include "skia/ext/refptr.h" + +namespace android_webview { + +// static +void ViewRenderer::RenderViewCreated(content::RenderView* render_view) { + new ViewRenderer(render_view); // |render_view| takes ownership. +} + +ViewRenderer::ViewRenderer(content::RenderView* render_view) + : content::RenderViewObserver(render_view), + // TODO(leandrogracia): default to false when SW mode uses Ubercompositor. + // Until then we need picture updates enabled for SW mode invalidation. + // http://crbug.com/170086. + capture_picture_enabled_(true) { +} + +ViewRenderer::~ViewRenderer() { + RendererPictureMap::GetInstance()->ClearRendererPicture(routing_id()); +} + +bool ViewRenderer::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ViewRenderer, message) + IPC_MESSAGE_HANDLER(AwViewMsg_EnableCapturePictureCallback, + OnEnableCapturePictureCallback) + IPC_MESSAGE_HANDLER(AwViewMsg_CapturePictureSync, + OnCapturePictureSync) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void ViewRenderer::DidCommitCompositorFrame() { + if (!capture_picture_enabled_) + return; + + skia::RefPtr<SkPicture> picture = render_view()->CapturePicture(); + RendererPictureMap::GetInstance()->SetRendererPicture(routing_id(), picture); + Send(new AwViewHostMsg_PictureUpdated(routing_id())); +} + +void ViewRenderer::OnEnableCapturePictureCallback(bool enable) { + capture_picture_enabled_ = enable; +} + +void ViewRenderer::OnCapturePictureSync() { + RendererPictureMap::GetInstance()->SetRendererPicture( + routing_id(), render_view()->CapturePicture()); +} + +} // namespace android_webview diff --git a/android_webview/renderer/view_renderer.h b/android_webview/renderer/view_renderer.h new file mode 100644 index 0000000..8c4ba8f --- /dev/null +++ b/android_webview/renderer/view_renderer.h @@ -0,0 +1,39 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_RENDERER_VIEW_RENDERER_H_ +#define ANDROID_WEBVIEW_RENDERER_VIEW_RENDERER_H_ + +#include "content/public/renderer/render_view_observer.h" + +namespace android_webview { + +// Render-process side of ViewRendererHost. +// Implements required interaction with content::RenderView. +class ViewRenderer : public content::RenderViewObserver { + public: + static void RenderViewCreated(content::RenderView* render_view); + + // Required to be public by IPC_MESSAGE_HANDLER. + using content::RenderViewObserver::Send; + + private: + ViewRenderer(content::RenderView* render_view); + virtual ~ViewRenderer(); + + // content::RenderViewObserver implementation. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void DidCommitCompositorFrame() OVERRIDE; + + void OnEnableCapturePictureCallback(bool enable); + void OnCapturePictureSync(); + + bool capture_picture_enabled_; + + DISALLOW_COPY_AND_ASSIGN(ViewRenderer); +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_RENDERER_VIEW_RENDERER_H_ |