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/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:
     54   explicit TracedValue(base::Value* value) : 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   }
     60   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:
     67   virtual ~TracedValue() {}
     68   scoped_ptr<base::Value> value_;
     69 
     70   DISALLOW_COPY_AND_ASSIGN(TracedValue);
     71 };
     72 
     73 }  // namespace
     74 
     75 // static
     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 
    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 
    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.
    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
    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.
    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 
    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 
    213 void BrowserViewRenderer::EnforceMemoryPolicyImmediately(
    214     SynchronousCompositorMemoryPolicy new_policy) {
    215   compositor_->SetMemoryPolicy(new_policy);
    216   ForceFakeCompositeSW();
    217 }
    218 
    219 size_t BrowserViewRenderer::GetNumTiles() const {
    220   return memory_policy_.num_resources_limit;
    221 }
    222 
    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 
    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 
    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 
    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     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 
    383 void BrowserViewRenderer::EnableOnNewPicture(bool enabled) {
    384   on_new_picture_enable_ = enabled;
    385 }
    386 
    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 
    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 
    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 
    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 
    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 
    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 
    452 void BrowserViewRenderer::OnDetachedFromWindow() {
    453   TRACE_EVENT0("android_webview", "BrowserViewRenderer::OnDetachedFromWindow");
    454   attached_to_window_ = false;
    455   DCHECK(!hardware_enabled_);
    456 }
    457 
    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 
    473 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 
    478 gfx::Rect BrowserViewRenderer::GetScreenRect() const {
    479   return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
    480 }
    481 
    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 
    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 
    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 
    514 void BrowserViewRenderer::SetDipScale(float dip_scale) {
    515   dip_scale_ = dip_scale;
    516   CHECK(dip_scale_ > 0);
    517 }
    518 
    519 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 
    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 
    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 
    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 
    603 gfx::Vector2dF BrowserViewRenderer::GetTotalRootLayerScrollOffset() {
    604   return scroll_offset_dip_;
    605 }
    606 
    607 bool BrowserViewRenderer::IsExternalFlingActive() const {
    608   return client_->IsFlingActive();
    609 }
    610 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    756 bool BrowserViewRenderer::CompositeSW(SkCanvas* canvas) {
    757   DCHECK(compositor_);
    758   ReturnResourceFromParent();
    759   bool result = compositor_->DemandDrawSw(canvas);
    760   DidComposite();
    761   return result;
    762 }
    763 
    764 void BrowserViewRenderer::DidComposite() {
    765   block_invalidates_ = false;
    766   post_fallback_tick_.Cancel();
    767   fallback_tick_fired_.Cancel();
    768   EnsureContinuousInvalidation(false);
    769 }
    770 
    771 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