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