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