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