Add test_runner support for new accessibility event
[chromium-blink-merge.git] / android_webview / browser / browser_view_renderer.cc
blob6b4ee929ec07988429f16de61e0a5c6adfcb112d
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/vector2d_conversions.h"
26 namespace android_webview {
28 namespace {
30 const double kEpsilon = 1e-8;
32 const int64 kFallbackTickTimeoutInMilliseconds = 100;
34 // Used to calculate memory allocation. Determined experimentally.
35 const size_t kMemoryMultiplier = 20;
36 const size_t kBytesPerPixel = 4;
37 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
38 uint64 g_memory_override_in_bytes = 0u;
40 const void* kBrowserViewRendererUserDataKey = &kBrowserViewRendererUserDataKey;
42 class BrowserViewRendererUserData : public base::SupportsUserData::Data {
43 public:
44 BrowserViewRendererUserData(BrowserViewRenderer* ptr) : bvr_(ptr) {}
46 static BrowserViewRenderer* GetBrowserViewRenderer(
47 content::WebContents* web_contents) {
48 if (!web_contents)
49 return NULL;
50 BrowserViewRendererUserData* data =
51 static_cast<BrowserViewRendererUserData*>(
52 web_contents->GetUserData(kBrowserViewRendererUserDataKey));
53 return data ? data->bvr_ : NULL;
56 private:
57 BrowserViewRenderer* bvr_;
60 } // namespace
62 // static
63 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
64 base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
66 // If the value was overridden on the command line, use the specified value.
67 bool client_hard_limit_bytes_overridden =
68 cl->HasSwitch(switches::kForceGpuMemAvailableMb);
69 if (client_hard_limit_bytes_overridden) {
70 base::StringToUint64(
71 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
72 switches::kForceGpuMemAvailableMb),
73 &g_memory_override_in_bytes);
74 g_memory_override_in_bytes *= 1024 * 1024;
78 // static
79 BrowserViewRenderer* BrowserViewRenderer::FromWebContents(
80 content::WebContents* web_contents) {
81 return BrowserViewRendererUserData::GetBrowserViewRenderer(web_contents);
84 BrowserViewRenderer::BrowserViewRenderer(
85 BrowserViewRendererClient* client,
86 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
87 : client_(client),
88 shared_renderer_state_(ui_task_runner, this),
89 ui_task_runner_(ui_task_runner),
90 compositor_(NULL),
91 is_paused_(false),
92 view_visible_(false),
93 window_visible_(false),
94 attached_to_window_(false),
95 hardware_enabled_(false),
96 dip_scale_(0.0),
97 page_scale_factor_(1.0),
98 on_new_picture_enable_(false),
99 clear_view_(false),
100 offscreen_pre_raster_(false),
101 compositor_needs_continuous_invalidate_(false),
102 block_invalidates_(false),
103 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 // This function updates the resource allocation in GlobalTileManager.
124 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
125 DCHECK(ui_task_runner_->BelongsToCurrentThread());
126 // Constants from Android ComponentCallbacks2.
127 enum {
128 TRIM_MEMORY_RUNNING_LOW = 10,
129 TRIM_MEMORY_UI_HIDDEN = 20,
130 TRIM_MEMORY_BACKGROUND = 40,
131 TRIM_MEMORY_MODERATE = 60,
134 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
135 // it does not indicate memory pressure, but merely that the app is
136 // backgrounded.
137 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
138 return;
140 // Do not release resources on view we expect to get DrawGL soon.
141 if (level < TRIM_MEMORY_BACKGROUND && visible)
142 return;
144 // Nothing to drop.
145 if (!compositor_ || !hardware_enabled_)
146 return;
148 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
150 // Drop everything in hardware.
151 if (level >= TRIM_MEMORY_MODERATE) {
152 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
153 return;
156 // Just set the memory limit to 0 and drop all tiles. This will be reset to
157 // normal levels in the next DrawGL call.
158 compositor_->SetMemoryPolicy(0u);
159 ForceFakeCompositeSW();
162 size_t BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
163 if (g_memory_override_in_bytes)
164 return static_cast<size_t>(g_memory_override_in_bytes);
166 gfx::Rect interest_rect = offscreen_pre_raster_
167 ? gfx::Rect(size_)
168 : last_on_draw_global_visible_rect_;
169 size_t width = interest_rect.width();
170 size_t height = interest_rect.height();
171 size_t bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
172 // Round up to a multiple of kMemoryAllocationStep.
173 bytes_limit =
174 (bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
175 return bytes_limit;
178 void BrowserViewRenderer::PrepareToDraw(const gfx::Vector2d& scroll,
179 const gfx::Rect& global_visible_rect) {
180 last_on_draw_scroll_offset_ = scroll;
181 last_on_draw_global_visible_rect_ = global_visible_rect;
184 bool BrowserViewRenderer::CanOnDraw() {
185 if (!compositor_) {
186 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_NoCompositor",
187 TRACE_EVENT_SCOPE_THREAD);
188 return false;
190 if (clear_view_) {
191 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_ClearView",
192 TRACE_EVENT_SCOPE_THREAD);
193 return false;
196 return true;
199 bool BrowserViewRenderer::OnDrawHardware() {
200 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
201 shared_renderer_state_.InitializeHardwareDrawIfNeededOnUI();
203 if (!CanOnDraw()) {
204 return false;
207 shared_renderer_state_.SetScrollOffsetOnUI(last_on_draw_scroll_offset_);
209 if (!hardware_enabled_) {
210 TRACE_EVENT0("android_webview", "InitializeHwDraw");
211 hardware_enabled_ = compositor_->InitializeHwDraw();
213 if (!hardware_enabled_) {
214 TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_HardwareNotEnabled",
215 TRACE_EVENT_SCOPE_THREAD);
216 return false;
219 return CompositeHw();
222 bool BrowserViewRenderer::CompositeHw() {
223 ReturnResourceFromParent();
224 compositor_->SetMemoryPolicy(CalculateDesiredMemoryPolicy());
226 ParentCompositorDrawConstraints parent_draw_constraints =
227 shared_renderer_state_.GetParentDrawConstraintsOnUI();
228 gfx::Size surface_size(size_);
229 gfx::Rect viewport(surface_size);
230 gfx::Rect clip = viewport;
231 gfx::Transform transform_for_tile_priority =
232 parent_draw_constraints.transform;
234 // If the WebView is on a layer, WebView does not know what transform is
235 // applied onto the layer so global visible rect does not make sense here.
236 // In this case, just use the surface rect for tiling.
237 gfx::Rect viewport_rect_for_tile_priority;
239 // Leave viewport_rect_for_tile_priority empty if offscreen_pre_raster_ is on.
240 if (!offscreen_pre_raster_) {
241 if (parent_draw_constraints.is_layer) {
242 viewport_rect_for_tile_priority = parent_draw_constraints.surface_rect;
243 } else {
244 viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
248 scoped_ptr<cc::CompositorFrame> frame =
249 compositor_->DemandDrawHw(surface_size,
250 gfx::Transform(),
251 viewport,
252 clip,
253 viewport_rect_for_tile_priority,
254 transform_for_tile_priority);
255 if (!frame.get()) {
256 TRACE_EVENT_INSTANT0("android_webview", "NoNewFrame",
257 TRACE_EVENT_SCOPE_THREAD);
258 return false;
261 scoped_ptr<ChildFrame> child_frame = make_scoped_ptr(
262 new ChildFrame(frame.Pass(), viewport_rect_for_tile_priority,
263 transform_for_tile_priority, offscreen_pre_raster_,
264 parent_draw_constraints.is_layer));
266 DidComposite();
267 // Uncommitted frame can happen with consecutive fallback ticks.
268 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
269 shared_renderer_state_.SetCompositorFrameOnUI(child_frame.Pass());
270 return true;
273 void BrowserViewRenderer::UpdateParentDrawConstraints() {
274 EnsureContinuousInvalidation(true);
275 ParentCompositorDrawConstraints parent_draw_constraints =
276 shared_renderer_state_.GetParentDrawConstraintsOnUI();
277 client_->ParentDrawConstraintsUpdated(parent_draw_constraints);
280 void BrowserViewRenderer::ReturnUnusedResource(
281 scoped_ptr<ChildFrame> child_frame) {
282 if (!child_frame.get() || !child_frame->frame.get())
283 return;
285 cc::CompositorFrameAck frame_ack;
286 cc::TransferableResource::ReturnResources(
287 child_frame->frame->delegated_frame_data->resource_list,
288 &frame_ack.resources);
289 if (compositor_ && !frame_ack.resources.empty())
290 compositor_->ReturnResources(frame_ack);
293 void BrowserViewRenderer::ReturnResourceFromParent() {
294 cc::CompositorFrameAck frame_ack;
295 shared_renderer_state_.SwapReturnedResourcesOnUI(&frame_ack.resources);
296 if (compositor_ && !frame_ack.resources.empty()) {
297 compositor_->ReturnResources(frame_ack);
301 void BrowserViewRenderer::DetachFunctorFromView() {
302 client_->DetachFunctorFromView();
305 bool BrowserViewRenderer::OnDrawSoftware(SkCanvas* canvas) {
306 return CanOnDraw() && CompositeSW(canvas);
309 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
310 int height) {
311 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
313 // Return empty Picture objects for empty SkPictures.
314 if (width <= 0 || height <= 0) {
315 SkPictureRecorder emptyRecorder;
316 emptyRecorder.beginRecording(0, 0);
317 return skia::AdoptRef(emptyRecorder.endRecording());
320 // Reset scroll back to the origin, will go back to the old
321 // value when scroll_reset is out of scope.
322 base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
323 gfx::Vector2dF());
325 SkPictureRecorder recorder;
326 SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
327 if (compositor_)
328 CompositeSW(rec_canvas);
329 return skia::AdoptRef(recorder.endRecording());
332 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
333 on_new_picture_enable_ = enabled;
336 void BrowserViewRenderer::ClearView() {
337 TRACE_EVENT_INSTANT0("android_webview",
338 "BrowserViewRenderer::ClearView",
339 TRACE_EVENT_SCOPE_THREAD);
340 if (clear_view_)
341 return;
343 clear_view_ = true;
344 // Always invalidate ignoring the compositor to actually clear the webview.
345 EnsureContinuousInvalidation(true);
348 void BrowserViewRenderer::SetOffscreenPreRaster(bool enable) {
349 // TODO(hush): anything to do when the setting is toggled?
350 offscreen_pre_raster_ = enable;
353 void BrowserViewRenderer::SetIsPaused(bool paused) {
354 TRACE_EVENT_INSTANT1("android_webview",
355 "BrowserViewRenderer::SetIsPaused",
356 TRACE_EVENT_SCOPE_THREAD,
357 "paused",
358 paused);
359 is_paused_ = paused;
360 EnsureContinuousInvalidation(false);
363 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
364 TRACE_EVENT_INSTANT1("android_webview",
365 "BrowserViewRenderer::SetViewVisibility",
366 TRACE_EVENT_SCOPE_THREAD,
367 "view_visible",
368 view_visible);
369 view_visible_ = view_visible;
372 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
373 TRACE_EVENT_INSTANT1("android_webview",
374 "BrowserViewRenderer::SetWindowVisibility",
375 TRACE_EVENT_SCOPE_THREAD,
376 "window_visible",
377 window_visible);
378 window_visible_ = window_visible;
379 EnsureContinuousInvalidation(false);
382 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
383 TRACE_EVENT_INSTANT2("android_webview",
384 "BrowserViewRenderer::OnSizeChanged",
385 TRACE_EVENT_SCOPE_THREAD,
386 "width",
387 width,
388 "height",
389 height);
390 size_.SetSize(width, height);
393 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
394 TRACE_EVENT2("android_webview",
395 "BrowserViewRenderer::OnAttachedToWindow",
396 "width",
397 width,
398 "height",
399 height);
400 attached_to_window_ = true;
401 size_.SetSize(width, height);
404 void BrowserViewRenderer::OnDetachedFromWindow() {
405 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
406 shared_renderer_state_.ReleaseHardwareDrawIfNeededOnUI();
407 attached_to_window_ = false;
408 DCHECK(!hardware_enabled_);
411 void BrowserViewRenderer::ReleaseHardware() {
412 DCHECK(hardware_enabled_);
413 ReturnUnusedResource(shared_renderer_state_.PassUncommittedFrameOnUI());
414 ReturnResourceFromParent();
415 DCHECK(shared_renderer_state_.ReturnedResourcesEmptyOnUI());
417 if (compositor_) {
418 compositor_->ReleaseHwDraw();
421 hardware_enabled_ = false;
424 bool BrowserViewRenderer::IsVisible() const {
425 // Ignore |window_visible_| if |attached_to_window_| is false.
426 return view_visible_ && (!attached_to_window_ || window_visible_);
429 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
430 return gfx::Rect(client_->GetLocationOnScreen(), size_);
433 void BrowserViewRenderer::DidInitializeCompositor(
434 content::SynchronousCompositor* compositor) {
435 TRACE_EVENT0("android_webview",
436 "BrowserViewRenderer::DidInitializeCompositor");
437 DCHECK(compositor);
438 DCHECK(!compositor_);
439 compositor_ = compositor;
442 void BrowserViewRenderer::DidDestroyCompositor(
443 content::SynchronousCompositor* compositor) {
444 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
445 DCHECK(compositor_);
446 compositor_ = NULL;
449 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
450 if (compositor_needs_continuous_invalidate_ == invalidate)
451 return;
453 TRACE_EVENT_INSTANT1("android_webview",
454 "BrowserViewRenderer::SetContinuousInvalidate",
455 TRACE_EVENT_SCOPE_THREAD,
456 "invalidate",
457 invalidate);
458 compositor_needs_continuous_invalidate_ = invalidate;
460 EnsureContinuousInvalidation(false);
463 void BrowserViewRenderer::SetDipScale(float dip_scale) {
464 dip_scale_ = dip_scale;
465 CHECK_GT(dip_scale_, 0.f);
468 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
469 DCHECK_GT(dip_scale_, 0.f);
470 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
471 max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
474 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
475 gfx::Vector2d max_offset = max_scroll_offset();
476 gfx::Vector2dF scroll_offset_dip;
477 // To preserve the invariant that scrolling to the maximum physical pixel
478 // value also scrolls to the maximum dip pixel value we transform the physical
479 // offset into the dip offset by using a proportion (instead of dividing by
480 // dip_scale * page_scale_factor).
481 if (max_offset.x()) {
482 scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
483 max_offset.x());
485 if (max_offset.y()) {
486 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
487 max_offset.y());
490 DCHECK_LE(0.f, scroll_offset_dip.x());
491 DCHECK_LE(0.f, scroll_offset_dip.y());
492 DCHECK(scroll_offset_dip.x() < max_scroll_offset_dip_.x() ||
493 scroll_offset_dip.x() - max_scroll_offset_dip_.x() < kEpsilon)
494 << scroll_offset_dip.x() << " " << max_scroll_offset_dip_.x();
495 DCHECK(scroll_offset_dip.y() < max_scroll_offset_dip_.y() ||
496 scroll_offset_dip.y() - max_scroll_offset_dip_.y() < kEpsilon)
497 << scroll_offset_dip.y() << " " << max_scroll_offset_dip_.y();
499 if (scroll_offset_dip_ == scroll_offset_dip)
500 return;
502 scroll_offset_dip_ = scroll_offset_dip;
504 TRACE_EVENT_INSTANT2("android_webview",
505 "BrowserViewRenderer::ScrollTo",
506 TRACE_EVENT_SCOPE_THREAD,
507 "x",
508 scroll_offset_dip.x(),
509 "y",
510 scroll_offset_dip.y());
512 if (compositor_)
513 compositor_->DidChangeRootLayerScrollOffset();
516 void BrowserViewRenderer::DidUpdateContent() {
517 TRACE_EVENT_INSTANT0("android_webview",
518 "BrowserViewRenderer::DidUpdateContent",
519 TRACE_EVENT_SCOPE_THREAD);
520 clear_view_ = false;
521 if (on_new_picture_enable_)
522 client_->OnNewPicture();
525 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
526 gfx::Vector2dF scroll_offset_dip) {
527 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
528 // DrawGl when http://crbug.com/249972 is fixed.
529 if (scroll_offset_dip_ == scroll_offset_dip)
530 return;
532 scroll_offset_dip_ = scroll_offset_dip;
534 gfx::Vector2d max_offset = max_scroll_offset();
535 gfx::Vector2d scroll_offset;
536 // For an explanation as to why this is done this way see the comment in
537 // BrowserViewRenderer::ScrollTo.
538 if (max_scroll_offset_dip_.x()) {
539 scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
540 max_scroll_offset_dip_.x());
543 if (max_scroll_offset_dip_.y()) {
544 scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
545 max_scroll_offset_dip_.y());
548 DCHECK_LE(0, scroll_offset.x());
549 DCHECK_LE(0, scroll_offset.y());
550 DCHECK_LE(scroll_offset.x(), max_offset.x());
551 DCHECK_LE(scroll_offset.y(), max_offset.y());
553 client_->ScrollContainerViewTo(scroll_offset);
556 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
557 return scroll_offset_dip_;
560 bool BrowserViewRenderer::IsExternalFlingActive() const {
561 return client_->IsFlingActive();
564 void BrowserViewRenderer::UpdateRootLayerState(
565 const gfx::Vector2dF& total_scroll_offset_dip,
566 const gfx::Vector2dF& max_scroll_offset_dip,
567 const gfx::SizeF& scrollable_size_dip,
568 float page_scale_factor,
569 float min_page_scale_factor,
570 float max_page_scale_factor) {
571 TRACE_EVENT_INSTANT1(
572 "android_webview",
573 "BrowserViewRenderer::UpdateRootLayerState",
574 TRACE_EVENT_SCOPE_THREAD,
575 "state",
576 RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip));
578 DCHECK_GT(dip_scale_, 0.f);
580 max_scroll_offset_dip_ = max_scroll_offset_dip;
581 DCHECK_LE(0.f, max_scroll_offset_dip_.x());
582 DCHECK_LE(0.f, max_scroll_offset_dip_.y());
584 page_scale_factor_ = page_scale_factor;
585 DCHECK_GT(page_scale_factor_, 0.f);
587 client_->UpdateScrollState(max_scroll_offset(),
588 scrollable_size_dip,
589 page_scale_factor,
590 min_page_scale_factor,
591 max_page_scale_factor);
592 SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
595 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
596 BrowserViewRenderer::RootLayerStateAsValue(
597 const gfx::Vector2dF& total_scroll_offset_dip,
598 const gfx::SizeF& scrollable_size_dip) {
599 scoped_refptr<base::trace_event::TracedValue> state =
600 new base::trace_event::TracedValue();
602 state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x());
603 state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y());
605 state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x());
606 state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y());
608 state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
609 state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
611 state->SetDouble("page_scale_factor", page_scale_factor_);
612 return state;
615 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
616 gfx::Vector2dF latest_overscroll_delta,
617 gfx::Vector2dF current_fling_velocity) {
618 const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
619 if (accumulated_overscroll == latest_overscroll_delta)
620 overscroll_rounding_error_ = gfx::Vector2dF();
621 gfx::Vector2dF scaled_overscroll_delta =
622 gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
623 gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
624 scaled_overscroll_delta + overscroll_rounding_error_);
625 overscroll_rounding_error_ =
626 scaled_overscroll_delta - rounded_overscroll_delta;
627 client_->DidOverscroll(rounded_overscroll_delta);
630 void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate) {
631 // This method should be called again when any of these conditions change.
632 bool need_invalidate =
633 compositor_needs_continuous_invalidate_ || force_invalidate;
634 if (!need_invalidate || block_invalidates_)
635 return;
637 // Always call view invalidate. We rely the Android framework to ignore the
638 // invalidate when it's not needed such as when view is not visible.
639 client_->PostInvalidate();
641 // Stop fallback ticks when one of these is true.
642 // 1) Webview is paused. Also need to check we are not in clear view since
643 // paused, offscreen still expect clear view to recover.
644 // 2) If we are attached to window and the window is not visible (eg when
645 // app is in the background). We are sure in this case the webview is used
646 // "on-screen" but that updates are not needed when in the background.
647 bool throttle_fallback_tick =
648 (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
649 if (throttle_fallback_tick)
650 return;
652 block_invalidates_ = compositor_needs_continuous_invalidate_;
653 if (fallback_tick_pending_)
654 return;
656 // Unretained here is safe because the callbacks are cancelled when
657 // they are destroyed.
658 post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick,
659 base::Unretained(this)));
660 fallback_tick_fired_.Cancel();
661 fallback_tick_pending_ = false;
663 // No need to reschedule fallback tick if compositor does not need to be
664 // ticked. This can happen if this is reached because force_invalidate is
665 // true.
666 if (compositor_needs_continuous_invalidate_) {
667 fallback_tick_pending_ = true;
668 ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
672 void BrowserViewRenderer::PostFallbackTick() {
673 DCHECK(fallback_tick_fired_.IsCancelled());
674 fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
675 base::Unretained(this)));
676 if (compositor_needs_continuous_invalidate_) {
677 ui_task_runner_->PostDelayedTask(
678 FROM_HERE,
679 fallback_tick_fired_.callback(),
680 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
681 } else {
682 // Pretend we just composited to unblock further invalidates.
683 DidComposite();
687 void BrowserViewRenderer::FallbackTickFired() {
688 TRACE_EVENT1("android_webview",
689 "BrowserViewRenderer::FallbackTickFired",
690 "compositor_needs_continuous_invalidate_",
691 compositor_needs_continuous_invalidate_);
693 // This should only be called if OnDraw or DrawGL did not come in time, which
694 // means block_invalidates_ must still be true.
695 DCHECK(block_invalidates_);
696 fallback_tick_pending_ = false;
697 if (compositor_needs_continuous_invalidate_ && compositor_) {
698 if (hardware_enabled_) {
699 CompositeHw();
700 } else {
701 ForceFakeCompositeSW();
703 } else {
704 // Pretend we just composited to unblock further invalidates.
705 DidComposite();
709 void BrowserViewRenderer::ForceFakeCompositeSW() {
710 DCHECK(compositor_);
711 SkBitmap bitmap;
712 bitmap.allocN32Pixels(1, 1);
713 bitmap.eraseColor(0);
714 SkCanvas canvas(bitmap);
715 CompositeSW(&canvas);
718 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
719 DCHECK(compositor_);
720 ReturnResourceFromParent();
721 bool result = compositor_->DemandDrawSw(canvas);
722 DidComposite();
723 return result;
726 void BrowserViewRenderer::DidComposite() {
727 block_invalidates_ = false;
728 post_fallback_tick_.Cancel();
729 fallback_tick_fired_.Cancel();
730 fallback_tick_pending_ = false;
731 EnsureContinuousInvalidation(false);
734 std::string BrowserViewRenderer::ToString() const {
735 std::string str;
736 base::StringAppendF(&str, "is_paused: %d ", is_paused_);
737 base::StringAppendF(&str, "view_visible: %d ", view_visible_);
738 base::StringAppendF(&str, "window_visible: %d ", window_visible_);
739 base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
740 base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
741 base::StringAppendF(&str,
742 "compositor_needs_continuous_invalidate: %d ",
743 compositor_needs_continuous_invalidate_);
744 base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
745 base::StringAppendF(&str, "view size: %s ", size_.ToString().c_str());
746 base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
747 base::StringAppendF(&str,
748 "global visible rect: %s ",
749 last_on_draw_global_visible_rect_.ToString().c_str());
750 base::StringAppendF(
751 &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
752 base::StringAppendF(&str,
753 "overscroll_rounding_error_: %s ",
754 overscroll_rounding_error_.ToString().c_str());
755 base::StringAppendF(
756 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
757 base::StringAppendF(&str, "clear_view: %d ", clear_view_);
758 return str;
761 } // namespace android_webview