diff options
Diffstat (limited to 'android_webview/browser/browser_view_renderer_impl.cc')
-rw-r--r-- | android_webview/browser/browser_view_renderer_impl.cc | 571 |
1 files changed, 0 insertions, 571 deletions
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 bfd8f4b..0000000 --- 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 |