Reduce page_cycler repeat count from 10 to 6
[chromium-blink-merge.git] / android_webview / browser / browser_view_renderer.cc
blob9d660fb5bfa41fc402bdf38e536f1ba8a682f208
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 "base/auto_reset.h"
9 #include "base/command_line.h"
10 #include "base/debug/trace_event_argument.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/stringprintf.h"
14 #include "cc/output/compositor_frame.h"
15 #include "content/public/common/content_switches.h"
16 #include "gpu/command_buffer/service/gpu_switches.h"
17 #include "third_party/skia/include/core/SkBitmap.h"
18 #include "third_party/skia/include/core/SkCanvas.h"
19 #include "third_party/skia/include/core/SkPicture.h"
20 #include "third_party/skia/include/core/SkPictureRecorder.h"
21 #include "ui/gfx/geometry/vector2d_conversions.h"
23 namespace android_webview {
25 namespace {
27 const int64 kFallbackTickTimeoutInMilliseconds = 100;
29 // Used to calculate memory allocation. Determined experimentally.
30 const size_t kMemoryMultiplier = 20;
31 const size_t kBytesPerPixel = 4;
32 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
33 uint64 g_memory_override_in_bytes = 0u;
35 } // namespace
37 // static
38 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
39 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
41 // If the value was overridden on the command line, use the specified value.
42 bool client_hard_limit_bytes_overridden =
43 cl->HasSwitch(switches::kForceGpuMemAvailableMb);
44 if (client_hard_limit_bytes_overridden) {
45 base::StringToUint64(
46 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
47 switches::kForceGpuMemAvailableMb),
48 &g_memory_override_in_bytes);
49 g_memory_override_in_bytes *= 1024 * 1024;
53 BrowserViewRenderer::BrowserViewRenderer(
54 BrowserViewRendererClient* client,
55 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
56 : client_(client),
57 shared_renderer_state_(ui_task_runner, this),
58 ui_task_runner_(ui_task_runner),
59 compositor_(NULL),
60 is_paused_(false),
61 view_visible_(false),
62 window_visible_(false),
63 attached_to_window_(false),
64 hardware_enabled_(false),
65 dip_scale_(0.0),
66 page_scale_factor_(1.0),
67 on_new_picture_enable_(false),
68 clear_view_(false),
69 compositor_needs_continuous_invalidate_(false),
70 invalidate_after_composite_(false),
71 block_invalidates_(false),
72 fallback_tick_pending_(false) {
75 BrowserViewRenderer::~BrowserViewRenderer() {
78 SharedRendererState* BrowserViewRenderer::GetAwDrawGLViewContext() {
79 return &shared_renderer_state_;
82 bool BrowserViewRenderer::RequestDrawGL(bool wait_for_completion) {
83 return client_->RequestDrawGL(wait_for_completion);
86 // This function updates the resource allocation in GlobalTileManager.
87 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
88 DCHECK(ui_task_runner_->BelongsToCurrentThread());
89 // Constants from Android ComponentCallbacks2.
90 enum {
91 TRIM_MEMORY_RUNNING_LOW = 10,
92 TRIM_MEMORY_UI_HIDDEN = 20,
93 TRIM_MEMORY_BACKGROUND = 40,
94 TRIM_MEMORY_MODERATE = 60,
97 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
98 // it does not indicate memory pressure, but merely that the app is
99 // backgrounded.
100 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
101 return;
103 // Do not release resources on view we expect to get DrawGL soon.
104 if (level < TRIM_MEMORY_BACKGROUND && visible)
105 return;
107 // Nothing to drop.
108 if (!compositor_ || !hardware_enabled_)
109 return;
111 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
113 // Drop everything in hardware.
114 if (level >= TRIM_MEMORY_MODERATE) {
115 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
116 return;
119 // Just set the memory limit to 0 and drop all tiles. This will be reset to
120 // normal levels in the next DrawGL call.
121 compositor_->SetMemoryPolicy(0u);
122 ForceFakeCompositeSW();
125 size_t BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
126 if (g_memory_override_in_bytes)
127 return static_cast<size_t>(g_memory_override_in_bytes);
129 size_t width = last_on_draw_global_visible_rect_.width();
130 size_t height = last_on_draw_global_visible_rect_.height();
131 size_t bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
132 // Round up to a multiple of kMemoryAllocationStep.
133 bytes_limit =
134 (bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
135 return bytes_limit;
138 void BrowserViewRenderer::PrepareToDraw(const gfx::Vector2d& scroll,
139 const gfx::Rect& global_visible_rect) {
140 last_on_draw_scroll_offset_ = scroll;
141 last_on_draw_global_visible_rect_ = global_visible_rect;
144 bool BrowserViewRenderer::OnDrawHardware() {
145 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
146 shared_renderer_state_.InitializeHardwareDrawIfNeededOnUI();
147 if (!compositor_) {
148 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_NoCompositor",
149 TRACE_EVENT_SCOPE_THREAD);
150 return false;
153 shared_renderer_state_.SetScrollOffsetOnUI(last_on_draw_scroll_offset_);
155 if (!hardware_enabled_) {
156 TRACE_EVENT0("android_webview", "InitializeHwDraw");
157 hardware_enabled_ = compositor_->InitializeHwDraw();
159 if (!hardware_enabled_) {
160 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_HardwareNotEnabled",
161 TRACE_EVENT_SCOPE_THREAD);
162 return false;
165 if (last_on_draw_global_visible_rect_.IsEmpty() &&
166 parent_draw_constraints_.surface_rect.IsEmpty()) {
167 TRACE_EVENT_INSTANT0("android_webview",
168 "EarlyOut_EmptyVisibleRect",
169 TRACE_EVENT_SCOPE_THREAD);
170 shared_renderer_state_.SetForceInvalidateOnNextDrawGLOnUI(true);
171 return true;
174 ReturnResourceFromParent();
175 if (shared_renderer_state_.HasCompositorFrameOnUI()) {
176 TRACE_EVENT_INSTANT0("android_webview",
177 "EarlyOut_PreviousFrameUnconsumed",
178 TRACE_EVENT_SCOPE_THREAD);
179 DidSkipCompositeInDraw();
180 return true;
183 scoped_ptr<cc::CompositorFrame> frame = CompositeHw();
184 if (!frame.get()) {
185 TRACE_EVENT_INSTANT0("android_webview", "NoNewFrame",
186 TRACE_EVENT_SCOPE_THREAD);
187 return false;
190 shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), false);
191 return true;
194 scoped_ptr<cc::CompositorFrame> BrowserViewRenderer::CompositeHw() {
195 compositor_->SetMemoryPolicy(CalculateDesiredMemoryPolicy());
197 parent_draw_constraints_ =
198 shared_renderer_state_.GetParentDrawConstraintsOnUI();
199 gfx::Size surface_size(size_);
200 gfx::Rect viewport(surface_size);
201 gfx::Rect clip = viewport;
202 gfx::Transform transform_for_tile_priority =
203 parent_draw_constraints_.transform;
205 // If the WebView is on a layer, WebView does not know what transform is
206 // applied onto the layer so global visible rect does not make sense here.
207 // In this case, just use the surface rect for tiling.
208 gfx::Rect viewport_rect_for_tile_priority;
209 if (parent_draw_constraints_.is_layer ||
210 last_on_draw_global_visible_rect_.IsEmpty()) {
211 viewport_rect_for_tile_priority = parent_draw_constraints_.surface_rect;
212 } else {
213 viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
216 scoped_ptr<cc::CompositorFrame> frame =
217 compositor_->DemandDrawHw(surface_size,
218 gfx::Transform(),
219 viewport,
220 clip,
221 viewport_rect_for_tile_priority,
222 transform_for_tile_priority);
223 if (frame.get())
224 DidComposite();
225 return frame.Pass();
228 void BrowserViewRenderer::UpdateParentDrawConstraints() {
229 // Post an invalidate if the parent draw constraints are stale and there is
230 // no pending invalidate.
231 bool needs_force_invalidate =
232 shared_renderer_state_.NeedsForceInvalidateOnNextDrawGLOnUI();
233 if (needs_force_invalidate ||
234 !parent_draw_constraints_.Equals(
235 shared_renderer_state_.GetParentDrawConstraintsOnUI())) {
236 shared_renderer_state_.SetForceInvalidateOnNextDrawGLOnUI(false);
237 EnsureContinuousInvalidation(true, needs_force_invalidate);
241 void BrowserViewRenderer::ReturnUnusedResource(
242 scoped_ptr<cc::CompositorFrame> frame) {
243 if (!frame.get())
244 return;
246 cc::CompositorFrameAck frame_ack;
247 cc::TransferableResource::ReturnResources(
248 frame->delegated_frame_data->resource_list, &frame_ack.resources);
249 if (compositor_ && !frame_ack.resources.empty())
250 compositor_->ReturnResources(frame_ack);
253 void BrowserViewRenderer::ReturnResourceFromParent() {
254 cc::CompositorFrameAck frame_ack;
255 shared_renderer_state_.SwapReturnedResourcesOnUI(&frame_ack.resources);
256 if (compositor_ && !frame_ack.resources.empty()) {
257 compositor_->ReturnResources(frame_ack);
261 void BrowserViewRenderer::DidSkipCommitFrame() {
262 // Treat it the same way as skipping onDraw.
263 DidSkipCompositeInDraw();
266 void BrowserViewRenderer::InvalidateOnFunctorDestroy() {
267 client_->InvalidateOnFunctorDestroy();
270 bool BrowserViewRenderer::OnDrawSoftware(SkCanvas* canvas) {
271 if (!compositor_) {
272 TRACE_EVENT_INSTANT0(
273 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
274 return false;
277 return CompositeSW(canvas);
280 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
281 int height) {
282 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
284 // Return empty Picture objects for empty SkPictures.
285 if (width <= 0 || height <= 0) {
286 SkPictureRecorder emptyRecorder;
287 emptyRecorder.beginRecording(0, 0);
288 return skia::AdoptRef(emptyRecorder.endRecording());
291 // Reset scroll back to the origin, will go back to the old
292 // value when scroll_reset is out of scope.
293 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
294 gfx::Vector2dF());
296 SkPictureRecorder recorder;
297 SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
298 if (compositor_)
299 CompositeSW(rec_canvas);
300 return skia::AdoptRef(recorder.endRecording());
303 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
304 on_new_picture_enable_ = enabled;
307 void BrowserViewRenderer::ClearView() {
308 TRACE_EVENT_INSTANT0("android_webview",
309 "BrowserViewRenderer::ClearView",
310 TRACE_EVENT_SCOPE_THREAD);
311 if (clear_view_)
312 return;
314 clear_view_ = true;
315 // Always invalidate ignoring the compositor to actually clear the webview.
316 EnsureContinuousInvalidation(true, false);
319 void BrowserViewRenderer::SetIsPaused(bool paused) {
320 TRACE_EVENT_INSTANT1("android_webview",
321 "BrowserViewRenderer::SetIsPaused",
322 TRACE_EVENT_SCOPE_THREAD,
323 "paused",
324 paused);
325 is_paused_ = paused;
326 EnsureContinuousInvalidation(false, false);
329 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
330 TRACE_EVENT_INSTANT1("android_webview",
331 "BrowserViewRenderer::SetViewVisibility",
332 TRACE_EVENT_SCOPE_THREAD,
333 "view_visible",
334 view_visible);
335 view_visible_ = view_visible;
338 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
339 TRACE_EVENT_INSTANT1("android_webview",
340 "BrowserViewRenderer::SetWindowVisibility",
341 TRACE_EVENT_SCOPE_THREAD,
342 "window_visible",
343 window_visible);
344 window_visible_ = window_visible;
345 EnsureContinuousInvalidation(false, false);
348 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
349 TRACE_EVENT_INSTANT2("android_webview",
350 "BrowserViewRenderer::OnSizeChanged",
351 TRACE_EVENT_SCOPE_THREAD,
352 "width",
353 width,
354 "height",
355 height);
356 size_.SetSize(width, height);
359 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
360 TRACE_EVENT2("android_webview",
361 "BrowserViewRenderer::OnAttachedToWindow",
362 "width",
363 width,
364 "height",
365 height);
366 attached_to_window_ = true;
367 size_.SetSize(width, height);
370 void BrowserViewRenderer::OnDetachedFromWindow() {
371 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
372 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
373 attached_to_window_ = false;
374 DCHECK(!hardware_enabled_);
377 void BrowserViewRenderer::ReleaseHardware() {
378 DCHECK(hardware_enabled_);
379 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
380 ReturnResourceFromParent();
381 DCHECK(shared_renderer_state_.ReturnedResourcesEmptyOnUI());
383 if (compositor_) {
384 compositor_->ReleaseHwDraw();
387 hardware_enabled_ = false;
390 bool BrowserViewRenderer::IsVisible() const {
391 // Ignore |window_visible_| if |attached_to_window_| is false.
392 return view_visible_ && (!attached_to_window_ || window_visible_);
395 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
396 return gfx::Rect(client_->GetLocationOnScreen(), size_);
399 void BrowserViewRenderer::DidInitializeCompositor(
400 content::SynchronousCompositor* compositor) {
401 TRACE_EVENT0("android_webview",
402 "BrowserViewRenderer::DidInitializeCompositor");
403 DCHECK(compositor);
404 DCHECK(!compositor_);
405 compositor_ = compositor;
408 void BrowserViewRenderer::DidDestroyCompositor(
409 content::SynchronousCompositor* compositor) {
410 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
411 DCHECK(compositor_);
412 compositor_ = NULL;
415 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
416 if (compositor_needs_continuous_invalidate_ == invalidate)
417 return;
419 TRACE_EVENT_INSTANT1("android_webview",
420 "BrowserViewRenderer::SetContinuousInvalidate",
421 TRACE_EVENT_SCOPE_THREAD,
422 "invalidate",
423 invalidate);
424 compositor_needs_continuous_invalidate_ = invalidate;
426 EnsureContinuousInvalidation(false, false);
429 void BrowserViewRenderer::SetDipScale(float dip_scale) {
430 dip_scale_ = dip_scale;
431 CHECK_GT(dip_scale_, 0);
434 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
435 DCHECK_GT(dip_scale_, 0);
436 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
437 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
440 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
441 gfx::Vector2d max_offset = max_scroll_offset();
442 gfx::Vector2dF scroll_offset_dip;
443 // To preserve the invariant that scrolling to the maximum physical pixel
444 // value also scrolls to the maximum dip pixel value we transform the physical
445 // offset into the dip offset by using a proportion (instead of dividing by
446 // dip_scale * page_scale_factor).
447 if (max_offset.x()) {
448 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
449 max_offset.x());
451 if (max_offset.y()) {
452 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
453 max_offset.y());
456 DCHECK_LE(0, scroll_offset_dip.x());
457 DCHECK_LE(0, scroll_offset_dip.y());
458 DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
459 DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
461 if (scroll_offset_dip_ == scroll_offset_dip)
462 return;
464 scroll_offset_dip_ = scroll_offset_dip;
466 TRACE_EVENT_INSTANT2("android_webview",
467 "BrowserViewRenderer::ScrollTo",
468 TRACE_EVENT_SCOPE_THREAD,
469 "x",
470 scroll_offset_dip.x(),
471 "y",
472 scroll_offset_dip.y());
474 if (compositor_)
475 compositor_->DidChangeRootLayerScrollOffset();
478 void BrowserViewRenderer::DidUpdateContent() {
479 TRACE_EVENT_INSTANT0("android_webview",
480 "BrowserViewRenderer::DidUpdateContent",
481 TRACE_EVENT_SCOPE_THREAD);
482 clear_view_ = false;
483 if (on_new_picture_enable_)
484 client_->OnNewPicture();
487 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
488 gfx::Vector2dF scroll_offset_dip) {
489 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
490 // DrawGl when http://crbug.com/249972 is fixed.
491 if (scroll_offset_dip_ == scroll_offset_dip)
492 return;
494 scroll_offset_dip_ = scroll_offset_dip;
496 gfx::Vector2d max_offset = max_scroll_offset();
497 gfx::Vector2d scroll_offset;
498 // For an explanation as to why this is done this way see the comment in
499 // BrowserViewRenderer::ScrollTo.
500 if (max_scroll_offset_dip_.x()) {
501 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
502 max_scroll_offset_dip_.x());
505 if (max_scroll_offset_dip_.y()) {
506 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
507 max_scroll_offset_dip_.y());
510 DCHECK_LE(0, scroll_offset.x());
511 DCHECK_LE(0, scroll_offset.y());
512 DCHECK_LE(scroll_offset.x(), max_offset.x());
513 DCHECK_LE(scroll_offset.y(), max_offset.y());
515 client_->ScrollContainerViewTo(scroll_offset);
518 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
519 return scroll_offset_dip_;
522 bool BrowserViewRenderer::IsExternalFlingActive() const {
523 return client_->IsFlingActive();
526 void BrowserViewRenderer::UpdateRootLayerState(
527 const gfx::Vector2dF& total_scroll_offset_dip,
528 const gfx::Vector2dF& max_scroll_offset_dip,
529 const gfx::SizeF& scrollable_size_dip,
530 float page_scale_factor,
531 float min_page_scale_factor,
532 float max_page_scale_factor) {
533 TRACE_EVENT_INSTANT1(
534 "android_webview",
535 "BrowserViewRenderer::UpdateRootLayerState",
536 TRACE_EVENT_SCOPE_THREAD,
537 "state",
538 RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip));
540 DCHECK_GT(dip_scale_, 0);
542 max_scroll_offset_dip_ = max_scroll_offset_dip;
543 DCHECK_LE(0, max_scroll_offset_dip_.x());
544 DCHECK_LE(0, max_scroll_offset_dip_.y());
546 page_scale_factor_ = page_scale_factor;
547 DCHECK_GT(page_scale_factor_, 0);
549 client_->UpdateScrollState(max_scroll_offset(),
550 scrollable_size_dip,
551 page_scale_factor,
552 min_page_scale_factor,
553 max_page_scale_factor);
554 SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
557 scoped_refptr<base::debug::ConvertableToTraceFormat>
558 BrowserViewRenderer::RootLayerStateAsValue(
559 const gfx::Vector2dF& total_scroll_offset_dip,
560 const gfx::SizeF& scrollable_size_dip) {
561 scoped_refptr<base::debug::TracedValue> state =
562 new base::debug::TracedValue();
564 state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x());
565 state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y());
567 state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x());
568 state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y());
570 state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
571 state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
573 state->SetDouble("page_scale_factor", page_scale_factor_);
574 return state;
577 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
578 gfx::Vector2dF latest_overscroll_delta,
579 gfx::Vector2dF current_fling_velocity) {
580 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
581 if (accumulated_overscroll == latest_overscroll_delta)
582 overscroll_rounding_error_ = gfx::Vector2dF();
583 gfx::Vector2dF scaled_overscroll_delta =
584 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
585 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
586 scaled_overscroll_delta + overscroll_rounding_error_);
587 overscroll_rounding_error_ =
588 scaled_overscroll_delta - rounded_overscroll_delta;
589 client_->DidOverscroll(rounded_overscroll_delta);
592 void BrowserViewRenderer::EnsureContinuousInvalidation(
593 bool force_invalidate,
594 bool skip_reschedule_tick) {
595 if (force_invalidate)
596 invalidate_after_composite_ = true;
598 // This method should be called again when any of these conditions change.
599 bool need_invalidate =
600 compositor_needs_continuous_invalidate_ || invalidate_after_composite_;
601 if (!need_invalidate || block_invalidates_)
602 return;
604 if (!compositor_needs_continuous_invalidate_ && invalidate_after_composite_)
605 invalidate_after_composite_ = false;
607 // Always call view invalidate. We rely the Android framework to ignore the
608 // invalidate when it's not needed such as when view is not visible.
609 client_->PostInvalidate();
611 // Stop fallback ticks when one of these is true.
612 // 1) Webview is paused. Also need to check we are not in clear view since
613 // paused, offscreen still expect clear view to recover.
614 // 2) If we are attached to window and the window is not visible (eg when
615 // app is in the background). We are sure in this case the webview is used
616 // "on-screen" but that updates are not needed when in the background.
617 bool throttle_fallback_tick =
618 (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
619 if (throttle_fallback_tick)
620 return;
622 block_invalidates_ = compositor_needs_continuous_invalidate_;
623 if (skip_reschedule_tick && fallback_tick_pending_)
624 return;
626 // Unretained here is safe because the callbacks are cancelled when
627 // they are destroyed.
628 post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick,
629 base::Unretained(this)));
630 fallback_tick_fired_.Cancel();
631 fallback_tick_pending_ = false;
633 // No need to reschedule fallback tick if compositor does not need to be
634 // ticked. This can happen if this is reached because force_invalidate is
635 // true.
636 if (compositor_needs_continuous_invalidate_) {
637 fallback_tick_pending_ = true;
638 ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
642 void BrowserViewRenderer::PostFallbackTick() {
643 DCHECK(fallback_tick_fired_.IsCancelled());
644 fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
645 base::Unretained(this)));
646 if (compositor_needs_continuous_invalidate_) {
647 ui_task_runner_->PostDelayedTask(
648 FROM_HERE,
649 fallback_tick_fired_.callback(),
650 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
651 } else {
652 // Pretend we just composited to unblock further invalidates.
653 DidComposite();
657 void BrowserViewRenderer::FallbackTickFired() {
658 TRACE_EVENT1("android_webview",
659 "BrowserViewRenderer::FallbackTickFired",
660 "compositor_needs_continuous_invalidate_",
661 compositor_needs_continuous_invalidate_);
663 // This should only be called if OnDraw or DrawGL did not come in time, which
664 // means block_invalidates_ must still be true.
665 DCHECK(block_invalidates_);
666 fallback_tick_pending_ = false;
667 if (compositor_needs_continuous_invalidate_ && compositor_) {
668 if (hardware_enabled_) {
669 ReturnResourceFromParent();
670 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
671 scoped_ptr<cc::CompositorFrame> frame = CompositeHw();
672 if (frame.get()) {
673 shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), true);
675 } else {
676 ForceFakeCompositeSW();
678 } else {
679 // Pretend we just composited to unblock further invalidates.
680 DidComposite();
684 void BrowserViewRenderer::ForceFakeCompositeSW() {
685 DCHECK(compositor_);
686 SkBitmap bitmap;
687 bitmap.allocN32Pixels(1, 1);
688 bitmap.eraseColor(0);
689 SkCanvas canvas(bitmap);
690 CompositeSW(&canvas);
693 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
694 DCHECK(compositor_);
695 ReturnResourceFromParent();
696 bool result = compositor_->DemandDrawSw(canvas);
697 DidComposite();
698 return result;
701 void BrowserViewRenderer::DidComposite() {
702 block_invalidates_ = false;
703 post_fallback_tick_.Cancel();
704 fallback_tick_fired_.Cancel();
705 fallback_tick_pending_ = false;
706 EnsureContinuousInvalidation(false, false);
709 void BrowserViewRenderer::DidSkipCompositeInDraw() {
710 block_invalidates_ = false;
711 EnsureContinuousInvalidation(true, true);
714 std::string BrowserViewRenderer::ToString() const {
715 std::string str;
716 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
717 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
718 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
719 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
720 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
721 base::StringAppendF(&str,
722 "compositor_needs_continuous_invalidate: %d ",
723 compositor_needs_continuous_invalidate_);
724 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
725 base::StringAppendF(&str, "view size: %s ", size_.ToString().c_str());
726 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
727 base::StringAppendF(&str,
728 "global visible rect: %s ",
729 last_on_draw_global_visible_rect_.ToString().c_str());
730 base::StringAppendF(
731 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
732 base::StringAppendF(&str,
733 "overscroll_rounding_error_: %s ",
734 overscroll_rounding_error_.ToString().c_str());
735 base::StringAppendF(
736 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
737 base::StringAppendF(&str, "clear_view: %d ", clear_view_);
738 return str;
741 } // namespace android_webview