Home | History | Annotate | Download | only in native
      1 // Copyright (c) 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/native/java_browser_view_renderer_helper.h"
      6 
      7 #include <android/bitmap.h>
      8 
      9 #include "android_webview/public/browser/draw_sw.h"
     10 #include "base/debug/trace_event.h"
     11 #include "jni/JavaBrowserViewRendererHelper_jni.h"
     12 #include "third_party/skia/include/core/SkBitmap.h"
     13 #include "third_party/skia/include/utils/SkCanvasStateUtils.h"
     14 
     15 using base::android::JavaRef;
     16 using base::android::ScopedJavaLocalRef;
     17 
     18 namespace android_webview {
     19 
     20 namespace {
     21 
     22 // Provides software rendering functions from the Android glue layer.
     23 // Allows preventing extra copies of data when rendering.
     24 AwDrawSWFunctionTable* g_sw_draw_functions = NULL;
     25 
     26 class ScopedPixelAccess {
     27  public:
     28   ScopedPixelAccess(JNIEnv* env, jobject java_canvas) : pixels_(NULL) {
     29     if (g_sw_draw_functions)
     30       pixels_ = g_sw_draw_functions->access_pixels(env, java_canvas);
     31   }
     32 
     33   ~ScopedPixelAccess() {
     34     if (pixels_)
     35       g_sw_draw_functions->release_pixels(pixels_);
     36   }
     37 
     38   AwPixelInfo* pixels() { return pixels_; }
     39 
     40  private:
     41   AwPixelInfo* pixels_;
     42 
     43   DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedPixelAccess);
     44 };
     45 
     46 }  // namespace
     47 
     48 // static
     49 void JavaBrowserViewRendererHelper::SetAwDrawSWFunctionTable(
     50     AwDrawSWFunctionTable* table) {
     51   g_sw_draw_functions = table;
     52 }
     53 
     54 // static
     55 JavaBrowserViewRendererHelper* JavaBrowserViewRendererHelper::GetInstance() {
     56   static JavaBrowserViewRendererHelper* g_instance =
     57       new JavaBrowserViewRendererHelper;
     58   return g_instance;
     59 }
     60 
     61 // static
     62 BrowserViewRendererJavaHelper* BrowserViewRendererJavaHelper::GetInstance() {
     63   return JavaBrowserViewRendererHelper::GetInstance();
     64 }
     65 
     66 JavaBrowserViewRendererHelper::JavaBrowserViewRendererHelper() {}
     67 
     68 JavaBrowserViewRendererHelper::~JavaBrowserViewRendererHelper() {}
     69 
     70 bool JavaBrowserViewRendererHelper::RenderViaAuxilaryBitmapIfNeeded(
     71     jobject java_canvas,
     72     const gfx::Vector2d& scroll_correction,
     73     const gfx::Size& auxiliary_bitmap_size,
     74     RenderMethod render_source) {
     75   TRACE_EVENT0("android_webview", "RenderViaAuxilaryBitmapIfNeeded");
     76 
     77   JNIEnv* env = base::android::AttachCurrentThread();
     78   ScopedPixelAccess auto_release_pixels(env, java_canvas);
     79   AwPixelInfo* pixels = auto_release_pixels.pixels();
     80   if (pixels && pixels->state) {
     81     skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(
     82         SkCanvasStateUtils::CreateFromCanvasState(pixels->state));
     83 
     84     // Workarounds for http://crbug.com/271096: SW draw only supports
     85     // translate & scale transforms, and a simple rectangular clip.
     86     if (canvas && (!canvas->isClipRect() ||
     87                    (canvas->getTotalMatrix().getType() &
     88                     ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)))) {
     89       canvas.clear();
     90     }
     91     if (canvas) {
     92       canvas->translate(scroll_correction.x(), scroll_correction.y());
     93       return render_source.Run(canvas.get());
     94     }
     95   }
     96   return RenderViaAuxilaryBitmap(env,
     97                                  java_canvas,
     98                                  scroll_correction,
     99                                  auxiliary_bitmap_size,
    100                                  render_source);
    101 }
    102 
    103 bool JavaBrowserViewRendererHelper::RenderViaAuxilaryBitmap(
    104     JNIEnv* env,
    105     jobject java_canvas,
    106     const gfx::Vector2d& scroll_correction,
    107     const gfx::Size& auxiliary_bitmap_size,
    108     const RenderMethod& render_source) {
    109   // Render into an auxiliary bitmap if pixel info is not available.
    110   ScopedJavaLocalRef<jobject> jcanvas(env, java_canvas);
    111   TRACE_EVENT0("android_webview", "RenderToAuxBitmap");
    112 
    113   if (auxiliary_bitmap_size.width() <= 0 || auxiliary_bitmap_size.height() <= 0)
    114     return false;
    115 
    116   ScopedJavaLocalRef<jobject> jbitmap(
    117       Java_JavaBrowserViewRendererHelper_createBitmap(
    118           env,
    119           auxiliary_bitmap_size.width(),
    120           auxiliary_bitmap_size.height(),
    121           jcanvas.obj()));
    122   if (!jbitmap.obj())
    123     return false;
    124 
    125   if (!RasterizeIntoBitmap(env,
    126                            jbitmap,
    127                            render_source)) {
    128     return false;
    129   }
    130 
    131   Java_JavaBrowserViewRendererHelper_drawBitmapIntoCanvas(
    132       env,
    133       jbitmap.obj(),
    134       jcanvas.obj(),
    135       scroll_correction.x(),
    136       scroll_correction.y());
    137   return true;
    138 }
    139 
    140 bool RegisterJavaBrowserViewRendererHelper(JNIEnv* env) {
    141   return RegisterNativesImpl(env);
    142 }
    143 
    144 bool JavaBrowserViewRendererHelper::RasterizeIntoBitmap(
    145     JNIEnv* env,
    146     const JavaRef<jobject>& jbitmap,
    147     const JavaBrowserViewRendererHelper::RenderMethod& renderer) {
    148   DCHECK(jbitmap.obj());
    149 
    150   AndroidBitmapInfo bitmap_info;
    151   if (AndroidBitmap_getInfo(env, jbitmap.obj(), &bitmap_info) < 0) {
    152     LOG(ERROR) << "Error getting java bitmap info.";
    153     return false;
    154   }
    155 
    156   void* pixels = NULL;
    157   if (AndroidBitmap_lockPixels(env, jbitmap.obj(), &pixels) < 0) {
    158     LOG(ERROR) << "Error locking java bitmap pixels.";
    159     return false;
    160   }
    161 
    162   bool succeeded;
    163   {
    164     SkImageInfo info =
    165         SkImageInfo::MakeN32Premul(bitmap_info.width, bitmap_info.height);
    166     SkBitmap bitmap;
    167     bitmap.installPixels(info, pixels, bitmap_info.stride);
    168 
    169     SkCanvas canvas(bitmap);
    170     succeeded = renderer.Run(&canvas);
    171   }
    172 
    173   if (AndroidBitmap_unlockPixels(env, jbitmap.obj()) < 0) {
    174     LOG(ERROR) << "Error unlocking java bitmap pixels.";
    175     return false;
    176   }
    177 
    178   return succeeded;
    179 }
    180 
    181 }  // namespace android_webview
    182