This source file includes following definitions.
- lock_
- height_
- OnDraw
- DidDrawGL
- DrawSWInternal
- CapturePicture
- EnableOnNewPicture
- ClearView
- SetIsPaused
- SetViewVisibility
- SetWindowVisibility
- OnSizeChanged
- OnAttachedToWindow
- OnDetachedFromWindow
- IsAttachedToWindow
- IsVisible
- GetScreenRect
- DidInitializeCompositor
- DidDestroyCompositor
- SetContinuousInvalidate
- SetDipScale
- max_scroll_offset
- ScrollTo
- DidUpdateContent
- SetMaxRootLayerScrollOffset
- SetTotalRootLayerScrollOffset
- GetTotalRootLayerScrollOffset
- IsExternalFlingActive
- SetRootLayerPageScaleFactorAndLimits
- SetRootLayerScrollableSize
- DidOverscroll
- EnsureContinuousInvalidation
- FallbackTickFired
- ForceFakeCompositeSW
- CompositeSW
- DidComposite
- ToString
#include "android_webview/browser/browser_view_renderer.h"
#include "android_webview/browser/browser_view_renderer_client.h"
#include "android_webview/browser/shared_renderer_state.h"
#include "android_webview/public/browser/draw_gl.h"
#include "base/android/jni_android.h"
#include "base/auto_reset.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/android/synchronous_compositor.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/SkPicture.h"
#include "ui/gfx/vector2d_conversions.h"
using base::android::AttachCurrentThread;
using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
namespace android_webview {
namespace {
const int64 kFallbackTickTimeoutInMilliseconds = 20;
class AutoResetWithLock {
public:
AutoResetWithLock(gfx::Vector2dF* scoped_variable,
gfx::Vector2dF new_value,
base::Lock& lock)
: scoped_variable_(scoped_variable),
original_value_(*scoped_variable),
lock_(lock) {
base::AutoLock auto_lock(lock_);
*scoped_variable_ = new_value;
}
~AutoResetWithLock() {
base::AutoLock auto_lock(lock_);
*scoped_variable_ = original_value_;
}
private:
gfx::Vector2dF* scoped_variable_;
gfx::Vector2dF original_value_;
base::Lock& lock_;
DISALLOW_COPY_AND_ASSIGN(AutoResetWithLock);
};
}
BrowserViewRenderer::BrowserViewRenderer(
BrowserViewRendererClient* client,
SharedRendererState* shared_renderer_state,
content::WebContents* web_contents,
const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
: client_(client),
shared_renderer_state_(shared_renderer_state),
web_contents_(web_contents),
weak_factory_on_ui_thread_(this),
ui_thread_weak_ptr_(weak_factory_on_ui_thread_.GetWeakPtr()),
ui_task_runner_(ui_task_runner),
has_compositor_(false),
is_paused_(false),
view_visible_(false),
window_visible_(false),
attached_to_window_(false),
dip_scale_(0.0),
page_scale_factor_(1.0),
on_new_picture_enable_(false),
clear_view_(false),
compositor_needs_continuous_invalidate_(false),
block_invalidates_(false),
width_(0),
height_(0) {
CHECK(web_contents_);
content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
}
BrowserViewRenderer::~BrowserViewRenderer() {
content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
}
bool BrowserViewRenderer::OnDraw(jobject java_canvas,
bool is_hardware_canvas,
const gfx::Vector2d& scroll,
const gfx::Rect& global_visible_rect,
const gfx::Rect& clip) {
draw_gl_input_.frame_id++;
draw_gl_input_.scroll_offset = scroll;
draw_gl_input_.global_visible_rect = global_visible_rect;
if (clear_view_)
return false;
if (is_hardware_canvas && attached_to_window_) {
shared_renderer_state_->SetDrawGLInput(draw_gl_input_);
return has_compositor_ && client_->RequestDrawGL(java_canvas);
}
return DrawSWInternal(java_canvas, clip);
}
void BrowserViewRenderer::DidDrawGL(const DrawGLResult& result) {
DidComposite(!result.clip_contains_visible_rect);
}
bool BrowserViewRenderer::DrawSWInternal(jobject java_canvas,
const gfx::Rect& clip) {
if (clip.IsEmpty()) {
TRACE_EVENT_INSTANT0(
"android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
return true;
}
if (!has_compositor_) {
TRACE_EVENT_INSTANT0(
"android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
return false;
}
return BrowserViewRendererJavaHelper::GetInstance()
->RenderViaAuxilaryBitmapIfNeeded(
java_canvas,
draw_gl_input_.scroll_offset,
clip,
base::Bind(&BrowserViewRenderer::CompositeSW,
base::Unretained(this)));
}
skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
int height) {
TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
if (width <= 0 || height <= 0) {
return picture;
}
AutoResetWithLock scroll_reset(
&scroll_offset_dip_, gfx::Vector2dF(), scroll_offset_dip_lock_);
SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
if (has_compositor_)
CompositeSW(rec_canvas);
picture->endRecording();
return picture;
}
void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
on_new_picture_enable_ = enabled;
}
void BrowserViewRenderer::ClearView() {
TRACE_EVENT_INSTANT0("android_webview",
"BrowserViewRenderer::ClearView",
TRACE_EVENT_SCOPE_THREAD);
if (clear_view_)
return;
clear_view_ = true;
EnsureContinuousInvalidation(true);
}
void BrowserViewRenderer::SetIsPaused(bool paused) {
TRACE_EVENT_INSTANT1("android_webview",
"BrowserViewRenderer::SetIsPaused",
TRACE_EVENT_SCOPE_THREAD,
"paused",
paused);
is_paused_ = paused;
EnsureContinuousInvalidation(false);
}
void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
TRACE_EVENT_INSTANT1("android_webview",
"BrowserViewRenderer::SetViewVisibility",
TRACE_EVENT_SCOPE_THREAD,
"view_visible",
view_visible);
view_visible_ = view_visible;
}
void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
TRACE_EVENT_INSTANT1("android_webview",
"BrowserViewRenderer::SetWindowVisibility",
TRACE_EVENT_SCOPE_THREAD,
"window_visible",
window_visible);
window_visible_ = window_visible;
EnsureContinuousInvalidation(false);
}
void BrowserViewRenderer::OnSizeChanged(int width, int height) {
TRACE_EVENT_INSTANT2("android_webview",
"BrowserViewRenderer::OnSizeChanged",
TRACE_EVENT_SCOPE_THREAD,
"width",
width,
"height",
height);
width_ = width;
height_ = height;
}
void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
TRACE_EVENT2("android_webview",
"BrowserViewRenderer::OnAttachedToWindow",
"width",
width,
"height",
height);
attached_to_window_ = true;
width_ = width;
height_ = height;
}
void BrowserViewRenderer::OnDetachedFromWindow() {
TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
attached_to_window_ = false;
}
bool BrowserViewRenderer::IsAttachedToWindow() const {
return attached_to_window_;
}
bool BrowserViewRenderer::IsVisible() const {
return view_visible_ && (!attached_to_window_ || window_visible_);
}
gfx::Rect BrowserViewRenderer::GetScreenRect() const {
return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
}
void BrowserViewRenderer::DidInitializeCompositor(
content::SynchronousCompositor* compositor) {
TRACE_EVENT0("android_webview",
"BrowserViewRenderer::DidInitializeCompositor");
DCHECK(compositor);
DCHECK(!has_compositor_);
DCHECK(ui_task_runner_->BelongsToCurrentThread());
has_compositor_ = true;
shared_renderer_state_->SetCompositorOnUiThread(compositor);
}
void BrowserViewRenderer::DidDestroyCompositor(
content::SynchronousCompositor* compositor) {
TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
DCHECK(has_compositor_);
DCHECK(ui_task_runner_->BelongsToCurrentThread());
has_compositor_ = false;
shared_renderer_state_->SetCompositorOnUiThread(NULL);
}
void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
if (!ui_task_runner_->BelongsToCurrentThread()) {
ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&BrowserViewRenderer::SetContinuousInvalidate,
ui_thread_weak_ptr_,
invalidate));
return;
}
if (compositor_needs_continuous_invalidate_ == invalidate)
return;
TRACE_EVENT_INSTANT1("android_webview",
"BrowserViewRenderer::SetContinuousInvalidate",
TRACE_EVENT_SCOPE_THREAD,
"invalidate",
invalidate);
compositor_needs_continuous_invalidate_ = invalidate;
EnsureContinuousInvalidation(false);
}
void BrowserViewRenderer::SetDipScale(float dip_scale) {
dip_scale_ = dip_scale;
CHECK(dip_scale_ > 0);
}
gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
DCHECK_GT(dip_scale_, 0);
return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
}
void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
gfx::Vector2d max_offset = max_scroll_offset();
gfx::Vector2dF scroll_offset_dip;
if (max_offset.x()) {
scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
max_offset.x());
}
if (max_offset.y()) {
scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
max_offset.y());
}
DCHECK_LE(0, scroll_offset_dip.x());
DCHECK_LE(0, scroll_offset_dip.y());
DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
{
base::AutoLock lock(scroll_offset_dip_lock_);
if (scroll_offset_dip_ == scroll_offset_dip)
return;
scroll_offset_dip_ = scroll_offset_dip;
}
if (has_compositor_)
shared_renderer_state_->GetCompositor()->
DidChangeRootLayerScrollOffset();
}
void BrowserViewRenderer::DidUpdateContent() {
if (!ui_task_runner_->BelongsToCurrentThread()) {
ui_task_runner_->PostTask(FROM_HERE,
base::Bind(&BrowserViewRenderer::DidUpdateContent,
ui_thread_weak_ptr_));
return;
}
TRACE_EVENT_INSTANT0("android_webview",
"BrowserViewRenderer::DidUpdateContent",
TRACE_EVENT_SCOPE_THREAD);
clear_view_ = false;
if (on_new_picture_enable_)
client_->OnNewPicture();
}
void BrowserViewRenderer::SetMaxRootLayerScrollOffset(
gfx::Vector2dF new_value_dip) {
if (!ui_task_runner_->BelongsToCurrentThread()) {
ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&BrowserViewRenderer::SetMaxRootLayerScrollOffset,
ui_thread_weak_ptr_,
new_value_dip));
return;
}
DCHECK_GT(dip_scale_, 0);
max_scroll_offset_dip_ = new_value_dip;
DCHECK_LE(0, max_scroll_offset_dip_.x());
DCHECK_LE(0, max_scroll_offset_dip_.y());
client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
}
void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
gfx::Vector2dF scroll_offset_dip) {
if (!ui_task_runner_->BelongsToCurrentThread()) {
ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&BrowserViewRenderer::SetTotalRootLayerScrollOffset,
ui_thread_weak_ptr_,
scroll_offset_dip));
return;
}
{
base::AutoLock lock(scroll_offset_dip_lock_);
if (scroll_offset_dip_ == scroll_offset_dip)
return;
scroll_offset_dip_ = scroll_offset_dip;
}
gfx::Vector2d max_offset = max_scroll_offset();
gfx::Vector2d scroll_offset;
if (max_scroll_offset_dip_.x()) {
scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
max_scroll_offset_dip_.x());
}
if (max_scroll_offset_dip_.y()) {
scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
max_scroll_offset_dip_.y());
}
DCHECK(0 <= scroll_offset.x());
DCHECK(0 <= scroll_offset.y());
client_->ScrollContainerViewTo(scroll_offset);
}
gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
base::AutoLock lock(scroll_offset_dip_lock_);
return scroll_offset_dip_;
}
bool BrowserViewRenderer::IsExternalFlingActive() const {
if (!ui_task_runner_->BelongsToCurrentThread()) {
return false;
}
return client_->IsFlingActive();
}
void BrowserViewRenderer::SetRootLayerPageScaleFactorAndLimits(
float page_scale_factor,
float min_page_scale_factor,
float max_page_scale_factor) {
if (!ui_task_runner_->BelongsToCurrentThread()) {
ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&BrowserViewRenderer::SetRootLayerPageScaleFactorAndLimits,
ui_thread_weak_ptr_,
page_scale_factor,
min_page_scale_factor,
max_page_scale_factor));
return;
}
page_scale_factor_ = page_scale_factor;
DCHECK_GT(page_scale_factor_, 0);
client_->SetPageScaleFactorAndLimits(
page_scale_factor, min_page_scale_factor, max_page_scale_factor);
client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
}
void BrowserViewRenderer::SetRootLayerScrollableSize(
gfx::SizeF scrollable_size) {
if (!ui_task_runner_->BelongsToCurrentThread()) {
ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&BrowserViewRenderer::SetRootLayerScrollableSize,
ui_thread_weak_ptr_,
scrollable_size));
return;
}
client_->SetContentsSize(scrollable_size);
}
void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
gfx::Vector2dF latest_overscroll_delta,
gfx::Vector2dF current_fling_velocity) {
if (!ui_task_runner_->BelongsToCurrentThread()) {
ui_task_runner_->PostTask(
FROM_HERE,
base::Bind(&BrowserViewRenderer::DidOverscroll,
ui_thread_weak_ptr_,
accumulated_overscroll,
latest_overscroll_delta,
current_fling_velocity));
return;
}
const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
if (accumulated_overscroll == latest_overscroll_delta)
overscroll_rounding_error_ = gfx::Vector2dF();
gfx::Vector2dF scaled_overscroll_delta =
gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
scaled_overscroll_delta + overscroll_rounding_error_);
overscroll_rounding_error_ =
scaled_overscroll_delta - rounded_overscroll_delta;
client_->DidOverscroll(rounded_overscroll_delta);
}
void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate) {
bool need_invalidate =
compositor_needs_continuous_invalidate_ || force_invalidate;
if (!need_invalidate || block_invalidates_)
return;
client_->PostInvalidate();
bool throttle_fallback_tick =
(is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
if (throttle_fallback_tick)
return;
block_invalidates_ = compositor_needs_continuous_invalidate_;
fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
base::Unretained(this)));
if (compositor_needs_continuous_invalidate_) {
ui_task_runner_->PostDelayedTask(
FROM_HERE,
fallback_tick_.callback(),
base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
}
}
void BrowserViewRenderer::FallbackTickFired() {
TRACE_EVENT1("android_webview",
"BrowserViewRenderer::FallbackTickFired",
"compositor_needs_continuous_invalidate_",
compositor_needs_continuous_invalidate_);
DCHECK(block_invalidates_);
if (compositor_needs_continuous_invalidate_ && has_compositor_)
ForceFakeCompositeSW();
}
void BrowserViewRenderer::ForceFakeCompositeSW() {
DCHECK(has_compositor_);
SkBitmap bitmap;
bitmap.allocN32Pixels(1, 1);
bitmap.eraseColor(0);
SkCanvas canvas(bitmap);
CompositeSW(&canvas);
}
bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
DCHECK(has_compositor_);
bool result = shared_renderer_state_->GetCompositor()->
DemandDrawSw(canvas);
DidComposite(false);
return result;
}
void BrowserViewRenderer::DidComposite(bool force_invalidate) {
fallback_tick_.Cancel();
block_invalidates_ = false;
EnsureContinuousInvalidation(force_invalidate);
}
std::string BrowserViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
std::string str;
base::StringAppendF(&str, "is_paused: %d ", is_paused_);
base::StringAppendF(&str, "view_visible: %d ", view_visible_);
base::StringAppendF(&str, "window_visible: %d ", window_visible_);
base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
base::StringAppendF(&str,
"compositor_needs_continuous_invalidate: %d ",
compositor_needs_continuous_invalidate_);
base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
base::StringAppendF(&str,
"global visible rect: %s ",
draw_gl_input_.global_visible_rect.ToString().c_str());
base::StringAppendF(
&str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
base::StringAppendF(&str,
"overscroll_rounding_error_: %s ",
overscroll_rounding_error_.ToString().c_str());
base::StringAppendF(
&str, "on_new_picture_enable: %d ", on_new_picture_enable_);
base::StringAppendF(&str, "clear_view: %d ", clear_view_);
if (draw_info) {
base::StringAppendF(&str,
"clip left top right bottom: [%d %d %d %d] ",
draw_info->clip_left,
draw_info->clip_top,
draw_info->clip_right,
draw_info->clip_bottom);
base::StringAppendF(&str,
"surface width height: [%d %d] ",
draw_info->width,
draw_info->height);
base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
}
return str;
}
}