Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / android_webview / browser / browser_view_renderer.cc
blob4bf5e4bd1c06dd6214f0e020d4474ee9f39f2b8f
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "android_webview/browser/browser_view_renderer.h"
7 #include "android_webview/browser/browser_view_renderer_client.h"
8 #include "android_webview/browser/child_frame.h"
9 #include "base/auto_reset.h"
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/supports_user_data.h"
15 #include "base/trace_event/trace_event_argument.h"
16 #include "cc/output/compositor_frame.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/common/content_switches.h"
19 #include "gpu/command_buffer/service/gpu_switches.h"
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "third_party/skia/include/core/SkCanvas.h"
22 #include "third_party/skia/include/core/SkPicture.h"
23 #include "third_party/skia/include/core/SkPictureRecorder.h"
24 #include "ui/gfx/geometry/scroll_offset.h"
25 #include "ui/gfx/geometry/vector2d_conversions.h"
27 namespace android_webview {
29 namespace {
31 const double kEpsilon = 1e-8;
33 const int64 kFallbackTickTimeoutInMilliseconds = 100;
35 // Used to calculate memory allocation. Determined experimentally.
36 const size_t kMemoryMultiplier = 20;
37 const size_t kBytesPerPixel = 4;
38 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
39 uint64 g_memory_override_in_bytes = 0u;
41 const void* kBrowserViewRendererUserDataKey = &kBrowserViewRendererUserDataKey;
43 class BrowserViewRendererUserData : public base::SupportsUserData::Data {
44 public:
45 BrowserViewRendererUserData(BrowserViewRenderer* ptr) : bvr_(ptr) {}
47 static BrowserViewRenderer* GetBrowserViewRenderer(
48 content::WebContents* web_contents) {
49 if (!web_contents)
50 return NULL;
51 BrowserViewRendererUserData* data =
52 static_cast<BrowserViewRendererUserData*>(
53 web_contents->GetUserData(kBrowserViewRendererUserDataKey));
54 return data ? data->bvr_ : NULL;
57 private:
58 BrowserViewRenderer* bvr_;
61 } // namespace
63 // static
64 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
65 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
67 // If the value was overridden on the command line, use the specified value.
68 bool client_hard_limit_bytes_overridden =
69 cl->HasSwitch(switches::kForceGpuMemAvailableMb);
70 if (client_hard_limit_bytes_overridden) {
71 base::StringToUint64(
72 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
73 switches::kForceGpuMemAvailableMb),
74 &g_memory_override_in_bytes);
75 g_memory_override_in_bytes *= 1024 * 1024;
79 // static
80 BrowserViewRenderer* BrowserViewRenderer::FromWebContents(
81 content::WebContents* web_contents) {
82 return BrowserViewRendererUserData::GetBrowserViewRenderer(web_contents);
85 BrowserViewRenderer::BrowserViewRenderer(
86 BrowserViewRendererClient* client,
87 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
88 : client_(client),
89 shared_renderer_state_(ui_task_runner, this),
90 ui_task_runner_(ui_task_runner),
91 compositor_(NULL),
92 is_paused_(false),
93 view_visible_(false),
94 window_visible_(false),
95 attached_to_window_(false),
96 hardware_enabled_(false),
97 dip_scale_(0.f),
98 page_scale_factor_(1.f),
99 min_page_scale_factor_(0.f),
100 max_page_scale_factor_(0.f),
101 on_new_picture_enable_(false),
102 clear_view_(false),
103 offscreen_pre_raster_(false),
104 fallback_tick_pending_(false) {}
106 BrowserViewRenderer::~BrowserViewRenderer() {
109 void BrowserViewRenderer::RegisterWithWebContents(
110 content::WebContents* web_contents) {
111 web_contents->SetUserData(kBrowserViewRendererUserDataKey,
112 new BrowserViewRendererUserData(this));
115 SharedRendererState* BrowserViewRenderer::GetAwDrawGLViewContext() {
116 return &shared_renderer_state_;
119 bool BrowserViewRenderer::RequestDrawGL(bool wait_for_completion) {
120 return client_->RequestDrawGL(wait_for_completion);
123 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
124 DCHECK(ui_task_runner_->BelongsToCurrentThread());
125 // Constants from Android ComponentCallbacks2.
126 enum {
127 TRIM_MEMORY_RUNNING_LOW = 10,
128 TRIM_MEMORY_UI_HIDDEN = 20,
129 TRIM_MEMORY_BACKGROUND = 40,
130 TRIM_MEMORY_MODERATE = 60,
133 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
134 // it does not indicate memory pressure, but merely that the app is
135 // backgrounded.
136 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
137 return;
139 // Do not release resources on view we expect to get DrawGL soon.
140 if (level < TRIM_MEMORY_BACKGROUND && visible)
141 return;
143 // Nothing to drop.
144 if (!compositor_ || !hardware_enabled_)
145 return;
147 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
149 // If offscreen pre-raster is disabled, drop everything in hardware. Otherwise
150 // keep the tiles and just delete the HardwareRenderer.
151 if (level >= TRIM_MEMORY_MODERATE) {
152 if (offscreen_pre_raster_)
153 shared_renderer_state_.DeleteHardwareRendererOnUI();
154 else
155 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
156 return;
159 // Just set the memory limit to 0 and drop all tiles. This will be reset to
160 // normal levels in the next DrawGL call.
161 if (!offscreen_pre_raster_)
162 compositor_->SetMemoryPolicy(0u);
165 void BrowserViewRenderer::UpdateMemoryPolicy() {
166 if (!hardware_enabled_) {
167 compositor_->SetMemoryPolicy(0u);
168 return;
171 size_t bytes_limit = 0u;
172 if (g_memory_override_in_bytes) {
173 bytes_limit = static_cast<size_t>(g_memory_override_in_bytes);
174 } else {
175 ParentCompositorDrawConstraints parent_draw_constraints =
176 shared_renderer_state_.GetParentDrawConstraintsOnUI();
177 gfx::Rect interest_rect =
178 offscreen_pre_raster_ || parent_draw_constraints.is_layer
179 ? gfx::Rect(size_)
180 : last_on_draw_global_visible_rect_;
181 size_t width = interest_rect.width();
182 size_t height = interest_rect.height();
183 bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
184 // Round up to a multiple of kMemoryAllocationStep.
185 bytes_limit =
186 (bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
189 compositor_->SetMemoryPolicy(bytes_limit);
192 void BrowserViewRenderer::PrepareToDraw(const gfx::Vector2d& scroll,
193 const gfx::Rect& global_visible_rect) {
194 last_on_draw_scroll_offset_ = scroll;
195 last_on_draw_global_visible_rect_ = global_visible_rect;
198 bool BrowserViewRenderer::CanOnDraw() {
199 if (!compositor_) {
200 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_NoCompositor",
201 TRACE_EVENT_SCOPE_THREAD);
202 return false;
204 if (clear_view_) {
205 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_ClearView",
206 TRACE_EVENT_SCOPE_THREAD);
207 return false;
210 return true;
213 bool BrowserViewRenderer::OnDrawHardware() {
214 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
216 shared_renderer_state_.InitializeHardwareDrawIfNeededOnUI();
218 if (!CanOnDraw()) {
219 return false;
222 shared_renderer_state_.SetScrollOffsetOnUI(last_on_draw_scroll_offset_);
223 hardware_enabled_ = true;
225 return CompositeHw();
228 bool BrowserViewRenderer::CompositeHw() {
229 CancelFallbackTick();
231 ReturnResourceFromParent();
232 UpdateMemoryPolicy();
234 ParentCompositorDrawConstraints parent_draw_constraints =
235 shared_renderer_state_.GetParentDrawConstraintsOnUI();
236 gfx::Size surface_size(size_);
237 gfx::Rect viewport(surface_size);
238 gfx::Rect clip = viewport;
239 gfx::Transform transform_for_tile_priority =
240 parent_draw_constraints.transform;
242 // If the WebView is on a layer, WebView does not know what transform is
243 // applied onto the layer so global visible rect does not make sense here.
244 // In this case, just use the surface rect for tiling.
245 gfx::Rect viewport_rect_for_tile_priority;
247 // Leave viewport_rect_for_tile_priority empty if offscreen_pre_raster_ is on.
248 if (!offscreen_pre_raster_ && !parent_draw_constraints.is_layer) {
249 viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
252 scoped_ptr<cc::CompositorFrame> frame =
253 compositor_->DemandDrawHw(surface_size,
254 gfx::Transform(),
255 viewport,
256 clip,
257 viewport_rect_for_tile_priority,
258 transform_for_tile_priority);
259 if (!frame.get()) {
260 TRACE_EVENT_INSTANT0("android_webview", "NoNewFrame",
261 TRACE_EVENT_SCOPE_THREAD);
262 return false;
265 scoped_ptr<ChildFrame> child_frame = make_scoped_ptr(
266 new ChildFrame(frame.Pass(), viewport_rect_for_tile_priority.IsEmpty(),
267 transform_for_tile_priority, offscreen_pre_raster_,
268 parent_draw_constraints.is_layer));
270 // Uncommitted frame can happen with consecutive fallback ticks.
271 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
272 shared_renderer_state_.SetCompositorFrameOnUI(child_frame.Pass());
273 return true;
276 void BrowserViewRenderer::UpdateParentDrawConstraints() {
277 PostInvalidateWithFallback();
278 ParentCompositorDrawConstraints parent_draw_constraints =
279 shared_renderer_state_.GetParentDrawConstraintsOnUI();
280 client_->ParentDrawConstraintsUpdated(parent_draw_constraints);
283 void BrowserViewRenderer::ReturnUnusedResource(
284 scoped_ptr<ChildFrame> child_frame) {
285 if (!child_frame.get() || !child_frame->frame.get())
286 return;
288 cc::CompositorFrameAck frame_ack;
289 cc::TransferableResource::ReturnResources(
290 child_frame->frame->delegated_frame_data->resource_list,
291 &frame_ack.resources);
292 if (compositor_ && !frame_ack.resources.empty())
293 compositor_->ReturnResources(frame_ack);
296 void BrowserViewRenderer::ReturnResourceFromParent() {
297 cc::CompositorFrameAck frame_ack;
298 shared_renderer_state_.SwapReturnedResourcesOnUI(&frame_ack.resources);
299 if (compositor_ && !frame_ack.resources.empty()) {
300 compositor_->ReturnResources(frame_ack);
304 void BrowserViewRenderer::DetachFunctorFromView() {
305 client_->DetachFunctorFromView();
308 bool BrowserViewRenderer::OnDrawSoftware(SkCanvas* canvas) {
309 return CanOnDraw() && CompositeSW(canvas);
312 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
313 int height) {
314 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
316 // Return empty Picture objects for empty SkPictures.
317 if (width <= 0 || height <= 0) {
318 SkPictureRecorder emptyRecorder;
319 emptyRecorder.beginRecording(0, 0);
320 return skia::AdoptRef(emptyRecorder.endRecording());
323 SkPictureRecorder recorder;
324 SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
325 if (compositor_) {
327 // Reset scroll back to the origin, will go back to the old
328 // value when scroll_reset is out of scope.
329 compositor_->DidChangeRootLayerScrollOffset(gfx::ScrollOffset());
330 CompositeSW(rec_canvas);
332 compositor_->DidChangeRootLayerScrollOffset(
333 gfx::ScrollOffset(scroll_offset_dip_));
335 return skia::AdoptRef(recorder.endRecording());
338 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
339 on_new_picture_enable_ = enabled;
342 void BrowserViewRenderer::ClearView() {
343 TRACE_EVENT_INSTANT0("android_webview",
344 "BrowserViewRenderer::ClearView",
345 TRACE_EVENT_SCOPE_THREAD);
346 if (clear_view_)
347 return;
349 clear_view_ = true;
350 // Always invalidate ignoring the compositor to actually clear the webview.
351 PostInvalidateWithFallback();
354 void BrowserViewRenderer::SetOffscreenPreRaster(bool enable) {
355 if (offscreen_pre_raster_ != enable && compositor_)
356 UpdateMemoryPolicy();
358 offscreen_pre_raster_ = enable;
361 void BrowserViewRenderer::SetIsPaused(bool paused) {
362 TRACE_EVENT_INSTANT1("android_webview",
363 "BrowserViewRenderer::SetIsPaused",
364 TRACE_EVENT_SCOPE_THREAD,
365 "paused",
366 paused);
367 is_paused_ = paused;
368 UpdateCompositorIsActive();
371 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
372 TRACE_EVENT_INSTANT1("android_webview",
373 "BrowserViewRenderer::SetViewVisibility",
374 TRACE_EVENT_SCOPE_THREAD,
375 "view_visible",
376 view_visible);
377 view_visible_ = view_visible;
380 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
381 TRACE_EVENT_INSTANT1("android_webview",
382 "BrowserViewRenderer::SetWindowVisibility",
383 TRACE_EVENT_SCOPE_THREAD,
384 "window_visible",
385 window_visible);
386 window_visible_ = window_visible;
387 UpdateCompositorIsActive();
390 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
391 TRACE_EVENT_INSTANT2("android_webview",
392 "BrowserViewRenderer::OnSizeChanged",
393 TRACE_EVENT_SCOPE_THREAD,
394 "width",
395 width,
396 "height",
397 height);
398 size_.SetSize(width, height);
401 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
402 TRACE_EVENT2("android_webview",
403 "BrowserViewRenderer::OnAttachedToWindow",
404 "width",
405 width,
406 "height",
407 height);
408 attached_to_window_ = true;
409 size_.SetSize(width, height);
410 UpdateCompositorIsActive();
413 void BrowserViewRenderer::OnDetachedFromWindow() {
414 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
415 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
416 attached_to_window_ = false;
417 DCHECK(!hardware_enabled_);
418 UpdateCompositorIsActive();
421 void BrowserViewRenderer::OnComputeScroll(base::TimeTicks animation_time) {
422 if (!compositor_)
423 return;
424 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnComputeScroll");
425 compositor_->OnComputeScroll(animation_time);
428 void BrowserViewRenderer::ReleaseHardware() {
429 DCHECK(hardware_enabled_);
430 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
431 ReturnResourceFromParent();
432 DCHECK(shared_renderer_state_.ReturnedResourcesEmptyOnUI());
434 if (compositor_) {
435 compositor_->SetMemoryPolicy(0u);
438 hardware_enabled_ = false;
441 bool BrowserViewRenderer::IsVisible() const {
442 // Ignore |window_visible_| if |attached_to_window_| is false.
443 return view_visible_ && (!attached_to_window_ || window_visible_);
446 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
447 return gfx::Rect(client_->GetLocationOnScreen(), size_);
450 void BrowserViewRenderer::DidInitializeCompositor(
451 content::SynchronousCompositor* compositor) {
452 TRACE_EVENT0("android_webview",
453 "BrowserViewRenderer::DidInitializeCompositor");
454 DCHECK(compositor);
455 DCHECK(!compositor_);
456 compositor_ = compositor;
457 UpdateCompositorIsActive();
460 void BrowserViewRenderer::DidDestroyCompositor(
461 content::SynchronousCompositor* compositor) {
462 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
463 DCHECK(compositor_);
464 compositor_->SetIsActive(false);
465 compositor_ = NULL;
468 void BrowserViewRenderer::SetDipScale(float dip_scale) {
469 dip_scale_ = dip_scale;
470 CHECK_GT(dip_scale_, 0.f);
473 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
474 DCHECK_GT(dip_scale_, 0.f);
475 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
476 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
479 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
480 gfx::Vector2d max_offset = max_scroll_offset();
481 gfx::Vector2dF scroll_offset_dip;
482 // To preserve the invariant that scrolling to the maximum physical pixel
483 // value also scrolls to the maximum dip pixel value we transform the physical
484 // offset into the dip offset by using a proportion (instead of dividing by
485 // dip_scale * page_scale_factor).
486 if (max_offset.x()) {
487 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
488 max_offset.x());
490 if (max_offset.y()) {
491 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
492 max_offset.y());
495 DCHECK_LE(0.f, scroll_offset_dip.x());
496 DCHECK_LE(0.f, scroll_offset_dip.y());
497 DCHECK(scroll_offset_dip.x() < max_scroll_offset_dip_.x() ||
498 scroll_offset_dip.x() - max_scroll_offset_dip_.x() < kEpsilon)
499 << scroll_offset_dip.x() << " " << max_scroll_offset_dip_.x();
500 DCHECK(scroll_offset_dip.y() < max_scroll_offset_dip_.y() ||
501 scroll_offset_dip.y() - max_scroll_offset_dip_.y() < kEpsilon)
502 << scroll_offset_dip.y() << " " << max_scroll_offset_dip_.y();
504 if (scroll_offset_dip_ == scroll_offset_dip)
505 return;
507 scroll_offset_dip_ = scroll_offset_dip;
509 TRACE_EVENT_INSTANT2("android_webview",
510 "BrowserViewRenderer::ScrollTo",
511 TRACE_EVENT_SCOPE_THREAD,
512 "x",
513 scroll_offset_dip.x(),
514 "y",
515 scroll_offset_dip.y());
517 if (compositor_) {
518 compositor_->DidChangeRootLayerScrollOffset(
519 gfx::ScrollOffset(scroll_offset_dip_));
523 void BrowserViewRenderer::DidUpdateContent() {
524 TRACE_EVENT_INSTANT0("android_webview",
525 "BrowserViewRenderer::DidUpdateContent",
526 TRACE_EVENT_SCOPE_THREAD);
527 clear_view_ = false;
528 if (on_new_picture_enable_)
529 client_->OnNewPicture();
532 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
533 gfx::Vector2dF scroll_offset_dip) {
534 if (scroll_offset_dip_ == scroll_offset_dip)
535 return;
536 scroll_offset_dip_ = scroll_offset_dip;
538 gfx::Vector2d max_offset = max_scroll_offset();
539 gfx::Vector2d scroll_offset;
540 // For an explanation as to why this is done this way see the comment in
541 // BrowserViewRenderer::ScrollTo.
542 if (max_scroll_offset_dip_.x()) {
543 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
544 max_scroll_offset_dip_.x());
547 if (max_scroll_offset_dip_.y()) {
548 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
549 max_scroll_offset_dip_.y());
552 DCHECK_LE(0, scroll_offset.x());
553 DCHECK_LE(0, scroll_offset.y());
554 DCHECK_LE(scroll_offset.x(), max_offset.x());
555 DCHECK_LE(scroll_offset.y(), max_offset.y());
557 client_->ScrollContainerViewTo(scroll_offset);
560 void BrowserViewRenderer::UpdateRootLayerState(
561 const gfx::Vector2dF& total_scroll_offset_dip,
562 const gfx::Vector2dF& max_scroll_offset_dip,
563 const gfx::SizeF& scrollable_size_dip,
564 float page_scale_factor,
565 float min_page_scale_factor,
566 float max_page_scale_factor) {
567 TRACE_EVENT_INSTANT1(
568 "android_webview",
569 "BrowserViewRenderer::UpdateRootLayerState",
570 TRACE_EVENT_SCOPE_THREAD,
571 "state",
572 RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip));
574 DCHECK_GE(max_scroll_offset_dip.x(), 0.f);
575 DCHECK_GE(max_scroll_offset_dip.y(), 0.f);
576 DCHECK_GT(page_scale_factor, 0.f);
577 // SetDipScale should have been called at least once before this is called.
578 DCHECK_GT(dip_scale_, 0.f);
580 if (max_scroll_offset_dip_ != max_scroll_offset_dip ||
581 scrollable_size_dip_ != scrollable_size_dip ||
582 page_scale_factor_ != page_scale_factor ||
583 min_page_scale_factor_ != min_page_scale_factor ||
584 max_page_scale_factor_ != max_page_scale_factor) {
585 max_scroll_offset_dip_ = max_scroll_offset_dip;
586 scrollable_size_dip_ = scrollable_size_dip;
587 page_scale_factor_ = page_scale_factor;
588 min_page_scale_factor_ = min_page_scale_factor;
589 max_page_scale_factor_ = max_page_scale_factor;
591 client_->UpdateScrollState(max_scroll_offset(), scrollable_size_dip,
592 page_scale_factor, min_page_scale_factor,
593 max_page_scale_factor);
595 SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
598 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
599 BrowserViewRenderer::RootLayerStateAsValue(
600 const gfx::Vector2dF& total_scroll_offset_dip,
601 const gfx::SizeF& scrollable_size_dip) {
602 scoped_refptr<base::trace_event::TracedValue> state =
603 new base::trace_event::TracedValue();
605 state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x());
606 state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y());
608 state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x());
609 state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y());
611 state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
612 state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
614 state->SetDouble("page_scale_factor", page_scale_factor_);
615 return state;
618 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
619 gfx::Vector2dF latest_overscroll_delta,
620 gfx::Vector2dF current_fling_velocity) {
621 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
622 if (accumulated_overscroll == latest_overscroll_delta)
623 overscroll_rounding_error_ = gfx::Vector2dF();
624 gfx::Vector2dF scaled_overscroll_delta =
625 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
626 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
627 scaled_overscroll_delta + overscroll_rounding_error_);
628 overscroll_rounding_error_ =
629 scaled_overscroll_delta - rounded_overscroll_delta;
630 gfx::Vector2dF fling_velocity_pixels =
631 gfx::ScaleVector2d(current_fling_velocity, physical_pixel_scale);
633 client_->DidOverscroll(rounded_overscroll_delta, fling_velocity_pixels);
636 void BrowserViewRenderer::PostInvalidate() {
637 TRACE_EVENT_INSTANT0("android_webview", "BrowserViewRenderer::PostInvalidate",
638 TRACE_EVENT_SCOPE_THREAD);
639 PostInvalidateWithFallback();
642 void BrowserViewRenderer::PostInvalidateWithFallback() {
643 // Always call view invalidate. We rely the Android framework to ignore the
644 // invalidate when it's not needed such as when view is not visible.
645 client_->PostInvalidate();
647 // Stop fallback ticks when one of these is true.
648 // 1) Webview is paused. Also need to check we are not in clear view since
649 // paused, offscreen still expect clear view to recover.
650 // 2) If we are attached to window and the window is not visible (eg when
651 // app is in the background). We are sure in this case the webview is used
652 // "on-screen" but that updates are not needed when in the background.
653 bool throttle_fallback_tick =
654 (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
656 if (throttle_fallback_tick || fallback_tick_pending_)
657 return;
659 DCHECK(post_fallback_tick_.IsCancelled());
660 DCHECK(fallback_tick_fired_.IsCancelled());
662 post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick,
663 base::Unretained(this)));
664 ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
665 fallback_tick_pending_ = true;
668 void BrowserViewRenderer::CancelFallbackTick() {
669 post_fallback_tick_.Cancel();
670 fallback_tick_fired_.Cancel();
671 fallback_tick_pending_ = false;
674 void BrowserViewRenderer::PostFallbackTick() {
675 DCHECK(fallback_tick_fired_.IsCancelled());
676 TRACE_EVENT0("android_webview", "BrowserViewRenderer::PostFallbackTick");
677 post_fallback_tick_.Cancel();
678 fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
679 base::Unretained(this)));
680 ui_task_runner_->PostDelayedTask(
681 FROM_HERE, fallback_tick_fired_.callback(),
682 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
685 void BrowserViewRenderer::FallbackTickFired() {
686 TRACE_EVENT0("android_webview", "BrowserViewRenderer::FallbackTickFired");
687 // This should only be called if OnDraw or DrawGL did not come in time, which
688 // means fallback_tick_pending_ must still be true.
689 DCHECK(fallback_tick_pending_);
690 fallback_tick_fired_.Cancel();
691 fallback_tick_pending_ = false;
692 if (compositor_) {
693 if (hardware_enabled_ && !size_.IsEmpty()) {
694 CompositeHw();
695 } else {
696 ForceFakeCompositeSW();
701 void BrowserViewRenderer::ForceFakeCompositeSW() {
702 DCHECK(compositor_);
703 SkBitmap bitmap;
704 bitmap.allocN32Pixels(1, 1);
705 bitmap.eraseColor(0);
706 SkCanvas canvas(bitmap);
707 CompositeSW(&canvas);
710 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
711 DCHECK(compositor_);
712 CancelFallbackTick();
713 ReturnResourceFromParent();
714 return compositor_->DemandDrawSw(canvas);
717 void BrowserViewRenderer::UpdateCompositorIsActive() {
718 if (compositor_)
719 compositor_->SetIsActive(!is_paused_ &&
720 (!attached_to_window_ || window_visible_));
723 std::string BrowserViewRenderer::ToString() const {
724 std::string str;
725 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
726 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
727 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
728 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
729 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
730 base::StringAppendF(&str, "fallback_tick_pending: %d ",
731 fallback_tick_pending_);
732 base::StringAppendF(&str, "view size: %s ", size_.ToString().c_str());
733 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
734 base::StringAppendF(&str,
735 "global visible rect: %s ",
736 last_on_draw_global_visible_rect_.ToString().c_str());
737 base::StringAppendF(
738 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
739 base::StringAppendF(&str,
740 "overscroll_rounding_error_: %s ",
741 overscroll_rounding_error_.ToString().c_str());
742 base::StringAppendF(
743 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
744 base::StringAppendF(&str, "clear_view: %d ", clear_view_);
745 return str;
748 } // namespace android_webview