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/shared_renderer_state.h"
9 #include "android_webview/common/aw_switches.h"
10 #include "android_webview/public/browser/draw_gl.h"
11 #include "base/android/jni_android.h"
12 #include "base/auto_reset.h"
13 #include "base/command_line.h"
14 #include "base/debug/trace_event.h"
15 #include "base/json/json_writer.h"
16 #include "base/logging.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/stringprintf.h"
19 #include "cc/output/compositor_frame.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/common/content_switches.h"
23 #include "third_party/skia/include/core/SkBitmap.h"
24 #include "third_party/skia/include/core/SkCanvas.h"
25 #include "third_party/skia/include/core/SkPicture.h"
26 #include "third_party/skia/include/core/SkPictureRecorder.h"
27 #include "ui/gfx/vector2d_conversions.h"
29 using base::android::AttachCurrentThread
;
30 using base::android::JavaRef
;
31 using base::android::ScopedJavaLocalRef
;
32 using content::BrowserThread
;
33 using content::SynchronousCompositorMemoryPolicy
;
35 namespace android_webview
{
39 const int64 kFallbackTickTimeoutInMilliseconds
= 100;
41 // Used to calculate memory allocation. Determined experimentally.
42 const size_t kMemoryMultiplier
= 20;
43 const size_t kBytesPerPixel
= 4;
44 const size_t kMemoryAllocationStep
= 5 * 1024 * 1024;
46 // Used to calculate tile allocation. Determined experimentally.
47 const size_t kTileMultiplier
= 12;
48 const size_t kTileAllocationStep
= 20;
49 // This will be set by static function CalculateTileMemoryPolicy() during init.
50 // See AwMainDelegate::BasicStartupComplete.
53 class TracedValue
: public base::debug::ConvertableToTraceFormat
{
55 explicit TracedValue(base::Value
* value
) : value_(value
) {}
56 static scoped_refptr
<base::debug::ConvertableToTraceFormat
> FromValue(
58 return scoped_refptr
<base::debug::ConvertableToTraceFormat
>(
59 new TracedValue(value
));
61 virtual void AppendAsTraceFormat(std::string
* out
) const OVERRIDE
{
63 base::JSONWriter::Write(value_
.get(), &tmp
);
68 virtual ~TracedValue() {}
69 scoped_ptr
<base::Value
> value_
;
71 DISALLOW_COPY_AND_ASSIGN(TracedValue
);
77 void BrowserViewRenderer::CalculateTileMemoryPolicy(bool use_zero_copy
) {
79 // Use chrome's default tile size, which varies from 256 to 512.
80 // Be conservative here and use the smallest tile size possible.
81 g_tile_area
= 256 * 256;
83 // Also use a high tile limit since there are no file descriptor issues.
84 GlobalTileManager::GetInstance()->SetTileLimit(1000);
88 CommandLine
* cl
= CommandLine::ForCurrentProcess();
89 const char kDefaultTileSize
[] = "384";
91 if (!cl
->HasSwitch(switches::kDefaultTileWidth
))
92 cl
->AppendSwitchASCII(switches::kDefaultTileWidth
, kDefaultTileSize
);
94 if (!cl
->HasSwitch(switches::kDefaultTileHeight
))
95 cl
->AppendSwitchASCII(switches::kDefaultTileHeight
, kDefaultTileSize
);
98 base::StringToSizeT(kDefaultTileSize
, &tile_size
);
99 g_tile_area
= tile_size
* tile_size
;
102 BrowserViewRenderer::BrowserViewRenderer(
103 BrowserViewRendererClient
* client
,
104 SharedRendererState
* shared_renderer_state
,
105 content::WebContents
* web_contents
,
106 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
)
108 shared_renderer_state_(shared_renderer_state
),
109 web_contents_(web_contents
),
110 ui_task_runner_(ui_task_runner
),
113 view_visible_(false),
114 window_visible_(false),
115 attached_to_window_(false),
116 hardware_enabled_(false),
118 page_scale_factor_(1.0),
119 on_new_picture_enable_(false),
121 compositor_needs_continuous_invalidate_(false),
122 block_invalidates_(false),
127 CHECK(web_contents_
);
128 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, this);
130 // Currently the logic in this class relies on |compositor_| remaining
131 // NULL until the DidInitializeCompositor() call, hence it is not set here.
134 BrowserViewRenderer::~BrowserViewRenderer() {
135 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, NULL
);
136 // OnDetachedFromWindow should be called before the destructor, so the memory
137 // policy should have already been updated.
140 // This function updates the cached memory policy in shared renderer state, as
141 // well as the tile resource allocation in GlobalTileManager.
142 void BrowserViewRenderer::TrimMemory(const int level
, const bool visible
) {
143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
144 // Constants from Android ComponentCallbacks2.
146 TRIM_MEMORY_RUNNING_LOW
= 10,
147 TRIM_MEMORY_UI_HIDDEN
= 20,
148 TRIM_MEMORY_BACKGROUND
= 40,
151 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
152 // it does not indicate memory pressure, but merely that the app is
154 if (level
< TRIM_MEMORY_RUNNING_LOW
|| level
== TRIM_MEMORY_UI_HIDDEN
)
157 // Do not release resources on view we expect to get DrawGL soon.
158 if (level
< TRIM_MEMORY_BACKGROUND
&& visible
)
161 // Just set the memory limit to 0 and drop all tiles. This will be reset to
162 // normal levels in the next DrawGL call.
163 SynchronousCompositorMemoryPolicy zero_policy
;
164 if (memory_policy_
== zero_policy
)
167 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
169 RequestMemoryPolicy(zero_policy
);
170 EnforceMemoryPolicyImmediately(zero_policy
);
173 SynchronousCompositorMemoryPolicy
174 BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
175 SynchronousCompositorMemoryPolicy policy
;
176 size_t width
= last_on_draw_global_visible_rect_
.width();
177 size_t height
= last_on_draw_global_visible_rect_
.height();
178 policy
.bytes_limit
= kMemoryMultiplier
* kBytesPerPixel
* width
* height
;
179 // Round up to a multiple of kMemoryAllocationStep.
181 (policy
.bytes_limit
/ kMemoryAllocationStep
+ 1) * kMemoryAllocationStep
;
183 size_t tiles
= width
* height
* kTileMultiplier
/ g_tile_area
;
184 // Round up to a multiple of kTileAllocationStep. The minimum number of tiles
185 // is also kTileAllocationStep.
186 tiles
= (tiles
/ kTileAllocationStep
+ 1) * kTileAllocationStep
;
187 policy
.num_resources_limit
= tiles
;
191 // This function updates the cached memory policy in shared renderer state, as
192 // well as the tile resource allocation in GlobalTileManager.
193 void BrowserViewRenderer::RequestMemoryPolicy(
194 SynchronousCompositorMemoryPolicy
& new_policy
) {
195 // This will be used in SetNumTiles.
196 num_bytes_
= new_policy
.bytes_limit
;
198 GlobalTileManager
* manager
= GlobalTileManager::GetInstance();
200 // The following line will call BrowserViewRenderer::SetTilesNum().
201 manager
->RequestTiles(new_policy
.num_resources_limit
, tile_manager_key_
);
204 void BrowserViewRenderer::SetNumTiles(size_t num_tiles
,
205 bool effective_immediately
) {
206 if (num_tiles
== num_tiles_
)
208 num_tiles_
= num_tiles
;
210 memory_policy_
.num_resources_limit
= num_tiles_
;
211 memory_policy_
.bytes_limit
= num_bytes_
;
213 if (effective_immediately
)
214 EnforceMemoryPolicyImmediately(memory_policy_
);
217 void BrowserViewRenderer::EnforceMemoryPolicyImmediately(
218 SynchronousCompositorMemoryPolicy new_policy
) {
219 compositor_
->SetMemoryPolicy(new_policy
);
220 ForceFakeCompositeSW();
223 size_t BrowserViewRenderer::GetNumTiles() const {
224 return memory_policy_
.num_resources_limit
;
227 bool BrowserViewRenderer::OnDraw(jobject java_canvas
,
228 bool is_hardware_canvas
,
229 const gfx::Vector2d
& scroll
,
230 const gfx::Rect
& global_visible_rect
) {
231 last_on_draw_scroll_offset_
= scroll
;
232 last_on_draw_global_visible_rect_
= global_visible_rect
;
237 if (is_hardware_canvas
&& attached_to_window_
&&
238 !switches::ForceAuxiliaryBitmap()) {
239 return OnDrawHardware(java_canvas
);
242 // Perform a software draw
243 return OnDrawSoftware(java_canvas
);
246 bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas
) {
250 if (!hardware_enabled_
) {
251 hardware_enabled_
= compositor_
->InitializeHwDraw();
252 if (hardware_enabled_
) {
253 tile_manager_key_
= GlobalTileManager::GetInstance()->PushBack(this);
254 gpu::GLInProcessContext
* share_context
= compositor_
->GetShareContext();
255 DCHECK(share_context
);
256 shared_renderer_state_
->SetSharedContext(share_context
);
259 if (!hardware_enabled_
)
262 ReturnResourceFromParent();
263 SynchronousCompositorMemoryPolicy new_policy
= CalculateDesiredMemoryPolicy();
264 RequestMemoryPolicy(new_policy
);
265 compositor_
->SetMemoryPolicy(memory_policy_
);
267 scoped_ptr
<DrawGLInput
> draw_gl_input(new DrawGLInput
);
268 draw_gl_input
->scroll_offset
= last_on_draw_scroll_offset_
;
269 draw_gl_input
->width
= width_
;
270 draw_gl_input
->height
= height_
;
272 parent_draw_constraints_
= shared_renderer_state_
->ParentDrawConstraints();
273 gfx::Size
surface_size(width_
, height_
);
274 gfx::Rect
viewport(surface_size
);
275 gfx::Rect clip
= viewport
;
276 gfx::Transform transform_for_tile_priority
=
277 parent_draw_constraints_
.transform
;
279 // If the WebView is on a layer, WebView does not know what transform is
280 // applied onto the layer so global visible rect does not make sense here.
281 // In this case, just use the surface rect for tiling.
282 gfx::Rect viewport_rect_for_tile_priority
;
283 if (parent_draw_constraints_
.is_layer
)
284 viewport_rect_for_tile_priority
= parent_draw_constraints_
.surface_rect
;
286 viewport_rect_for_tile_priority
= last_on_draw_global_visible_rect_
;
288 scoped_ptr
<cc::CompositorFrame
> frame
=
289 compositor_
->DemandDrawHw(surface_size
,
293 viewport_rect_for_tile_priority
,
294 transform_for_tile_priority
);
298 GlobalTileManager::GetInstance()->DidUse(tile_manager_key_
);
300 frame
->AssignTo(&draw_gl_input
->frame
);
301 ReturnUnusedResource(shared_renderer_state_
->PassDrawGLInput());
302 shared_renderer_state_
->SetDrawGLInput(draw_gl_input
.Pass());
304 return client_
->RequestDrawGL(java_canvas
, false);
307 void BrowserViewRenderer::UpdateParentDrawConstraints() {
308 // Post an invalidate if the parent draw constraints are stale and there is
309 // no pending invalidate.
310 if (!parent_draw_constraints_
.Equals(
311 shared_renderer_state_
->ParentDrawConstraints()))
312 EnsureContinuousInvalidation(true);
315 void BrowserViewRenderer::ReturnUnusedResource(scoped_ptr
<DrawGLInput
> input
) {
319 cc::CompositorFrameAck frame_ack
;
320 cc::TransferableResource::ReturnResources(
321 input
->frame
.delegated_frame_data
->resource_list
,
322 &frame_ack
.resources
);
323 if (!frame_ack
.resources
.empty())
324 compositor_
->ReturnResources(frame_ack
);
327 void BrowserViewRenderer::ReturnResourceFromParent() {
328 cc::CompositorFrameAck frame_ack
;
329 shared_renderer_state_
->SwapReturnedResources(&frame_ack
.resources
);
330 if (!frame_ack
.resources
.empty()) {
331 compositor_
->ReturnResources(frame_ack
);
335 bool BrowserViewRenderer::OnDrawSoftware(jobject java_canvas
) {
337 TRACE_EVENT_INSTANT0(
338 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD
);
342 // TODO(hush): right now webview size is passed in as the auxiliary bitmap
343 // size, which might hurt performace (only for software draws with auxiliary
344 // bitmap). For better performance, get global visible rect, transform it
345 // from screen space to view space, then intersect with the webview in
346 // viewspace. Use the resulting rect as the auxiliary
348 return BrowserViewRendererJavaHelper::GetInstance()
349 ->RenderViaAuxilaryBitmapIfNeeded(
351 last_on_draw_scroll_offset_
,
352 gfx::Size(width_
, height_
),
353 base::Bind(&BrowserViewRenderer::CompositeSW
,
354 base::Unretained(this)));
357 skia::RefPtr
<SkPicture
> BrowserViewRenderer::CapturePicture(int width
,
359 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
361 // Return empty Picture objects for empty SkPictures.
362 if (width
<= 0 || height
<= 0) {
363 SkPictureRecorder emptyRecorder
;
364 emptyRecorder
.beginRecording(0, 0);
365 return skia::AdoptRef(emptyRecorder
.endRecording());
368 // Reset scroll back to the origin, will go back to the old
369 // value when scroll_reset is out of scope.
370 base::AutoReset
<gfx::Vector2dF
> scroll_reset(&scroll_offset_dip_
,
373 SkPictureRecorder recorder
;
374 SkCanvas
* rec_canvas
= recorder
.beginRecording(width
, height
, NULL
, 0);
376 CompositeSW(rec_canvas
);
377 return skia::AdoptRef(recorder
.endRecording());
380 void BrowserViewRenderer::EnableOnNewPicture(bool enabled
) {
381 on_new_picture_enable_
= enabled
;
384 void BrowserViewRenderer::ClearView() {
385 TRACE_EVENT_INSTANT0("android_webview",
386 "BrowserViewRenderer::ClearView",
387 TRACE_EVENT_SCOPE_THREAD
);
392 // Always invalidate ignoring the compositor to actually clear the webview.
393 EnsureContinuousInvalidation(true);
396 void BrowserViewRenderer::SetIsPaused(bool paused
) {
397 TRACE_EVENT_INSTANT1("android_webview",
398 "BrowserViewRenderer::SetIsPaused",
399 TRACE_EVENT_SCOPE_THREAD
,
403 EnsureContinuousInvalidation(false);
406 void BrowserViewRenderer::SetViewVisibility(bool view_visible
) {
407 TRACE_EVENT_INSTANT1("android_webview",
408 "BrowserViewRenderer::SetViewVisibility",
409 TRACE_EVENT_SCOPE_THREAD
,
412 view_visible_
= view_visible
;
415 void BrowserViewRenderer::SetWindowVisibility(bool window_visible
) {
416 TRACE_EVENT_INSTANT1("android_webview",
417 "BrowserViewRenderer::SetWindowVisibility",
418 TRACE_EVENT_SCOPE_THREAD
,
421 window_visible_
= window_visible
;
422 EnsureContinuousInvalidation(false);
425 void BrowserViewRenderer::OnSizeChanged(int width
, int height
) {
426 TRACE_EVENT_INSTANT2("android_webview",
427 "BrowserViewRenderer::OnSizeChanged",
428 TRACE_EVENT_SCOPE_THREAD
,
437 void BrowserViewRenderer::OnAttachedToWindow(int width
, int height
) {
438 TRACE_EVENT2("android_webview",
439 "BrowserViewRenderer::OnAttachedToWindow",
444 attached_to_window_
= true;
449 void BrowserViewRenderer::OnDetachedFromWindow() {
450 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
451 attached_to_window_
= false;
452 DCHECK(!hardware_enabled_
);
455 void BrowserViewRenderer::ReleaseHardware() {
456 DCHECK(hardware_enabled_
);
457 ReturnUnusedResource(shared_renderer_state_
->PassDrawGLInput());
458 ReturnResourceFromParent();
459 DCHECK(shared_renderer_state_
->ReturnedResourcesEmpty());
461 compositor_
->ReleaseHwDraw();
462 shared_renderer_state_
->SetSharedContext(NULL
);
463 hardware_enabled_
= false;
465 SynchronousCompositorMemoryPolicy zero_policy
;
466 RequestMemoryPolicy(zero_policy
);
467 GlobalTileManager::GetInstance()->Remove(tile_manager_key_
);
470 bool BrowserViewRenderer::IsVisible() const {
471 // Ignore |window_visible_| if |attached_to_window_| is false.
472 return view_visible_
&& (!attached_to_window_
|| window_visible_
);
475 gfx::Rect
BrowserViewRenderer::GetScreenRect() const {
476 return gfx::Rect(client_
->GetLocationOnScreen(), gfx::Size(width_
, height_
));
479 void BrowserViewRenderer::DidInitializeCompositor(
480 content::SynchronousCompositor
* compositor
) {
481 TRACE_EVENT0("android_webview",
482 "BrowserViewRenderer::DidInitializeCompositor");
484 DCHECK(!compositor_
);
485 compositor_
= compositor
;
488 void BrowserViewRenderer::DidDestroyCompositor(
489 content::SynchronousCompositor
* compositor
) {
490 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
493 SynchronousCompositorMemoryPolicy zero_policy
;
494 DCHECK(memory_policy_
== zero_policy
);
497 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate
) {
498 if (compositor_needs_continuous_invalidate_
== invalidate
)
501 TRACE_EVENT_INSTANT1("android_webview",
502 "BrowserViewRenderer::SetContinuousInvalidate",
503 TRACE_EVENT_SCOPE_THREAD
,
506 compositor_needs_continuous_invalidate_
= invalidate
;
508 EnsureContinuousInvalidation(false);
511 void BrowserViewRenderer::SetDipScale(float dip_scale
) {
512 dip_scale_
= dip_scale
;
513 CHECK(dip_scale_
> 0);
516 gfx::Vector2d
BrowserViewRenderer::max_scroll_offset() const {
517 DCHECK_GT(dip_scale_
, 0);
518 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
519 max_scroll_offset_dip_
, dip_scale_
* page_scale_factor_
));
522 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset
) {
523 gfx::Vector2d max_offset
= max_scroll_offset();
524 gfx::Vector2dF scroll_offset_dip
;
525 // To preserve the invariant that scrolling to the maximum physical pixel
526 // value also scrolls to the maximum dip pixel value we transform the physical
527 // offset into the dip offset by using a proportion (instead of dividing by
528 // dip_scale * page_scale_factor).
529 if (max_offset
.x()) {
530 scroll_offset_dip
.set_x((scroll_offset
.x() * max_scroll_offset_dip_
.x()) /
533 if (max_offset
.y()) {
534 scroll_offset_dip
.set_y((scroll_offset
.y() * max_scroll_offset_dip_
.y()) /
538 DCHECK_LE(0, scroll_offset_dip
.x());
539 DCHECK_LE(0, scroll_offset_dip
.y());
540 DCHECK_LE(scroll_offset_dip
.x(), max_scroll_offset_dip_
.x());
541 DCHECK_LE(scroll_offset_dip
.y(), max_scroll_offset_dip_
.y());
543 if (scroll_offset_dip_
== scroll_offset_dip
)
546 scroll_offset_dip_
= scroll_offset_dip
;
548 TRACE_EVENT_INSTANT2("android_webview",
549 "BrowserViewRenderer::ScrollTo",
550 TRACE_EVENT_SCOPE_THREAD
,
552 scroll_offset_dip
.x(),
554 scroll_offset_dip
.y());
557 compositor_
->DidChangeRootLayerScrollOffset();
560 void BrowserViewRenderer::DidUpdateContent() {
561 TRACE_EVENT_INSTANT0("android_webview",
562 "BrowserViewRenderer::DidUpdateContent",
563 TRACE_EVENT_SCOPE_THREAD
);
565 if (on_new_picture_enable_
)
566 client_
->OnNewPicture();
569 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
570 gfx::Vector2dF scroll_offset_dip
) {
571 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
572 // DrawGl when http://crbug.com/249972 is fixed.
573 if (scroll_offset_dip_
== scroll_offset_dip
)
576 scroll_offset_dip_
= scroll_offset_dip
;
578 gfx::Vector2d max_offset
= max_scroll_offset();
579 gfx::Vector2d scroll_offset
;
580 // For an explanation as to why this is done this way see the comment in
581 // BrowserViewRenderer::ScrollTo.
582 if (max_scroll_offset_dip_
.x()) {
583 scroll_offset
.set_x((scroll_offset_dip
.x() * max_offset
.x()) /
584 max_scroll_offset_dip_
.x());
587 if (max_scroll_offset_dip_
.y()) {
588 scroll_offset
.set_y((scroll_offset_dip
.y() * max_offset
.y()) /
589 max_scroll_offset_dip_
.y());
592 DCHECK(0 <= scroll_offset
.x());
593 DCHECK(0 <= scroll_offset
.y());
594 DCHECK(scroll_offset
.x() <= max_offset
.x());
595 DCHECK(scroll_offset
.y() <= max_offset
.y());
597 client_
->ScrollContainerViewTo(scroll_offset
);
600 gfx::Vector2dF
BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
601 return scroll_offset_dip_
;
604 bool BrowserViewRenderer::IsExternalFlingActive() const {
605 return client_
->IsFlingActive();
608 void BrowserViewRenderer::UpdateRootLayerState(
609 const gfx::Vector2dF
& total_scroll_offset_dip
,
610 const gfx::Vector2dF
& max_scroll_offset_dip
,
611 const gfx::SizeF
& scrollable_size_dip
,
612 float page_scale_factor
,
613 float min_page_scale_factor
,
614 float max_page_scale_factor
) {
615 TRACE_EVENT_INSTANT1(
617 "BrowserViewRenderer::UpdateRootLayerState",
618 TRACE_EVENT_SCOPE_THREAD
,
620 TracedValue::FromValue(
621 RootLayerStateAsValue(total_scroll_offset_dip
, scrollable_size_dip
)
624 DCHECK_GT(dip_scale_
, 0);
626 max_scroll_offset_dip_
= max_scroll_offset_dip
;
627 DCHECK_LE(0, max_scroll_offset_dip_
.x());
628 DCHECK_LE(0, max_scroll_offset_dip_
.y());
630 page_scale_factor_
= page_scale_factor
;
631 DCHECK_GT(page_scale_factor_
, 0);
633 client_
->UpdateScrollState(max_scroll_offset(),
636 min_page_scale_factor
,
637 max_page_scale_factor
);
638 SetTotalRootLayerScrollOffset(total_scroll_offset_dip
);
641 scoped_ptr
<base::Value
> BrowserViewRenderer::RootLayerStateAsValue(
642 const gfx::Vector2dF
& total_scroll_offset_dip
,
643 const gfx::SizeF
& scrollable_size_dip
) {
644 scoped_ptr
<base::DictionaryValue
> state(new base::DictionaryValue
);
646 state
->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip
.x());
647 state
->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip
.y());
649 state
->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_
.x());
650 state
->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_
.y());
652 state
->SetDouble("scrollable_size_dip.width", scrollable_size_dip
.width());
653 state
->SetDouble("scrollable_size_dip.height", scrollable_size_dip
.height());
655 state
->SetDouble("page_scale_factor", page_scale_factor_
);
656 return state
.PassAs
<base::Value
>();
659 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll
,
660 gfx::Vector2dF latest_overscroll_delta
,
661 gfx::Vector2dF current_fling_velocity
) {
662 const float physical_pixel_scale
= dip_scale_
* page_scale_factor_
;
663 if (accumulated_overscroll
== latest_overscroll_delta
)
664 overscroll_rounding_error_
= gfx::Vector2dF();
665 gfx::Vector2dF scaled_overscroll_delta
=
666 gfx::ScaleVector2d(latest_overscroll_delta
, physical_pixel_scale
);
667 gfx::Vector2d rounded_overscroll_delta
= gfx::ToRoundedVector2d(
668 scaled_overscroll_delta
+ overscroll_rounding_error_
);
669 overscroll_rounding_error_
=
670 scaled_overscroll_delta
- rounded_overscroll_delta
;
671 client_
->DidOverscroll(rounded_overscroll_delta
);
674 void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate
) {
675 // This method should be called again when any of these conditions change.
676 bool need_invalidate
=
677 compositor_needs_continuous_invalidate_
|| force_invalidate
;
678 if (!need_invalidate
|| block_invalidates_
)
681 // Always call view invalidate. We rely the Android framework to ignore the
682 // invalidate when it's not needed such as when view is not visible.
683 client_
->PostInvalidate();
685 // Stop fallback ticks when one of these is true.
686 // 1) Webview is paused. Also need to check we are not in clear view since
687 // paused, offscreen still expect clear view to recover.
688 // 2) If we are attached to window and the window is not visible (eg when
689 // app is in the background). We are sure in this case the webview is used
690 // "on-screen" but that updates are not needed when in the background.
691 bool throttle_fallback_tick
=
692 (is_paused_
&& !clear_view_
) || (attached_to_window_
&& !window_visible_
);
693 if (throttle_fallback_tick
)
696 block_invalidates_
= compositor_needs_continuous_invalidate_
;
698 // Unretained here is safe because the callbacks are cancelled when
699 // they are destroyed.
700 post_fallback_tick_
.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick
,
701 base::Unretained(this)));
702 fallback_tick_fired_
.Cancel();
704 // No need to reschedule fallback tick if compositor does not need to be
705 // ticked. This can happen if this is reached because force_invalidate is
707 if (compositor_needs_continuous_invalidate_
)
708 ui_task_runner_
->PostTask(FROM_HERE
, post_fallback_tick_
.callback());
711 void BrowserViewRenderer::PostFallbackTick() {
712 DCHECK(fallback_tick_fired_
.IsCancelled());
713 fallback_tick_fired_
.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired
,
714 base::Unretained(this)));
715 if (compositor_needs_continuous_invalidate_
) {
716 ui_task_runner_
->PostDelayedTask(
718 fallback_tick_fired_
.callback(),
719 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds
));
723 void BrowserViewRenderer::FallbackTickFired() {
724 TRACE_EVENT1("android_webview",
725 "BrowserViewRenderer::FallbackTickFired",
726 "compositor_needs_continuous_invalidate_",
727 compositor_needs_continuous_invalidate_
);
729 // This should only be called if OnDraw or DrawGL did not come in time, which
730 // means block_invalidates_ must still be true.
731 DCHECK(block_invalidates_
);
732 if (compositor_needs_continuous_invalidate_
&& compositor_
)
733 ForceFakeCompositeSW();
736 void BrowserViewRenderer::ForceFakeCompositeSW() {
739 bitmap
.allocN32Pixels(1, 1);
740 bitmap
.eraseColor(0);
741 SkCanvas
canvas(bitmap
);
742 CompositeSW(&canvas
);
745 bool BrowserViewRenderer::CompositeSW(SkCanvas
* canvas
) {
747 ReturnResourceFromParent();
748 bool result
= compositor_
->DemandDrawSw(canvas
);
753 void BrowserViewRenderer::DidComposite() {
754 block_invalidates_
= false;
755 post_fallback_tick_
.Cancel();
756 fallback_tick_fired_
.Cancel();
757 EnsureContinuousInvalidation(false);
760 std::string
BrowserViewRenderer::ToString(AwDrawGLInfo
* draw_info
) const {
762 base::StringAppendF(&str
, "is_paused: %d ", is_paused_
);
763 base::StringAppendF(&str
, "view_visible: %d ", view_visible_
);
764 base::StringAppendF(&str
, "window_visible: %d ", window_visible_
);
765 base::StringAppendF(&str
, "dip_scale: %f ", dip_scale_
);
766 base::StringAppendF(&str
, "page_scale_factor: %f ", page_scale_factor_
);
767 base::StringAppendF(&str
,
768 "compositor_needs_continuous_invalidate: %d ",
769 compositor_needs_continuous_invalidate_
);
770 base::StringAppendF(&str
, "block_invalidates: %d ", block_invalidates_
);
771 base::StringAppendF(&str
, "view width height: [%d %d] ", width_
, height_
);
772 base::StringAppendF(&str
, "attached_to_window: %d ", attached_to_window_
);
773 base::StringAppendF(&str
,
774 "global visible rect: %s ",
775 last_on_draw_global_visible_rect_
.ToString().c_str());
777 &str
, "scroll_offset_dip: %s ", scroll_offset_dip_
.ToString().c_str());
778 base::StringAppendF(&str
,
779 "overscroll_rounding_error_: %s ",
780 overscroll_rounding_error_
.ToString().c_str());
782 &str
, "on_new_picture_enable: %d ", on_new_picture_enable_
);
783 base::StringAppendF(&str
, "clear_view: %d ", clear_view_
);
785 base::StringAppendF(&str
,
786 "clip left top right bottom: [%d %d %d %d] ",
787 draw_info
->clip_left
,
789 draw_info
->clip_right
,
790 draw_info
->clip_bottom
);
791 base::StringAppendF(&str
,
792 "surface width height: [%d %d] ",
795 base::StringAppendF(&str
, "is_layer: %d ", draw_info
->is_layer
);
800 } // namespace android_webview