Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / android_webview / browser / browser_view_renderer.cc
blob93ab0a8073e4d126effe033d8a0b0181d9d72ff8
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 {
37 namespace {
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.
51 size_t g_tile_area;
53 class TracedValue : public base::debug::ConvertableToTraceFormat {
54 public:
55 explicit TracedValue(base::Value* value) : value_(value) {}
56 static scoped_refptr<base::debug::ConvertableToTraceFormat> FromValue(
57 base::Value* value) {
58 return scoped_refptr<base::debug::ConvertableToTraceFormat>(
59 new TracedValue(value));
61 virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
62 std::string tmp;
63 base::JSONWriter::Write(value_.get(), &tmp);
64 *out += tmp;
67 private:
68 virtual ~TracedValue() {}
69 scoped_ptr<base::Value> value_;
71 DISALLOW_COPY_AND_ASSIGN(TracedValue);
74 } // namespace
76 // static
77 void BrowserViewRenderer::CalculateTileMemoryPolicy(bool use_zero_copy) {
78 if (!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);
85 return;
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);
97 size_t tile_size;
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)
107 : client_(client),
108 shared_renderer_state_(shared_renderer_state),
109 web_contents_(web_contents),
110 ui_task_runner_(ui_task_runner),
111 compositor_(NULL),
112 is_paused_(false),
113 view_visible_(false),
114 window_visible_(false),
115 attached_to_window_(false),
116 hardware_enabled_(false),
117 dip_scale_(0.0),
118 page_scale_factor_(1.0),
119 on_new_picture_enable_(false),
120 clear_view_(false),
121 compositor_needs_continuous_invalidate_(false),
122 block_invalidates_(false),
123 width_(0),
124 height_(0),
125 num_tiles_(0u),
126 num_bytes_(0u) {
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.
145 enum {
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
153 // backgrounded.
154 if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
155 return;
157 // Do not release resources on view we expect to get DrawGL soon.
158 if (level < TRIM_MEMORY_BACKGROUND && visible)
159 return;
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)
165 return;
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.
180 policy.bytes_limit =
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;
188 return policy;
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_)
207 return;
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;
234 if (clear_view_)
235 return false;
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) {
247 if (!compositor_)
248 return false;
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_)
260 return false;
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;
285 else
286 viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
288 scoped_ptr<cc::CompositorFrame> frame =
289 compositor_->DemandDrawHw(surface_size,
290 gfx::Transform(),
291 viewport,
292 clip,
293 viewport_rect_for_tile_priority,
294 transform_for_tile_priority);
295 if (!frame.get())
296 return false;
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());
303 DidComposite();
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) {
316 if (!input.get())
317 return;
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) {
336 if (!compositor_) {
337 TRACE_EVENT_INSTANT0(
338 "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
339 return false;
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
347 // bitmap.
348 return BrowserViewRendererJavaHelper::GetInstance()
349 ->RenderViaAuxilaryBitmapIfNeeded(
350 java_canvas,
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,
358 int height) {
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_,
371 gfx::Vector2dF());
373 SkPictureRecorder recorder;
374 SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
375 if (compositor_)
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);
388 if (clear_view_)
389 return;
391 clear_view_ = true;
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,
400 "paused",
401 paused);
402 is_paused_ = paused;
403 EnsureContinuousInvalidation(false);
406 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
407 TRACE_EVENT_INSTANT1("android_webview",
408 "BrowserViewRenderer::SetViewVisibility",
409 TRACE_EVENT_SCOPE_THREAD,
410 "view_visible",
411 view_visible);
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,
419 "window_visible",
420 window_visible);
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,
429 "width",
430 width,
431 "height",
432 height);
433 width_ = width;
434 height_ = height;
437 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
438 TRACE_EVENT2("android_webview",
439 "BrowserViewRenderer::OnAttachedToWindow",
440 "width",
441 width,
442 "height",
443 height);
444 attached_to_window_ = true;
445 width_ = width;
446 height_ = height;
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");
483 DCHECK(compositor);
484 DCHECK(!compositor_);
485 compositor_ = compositor;
488 void BrowserViewRenderer::DidDestroyCompositor(
489 content::SynchronousCompositor* compositor) {
490 TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
491 DCHECK(compositor_);
492 compositor_ = NULL;
493 SynchronousCompositorMemoryPolicy zero_policy;
494 DCHECK(memory_policy_ == zero_policy);
497 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
498 if (compositor_needs_continuous_invalidate_ == invalidate)
499 return;
501 TRACE_EVENT_INSTANT1("android_webview",
502 "BrowserViewRenderer::SetContinuousInvalidate",
503 TRACE_EVENT_SCOPE_THREAD,
504 "invalidate",
505 invalidate);
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()) /
531 max_offset.x());
533 if (max_offset.y()) {
534 scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
535 max_offset.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)
544 return;
546 scroll_offset_dip_ = scroll_offset_dip;
548 TRACE_EVENT_INSTANT2("android_webview",
549 "BrowserViewRenderer::ScrollTo",
550 TRACE_EVENT_SCOPE_THREAD,
551 "x",
552 scroll_offset_dip.x(),
553 "y",
554 scroll_offset_dip.y());
556 if (compositor_)
557 compositor_->DidChangeRootLayerScrollOffset();
560 void BrowserViewRenderer::DidUpdateContent() {
561 TRACE_EVENT_INSTANT0("android_webview",
562 "BrowserViewRenderer::DidUpdateContent",
563 TRACE_EVENT_SCOPE_THREAD);
564 clear_view_ = false;
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)
574 return;
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(
616 "android_webview",
617 "BrowserViewRenderer::UpdateRootLayerState",
618 TRACE_EVENT_SCOPE_THREAD,
619 "state",
620 TracedValue::FromValue(
621 RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip)
622 .release()));
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(),
634 scrollable_size_dip,
635 page_scale_factor,
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_)
679 return;
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)
694 return;
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
706 // true.
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(
717 FROM_HERE,
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() {
737 DCHECK(compositor_);
738 SkBitmap bitmap;
739 bitmap.allocN32Pixels(1, 1);
740 bitmap.eraseColor(0);
741 SkCanvas canvas(bitmap);
742 CompositeSW(&canvas);
745 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
746 DCHECK(compositor_);
747 ReturnResourceFromParent();
748 bool result = compositor_->DemandDrawSw(canvas);
749 DidComposite();
750 return result;
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 {
761 std::string str;
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());
776 base::StringAppendF(
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());
781 base::StringAppendF(
782 &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
783 base::StringAppendF(&str, "clear_view: %d ", clear_view_);
784 if (draw_info) {
785 base::StringAppendF(&str,
786 "clip left top right bottom: [%d %d %d %d] ",
787 draw_info->clip_left,
788 draw_info->clip_top,
789 draw_info->clip_right,
790 draw_info->clip_bottom);
791 base::StringAppendF(&str,
792 "surface width height: [%d %d] ",
793 draw_info->width,
794 draw_info->height);
795 base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
797 return str;
800 } // namespace android_webview