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 "gpu/command_buffer/service/gpu_switches.h"
24 #include "third_party/skia/include/core/SkBitmap.h"
25 #include "third_party/skia/include/core/SkCanvas.h"
26 #include "third_party/skia/include/core/SkPicture.h"
27 #include "third_party/skia/include/core/SkPictureRecorder.h"
28 #include "ui/gfx/vector2d_conversions.h"
30 using base::android::AttachCurrentThread
;
31 using base::android::JavaRef
;
32 using base::android::ScopedJavaLocalRef
;
33 using content::BrowserThread
;
34 using content::SynchronousCompositorMemoryPolicy
;
36 namespace android_webview
{
40 const int64 kFallbackTickTimeoutInMilliseconds
= 100;
42 // Used to calculate memory allocation. Determined experimentally.
43 const size_t kMemoryMultiplier
= 20;
44 const size_t kBytesPerPixel
= 4;
45 const size_t kMemoryAllocationStep
= 5 * 1024 * 1024;
46 uint64 g_memory_override_in_bytes
= 0u;
48 // Used to calculate tile allocation. Determined experimentally.
49 const size_t kTileMultiplier
= 12;
50 const size_t kTileAllocationStep
= 20;
51 // This will be set by static function CalculateTileMemoryPolicy() during init.
52 // See AwMainDelegate::BasicStartupComplete.
55 class TracedValue
: public base::debug::ConvertableToTraceFormat
{
57 explicit TracedValue(base::Value
* value
) : value_(value
) {}
58 static scoped_refptr
<base::debug::ConvertableToTraceFormat
> FromValue(
60 return scoped_refptr
<base::debug::ConvertableToTraceFormat
>(
61 new TracedValue(value
));
63 virtual void AppendAsTraceFormat(std::string
* out
) const OVERRIDE
{
65 base::JSONWriter::Write(value_
.get(), &tmp
);
70 virtual ~TracedValue() {}
71 scoped_ptr
<base::Value
> value_
;
73 DISALLOW_COPY_AND_ASSIGN(TracedValue
);
79 void BrowserViewRenderer::CalculateTileMemoryPolicy() {
80 CommandLine
* cl
= CommandLine::ForCurrentProcess();
82 // If the value was overridden on the command line, use the specified value.
83 bool client_hard_limit_bytes_overridden
=
84 cl
->HasSwitch(switches::kForceGpuMemAvailableMb
);
85 if (client_hard_limit_bytes_overridden
) {
87 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
88 switches::kForceGpuMemAvailableMb
),
89 &g_memory_override_in_bytes
);
90 g_memory_override_in_bytes
*= 1024 * 1024;
93 // Use chrome's default tile size, which varies from 256 to 512.
94 // Be conservative here and use the smallest tile size possible.
95 g_tile_area
= 256 * 256;
97 // Also use a high tile limit since there are no file descriptor issues.
98 GlobalTileManager::GetInstance()->SetTileLimit(1000);
101 BrowserViewRenderer::BrowserViewRenderer(
102 BrowserViewRendererClient
* client
,
103 SharedRendererState
* shared_renderer_state
,
104 content::WebContents
* web_contents
,
105 const scoped_refptr
<base::SingleThreadTaskRunner
>& ui_task_runner
)
107 shared_renderer_state_(shared_renderer_state
),
108 web_contents_(web_contents
),
109 ui_task_runner_(ui_task_runner
),
112 view_visible_(false),
113 window_visible_(false),
114 attached_to_window_(false),
115 hardware_enabled_(false),
117 page_scale_factor_(1.0),
118 on_new_picture_enable_(false),
120 compositor_needs_continuous_invalidate_(false),
121 block_invalidates_(false),
124 CHECK(web_contents_
);
125 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, this);
127 // Currently the logic in this class relies on |compositor_| remaining
128 // NULL until the DidInitializeCompositor() call, hence it is not set here.
131 BrowserViewRenderer::~BrowserViewRenderer() {
132 content::SynchronousCompositor::SetClientForWebContents(web_contents_
, NULL
);
133 // OnDetachedFromWindow should be called before the destructor, so the memory
134 // policy should have already been updated.
137 // This function updates the resource allocation in GlobalTileManager.
138 void BrowserViewRenderer::TrimMemory(const int level
, const bool visible
) {
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
140 // Constants from Android ComponentCallbacks2.
142 TRIM_MEMORY_RUNNING_LOW
= 10,
143 TRIM_MEMORY_UI_HIDDEN
= 20,
144 TRIM_MEMORY_BACKGROUND
= 40,
147 // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
148 // it does not indicate memory pressure, but merely that the app is
150 if (level
< TRIM_MEMORY_RUNNING_LOW
|| level
== TRIM_MEMORY_UI_HIDDEN
)
153 // Do not release resources on view we expect to get DrawGL soon.
154 if (level
< TRIM_MEMORY_BACKGROUND
&& visible
)
157 // Just set the memory limit to 0 and drop all tiles. This will be reset to
158 // normal levels in the next DrawGL call.
159 SynchronousCompositorMemoryPolicy zero_policy
;
160 if (memory_policy_
== zero_policy
)
163 TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
165 RequestMemoryPolicy(zero_policy
);
166 EnforceMemoryPolicyImmediately(zero_policy
);
169 SynchronousCompositorMemoryPolicy
170 BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
171 SynchronousCompositorMemoryPolicy policy
;
172 size_t width
= last_on_draw_global_visible_rect_
.width();
173 size_t height
= last_on_draw_global_visible_rect_
.height();
174 policy
.bytes_limit
= kMemoryMultiplier
* kBytesPerPixel
* width
* height
;
175 // Round up to a multiple of kMemoryAllocationStep.
177 (policy
.bytes_limit
/ kMemoryAllocationStep
+ 1) * kMemoryAllocationStep
;
179 if (g_memory_override_in_bytes
)
180 policy
.bytes_limit
= static_cast<size_t>(g_memory_override_in_bytes
);
182 size_t tiles
= width
* height
* kTileMultiplier
/ g_tile_area
;
183 // Round up to a multiple of kTileAllocationStep. The minimum number of tiles
184 // is also kTileAllocationStep.
185 tiles
= (tiles
/ kTileAllocationStep
+ 1) * kTileAllocationStep
;
186 policy
.num_resources_limit
= tiles
;
190 // This function updates the cached memory policy in shared renderer state, as
191 // well as the tile resource allocation in GlobalTileManager.
192 void BrowserViewRenderer::RequestMemoryPolicy(
193 SynchronousCompositorMemoryPolicy
& new_policy
) {
194 GlobalTileManager
* manager
= GlobalTileManager::GetInstance();
196 // The following line will call BrowserViewRenderer::SetMemoryPolicy().
197 manager
->RequestTiles(new_policy
, tile_manager_key_
);
200 void BrowserViewRenderer::SetMemoryPolicy(
201 SynchronousCompositorMemoryPolicy new_policy
,
202 bool effective_immediately
) {
203 memory_policy_
= new_policy
;
204 if (effective_immediately
)
205 EnforceMemoryPolicyImmediately(memory_policy_
);
208 void BrowserViewRenderer::EnforceMemoryPolicyImmediately(
209 SynchronousCompositorMemoryPolicy new_policy
) {
210 compositor_
->SetMemoryPolicy(new_policy
);
211 ForceFakeCompositeSW();
214 SynchronousCompositorMemoryPolicy
BrowserViewRenderer::GetMemoryPolicy() const {
215 return memory_policy_
;
218 bool BrowserViewRenderer::OnDraw(jobject java_canvas
,
219 bool is_hardware_canvas
,
220 const gfx::Vector2d
& scroll
,
221 const gfx::Rect
& global_visible_rect
) {
222 last_on_draw_scroll_offset_
= scroll
;
223 last_on_draw_global_visible_rect_
= global_visible_rect
;
228 if (is_hardware_canvas
&& attached_to_window_
&&
229 !switches::ForceAuxiliaryBitmap()) {
230 return OnDrawHardware(java_canvas
);
233 // Perform a software draw
234 return OnDrawSoftware(java_canvas
);
237 bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas
) {
238 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDrawHardware");
242 if (last_on_draw_global_visible_rect_
.IsEmpty()) {
243 TRACE_EVENT_INSTANT0("android_webview",
244 "EarlyOut_EmptyVisibleRect",
245 TRACE_EVENT_SCOPE_THREAD
);
246 shared_renderer_state_
->SetForceInvalidateOnNextDrawGL(true);
247 return client_
->RequestDrawGL(java_canvas
, false);
250 if (!hardware_enabled_
) {
251 hardware_enabled_
= compositor_
->InitializeHwDraw();
252 if (hardware_enabled_
) {
253 tile_manager_key_
= GlobalTileManager::GetInstance()->PushBack(this);
256 if (!hardware_enabled_
)
259 ReturnResourceFromParent();
260 SynchronousCompositorMemoryPolicy new_policy
= CalculateDesiredMemoryPolicy();
261 RequestMemoryPolicy(new_policy
);
262 compositor_
->SetMemoryPolicy(memory_policy_
);
264 if (shared_renderer_state_
->HasDrawGLInput()) {
265 TRACE_EVENT_INSTANT0("android_webview",
266 "EarlyOut_PreviousFrameUnconsumed",
267 TRACE_EVENT_SCOPE_THREAD
);
268 // TODO(boliu): Rename this method. We didn't actually composite here.
270 return client_
->RequestDrawGL(java_canvas
, false);
273 scoped_ptr
<DrawGLInput
> draw_gl_input(new DrawGLInput
);
274 draw_gl_input
->scroll_offset
= last_on_draw_scroll_offset_
;
275 draw_gl_input
->width
= width_
;
276 draw_gl_input
->height
= height_
;
278 parent_draw_constraints_
= shared_renderer_state_
->ParentDrawConstraints();
279 gfx::Size
surface_size(width_
, height_
);
280 gfx::Rect
viewport(surface_size
);
281 gfx::Rect clip
= viewport
;
282 gfx::Transform transform_for_tile_priority
=
283 parent_draw_constraints_
.transform
;
285 // If the WebView is on a layer, WebView does not know what transform is
286 // applied onto the layer so global visible rect does not make sense here.
287 // In this case, just use the surface rect for tiling.
288 gfx::Rect viewport_rect_for_tile_priority
;
289 if (parent_draw_constraints_
.is_layer
)
290 viewport_rect_for_tile_priority
= parent_draw_constraints_
.surface_rect
;
292 viewport_rect_for_tile_priority
= last_on_draw_global_visible_rect_
;
294 scoped_ptr
<cc::CompositorFrame
> frame
=
295 compositor_
->DemandDrawHw(surface_size
,
299 viewport_rect_for_tile_priority
,
300 transform_for_tile_priority
);
304 GlobalTileManager::GetInstance()->DidUse(tile_manager_key_
);
306 frame
->AssignTo(&draw_gl_input
->frame
);
307 shared_renderer_state_
->SetDrawGLInput(draw_gl_input
.Pass());
309 return client_
->RequestDrawGL(java_canvas
, false);
312 void BrowserViewRenderer::UpdateParentDrawConstraints() {
313 // Post an invalidate if the parent draw constraints are stale and there is
314 // no pending invalidate.
315 if (shared_renderer_state_
->NeedsForceInvalidateOnNextDrawGL() ||
316 !parent_draw_constraints_
.Equals(
317 shared_renderer_state_
->ParentDrawConstraints())) {
318 shared_renderer_state_
->SetForceInvalidateOnNextDrawGL(false);
319 EnsureContinuousInvalidation(true);
323 void BrowserViewRenderer::ReturnUnusedResource(scoped_ptr
<DrawGLInput
> input
) {
327 cc::CompositorFrameAck frame_ack
;
328 cc::TransferableResource::ReturnResources(
329 input
->frame
.delegated_frame_data
->resource_list
,
330 &frame_ack
.resources
);
331 if (!frame_ack
.resources
.empty())
332 compositor_
->ReturnResources(frame_ack
);
335 void BrowserViewRenderer::ReturnResourceFromParent() {
336 cc::CompositorFrameAck frame_ack
;
337 shared_renderer_state_
->SwapReturnedResources(&frame_ack
.resources
);
338 if (!frame_ack
.resources
.empty()) {
339 compositor_
->ReturnResources(frame_ack
);
343 bool BrowserViewRenderer::OnDrawSoftware(jobject java_canvas
) {
345 TRACE_EVENT_INSTANT0(
346 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD
);
350 // TODO(hush): right now webview size is passed in as the auxiliary bitmap
351 // size, which might hurt performace (only for software draws with auxiliary
352 // bitmap). For better performance, get global visible rect, transform it
353 // from screen space to view space, then intersect with the webview in
354 // viewspace. Use the resulting rect as the auxiliary
356 return BrowserViewRendererJavaHelper::GetInstance()
357 ->RenderViaAuxilaryBitmapIfNeeded(
359 last_on_draw_scroll_offset_
,
360 gfx::Size(width_
, height_
),
361 base::Bind(&BrowserViewRenderer::CompositeSW
,
362 base::Unretained(this)));
365 skia::RefPtr
<SkPicture
> BrowserViewRenderer::CapturePicture(int width
,
367 TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
369 // Return empty Picture objects for empty SkPictures.
370 if (width
<= 0 || height
<= 0) {
371 SkPictureRecorder emptyRecorder
;
372 emptyRecorder
.beginRecording(0, 0);
373 return skia::AdoptRef(emptyRecorder
.endRecording());
376 // Reset scroll back to the origin, will go back to the old
377 // value when scroll_reset is out of scope.
378 base::AutoReset
<gfx::Vector2dF
> scroll_reset(&scroll_offset_dip_
,
381 SkPictureRecorder recorder
;
382 SkCanvas
* rec_canvas
= recorder
.beginRecording(width
, height
, NULL
, 0);
384 CompositeSW(rec_canvas
);
385 return skia::AdoptRef(recorder
.endRecording());
388 void BrowserViewRenderer::EnableOnNewPicture(bool enabled
) {
389 on_new_picture_enable_
= enabled
;
392 void BrowserViewRenderer::ClearView() {
393 TRACE_EVENT_INSTANT0("android_webview",
394 "BrowserViewRenderer::ClearView",
395 TRACE_EVENT_SCOPE_THREAD
);
400 // Always invalidate ignoring the compositor to actually clear the webview.
401 EnsureContinuousInvalidation(true);
404 void BrowserViewRenderer::SetIsPaused(bool paused
) {
405 TRACE_EVENT_INSTANT1("android_webview",
406 "BrowserViewRenderer::SetIsPaused",
407 TRACE_EVENT_SCOPE_THREAD
,
411 EnsureContinuousInvalidation(false);
414 void BrowserViewRenderer::SetViewVisibility(bool view_visible
) {
415 TRACE_EVENT_INSTANT1("android_webview",
416 "BrowserViewRenderer::SetViewVisibility",
417 TRACE_EVENT_SCOPE_THREAD
,
420 view_visible_
= view_visible
;
423 void BrowserViewRenderer::SetWindowVisibility(bool window_visible
) {
424 TRACE_EVENT_INSTANT1("android_webview",
425 "BrowserViewRenderer::SetWindowVisibility",
426 TRACE_EVENT_SCOPE_THREAD
,
429 window_visible_
= window_visible
;
430 EnsureContinuousInvalidation(false);
433 void BrowserViewRenderer::OnSizeChanged(int width
, int height
) {
434 TRACE_EVENT_INSTANT2("android_webview",
435 "BrowserViewRenderer::OnSizeChanged",
436 TRACE_EVENT_SCOPE_THREAD
,
445 void BrowserViewRenderer::OnAttachedToWindow(int width
, int height
) {
446 TRACE_EVENT2("android_webview",
447 "BrowserViewRenderer::OnAttachedToWindow",
452 attached_to_window_
= true;
457 void BrowserViewRenderer::OnDetachedFromWindow() {
458 TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
459 attached_to_window_
= false;
460 DCHECK(!hardware_enabled_
);
463 void BrowserViewRenderer::ReleaseHardware() {
464 DCHECK(hardware_enabled_
);
465 ReturnUnusedResource(shared_renderer_state_
->PassDrawGLInput());
466 ReturnResourceFromParent();
467 DCHECK(shared_renderer_state_
->ReturnedResourcesEmpty());
469 compositor_
->ReleaseHwDraw();
470 hardware_enabled_
= false;
472 SynchronousCompositorMemoryPolicy zero_policy
;
473 RequestMemoryPolicy(zero_policy
);
474 GlobalTileManager::GetInstance()->Remove(tile_manager_key_
);
477 bool BrowserViewRenderer::IsVisible() const {
478 // Ignore |window_visible_| if |attached_to_window_| is false.
479 return view_visible_
&& (!attached_to_window_
|| window_visible_
);
482 gfx::Rect
BrowserViewRenderer::GetScreenRect() const {
483 return gfx::Rect(client_
->GetLocationOnScreen(), gfx::Size(width_
, height_
));
486 void BrowserViewRenderer::DidInitializeCompositor(
487 content::SynchronousCompositor
* compositor
) {
488 TRACE_EVENT0("android_webview",
489 "BrowserViewRenderer::DidInitializeCompositor");
491 DCHECK(!compositor_
);
492 compositor_
= compositor
;
495 void BrowserViewRenderer::DidDestroyCompositor(
496 content::SynchronousCompositor
* compositor
) {
497 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
500 SynchronousCompositorMemoryPolicy zero_policy
;
501 DCHECK(memory_policy_
== zero_policy
);
504 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate
) {
505 if (compositor_needs_continuous_invalidate_
== invalidate
)
508 TRACE_EVENT_INSTANT1("android_webview",
509 "BrowserViewRenderer::SetContinuousInvalidate",
510 TRACE_EVENT_SCOPE_THREAD
,
513 compositor_needs_continuous_invalidate_
= invalidate
;
515 EnsureContinuousInvalidation(false);
518 void BrowserViewRenderer::SetDipScale(float dip_scale
) {
519 dip_scale_
= dip_scale
;
520 CHECK_GT(dip_scale_
, 0);
523 gfx::Vector2d
BrowserViewRenderer::max_scroll_offset() const {
524 DCHECK_GT(dip_scale_
, 0);
525 return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
526 max_scroll_offset_dip_
, dip_scale_
* page_scale_factor_
));
529 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset
) {
530 gfx::Vector2d max_offset
= max_scroll_offset();
531 gfx::Vector2dF scroll_offset_dip
;
532 // To preserve the invariant that scrolling to the maximum physical pixel
533 // value also scrolls to the maximum dip pixel value we transform the physical
534 // offset into the dip offset by using a proportion (instead of dividing by
535 // dip_scale * page_scale_factor).
536 if (max_offset
.x()) {
537 scroll_offset_dip
.set_x((scroll_offset
.x() * max_scroll_offset_dip_
.x()) /
540 if (max_offset
.y()) {
541 scroll_offset_dip
.set_y((scroll_offset
.y() * max_scroll_offset_dip_
.y()) /
545 DCHECK_LE(0, scroll_offset_dip
.x());
546 DCHECK_LE(0, scroll_offset_dip
.y());
547 DCHECK_LE(scroll_offset_dip
.x(), max_scroll_offset_dip_
.x());
548 DCHECK_LE(scroll_offset_dip
.y(), max_scroll_offset_dip_
.y());
550 if (scroll_offset_dip_
== scroll_offset_dip
)
553 scroll_offset_dip_
= scroll_offset_dip
;
555 TRACE_EVENT_INSTANT2("android_webview",
556 "BrowserViewRenderer::ScrollTo",
557 TRACE_EVENT_SCOPE_THREAD
,
559 scroll_offset_dip
.x(),
561 scroll_offset_dip
.y());
564 compositor_
->DidChangeRootLayerScrollOffset();
567 void BrowserViewRenderer::DidUpdateContent() {
568 TRACE_EVENT_INSTANT0("android_webview",
569 "BrowserViewRenderer::DidUpdateContent",
570 TRACE_EVENT_SCOPE_THREAD
);
572 if (on_new_picture_enable_
)
573 client_
->OnNewPicture();
576 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
577 gfx::Vector2dF scroll_offset_dip
) {
578 // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
579 // DrawGl when http://crbug.com/249972 is fixed.
580 if (scroll_offset_dip_
== scroll_offset_dip
)
583 scroll_offset_dip_
= scroll_offset_dip
;
585 gfx::Vector2d max_offset
= max_scroll_offset();
586 gfx::Vector2d scroll_offset
;
587 // For an explanation as to why this is done this way see the comment in
588 // BrowserViewRenderer::ScrollTo.
589 if (max_scroll_offset_dip_
.x()) {
590 scroll_offset
.set_x((scroll_offset_dip
.x() * max_offset
.x()) /
591 max_scroll_offset_dip_
.x());
594 if (max_scroll_offset_dip_
.y()) {
595 scroll_offset
.set_y((scroll_offset_dip
.y() * max_offset
.y()) /
596 max_scroll_offset_dip_
.y());
599 DCHECK_LE(0, scroll_offset
.x());
600 DCHECK_LE(0, scroll_offset
.y());
601 DCHECK_LE(scroll_offset
.x(), max_offset
.x());
602 DCHECK_LE(scroll_offset
.y(), max_offset
.y());
604 client_
->ScrollContainerViewTo(scroll_offset
);
607 gfx::Vector2dF
BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
608 return scroll_offset_dip_
;
611 bool BrowserViewRenderer::IsExternalFlingActive() const {
612 return client_
->IsFlingActive();
615 void BrowserViewRenderer::UpdateRootLayerState(
616 const gfx::Vector2dF
& total_scroll_offset_dip
,
617 const gfx::Vector2dF
& max_scroll_offset_dip
,
618 const gfx::SizeF
& scrollable_size_dip
,
619 float page_scale_factor
,
620 float min_page_scale_factor
,
621 float max_page_scale_factor
) {
622 TRACE_EVENT_INSTANT1(
624 "BrowserViewRenderer::UpdateRootLayerState",
625 TRACE_EVENT_SCOPE_THREAD
,
627 TracedValue::FromValue(
628 RootLayerStateAsValue(total_scroll_offset_dip
, scrollable_size_dip
)
631 DCHECK_GT(dip_scale_
, 0);
633 max_scroll_offset_dip_
= max_scroll_offset_dip
;
634 DCHECK_LE(0, max_scroll_offset_dip_
.x());
635 DCHECK_LE(0, max_scroll_offset_dip_
.y());
637 page_scale_factor_
= page_scale_factor
;
638 DCHECK_GT(page_scale_factor_
, 0);
640 client_
->UpdateScrollState(max_scroll_offset(),
643 min_page_scale_factor
,
644 max_page_scale_factor
);
645 SetTotalRootLayerScrollOffset(total_scroll_offset_dip
);
648 scoped_ptr
<base::Value
> BrowserViewRenderer::RootLayerStateAsValue(
649 const gfx::Vector2dF
& total_scroll_offset_dip
,
650 const gfx::SizeF
& scrollable_size_dip
) {
651 scoped_ptr
<base::DictionaryValue
> state(new base::DictionaryValue
);
653 state
->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip
.x());
654 state
->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip
.y());
656 state
->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_
.x());
657 state
->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_
.y());
659 state
->SetDouble("scrollable_size_dip.width", scrollable_size_dip
.width());
660 state
->SetDouble("scrollable_size_dip.height", scrollable_size_dip
.height());
662 state
->SetDouble("page_scale_factor", page_scale_factor_
);
663 return state
.PassAs
<base::Value
>();
666 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll
,
667 gfx::Vector2dF latest_overscroll_delta
,
668 gfx::Vector2dF current_fling_velocity
) {
669 const float physical_pixel_scale
= dip_scale_
* page_scale_factor_
;
670 if (accumulated_overscroll
== latest_overscroll_delta
)
671 overscroll_rounding_error_
= gfx::Vector2dF();
672 gfx::Vector2dF scaled_overscroll_delta
=
673 gfx::ScaleVector2d(latest_overscroll_delta
, physical_pixel_scale
);
674 gfx::Vector2d rounded_overscroll_delta
= gfx::ToRoundedVector2d(
675 scaled_overscroll_delta
+ overscroll_rounding_error_
);
676 overscroll_rounding_error_
=
677 scaled_overscroll_delta
- rounded_overscroll_delta
;
678 client_
->DidOverscroll(rounded_overscroll_delta
);
681 void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate
) {
682 // This method should be called again when any of these conditions change.
683 bool need_invalidate
=
684 compositor_needs_continuous_invalidate_
|| force_invalidate
;
685 if (!need_invalidate
|| block_invalidates_
)
688 // Always call view invalidate. We rely the Android framework to ignore the
689 // invalidate when it's not needed such as when view is not visible.
690 client_
->PostInvalidate();
692 // Stop fallback ticks when one of these is true.
693 // 1) Webview is paused. Also need to check we are not in clear view since
694 // paused, offscreen still expect clear view to recover.
695 // 2) If we are attached to window and the window is not visible (eg when
696 // app is in the background). We are sure in this case the webview is used
697 // "on-screen" but that updates are not needed when in the background.
698 bool throttle_fallback_tick
=
699 (is_paused_
&& !clear_view_
) || (attached_to_window_
&& !window_visible_
);
700 if (throttle_fallback_tick
)
703 block_invalidates_
= compositor_needs_continuous_invalidate_
;
705 // Unretained here is safe because the callbacks are cancelled when
706 // they are destroyed.
707 post_fallback_tick_
.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick
,
708 base::Unretained(this)));
709 fallback_tick_fired_
.Cancel();
711 // No need to reschedule fallback tick if compositor does not need to be
712 // ticked. This can happen if this is reached because force_invalidate is
714 if (compositor_needs_continuous_invalidate_
)
715 ui_task_runner_
->PostTask(FROM_HERE
, post_fallback_tick_
.callback());
718 void BrowserViewRenderer::PostFallbackTick() {
719 DCHECK(fallback_tick_fired_
.IsCancelled());
720 fallback_tick_fired_
.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired
,
721 base::Unretained(this)));
722 if (compositor_needs_continuous_invalidate_
) {
723 ui_task_runner_
->PostDelayedTask(
725 fallback_tick_fired_
.callback(),
726 base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds
));
728 // Pretend we just composited to unblock further invalidates.
733 void BrowserViewRenderer::FallbackTickFired() {
734 TRACE_EVENT1("android_webview",
735 "BrowserViewRenderer::FallbackTickFired",
736 "compositor_needs_continuous_invalidate_",
737 compositor_needs_continuous_invalidate_
);
739 // This should only be called if OnDraw or DrawGL did not come in time, which
740 // means block_invalidates_ must still be true.
741 DCHECK(block_invalidates_
);
742 if (compositor_needs_continuous_invalidate_
&& compositor_
) {
743 ForceFakeCompositeSW();
745 // Pretend we just composited to unblock further invalidates.
750 void BrowserViewRenderer::ForceFakeCompositeSW() {
753 bitmap
.allocN32Pixels(1, 1);
754 bitmap
.eraseColor(0);
755 SkCanvas
canvas(bitmap
);
756 CompositeSW(&canvas
);
759 bool BrowserViewRenderer::CompositeSW(SkCanvas
* canvas
) {
761 ReturnResourceFromParent();
762 bool result
= compositor_
->DemandDrawSw(canvas
);
767 void BrowserViewRenderer::DidComposite() {
768 block_invalidates_
= false;
769 post_fallback_tick_
.Cancel();
770 fallback_tick_fired_
.Cancel();
771 EnsureContinuousInvalidation(false);
774 std::string
BrowserViewRenderer::ToString(AwDrawGLInfo
* draw_info
) const {
776 base::StringAppendF(&str
, "is_paused: %d ", is_paused_
);
777 base::StringAppendF(&str
, "view_visible: %d ", view_visible_
);
778 base::StringAppendF(&str
, "window_visible: %d ", window_visible_
);
779 base::StringAppendF(&str
, "dip_scale: %f ", dip_scale_
);
780 base::StringAppendF(&str
, "page_scale_factor: %f ", page_scale_factor_
);
781 base::StringAppendF(&str
,
782 "compositor_needs_continuous_invalidate: %d ",
783 compositor_needs_continuous_invalidate_
);
784 base::StringAppendF(&str
, "block_invalidates: %d ", block_invalidates_
);
785 base::StringAppendF(&str
, "view width height: [%d %d] ", width_
, height_
);
786 base::StringAppendF(&str
, "attached_to_window: %d ", attached_to_window_
);
787 base::StringAppendF(&str
,
788 "global visible rect: %s ",
789 last_on_draw_global_visible_rect_
.ToString().c_str());
791 &str
, "scroll_offset_dip: %s ", scroll_offset_dip_
.ToString().c_str());
792 base::StringAppendF(&str
,
793 "overscroll_rounding_error_: %s ",
794 overscroll_rounding_error_
.ToString().c_str());
796 &str
, "on_new_picture_enable: %d ", on_new_picture_enable_
);
797 base::StringAppendF(&str
, "clear_view: %d ", clear_view_
);
799 base::StringAppendF(&str
,
800 "clip left top right bottom: [%d %d %d %d] ",
801 draw_info
->clip_left
,
803 draw_info
->clip_right
,
804 draw_info
->clip_bottom
);
805 base::StringAppendF(&str
,
806 "surface width height: [%d %d] ",
809 base::StringAppendF(&str
, "is_layer: %d ", draw_info
->is_layer
);
814 } // namespace android_webview