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