Home | History | Annotate | Download | only in browser
      1 // Copyright 2013 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/in_process_view_renderer.h"
      6 
      7 #include <android/bitmap.h>
      8 
      9 #include "android_webview/browser/aw_gl_surface.h"
     10 #include "android_webview/browser/scoped_app_gl_state_restore.h"
     11 #include "android_webview/common/aw_switches.h"
     12 #include "android_webview/public/browser/draw_gl.h"
     13 #include "android_webview/public/browser/draw_sw.h"
     14 #include "base/android/jni_android.h"
     15 #include "base/auto_reset.h"
     16 #include "base/command_line.h"
     17 #include "base/debug/trace_event.h"
     18 #include "base/lazy_instance.h"
     19 #include "base/logging.h"
     20 #include "base/strings/string_number_conversions.h"
     21 #include "base/strings/stringprintf.h"
     22 #include "content/public/browser/browser_thread.h"
     23 #include "content/public/browser/web_contents.h"
     24 #include "content/public/common/content_switches.h"
     25 #include "gpu/command_buffer/service/in_process_command_buffer.h"
     26 #include "third_party/skia/include/core/SkBitmap.h"
     27 #include "third_party/skia/include/core/SkCanvas.h"
     28 #include "third_party/skia/include/core/SkDevice.h"
     29 #include "third_party/skia/include/core/SkGraphics.h"
     30 #include "third_party/skia/include/core/SkPicture.h"
     31 #include "third_party/skia/include/utils/SkCanvasStateUtils.h"
     32 #include "ui/gfx/skia_util.h"
     33 #include "ui/gfx/transform.h"
     34 #include "ui/gfx/vector2d_conversions.h"
     35 #include "ui/gfx/vector2d_f.h"
     36 
     37 using base::android::AttachCurrentThread;
     38 using base::android::JavaRef;
     39 using base::android::ScopedJavaLocalRef;
     40 using content::BrowserThread;
     41 
     42 namespace android_webview {
     43 
     44 namespace {
     45 
     46 
     47 const void* kUserDataKey = &kUserDataKey;
     48 
     49 class UserData : public content::WebContents::Data {
     50  public:
     51   UserData(InProcessViewRenderer* ptr) : instance_(ptr) {}
     52   virtual ~UserData() {
     53     instance_->WebContentsGone();
     54   }
     55 
     56   static InProcessViewRenderer* GetInstance(content::WebContents* contents) {
     57     if (!contents)
     58       return NULL;
     59     UserData* data = reinterpret_cast<UserData*>(
     60         contents->GetUserData(kUserDataKey));
     61     return data ? data->instance_ : NULL;
     62   }
     63 
     64  private:
     65   InProcessViewRenderer* instance_;
     66 };
     67 
     68 bool RasterizeIntoBitmap(JNIEnv* env,
     69                          const JavaRef<jobject>& jbitmap,
     70                          int scroll_x,
     71                          int scroll_y,
     72                          const InProcessViewRenderer::RenderMethod& renderer) {
     73   DCHECK(jbitmap.obj());
     74 
     75   AndroidBitmapInfo bitmap_info;
     76   if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
     77     LOG(ERROR) << "Error getting java bitmap info.";
     78     return false;
     79   }
     80 
     81   void* pixels = NULL;
     82   if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
     83     LOG(ERROR) << "Error locking java bitmap pixels.";
     84     return false;
     85   }
     86 
     87   bool succeeded;
     88   {
     89     SkBitmap bitmap;
     90     bitmap.setConfig(SkBitmap::kARGB_8888_Config,
     91                      bitmap_info.width,
     92                      bitmap_info.height,
     93                      bitmap_info.stride);
     94     bitmap.setPixels(pixels);
     95 
     96     SkDevice device(bitmap);
     97     SkCanvas canvas(&device);
     98     canvas.translate(-scroll_x, -scroll_y);
     99     succeeded = renderer.Run(&canvas);
    100   }
    101 
    102   if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) {
    103     LOG(ERROR) << "Error unlocking java bitmap pixels.";
    104     return false;
    105   }
    106 
    107   return succeeded;
    108 }
    109 
    110 bool RenderPictureToCanvas(SkPicture* picture, SkCanvas* canvas) {
    111   canvas->drawPicture(*picture);
    112   return true;
    113 }
    114 
    115 class ScopedPixelAccess {
    116  public:
    117   ScopedPixelAccess(JNIEnv* env, jobject java_canvas) {
    118     AwDrawSWFunctionTable* sw_functions =
    119         BrowserViewRenderer::GetAwDrawSWFunctionTable();
    120     pixels_ = sw_functions ?
    121       sw_functions->access_pixels(env, java_canvas) : NULL;
    122   }
    123   ~ScopedPixelAccess() {
    124     if (pixels_)
    125       BrowserViewRenderer::GetAwDrawSWFunctionTable()->release_pixels(pixels_);
    126   }
    127   AwPixelInfo* pixels() { return pixels_; }
    128 
    129  private:
    130   AwPixelInfo* pixels_;
    131 
    132   DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess);
    133 };
    134 
    135 bool HardwareEnabled() {
    136   static bool g_hw_enabled = !CommandLine::ForCurrentProcess()->HasSwitch(
    137       switches::kDisableWebViewGLMode);
    138   return g_hw_enabled;
    139 }
    140 
    141 // Provides software rendering functions from the Android glue layer.
    142 // Allows preventing extra copies of data when rendering.
    143 AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
    144 
    145 const int64 kFallbackTickTimeoutInMilliseconds = 20;
    146 
    147 
    148 // Used to calculate memory and resource allocation. Determined experimentally.
    149 size_t g_memory_multiplier = 10;
    150 size_t g_num_gralloc_limit = 150;
    151 const size_t kBytesPerPixel = 4;
    152 const size_t kMemoryAllocationStep = 5 * 1024 * 1024;
    153 
    154 class ScopedAllowGL {
    155  public:
    156   ScopedAllowGL();
    157   ~ScopedAllowGL();
    158 
    159   static bool IsAllowed() {
    160     return BrowserThread::CurrentlyOn(BrowserThread::UI) && allow_gl;
    161   }
    162 
    163  private:
    164   static bool allow_gl;
    165 
    166   DISALLOW_COPY_AND_ASSIGN(ScopedAllowGL);
    167 };
    168 
    169 ScopedAllowGL::ScopedAllowGL() {
    170   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    171   DCHECK(!allow_gl);
    172   allow_gl = true;
    173 }
    174 
    175 ScopedAllowGL::~ScopedAllowGL() {
    176   allow_gl = false;
    177 }
    178 
    179 bool ScopedAllowGL::allow_gl = false;
    180 
    181 base::LazyInstance<GLViewRendererManager>::Leaky g_view_renderer_manager;
    182 
    183 void RequestProcessGLOnUIThread() {
    184   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    185     BrowserThread::PostTask(
    186         BrowserThread::UI, FROM_HERE, base::Bind(&RequestProcessGLOnUIThread));
    187     return;
    188   }
    189 
    190   InProcessViewRenderer* renderer = static_cast<InProcessViewRenderer*>(
    191       g_view_renderer_manager.Get().GetMostRecentlyDrawn());
    192   if (!renderer || !renderer->RequestProcessGL()) {
    193     LOG(ERROR) << "Failed to request GL process. Deadlock likely: "
    194                << !!renderer;
    195   }
    196 }
    197 
    198 }  // namespace
    199 
    200 // Called from different threads!
    201 static void ScheduleGpuWork() {
    202   if (ScopedAllowGL::IsAllowed()) {
    203     gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
    204   } else {
    205     RequestProcessGLOnUIThread();
    206   }
    207 }
    208 
    209 // static
    210 void BrowserViewRenderer::SetAwDrawSWFunctionTable(
    211     AwDrawSWFunctionTable* table) {
    212   g_sw_draw_functions = table;
    213   gpu::InProcessCommandBuffer::SetScheduleCallback(
    214       base::Bind(&ScheduleGpuWork));
    215 }
    216 
    217 // static
    218 AwDrawSWFunctionTable* BrowserViewRenderer::GetAwDrawSWFunctionTable() {
    219   return g_sw_draw_functions;
    220 }
    221 
    222 InProcessViewRenderer::InProcessViewRenderer(
    223     BrowserViewRenderer::Client* client,
    224     JavaHelper* java_helper,
    225     content::WebContents* web_contents)
    226     : client_(client),
    227       java_helper_(java_helper),
    228       web_contents_(web_contents),
    229       compositor_(NULL),
    230       is_paused_(false),
    231       view_visible_(false),
    232       window_visible_(false),
    233       attached_to_window_(false),
    234       dip_scale_(0.0),
    235       page_scale_factor_(1.0),
    236       on_new_picture_enable_(false),
    237       compositor_needs_continuous_invalidate_(false),
    238       block_invalidates_(false),
    239       width_(0),
    240       height_(0),
    241       hardware_initialized_(false),
    242       hardware_failed_(false),
    243       last_egl_context_(NULL),
    244       manager_key_(g_view_renderer_manager.Get().NullKey()) {
    245   CHECK(web_contents_);
    246   web_contents_->SetUserData(kUserDataKey, new UserData(this));
    247   content::SynchronousCompositor::SetClientForWebContents(web_contents_, this);
    248 
    249   // Currently the logic in this class relies on |compositor_| remaining NULL
    250   // until the DidInitializeCompositor() call, hence it is not set here.
    251 }
    252 
    253 InProcessViewRenderer::~InProcessViewRenderer() {
    254   CHECK(web_contents_);
    255   content::SynchronousCompositor::SetClientForWebContents(web_contents_, NULL);
    256   web_contents_->SetUserData(kUserDataKey, NULL);
    257   NoLongerExpectsDrawGL();
    258   DCHECK(web_contents_ == NULL);  // WebContentsGone should have been called.
    259 }
    260 
    261 
    262 // TODO(boliu): Should also call this when we know for sure we are no longer,
    263 // for example, when visible rect becomes 0.
    264 void InProcessViewRenderer::NoLongerExpectsDrawGL() {
    265   GLViewRendererManager& mru = g_view_renderer_manager.Get();
    266   if (manager_key_ != mru.NullKey()) {
    267     mru.NoLongerExpectsDrawGL(manager_key_);
    268     manager_key_ = mru.NullKey();
    269 
    270     // TODO(boliu): If this is the first one and there are GL pending,
    271     // requestDrawGL on next one.
    272     // TODO(boliu): If this is the last one, lose all global contexts.
    273   }
    274 }
    275 
    276 // static
    277 InProcessViewRenderer* InProcessViewRenderer::FromWebContents(
    278     content::WebContents* contents) {
    279   return UserData::GetInstance(contents);
    280 }
    281 
    282 void InProcessViewRenderer::WebContentsGone() {
    283   web_contents_ = NULL;
    284   compositor_ = NULL;
    285 }
    286 
    287 // static
    288 void InProcessViewRenderer::CalculateTileMemoryPolicy() {
    289   CommandLine* cl = CommandLine::ForCurrentProcess();
    290   if (cl->HasSwitch(switches::kTileMemoryMultiplier)) {
    291     std::string string_value =
    292         cl->GetSwitchValueASCII(switches::kTileMemoryMultiplier);
    293     int int_value = 0;
    294     if (base::StringToInt(string_value, &int_value) &&
    295         int_value >= 2 && int_value <= 50) {
    296       g_memory_multiplier = int_value;
    297     }
    298   }
    299 
    300   if (cl->HasSwitch(switches::kNumGrallocBuffersPerWebview)) {
    301     std::string string_value =
    302         cl->GetSwitchValueASCII(switches::kNumGrallocBuffersPerWebview);
    303     int int_value = 0;
    304     if (base::StringToInt(string_value, &int_value) &&
    305         int_value >= 50 && int_value <= 500) {
    306       g_num_gralloc_limit = int_value;
    307     }
    308   }
    309 
    310   const char kDefaultTileSize[] = "384";
    311   if (!cl->HasSwitch(switches::kDefaultTileWidth))
    312     cl->AppendSwitchASCII(switches::kDefaultTileWidth, kDefaultTileSize);
    313 
    314   if (!cl->HasSwitch(switches::kDefaultTileHeight))
    315     cl->AppendSwitchASCII(switches::kDefaultTileHeight, kDefaultTileSize);
    316 }
    317 
    318 bool InProcessViewRenderer::RequestProcessGL() {
    319   return client_->RequestDrawGL(NULL);
    320 }
    321 
    322 void InProcessViewRenderer::TrimMemory(int level) {
    323   // Constants from Android ComponentCallbacks2.
    324   enum {
    325     TRIM_MEMORY_RUNNING_LOW = 10,
    326     TRIM_MEMORY_UI_HIDDEN = 20,
    327     TRIM_MEMORY_BACKGROUND = 40,
    328   };
    329 
    330   // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because
    331   // it does not indicate memory pressure, but merely that the app is
    332   // backgrounded.
    333   if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN)
    334     return;
    335 
    336   // Nothing to drop.
    337   if (!attached_to_window_ || !hardware_initialized_ || !compositor_)
    338     return;
    339 
    340   // Do not release resources on view we expect to get DrawGL soon.
    341   if (level < TRIM_MEMORY_BACKGROUND) {
    342     client_->UpdateGlobalVisibleRect();
    343     if (view_visible_ && window_visible_ &&
    344         !cached_global_visible_rect_.IsEmpty()) {
    345       return;
    346     }
    347   }
    348 
    349   if (!eglGetCurrentContext()) {
    350     NOTREACHED();
    351     return;
    352   }
    353 
    354   // Just set the memory limit to 0 and drop all tiles. This will be reset to
    355   // normal levels in the next DrawGL call.
    356   content::SynchronousCompositorMemoryPolicy policy;
    357   policy.bytes_limit = 0;
    358   policy.num_resources_limit = 0;
    359   if (memory_policy_ == policy)
    360     return;
    361 
    362   TRACE_EVENT0("android_webview", "InProcessViewRenderer::TrimMemory");
    363   ScopedAppGLStateRestore state_restore(
    364       ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
    365   gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
    366   ScopedAllowGL allow_gl;
    367 
    368   SetMemoryPolicy(policy);
    369   ForceFakeCompositeSW();
    370 }
    371 
    372 void InProcessViewRenderer::SetMemoryPolicy(
    373     content::SynchronousCompositorMemoryPolicy& new_policy) {
    374   if (memory_policy_ == new_policy)
    375     return;
    376 
    377   memory_policy_ = new_policy;
    378   compositor_->SetMemoryPolicy(memory_policy_);
    379 }
    380 
    381 void InProcessViewRenderer::UpdateCachedGlobalVisibleRect() {
    382   client_->UpdateGlobalVisibleRect();
    383 }
    384 
    385 bool InProcessViewRenderer::OnDraw(jobject java_canvas,
    386                                    bool is_hardware_canvas,
    387                                    const gfx::Vector2d& scroll,
    388                                    const gfx::Rect& clip) {
    389   scroll_at_start_of_frame_  = scroll;
    390   if (is_hardware_canvas && attached_to_window_ && HardwareEnabled()) {
    391     // We should be performing a hardware draw here. If we don't have the
    392     // comositor yet or if RequestDrawGL fails, it means we failed this draw and
    393     // thus return false here to clear to background color for this draw.
    394     return compositor_ && client_->RequestDrawGL(java_canvas);
    395   }
    396   // Perform a software draw
    397   return DrawSWInternal(java_canvas, clip);
    398 }
    399 
    400 bool InProcessViewRenderer::InitializeHwDraw() {
    401   TRACE_EVENT0("android_webview", "InitializeHwDraw");
    402   DCHECK(!gl_surface_);
    403   gl_surface_  = new AwGLSurface;
    404   hardware_failed_ = !compositor_->InitializeHwDraw(gl_surface_);
    405   hardware_initialized_ = true;
    406 
    407   if (hardware_failed_)
    408     gl_surface_ = NULL;
    409 
    410   return !hardware_failed_;
    411 }
    412 
    413 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
    414   TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
    415 
    416   manager_key_ = g_view_renderer_manager.Get().DidDrawGL(manager_key_, this);
    417 
    418   // We need to watch if the current Android context has changed and enforce
    419   // a clean-up in the compositor.
    420   EGLContext current_context = eglGetCurrentContext();
    421   if (!current_context) {
    422     TRACE_EVENT_INSTANT0(
    423         "android_webview", "EarlyOut_NullEGLContext", TRACE_EVENT_SCOPE_THREAD);
    424     return;
    425   }
    426 
    427   ScopedAppGLStateRestore state_restore(ScopedAppGLStateRestore::MODE_DRAW);
    428   gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
    429   ScopedAllowGL allow_gl;
    430 
    431   if (!attached_to_window_) {
    432     TRACE_EVENT_INSTANT0(
    433         "android_webview", "EarlyOut_NotAttached", TRACE_EVENT_SCOPE_THREAD);
    434     return;
    435   }
    436 
    437   if (draw_info->mode == AwDrawGLInfo::kModeProcess) {
    438     TRACE_EVENT_INSTANT0(
    439         "android_webview", "EarlyOut_ModeProcess", TRACE_EVENT_SCOPE_THREAD);
    440     return;
    441   }
    442 
    443   if (compositor_ && !hardware_initialized_) {
    444     if (InitializeHwDraw()) {
    445       last_egl_context_ = current_context;
    446     } else {
    447       TRACE_EVENT_INSTANT0(
    448           "android_webview", "EarlyOut_HwInitFail", TRACE_EVENT_SCOPE_THREAD);
    449       LOG(ERROR) << "WebView hardware initialization failed";
    450       return;
    451     }
    452   }
    453 
    454   UpdateCachedGlobalVisibleRect();
    455   if (cached_global_visible_rect_.IsEmpty()) {
    456     TRACE_EVENT_INSTANT0("android_webview",
    457                          "EarlyOut_EmptyVisibleRect",
    458                          TRACE_EVENT_SCOPE_THREAD);
    459     return;
    460   }
    461 
    462   if (last_egl_context_ != current_context) {
    463     // TODO(boliu): Handle context lost
    464     TRACE_EVENT_INSTANT0(
    465         "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD);
    466   }
    467 
    468   if (!compositor_) {
    469     TRACE_EVENT_INSTANT0(
    470         "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
    471     return;
    472   }
    473 
    474   // DrawGL may be called without OnDraw, so cancel |fallback_tick_| here as
    475   // well just to be safe.
    476   fallback_tick_.Cancel();
    477 
    478   // Update memory budget. This will no-op in compositor if the policy has not
    479   // changed since last draw.
    480   content::SynchronousCompositorMemoryPolicy policy;
    481   policy.bytes_limit = g_memory_multiplier * kBytesPerPixel *
    482                        cached_global_visible_rect_.width() *
    483                        cached_global_visible_rect_.height();
    484   // Round up to a multiple of kMemoryAllocationStep.
    485   policy.bytes_limit =
    486       (policy.bytes_limit / kMemoryAllocationStep + 1) * kMemoryAllocationStep;
    487   policy.num_resources_limit = g_num_gralloc_limit;
    488   SetMemoryPolicy(policy);
    489 
    490   DCHECK(gl_surface_);
    491   gl_surface_->SetBackingFrameBufferObject(
    492       state_restore.framebuffer_binding_ext());
    493 
    494   gfx::Transform transform;
    495   transform.matrix().setColMajorf(draw_info->transform);
    496   transform.Translate(scroll_at_start_of_frame_.x(),
    497                       scroll_at_start_of_frame_.y());
    498   gfx::Rect clip_rect(draw_info->clip_left,
    499                       draw_info->clip_top,
    500                       draw_info->clip_right - draw_info->clip_left,
    501                       draw_info->clip_bottom - draw_info->clip_top);
    502 
    503   // Assume we always draw the full visible rect if we are drawing into a layer.
    504   bool drew_full_visible_rect = true;
    505 
    506   gfx::Rect viewport_rect;
    507   if (!draw_info->is_layer) {
    508     viewport_rect = cached_global_visible_rect_;
    509     clip_rect.Intersect(viewport_rect);
    510     drew_full_visible_rect = clip_rect.Contains(viewport_rect);
    511   } else {
    512     viewport_rect = clip_rect;
    513   }
    514 
    515   block_invalidates_ = true;
    516   // TODO(joth): Check return value.
    517   compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height),
    518                             transform,
    519                             viewport_rect,
    520                             clip_rect,
    521                             state_restore.stencil_enabled());
    522   block_invalidates_ = false;
    523   gl_surface_->ResetBackingFrameBufferObject();
    524 
    525   EnsureContinuousInvalidation(draw_info, !drew_full_visible_rect);
    526 }
    527 
    528 void InProcessViewRenderer::SetGlobalVisibleRect(
    529     const gfx::Rect& visible_rect) {
    530   cached_global_visible_rect_ = visible_rect;
    531 }
    532 
    533 bool InProcessViewRenderer::DrawSWInternal(jobject java_canvas,
    534                                            const gfx::Rect& clip) {
    535   if (clip.IsEmpty()) {
    536     TRACE_EVENT_INSTANT0(
    537         "android_webview", "EarlyOut_EmptyClip", TRACE_EVENT_SCOPE_THREAD);
    538     return true;
    539   }
    540 
    541   if (!compositor_) {
    542     TRACE_EVENT_INSTANT0(
    543         "android_webview", "EarlyOut_NoCompositor", TRACE_EVENT_SCOPE_THREAD);
    544     return false;
    545   }
    546 
    547   return RenderViaAuxilaryBitmapIfNeeded(
    548       java_canvas,
    549       java_helper_,
    550       scroll_at_start_of_frame_,
    551       clip,
    552       base::Bind(&InProcessViewRenderer::CompositeSW,
    553                  base::Unretained(this)),
    554       web_contents_);
    555 }
    556 
    557 // static
    558 bool InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded(
    559       jobject java_canvas,
    560       BrowserViewRenderer::JavaHelper* java_helper,
    561       const gfx::Vector2d& scroll_correction,
    562       const gfx::Rect& clip,
    563       InProcessViewRenderer::RenderMethod render_source,
    564       void* owner_key) {
    565   TRACE_EVENT0("android_webview",
    566                "InProcessViewRenderer::RenderViaAuxilaryBitmapIfNeeded");
    567 
    568   JNIEnv* env = AttachCurrentThread();
    569   ScopedPixelAccess auto_release_pixels(env, java_canvas);
    570   AwPixelInfo* pixels = auto_release_pixels.pixels();
    571   if (pixels && pixels->state) {
    572     skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(
    573         SkCanvasStateUtils::CreateFromCanvasState(pixels->state));
    574 
    575     // Workarounds for http://crbug.com/271096: SW draw only supports
    576     // translate & scale transforms, and a simple rectangular clip.
    577     if (canvas && (!canvas->getTotalClip().isRect() ||
    578           (canvas->getTotalMatrix().getType() &
    579            ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)))) {
    580       canvas.clear();
    581     }
    582     if (canvas) {
    583       canvas->translate(scroll_correction.x(), scroll_correction.y());
    584       return render_source.Run(canvas.get());
    585     }
    586   }
    587 
    588   // Render into an auxiliary bitmap if pixel info is not available.
    589   ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
    590   TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
    591   ScopedJavaLocalRef<jobject> jbitmap(java_helper->CreateBitmap(
    592       env, clip.width(), clip.height(), jcanvas, owner_key));
    593   if (!jbitmap.obj()) {
    594     TRACE_EVENT_INSTANT0("android_webview",
    595                          "EarlyOut_BitmapAllocFail",
    596                          TRACE_EVENT_SCOPE_THREAD);
    597     return false;
    598   }
    599 
    600   if (!RasterizeIntoBitmap(env, jbitmap,
    601                            clip.x() - scroll_correction.x(),
    602                            clip.y() - scroll_correction.y(),
    603                            render_source)) {
    604     TRACE_EVENT_INSTANT0("android_webview",
    605                          "EarlyOut_RasterizeFail",
    606                          TRACE_EVENT_SCOPE_THREAD);
    607     return false;
    608   }
    609 
    610   java_helper->DrawBitmapIntoCanvas(env, jbitmap, jcanvas,
    611                                     clip.x(), clip.y());
    612   return true;
    613 }
    614 
    615 skia::RefPtr<SkPicture> InProcessViewRenderer::CapturePicture(int width,
    616                                                               int height) {
    617   TRACE_EVENT0("android_webview", "InProcessViewRenderer::CapturePicture");
    618 
    619   // Return empty Picture objects for empty SkPictures.
    620   skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
    621   if (width <= 0 || height <= 0) {
    622     return picture;
    623   }
    624 
    625   // Reset scroll back to the origin, will go back to the old
    626   // value when scroll_reset is out of scope.
    627   base::AutoReset<gfx::Vector2dF> scroll_reset(&scroll_offset_dip_,
    628                                                gfx::Vector2d());
    629 
    630   SkCanvas* rec_canvas = picture->beginRecording(width, height, 0);
    631   if (compositor_)
    632     CompositeSW(rec_canvas);
    633   picture->endRecording();
    634   return picture;
    635 }
    636 
    637 void InProcessViewRenderer::EnableOnNewPicture(bool enabled) {
    638   on_new_picture_enable_ = enabled;
    639   EnsureContinuousInvalidation(NULL, false);
    640 }
    641 
    642 void InProcessViewRenderer::SetIsPaused(bool paused) {
    643   TRACE_EVENT_INSTANT1("android_webview",
    644                        "InProcessViewRenderer::SetIsPaused",
    645                        TRACE_EVENT_SCOPE_THREAD,
    646                        "paused",
    647                        paused);
    648   is_paused_ = paused;
    649   EnsureContinuousInvalidation(NULL, false);
    650 }
    651 
    652 void InProcessViewRenderer::SetViewVisibility(bool view_visible) {
    653   TRACE_EVENT_INSTANT1("android_webview",
    654                        "InProcessViewRenderer::SetViewVisibility",
    655                        TRACE_EVENT_SCOPE_THREAD,
    656                        "view_visible",
    657                        view_visible);
    658   view_visible_ = view_visible;
    659 }
    660 
    661 void InProcessViewRenderer::SetWindowVisibility(bool window_visible) {
    662   TRACE_EVENT_INSTANT1("android_webview",
    663                        "InProcessViewRenderer::SetWindowVisibility",
    664                        TRACE_EVENT_SCOPE_THREAD,
    665                        "window_visible",
    666                        window_visible);
    667   window_visible_ = window_visible;
    668   EnsureContinuousInvalidation(NULL, false);
    669 }
    670 
    671 void InProcessViewRenderer::OnSizeChanged(int width, int height) {
    672   TRACE_EVENT_INSTANT2("android_webview",
    673                        "InProcessViewRenderer::OnSizeChanged",
    674                        TRACE_EVENT_SCOPE_THREAD,
    675                        "width",
    676                        width,
    677                        "height",
    678                        height);
    679   width_ = width;
    680   height_ = height;
    681 }
    682 
    683 void InProcessViewRenderer::OnAttachedToWindow(int width, int height) {
    684   TRACE_EVENT2("android_webview",
    685                "InProcessViewRenderer::OnAttachedToWindow",
    686                "width",
    687                width,
    688                "height",
    689                height);
    690   attached_to_window_ = true;
    691   width_ = width;
    692   height_ = height;
    693 }
    694 
    695 void InProcessViewRenderer::OnDetachedFromWindow() {
    696   TRACE_EVENT0("android_webview",
    697                "InProcessViewRenderer::OnDetachedFromWindow");
    698 
    699   NoLongerExpectsDrawGL();
    700   if (hardware_initialized_) {
    701     DCHECK(compositor_);
    702 
    703     ScopedAppGLStateRestore state_restore(
    704         ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT);
    705     gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
    706     ScopedAllowGL allow_gl;
    707     compositor_->ReleaseHwDraw();
    708     hardware_initialized_ = false;
    709   }
    710 
    711   gl_surface_ = NULL;
    712   attached_to_window_ = false;
    713 }
    714 
    715 bool InProcessViewRenderer::IsAttachedToWindow() {
    716   return attached_to_window_;
    717 }
    718 
    719 bool InProcessViewRenderer::IsVisible() {
    720   // Ignore |window_visible_| if |attached_to_window_| is false.
    721   return view_visible_ && (!attached_to_window_ || window_visible_);
    722 }
    723 
    724 gfx::Rect InProcessViewRenderer::GetScreenRect() {
    725   return gfx::Rect(client_->GetLocationOnScreen(), gfx::Size(width_, height_));
    726 }
    727 
    728 void InProcessViewRenderer::DidInitializeCompositor(
    729     content::SynchronousCompositor* compositor) {
    730   TRACE_EVENT0("android_webview",
    731                "InProcessViewRenderer::DidInitializeCompositor");
    732   DCHECK(compositor && compositor_ == NULL);
    733   compositor_ = compositor;
    734   hardware_initialized_ = false;
    735   hardware_failed_ = false;
    736 }
    737 
    738 void InProcessViewRenderer::DidDestroyCompositor(
    739     content::SynchronousCompositor* compositor) {
    740   TRACE_EVENT0("android_webview",
    741                "InProcessViewRenderer::DidDestroyCompositor");
    742   DCHECK(compositor_ == compositor);
    743 
    744   // This can fail if Apps call destroy while the webview is still attached
    745   // to the view tree. This is an illegal operation that will lead to leaks.
    746   // Log for now. Consider a proper fix if this becomes a problem.
    747   LOG_IF(ERROR, hardware_initialized_)
    748       << "Destroy called before OnDetachedFromWindow. May Leak GL resources";
    749   compositor_ = NULL;
    750 }
    751 
    752 void InProcessViewRenderer::SetContinuousInvalidate(bool invalidate) {
    753   if (compositor_needs_continuous_invalidate_ == invalidate)
    754     return;
    755 
    756   TRACE_EVENT_INSTANT1("android_webview",
    757                        "InProcessViewRenderer::SetContinuousInvalidate",
    758                        TRACE_EVENT_SCOPE_THREAD,
    759                        "invalidate",
    760                        invalidate);
    761   compositor_needs_continuous_invalidate_ = invalidate;
    762   EnsureContinuousInvalidation(NULL, false);
    763 }
    764 
    765 void InProcessViewRenderer::SetDipScale(float dip_scale) {
    766   dip_scale_ = dip_scale;
    767   CHECK(dip_scale_ > 0);
    768 }
    769 
    770 gfx::Vector2d InProcessViewRenderer::max_scroll_offset() const {
    771   DCHECK_GT(dip_scale_, 0);
    772   return gfx::ToCeiledVector2d(gfx::ScaleVector2d(
    773       max_scroll_offset_dip_, dip_scale_ * page_scale_factor_));
    774 }
    775 
    776 void InProcessViewRenderer::ScrollTo(gfx::Vector2d scroll_offset) {
    777   gfx::Vector2d max_offset = max_scroll_offset();
    778   gfx::Vector2dF scroll_offset_dip;
    779   // To preserve the invariant that scrolling to the maximum physical pixel
    780   // value also scrolls to the maximum dip pixel value we transform the physical
    781   // offset into the dip offset by using a proportion (instead of dividing by
    782   // dip_scale * page_scale_factor).
    783   if (max_offset.x()) {
    784     scroll_offset_dip.set_x((scroll_offset.x() * max_scroll_offset_dip_.x()) /
    785                             max_offset.x());
    786   }
    787   if (max_offset.y()) {
    788     scroll_offset_dip.set_y((scroll_offset.y() * max_scroll_offset_dip_.y()) /
    789                             max_offset.y());
    790   }
    791 
    792   DCHECK_LE(0, scroll_offset_dip.x());
    793   DCHECK_LE(0, scroll_offset_dip.y());
    794   DCHECK_LE(scroll_offset_dip.x(), max_scroll_offset_dip_.x());
    795   DCHECK_LE(scroll_offset_dip.y(), max_scroll_offset_dip_.y());
    796 
    797   if (scroll_offset_dip_ == scroll_offset_dip)
    798     return;
    799 
    800   scroll_offset_dip_ = scroll_offset_dip;
    801 
    802   if (compositor_)
    803     compositor_->DidChangeRootLayerScrollOffset();
    804 }
    805 
    806 void InProcessViewRenderer::DidUpdateContent() {
    807   if (on_new_picture_enable_)
    808     client_->OnNewPicture();
    809 }
    810 
    811 void InProcessViewRenderer::SetMaxRootLayerScrollOffset(
    812     gfx::Vector2dF new_value_dip) {
    813   DCHECK_GT(dip_scale_, 0);
    814 
    815   max_scroll_offset_dip_ = new_value_dip;
    816   DCHECK_LE(0, max_scroll_offset_dip_.x());
    817   DCHECK_LE(0, max_scroll_offset_dip_.y());
    818 
    819   client_->SetMaxContainerViewScrollOffset(max_scroll_offset());
    820 }
    821 
    822 void InProcessViewRenderer::SetTotalRootLayerScrollOffset(
    823     gfx::Vector2dF scroll_offset_dip) {
    824   // TOOD(mkosiba): Add a DCHECK to say that this does _not_ get called during
    825   // DrawGl when http://crbug.com/249972 is fixed.
    826   if (scroll_offset_dip_ == scroll_offset_dip)
    827     return;
    828 
    829   scroll_offset_dip_ = scroll_offset_dip;
    830 
    831   gfx::Vector2d max_offset = max_scroll_offset();
    832   gfx::Vector2d scroll_offset;
    833   // For an explanation as to why this is done this way see the comment in
    834   // InProcessViewRenderer::ScrollTo.
    835   if (max_scroll_offset_dip_.x()) {
    836     scroll_offset.set_x((scroll_offset_dip.x() * max_offset.x()) /
    837                         max_scroll_offset_dip_.x());
    838   }
    839 
    840   if (max_scroll_offset_dip_.y()) {
    841     scroll_offset.set_y((scroll_offset_dip.y() * max_offset.y()) /
    842                         max_scroll_offset_dip_.y());
    843   }
    844 
    845   DCHECK(0 <= scroll_offset.x());
    846   DCHECK(0 <= scroll_offset.y());
    847   DCHECK(scroll_offset.x() <= max_offset.x());
    848   DCHECK(scroll_offset.y() <= max_offset.y());
    849 
    850   client_->ScrollContainerViewTo(scroll_offset);
    851 }
    852 
    853 gfx::Vector2dF InProcessViewRenderer::GetTotalRootLayerScrollOffset() {
    854   return scroll_offset_dip_;
    855 }
    856 
    857 bool InProcessViewRenderer::IsExternalFlingActive() const {
    858   return client_->IsFlingActive();
    859 }
    860 
    861 void InProcessViewRenderer::SetRootLayerPageScaleFactor(
    862     float page_scale_factor) {
    863   page_scale_factor_ = page_scale_factor;
    864   DCHECK_GT(page_scale_factor_, 0);
    865   client_->SetPageScaleFactor(page_scale_factor);
    866 }
    867 
    868 void InProcessViewRenderer::SetRootLayerScrollableSize(
    869     gfx::SizeF scrollable_size) {
    870   client_->SetContentsSize(scrollable_size);
    871 }
    872 
    873 void InProcessViewRenderer::DidOverscroll(
    874     gfx::Vector2dF accumulated_overscroll,
    875     gfx::Vector2dF latest_overscroll_delta,
    876     gfx::Vector2dF current_fling_velocity) {
    877   DCHECK(current_fling_velocity.IsZero());
    878   const float physical_pixel_scale = dip_scale_ * page_scale_factor_;
    879   if (accumulated_overscroll == latest_overscroll_delta)
    880     overscroll_rounding_error_ = gfx::Vector2dF();
    881   gfx::Vector2dF scaled_overscroll_delta =
    882       gfx::ScaleVector2d(latest_overscroll_delta, physical_pixel_scale);
    883   gfx::Vector2d rounded_overscroll_delta = gfx::ToRoundedVector2d(
    884       scaled_overscroll_delta + overscroll_rounding_error_);
    885   overscroll_rounding_error_ =
    886       scaled_overscroll_delta - rounded_overscroll_delta;
    887   client_->DidOverscroll(rounded_overscroll_delta);
    888 }
    889 
    890 void InProcessViewRenderer::EnsureContinuousInvalidation(
    891     AwDrawGLInfo* draw_info,
    892     bool invalidate_ignore_compositor) {
    893   // This method should be called again when any of these conditions change.
    894   bool need_invalidate =
    895       compositor_needs_continuous_invalidate_ || invalidate_ignore_compositor;
    896   if (!need_invalidate || block_invalidates_)
    897     return;
    898 
    899   if (draw_info) {
    900     draw_info->dirty_left = cached_global_visible_rect_.x();
    901     draw_info->dirty_top = cached_global_visible_rect_.y();
    902     draw_info->dirty_right = cached_global_visible_rect_.right();
    903     draw_info->dirty_bottom = cached_global_visible_rect_.bottom();
    904     draw_info->status_mask |= AwDrawGLInfo::kStatusMaskDraw;
    905   } else {
    906     client_->PostInvalidate();
    907   }
    908 
    909   bool throttle_fallback_tick = (is_paused_ && !on_new_picture_enable_) ||
    910                                 (attached_to_window_ && !window_visible_);
    911   if (throttle_fallback_tick)
    912     return;
    913 
    914   block_invalidates_ = compositor_needs_continuous_invalidate_;
    915 
    916   // Unretained here is safe because the callback is cancelled when
    917   // |fallback_tick_| is destroyed.
    918   fallback_tick_.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired,
    919                                   base::Unretained(this)));
    920 
    921   // No need to reschedule fallback tick if compositor does not need to be
    922   // ticked. This can happen if this is reached because
    923   // invalidate_ignore_compositor is true.
    924   if (compositor_needs_continuous_invalidate_) {
    925     BrowserThread::PostDelayedTask(
    926         BrowserThread::UI,
    927         FROM_HERE,
    928         fallback_tick_.callback(),
    929         base::TimeDelta::FromMilliseconds(
    930             kFallbackTickTimeoutInMilliseconds));
    931   }
    932 }
    933 
    934 void InProcessViewRenderer::FallbackTickFired() {
    935   TRACE_EVENT1("android_webview",
    936                "InProcessViewRenderer::FallbackTickFired",
    937                "compositor_needs_continuous_invalidate_",
    938                compositor_needs_continuous_invalidate_);
    939 
    940   // This should only be called if OnDraw or DrawGL did not come in time, which
    941   // means block_invalidates_ must still be true.
    942   DCHECK(block_invalidates_);
    943   if (compositor_needs_continuous_invalidate_ && compositor_)
    944     ForceFakeCompositeSW();
    945 }
    946 
    947 void InProcessViewRenderer::ForceFakeCompositeSW() {
    948   DCHECK(compositor_);
    949   SkDevice device(SkBitmap::kARGB_8888_Config, 1, 1);
    950   SkCanvas canvas(&device);
    951   CompositeSW(&canvas);
    952 }
    953 
    954 bool InProcessViewRenderer::CompositeSW(SkCanvas* canvas) {
    955   DCHECK(compositor_);
    956 
    957   fallback_tick_.Cancel();
    958   block_invalidates_ = true;
    959   bool result = compositor_->DemandDrawSw(canvas);
    960   block_invalidates_ = false;
    961   EnsureContinuousInvalidation(NULL, false);
    962   return result;
    963 }
    964 
    965 std::string InProcessViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
    966   std::string str;
    967   base::StringAppendF(&str, "is_paused: %d ", is_paused_);
    968   base::StringAppendF(&str, "view_visible: %d ", view_visible_);
    969   base::StringAppendF(&str, "window_visible: %d ", window_visible_);
    970   base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
    971   base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
    972   base::StringAppendF(&str,
    973                       "compositor_needs_continuous_invalidate: %d ",
    974                       compositor_needs_continuous_invalidate_);
    975   base::StringAppendF(&str, "block_invalidates: %d ", block_invalidates_);
    976   base::StringAppendF(&str, "view width height: [%d %d] ", width_, height_);
    977   base::StringAppendF(&str, "attached_to_window: %d ", attached_to_window_);
    978   base::StringAppendF(&str, "hardware_initialized: %d ", hardware_initialized_);
    979   base::StringAppendF(&str, "hardware_failed: %d ", hardware_failed_);
    980   base::StringAppendF(&str,
    981                       "global visible rect: %s ",
    982                       cached_global_visible_rect_.ToString().c_str());
    983   base::StringAppendF(&str,
    984                       "scroll_at_start_of_frame: %s ",
    985                       scroll_at_start_of_frame_.ToString().c_str());
    986   base::StringAppendF(
    987       &str, "scroll_offset_dip: %s ", scroll_offset_dip_.ToString().c_str());
    988   base::StringAppendF(&str,
    989                       "overscroll_rounding_error_: %s ",
    990                       overscroll_rounding_error_.ToString().c_str());
    991   base::StringAppendF(
    992       &str, "on_new_picture_enable: %d ", on_new_picture_enable_);
    993   if (draw_info) {
    994     base::StringAppendF(&str,
    995                         "clip left top right bottom: [%d %d %d %d] ",
    996                         draw_info->clip_left,
    997                         draw_info->clip_top,
    998                         draw_info->clip_right,
    999                         draw_info->clip_bottom);
   1000     base::StringAppendF(&str,
   1001                         "surface width height: [%d %d] ",
   1002                         draw_info->width,
   1003                         draw_info->height);
   1004     base::StringAppendF(&str, "is_layer: %d ", draw_info->is_layer);
   1005   }
   1006   return str;
   1007 }
   1008 
   1009 }  // namespace android_webview
   1010