Revert of Disable spdy tests for constant failures on Volantis bot (patchset #2 id...
[chromium-blink-merge.git] / android_webview / browser / browser_view_renderer.cc
bloba2432efb52c7e38be362f857d08c9810f4f9cc0d
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 double kEpsilon = 1e-8;
29 const int64 kFallbackTickTimeoutInMilliseconds = 100;
31 // Used to calculate memory allocation. Determined experimentally.
32 const size_t kMemoryMultiplier = 20;
33 const size_t kBytesPerPixel = 4;
34 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
35 uint64 g_memory_override_in_bytes = 0u;
37 } // namespace
39 // static
40 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
41 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
43 // If the value was overridden on the command line, use the specified value.
44 bool client_hard_limit_bytes_overridden =
45 cl->HasSwitch(switches::kForceGpuMemAvailableMb);
46 if (client_hard_limit_bytes_overridden) {
47 base::StringToUint64(
48 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
49 switches::kForceGpuMemAvailableMb),
50 &g_memory_override_in_bytes);
51 g_memory_override_in_bytes *= 1024 * 1024;
55 BrowserViewRenderer::BrowserViewRenderer(
56 BrowserViewRendererClient* client,
57 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
58 : client_(client),
59 shared_renderer_state_(ui_task_runner, this),
60 ui_task_runner_(ui_task_runner),
61 compositor_(NULL),
62 is_paused_(false),
63 view_visible_(false),
64 window_visible_(false),
65 attached_to_window_(false),
66 hardware_enabled_(false),
67 dip_scale_(0.0),
68 page_scale_factor_(1.0),
69 on_new_picture_enable_(false),
70 clear_view_(false),
71 compositor_needs_continuous_invalidate_(false),
72 invalidate_after_composite_(false),
73 block_invalidates_(false),
74 fallback_tick_pending_(false) {
77 BrowserViewRenderer::~BrowserViewRenderer() {
80 SharedRendererState* BrowserViewRenderer::GetAwDrawGLViewContext() {
81 return &shared_renderer_state_;
84 bool BrowserViewRenderer::RequestDrawGL(bool wait_for_completion) {
85 return client_->RequestDrawGL(wait_for_completion);
88 // This function updates the resource allocation in GlobalTileManager.
89 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
90 DCHECK(ui_task_runner_->BelongsToCurrentThread());
91 // Constants from Android ComponentCallbacks2.
92 enum {
93 TRIM_MEMORY_RUNNING_LOW = 10,
94 TRIM_MEMORY_UI_HIDDEN = 20,
95 TRIM_MEMORY_BACKGROUND = 40,
96 TRIM_MEMORY_MODERATE = 60,
99 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
100 // it does not indicate memory pressure, but merely that the app is
101 // backgrounded.
102 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
103 return;
105 // Do not release resources on view we expect to get DrawGL soon.
106 if (level < TRIM_MEMORY_BACKGROUND && visible)
107 return;
109 // Nothing to drop.
110 if (!compositor_ || !hardware_enabled_)
111 return;
113 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
115 // Drop everything in hardware.
116 if (level >= TRIM_MEMORY_MODERATE) {
117 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
118 return;
121 // Just set the memory limit to 0 and drop all tiles. This will be reset to
122 // normal levels in the next DrawGL call.
123 compositor_->SetMemoryPolicy(0u);
124 ForceFakeCompositeSW();
127 size_t BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
128 if (g_memory_override_in_bytes)
129 return static_cast<size_t>(g_memory_override_in_bytes);
131 size_t width = last_on_draw_global_visible_rect_.width();
132 size_t height = last_on_draw_global_visible_rect_.height();
133 size_t bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
134 // Round up to a multiple of kMemoryAllocationStep.
135 bytes_limit =
136 (bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
137 return bytes_limit;
140 void BrowserViewRenderer::PrepareToDraw(const gfx::Vector2d& scroll,
141 const gfx::Rect& global_visible_rect) {
142 last_on_draw_scroll_offset_ = scroll;
143 last_on_draw_global_visible_rect_ = global_visible_rect;
146 bool BrowserViewRenderer::CanOnDraw() {
147 if (!compositor_) {
148 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_NoCompositor",
149 TRACE_EVENT_SCOPE_THREAD);
150 return false;
152 if (clear_view_) {
153 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_ClearView",
154 TRACE_EVENT_SCOPE_THREAD);
155 return false;
158 return true;
161 bool BrowserViewRenderer::OnDrawHardware() {
162 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
163 shared_renderer_state_.InitializeHardwareDrawIfNeededOnUI();
165 if (!CanOnDraw()) {
166 return false;
169 shared_renderer_state_.SetScrollOffsetOnUI(last_on_draw_scroll_offset_);
171 if (!hardware_enabled_) {
172 TRACE_EVENT0("android_webview", "InitializeHwDraw");
173 hardware_enabled_ = compositor_->InitializeHwDraw();
175 if (!hardware_enabled_) {
176 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_HardwareNotEnabled",
177 TRACE_EVENT_SCOPE_THREAD);
178 return false;
181 if (last_on_draw_global_visible_rect_.IsEmpty() &&
182 parent_draw_constraints_.surface_rect.IsEmpty()) {
183 TRACE_EVENT_INSTANT0("android_webview",
184 "EarlyOut_EmptyVisibleRect",
185 TRACE_EVENT_SCOPE_THREAD);
186 shared_renderer_state_.SetForceInvalidateOnNextDrawGLOnUI(true);
187 return true;
190 ReturnResourceFromParent();
191 if (shared_renderer_state_.HasCompositorFrameOnUI()) {
192 TRACE_EVENT_INSTANT0("android_webview",
193 "EarlyOut_PreviousFrameUnconsumed",
194 TRACE_EVENT_SCOPE_THREAD);
195 DidSkipCompositeInDraw();
196 return true;
199 scoped_ptr<cc::CompositorFrame> frame = CompositeHw();
200 if (!frame.get()) {
201 TRACE_EVENT_INSTANT0("android_webview", "NoNewFrame",
202 TRACE_EVENT_SCOPE_THREAD);
203 return false;
206 shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), false);
207 return true;
210 scoped_ptr<cc::CompositorFrame> BrowserViewRenderer::CompositeHw() {
211 compositor_->SetMemoryPolicy(CalculateDesiredMemoryPolicy());
213 parent_draw_constraints_ =
214 shared_renderer_state_.GetParentDrawConstraintsOnUI();
215 gfx::Size surface_size(size_);
216 gfx::Rect viewport(surface_size);
217 gfx::Rect clip = viewport;
218 gfx::Transform transform_for_tile_priority =
219 parent_draw_constraints_.transform;
221 // If the WebView is on a layer, WebView does not know what transform is
222 // applied onto the layer so global visible rect does not make sense here.
223 // In this case, just use the surface rect for tiling.
224 gfx::Rect viewport_rect_for_tile_priority;
225 if (parent_draw_constraints_.is_layer ||
226 last_on_draw_global_visible_rect_.IsEmpty()) {
227 viewport_rect_for_tile_priority = parent_draw_constraints_.surface_rect;
228 } else {
229 viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
232 scoped_ptr<cc::CompositorFrame> frame =
233 compositor_->DemandDrawHw(surface_size,
234 gfx::Transform(),
235 viewport,
236 clip,
237 viewport_rect_for_tile_priority,
238 transform_for_tile_priority);
239 if (frame.get())
240 DidComposite();
241 return frame.Pass();
244 void BrowserViewRenderer::UpdateParentDrawConstraints() {
245 // Post an invalidate if the parent draw constraints are stale and there is
246 // no pending invalidate.
247 bool needs_force_invalidate =
248 shared_renderer_state_.NeedsForceInvalidateOnNextDrawGLOnUI();
249 if (needs_force_invalidate ||
250 !parent_draw_constraints_.Equals(
251 shared_renderer_state_.GetParentDrawConstraintsOnUI())) {
252 shared_renderer_state_.SetForceInvalidateOnNextDrawGLOnUI(false);
253 EnsureContinuousInvalidation(true, needs_force_invalidate);
257 void BrowserViewRenderer::ReturnUnusedResource(
258 scoped_ptr<cc::CompositorFrame> frame) {
259 if (!frame.get())
260 return;
262 cc::CompositorFrameAck frame_ack;
263 cc::TransferableResource::ReturnResources(
264 frame->delegated_frame_data->resource_list, &frame_ack.resources);
265 if (compositor_ && !frame_ack.resources.empty())
266 compositor_->ReturnResources(frame_ack);
269 void BrowserViewRenderer::ReturnResourceFromParent() {
270 cc::CompositorFrameAck frame_ack;
271 shared_renderer_state_.SwapReturnedResourcesOnUI(&frame_ack.resources);
272 if (compositor_ && !frame_ack.resources.empty()) {
273 compositor_->ReturnResources(frame_ack);
277 void BrowserViewRenderer::DidSkipCommitFrame() {
278 // Treat it the same way as skipping onDraw.
279 DidSkipCompositeInDraw();
282 void BrowserViewRenderer::InvalidateOnFunctorDestroy() {
283 client_->InvalidateOnFunctorDestroy();
286 bool BrowserViewRenderer::OnDrawSoftware(SkCanvas* canvas) {
287 return CanOnDraw() && CompositeSW(canvas);
290 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
291 int height) {
292 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
294 // Return empty Picture objects for empty SkPictures.
295 if (width <= 0 || height <= 0) {
296 SkPictureRecorder emptyRecorder;
297 emptyRecorder.beginRecording(0, 0);
298 return skia::AdoptRef(emptyRecorder.endRecording());
301 // Reset scroll back to the origin, will go back to the old
302 // value when scroll_reset is out of scope.
303 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
304 gfx::Vector2dF());
306 SkPictureRecorder recorder;
307 SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
308 if (compositor_)
309 CompositeSW(rec_canvas);
310 return skia::AdoptRef(recorder.endRecording());
313 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
314 on_new_picture_enable_ = enabled;
317 void BrowserViewRenderer::ClearView() {
318 TRACE_EVENT_INSTANT0("android_webview",
319 "BrowserViewRenderer::ClearView",
320 TRACE_EVENT_SCOPE_THREAD);
321 if (clear_view_)
322 return;
324 clear_view_ = true;
325 // Always invalidate ignoring the compositor to actually clear the webview.
326 EnsureContinuousInvalidation(true, false);
329 void BrowserViewRenderer::SetIsPaused(bool paused) {
330 TRACE_EVENT_INSTANT1("android_webview",
331 "BrowserViewRenderer::SetIsPaused",
332 TRACE_EVENT_SCOPE_THREAD,
333 "paused",
334 paused);
335 is_paused_ = paused;
336 EnsureContinuousInvalidation(false, false);
339 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
340 TRACE_EVENT_INSTANT1("android_webview",
341 "BrowserViewRenderer::SetViewVisibility",
342 TRACE_EVENT_SCOPE_THREAD,
343 "view_visible",
344 view_visible);
345 view_visible_ = view_visible;
348 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
349 TRACE_EVENT_INSTANT1("android_webview",
350 "BrowserViewRenderer::SetWindowVisibility",
351 TRACE_EVENT_SCOPE_THREAD,
352 "window_visible",
353 window_visible);
354 window_visible_ = window_visible;
355 EnsureContinuousInvalidation(false, false);
358 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
359 TRACE_EVENT_INSTANT2("android_webview",
360 "BrowserViewRenderer::OnSizeChanged",
361 TRACE_EVENT_SCOPE_THREAD,
362 "width",
363 width,
364 "height",
365 height);
366 size_.SetSize(width, height);
369 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
370 TRACE_EVENT2("android_webview",
371 "BrowserViewRenderer::OnAttachedToWindow",
372 "width",
373 width,
374 "height",
375 height);
376 attached_to_window_ = true;
377 size_.SetSize(width, height);
380 void BrowserViewRenderer::OnDetachedFromWindow() {
381 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
382 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
383 attached_to_window_ = false;
384 DCHECK(!hardware_enabled_);
387 void BrowserViewRenderer::ReleaseHardware() {
388 DCHECK(hardware_enabled_);
389 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
390 ReturnResourceFromParent();
391 DCHECK(shared_renderer_state_.ReturnedResourcesEmptyOnUI());
393 if (compositor_) {
394 compositor_->ReleaseHwDraw();
397 hardware_enabled_ = false;
400 bool BrowserViewRenderer::IsVisible() const {
401 // Ignore |window_visible_| if |attached_to_window_| is false.
402 return view_visible_ && (!attached_to_window_ || window_visible_);
405 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
406 return gfx::Rect(client_->GetLocationOnScreen(), size_);
409 void BrowserViewRenderer::DidInitializeCompositor(
410 content::SynchronousCompositor* compositor) {
411 TRACE_EVENT0("android_webview",
412 "BrowserViewRenderer::DidInitializeCompositor");
413 DCHECK(compositor);
414 DCHECK(!compositor_);
415 compositor_ = compositor;
418 void BrowserViewRenderer::DidDestroyCompositor(
419 content::SynchronousCompositor* compositor) {
420 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
421 DCHECK(compositor_);
422 compositor_ = NULL;
425 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
426 if (compositor_needs_continuous_invalidate_ == invalidate)
427 return;
429 TRACE_EVENT_INSTANT1("android_webview",
430 "BrowserViewRenderer::SetContinuousInvalidate",
431 TRACE_EVENT_SCOPE_THREAD,
432 "invalidate",
433 invalidate);
434 compositor_needs_continuous_invalidate_ = invalidate;
436 EnsureContinuousInvalidation(false, false);
439 void BrowserViewRenderer::SetDipScale(float dip_scale) {
440 dip_scale_ = dip_scale;
441 CHECK_GT(dip_scale_, 0.f);
444 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
445 DCHECK_GT(dip_scale_, 0.f);
446 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
447 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
450 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
451 gfx::Vector2d max_offset = max_scroll_offset();
452 gfx::Vector2dF scroll_offset_dip;
453 // To preserve the invariant that scrolling to the maximum physical pixel
454 // value also scrolls to the maximum dip pixel value we transform the physical
455 // offset into the dip offset by using a proportion (instead of dividing by
456 // dip_scale * page_scale_factor).
457 if (max_offset.x()) {
458 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
459 max_offset.x());
461 if (max_offset.y()) {
462 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
463 max_offset.y());
466 DCHECK_LE(0.f, scroll_offset_dip.x());
467 DCHECK_LE(0.f, scroll_offset_dip.y());
468 DCHECK(scroll_offset_dip.x() < max_scroll_offset_dip_.x() ||
469 scroll_offset_dip.x() - max_scroll_offset_dip_.x() < kEpsilon)
470 << scroll_offset_dip.x() << " " << max_scroll_offset_dip_.x();
471 DCHECK(scroll_offset_dip.y() < max_scroll_offset_dip_.y() ||
472 scroll_offset_dip.y() - max_scroll_offset_dip_.y() < kEpsilon)
473 << scroll_offset_dip.y() << " " << max_scroll_offset_dip_.y();
475 if (scroll_offset_dip_ == scroll_offset_dip)
476 return;
478 scroll_offset_dip_ = scroll_offset_dip;
480 TRACE_EVENT_INSTANT2("android_webview",
481 "BrowserViewRenderer::ScrollTo",
482 TRACE_EVENT_SCOPE_THREAD,
483 "x",
484 scroll_offset_dip.x(),
485 "y",
486 scroll_offset_dip.y());
488 if (compositor_)
489 compositor_->DidChangeRootLayerScrollOffset();
492 void BrowserViewRenderer::DidUpdateContent() {
493 TRACE_EVENT_INSTANT0("android_webview",
494 "BrowserViewRenderer::DidUpdateContent",
495 TRACE_EVENT_SCOPE_THREAD);
496 clear_view_ = false;
497 if (on_new_picture_enable_)
498 client_->OnNewPicture();
501 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
502 gfx::Vector2dF scroll_offset_dip) {
503 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
504 // DrawGl when http://crbug.com/249972 is fixed.
505 if (scroll_offset_dip_ == scroll_offset_dip)
506 return;
508 scroll_offset_dip_ = scroll_offset_dip;
510 gfx::Vector2d max_offset = max_scroll_offset();
511 gfx::Vector2d scroll_offset;
512 // For an explanation as to why this is done this way see the comment in
513 // BrowserViewRenderer::ScrollTo.
514 if (max_scroll_offset_dip_.x()) {
515 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
516 max_scroll_offset_dip_.x());
519 if (max_scroll_offset_dip_.y()) {
520 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
521 max_scroll_offset_dip_.y());
524 DCHECK_LE(0, scroll_offset.x());
525 DCHECK_LE(0, scroll_offset.y());
526 DCHECK_LE(scroll_offset.x(), max_offset.x());
527 DCHECK_LE(scroll_offset.y(), max_offset.y());
529 client_->ScrollContainerViewTo(scroll_offset);
532 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
533 return scroll_offset_dip_;
536 bool BrowserViewRenderer::IsExternalFlingActive() const {
537 return client_->IsFlingActive();
540 void BrowserViewRenderer::UpdateRootLayerState(
541 const gfx::Vector2dF& total_scroll_offset_dip,
542 const gfx::Vector2dF& max_scroll_offset_dip,
543 const gfx::SizeF& scrollable_size_dip,
544 float page_scale_factor,
545 float min_page_scale_factor,
546 float max_page_scale_factor) {
547 TRACE_EVENT_INSTANT1(
548 "android_webview",
549 "BrowserViewRenderer::UpdateRootLayerState",
550 TRACE_EVENT_SCOPE_THREAD,
551 "state",
552 RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip));
554 DCHECK_GT(dip_scale_, 0.f);
556 max_scroll_offset_dip_ = max_scroll_offset_dip;
557 DCHECK_LE(0.f, max_scroll_offset_dip_.x());
558 DCHECK_LE(0.f, max_scroll_offset_dip_.y());
560 page_scale_factor_ = page_scale_factor;
561 DCHECK_GT(page_scale_factor_, 0.f);
563 client_->UpdateScrollState(max_scroll_offset(),
564 scrollable_size_dip,
565 page_scale_factor,
566 min_page_scale_factor,
567 max_page_scale_factor);
568 SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
571 scoped_refptr<base::debug::ConvertableToTraceFormat>
572 BrowserViewRenderer::RootLayerStateAsValue(
573 const gfx::Vector2dF& total_scroll_offset_dip,
574 const gfx::SizeF& scrollable_size_dip) {
575 scoped_refptr<base::debug::TracedValue> state =
576 new base::debug::TracedValue();
578 state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x());
579 state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y());
581 state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x());
582 state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y());
584 state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
585 state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
587 state->SetDouble("page_scale_factor", page_scale_factor_);
588 return state;
591 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
592 gfx::Vector2dF latest_overscroll_delta,
593 gfx::Vector2dF current_fling_velocity) {
594 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
595 if (accumulated_overscroll == latest_overscroll_delta)
596 overscroll_rounding_error_ = gfx::Vector2dF();
597 gfx::Vector2dF scaled_overscroll_delta =
598 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
599 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
600 scaled_overscroll_delta + overscroll_rounding_error_);
601 overscroll_rounding_error_ =
602 scaled_overscroll_delta - rounded_overscroll_delta;
603 client_->DidOverscroll(rounded_overscroll_delta);
606 void BrowserViewRenderer::EnsureContinuousInvalidation(
607 bool force_invalidate,
608 bool skip_reschedule_tick) {
609 if (force_invalidate)
610 invalidate_after_composite_ = true;
612 // This method should be called again when any of these conditions change.
613 bool need_invalidate =
614 compositor_needs_continuous_invalidate_ || invalidate_after_composite_;
615 if (!need_invalidate || block_invalidates_)
616 return;
618 if (!compositor_needs_continuous_invalidate_ && invalidate_after_composite_)
619 invalidate_after_composite_ = false;
621 // Always call view invalidate. We rely the Android framework to ignore the
622 // invalidate when it's not needed such as when view is not visible.
623 client_->PostInvalidate();
625 // Stop fallback ticks when one of these is true.
626 // 1) Webview is paused. Also need to check we are not in clear view since
627 // paused, offscreen still expect clear view to recover.
628 // 2) If we are attached to window and the window is not visible (eg when
629 // app is in the background). We are sure in this case the webview is used
630 // "on-screen" but that updates are not needed when in the background.
631 bool throttle_fallback_tick =
632 (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
633 if (throttle_fallback_tick)
634 return;
636 block_invalidates_ = compositor_needs_continuous_invalidate_;
637 if (skip_reschedule_tick && fallback_tick_pending_)
638 return;
640 // Unretained here is safe because the callbacks are cancelled when
641 // they are destroyed.
642 post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick,
643 base::Unretained(this)));
644 fallback_tick_fired_.Cancel();
645 fallback_tick_pending_ = false;
647 // No need to reschedule fallback tick if compositor does not need to be
648 // ticked. This can happen if this is reached because force_invalidate is
649 // true.
650 if (compositor_needs_continuous_invalidate_) {
651 fallback_tick_pending_ = true;
652 ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
656 void BrowserViewRenderer::PostFallbackTick() {
657 DCHECK(fallback_tick_fired_.IsCancelled());
658 fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
659 base::Unretained(this)));
660 if (compositor_needs_continuous_invalidate_) {
661 ui_task_runner_->PostDelayedTask(
662 FROM_HERE,
663 fallback_tick_fired_.callback(),
664 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
665 } else {
666 // Pretend we just composited to unblock further invalidates.
667 DidComposite();
671 void BrowserViewRenderer::FallbackTickFired() {
672 TRACE_EVENT1("android_webview",
673 "BrowserViewRenderer::FallbackTickFired",
674 "compositor_needs_continuous_invalidate_",
675 compositor_needs_continuous_invalidate_);
677 // This should only be called if OnDraw or DrawGL did not come in time, which
678 // means block_invalidates_ must still be true.
679 DCHECK(block_invalidates_);
680 fallback_tick_pending_ = false;
681 if (compositor_needs_continuous_invalidate_ && compositor_) {
682 if (hardware_enabled_) {
683 ReturnResourceFromParent();
684 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
685 scoped_ptr<cc::CompositorFrame> frame = CompositeHw();
686 if (frame.get()) {
687 shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), true);
689 } else {
690 ForceFakeCompositeSW();
692 } else {
693 // Pretend we just composited to unblock further invalidates.
694 DidComposite();
698 void BrowserViewRenderer::ForceFakeCompositeSW() {
699 DCHECK(compositor_);
700 SkBitmap bitmap;
701 bitmap.allocN32Pixels(1, 1);
702 bitmap.eraseColor(0);
703 SkCanvas canvas(bitmap);
704 CompositeSW(&canvas);
707 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
708 DCHECK(compositor_);
709 ReturnResourceFromParent();
710 bool result = compositor_->DemandDrawSw(canvas);
711 DidComposite();
712 return result;
715 void BrowserViewRenderer::DidComposite() {
716 block_invalidates_ = false;
717 post_fallback_tick_.Cancel();
718 fallback_tick_fired_.Cancel();
719 fallback_tick_pending_ = false;
720 EnsureContinuousInvalidation(false, false);
723 void BrowserViewRenderer::DidSkipCompositeInDraw() {
724 block_invalidates_ = false;
725 EnsureContinuousInvalidation(true, true);
728 std::string BrowserViewRenderer::ToString() const {
729 std::string str;
730 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
731 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
732 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
733 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
734 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
735 base::StringAppendF(&str,
736 "compositor_needs_continuous_invalidate: %d ",
737 compositor_needs_continuous_invalidate_);
738 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
739 base::StringAppendF(&str, "view size: %s ", size_.ToString().c_str());
740 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
741 base::StringAppendF(&str,
742 "global visible rect: %s ",
743 last_on_draw_global_visible_rect_.ToString().c_str());
744 base::StringAppendF(
745 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
746 base::StringAppendF(&str,
747 "overscroll_rounding_error_: %s ",
748 overscroll_rounding_error_.ToString().c_str());
749 base::StringAppendF(
750 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
751 base::StringAppendF(&str, "clear_view: %d ", clear_view_);
752 return str;
755 } // namespace android_webview