Index: android_webview/browser/browser_view_renderer_impl.cc |
diff --git a/android_webview/browser/browser_view_renderer_impl.cc b/android_webview/browser/browser_view_renderer_impl.cc |
deleted file mode 100644 |
index bfd8f4b6355a2bc19f8ab6d6b90d0bcb432e650a..0000000000000000000000000000000000000000 |
--- a/android_webview/browser/browser_view_renderer_impl.cc |
+++ /dev/null |
@@ -1,571 +0,0 @@ |
-// 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 "android_webview/browser/in_process_view_renderer.h" |
-#include "android_webview/common/aw_switches.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/command_line.h" |
-#include "base/debug/trace_event.h" |
-#include "base/logging.h" |
-#include "cc/layers/layer.h" |
-#include "content/public/browser/android/content_view_core.h" |
-#include "content/public/browser/render_process_host.h" |
-#include "content/public/browser/render_view_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_conversions.h" |
-#include "ui/gfx/transform.h" |
-#include "ui/gfx/vector2d_f.h" |
-#include "ui/gl/gl_bindings.h" |
- |
-using base::android::AttachCurrentThread; |
-using base::android::JavaRef; |
-using base::android::ScopedJavaLocalRef; |
-using content::Compositor; |
-using content::ContentViewCore; |
- |
-namespace android_webview { |
- |
-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; |
- |
-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; |
-} |
- |
-bool RenderPictureToCanvas(SkPicture* picture, SkCanvas* canvas) { |
- canvas->drawPicture(*picture); |
- return true; |
-} |
- |
-const void* kUserDataKey = &kUserDataKey; |
- |
-} // namespace |
- |
-class BrowserViewRendererImpl::UserData : public content::WebContents::Data { |
- public: |
- UserData(BrowserViewRendererImpl* ptr) : instance_(ptr) {} |
- virtual ~UserData() { |
- instance_->WebContentsGone(); |
- } |
- |
- static BrowserViewRendererImpl* GetInstance(content::WebContents* contents) { |
- if (!contents) |
- return NULL; |
- UserData* data = reinterpret_cast<UserData*>( |
- contents->GetUserData(kUserDataKey)); |
- return data ? data->instance_ : NULL; |
- } |
- |
- private: |
- BrowserViewRendererImpl* instance_; |
-}; |
- |
-// static |
-BrowserViewRenderer* BrowserViewRendererImpl::Create( |
- BrowserViewRenderer::Client* client, |
- JavaHelper* java_helper) { |
- if (CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kNoMergeUIAndRendererCompositorThreads)) { |
- return new BrowserViewRendererImpl(client, java_helper); |
- } |
- |
- return new InProcessViewRenderer(client, java_helper); |
-} |
- |
-// static |
-BrowserViewRendererImpl* BrowserViewRendererImpl::FromWebContents( |
- content::WebContents* contents) { |
- return UserData::GetInstance(contents); |
-} |
- |
-BrowserViewRendererImpl::BrowserViewRendererImpl( |
- BrowserViewRenderer::Client* client, |
- JavaHelper* java_helper) |
- : client_(client), |
- java_helper_(java_helper), |
- view_renderer_host_(new ViewRendererHost(NULL, this)), |
- compositor_(Compositor::Create(this)), |
- view_clip_layer_(cc::Layer::Create()), |
- transform_layer_(cc::Layer::Create()), |
- scissor_clip_layer_(cc::Layer::Create()), |
- view_attached_(false), |
- view_visible_(false), |
- compositor_visible_(false), |
- is_composite_pending_(false), |
- dpi_scale_(1.0f), |
- page_scale_(1.0f), |
- new_picture_enabled_(false), |
- last_frame_context_(NULL), |
- web_contents_(NULL), |
- update_frame_info_callback_( |
- base::Bind(&BrowserViewRendererImpl::OnFrameInfoUpdated, |
- base::Unretained(this))), |
- prevent_client_invalidate_(false) { |
- |
- 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() { |
- SetContents(NULL); |
-} |
- |
-// static |
-void BrowserViewRenderer::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."; |
-} |
- |
-// static |
-AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() { |
- return g_sw_draw_functions; |
-} |
- |
-// static |
-bool BrowserViewRenderer::IsSkiaVersionCompatible() { |
- DCHECK(g_sw_draw_functions); |
- return g_is_skia_version_compatible; |
-} |
- |
-void BrowserViewRendererImpl::SetContents(ContentViewCore* content_view_core) { |
- // First remove association from the prior ContentViewCore / WebContents. |
- if (web_contents_) { |
- ContentViewCore* previous_content_view_core = |
- ContentViewCore::FromWebContents(web_contents_); |
- if (previous_content_view_core) { |
- previous_content_view_core->RemoveFrameInfoCallback( |
- update_frame_info_callback_); |
- } |
- web_contents_->SetUserData(kUserDataKey, NULL); |
- DCHECK(!web_contents_); // WebContentsGone should have been called. |
- } |
- |
- if (!content_view_core) |
- return; |
- |
- web_contents_ = content_view_core->GetWebContents(); |
- web_contents_->SetUserData(kUserDataKey, new UserData(this)); |
- view_renderer_host_->Observe(web_contents_); |
- |
- content_view_core->AddFrameInfoCallback(update_frame_info_callback_); |
- dpi_scale_ = content_view_core->GetDpiScale(); |
- |
- view_clip_layer_->RemoveAllChildren(); |
- view_clip_layer_->AddChild(content_view_core->GetLayer()); |
- Invalidate(); |
-} |
- |
-void BrowserViewRendererImpl::WebContentsGone() { |
- web_contents_ = NULL; |
-} |
- |
-bool BrowserViewRendererImpl::PrepareDrawGL(int x, int y) { |
- hw_rendering_scroll_ = gfx::Point(x, y); |
- return true; |
-} |
- |
-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; |
- |
- // 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)); |
- |
- // We need to trigger a compositor invalidate because otherwise, if nothing |
- // has changed since last draw the compositor will early out (Android may |
- // trigger a draw at anytime). However, we don't want to trigger a client |
- // (i.e. Android View system) invalidate as a result of this (otherwise we'll |
- // end up in a loop of DrawGL calls). |
- prevent_client_invalidate_ = true; |
- compositor_->SetNeedsRedraw(); |
- prevent_client_invalidate_ = false; |
- |
- 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; |
- |
- // The GL functor must ensure these are set to zero before returning. |
- // Not setting them leads to graphical artifacts that can affect other apps. |
- glBindBuffer(GL_ARRAY_BUFFER, 0); |
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
-} |
- |
-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(), true)); |
- 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, |
- clip.x(), clip.y()); |
- 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() { |
- if (!g_sw_draw_functions) |
- return ScopedJavaLocalRef<jobject>(); |
- |
- gfx::Size record_size = ToCeiledSize(content_size_css_); |
- |
- // Return empty Picture objects for empty SkPictures. |
- JNIEnv* env = AttachCurrentThread(); |
- if (record_size.width() <= 0 || record_size.height() <= 0) { |
- return java_helper_->RecordBitmapIntoPicture( |
- env, ScopedJavaLocalRef<jobject>()); |
- } |
- |
- skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); |
- SkCanvas* rec_canvas = picture->beginRecording(record_size.width(), |
- record_size.height(), |
- 0); |
- if (!RenderPicture(rec_canvas)) |
- return ScopedJavaLocalRef<jobject>(); |
- picture->endRecording(); |
- |
- if (g_is_skia_version_compatible) { |
- // Add a reference that the create_picture() will take ownership of. |
- picture->ref(); |
- return ScopedJavaLocalRef<jobject>(env, |
- g_sw_draw_functions->create_picture(env, picture.get())); |
- } |
- |
- // 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(), false)); |
- if (!jbitmap.obj()) |
- return ScopedJavaLocalRef<jobject>(); |
- |
- if (!RasterizeIntoBitmap(env, jbitmap, 0, 0, |
- base::Bind(&RenderPictureToCanvas, |
- base::Unretained(picture.get())))) { |
- return ScopedJavaLocalRef<jobject>(); |
- } |
- |
- return java_helper_->RecordBitmapIntoPicture(env, jbitmap); |
-} |
- |
-void BrowserViewRendererImpl::EnableOnNewPicture(bool enabled) { |
- new_picture_enabled_ = enabled; |
- |
- // 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); |
- // http://crbug.com/176945 |
-} |
- |
-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_attached_ = true; |
- view_size_ = gfx::Size(width, height); |
- view_clip_layer_->SetBounds(view_size_); |
-} |
- |
-void BrowserViewRendererImpl::OnDetachedFromWindow() { |
- view_attached_ = false; |
- view_visible_ = false; |
- SetCompositorVisibility(false); |
-} |
- |
-bool BrowserViewRendererImpl::IsAttachedToWindow() { |
- return view_attached_; |
-} |
- |
-bool BrowserViewRendererImpl::IsViewVisible() { |
- return view_visible_; |
-} |
- |
-gfx::Rect BrowserViewRendererImpl::GetScreenRect() { |
- return gfx::Rect(client_->GetLocationOnScreen(), view_size_); |
-} |
- |
-void BrowserViewRendererImpl::ScheduleComposite() { |
- TRACE_EVENT0("android_webview", "BrowserViewRendererImpl::ScheduleComposite"); |
- |
- if (is_composite_pending_) |
- return; |
- |
- is_composite_pending_ = true; |
- |
- if (!prevent_client_invalidate_) |
- Invalidate(); |
-} |
- |
-skia::RefPtr<SkPicture> BrowserViewRendererImpl::GetLastCapturedPicture() { |
- // Use the latest available picture if the listener callback is enabled. |
- skia::RefPtr<SkPicture> picture = |
- RendererPictureMap::GetInstance()->GetRendererPicture( |
- web_contents_->GetRoutingID()); |
- if (picture) return picture; |
- |
- // Get it synchronously. |
- view_renderer_host_->CapturePictureSync(); |
- return RendererPictureMap::GetInstance()->GetRendererPicture( |
- web_contents_->GetRoutingID()); |
-} |
- |
-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; |
- |
- client_->OnNewPicture(); |
- |
- // TODO(mkosiba): Remove when invalidation path is re-implemented. |
- 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(); |
-} |
- |
-bool BrowserViewRendererImpl::RenderSW(SkCanvas* canvas) { |
- float content_scale = dpi_scale_ * page_scale_; |
- canvas->scale(content_scale, content_scale); |
- |
- // Clear to white any parts of the view not covered by the scaled contents. |
- // TODO(leandrogracia): this should be automatically done by the SW rendering |
- // path once multiple layers are supported. |
- gfx::Size physical_content_size = gfx::ToCeiledSize( |
- gfx::ScaleSize(content_size_css_, content_scale)); |
- if (physical_content_size.width() < view_size_.width() || |
- physical_content_size.height() < view_size_.height()) |
- canvas->clear(SK_ColorWHITE); |
- |
- // TODO(leandrogracia): use the appropriate SW rendering path when available |
- // instead of abusing CapturePicture. |
- return RenderPicture(canvas); |
-} |
- |
-bool BrowserViewRendererImpl::RenderPicture(SkCanvas* canvas) { |
- skia::RefPtr<SkPicture> picture = GetLastCapturedPicture(); |
- if (!picture) |
- return false; |
- |
- picture->draw(canvas); |
- return true; |
-} |
- |
-void BrowserViewRendererImpl::OnFrameInfoUpdated( |
- const gfx::SizeF& content_size, |
- const gfx::Vector2dF& scroll_offset, |
- float page_scale_factor) { |
- page_scale_ = page_scale_factor; |
- content_size_css_ = content_size; |
-} |
- |
-} // namespace android_webview |