graphics_utils.cpp revision a68073f3c0ef06b8a5c0a6c71cf33bc1f37664b9
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17// Provides a webviewchromium glue layer adapter from the internal Android 18// graphics types into the types the chromium stack expects, and back. 19 20#define LOG_TAG "webviewchromium_plat_support" 21 22#include "android_webview/public/browser/draw_gl.h" 23#include "android_webview/public/browser/draw_sw.h" 24 25#include <cstdlib> 26#include <jni.h> 27#include <UniquePtr.h> 28#include <utils/Log.h> 29#include <utils/Vector.h> 30#include "graphic_buffer_impl.h" 31#include "GraphicsJNI.h" 32#include "SkGraphics.h" 33#include "SkPicture.h" 34 35#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) 36 37namespace android { 38namespace { 39 40class PixelInfo : public AwPixelInfo { 41 public: 42 PixelInfo(SkCanvas* canvas, const SkBitmap* bitmap); 43 ~PixelInfo(); 44 45 void AddRectToClip(const SkIRect& rect); 46 47 private: 48 const SkBitmap* bitmap_; 49 SkAutoLockPixels bitmap_locker_; 50 Vector<int> clip_rect_storage_; 51}; 52 53class ClipValidator : public SkCanvas::ClipVisitor { 54 public: 55 ClipValidator() : failed_(false) {} 56 bool failed() { return failed_; } 57 58 // ClipVisitor 59 virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) { 60 failed_ |= antialias; 61 } 62 63 virtual void clipPath(const SkPath&, SkRegion::Op, bool antialias) { 64 failed_ |= antialias; 65 } 66 67 private: 68 bool failed_; 69}; 70 71PixelInfo::PixelInfo(SkCanvas* canvas, const SkBitmap* bitmap) 72 : bitmap_(bitmap), 73 bitmap_locker_(*bitmap) { 74 memset(this, 0, sizeof(AwPixelInfo)); 75 version = kAwPixelInfoVersion; 76} 77 78PixelInfo::~PixelInfo() {} 79 80void PixelInfo::AddRectToClip(const SkIRect& rect) { 81 ALOG_ASSERT(rect.width() >= 0 && rect.height() >= 0); 82 clip_rect_storage_.push_back(rect.x()); 83 clip_rect_storage_.push_back(rect.y()); 84 clip_rect_storage_.push_back(rect.width()); 85 clip_rect_storage_.push_back(rect.height()); 86 clip_rects = const_cast<int*>(clip_rect_storage_.array()); 87 clip_rect_count = clip_rect_storage_.size() / 4; 88} 89 90PixelInfo* TryToCreatePixelInfo(SkCanvas* canvas) { 91 // Check the clip can decompose into simple rectangles. This validator is 92 // not a perfect guarantee, but it's the closest I can do with the current 93 // API. TODO: compile this out in release builds as currently Java canvases 94 // do not allow for antialiased clip. 95 ClipValidator validator; 96 canvas->replayClips(&validator); 97 if (validator.failed()) 98 return NULL; 99 100 SkCanvas::LayerIter layer(SkCanvas::LayerIter(canvas, false)); 101 if (layer.done()) 102 return NULL; 103 SkDevice* device = layer.device(); 104 if (!device) 105 return NULL; 106 const SkBitmap* bitmap = &device->accessBitmap(true); 107 if (!bitmap->lockPixelsAreWritable()) 108 return NULL; 109 const SkRegion& region = layer.clip(); 110 layer.next(); 111 // Currently don't handle multiple layers well, so early out 112 // TODO: Return all layers in PixelInfo 113 if (!layer.done()) 114 return NULL; 115 116 UniquePtr<PixelInfo> pixels(new PixelInfo(canvas, bitmap)); 117 pixels->config = 118 bitmap->config() == SkBitmap::kARGB_8888_Config ? AwConfig_ARGB_8888 : 119 bitmap->config() == SkBitmap::kARGB_4444_Config ? AwConfig_ARGB_4444 : 120 bitmap->config() == SkBitmap::kRGB_565_Config ? AwConfig_RGB_565 : -1; 121 if (pixels->config < 0) 122 return NULL; 123 124 pixels->width = bitmap->width(); 125 pixels->height = bitmap->height(); 126 pixels->row_bytes = bitmap->rowBytes(); 127 pixels->pixels = bitmap->getPixels(); 128 const SkMatrix& matrix = layer.matrix(); 129 for (int i = 0; i < 9; i++) { 130 pixels->matrix[i] = matrix.get(i); 131 } 132 133 if (region.isEmpty()) { 134 pixels->AddRectToClip(region.getBounds()); 135 } else { 136 SkRegion::Iterator clip_iterator(region); 137 for (; !clip_iterator.done(); clip_iterator.next()) { 138 pixels->AddRectToClip(clip_iterator.rect()); 139 } 140 } 141 142 // WebViewClassic used the DrawFilter for its own purposes (e.g. disabling 143 // dithering when zooming/scrolling) so for now at least, just ignore any 144 // client supplied DrawFilter. 145 ALOGW_IF(canvas->getDrawFilter(), 146 "DrawFilter not supported in webviewchromium, will be ignored"); 147 return pixels.release(); 148} 149 150AwPixelInfo* GetPixels(JNIEnv* env, jobject java_canvas) { 151 SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, java_canvas); 152 if (!canvas) 153 return NULL; 154 155 return TryToCreatePixelInfo(canvas); 156} 157 158void ReleasePixels(AwPixelInfo* pixels) { 159 delete static_cast<PixelInfo*>(pixels); 160} 161 162jobject CreatePicture(JNIEnv* env, SkPicture* picture) { 163 jclass clazz = env->FindClass("android/graphics/Picture"); 164 jmethodID constructor = env->GetMethodID(clazz, "<init>", "(IZ)V"); 165 ALOG_ASSERT(clazz); 166 ALOG_ASSERT(constructor); 167 return env->NewObject(clazz, constructor, picture, false); 168} 169 170bool IsSkiaVersionCompatible(SkiaVersionFunction function) { 171 bool compatible = false; 172 if (function && function == &SkGraphics::GetVersion) { 173 int android_major, android_minor, android_patch; 174 SkGraphics::GetVersion(&android_major, &android_minor, &android_patch); 175 176 int chromium_major, chromium_minor, chromium_patch; 177 (*function)(&chromium_major, &chromium_minor, &chromium_patch); 178 179 compatible = android_major == chromium_major && 180 android_minor == chromium_minor && 181 android_patch == chromium_patch; 182 } 183 return compatible; 184} 185 186jint GetDrawSWFunctionTable(JNIEnv* env, jclass) { 187 static const AwDrawSWFunctionTable function_table = { 188 &GetPixels, 189 &ReleasePixels, 190 &CreatePicture, 191 &IsSkiaVersionCompatible, 192 }; 193 return reinterpret_cast<jint>(&function_table); 194} 195 196jint GetDrawGLFunctionTable(JNIEnv* env, jclass) { 197 static const AwDrawGLFunctionTable function_table = { 198 &GraphicBufferImpl::Create, 199 &GraphicBufferImpl::Release, 200 &GraphicBufferImpl::MapStatic, 201 &GraphicBufferImpl::UnmapStatic, 202 &GraphicBufferImpl::GetNativeBufferStatic, 203 &GraphicBufferImpl::GetStrideStatic, 204 }; 205 return reinterpret_cast<jint>(&function_table); 206} 207 208const char kClassName[] = "com/android/webview/chromium/GraphicsUtils"; 209const JNINativeMethod kJniMethods[] = { 210 { "nativeGetDrawSWFunctionTable", "()I", 211 reinterpret_cast<void*>(GetDrawSWFunctionTable) }, 212 { "nativeGetDrawGLFunctionTable", "()I", 213 reinterpret_cast<void*>(GetDrawGLFunctionTable) }, 214}; 215 216} // namespace 217 218void RegisterGraphicsUtils(JNIEnv* env) { 219 jclass clazz = env->FindClass(kClassName); 220 LOG_ALWAYS_FATAL_IF(!clazz, "Unable to find class '%s'", kClassName); 221 222 int res = env->RegisterNatives(clazz, kJniMethods, NELEM(kJniMethods)); 223 LOG_ALWAYS_FATAL_IF(res < 0, "register native methods failed: res=%d", res); 224} 225 226} // namespace android 227