Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / android_webview / browser / browser_view_renderer.cc
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.
4
5 #include "android_webview/browser/browser_view_renderer.h"
6
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"
28
29 using base::android::AttachCurrentThread;
30 using base::android::JavaRef;
31 using base::android::ScopedJavaLocalRef;
32 using content::BrowserThread;
33 using content::SynchronousCompositorMemoryPolicy;
34
35 namespace android_webview {
36
37 namespace {
38
39 const int64 kFallbackTickTimeoutInMilliseconds = 100;
40
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;
45
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;
52
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));
60   }
61   virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
62     std::string tmp;
63     base::JSONWriter::Write(value_.get(), &tmp);
64     *out += tmp;
65   }
66
67  private:
68   virtual ~TracedValue() {}
69   scoped_ptr<base::Value> value_;
70
71   DISALLOW_COPY_AND_ASSIGN(TracedValue);
72 };
73
74 }  // namespace
75
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;
82
83     // Also use a high tile limit since there are no file descriptor issues.
84     GlobalTileManager::GetInstance()->SetTileLimit(1000);
85     return;
86   }
87
88   CommandLine* cl = CommandLine::ForCurrentProcess();
89   const char kDefaultTileSize[] = "384";
90
91   if (!cl->HasSwitch(switches::kDefaultTileWidth))
92     cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
93
94   if (!cl->HasSwitch(switches::kDefaultTileHeight))
95     cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
96
97   size_t tile_size;
98   base::StringToSizeT(kDefaultTileSize, &tile_size);
99   g_tile_area = tile_size * tile_size;
100 }
101
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);
129
130   // Currently the logic in this class relies on |compositor_| remaining
131   // NULL until the DidInitializeCompositor() call, hence it is not set here.
132 }
133
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.
138 }
139
140 // This function updates the resource allocation in GlobalTileManager.
141 void BrowserViewRenderer::TrimMemory(const int level, const bool visible) {
142   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143   // Constants from Android ComponentCallbacks2.
144   enum {
145     TRIM_MEMORY_RUNNING_LOW = 10,
146     TRIM_MEMORY_UI_HIDDEN = 20,
147     TRIM_MEMORY_BACKGROUND = 40,
148   };
149
150   // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
151   // it does not indicate memory pressure, but merely that the app is
152   // backgrounded.
153   if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
154     return;
155
156   // Do not release resources on view we expect to get DrawGL soon.
157   if (level < TRIM_MEMORY_BACKGROUND && visible)
158     return;
159
160   // Just set the memory limit to 0 and drop all tiles. This will be reset to
161   // normal levels in the next DrawGL call.
162   SynchronousCompositorMemoryPolicy zero_policy;
163   if (memory_policy_ == zero_policy)
164     return;
165
166   TRACE_EVENT0("android_webview", "BrowserViewRenderer::TrimMemory");
167
168   RequestMemoryPolicy(zero_policy);
169   EnforceMemoryPolicyImmediately(zero_policy);
170 }
171
172 SynchronousCompositorMemoryPolicy
173 BrowserViewRenderer::CalculateDesiredMemoryPolicy() {
174   SynchronousCompositorMemoryPolicy policy;
175   size_t width = last_on_draw_global_visible_rect_.width();
176   size_t height = last_on_draw_global_visible_rect_.height();
177   policy.bytes_limit = kMemoryMultiplier * kBytesPerPixel * width * height;
178   // Round up to a multiple of kMemoryAllocationStep.
179   policy.bytes_limit =
180       (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
181
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;
187   return policy;
188 }
189
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   // This will be used in SetNumTiles.
195   num_bytes_ = new_policy.bytes_limit;
196
197   GlobalTileManager* manager = GlobalTileManager::GetInstance();
198
199   // The following line will call BrowserViewRenderer::SetTilesNum().
200   manager->RequestTiles(new_policy.num_resources_limit, tile_manager_key_);
201 }
202
203 void BrowserViewRenderer::SetNumTiles(size_t num_tiles,
204                                       bool effective_immediately) {
205   num_tiles_ = num_tiles;
206
207   memory_policy_.num_resources_limit = num_tiles_;
208   memory_policy_.bytes_limit = num_bytes_;
209
210   if (effective_immediately)
211     EnforceMemoryPolicyImmediately(memory_policy_);
212 }
213
214 void BrowserViewRenderer::EnforceMemoryPolicyImmediately(
215     SynchronousCompositorMemoryPolicy new_policy) {
216   compositor_->SetMemoryPolicy(new_policy);
217   ForceFakeCompositeSW();
218 }
219
220 size_t BrowserViewRenderer::GetNumTiles() const {
221   return memory_policy_.num_resources_limit;
222 }
223
224 bool BrowserViewRenderer::OnDraw(jobject java_canvas,
225                                  bool is_hardware_canvas,
226                                  const gfx::Vector2d& scroll,
227                                  const gfx::Rect& global_visible_rect) {
228   last_on_draw_scroll_offset_ = scroll;
229   last_on_draw_global_visible_rect_ = global_visible_rect;
230
231   if (clear_view_)
232     return false;
233
234   if (is_hardware_canvas && attached_to_window_ &&
235       !switches::ForceAuxiliaryBitmap()) {
236     return OnDrawHardware(java_canvas);
237   }
238
239   // Perform a software draw
240   return OnDrawSoftware(java_canvas);
241 }
242
243 bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) {
244   if (!compositor_)
245     return false;
246
247   if (last_on_draw_global_visible_rect_.IsEmpty()) {
248     shared_renderer_state_->SetForceInvalidateOnNextDrawGL(true);
249     return client_->RequestDrawGL(java_canvas, false);
250   }
251
252   if (!hardware_enabled_) {
253     hardware_enabled_ = compositor_->InitializeHwDraw();
254     if (hardware_enabled_) {
255       tile_manager_key_ = GlobalTileManager::GetInstance()->PushBack(this);
256       gpu::GLInProcessContext* share_context = compositor_->GetShareContext();
257       DCHECK(share_context);
258       shared_renderer_state_->SetSharedContext(share_context);
259     }
260   }
261   if (!hardware_enabled_)
262     return false;
263
264   ReturnResourceFromParent();
265   SynchronousCompositorMemoryPolicy new_policy = CalculateDesiredMemoryPolicy();
266   RequestMemoryPolicy(new_policy);
267   compositor_->SetMemoryPolicy(memory_policy_);
268
269   scoped_ptr<DrawGLInput> draw_gl_input(new DrawGLInput);
270   draw_gl_input->scroll_offset = last_on_draw_scroll_offset_;
271   draw_gl_input->width = width_;
272   draw_gl_input->height = height_;
273
274   parent_draw_constraints_ = shared_renderer_state_->ParentDrawConstraints();
275   gfx::Size surface_size(width_, height_);
276   gfx::Rect viewport(surface_size);
277   gfx::Rect clip = viewport;
278   gfx::Transform transform_for_tile_priority =
279       parent_draw_constraints_.transform;
280
281   // If the WebView is on a layer, WebView does not know what transform is
282   // applied onto the layer so global visible rect does not make sense here.
283   // In this case, just use the surface rect for tiling.
284   gfx::Rect viewport_rect_for_tile_priority;
285   if (parent_draw_constraints_.is_layer)
286     viewport_rect_for_tile_priority = parent_draw_constraints_.surface_rect;
287   else
288     viewport_rect_for_tile_priority = last_on_draw_global_visible_rect_;
289
290   scoped_ptr<cc::CompositorFrame> frame =
291       compositor_->DemandDrawHw(surface_size,
292                                 gfx::Transform(),
293                                 viewport,
294                                 clip,
295                                 viewport_rect_for_tile_priority,
296                                 transform_for_tile_priority);
297   if (!frame.get())
298     return false;
299
300   GlobalTileManager::GetInstance()->DidUse(tile_manager_key_);
301
302   frame->AssignTo(&draw_gl_input->frame);
303   ReturnUnusedResource(shared_renderer_state_->PassDrawGLInput());
304   shared_renderer_state_->SetDrawGLInput(draw_gl_input.Pass());
305   DidComposite();
306   return client_->RequestDrawGL(java_canvas, false);
307 }
308
309 void BrowserViewRenderer::UpdateParentDrawConstraints() {
310   // Post an invalidate if the parent draw constraints are stale and there is
311   // no pending invalidate.
312   if (shared_renderer_state_->NeedsForceInvalidateOnNextDrawGL() ||
313       !parent_draw_constraints_.Equals(
314         shared_renderer_state_->ParentDrawConstraints())) {
315     shared_renderer_state_->SetForceInvalidateOnNextDrawGL(false);
316     EnsureContinuousInvalidation(true);
317   }
318 }
319
320 void BrowserViewRenderer::ReturnUnusedResource(scoped_ptr<DrawGLInput> input) {
321   if (!input.get())
322     return;
323
324   cc::CompositorFrameAck frame_ack;
325   cc::TransferableResource::ReturnResources(
326       input->frame.delegated_frame_data->resource_list,
327       &frame_ack.resources);
328   if (!frame_ack.resources.empty())
329     compositor_->ReturnResources(frame_ack);
330 }
331
332 void BrowserViewRenderer::ReturnResourceFromParent() {
333   cc::CompositorFrameAck frame_ack;
334   shared_renderer_state_->SwapReturnedResources(&frame_ack.resources);
335   if (!frame_ack.resources.empty()) {
336     compositor_->ReturnResources(frame_ack);
337   }
338 }
339
340 bool BrowserViewRenderer::OnDrawSoftware(jobject java_canvas) {
341   if (!compositor_) {
342     TRACE_EVENT_INSTANT0(
343         "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
344     return false;
345   }
346
347   // TODO(hush): right now webview size is passed in as the auxiliary bitmap
348   // size, which might hurt performace (only for software draws with auxiliary
349   // bitmap). For better performance, get global visible rect, transform it
350   // from screen space to view space, then intersect with the webview in
351   // viewspace.  Use the resulting rect as the auxiliary
352   // bitmap.
353   return BrowserViewRendererJavaHelper::GetInstance()
354       ->RenderViaAuxilaryBitmapIfNeeded(
355           java_canvas,
356           last_on_draw_scroll_offset_,
357           gfx::Size(width_, height_),
358           base::Bind(&BrowserViewRenderer::CompositeSW,
359                      base::Unretained(this)));
360 }
361
362 skia::RefPtr<SkPicture> BrowserViewRenderer::CapturePicture(int width,
363                                                             int height) {
364   TRACE_EVENT0("android_webview", "BrowserViewRenderer::CapturePicture");
365
366   // Return empty Picture objects for empty SkPictures.
367   if (width <= 0 || height <= 0) {
368     SkPictureRecorder emptyRecorder;
369     emptyRecorder.beginRecording(0, 0);
370     return skia::AdoptRef(emptyRecorder.endRecording());
371   }
372
373   // Reset scroll back to the origin, will go back to the old
374   // value when scroll_reset is out of scope.
375   base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
376                                                gfx::Vector2dF());
377
378   SkPictureRecorder recorder;
379   SkCanvas* rec_canvas = recorder.beginRecording(width, height, NULL, 0);
380   if (compositor_)
381     CompositeSW(rec_canvas);
382   return skia::AdoptRef(recorder.endRecording());
383 }
384
385 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
386   on_new_picture_enable_ = enabled;
387 }
388
389 void BrowserViewRenderer::ClearView() {
390   TRACE_EVENT_INSTANT0("android_webview",
391                        "BrowserViewRenderer::ClearView",
392                        TRACE_EVENT_SCOPE_THREAD);
393   if (clear_view_)
394     return;
395
396   clear_view_ = true;
397   // Always invalidate ignoring the compositor to actually clear the webview.
398   EnsureContinuousInvalidation(true);
399 }
400
401 void BrowserViewRenderer::SetIsPaused(bool paused) {
402   TRACE_EVENT_INSTANT1("android_webview",
403                        "BrowserViewRenderer::SetIsPaused",
404                        TRACE_EVENT_SCOPE_THREAD,
405                        "paused",
406                        paused);
407   is_paused_ = paused;
408   EnsureContinuousInvalidation(false);
409 }
410
411 void BrowserViewRenderer::SetViewVisibility(bool view_visible) {
412   TRACE_EVENT_INSTANT1("android_webview",
413                        "BrowserViewRenderer::SetViewVisibility",
414                        TRACE_EVENT_SCOPE_THREAD,
415                        "view_visible",
416                        view_visible);
417   view_visible_ = view_visible;
418 }
419
420 void BrowserViewRenderer::SetWindowVisibility(bool window_visible) {
421   TRACE_EVENT_INSTANT1("android_webview",
422                        "BrowserViewRenderer::SetWindowVisibility",
423                        TRACE_EVENT_SCOPE_THREAD,
424                        "window_visible",
425                        window_visible);
426   window_visible_ = window_visible;
427   EnsureContinuousInvalidation(false);
428 }
429
430 void BrowserViewRenderer::OnSizeChanged(int width, int height) {
431   TRACE_EVENT_INSTANT2("android_webview",
432                        "BrowserViewRenderer::OnSizeChanged",
433                        TRACE_EVENT_SCOPE_THREAD,
434                        "width",
435                        width,
436                        "height",
437                        height);
438   width_ = width;
439   height_ = height;
440 }
441
442 void BrowserViewRenderer::OnAttachedToWindow(int width, int height) {
443   TRACE_EVENT2("android_webview",
444                "BrowserViewRenderer::OnAttachedToWindow",
445                "width",
446                width,
447                "height",
448                height);
449   attached_to_window_ = true;
450   width_ = width;
451   height_ = height;
452 }
453
454 void BrowserViewRenderer::OnDetachedFromWindow() {
455   TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
456   attached_to_window_ = false;
457   DCHECK(!hardware_enabled_);
458 }
459
460 void BrowserViewRenderer::ReleaseHardware() {
461   DCHECK(hardware_enabled_);
462   ReturnUnusedResource(shared_renderer_state_->PassDrawGLInput());
463   ReturnResourceFromParent();
464   DCHECK(shared_renderer_state_->ReturnedResourcesEmpty());
465
466   compositor_->ReleaseHwDraw();
467   shared_renderer_state_->SetSharedContext(NULL);
468   hardware_enabled_ = false;
469
470   SynchronousCompositorMemoryPolicy zero_policy;
471   RequestMemoryPolicy(zero_policy);
472   GlobalTileManager::GetInstance()->Remove(tile_manager_key_);
473 }
474
475 bool BrowserViewRenderer::IsVisible() const {
476   // Ignore |window_visible_| if |attached_to_window_| is false.
477   return view_visible_ && (!attached_to_window_ || window_visible_);
478 }
479
480 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
481   return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
482 }
483
484 void BrowserViewRenderer::DidInitializeCompositor(
485     content::SynchronousCompositor* compositor) {
486   TRACE_EVENT0("android_webview",
487                "BrowserViewRenderer::DidInitializeCompositor");
488   DCHECK(compositor);
489   DCHECK(!compositor_);
490   compositor_ = compositor;
491 }
492
493 void BrowserViewRenderer::DidDestroyCompositor(
494     content::SynchronousCompositor* compositor) {
495   TRACE_EVENT0("android_webview", "BrowserViewRenderer::DidDestroyCompositor");
496   DCHECK(compositor_);
497   compositor_ = NULL;
498   SynchronousCompositorMemoryPolicy zero_policy;
499   DCHECK(memory_policy_ == zero_policy);
500 }
501
502 void BrowserViewRenderer::SetContinuousInvalidate(bool invalidate) {
503   if (compositor_needs_continuous_invalidate_ == invalidate)
504     return;
505
506   TRACE_EVENT_INSTANT1("android_webview",
507                        "BrowserViewRenderer::SetContinuousInvalidate",
508                        TRACE_EVENT_SCOPE_THREAD,
509                        "invalidate",
510                        invalidate);
511   compositor_needs_continuous_invalidate_ = invalidate;
512
513   EnsureContinuousInvalidation(false);
514 }
515
516 void BrowserViewRenderer::SetDipScale(float dip_scale) {
517   dip_scale_ = dip_scale;
518   CHECK(dip_scale_ > 0);
519 }
520
521 gfx::Vector2d BrowserViewRenderer::max_scroll_offset() const {
522   DCHECK_GT(dip_scale_, 0);
523   return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
524       max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
525 }
526
527 void BrowserViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
528   gfx::Vector2d max_offset = max_scroll_offset();
529   gfx::Vector2dF scroll_offset_dip;
530   // To preserve the invariant that scrolling to the maximum physical pixel
531   // value also scrolls to the maximum dip pixel value we transform the physical
532   // offset into the dip offset by using a proportion (instead of dividing by
533   // dip_scale * page_scale_factor).
534   if (max_offset.x()) {
535     scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
536                             max_offset.x());
537   }
538   if (max_offset.y()) {
539     scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
540                             max_offset.y());
541   }
542
543   DCHECK_LE(0, scroll_offset_dip.x());
544   DCHECK_LE(0, scroll_offset_dip.y());
545   DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
546   DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
547
548   if (scroll_offset_dip_ == scroll_offset_dip)
549     return;
550
551   scroll_offset_dip_ = scroll_offset_dip;
552
553   TRACE_EVENT_INSTANT2("android_webview",
554                "BrowserViewRenderer::ScrollTo",
555                TRACE_EVENT_SCOPE_THREAD,
556                "x",
557                scroll_offset_dip.x(),
558                "y",
559                scroll_offset_dip.y());
560
561   if (compositor_)
562     compositor_->DidChangeRootLayerScrollOffset();
563 }
564
565 void BrowserViewRenderer::DidUpdateContent() {
566   TRACE_EVENT_INSTANT0("android_webview",
567                        "BrowserViewRenderer::DidUpdateContent",
568                        TRACE_EVENT_SCOPE_THREAD);
569   clear_view_ = false;
570   if (on_new_picture_enable_)
571     client_->OnNewPicture();
572 }
573
574 void BrowserViewRenderer::SetTotalRootLayerScrollOffset(
575     gfx::Vector2dF scroll_offset_dip) {
576   // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
577   // DrawGl when http://crbug.com/249972 is fixed.
578   if (scroll_offset_dip_ == scroll_offset_dip)
579     return;
580
581   scroll_offset_dip_ = scroll_offset_dip;
582
583   gfx::Vector2d max_offset = max_scroll_offset();
584   gfx::Vector2d scroll_offset;
585   // For an explanation as to why this is done this way see the comment in
586   // BrowserViewRenderer::ScrollTo.
587   if (max_scroll_offset_dip_.x()) {
588     scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
589                         max_scroll_offset_dip_.x());
590   }
591
592   if (max_scroll_offset_dip_.y()) {
593     scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
594                         max_scroll_offset_dip_.y());
595   }
596
597   DCHECK(0 <= scroll_offset.x());
598   DCHECK(0 <= scroll_offset.y());
599   DCHECK(scroll_offset.x() <= max_offset.x());
600   DCHECK(scroll_offset.y() <= max_offset.y());
601
602   client_->ScrollContainerViewTo(scroll_offset);
603 }
604
605 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
606   return scroll_offset_dip_;
607 }
608
609 bool BrowserViewRenderer::IsExternalFlingActive() const {
610   return client_->IsFlingActive();
611 }
612
613 void BrowserViewRenderer::UpdateRootLayerState(
614     const gfx::Vector2dF& total_scroll_offset_dip,
615     const gfx::Vector2dF& max_scroll_offset_dip,
616     const gfx::SizeF& scrollable_size_dip,
617     float page_scale_factor,
618     float min_page_scale_factor,
619     float max_page_scale_factor) {
620   TRACE_EVENT_INSTANT1(
621       "android_webview",
622       "BrowserViewRenderer::UpdateRootLayerState",
623       TRACE_EVENT_SCOPE_THREAD,
624       "state",
625       TracedValue::FromValue(
626           RootLayerStateAsValue(total_scroll_offset_dip, scrollable_size_dip)
627               .release()));
628
629   DCHECK_GT(dip_scale_, 0);
630
631   max_scroll_offset_dip_ = max_scroll_offset_dip;
632   DCHECK_LE(0, max_scroll_offset_dip_.x());
633   DCHECK_LE(0, max_scroll_offset_dip_.y());
634
635   page_scale_factor_ = page_scale_factor;
636   DCHECK_GT(page_scale_factor_, 0);
637
638   client_->UpdateScrollState(max_scroll_offset(),
639                              scrollable_size_dip,
640                              page_scale_factor,
641                              min_page_scale_factor,
642                              max_page_scale_factor);
643   SetTotalRootLayerScrollOffset(total_scroll_offset_dip);
644 }
645
646 scoped_ptr<base::Value> BrowserViewRenderer::RootLayerStateAsValue(
647     const gfx::Vector2dF& total_scroll_offset_dip,
648     const gfx::SizeF& scrollable_size_dip) {
649   scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
650
651   state->SetDouble("total_scroll_offset_dip.x", total_scroll_offset_dip.x());
652   state->SetDouble("total_scroll_offset_dip.y", total_scroll_offset_dip.y());
653
654   state->SetDouble("max_scroll_offset_dip.x", max_scroll_offset_dip_.x());
655   state->SetDouble("max_scroll_offset_dip.y", max_scroll_offset_dip_.y());
656
657   state->SetDouble("scrollable_size_dip.width", scrollable_size_dip.width());
658   state->SetDouble("scrollable_size_dip.height", scrollable_size_dip.height());
659
660   state->SetDouble("page_scale_factor", page_scale_factor_);
661   return state.PassAs<base::Value>();
662 }
663
664 void BrowserViewRenderer::DidOverscroll(gfx::Vector2dF accumulated_overscroll,
665                                         gfx::Vector2dF latest_overscroll_delta,
666                                         gfx::Vector2dF current_fling_velocity) {
667   const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
668   if (accumulated_overscroll == latest_overscroll_delta)
669     overscroll_rounding_error_ = gfx::Vector2dF();
670   gfx::Vector2dF scaled_overscroll_delta =
671       gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
672   gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
673       scaled_overscroll_delta + overscroll_rounding_error_);
674   overscroll_rounding_error_ =
675       scaled_overscroll_delta - rounded_overscroll_delta;
676   client_->DidOverscroll(rounded_overscroll_delta);
677 }
678
679 void BrowserViewRenderer::EnsureContinuousInvalidation(bool force_invalidate) {
680   // This method should be called again when any of these conditions change.
681   bool need_invalidate =
682       compositor_needs_continuous_invalidate_ || force_invalidate;
683   if (!need_invalidate || block_invalidates_)
684     return;
685
686   // Always call view invalidate. We rely the Android framework to ignore the
687   // invalidate when it's not needed such as when view is not visible.
688   client_->PostInvalidate();
689
690   // Stop fallback ticks when one of these is true.
691   // 1) Webview is paused. Also need to check we are not in clear view since
692   // paused, offscreen still expect clear view to recover.
693   // 2) If we are attached to window and the window is not visible (eg when
694   // app is in the background). We are sure in this case the webview is used
695   // "on-screen" but that updates are not needed when in the background.
696   bool throttle_fallback_tick =
697       (is_paused_ && !clear_view_) || (attached_to_window_ && !window_visible_);
698   if (throttle_fallback_tick)
699     return;
700
701   block_invalidates_ = compositor_needs_continuous_invalidate_;
702
703   // Unretained here is safe because the callbacks are cancelled when
704   // they are destroyed.
705   post_fallback_tick_.Reset(base::Bind(&BrowserViewRenderer::PostFallbackTick,
706                                        base::Unretained(this)));
707   fallback_tick_fired_.Cancel();
708
709   // No need to reschedule fallback tick if compositor does not need to be
710   // ticked. This can happen if this is reached because force_invalidate is
711   // true.
712   if (compositor_needs_continuous_invalidate_)
713     ui_task_runner_->PostTask(FROM_HERE, post_fallback_tick_.callback());
714 }
715
716 void BrowserViewRenderer::PostFallbackTick() {
717   DCHECK(fallback_tick_fired_.IsCancelled());
718   fallback_tick_fired_.Reset(base::Bind(&BrowserViewRenderer::FallbackTickFired,
719                                         base::Unretained(this)));
720   if (compositor_needs_continuous_invalidate_) {
721     ui_task_runner_->PostDelayedTask(
722         FROM_HERE,
723         fallback_tick_fired_.callback(),
724         base::TimeDelta::FromMilliseconds(kFallbackTickTimeoutInMilliseconds));
725   } else {
726     // Pretend we just composited to unblock further invalidates.
727     DidComposite();
728   }
729 }
730
731 void BrowserViewRenderer::FallbackTickFired() {
732   TRACE_EVENT1("android_webview",
733                "BrowserViewRenderer::FallbackTickFired",
734                "compositor_needs_continuous_invalidate_",
735                compositor_needs_continuous_invalidate_);
736
737   // This should only be called if OnDraw or DrawGL did not come in time, which
738   // means block_invalidates_ must still be true.
739   DCHECK(block_invalidates_);
740   if (compositor_needs_continuous_invalidate_ && compositor_) {
741     ForceFakeCompositeSW();
742   } else {
743     // Pretend we just composited to unblock further invalidates.
744     DidComposite();
745   }
746 }
747
748 void BrowserViewRenderer::ForceFakeCompositeSW() {
749   DCHECK(compositor_);
750   SkBitmap bitmap;
751   bitmap.allocN32Pixels(1, 1);
752   bitmap.eraseColor(0);
753   SkCanvas canvas(bitmap);
754   CompositeSW(&canvas);
755 }
756
757 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
758   DCHECK(compositor_);
759   ReturnResourceFromParent();
760   bool result = compositor_->DemandDrawSw(canvas);
761   DidComposite();
762   return result;
763 }
764
765 void BrowserViewRenderer::DidComposite() {
766   block_invalidates_ = false;
767   post_fallback_tick_.Cancel();
768   fallback_tick_fired_.Cancel();
769   EnsureContinuousInvalidation(false);
770 }
771
772 std::string BrowserViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
773   std::string str;
774   base::StringAppendF(&str, "is_paused: %d ", is_paused_);
775   base::StringAppendF(&str, "view_visible: %d ", view_visible_);
776   base::StringAppendF(&str, "window_visible: %d ", window_visible_);
777   base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
778   base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
779   base::StringAppendF(&str,
780                       "compositor_needs_continuous_invalidate: %d ",
781                       compositor_needs_continuous_invalidate_);
782   base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
783   base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
784   base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
785   base::StringAppendF(&str,
786                       "global visible rect: %s ",
787                       last_on_draw_global_visible_rect_.ToString().c_str());
788   base::StringAppendF(
789       &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
790   base::StringAppendF(&str,
791                       "overscroll_rounding_error_: %s ",
792                       overscroll_rounding_error_.ToString().c_str());
793   base::StringAppendF(
794       &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
795   base::StringAppendF(&str, "clear_view: %d ", clear_view_);
796   if (draw_info) {
797     base::StringAppendF(&str,
798                         "clip left top right bottom: [%d %d %d %d] ",
799                         draw_info->clip_left,
800                         draw_info->clip_top,
801                         draw_info->clip_right,
802                         draw_info->clip_bottom);
803     base::StringAppendF(&str,
804                         "surface width height: [%d %d] ",
805                         draw_info->width,
806                         draw_info->height);
807     base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
808   }
809   return str;
810 }
811
812 }  // namespace android_webview