diff options
Diffstat (limited to 'core/jni')
40 files changed, 2654 insertions, 1689 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index f446c3a..cb00062 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -57,7 +57,6 @@ LOCAL_SRC_FILES:= \ android_view_KeyEvent.cpp \ android_view_KeyCharacterMap.cpp \ android_view_GraphicBuffer.cpp \ - android_view_GLRenderer.cpp \ android_view_GLES20Canvas.cpp \ android_view_HardwareLayer.cpp \ android_view_ThreadedRenderer.cpp \ @@ -90,6 +89,7 @@ LOCAL_SRC_FILES:= \ android_util_Process.cpp \ android_util_StringBlock.cpp \ android_util_XmlBlock.cpp \ + android_graphics_Picture.cpp \ android/graphics/AutoDecodeCancel.cpp \ android/graphics/Bitmap.cpp \ android/graphics/BitmapFactory.cpp \ @@ -141,6 +141,7 @@ LOCAL_SRC_FILES:= \ android_hardware_camera2_DngCreator.cpp \ android_hardware_SensorManager.cpp \ android_hardware_SerialPort.cpp \ + android_hardware_SoundTrigger.cpp \ android_hardware_UsbDevice.cpp \ android_hardware_UsbDeviceConnection.cpp \ android_hardware_UsbRequest.cpp \ @@ -236,6 +237,7 @@ LOCAL_SHARED_LIBRARIES := \ libpdfium \ libimg_utils \ libnetd_client \ + libsoundtrigger ifeq ($(USE_OPENGL_RENDERER),true) LOCAL_SHARED_LIBRARIES += libhwui diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index e069876..598d6c1 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -29,7 +29,6 @@ #include <SkGraphics.h> #include <SkImageDecoder.h> -#include <SkImageRef_GlobalPool.h> #include "jni.h" #include "JNIHelp.h" @@ -83,6 +82,7 @@ extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *e extern int register_android_hardware_camera2_DngCreator(JNIEnv *env); extern int register_android_hardware_SensorManager(JNIEnv *env); extern int register_android_hardware_SerialPort(JNIEnv *env); +extern int register_android_hardware_SoundTrigger(JNIEnv *env); extern int register_android_hardware_UsbDevice(JNIEnv *env); extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env); extern int register_android_hardware_UsbRequest(JNIEnv *env); @@ -130,7 +130,6 @@ extern int register_android_view_RenderNode(JNIEnv* env); extern int register_android_view_RenderNodeAnimator(JNIEnv* env); extern int register_android_view_GraphicBuffer(JNIEnv* env); extern int register_android_view_GLES20Canvas(JNIEnv* env); -extern int register_android_view_GLRenderer(JNIEnv* env); extern int register_android_view_HardwareLayer(JNIEnv* env); extern int register_android_view_ThreadedRenderer(JNIEnv* env); extern int register_android_view_Surface(JNIEnv* env); @@ -160,6 +159,7 @@ extern int register_android_net_TrafficStats(JNIEnv* env); extern int register_android_text_AndroidCharacter(JNIEnv *env); extern int register_android_text_AndroidBidi(JNIEnv *env); extern int register_android_opengl_classes(JNIEnv *env); +extern int register_android_server_fingerprint_FingerprintService(JNIEnv* env); extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env); extern int register_android_server_Watchdog(JNIEnv* env); extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env); @@ -245,14 +245,6 @@ AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) mArgBlockLength(argBlockLength) { SkGraphics::Init(); - // this sets our preference for 16bit images during decode - // in case the src is opaque and 24bit - SkImageDecoder::SetDeviceConfig(SkBitmap::kRGB_565_Config); - // This cache is shared between browser native images, and java "purgeable" - // bitmaps. This globalpool is for images that do not either use the java - // heap, or are not backed by ashmem. See BitmapFactory.cpp for the key - // java call site. - SkImageRef_GlobalPool::SetRAMBudget(512 * 1024); // There is also a global font cache, but its budget is specified in code // see SkFontHost_android.cpp @@ -499,6 +491,8 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) char profile_duration[sizeof("-Xprofile-duration:") + PROPERTY_VALUE_MAX]; char profile_interval[sizeof("-Xprofile-interval:") + PROPERTY_VALUE_MAX]; char profile_backoff[sizeof("-Xprofile-backoff:") + PROPERTY_VALUE_MAX]; + char profile_top_k_threshold[sizeof("-Xprofile-top-k-threshold:") + PROPERTY_VALUE_MAX]; + char profile_top_k_change_threshold[sizeof("-Xprofile-top-k-change-threshold:") + PROPERTY_VALUE_MAX]; char langOption[sizeof("-Duser.language=") + 3]; char regionOption[sizeof("-Duser.region=") + 3]; char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:") + sizeof(propBuf)]; @@ -822,31 +816,65 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) * Set profiler options */ if (libart) { - // Number of seconds during profile runs. - strcpy(profile_period, "-Xprofile-period:"); - property_get("dalvik.vm.profile.period_secs", profile_period+17, "10"); - opt.optionString = profile_period; - mOptions.add(opt); + // Whether or not the profiler should be enabled. + property_get("dalvik.vm.profiler", propBuf, "0"); + if (propBuf[0] == '1') { + opt.optionString = "-Xenable-profiler"; + mOptions.add(opt); + } - // Length of each profile run (seconds). - strcpy(profile_duration, "-Xprofile-duration:"); - property_get("dalvik.vm.profile.duration_secs", profile_duration+19, "30"); - opt.optionString = profile_duration; - mOptions.add(opt); + // Whether the profile should start upon app startup or be delayed by some random offset + // (in seconds) that is bound between 0 and a fixed value. + property_get("dalvik.vm.profile.start-immed", propBuf, "0"); + if (propBuf[0] == '1') { + opt.optionString = "-Xprofile-start-immediately"; + mOptions.add(opt); + } + // Number of seconds during profile runs. + strcpy(profile_period, "-Xprofile-period:"); + if (property_get("dalvik.vm.profile.period-secs", profile_period+17, NULL) > 0) { + opt.optionString = profile_period; + mOptions.add(opt); + } - // Polling interval during profile run (microseconds). - strcpy(profile_interval, "-Xprofile-interval:"); - property_get("dalvik.vm.profile.interval_us", profile_interval+19, "10000"); - opt.optionString = profile_interval; - mOptions.add(opt); + // Length of each profile run (seconds). + strcpy(profile_duration, "-Xprofile-duration:"); + if (property_get("dalvik.vm.profile.duration-secs", profile_duration+19, NULL) > 0) { + opt.optionString = profile_duration; + mOptions.add(opt); + } - // Coefficient for period backoff. The the period is multiplied - // by this value after each profile run. - strcpy(profile_backoff, "-Xprofile-backoff:"); - property_get("dalvik.vm.profile.backoff_coeff", profile_backoff+18, "2.0"); - opt.optionString = profile_backoff; - mOptions.add(opt); + // Polling interval during profile run (microseconds). + strcpy(profile_interval, "-Xprofile-interval:"); + if (property_get("dalvik.vm.profile.interval-us", profile_interval+19, NULL) > 0) { + opt.optionString = profile_interval; + mOptions.add(opt); + } + + // Coefficient for period backoff. The the period is multiplied + // by this value after each profile run. + strcpy(profile_backoff, "-Xprofile-backoff:"); + if (property_get("dalvik.vm.profile.backoff-coeff", profile_backoff+18, NULL) > 0) { + opt.optionString = profile_backoff; + mOptions.add(opt); + } + + // Top K% of samples that are considered relevant when deciding if the app should be recompiled. + strcpy(profile_top_k_threshold, "-Xprofile-top-k-threshold:"); + if (property_get("dalvik.vm.profile.top-k-thr", profile_top_k_threshold+26, NULL) > 0) { + opt.optionString = profile_top_k_threshold; + mOptions.add(opt); + } + + // The threshold after which a change in the structure of the top K% profiled samples becomes significant + // and triggers recompilation. A change in profile is considered significant if X% (top-k-change-threshold) + // of the top K% (top-k-threshold property) samples has changed. + strcpy(profile_top_k_change_threshold, "-Xprofile-top-k-change-threshold:"); + if (property_get("dalvik.vm.profile.top-k-ch-thr", profile_top_k_change_threshold+33, NULL) > 0) { + opt.optionString = profile_top_k_change_threshold; + mOptions.add(opt); + } } initArgs.version = JNI_VERSION_1_4; @@ -1214,7 +1242,6 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_RenderNodeAnimator), REG_JNI(register_android_view_GraphicBuffer), REG_JNI(register_android_view_GLES20Canvas), - REG_JNI(register_android_view_GLRenderer), REG_JNI(register_android_view_HardwareLayer), REG_JNI(register_android_view_ThreadedRenderer), REG_JNI(register_android_view_Surface), @@ -1290,6 +1317,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_hardware_camera2_DngCreator), REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_hardware_SerialPort), + REG_JNI(register_android_hardware_SoundTrigger), REG_JNI(register_android_hardware_UsbDevice), REG_JNI(register_android_hardware_UsbDeviceConnection), REG_JNI(register_android_hardware_UsbRequest), @@ -1301,6 +1329,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_media_ToneGenerator), REG_JNI(register_android_opengl_classes), + REG_JNI(register_android_server_fingerprint_FingerprintService), REG_JNI(register_android_server_NetworkManagementSocketTagger), REG_JNI(register_android_server_Watchdog), REG_JNI(register_android_ddm_DdmHandleNativeHeap), diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 0328517..c139c9d 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -258,16 +258,16 @@ static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width, // can return NULL static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) { - switch (src.config()) { - case SkBitmap::kARGB_8888_Config: + switch (src.colorType()) { + case kN32_SkColorType: if (src.isOpaque()) return ToColor_S32_Opaque; return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw; - case SkBitmap::kARGB_4444_Config: + case kARGB_4444_SkColorType: if (src.isOpaque()) return ToColor_S4444_Opaque; return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw; - case SkBitmap::kRGB_565_Config: + case kRGB_565_SkColorType: return ToColor_S565; - case SkBitmap::kIndex8_Config: + case kIndex_8_SkColorType: if (src.getColorTable() == NULL) { return NULL; } @@ -291,7 +291,7 @@ static int getPremulBitmapCreateFlags(bool isMutable) { static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, jint offset, jint stride, jint width, jint height, jint configHandle, jboolean isMutable) { - SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle); + SkColorType colorType = SkBitmapConfigToColorType(static_cast<SkBitmap::Config>(configHandle)); if (NULL != jColors) { size_t n = env->GetArrayLength(jColors); if (n < SkAbs32(stride) * (size_t)height) { @@ -301,12 +301,12 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, } // ARGB_4444 is a deprecated format, convert automatically to 8888 - if (config == SkBitmap::kARGB_4444_Config) { - config = SkBitmap::kARGB_8888_Config; + if (colorType == kARGB_4444_SkColorType) { + colorType = kN32_SkColorType; } SkBitmap bitmap; - bitmap.setConfig(config, width, height); + bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType)); jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL); if (NULL == buff) { @@ -361,24 +361,50 @@ static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { } static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, - jint width, jint height, jint configHandle, jint allocSize) { + jint width, jint height, jint configHandle, jint allocSize, + jboolean requestPremul) { SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle); - if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) { + SkColorType colorType = SkBitmapConfigToColorType(config); + + // ARGB_4444 is a deprecated format, convert automatically to 8888 + if (colorType == kARGB_4444_SkColorType) { + colorType = kN32_SkColorType; + } + + if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) { // done in native as there's no way to get BytesPerPixel in Java doThrowIAE(env, "Bitmap not large enough to support new configuration"); return; } SkPixelRef* ref = bitmap->pixelRef(); - SkSafeRef(ref); - bitmap->setConfig(config, width, height); + ref->ref(); + SkAlphaType alphaType; + if (bitmap->colorType() != kRGB_565_SkColorType + && bitmap->alphaType() == kOpaque_SkAlphaType) { + // If the original bitmap was set to opaque, keep that setting, unless it + // was 565, which is required to be opaque. + alphaType = kOpaque_SkAlphaType; + } else { + // Otherwise respect the premultiplied request. + alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; + } + bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType)); + // FIXME: Skia thinks of an SkPixelRef as having a constant SkImageInfo (except for + // its alphatype), so it would make more sense from Skia's perspective to create a + // new SkPixelRef. That said, libhwui uses the pointer to the SkPixelRef as a key + // for its cache, so it won't realize this is the same Java Bitmap. + SkImageInfo& info = const_cast<SkImageInfo&>(ref->info()); + // Use the updated from the SkBitmap, which may have corrected an invalid alphatype. + // (e.g. 565 non-opaque) + info = bitmap->info(); bitmap->setPixelRef(ref); // notifyPixelsChanged will increment the generation ID even though the actual pixel data // hasn't been touched. This signals the renderer that the bitmap (including width, height, - // and config) has changed. + // colortype and alphatype) has changed. ref->notifyPixelsChanged(); - SkSafeUnref(ref); + ref->unref(); } // These must match the int values in Bitmap.java @@ -489,28 +515,29 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { android::Parcel* p = android::parcelForJavaObject(env, parcel); - const bool isMutable = p->readInt32() != 0; - const SkBitmap::Config config = (SkBitmap::Config)p->readInt32(); - const int width = p->readInt32(); - const int height = p->readInt32(); - const int rowBytes = p->readInt32(); - const int density = p->readInt32(); - - if (SkBitmap::kARGB_8888_Config != config && - SkBitmap::kRGB_565_Config != config && - SkBitmap::kARGB_4444_Config != config && - SkBitmap::kIndex8_Config != config && - SkBitmap::kA8_Config != config) { - SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config); + const bool isMutable = p->readInt32() != 0; + const SkColorType colorType = (SkColorType)p->readInt32(); + const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); + const int width = p->readInt32(); + const int height = p->readInt32(); + const int rowBytes = p->readInt32(); + const int density = p->readInt32(); + + if (kN32_SkColorType != colorType && + kRGB_565_SkColorType != colorType && + kARGB_4444_SkColorType != colorType && + kIndex_8_SkColorType != colorType && + kAlpha_8_SkColorType != colorType) { + SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); return NULL; } SkBitmap* bitmap = new SkBitmap; - bitmap->setConfig(config, width, height, rowBytes); + bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes); SkColorTable* ctable = NULL; - if (config == SkBitmap::kIndex8_Config) { + if (colorType == kIndex_8_SkColorType) { int count = p->readInt32(); if (count > 0) { size_t size = count * sizeof(SkPMColor); @@ -561,13 +588,14 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, android::Parcel* p = android::parcelForJavaObject(env, parcel); p->writeInt32(isMutable); - p->writeInt32(bitmap->config()); + p->writeInt32(bitmap->colorType()); + p->writeInt32(bitmap->alphaType()); p->writeInt32(bitmap->width()); p->writeInt32(bitmap->height()); p->writeInt32(bitmap->rowBytes()); p->writeInt32(density); - if (bitmap->config() == SkBitmap::kIndex8_Config) { + if (bitmap->colorType() == kIndex_8_SkColorType) { SkColorTable* ctable = bitmap->getColorTable(); if (ctable != NULL) { int count = ctable->count(); @@ -799,7 +827,7 @@ static JNINativeMethod gBitmapMethods[] = { (void*)Bitmap_copy }, { "nativeDestructor", "(J)V", (void*)Bitmap_destructor }, { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, - { "nativeReconfigure", "(JIIII)V", (void*)Bitmap_reconfigure }, + { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure }, { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", (void*)Bitmap_compress }, { "nativeErase", "(JI)V", (void*)Bitmap_erase }, diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 7aa241a..86ed677 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -2,11 +2,8 @@ #include "BitmapFactory.h" #include "NinePatchPeeker.h" -#include "SkData.h" #include "SkFrontBufferedStream.h" #include "SkImageDecoder.h" -#include "SkImageRef_ashmem.h" -#include "SkImageRef_GlobalPool.h" #include "SkMath.h" #include "SkPixelRef.h" #include "SkStream.h" @@ -32,8 +29,6 @@ jfieldID gOptions_configFieldID; jfieldID gOptions_premultipliedFieldID; jfieldID gOptions_mutableFieldID; jfieldID gOptions_ditherFieldID; -jfieldID gOptions_purgeableFieldID; -jfieldID gOptions_shareableFieldID; jfieldID gOptions_preferQualityOverSpeedFieldID; jfieldID gOptions_scaledFieldID; jfieldID gOptions_densityFieldID; @@ -90,14 +85,6 @@ jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) { return jstr; } -static bool optionsPurgeable(JNIEnv* env, jobject options) { - return options != NULL && env->GetBooleanField(options, gOptions_purgeableFieldID); -} - -static bool optionsShareable(JNIEnv* env, jobject options) { - return options != NULL && env->GetBooleanField(options, gOptions_shareableFieldID); -} - static bool optionsJustBounds(JNIEnv* env, jobject options) { return options != NULL && env->GetBooleanField(options, gOptions_justBoundsFieldID); } @@ -125,28 +112,6 @@ static void scaleNinePatchChunk(android::Res_png_9patch* chunk, float scale) { } } -static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream, - int sampleSize, bool ditherImage) { - - SkImageInfo bitmapInfo; - if (!bitmap->asImageInfo(&bitmapInfo)) { - ALOGW("bitmap has unknown configuration so no memory has been allocated"); - return NULL; - } - - SkImageRef* pr; - // only use ashmem for large images, since mmaps come at a price - if (bitmap->getSize() >= 32 * 1024) { - pr = new SkImageRef_ashmem(bitmapInfo, stream, sampleSize); - } else { - pr = new SkImageRef_GlobalPool(bitmapInfo, stream, sampleSize); - } - pr->setDitherImage(ditherImage); - bitmap->setPixelRef(pr)->unref(); - pr->isOpaque(bitmap); - return pr; -} - static SkColorType colorTypeForScaledOutput(SkColorType colorType) { switch (colorType) { case kUnknown_SkColorType: @@ -230,21 +195,17 @@ private: const unsigned int mSize; }; -// since we "may" create a purgeable imageref, we require the stream be ref'able -// i.e. dynamically allocated, since its lifetime may exceed the current stack -// frame. static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, - jobject options, bool allowPurgeable, bool forcePurgeable = false) { + jobject options) { int sampleSize = 1; - SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode; + SkImageDecoder::Mode decodeMode = SkImageDecoder::kDecodePixels_Mode; SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config; bool doDither = true; bool isMutable = false; float scale = 1.0f; - bool isPurgeable = forcePurgeable || (allowPurgeable && optionsPurgeable(env, options)); bool preferQualityOverSpeed = false; bool requireUnpremultiplied = false; @@ -253,7 +214,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding if (options != NULL) { sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); if (optionsJustBounds(env, options)) { - mode = SkImageDecoder::kDecodeBounds_Mode; + decodeMode = SkImageDecoder::kDecodeBounds_Mode; } // initialize these, in case we fail later on @@ -281,7 +242,6 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding } const bool willScale = scale != 1.0f; - isPurgeable &= !willScale; SkImageDecoder* decoder = SkImageDecoder::Factory(stream); if (decoder == NULL) { @@ -312,8 +272,6 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding NinePatchPeeker peeker(decoder); decoder->setPeeker(&peeker); - SkImageDecoder::Mode decodeMode = isPurgeable ? SkImageDecoder::kDecodeBounds_Mode : mode; - JavaPixelAllocator javaAllocator(env); RecyclingPixelAllocator recyclingAllocator(outputBitmap->pixelRef(), existingBufferSize); ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize); @@ -354,7 +312,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding int scaledWidth = decodingBitmap.width(); int scaledHeight = decodingBitmap.height(); - if (willScale && mode != SkImageDecoder::kDecodeBounds_Mode) { + if (willScale && decodeMode != SkImageDecoder::kDecodeBounds_Mode) { scaledWidth = int(scaledWidth * scale + 0.5f); scaledHeight = int(scaledHeight * scale + 0.5f); } @@ -368,7 +326,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding } // if we're in justBounds mode, return now (skip the java bitmap) - if (mode == SkImageDecoder::kDecodeBounds_Mode) { + if (decodeMode == SkImageDecoder::kDecodeBounds_Mode) { return NULL; } @@ -428,7 +386,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding // FIXME: If the alphaType is kUnpremul and the image has alpha, the // colors may not be correct, since Skia does not yet support drawing // to/from unpremultiplied bitmaps. - outputBitmap->setConfig(SkImageInfo::Make(scaledWidth, scaledHeight, + outputBitmap->setInfo(SkImageInfo::Make(scaledWidth, scaledHeight, colorType, decodingBitmap.alphaType())); if (!outputBitmap->allocPixels(outputAllocator, NULL)) { return nullObjectReturn("allocation failed for scaled bitmap"); @@ -460,21 +418,15 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding } } - SkPixelRef* pr; - if (isPurgeable) { - pr = installPixelRef(outputBitmap, stream, sampleSize, doDither); - } else { - // if we get here, we're in kDecodePixels_Mode and will therefore - // already have a pixelref installed. - pr = outputBitmap->pixelRef(); - } - if (pr == NULL) { + // if we get here, we're in kDecodePixels_Mode and will therefore + // already have a pixelref installed. + if (outputBitmap->pixelRef() == NULL) { return nullObjectReturn("Got null SkPixelRef"); } if (!isMutable && javaBitmap == NULL) { // promise we will never change our pixels (great for sharing and pictures) - pr->setImmutable(); + outputBitmap->setImmutable(); } // detach bitmap from its autodeleter, since we want to own it now @@ -513,8 +465,7 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA SkAutoTUnref<SkStreamRewindable> bufferedStream( SkFrontBufferedStream::Create(stream, BYTES_TO_BUFFER)); SkASSERT(bufferedStream.get() != NULL); - // for now we don't allow purgeable with java inputstreams - bitmap = doDecode(env, bufferedStream, padding, options, false, false); + bitmap = doDecode(env, bufferedStream, padding, options); } return bitmap; } @@ -543,76 +494,33 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file, SkFILEStream::kCallerRetains_Ownership)); - SkAutoTUnref<SkStreamRewindable> stream; - - // Retain the old behavior of allowing purgeable if both purgeable and - // shareable are set to true. - bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions) - && optionsShareable(env, bitmapFactoryOptions); - if (isPurgeable) { - // Copy the stream, so the image can be decoded multiple times without - // continuing to modify the original file descriptor. - // Copy beginning from the current position. - const size_t fileSize = fileStream->getLength() - fileStream->getPosition(); - void* buffer = sk_malloc_flags(fileSize, 0); - if (buffer == NULL) { - return nullObjectReturn("Could not make a copy for ashmem"); - } - - SkAutoTUnref<SkData> data(SkData::NewFromMalloc(buffer, fileSize)); + // Use a buffered stream. Although an SkFILEStream can be rewound, this + // ensures that SkImageDecoder::Factory never rewinds beyond the + // current position of the file descriptor. + SkAutoTUnref<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream, + BYTES_TO_BUFFER)); - if (fileStream->read(buffer, fileSize) != fileSize) { - return nullObjectReturn("Could not read the file."); - } - - stream.reset(new SkMemoryStream(data)); - } else { - // Use a buffered stream. Although an SkFILEStream can be rewound, this - // ensures that SkImageDecoder::Factory never rewinds beyond the - // current position of the file descriptor. - stream.reset(SkFrontBufferedStream::Create(fileStream, BYTES_TO_BUFFER)); - } - - return doDecode(env, stream, padding, bitmapFactoryOptions, isPurgeable); + return doDecode(env, stream, padding, bitmapFactoryOptions); } static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset, jobject padding, jobject options) { - SkStreamRewindable* stream; Asset* asset = reinterpret_cast<Asset*>(native_asset); - bool forcePurgeable = optionsPurgeable(env, options); - if (forcePurgeable) { - // if we could "ref/reopen" the asset, we may not need to copy it here - // and we could assume optionsShareable, since assets are always RO - stream = CopyAssetToStream(asset); - if (stream == NULL) { - return NULL; - } - } else { - // since we know we'll be done with the asset when we return, we can - // just use a simple wrapper - stream = new AssetStreamAdaptor(asset, - AssetStreamAdaptor::kNo_OwnAsset, - AssetStreamAdaptor::kNo_HasMemoryBase); - } - SkAutoUnref aur(stream); - return doDecode(env, stream, padding, options, forcePurgeable, forcePurgeable); + // since we know we'll be done with the asset when we return, we can + // just use a simple wrapper + SkAutoTUnref<SkStreamRewindable> stream(new AssetStreamAdaptor(asset, + AssetStreamAdaptor::kNo_OwnAsset, AssetStreamAdaptor::kNo_HasMemoryBase)); + return doDecode(env, stream, padding, options); } static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, jint offset, jint length, jobject options) { - /* If optionsShareable() we could decide to just wrap the java array and - share it, but that means adding a globalref to the java array object - and managing its lifetime. For now we just always copy the array's data - if optionsPurgeable(), unless we're just decoding bounds. - */ - bool purgeable = optionsPurgeable(env, options) && !optionsJustBounds(env, options); AutoJavaByteArray ar(env, byteArray); - SkMemoryStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable); + SkMemoryStream* stream = new SkMemoryStream(ar.ptr() + offset, length, false); SkAutoUnref aur(stream); - return doDecode(env, stream, NULL, options, purgeable); + return doDecode(env, stream, NULL, options); } static void nativeRequestCancel(JNIEnv*, jobject joptions) { @@ -676,8 +584,6 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gOptions_premultipliedFieldID = getFieldIDCheck(env, options_class, "inPremultiplied", "Z"); gOptions_mutableFieldID = getFieldIDCheck(env, options_class, "inMutable", "Z"); gOptions_ditherFieldID = getFieldIDCheck(env, options_class, "inDither", "Z"); - gOptions_purgeableFieldID = getFieldIDCheck(env, options_class, "inPurgeable", "Z"); - gOptions_shareableFieldID = getFieldIDCheck(env, options_class, "inInputShareable", "Z"); gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, options_class, "inPreferQualityOverSpeed", "Z"); gOptions_scaledFieldID = getFieldIDCheck(env, options_class, "inScaled", "Z"); diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp index ef57e3d..d17f46c 100644 --- a/core/jni/android/graphics/Camera.cpp +++ b/core/jni/android/graphics/Camera.cpp @@ -3,6 +3,8 @@ #include "SkCamera.h" +#include "GraphicsJNI.h" + static jfieldID gNativeInstanceFieldID; static void Camera_constructor(JNIEnv* env, jobject obj) { @@ -93,7 +95,7 @@ static void Camera_getMatrix(JNIEnv* env, jobject obj, jlong matrixHandle) { } static void Camera_applyToCanvas(JNIEnv* env, jobject obj, jlong canvasHandle) { - SkCanvas* native_canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* native_canvas = GraphicsJNI::getNativeCanvas(canvasHandle); jlong viewHandle = env->GetLongField(obj, gNativeInstanceFieldID); Sk3DView* v = reinterpret_cast<Sk3DView*>(viewHandle); v->applyToCanvas((SkCanvas*)native_canvas); diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 432a615..9e09280 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -19,12 +19,14 @@ #include <android_runtime/AndroidRuntime.h> #include "SkCanvas.h" +#include "SkClipStack.h" #include "SkDevice.h" +#include "SkDeque.h" #include "SkDrawFilter.h" #include "SkGraphics.h" -#include "SkImageRef_GlobalPool.h" #include "SkPorterDuff.h" #include "SkShader.h" +#include "SkTArray.h" #include "SkTemplates.h" #ifdef USE_MINIKIN @@ -42,21 +44,6 @@ #include <utils/Log.h> -static uint32_t get_thread_msec() { -#if defined(HAVE_POSIX_CLOCKS) - struct timespec tm; - - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm); - - return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000; -#else - struct timeval tv; - - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000LL + tv.tv_usec / 1000; -#endif -} - namespace android { class ClipCopier : public SkCanvas::ClipVisitor { @@ -77,6 +64,155 @@ private: SkCanvas* m_dstCanvas; }; +// Holds an SkCanvas reference plus additional native data. +class NativeCanvasWrapper { +private: + struct SaveRec { + int saveCount; + SkCanvas::SaveFlags saveFlags; + }; + +public: + NativeCanvasWrapper(SkCanvas* canvas) + : mCanvas(canvas) + , mSaveStack(NULL) { + SkASSERT(canvas); + } + + ~NativeCanvasWrapper() { + delete mSaveStack; + } + + SkCanvas* getCanvas() const { + return mCanvas.get(); + } + + void setCanvas(SkCanvas* canvas) { + SkASSERT(canvas); + mCanvas.reset(canvas); + + delete mSaveStack; + mSaveStack = NULL; + } + + int save(SkCanvas::SaveFlags flags) { + int count = mCanvas->save(); + recordPartialSave(flags); + return count; + } + + int saveLayer(const SkRect* bounds, const SkPaint* paint, + SkCanvas::SaveFlags flags) { + int count = mCanvas->saveLayer(bounds, paint, + static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag)); + recordPartialSave(flags); + return count; + } + + int saveLayerAlpha(const SkRect* bounds, U8CPU alpha, + SkCanvas::SaveFlags flags) { + int count = mCanvas->saveLayerAlpha(bounds, alpha, + static_cast<SkCanvas::SaveFlags>(flags | SkCanvas::kMatrixClip_SaveFlag)); + recordPartialSave(flags); + return count; + } + + void restore() { + const SaveRec* rec = (NULL == mSaveStack) + ? NULL + : static_cast<SaveRec*>(mSaveStack->back()); + int currentSaveCount = mCanvas->getSaveCount() - 1; + SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount); + + if (NULL == rec || rec->saveCount != currentSaveCount) { + // Fast path - no record for this frame. + mCanvas->restore(); + return; + } + + bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag); + bool preserveClip = !(rec->saveFlags & SkCanvas::kClip_SaveFlag); + + SkMatrix savedMatrix; + if (preserveMatrix) { + savedMatrix = mCanvas->getTotalMatrix(); + } + + SkTArray<SkClipStack::Element> savedClips; + if (preserveClip) { + saveClipsForFrame(savedClips, currentSaveCount); + } + + mCanvas->restore(); + + if (preserveMatrix) { + mCanvas->setMatrix(savedMatrix); + } + + if (preserveClip && !savedClips.empty()) { + applyClips(savedClips); + } + + mSaveStack->pop_back(); + } + +private: + void recordPartialSave(SkCanvas::SaveFlags flags) { + // A partial save is a save operation which doesn't capture the full canvas state. + // (either kMatrix_SaveFlags or kClip_SaveFlag is missing). + + // Mask-out non canvas state bits. + flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag); + + if (SkCanvas::kMatrixClip_SaveFlag == flags) { + // not a partial save. + return; + } + + if (NULL == mSaveStack) { + mSaveStack = new SkDeque(sizeof(struct SaveRec), 8); + } + + SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back()); + // Store the save counter in the SkClipStack domain. + // (0-based, equal to the number of save ops on the stack). + rec->saveCount = mCanvas->getSaveCount() - 1; + rec->saveFlags = flags; + } + + void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, + int frameSaveCount) { + SkClipStack::Iter clipIterator(*mCanvas->getClipStack(), + SkClipStack::Iter::kTop_IterStart); + while (const SkClipStack::Element* elem = clipIterator.next()) { + if (elem->getSaveCount() < frameSaveCount) { + // done with the current frame. + break; + } + SkASSERT(elem->getSaveCount() == frameSaveCount); + clips.push_back(*elem); + } + } + + void applyClips(const SkTArray<SkClipStack::Element>& clips) { + ClipCopier clipCopier(mCanvas); + + // The clip stack stores clips in device space. + SkMatrix origMatrix = mCanvas->getTotalMatrix(); + mCanvas->resetMatrix(); + + // We pushed the clips in reverse order. + for (int i = clips.count() - 1; i >= 0; --i) { + clips[i].replay(&clipCopier); + } + + mCanvas->setMatrix(origMatrix); + } + + SkAutoTUnref<SkCanvas> mCanvas; + SkDeque* mSaveStack; // lazily allocated, tracks partial saves. +}; + // Returns true if the SkCanvas's clip is non-empty. static jboolean hasNonEmptyClip(const SkCanvas& canvas) { bool emptyClip = canvas.isClipEmpty(); @@ -85,28 +221,35 @@ static jboolean hasNonEmptyClip(const SkCanvas& canvas) { class SkCanvasGlue { public: + // Get the native wrapper for a given handle. + static inline NativeCanvasWrapper* getNativeWrapper(jlong nativeHandle) { + SkASSERT(nativeHandle); + return reinterpret_cast<NativeCanvasWrapper*>(nativeHandle); + } - static void finalizer(JNIEnv* env, jobject clazz, jlong canvasHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); - canvas->unref(); + // Get the SkCanvas for a given native handle. + static inline SkCanvas* getNativeCanvas(jlong nativeHandle) { + NativeCanvasWrapper* wrapper = getNativeWrapper(nativeHandle); + SkCanvas* canvas = wrapper->getCanvas(); + SkASSERT(canvas); + + return canvas; } - static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) { - SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + // Construct an SkCanvas from the bitmap. + static SkCanvas* createCanvas(SkBitmap* bitmap) { if (bitmap) { - return reinterpret_cast<jlong>(new SkCanvas(*bitmap)); - } else { - // Create an empty bitmap device to prevent callers from crashing - // if they attempt to draw into this canvas. - SkBitmap emptyBitmap; - return reinterpret_cast<jlong>(new SkCanvas(emptyBitmap)); + return SkNEW_ARGS(SkCanvas, (*bitmap)); } + + // Create an empty bitmap device to prevent callers from crashing + // if they attempt to draw into this canvas. + SkBitmap emptyBitmap; + return new SkCanvas(emptyBitmap); } - static void copyCanvasState(JNIEnv* env, jobject clazz, - jlong srcCanvasHandle, jlong dstCanvasHandle) { - SkCanvas* srcCanvas = reinterpret_cast<SkCanvas*>(srcCanvasHandle); - SkCanvas* dstCanvas = reinterpret_cast<SkCanvas*>(dstCanvasHandle); + // Copy the canvas matrix & clip state. + static void copyCanvasState(SkCanvas* srcCanvas, SkCanvas* dstCanvas) { if (srcCanvas && dstCanvas) { dstCanvas->setMatrix(srcCanvas->getTotalMatrix()); if (NULL != srcCanvas->getDevice() && NULL != dstCanvas->getDevice()) { @@ -116,10 +259,44 @@ public: } } + // Native JNI handlers + static void finalizer(JNIEnv* env, jobject clazz, jlong nativeHandle) { + NativeCanvasWrapper* wrapper = reinterpret_cast<NativeCanvasWrapper*>(nativeHandle); + delete wrapper; + } + + // Native wrapper constructor used by Canvas(Bitmap) + static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) { + // No check - 0 is a valid bitmapHandle. + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); + SkCanvas* canvas = createCanvas(bitmap); + + return reinterpret_cast<jlong>(new NativeCanvasWrapper(canvas)); + } + + // Native wrapper constructor used by Canvas(native_canvas) + static jlong initCanvas(JNIEnv* env, jobject, jlong canvasHandle) { + SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + return reinterpret_cast<jlong>(new NativeCanvasWrapper(canvas)); + } + + // Set the given bitmap as the new draw target (wrapped in a new SkCanvas), + // optionally copying canvas matrix & clip state. + static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, + jboolean copyState) { + NativeCanvasWrapper* wrapper = reinterpret_cast<NativeCanvasWrapper*>(canvasHandle); + SkCanvas* newCanvas = createCanvas(reinterpret_cast<SkBitmap*>(bitmapHandle)); + NPE_CHECK_RETURN_VOID(env, newCanvas); + + if (copyState == JNI_TRUE) { + copyCanvasState(wrapper->getCanvas(), newCanvas); + } + + // setCanvas() unrefs the old canvas. + wrapper->setCanvas(newCanvas); + } static void freeCaches(JNIEnv* env, jobject) { - // these are called in no particular order - SkImageRef_GlobalPool::SetRAMUsed(0); SkGraphics::PurgeFontCache(); } @@ -127,146 +304,107 @@ public: TextLayoutEngine::getInstance().purgeCaches(); } - static jboolean isOpaque(JNIEnv* env, jobject jcanvas) { - NPE_CHECK_RETURN_ZERO(env, jcanvas); - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); + static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); bool result = canvas->getDevice()->accessBitmap(false).isOpaque(); return result ? JNI_TRUE : JNI_FALSE; } - static jint getWidth(JNIEnv* env, jobject jcanvas) { - NPE_CHECK_RETURN_ZERO(env, jcanvas); - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); + static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); int width = canvas->getDevice()->accessBitmap(false).width(); return static_cast<jint>(width); } - static jint getHeight(JNIEnv* env, jobject jcanvas) { - NPE_CHECK_RETURN_ZERO(env, jcanvas); - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); + static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); int height = canvas->getDevice()->accessBitmap(false).height(); return static_cast<jint>(height); } - static jint saveAll(JNIEnv* env, jobject jcanvas) { - NPE_CHECK_RETURN_ZERO(env, jcanvas); - int result = GraphicsJNI::getNativeCanvas(env, jcanvas)->save(); - return static_cast<jint>(result); - } - - static jint save(JNIEnv* env, jobject jcanvas, jint flagsHandle) { + static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) { + NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); - NPE_CHECK_RETURN_ZERO(env, jcanvas); - int result = GraphicsJNI::getNativeCanvas(env, jcanvas)->save(flags); - return static_cast<jint>(result); + return static_cast<jint>(wrapper->save(flags)); } - static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds, - jlong paintHandle, jint flags) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - SkRect* bounds_ = NULL; - SkRect storage; - if (bounds != NULL) { - GraphicsJNI::jrectf_to_rect(env, bounds, &storage); - bounds_ = &storage; - } - return canvas->saveLayer(bounds_, paint, static_cast<SkCanvas::SaveFlags>(flags)); - } - - static jint saveLayer4F(JNIEnv* env, jobject, jlong canvasHandle, - jfloat l, jfloat t, jfloat r, jfloat b, - jlong paintHandle, jint flags) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, + jfloat l, jfloat t, jfloat r, jfloat b, + jlong paintHandle, jint flagsHandle) { + NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); SkRect bounds; bounds.set(l, t, r, b); - int result = canvas->saveLayer(&bounds, paint, - static_cast<SkCanvas::SaveFlags>(flags)); - return static_cast<jint>(result); + return static_cast<jint>(wrapper->saveLayer(&bounds, paint, flags)); } static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, - jobject bounds, jint alpha, jint flags) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); - SkRect* bounds_ = NULL; - SkRect storage; - if (bounds != NULL) { - GraphicsJNI::jrectf_to_rect(env, bounds, &storage); - bounds_ = &storage; - } - int result = canvas->saveLayerAlpha(bounds_, alpha, - static_cast<SkCanvas::SaveFlags>(flags)); - return static_cast<jint>(result); - } - - static jint saveLayerAlpha4F(JNIEnv* env, jobject, jlong canvasHandle, - jfloat l, jfloat t, jfloat r, jfloat b, - jint alpha, jint flags) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + jfloat l, jfloat t, jfloat r, jfloat b, + jint alpha, jint flagsHandle) { + NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); + SkCanvas::SaveFlags flags = static_cast<SkCanvas::SaveFlags>(flagsHandle); SkRect bounds; bounds.set(l, t, r, b); - int result = canvas->saveLayerAlpha(&bounds, alpha, - static_cast<SkCanvas::SaveFlags>(flags)); - return static_cast<jint>(result); + return static_cast<jint>(wrapper->saveLayerAlpha(&bounds, alpha, flags)); } - static void restore(JNIEnv* env, jobject jcanvas) { - NPE_CHECK_RETURN_VOID(env, jcanvas); - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); - if (canvas->getSaveCount() <= 1) { // cannot restore anymore + static void restore(JNIEnv* env, jobject, jlong canvasHandle) { + NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); + if (wrapper->getCanvas()->getSaveCount() <= 1) { // cannot restore anymore doThrowISE(env, "Underflow in restore"); return; } - canvas->restore(); + wrapper->restore(); } - static jint getSaveCount(JNIEnv* env, jobject jcanvas) { - NPE_CHECK_RETURN_ZERO(env, jcanvas); - int result = GraphicsJNI::getNativeCanvas(env, jcanvas)->getSaveCount(); - return static_cast<jint>(result); + static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) { + return static_cast<jint>(getNativeCanvas(canvasHandle)->getSaveCount()); } - static void restoreToCount(JNIEnv* env, jobject jcanvas, jint restoreCount) { - NPE_CHECK_RETURN_VOID(env, jcanvas); - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); + static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, + jint restoreCount) { + NativeCanvasWrapper* wrapper = getNativeWrapper(canvasHandle); if (restoreCount < 1) { doThrowIAE(env, "Underflow in restoreToCount"); return; } - canvas->restoreToCount(restoreCount); + + while (wrapper->getCanvas()->getSaveCount() > restoreCount) { + wrapper->restore(); + } } - static void translate(JNIEnv* env, jobject jcanvas, jfloat dx, jfloat dy) { - NPE_CHECK_RETURN_VOID(env, jcanvas); - (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->translate(dx, dy); + static void translate(JNIEnv*, jobject, jlong canvasHandle, + jfloat dx, jfloat dy) { + getNativeCanvas(canvasHandle)->translate(dx, dy); } - static void scale__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) { - NPE_CHECK_RETURN_VOID(env, jcanvas); - (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->scale(sx, sy); + static void scale__FF(JNIEnv*, jobject, jlong canvasHandle, + jfloat sx, jfloat sy) { + getNativeCanvas(canvasHandle)->scale(sx, sy); } - static void rotate__F(JNIEnv* env, jobject jcanvas, jfloat degrees) { - NPE_CHECK_RETURN_VOID(env, jcanvas); - (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->rotate(degrees); + static void rotate__F(JNIEnv*, jobject, jlong canvasHandle, + jfloat degrees) { + getNativeCanvas(canvasHandle)->rotate(degrees); } - static void skew__FF(JNIEnv* env, jobject jcanvas, jfloat sx, jfloat sy) { - NPE_CHECK_RETURN_VOID(env, jcanvas); - (void)GraphicsJNI::getNativeCanvas(env, jcanvas)->skew(sx, sy); + static void skew__FF(JNIEnv*, jobject, jlong canvasHandle, + jfloat sx, jfloat sy) { + getNativeCanvas(canvasHandle)->skew(sx, sy); } static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); canvas->concat(*matrix); } static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); if (NULL == matrix) { canvas->resetMatrix(); @@ -275,59 +413,19 @@ public: } } - static jboolean clipRect_FFFF(JNIEnv* env, jobject jcanvas, jfloat left, - jfloat top, jfloat right, jfloat bottom) { - NPE_CHECK_RETURN_ZERO(env, jcanvas); + static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, + jfloat left, jfloat top, jfloat right, + jfloat bottom, jint op) { SkRect r; r.set(left, top, right, bottom); - SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); - c->clipRect(r); + SkCanvas* c = getNativeCanvas(canvasHandle); + c->clipRect(r, static_cast<SkRegion::Op>(op)); return hasNonEmptyClip(*c); } - static jboolean clipRect_IIII(JNIEnv* env, jobject jcanvas, jint left, - jint top, jint right, jint bottom) { - NPE_CHECK_RETURN_ZERO(env, jcanvas); - SkRect r; - r.set(SkIntToScalar(left), SkIntToScalar(top), - SkIntToScalar(right), SkIntToScalar(bottom)); - SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); - c->clipRect(r); - return hasNonEmptyClip(*c); - } - - static jboolean clipRect_RectF(JNIEnv* env, jobject jcanvas, jobject rectf) { - NPE_CHECK_RETURN_ZERO(env, jcanvas); - NPE_CHECK_RETURN_ZERO(env, rectf); - SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); - SkRect tmp; - c->clipRect(*GraphicsJNI::jrectf_to_rect(env, rectf, &tmp)); - return hasNonEmptyClip(*c); - } - - static jboolean clipRect_Rect(JNIEnv* env, jobject jcanvas, jobject rect) { - NPE_CHECK_RETURN_ZERO(env, jcanvas); - NPE_CHECK_RETURN_ZERO(env, rect); - SkCanvas* c = GraphicsJNI::getNativeCanvas(env, jcanvas); - SkRect tmp; - c->clipRect(*GraphicsJNI::jrect_to_rect(env, rect, &tmp)); - return hasNonEmptyClip(*c); - - } - - static jboolean clipRect(JNIEnv* env, jobject, jlong canvasHandle, - jfloat left, jfloat top, jfloat right, jfloat bottom, - jint op) { - SkRect rect; - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); - rect.set(left, top, right, bottom); - canvas->clipRect(rect, static_cast<SkRegion::Op>(op)); - return hasNonEmptyClip(*canvas); - } - static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle, jint op) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); canvas->clipPath(*reinterpret_cast<SkPath*>(pathHandle), static_cast<SkRegion::Op>(op)); return hasNonEmptyClip(*canvas); @@ -335,30 +433,30 @@ public: static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle, jint op) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle); - canvas->clipRegion(*deviceRgn, static_cast<SkRegion::Op>(op)); + SkPath rgnPath; + if (deviceRgn->getBoundaryPath(&rgnPath)) { + // The region is specified in device space. + SkMatrix savedMatrix = canvas->getTotalMatrix(); + canvas->resetMatrix(); + canvas->clipPath(rgnPath, static_cast<SkRegion::Op>(op)); + canvas->setMatrix(savedMatrix); + } else { + canvas->clipRect(SkRect::MakeEmpty(), static_cast<SkRegion::Op>(op)); + } return hasNonEmptyClip(*canvas); } static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); canvas->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle)); } - static jboolean quickReject__RectF(JNIEnv* env, jobject, jlong canvasHandle, - jobject rect) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); - SkRect rect_; - GraphicsJNI::jrectf_to_rect(env, rect, &rect_); - bool result = canvas->quickReject(rect_); - return result ? JNI_TRUE : JNI_FALSE; - } - static jboolean quickReject__Path(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); bool result = canvas->quickReject(*reinterpret_cast<SkPath*>(pathHandle)); return result ? JNI_TRUE : JNI_FALSE; } @@ -366,7 +464,7 @@ public: static jboolean quickReject__FFFF(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, jfloat right, jfloat bottom) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkRect r; r.set(left, top, right, bottom); bool result = canvas->quickReject(r); @@ -375,45 +473,43 @@ public: static void drawRGB(JNIEnv* env, jobject, jlong canvasHandle, jint r, jint g, jint b) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); canvas->drawARGB(0xFF, r, g, b); } static void drawARGB(JNIEnv* env, jobject, jlong canvasHandle, jint a, jint r, jint g, jint b) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); canvas->drawARGB(a, r, g, b); } static void drawColor__I(JNIEnv* env, jobject, jlong canvasHandle, jint color) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); canvas->drawColor(color); } static void drawColor__II(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle); canvas->drawColor(color, SkPorterDuff::ToXfermodeMode(mode)); } static void drawPaint(JNIEnv* env, jobject, jlong canvasHandle, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); canvas->drawPaint(*paint); } - static void doPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, - jint offset, jint count, jobject jpaint, - jint modeHandle) { - NPE_CHECK_RETURN_VOID(env, jcanvas); + static void doPoints(JNIEnv* env, jlong canvasHandle, + jfloatArray jptsArray, jint offset, jint count, + jlong paintHandle, jint modeHandle) { NPE_CHECK_RETURN_VOID(env, jptsArray); - NPE_CHECK_RETURN_VOID(env, jpaint); SkCanvas::PointMode mode = static_cast<SkCanvas::PointMode>(modeHandle); - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); - const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint); + SkCanvas* canvas = getNativeCanvas(canvasHandle); + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); AutoJavaFloatArray autoPts(env, jptsArray); float* floats = autoPts.ptr(); @@ -433,86 +529,74 @@ public: pts[i].set(src[0], src[1]); src += 2; } - canvas->drawPoints(mode, count, pts, paint); + canvas->drawPoints(mode, count, pts, *paint); } - static void drawPoints(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, - jint offset, jint count, jobject jpaint) { - doPoints(env, jcanvas, jptsArray, offset, count, jpaint, + static void drawPoints(JNIEnv* env, jobject, jlong canvasHandle, + jfloatArray jptsArray, jint offset, + jint count, jlong paintHandle) { + doPoints(env, canvasHandle, jptsArray, offset, count, paintHandle, SkCanvas::kPoints_PointMode); } - static void drawLines(JNIEnv* env, jobject jcanvas, jfloatArray jptsArray, - jint offset, jint count, jobject jpaint) { - doPoints(env, jcanvas, jptsArray, offset, count, jpaint, + static void drawLines(JNIEnv* env, jobject, jlong canvasHandle, + jfloatArray jptsArray, jint offset, jint count, + jlong paintHandle) { + doPoints(env, canvasHandle, jptsArray, offset, count, paintHandle, SkCanvas::kLines_PointMode); } - static void drawPoint(JNIEnv* env, jobject jcanvas, jfloat x, jfloat y, - jobject jpaint) { - NPE_CHECK_RETURN_VOID(env, jcanvas); - NPE_CHECK_RETURN_VOID(env, jpaint); - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); - const SkPaint& paint = *GraphicsJNI::getNativePaint(env, jpaint); - - canvas->drawPoint(x, y, paint); + static void drawPoint(JNIEnv*, jobject, jlong canvasHandle, jfloat x, jfloat y, + jlong paintHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); + const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + canvas->drawPoint(x, y, *paint); } static void drawLine__FFFFPaint(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY, jfloat stopX, jfloat stopY, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); canvas->drawLine(startX, startY, stopX, stopY, *paint); } - static void drawRect__RectFPaint(JNIEnv* env, jobject, jlong canvasHandle, - jobject rect, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - SkRect rect_; - GraphicsJNI::jrectf_to_rect(env, rect, &rect_); - canvas->drawRect(rect_, *paint); - } - static void drawRect__FFFFPaint(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, jfloat right, jfloat bottom, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); canvas->drawRectCoords(left, top, right, bottom, *paint); } - static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jobject joval, - jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + static void drawOval(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jlong paintHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - SkRect oval; - GraphicsJNI::jrectf_to_rect(env, joval, &oval); + SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); canvas->drawOval(oval, *paint); } static void drawCircle(JNIEnv* env, jobject, jlong canvasHandle, jfloat cx, jfloat cy, jfloat radius, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); canvas->drawCircle(cx, cy, radius, *paint); } - static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jobject joval, - jfloat startAngle, jfloat sweepAngle, - jboolean useCenter, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + static void drawArc(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, jboolean useCenter, + jlong paintHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); - SkRect oval; - GraphicsJNI::jrectf_to_rect(env, joval, &oval); + SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); canvas->drawArc(oval, startAngle, sweepAngle, useCenter, *paint); } static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top, jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); canvas->drawRoundRect(rect, rx, ry, *paint); @@ -520,7 +604,7 @@ public: static void drawPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPath* path = reinterpret_cast<SkPath*>(pathHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); canvas->drawPath(*path, *paint); @@ -531,7 +615,7 @@ public: jfloat left, jfloat top, jlong paintHandle, jint canvasDensity, jint screenDensity, jint bitmapDensity) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); @@ -591,7 +675,7 @@ public: jlong bitmapHandle, jobject srcIRect, jobject dstRectF, jlong paintHandle, jint screenDensity, jint bitmapDensity) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); SkRect dst; @@ -604,7 +688,7 @@ public: jlong bitmapHandle, jobject srcIRect, jobject dstRect, jlong paintHandle, jint screenDensity, jint bitmapDensity) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); SkRect dst; @@ -616,14 +700,14 @@ public: static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle, jintArray jcolors, jint offset, jint stride, jfloat x, jfloat y, jint width, jint height, - jboolean hasAlpha, jlong paintHandle) - { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + jboolean hasAlpha, jlong paintHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + SkImageInfo info = SkImageInfo::Make(width, height, + hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType, + kPremul_SkAlphaType); SkBitmap bitmap; - bitmap.setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config : - SkBitmap::kRGB_565_Config, width, height); - if (!bitmap.allocPixels()) { + if (!bitmap.allocPixels(info)) { return; } @@ -638,7 +722,7 @@ public: static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle, jlong matrixHandle, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); @@ -649,7 +733,7 @@ public: jlong bitmapHandle, jint meshWidth, jint meshHeight, jfloatArray jverts, jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); @@ -759,7 +843,7 @@ public: jintArray jcolors, jint colorIndex, jshortArray jindices, jint indexIndex, jint indexCount, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(modeHandle); const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); @@ -797,26 +881,26 @@ public: static void drawText___CIIFFIPaintTypeface(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, jint count, - jfloat x, jfloat y, jint flags, + jfloat x, jfloat y, jint bidiFlags, jlong paintHandle, jlong typefaceHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); jchar* textArray = env->GetCharArrayElements(text, NULL); - drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint, typeface); + drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, bidiFlags, paint, typeface); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } static void drawText__StringIIFFIPaintTypeface(JNIEnv* env, jobject, jlong canvasHandle, jstring text, jint start, jint end, - jfloat x, jfloat y, jint flags, + jfloat x, jfloat y, jint bidiFlags, jlong paintHandle, jlong typefaceHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); const jchar* textArray = env->GetStringChars(text, NULL); - drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint, typeface); + drawTextWithGlyphs(canvas, textArray, start, end, x, y, bidiFlags, paint, typeface); env->ReleaseStringChars(text, textArray); } @@ -866,24 +950,25 @@ public: static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, int start, int end, - jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) { + jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { jint count = end - start; - drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint, typeface); + drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, bidiFlags, paint, + typeface); } static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, int start, int count, int contextCount, - jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) { + jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { #ifdef USE_MINIKIN Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface); + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); layout.doLayout(textArray, start, count, contextCount, css); drawGlyphsToSkia(canvas, paint, layout, x, y); #else sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - textArray, start, count, contextCount, flags); + textArray, start, count, contextCount, bidiFlags); if (value == NULL) { return; } @@ -894,7 +979,8 @@ public: x -= value->getTotalAdvance(); } paint->setTextAlign(SkPaint::kLeft_Align); - doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint); + doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), + x, y, paint); doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint); paint->setTextAlign(align); #endif @@ -905,42 +991,37 @@ public: #define kStdUnderline_Offset (1.0f / 9.0f) #define kStdUnderline_Thickness (1.0f / 18.0f) -static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, SkPaint* paint) { - uint32_t flags; - SkDrawFilter* drawFilter = canvas->getDrawFilter(); - if (drawFilter) { - SkPaint paintCopy(*paint); - drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); - flags = paintCopy.getFlags(); - } else { - flags = paint->getFlags(); - } - if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { - SkScalar left = x; - SkScalar right = x + length; - float textSize = paint->getTextSize(); - float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); - if (flags & SkPaint::kUnderlineText_Flag) { - SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; - SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; - canvas->drawRectCoords(left, top, right, bottom, *paint); + static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, + SkPaint* paint) { + uint32_t flags; + SkDrawFilter* drawFilter = canvas->getDrawFilter(); + if (drawFilter) { + SkPaint paintCopy(*paint); + drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); + flags = paintCopy.getFlags(); + } else { + flags = paint->getFlags(); } - if (flags & SkPaint::kStrikeThruText_Flag) { - SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; - SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; - canvas->drawRectCoords(left, top, right, bottom, *paint); + if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { + SkScalar left = x; + SkScalar right = x + length; + float textSize = paint->getTextSize(); + float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); + if (flags & SkPaint::kUnderlineText_Flag) { + SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; + SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; + canvas->drawRectCoords(left, top, right, bottom, *paint); + } + if (flags & SkPaint::kStrikeThruText_Flag) { + SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; + SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; + canvas->drawRectCoords(left, top, right, bottom, *paint); + } } } -} - - static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count, - jfloat x, jfloat y, int flags, SkPaint* paint) { - // Beware: this needs Glyph encoding (already done on the Paint constructor) - canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint); - } static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray, - int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) { + int index, int count, jfloat x, jfloat y, SkPaint* paint) { SkPoint* posPtr = new SkPoint[count]; for (int indx = 0; indx < count; indx++) { posPtr[indx].fX = x + posArray[indx * 2]; @@ -950,40 +1031,42 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l delete[] posPtr; } - static void drawTextRun___CIIIIFFIPaintTypeface( - JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, - jint count, jint contextIndex, jint contextCount, - jfloat x, jfloat y, jint dirFlags, jlong paintHandle, jlong typefaceHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + static void drawTextRun___CIIIIFFZPaintTypeface( + JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, + jint count, jint contextIndex, jint contextCount, + jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; jchar* chars = env->GetCharArrayElements(text, NULL); drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex, - count, contextCount, x, y, dirFlags, paint, typeface); + count, contextCount, x, y, bidiFlags, paint, typeface); env->ReleaseCharArrayElements(text, chars, JNI_ABORT); } - static void drawTextRun__StringIIIIFFIPaintTypeface( - JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, jint start, - jint end, jint contextStart, jint contextEnd, - jfloat x, jfloat y, jint dirFlags, jlong paintHandle, jlong typefaceHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + static void drawTextRun__StringIIIIFFZPaintTypeface( + JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, jint start, + jint end, jint contextStart, jint contextEnd, + jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; jint count = end - start; jint contextCount = contextEnd - contextStart; const jchar* chars = env->GetStringChars(text, NULL); drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart, - count, contextCount, x, y, dirFlags, paint, typeface); + count, contextCount, x, y, bidiFlags, paint, typeface); env->ReleaseStringChars(text, chars); } static void drawPosText___CII_FPaint(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, jint count, jfloatArray pos, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); jchar* textArray = text ? env->GetCharArrayElements(text, NULL) : NULL; jsize textCount = text ? env->GetArrayLength(text) : NULL; @@ -1014,7 +1097,7 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l jlong canvasHandle, jstring text, jfloatArray pos, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); const void* text_ = text ? env->GetStringChars(text, NULL) : NULL; int byteLength = text ? env->GetStringLength(text) : 0; @@ -1041,29 +1124,82 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l delete[] posPtr; } +#ifdef USE_MINIKIN + class DrawTextOnPathFunctor { + public: + DrawTextOnPathFunctor(const Layout& layout, SkCanvas* canvas, float hOffset, + float vOffset, SkPaint* paint, SkPath* path) + : layout(layout), canvas(canvas), hOffset(hOffset), vOffset(vOffset), + paint(paint), path(path) { + } + void operator()(size_t start, size_t end) { + uint16_t glyphs[1]; + for (size_t i = start; i < end; i++) { + glyphs[0] = layout.getGlyphId(i); + float x = hOffset + layout.getX(i); + float y = vOffset + layout.getY(i); + canvas->drawTextOnPathHV(glyphs, sizeof(glyphs), *path, x, y, *paint); + } + } + private: + const Layout& layout; + SkCanvas* canvas; + float hOffset; + float vOffset; + SkPaint* paint; + SkPath* path; + }; +#endif + + static void doDrawTextOnPath(SkPaint* paint, const jchar* text, int count, int bidiFlags, + float hOffset, float vOffset, SkPath* path, SkCanvas* canvas, TypefaceImpl* typeface) { +#ifdef USE_MINIKIN + Layout layout; + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); + layout.doLayout(text, 0, count, count, css); + hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path); + // Set align to left for drawing, as we don't want individual + // glyphs centered or right-aligned; the offset above takes + // care of all alignment. + SkPaint::Align align = paint->getTextAlign(); + paint->setTextAlign(SkPaint::kLeft_Align); + + DrawTextOnPathFunctor f(layout, canvas, hOffset, vOffset, paint, path); + MinikinUtils::forFontRun(layout, paint, f); + paint->setTextAlign(align); +#else + TextLayout::drawTextOnPath(paint, text, count, bidiFlags, hOffset, vOffset, path, canvas); +#endif + } + static void drawTextOnPath___CIIPathFFPaint(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, jint count, - jlong pathHandle, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + jlong pathHandle, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle, + jlong typefaceHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPath* path = reinterpret_cast<SkPath*>(pathHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); jchar* textArray = env->GetCharArrayElements(text, NULL); - TextLayout::drawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset, - path, canvas); + doDrawTextOnPath(paint, textArray + index, count, bidiFlags, hOffset, vOffset, + path, canvas, typeface); env->ReleaseCharArrayElements(text, textArray, 0); } static void drawTextOnPath__StringPathFFPaint(JNIEnv* env, jobject, jlong canvasHandle, jstring text, jlong pathHandle, - jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintHandle, + jlong typefaceHandle) { + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPath* path = reinterpret_cast<SkPath*>(pathHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + const jchar* text_ = env->GetStringChars(text, NULL); int count = env->GetStringLength(text); - TextLayout::drawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset, - path, canvas); + doDrawTextOnPath(paint, text_, count, bidiFlags, hOffset, vOffset, + path, canvas, typeface); env->ReleaseStringChars(text, text_); } @@ -1096,7 +1232,7 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l static jboolean getClipBounds(JNIEnv* env, jobject, jlong canvasHandle, jobject bounds) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkRect r; SkIRect ir; bool result = getHardClipBounds(canvas, &r); @@ -1112,7 +1248,7 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = getNativeCanvas(canvasHandle); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); *matrix = canvas->getTotalMatrix(); } @@ -1120,35 +1256,24 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l static JNINativeMethod gCanvasMethods[] = { {"finalizer", "(J)V", (void*) SkCanvasGlue::finalizer}, - {"initRaster","(J)J", (void*) SkCanvasGlue::initRaster}, - {"copyNativeCanvasState","(JJ)V", (void*) SkCanvasGlue::copyCanvasState}, - {"isOpaque","()Z", (void*) SkCanvasGlue::isOpaque}, - {"getWidth","()I", (void*) SkCanvasGlue::getWidth}, - {"getHeight","()I", (void*) SkCanvasGlue::getHeight}, - {"save","()I", (void*) SkCanvasGlue::saveAll}, - {"save","(I)I", (void*) SkCanvasGlue::save}, - {"native_saveLayer","(JLandroid/graphics/RectF;JI)I", - (void*) SkCanvasGlue::saveLayer}, - {"native_saveLayer","(JFFFFJI)I", (void*) SkCanvasGlue::saveLayer4F}, - {"native_saveLayerAlpha","(JLandroid/graphics/RectF;II)I", - (void*) SkCanvasGlue::saveLayerAlpha}, - {"native_saveLayerAlpha","(JFFFFII)I", - (void*) SkCanvasGlue::saveLayerAlpha4F}, - {"restore","()V", (void*) SkCanvasGlue::restore}, - {"getSaveCount","()I", (void*) SkCanvasGlue::getSaveCount}, - {"restoreToCount","(I)V", (void*) SkCanvasGlue::restoreToCount}, - {"translate","(FF)V", (void*) SkCanvasGlue::translate}, - {"scale","(FF)V", (void*) SkCanvasGlue::scale__FF}, - {"rotate","(F)V", (void*) SkCanvasGlue::rotate__F}, - {"skew","(FF)V", (void*) SkCanvasGlue::skew__FF}, + {"initRaster", "(J)J", (void*) SkCanvasGlue::initRaster}, + {"initCanvas", "(J)J", (void*) SkCanvasGlue::initCanvas}, + {"native_setBitmap", "(JJZ)V", (void*) SkCanvasGlue::setBitmap}, + {"native_isOpaque","(J)Z", (void*) SkCanvasGlue::isOpaque}, + {"native_getWidth","(J)I", (void*) SkCanvasGlue::getWidth}, + {"native_getHeight","(J)I", (void*) SkCanvasGlue::getHeight}, + {"native_save","(JI)I", (void*) SkCanvasGlue::save}, + {"native_saveLayer","(JFFFFJI)I", (void*) SkCanvasGlue::saveLayer}, + {"native_saveLayerAlpha","(JFFFFII)I", (void*) SkCanvasGlue::saveLayerAlpha}, + {"native_restore","(J)V", (void*) SkCanvasGlue::restore}, + {"native_getSaveCount","(J)I", (void*) SkCanvasGlue::getSaveCount}, + {"native_restoreToCount","(JI)V", (void*) SkCanvasGlue::restoreToCount}, + {"native_translate","(JFF)V", (void*) SkCanvasGlue::translate}, + {"native_scale","(JFF)V", (void*) SkCanvasGlue::scale__FF}, + {"native_rotate","(JF)V", (void*) SkCanvasGlue::rotate__F}, + {"native_skew","(JFF)V", (void*) SkCanvasGlue::skew__FF}, {"native_concat","(JJ)V", (void*) SkCanvasGlue::concat}, {"native_setMatrix","(JJ)V", (void*) SkCanvasGlue::setMatrix}, - {"clipRect","(FFFF)Z", (void*) SkCanvasGlue::clipRect_FFFF}, - {"clipRect","(IIII)Z", (void*) SkCanvasGlue::clipRect_IIII}, - {"clipRect","(Landroid/graphics/RectF;)Z", - (void*) SkCanvasGlue::clipRect_RectF}, - {"clipRect","(Landroid/graphics/Rect;)Z", - (void*) SkCanvasGlue::clipRect_Rect}, {"native_clipRect","(JFFFFI)Z", (void*) SkCanvasGlue::clipRect}, {"native_clipPath","(JJI)Z", (void*) SkCanvasGlue::clipPath}, {"native_clipRegion","(JJI)Z", (void*) SkCanvasGlue::clipRegion}, @@ -1156,8 +1281,6 @@ static JNINativeMethod gCanvasMethods[] = { {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) SkCanvasGlue::getClipBounds}, {"native_getCTM", "(JJ)V", (void*)SkCanvasGlue::getCTM}, - {"native_quickReject","(JLandroid/graphics/RectF;)Z", - (void*) SkCanvasGlue::quickReject__RectF}, {"native_quickReject","(JJ)Z", (void*) SkCanvasGlue::quickReject__Path}, {"native_quickReject","(JFFFF)Z", (void*)SkCanvasGlue::quickReject__FFFF}, {"native_drawRGB","(JIII)V", (void*) SkCanvasGlue::drawRGB}, @@ -1165,21 +1288,14 @@ static JNINativeMethod gCanvasMethods[] = { {"native_drawColor","(JI)V", (void*) SkCanvasGlue::drawColor__I}, {"native_drawColor","(JII)V", (void*) SkCanvasGlue::drawColor__II}, {"native_drawPaint","(JJ)V", (void*) SkCanvasGlue::drawPaint}, - {"drawPoint", "(FFLandroid/graphics/Paint;)V", - (void*) SkCanvasGlue::drawPoint}, - {"drawPoints", "([FIILandroid/graphics/Paint;)V", - (void*) SkCanvasGlue::drawPoints}, - {"drawLines", "([FIILandroid/graphics/Paint;)V", - (void*) SkCanvasGlue::drawLines}, + {"native_drawPoint", "(JFFJ)V", (void*) SkCanvasGlue::drawPoint}, + {"native_drawPoints", "(J[FIIJ)V", (void*) SkCanvasGlue::drawPoints}, + {"native_drawLines", "(J[FIIJ)V", (void*) SkCanvasGlue::drawLines}, {"native_drawLine","(JFFFFJ)V", (void*) SkCanvasGlue::drawLine__FFFFPaint}, - {"native_drawRect","(JLandroid/graphics/RectF;J)V", - (void*) SkCanvasGlue::drawRect__RectFPaint}, {"native_drawRect","(JFFFFJ)V", (void*) SkCanvasGlue::drawRect__FFFFPaint}, - {"native_drawOval","(JLandroid/graphics/RectF;J)V", - (void*) SkCanvasGlue::drawOval}, + {"native_drawOval","(JFFFFJ)V", (void*) SkCanvasGlue::drawOval}, {"native_drawCircle","(JFFFJ)V", (void*) SkCanvasGlue::drawCircle}, - {"native_drawArc","(JLandroid/graphics/RectF;FFZJ)V", - (void*) SkCanvasGlue::drawArc}, + {"native_drawArc","(JFFFFFFZJ)V", (void*) SkCanvasGlue::drawArc}, {"native_drawRoundRect","(JFFFFFFJ)V", (void*) SkCanvasGlue::drawRoundRect}, {"native_drawPath","(JJJ)V", (void*) SkCanvasGlue::drawPath}, @@ -1201,17 +1317,13 @@ static JNINativeMethod gCanvasMethods[] = { (void*) SkCanvasGlue::drawText___CIIFFIPaintTypeface}, {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) SkCanvasGlue::drawText__StringIIFFIPaintTypeface}, - {"native_drawTextRun","(J[CIIIIFFIJJ)V", - (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaintTypeface}, - {"native_drawTextRun","(JLjava/lang/String;IIIIFFIJJ)V", - (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaintTypeface}, - {"native_drawPosText","(J[CII[FJ)V", - (void*) SkCanvasGlue::drawPosText___CII_FPaint}, - {"native_drawPosText","(JLjava/lang/String;[FJ)V", - (void*) SkCanvasGlue::drawPosText__String_FPaint}, - {"native_drawTextOnPath","(J[CIIJFFIJ)V", + {"native_drawTextRun","(J[CIIIIFFZJJ)V", + (void*) SkCanvasGlue::drawTextRun___CIIIIFFZPaintTypeface}, + {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", + (void*) SkCanvasGlue::drawTextRun__StringIIIIFFZPaintTypeface}, + {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) SkCanvasGlue::drawTextOnPath___CIIPathFFPaint}, - {"native_drawTextOnPath","(JLjava/lang/String;JFFIJ)V", + {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) SkCanvasGlue::drawTextOnPath__StringPathFFPaint}, {"freeCaches", "()V", (void*) SkCanvasGlue::freeCaches}, @@ -1236,4 +1348,11 @@ int register_android_graphics_Canvas(JNIEnv* env) { return result; } +} // namespace android + +// GraphicsJNI helper for external clients. +// We keep the implementation here to avoid exposing NativeCanvasWrapper +// externally. +SkCanvas* GraphicsJNI::getNativeCanvas(jlong nativeHandle) { + return android::SkCanvasGlue::getNativeCanvas(nativeHandle); } diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp index fbfa2ec..3275875 100644 --- a/core/jni/android/graphics/DrawFilter.cpp +++ b/core/jni/android/graphics/DrawFilter.cpp @@ -30,6 +30,35 @@ namespace android { +// Custom version of SkPaintFlagsDrawFilter that also calls setFilterLevel. +class CompatFlagsDrawFilter : public SkPaintFlagsDrawFilter { +public: + CompatFlagsDrawFilter(uint32_t clearFlags, uint32_t setFlags, + SkPaint::FilterLevel desiredLevel) + : SkPaintFlagsDrawFilter(clearFlags, setFlags) + , fDesiredLevel(desiredLevel) { + } + + virtual bool filter(SkPaint* paint, Type type) { + SkPaintFlagsDrawFilter::filter(paint, type); + paint->setFilterLevel(fDesiredLevel); + return true; + } + +private: + const SkPaint::FilterLevel fDesiredLevel; +}; + +// Returns whether flags contains FILTER_BITMAP_FLAG. If flags does, remove it. +static inline bool hadFiltering(jint& flags) { + // Equivalent to the Java Paint's FILTER_BITMAP_FLAG. + static const uint32_t sFilterBitmapFlag = 0x02; + + const bool result = (flags & sFilterBitmapFlag) != 0; + flags &= ~sFilterBitmapFlag; + return result; +} + class SkDrawFilterGlue { public: @@ -40,12 +69,25 @@ public: static jlong CreatePaintFlagsDF(JNIEnv* env, jobject clazz, jint clearFlags, jint setFlags) { - // trim off any out-of-range bits - clearFlags &= SkPaint::kAllFlags; - setFlags &= SkPaint::kAllFlags; - if (clearFlags | setFlags) { - SkDrawFilter* filter = new SkPaintFlagsDrawFilter(clearFlags, setFlags); + // Mask both groups of flags to remove FILTER_BITMAP_FLAG, which no + // longer has a Skia equivalent flag (instead it corresponds to + // calling setFilterLevel), and keep track of which group(s), if + // any, had the flag set. + const bool turnFilteringOn = hadFiltering(setFlags); + const bool turnFilteringOff = hadFiltering(clearFlags); + + SkDrawFilter* filter; + if (turnFilteringOn) { + // Turning filtering on overrides turning it off. + filter = new CompatFlagsDrawFilter(clearFlags, setFlags, + SkPaint::kLow_FilterLevel); + } else if (turnFilteringOff) { + filter = new CompatFlagsDrawFilter(clearFlags, setFlags, + SkPaint::kNone_FilterLevel); + } else { + filter = new SkPaintFlagsDrawFilter(clearFlags, setFlags); + } return reinterpret_cast<jlong>(filter); } else { return NULL; diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index dce185d..2bd7a28 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -320,7 +320,7 @@ SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) { SkASSERT(canvas); SkASSERT(env->IsInstanceOf(canvas, gCanvas_class)); jlong canvasHandle = env->GetLongField(canvas, gCanvas_nativeInstanceID); - SkCanvas* c = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* c = getNativeCanvas(canvasHandle); SkASSERT(c); return c; } @@ -345,17 +345,6 @@ android::TypefaceImpl* GraphicsJNI::getNativeTypeface(JNIEnv* env, jobject paint return p; } -SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture) -{ - SkASSERT(env); - SkASSERT(picture); - SkASSERT(env->IsInstanceOf(picture, gPicture_class)); - jlong pictureHandle = env->GetLongField(picture, gPicture_nativeInstanceID); - SkPicture* p = reinterpret_cast<SkPicture*>(pictureHandle); - SkASSERT(p); - return p; -} - SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region) { SkASSERT(env); @@ -698,7 +687,7 @@ int register_android_graphics_Graphics(JNIEnv* env) "nativeInt", "I"); gCanvas_class = make_globalref(env, "android/graphics/Canvas"); - gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvas", "J"); + gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvasWrapper", "J"); gPaint_class = make_globalref(env, "android/graphics/Paint"); gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "J"); diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index db7b6d9..ad174f7 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -14,7 +14,6 @@ class SkBitmapRegionDecoder; class SkCanvas; class SkPaint; -class SkPicture; class GraphicsJNI { public: @@ -45,11 +44,11 @@ public: static SkPoint* jpointf_to_point(JNIEnv*, jobject jpointf, SkPoint* point); static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); + static SkCanvas* getNativeCanvas(jlong nativeHandle); static SkCanvas* getNativeCanvas(JNIEnv*, jobject canvas); static SkPaint* getNativePaint(JNIEnv*, jobject paint); static android::TypefaceImpl* getNativeTypeface(JNIEnv*, jobject paint); static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap); - static SkPicture* getNativePicture(JNIEnv*, jobject picture); static SkRegion* getNativeRegion(JNIEnv*, jobject region); // Given the 'native' long held by the Rasterizer.java object, return a diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp index 2113330..b394905 100644 --- a/core/jni/android/graphics/MaskFilter.cpp +++ b/core/jni/android/graphics/MaskFilter.cpp @@ -21,8 +21,7 @@ public: static jlong createBlur(JNIEnv* env, jobject, jfloat radius, jint blurStyle) { SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius); - SkMaskFilter* filter = SkBlurMaskFilter::Create( - (SkBlurMaskFilter::BlurStyle)blurStyle, sigma); + SkMaskFilter* filter = SkBlurMaskFilter::Create((SkBlurStyle)blurStyle, sigma); ThrowIAE_IfNull(env, filter); return reinterpret_cast<jlong>(filter); } diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp index a9360ea..fc92d53 100644 --- a/core/jni/android/graphics/MinikinUtils.cpp +++ b/core/jni/android/graphics/MinikinUtils.cpp @@ -19,6 +19,7 @@ #include <string> #include "SkPaint.h" +#include "SkPathMeasure.h" #include "minikin/Layout.h" #include "TypefaceImpl.h" #include "MinikinSkia.h" @@ -76,4 +77,20 @@ float MinikinUtils::xOffsetForTextAlign(SkPaint* paint, const Layout& layout) { return 0; } +float MinikinUtils::hOffsetForTextAlign(SkPaint* paint, const Layout& layout, const SkPath& path) { + float align = 0; + switch (paint->getTextAlign()) { + case SkPaint::kCenter_Align: + align = -0.5f; + break; + case SkPaint::kRight_Align: + align = -1; + break; + default: + return 0; + } + SkPathMeasure measure(path, false); + return align * (layout.getAdvance() - measure.getLength()); +} + } diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h index a96c6b1..b2662a1 100644 --- a/core/jni/android/graphics/MinikinUtils.h +++ b/core/jni/android/graphics/MinikinUtils.h @@ -36,6 +36,7 @@ public: static float xOffsetForTextAlign(SkPaint* paint, const Layout& layout); + static float hOffsetForTextAlign(SkPaint* paint, const Layout& layout, const SkPath& path); // f is a functor of type void f(size_t start, size_t end); template <typename F> static void forFontRun(const Layout& layout, SkPaint* paint, F& f) { diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp index 855d267..ab5bdb0 100644 --- a/core/jni/android/graphics/NinePatch.cpp +++ b/core/jni/android/graphics/NinePatch.cpp @@ -119,7 +119,7 @@ public: static void drawF(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRectF, jlong bitmapHandle, jlong chunkHandle, jlong paintHandle, jint destDensity, jint srcDensity) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle); const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); Res_png_9patch* chunk = reinterpret_cast<Res_png_9patch*>(chunkHandle); const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); @@ -138,7 +138,7 @@ public: static void drawI(JNIEnv* env, jobject, jlong canvasHandle, jobject boundsRect, jlong bitmapHandle, jlong chunkHandle, jlong paintHandle, jint destDensity, jint srcDensity) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); + SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle); const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); Res_png_9patch* chunk = reinterpret_cast<Res_png_9patch*>(chunkHandle); const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 8b11d31..dc30814 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -37,6 +37,7 @@ #include "TextLayout.h" #ifdef USE_MINIKIN +#include <minikin/GraphemeBreak.h> #include <minikin/Layout.h> #include "MinikinSkia.h" #include "MinikinUtils.h" @@ -707,7 +708,7 @@ public: } static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, TypefaceImpl* typeface, const jchar *text, - jint start, jint count, jint contextCount, jint flags, + jint start, jint count, jint contextCount, jboolean isRtl, jfloatArray advances, jint advancesIndex) { NPE_CHECK_RETURN_ZERO(env, paint); NPE_CHECK_RETURN_ZERO(env, text); @@ -729,14 +730,16 @@ public: jfloat* advancesArray = new jfloat[count]; jfloat totalAdvance = 0; + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; + #ifdef USE_MINIKIN Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface); + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); layout.doLayout(text, start, count, contextCount, css); layout.getAdvances(advancesArray); totalAdvance = layout.getAdvance(); #else - TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags, + TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, bidiFlags, advancesArray, &totalAdvance); #endif @@ -747,28 +750,28 @@ public: return totalAdvance; } - static jfloat getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, + static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text, jint index, jint count, jint contextIndex, jint contextCount, - jint flags, jfloatArray advances, jint advancesIndex) { + jboolean isRtl, jfloatArray advances, jint advancesIndex) { SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); jchar* textArray = env->GetCharArrayElements(text, NULL); jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex, - index - contextIndex, count, contextCount, flags, advances, advancesIndex); + index - contextIndex, count, contextCount, isRtl, advances, advancesIndex); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); return result; } - static jfloat getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, + static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, - jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags, + jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl, jfloatArray advances, jint advancesIndex) { SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); const jchar* textArray = env->GetStringChars(text, NULL); jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart, - start - contextStart, end - start, contextEnd - contextStart, flags, + start - contextStart, end - start, contextEnd - contextStart, isRtl, advances, advancesIndex); env->ReleaseStringChars(text, textArray); return result; @@ -776,6 +779,11 @@ public: static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start, jint count, jint flags, jint offset, jint opt) { +#ifdef USE_MINIKIN + GraphemeBreak::MoveOpt moveOpt = GraphemeBreak::MoveOpt(opt); + size_t result = GraphemeBreak::getTextRunCursor(text, start, count, offset, moveOpt); + return static_cast<jint>(result); +#else jfloat scalarArray[count]; TextLayout::getTextRunAdvances(paint, text, start, count, start + count, flags, @@ -816,24 +824,25 @@ public: } return pos; +#endif } static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text, - jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) { + jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) { SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); jchar* textArray = env->GetCharArrayElements(text, NULL); - jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags, + jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir, offset, cursorOpt); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); return result; } static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text, - jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) { + jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) { SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); const jchar* textArray = env->GetStringChars(text, NULL); jint result = doTextRunCursor(env, paint, textArray, contextStart, - contextEnd - contextStart, flags, offset, cursorOpt); + contextEnd - contextStart, dir, offset, cursorOpt); env->ReleaseStringChars(text, textArray); return result; } @@ -934,32 +943,62 @@ public: return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL); } - static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[], + static int breakText(JNIEnv* env, const SkPaint& paint, TypefaceImpl* typeface, const jchar text[], int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured, - SkPaint::TextBufferDirection tbd) { + SkPaint::TextBufferDirection textBufferDirection) { + size_t measuredCount = 0; + float measured = 0; + +#ifdef USE_MINIKIN + Layout layout; + std::string css = MinikinUtils::setLayoutProperties(&layout, &paint, bidiFlags, typeface); + layout.doLayout(text, 0, count, count, css); + float* advances = new float[count]; + layout.getAdvances(advances); + const bool forwardScan = (textBufferDirection == SkPaint::kForward_TextBufferDirection); + for (int i = 0; i < count; i++) { + // traverse in the given direction + int index = forwardScan ? i : (count - i - 1); + float width = advances[index]; + if (measured + width > maxWidth) { + break; + } + // properly handle clusters when scanning backwards + if (forwardScan || width != 0.0f) { + measuredCount = i + 1; + } + measured += width; + } + delete[] advances; +#else sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint, text, 0, count, count, bidiFlags); if (value == NULL) { return 0; } - SkScalar measured; - size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1, - maxWidth, &measured, tbd); + SkScalar m; + size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1, + maxWidth, &m, textBufferDirection); SkASSERT((bytes & 1) == 0); + measuredCount = bytes >> 1; + measured = SkScalarToFloat(m); +#endif if (jmeasured && env->GetArrayLength(jmeasured) > 0) { AutoJavaFloatArray autoMeasured(env, jmeasured, 1); jfloat* array = autoMeasured.ptr(); - array[0] = SkScalarToFloat(measured); + array[0] = measured; } - return bytes >> 1; + return measuredCount; } - static jint breakTextC(JNIEnv* env, jobject jpaint, jcharArray jtext, + static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext, jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) { - NPE_CHECK_RETURN_ZERO(env, jpaint); NPE_CHECK_RETURN_ZERO(env, jtext); + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + SkPaint::TextBufferDirection tbd; if (count < 0) { tbd = SkPaint::kBackward_TextBufferDirection; @@ -974,28 +1013,28 @@ public: return 0; } - SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); const jchar* text = env->GetCharArrayElements(jtext, NULL); - count = breakText(env, *paint, text + index, count, maxWidth, + count = breakText(env, *paint, typeface, text + index, count, maxWidth, bidiFlags, jmeasuredWidth, tbd); env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text), JNI_ABORT); return count; } - static jint breakTextS(JNIEnv* env, jobject jpaint, jstring jtext, + static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext, jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) { - NPE_CHECK_RETURN_ZERO(env, jpaint); NPE_CHECK_RETURN_ZERO(env, jtext); + SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + SkPaint::TextBufferDirection tbd = forwards ? SkPaint::kForward_TextBufferDirection : SkPaint::kBackward_TextBufferDirection; - SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint); int count = env->GetStringLength(jtext); const jchar* text = env->GetStringChars(jtext, NULL); - count = breakText(env, *paint, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd); + count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, tbd); env->ReleaseStringChars(jtext, text); return count; } @@ -1106,14 +1145,14 @@ static JNINativeMethod methods[] = { {"native_measureText","([CIII)F", (void*) SkPaintGlue::measureText_CIII}, {"native_measureText","(Ljava/lang/String;I)F", (void*) SkPaintGlue::measureText_StringI}, {"native_measureText","(Ljava/lang/String;III)F", (void*) SkPaintGlue::measureText_StringIII}, - {"native_breakText","([CIIFI[F)I", (void*) SkPaintGlue::breakTextC}, - {"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS}, + {"native_breakText","(JJ[CIIFI[F)I", (void*) SkPaintGlue::breakTextC}, + {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS}, {"native_getTextWidths","(JJ[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F}, {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F}, - {"native_getTextRunAdvances","(JJ[CIIIII[FI)F", - (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI}, - {"native_getTextRunAdvances","(JJLjava/lang/String;IIIII[FI)F", - (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI}, + {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F", + (void*) SkPaintGlue::getTextRunAdvances___CIIIIZ_FI}, + {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F", + (void*) SkPaintGlue::getTextRunAdvances__StringIIIIZ_FI}, {"native_getTextGlyphs","(JLjava/lang/String;IIIII[C)I", diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index 420a17f..6ef1d2c 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -2,22 +2,22 @@ ** ** Copyright 2006, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ // This file was generated from the C++ include file: SkPath.h // Any changes made to this file will be discarded by the build. -// To change this file, either edit the include, or device/tools/gluemaker/main.cpp, +// To change this file, either edit the include, or device/tools/gluemaker/main.cpp, // or one of the auxilary file specifications in device/tools/gluemaker. #include "jni.h" @@ -92,7 +92,7 @@ public: SkPath* obj = reinterpret_cast<SkPath*>(objHandle); return obj->isEmpty(); } - + static jboolean isRect(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect) { SkRect rect; SkPath* obj = reinterpret_cast<SkPath*>(objHandle); @@ -100,65 +100,66 @@ public: GraphicsJNI::rect_to_jrectf(rect, env, jrect); return result; } - + static void computeBounds(JNIEnv* env, jobject clazz, jlong objHandle, jobject jbounds) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); const SkRect& bounds = obj->getBounds(); GraphicsJNI::rect_to_jrectf(bounds, env, jbounds); } - + static void incReserve(JNIEnv* env, jobject clazz, jlong objHandle, jint extraPtCount) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->incReserve(extraPtCount); } - + static void moveTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->moveTo(x, y); } - + static void rMoveTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->rMoveTo(dx, dy); } - + static void lineTo__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x, jfloat y) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->lineTo(x, y); } - + static void rLineTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->rLineTo(dx, dy); } - + static void quadTo__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->quadTo(x1, y1, x2, y2); } - + static void rQuadTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx1, jfloat dy1, jfloat dx2, jfloat dy2) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->rQuadTo(dx1, dy1, dx2, dy2); } - + static void cubicTo__FFFFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->cubicTo(x1, y1, x2, y2, x3, y3); } - + static void rCubicTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat x1, jfloat y1, jfloat x2, jfloat y2, jfloat x3, jfloat y3) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->rCubicTo(x1, y1, x2, y2, x3, y3); } - - static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle, jboolean forceMoveTo) { + + static void arcTo(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, + jboolean forceMoveTo) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); - SkRect oval_; - GraphicsJNI::jrectf_to_rect(env, oval, &oval_); - obj->arcTo(oval_, startAngle, sweepAngle, forceMoveTo); + SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); + obj->arcTo(oval, startAngle, sweepAngle, forceMoveTo); } - + static void close(JNIEnv* env, jobject clazz, jlong objHandle) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->close(); @@ -185,28 +186,26 @@ public: obj->addCircle(x, y, radius, dir); } - static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jobject oval, jfloat startAngle, jfloat sweepAngle) { - SkRect oval_; + static void addArc(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle) { + SkRect oval = SkRect::MakeLTRB(left, top, right, bottom); SkPath* obj = reinterpret_cast<SkPath*>(objHandle); - GraphicsJNI::jrectf_to_rect(env, oval, &oval_); - obj->addArc(oval_, startAngle, sweepAngle); + obj->addArc(oval, startAngle, sweepAngle); } - static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jobject jrect, - jfloat rx, jfloat ry, jint dirHandle) { - SkRect rect; + static void addRoundRectXY(JNIEnv* env, jobject clazz, jlong objHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jfloat rx, jfloat ry, jint dirHandle) { + SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); SkPath* obj = reinterpret_cast<SkPath*>(objHandle); SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle); - GraphicsJNI::jrectf_to_rect(env, jrect, &rect); obj->addRoundRect(rect, rx, ry, dir); } - - static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jobject jrect, - jfloatArray array, jint dirHandle) { - SkRect rect; + + static void addRoundRect8(JNIEnv* env, jobject, jlong objHandle, jfloat left, jfloat top, + jfloat right, jfloat bottom, jfloatArray array, jint dirHandle) { + SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); SkPath* obj = reinterpret_cast<SkPath*>(objHandle); SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle); - GraphicsJNI::jrectf_to_rect(env, jrect, &rect); AutoJavaFloatArray afa(env, array, 8); #ifdef SK_SCALAR_IS_FLOAT const float* src = afa.ptr(); @@ -215,32 +214,32 @@ public: #endif obj->addRoundRect(rect, src, dir); } - + static void addPath__PathFF(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jfloat dx, jfloat dy) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); SkPath* src = reinterpret_cast<SkPath*>(srcHandle); obj->addPath(*src, dx, dy); } - + static void addPath__Path(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); SkPath* src = reinterpret_cast<SkPath*>(srcHandle); obj->addPath(*src); } - + static void addPath__PathMatrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong matrixHandle) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); SkPath* src = reinterpret_cast<SkPath*>(srcHandle); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); obj->addPath(*src, *matrix); } - + static void offset__FFPath(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy, jlong dstHandle) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); SkPath* dst = reinterpret_cast<SkPath*>(dstHandle); obj->offset(dx, dy, dst); } - + static void offset__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->offset(dx, dy); @@ -250,14 +249,14 @@ public: SkPath* obj = reinterpret_cast<SkPath*>(objHandle); obj->setLastPt(dx, dy); } - + static void transform__MatrixPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle, jlong dstHandle) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); SkPath* dst = reinterpret_cast<SkPath*>(dstHandle); obj->transform(*matrix, dst); } - + static void transform__Matrix(JNIEnv* env, jobject clazz, jlong objHandle, jlong matrixHandle) { SkPath* obj = reinterpret_cast<SkPath*>(objHandle); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); @@ -487,14 +486,14 @@ static JNINativeMethod methods[] = { {"native_rQuadTo","(JFFFF)V", (void*) SkPathGlue::rQuadTo}, {"native_cubicTo","(JFFFFFF)V", (void*) SkPathGlue::cubicTo__FFFFFF}, {"native_rCubicTo","(JFFFFFF)V", (void*) SkPathGlue::rCubicTo}, - {"native_arcTo","(JLandroid/graphics/RectF;FFZ)V", (void*) SkPathGlue::arcTo}, + {"native_arcTo","(JFFFFFFZ)V", (void*) SkPathGlue::arcTo}, {"native_close","(J)V", (void*) SkPathGlue::close}, {"native_addRect","(JFFFFI)V", (void*) SkPathGlue::addRect}, {"native_addOval","(JFFFFI)V", (void*) SkPathGlue::addOval}, {"native_addCircle","(JFFFI)V", (void*) SkPathGlue::addCircle}, - {"native_addArc","(JLandroid/graphics/RectF;FF)V", (void*) SkPathGlue::addArc}, - {"native_addRoundRect","(JLandroid/graphics/RectF;FFI)V", (void*) SkPathGlue::addRoundRectXY}, - {"native_addRoundRect","(JLandroid/graphics/RectF;[FI)V", (void*) SkPathGlue::addRoundRect8}, + {"native_addArc","(JFFFFFF)V", (void*) SkPathGlue::addArc}, + {"native_addRoundRect","(JFFFFFFI)V", (void*) SkPathGlue::addRoundRectXY}, + {"native_addRoundRect","(JFFFF[FI)V", (void*) SkPathGlue::addRoundRect8}, {"native_addPath","(JJFF)V", (void*) SkPathGlue::addPath__PathFF}, {"native_addPath","(JJ)V", (void*) SkPathGlue::addPath__Path}, {"native_addPath","(JJJ)V", (void*) SkPathGlue::addPath__PathMatrix}, diff --git a/core/jni/android/graphics/Picture.cpp b/core/jni/android/graphics/Picture.cpp index bac8ef7..bc0c25f 100644 --- a/core/jni/android/graphics/Picture.cpp +++ b/core/jni/android/graphics/Picture.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,125 +14,104 @@ * limitations under the License. */ -#include "jni.h" -#include "GraphicsJNI.h" -#include <android_runtime/AndroidRuntime.h> +#include "Picture.h" #include "SkCanvas.h" -#include "SkPicture.h" #include "SkStream.h" -#include "SkTemplates.h" -#include "CreateJavaOutputStreamAdaptor.h" namespace android { -class SkPictureGlue { -public: - static jlong newPicture(JNIEnv* env, jobject, jlong srcHandle) { - const SkPicture* src = reinterpret_cast<SkPicture*>(srcHandle); - if (src) { - return reinterpret_cast<jlong>(new SkPicture(*src)); - } else { - return reinterpret_cast<jlong>(new SkPicture); +Picture::Picture(const Picture* src) { + if (NULL != src) { + mWidth = src->width(); + mHeight = src->height(); + if (NULL != src->mPicture.get()) { + mPicture.reset(SkRef(src->mPicture.get())); + } if (NULL != src->mRecorder.get()) { + mPicture.reset(src->makePartialCopy()); } + } else { + mWidth = 0; + mHeight = 0; } +} - static jlong deserialize(JNIEnv* env, jobject, jobject jstream, - jbyteArray jstorage) { - SkPicture* picture = NULL; - SkStream* strm = CreateJavaInputStreamAdaptor(env, jstream, jstorage); - if (strm) { - picture = SkPicture::CreateFromStream(strm); - delete strm; - } - return reinterpret_cast<jlong>(picture); - } +SkCanvas* Picture::beginRecording(int width, int height) { + mPicture.reset(NULL); + mRecorder.reset(new SkPictureRecorder); + mWidth = width; + mHeight = height; + return mRecorder->beginRecording(width, height, NULL, 0); +} - static void killPicture(JNIEnv* env, jobject, jlong pictureHandle) { - SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle); - SkASSERT(picture); - picture->unref(); +void Picture::endRecording() { + if (NULL != mRecorder.get()) { + mPicture.reset(mRecorder->endRecording()); + mRecorder.reset(NULL); } +} - static void draw(JNIEnv* env, jobject, jlong canvasHandle, - jlong pictureHandle) { - SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasHandle); - SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle); - SkASSERT(canvas); - SkASSERT(picture); - picture->draw(canvas); +int Picture::width() const { + if (NULL != mPicture.get()) { + SkASSERT(mPicture->width() == mWidth); + SkASSERT(mPicture->height() == mHeight); } - static jboolean serialize(JNIEnv* env, jobject, jlong pictureHandle, - jobject jstream, jbyteArray jstorage) { - SkPicture* picture = reinterpret_cast<SkPicture*>(pictureHandle); - SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); - - if (NULL != strm) { - picture->serialize(strm); - delete strm; - return JNI_TRUE; - } - return JNI_FALSE; - } + return mWidth; +} - static jint getWidth(JNIEnv* env, jobject jpic) { - NPE_CHECK_RETURN_ZERO(env, jpic); - int width = GraphicsJNI::getNativePicture(env, jpic)->width(); - return static_cast<jint>(width); +int Picture::height() const { + if (NULL != mPicture.get()) { + SkASSERT(mPicture->width() == mWidth); + SkASSERT(mPicture->height() == mHeight); } - static jint getHeight(JNIEnv* env, jobject jpic) { - NPE_CHECK_RETURN_ZERO(env, jpic); - int height = GraphicsJNI::getNativePicture(env, jpic)->height(); - return static_cast<jint>(height); - } + return mHeight; +} - static jlong beginRecording(JNIEnv* env, jobject, jlong pictHandle, - jint w, jint h) { - SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle); - // beginRecording does not ref its return value, it just returns it. - SkCanvas* canvas = pict->beginRecording(w, h); - // the java side will wrap this guy in a Canvas.java, which will call - // unref in its finalizer, so we have to ref it here, so that both that - // Canvas.java and our picture can both be owners - canvas->ref(); - return reinterpret_cast<jlong>(canvas); - } +Picture* Picture::CreateFromStream(SkStream* stream) { + Picture* newPict = new Picture; - static void endRecording(JNIEnv* env, jobject, jlong pictHandle) { - SkPicture* pict = reinterpret_cast<SkPicture*>(pictHandle); - pict->endRecording(); + newPict->mPicture.reset(SkPicture::CreateFromStream(stream)); + if (NULL != newPict->mPicture.get()) { + newPict->mWidth = newPict->mPicture->width(); + newPict->mHeight = newPict->mPicture->height(); } -}; - -static JNINativeMethod gPictureMethods[] = { - {"getWidth", "()I", (void*) SkPictureGlue::getWidth}, - {"getHeight", "()I", (void*) SkPictureGlue::getHeight}, - {"nativeConstructor", "(J)J", (void*) SkPictureGlue::newPicture}, - {"nativeCreateFromStream", "(Ljava/io/InputStream;[B)J", (void*)SkPictureGlue::deserialize}, - {"nativeBeginRecording", "(JII)J", (void*) SkPictureGlue::beginRecording}, - {"nativeEndRecording", "(J)V", (void*) SkPictureGlue::endRecording}, - {"nativeDraw", "(JJ)V", (void*) SkPictureGlue::draw}, - {"nativeWriteToStream", "(JLjava/io/OutputStream;[B)Z", (void*)SkPictureGlue::serialize}, - {"nativeDestructor","(J)V", (void*) SkPictureGlue::killPicture} -}; -#include <android_runtime/AndroidRuntime.h> + return newPict; +} -#define REG(env, name, array) \ - result = android::AndroidRuntime::registerNativeMethods(env, name, array, \ - SK_ARRAY_COUNT(array)); \ - if (result < 0) return result +void Picture::serialize(SkWStream* stream) const { + if (NULL != mRecorder.get()) { + SkAutoTDelete<SkPicture> tempPict(this->makePartialCopy()); + tempPict->serialize(stream); + } else if (NULL != mPicture.get()) { + mPicture->serialize(stream); + } else { + SkPicture empty; + empty.serialize(stream); + } +} -int register_android_graphics_Picture(JNIEnv* env) { - int result; +void Picture::draw(SkCanvas* canvas) { + if (NULL != mRecorder.get()) { + this->endRecording(); + SkASSERT(NULL != mPicture.get()); + } + if (NULL != mPicture.get()) { + // TODO: remove this const_cast once pictures are immutable + const_cast<SkPicture*>(mPicture.get())->draw(canvas); + } +} - REG(env, "android/graphics/Picture", gPictureMethods); +SkPicture* Picture::makePartialCopy() const { + SkASSERT(NULL != mRecorder.get()); - return result; -} + SkPictureRecorder reRecorder; + SkCanvas* canvas = reRecorder.beginRecording(mWidth, mHeight, NULL, 0); + mRecorder->partialReplay(canvas); + return reRecorder.endRecording(); } - +}; // namespace android diff --git a/core/jni/android/graphics/Picture.h b/core/jni/android/graphics/Picture.h new file mode 100644 index 0000000..abb0403 --- /dev/null +++ b/core/jni/android/graphics/Picture.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GRAPHICS_PICTURE_H +#define ANDROID_GRAPHICS_PICTURE_H + +#include "SkPicture.h" +#include "SkPictureRecorder.h" +#include "SkRefCnt.h" +#include "SkTemplates.h" + +class SkCanvas; +class SkPicture; +class SkPictureRecorder; +class SkStream; +class SkWStream; + +namespace android { + +// Skia's SkPicture class has been split into an SkPictureRecorder +// and an SkPicture. AndroidPicture recreates the functionality +// of the old SkPicture interface by flip-flopping between the two +// new classes. +class Picture { +public: + explicit Picture(const Picture* src = NULL); + + SkCanvas* beginRecording(int width, int height); + + void endRecording(); + + int width() const; + + int height() const; + + static Picture* CreateFromStream(SkStream* stream); + + void serialize(SkWStream* stream) const; + + void draw(SkCanvas* canvas); + +private: + int mWidth; + int mHeight; + SkAutoTUnref<const SkPicture> mPicture; + SkAutoTDelete<SkPictureRecorder> mRecorder; + + // Make a copy of a picture that is in the midst of being recorded. The + // resulting picture will have balanced saves and restores. + SkPicture* makePartialCopy() const; +}; + +}; // namespace android +#endif // ANDROID_GRAPHICS_PICTURE_H diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp index d54aaa8..3812c27 100644 --- a/core/jni/android/graphics/pdf/PdfDocument.cpp +++ b/core/jni/android/graphics/pdf/PdfDocument.cpp @@ -24,6 +24,7 @@ #include "SkCanvas.h" #include "SkDocument.h" #include "SkPicture.h" +#include "SkPictureRecorder.h" #include "SkStream.h" #include "SkRect.h" @@ -32,15 +33,22 @@ namespace android { struct PageRecord { PageRecord(int width, int height, const SkRect& contentRect) - : mPicture(new SkPicture()), mWidth(width), mHeight(height) { + : mPictureRecorder(new SkPictureRecorder()) + , mPicture(NULL) + , mWidth(width) + , mHeight(height) { mContentRect = contentRect; } ~PageRecord() { - mPicture->unref(); + delete mPictureRecorder; + if (NULL != mPicture) { + mPicture->unref(); + } } - SkPicture* const mPicture; + SkPictureRecorder* mPictureRecorder; + SkPicture* mPicture; const int mWidth; const int mHeight; SkRect mContentRect; @@ -62,8 +70,8 @@ public: mPages.push_back(page); mCurrentPage = page; - SkCanvas* canvas = page->mPicture->beginRecording( - contentRect.width(), contentRect.height(), 0); + SkCanvas* canvas = page->mPictureRecorder->beginRecording( + contentRect.width(), contentRect.height(), NULL, 0); // We pass this canvas to Java where it is used to construct // a Java Canvas object which dereferences the pointer when it @@ -75,7 +83,11 @@ public: void finishPage() { assert(mCurrentPage != NULL); - mCurrentPage->mPicture->endRecording(); + assert(mCurrentPage->mPictureRecorder != NULL); + assert(mCurrentPage->mPicture == NULL); + mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->endRecording(); + delete mCurrentPage->mPictureRecorder; + mCurrentPage->mPictureRecorder = NULL; mCurrentPage = NULL; } @@ -89,7 +101,7 @@ public: canvas->clipRect(page->mContentRect); canvas->translate(page->mContentRect.left(), page->mContentRect.top()); - canvas->drawPicture(*page->mPicture); + canvas->drawPicture(page->mPicture); document->endPage(); } @@ -97,11 +109,10 @@ public: } void close() { + assert(NULL == mCurrentPage); for (unsigned i = 0; i < mPages.size(); i++) { delete mPages[i]; } - delete mCurrentPage; - mCurrentPage = NULL; } private: diff --git a/core/jni/android_graphics_Picture.cpp b/core/jni/android_graphics_Picture.cpp new file mode 100644 index 0000000..f827907 --- /dev/null +++ b/core/jni/android_graphics_Picture.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "jni.h" +#include "GraphicsJNI.h" +#include <android_runtime/AndroidRuntime.h> + +#include "Picture.h" + +#include "SkCanvas.h" +#include "SkStream.h" +#include "SkTemplates.h" +#include "CreateJavaOutputStreamAdaptor.h" + +namespace android { + +static jlong android_graphics_Picture_newPicture(JNIEnv* env, jobject, jlong srcHandle) { + const Picture* src = reinterpret_cast<Picture*>(srcHandle); + return reinterpret_cast<jlong>(new Picture(src)); +} + +static jlong android_graphics_Picture_deserialize(JNIEnv* env, jobject, jobject jstream, + jbyteArray jstorage) { + Picture* picture = NULL; + SkStream* strm = CreateJavaInputStreamAdaptor(env, jstream, jstorage); + if (strm) { + picture = Picture::CreateFromStream(strm); + delete strm; + } + return reinterpret_cast<jlong>(picture); +} + +static void android_graphics_Picture_killPicture(JNIEnv* env, jobject, jlong pictureHandle) { + Picture* picture = reinterpret_cast<Picture*>(pictureHandle); + SkASSERT(picture); + delete picture; +} + +static void android_graphics_Picture_draw(JNIEnv* env, jobject, jlong canvasHandle, + jlong pictureHandle) { + SkCanvas* canvas = GraphicsJNI::getNativeCanvas(canvasHandle); + Picture* picture = reinterpret_cast<Picture*>(pictureHandle); + SkASSERT(canvas); + SkASSERT(picture); + picture->draw(canvas); +} + +static jboolean android_graphics_Picture_serialize(JNIEnv* env, jobject, jlong pictureHandle, + jobject jstream, jbyteArray jstorage) { + Picture* picture = reinterpret_cast<Picture*>(pictureHandle); + SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); + + if (NULL != strm) { + picture->serialize(strm); + delete strm; + return JNI_TRUE; + } + return JNI_FALSE; +} + +static jint android_graphics_Picture_getWidth(JNIEnv* env, jobject, jlong pictureHandle) { + Picture* pict = reinterpret_cast<Picture*>(pictureHandle); + return static_cast<jint>(pict->width()); +} + +static jint android_graphics_Picture_getHeight(JNIEnv* env, jobject, jlong pictureHandle) { + Picture* pict = reinterpret_cast<Picture*>(pictureHandle); + return static_cast<jint>(pict->height()); +} + +static jlong android_graphics_Picture_beginRecording(JNIEnv* env, jobject, jlong pictHandle, + jint w, jint h) { + Picture* pict = reinterpret_cast<Picture*>(pictHandle); + // beginRecording does not ref its return value, it just returns it. + SkCanvas* canvas = pict->beginRecording(w, h); + // the java side will wrap this guy in a Canvas.java, which will call + // unref in its finalizer, so we have to ref it here, so that both that + // Canvas.java and our picture can both be owners + canvas->ref(); + return reinterpret_cast<jlong>(canvas); +} + +static void android_graphics_Picture_endRecording(JNIEnv* env, jobject, jlong pictHandle) { + Picture* pict = reinterpret_cast<Picture*>(pictHandle); + pict->endRecording(); +} + +static JNINativeMethod gMethods[] = { + {"nativeGetWidth", "(J)I", (void*) android_graphics_Picture_getWidth}, + {"nativeGetHeight", "(J)I", (void*) android_graphics_Picture_getHeight}, + {"nativeConstructor", "(J)J", (void*) android_graphics_Picture_newPicture}, + {"nativeCreateFromStream", "(Ljava/io/InputStream;[B)J", (void*)android_graphics_Picture_deserialize}, + {"nativeBeginRecording", "(JII)J", (void*) android_graphics_Picture_beginRecording}, + {"nativeEndRecording", "(J)V", (void*) android_graphics_Picture_endRecording}, + {"nativeDraw", "(JJ)V", (void*) android_graphics_Picture_draw}, + {"nativeWriteToStream", "(JLjava/io/OutputStream;[B)Z", (void*)android_graphics_Picture_serialize}, + {"nativeDestructor","(J)V", (void*) android_graphics_Picture_killPicture} +}; + +int register_android_graphics_Picture(JNIEnv* env) { + return AndroidRuntime::registerNativeMethods(env, "android/graphics/Picture", gMethods, NELEM(gMethods)); +} + +}; // namespace android diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 3a53331..f8bab24 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -36,6 +36,11 @@ using namespace android; +enum { + // Keep up to date with Camera.java + CAMERA_HAL_API_VERSION_NORMAL_CONNECT = -2, +}; + struct fields_t { jfieldID context; jfieldID facing; @@ -466,7 +471,7 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, // connect to camera service static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, - jobject weak_this, jint cameraId, jstring clientPackageName) + jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName) { // Convert jstring to String16 const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL); @@ -474,8 +479,18 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, String16 clientName(rawClientName, rawClientNameLen); env->ReleaseStringChars(clientPackageName, rawClientName); - sp<Camera> camera = Camera::connect(cameraId, clientName, - Camera::USE_CALLING_UID); + sp<Camera> camera; + if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) { + // Default path: hal version is don't care, do normal camera connect. + camera = Camera::connect(cameraId, clientName, + Camera::USE_CALLING_UID); + } else { + jint status = Camera::connectLegacy(cameraId, halVersion, clientName, + Camera::USE_CALLING_UID, camera); + if (status != NO_ERROR) { + return status; + } + } if (camera == NULL) { return -EACCES; @@ -510,7 +525,6 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, // finalizer is invoked later. static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) { - // TODO: Change to ALOGV ALOGV("release camera"); JNICameraContext* context = NULL; sp<Camera> camera; @@ -891,7 +905,7 @@ static JNINativeMethod camMethods[] = { "(ILandroid/hardware/Camera$CameraInfo;)V", (void*)android_hardware_Camera_getCameraInfo }, { "native_setup", - "(Ljava/lang/Object;ILjava/lang/String;)I", + "(Ljava/lang/Object;IILjava/lang/String;)I", (void*)android_hardware_Camera_native_setup }, { "native_release", "()V", diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index fcf8f83..c588942 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -51,6 +51,8 @@ struct SensorOffsets jfieldID fifoMaxEventCount; jfieldID stringType; jfieldID requiredPermission; + jfieldID maxDelay; + jfieldID flags; } gSensorOffsets; @@ -78,6 +80,8 @@ nativeClassInit (JNIEnv *_env, jclass _this) sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;"); sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission", "Ljava/lang/String;"); + sensorOffsets.maxDelay = _env->GetFieldID(sensorClass, "mMaxDelay", "I"); + sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags", "I"); } static jint @@ -112,6 +116,8 @@ nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next) env->SetObjectField(sensor, sensorOffsets.stringType, stringType); env->SetObjectField(sensor, sensorOffsets.requiredPermission, requiredPermission); + env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay()); + env->SetIntField(sensor, sensorOffsets.flags, list->getFlags()); next++; return size_t(next) < count ? next : 0; } @@ -160,7 +166,8 @@ private: ASensorEvent buffer[16]; while ((n = q->read(buffer, 16)) > 0) { for (int i=0 ; i<n ; i++) { - if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) { + if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER || + buffer[i].type == SENSOR_TYPE_WAKE_UP_STEP_COUNTER) { // step-counter returns a uint64, but the java API only deals with floats float value = float(buffer[i].u64.step_counter); env->SetFloatArrayRegion(mScratch, 0, 1, &value); @@ -175,11 +182,26 @@ private: gBaseEventQueueClassInfo.dispatchFlushCompleteEvent, buffer[i].meta_data.sensor); } else { + int8_t status; + switch (buffer[i].type) { + case SENSOR_TYPE_ORIENTATION: + case SENSOR_TYPE_MAGNETIC_FIELD: + case SENSOR_TYPE_ACCELEROMETER: + case SENSOR_TYPE_GYROSCOPE: + status = buffer[i].vector.status; + break; + case SENSOR_TYPE_HEART_RATE: + status = buffer[i].heart_rate.status; + break; + default: + status = SENSOR_STATUS_ACCURACY_HIGH; + break; + } env->CallVoidMethod(mReceiverObject, gBaseEventQueueClassInfo.dispatchSensorEvent, buffer[i].sensor, mScratch, - buffer[i].vector.status, + status, buffer[i].timestamp); } if (env->ExceptionCheck()) { diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp new file mode 100644 index 0000000..69e991d --- /dev/null +++ b/core/jni/android_hardware_SoundTrigger.cpp @@ -0,0 +1,661 @@ +/* +** +** Copyright 2014, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoundTrigger-JNI" +#include <utils/Log.h> + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" +#include <system/sound_trigger.h> +#include <soundtrigger/SoundTriggerCallback.h> +#include <soundtrigger/SoundTrigger.h> +#include <utils/RefBase.h> +#include <utils/Vector.h> +#include <binder/IMemory.h> +#include <binder/MemoryDealer.h> + +using namespace android; + +static jclass gArrayListClass; +static struct { + jmethodID add; +} gArrayListMethods; + +static const char* const kSoundTriggerClassPathName = "android/hardware/soundtrigger/SoundTrigger"; +static jclass gSoundTriggerClass; + +static const char* const kModuleClassPathName = "android/hardware/soundtrigger/SoundTriggerModule"; +static jclass gModuleClass; +static struct { + jfieldID mNativeContext; + jfieldID mId; +} gModuleFields; +static jmethodID gPostEventFromNative; + +static const char* const kModulePropertiesClassPathName = + "android/hardware/soundtrigger/SoundTrigger$ModuleProperties"; +static jclass gModulePropertiesClass; +static jmethodID gModulePropertiesCstor; + +static const char* const kSoundModelClassPathName = + "android/hardware/soundtrigger/SoundTrigger$SoundModel"; +static jclass gSoundModelClass; +static struct { + jfieldID data; +} gSoundModelFields; + +static const char* const kKeyPhraseClassPathName = + "android/hardware/soundtrigger/SoundTrigger$KeyPhrase"; +static jclass gKeyPhraseClass; +static struct { + jfieldID recognitionModes; + jfieldID locale; + jfieldID text; + jfieldID numUsers; +} gKeyPhraseFields; + +static const char* const kKeyPhraseSoundModelClassPathName = + "android/hardware/soundtrigger/SoundTrigger$KeyPhraseSoundModel"; +static jclass gKeyPhraseSoundModelClass; +static struct { + jfieldID keyPhrases; +} gKeyPhraseSoundModelFields; + + +static const char* const kRecognitionEventClassPathName = + "android/hardware/soundtrigger/SoundTrigger$RecognitionEvent"; +static jclass gRecognitionEventClass; +static jmethodID gRecognitionEventCstor; + +static const char* const kKeyPhraseRecognitionEventClassPathName = + "android/hardware/soundtrigger/SoundTrigger$KeyPhraseRecognitionEvent"; +static jclass gKeyPhraseRecognitionEventClass; +static jmethodID gKeyPhraseRecognitionEventCstor; + +static const char* const kKeyPhraseRecognitionExtraClassPathName = + "android/hardware/soundtrigger/SoundTrigger$KeyPhraseRecognitionExtra"; +static jclass gKeyPhraseRecognitionExtraClass; +static jmethodID gKeyPhraseRecognitionExtraCstor; + +static Mutex gLock; + +enum { + SOUNDTRIGGER_STATUS_OK = 0, + SOUNDTRIGGER_STATUS_ERROR = INT_MIN, + SOUNDTRIGGER_PERMISSION_DENIED = -1, + SOUNDTRIGGER_STATUS_NO_INIT = -19, + SOUNDTRIGGER_STATUS_BAD_VALUE = -22, + SOUNDTRIGGER_STATUS_DEAD_OBJECT = -32, + SOUNDTRIGGER_INVALID_OPERATION = -38, +}; + +enum { + SOUNDTRIGGER_EVENT_RECOGNITION = 1, + SOUNDTRIGGER_EVENT_SERVICE_DIED = 2, +}; + +// ---------------------------------------------------------------------------- +// ref-counted object for callbacks +class JNISoundTriggerCallback: public SoundTriggerCallback +{ +public: + JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz); + ~JNISoundTriggerCallback(); + + virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event); + virtual void onServiceDied(); + +private: + jclass mClass; // Reference to SoundTrigger class + jobject mObject; // Weak ref to SoundTrigger Java object to call on +}; + +JNISoundTriggerCallback::JNISoundTriggerCallback(JNIEnv* env, jobject thiz, jobject weak_thiz) +{ + + // Hold onto the SoundTriggerModule class for use in calling the static method + // that posts events to the application thread. + jclass clazz = env->GetObjectClass(thiz); + if (clazz == NULL) { + ALOGE("Can't find class %s", kModuleClassPathName); + return; + } + mClass = (jclass)env->NewGlobalRef(clazz); + + // We use a weak reference so the SoundTriggerModule object can be garbage collected. + // The reference is only used as a proxy for callbacks. + mObject = env->NewGlobalRef(weak_thiz); +} + +JNISoundTriggerCallback::~JNISoundTriggerCallback() +{ + // remove global references + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->DeleteGlobalRef(mObject); + env->DeleteGlobalRef(mClass); +} + +void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognition_event *event) +{ + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + jobject jEvent; + + jbyteArray jData = NULL; + if (event->data_size) { + jData = env->NewByteArray(event->data_size); + jbyte *nData = env->GetByteArrayElements(jData, NULL); + memcpy(nData, (char *)event + event->data_offset, event->data_size); + env->ReleaseByteArrayElements(jData, nData, 0); + } + + if (event->type == SOUND_MODEL_TYPE_KEYPHRASE) { + struct sound_trigger_phrase_recognition_event *phraseEvent = + (struct sound_trigger_phrase_recognition_event *)event; + + jobjectArray jExtras = env->NewObjectArray(phraseEvent->num_phrases, + gKeyPhraseRecognitionExtraClass, NULL); + if (jExtras == NULL) { + return; + } + + for (size_t i = 0; i < phraseEvent->num_phrases; i++) { + jintArray jConfidenceLevels = env->NewIntArray(phraseEvent->phrase_extras[i].num_users); + if (jConfidenceLevels == NULL) { + return; + } + jint *nConfidenceLevels = env->GetIntArrayElements(jConfidenceLevels, NULL); + memcpy(nConfidenceLevels, + phraseEvent->phrase_extras[i].confidence_levels, + phraseEvent->phrase_extras[i].num_users * sizeof(int)); + env->ReleaseIntArrayElements(jConfidenceLevels, nConfidenceLevels, 0); + jobject jNewExtra = env->NewObject(gKeyPhraseRecognitionExtraClass, + gKeyPhraseRecognitionExtraCstor, + jConfidenceLevels, + phraseEvent->phrase_extras[i].recognition_modes); + + if (jNewExtra == NULL) { + return; + } + env->SetObjectArrayElement(jExtras, i, jNewExtra); + + } + jEvent = env->NewObject(gKeyPhraseRecognitionEventClass, gKeyPhraseRecognitionEventCstor, + event->status, event->model, event->capture_available, + event->capture_session, event->capture_delay_ms, jData, + phraseEvent->key_phrase_in_capture, jExtras); + } else { + jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor, + event->status, event->model, event->capture_available, + event->capture_session, event->capture_delay_ms, jData); + } + + + env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject, + SOUNDTRIGGER_EVENT_RECOGNITION, 0, 0, jEvent); + if (env->ExceptionCheck()) { + ALOGW("An exception occurred while notifying an event."); + env->ExceptionClear(); + } +} + +void JNISoundTriggerCallback::onServiceDied() +{ + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject, + SOUNDTRIGGER_EVENT_SERVICE_DIED, 0, 0, NULL); + if (env->ExceptionCheck()) { + ALOGW("An exception occurred while notifying an event."); + env->ExceptionClear(); + } +} + +// ---------------------------------------------------------------------------- + +static sp<SoundTrigger> getSoundTrigger(JNIEnv* env, jobject thiz) +{ + Mutex::Autolock l(gLock); + SoundTrigger* const st = (SoundTrigger*)env->GetLongField(thiz, + gModuleFields.mNativeContext); + return sp<SoundTrigger>(st); +} + +static sp<SoundTrigger> setSoundTrigger(JNIEnv* env, jobject thiz, const sp<SoundTrigger>& module) +{ + Mutex::Autolock l(gLock); + sp<SoundTrigger> old = (SoundTrigger*)env->GetLongField(thiz, + gModuleFields.mNativeContext); + if (module.get()) { + module->incStrong((void*)setSoundTrigger); + } + if (old != 0) { + old->decStrong((void*)setSoundTrigger); + } + env->SetLongField(thiz, gModuleFields.mNativeContext, (jlong)module.get()); + return old; +} + + +static jint +android_hardware_SoundTrigger_listModules(JNIEnv *env, jobject clazz, + jobject jModules) +{ + ALOGV("listModules"); + + if (jModules == NULL) { + ALOGE("listModules NULL AudioPatch ArrayList"); + return SOUNDTRIGGER_STATUS_BAD_VALUE; + } + if (!env->IsInstanceOf(jModules, gArrayListClass)) { + ALOGE("listModules not an arraylist"); + return SOUNDTRIGGER_STATUS_BAD_VALUE; + } + + unsigned int numModules = 0; + struct sound_trigger_module_descriptor *nModules = NULL; + + status_t status = SoundTrigger::listModules(nModules, &numModules); + if (status != NO_ERROR || numModules == 0) { + return (jint)status; + } + + nModules = (struct sound_trigger_module_descriptor *) + calloc(numModules, sizeof(struct sound_trigger_module_descriptor)); + + status = SoundTrigger::listModules(nModules, &numModules); + ALOGV("listModules SoundTrigger::listModules status %d numModules %d", status, numModules); + + if (status != NO_ERROR) { + numModules = 0; + } + + for (size_t i = 0; i < numModules; i++) { + char str[SOUND_TRIGGER_MAX_STRING_LEN]; + + jstring implementor = env->NewStringUTF(nModules[i].properties.implementor); + jstring description = env->NewStringUTF(nModules[i].properties.description); + SoundTrigger::guidToString(&nModules[i].properties.uuid, + str, + SOUND_TRIGGER_MAX_STRING_LEN); + jstring uuid = env->NewStringUTF(str); + + ALOGV("listModules module %d id %d description %s maxSoundModels %d", + i, nModules[i].handle, nModules[i].properties.description, + nModules[i].properties.max_sound_models); + + jobject newModuleDesc = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor, + nModules[i].handle, + implementor, description, uuid, + nModules[i].properties.version, + nModules[i].properties.max_sound_models, + nModules[i].properties.max_key_phrases, + nModules[i].properties.max_users, + nModules[i].properties.recognition_modes, + nModules[i].properties.capture_transition, + nModules[i].properties.max_buffer_ms, + nModules[i].properties.concurrent_capture, + nModules[i].properties.power_consumption_mw); + + env->DeleteLocalRef(implementor); + env->DeleteLocalRef(description); + env->DeleteLocalRef(uuid); + if (newModuleDesc == NULL) { + status = SOUNDTRIGGER_STATUS_ERROR; + goto exit; + } + env->CallBooleanMethod(jModules, gArrayListMethods.add, newModuleDesc); + } + +exit: + free(nModules); + return (jint) status; +} + +static void +android_hardware_SoundTrigger_setup(JNIEnv *env, jobject thiz, jobject weak_this) +{ + ALOGV("setup"); + + sp<JNISoundTriggerCallback> callback = new JNISoundTriggerCallback(env, thiz, weak_this); + + sound_trigger_module_handle_t handle = + (sound_trigger_module_handle_t)env->GetIntField(thiz, gModuleFields.mId); + + sp<SoundTrigger> module = SoundTrigger::attach(handle, callback); + if (module == 0) { + return; + } + + setSoundTrigger(env, thiz, module); +} + +static void +android_hardware_SoundTrigger_detach(JNIEnv *env, jobject thiz) +{ + ALOGV("detach"); + sp<SoundTrigger> module = setSoundTrigger(env, thiz, 0); + ALOGV("detach module %p", module.get()); + if (module != 0) { + ALOGV("detach module->detach()"); + module->detach(); + } +} + +static void +android_hardware_SoundTrigger_finalize(JNIEnv *env, jobject thiz) +{ + ALOGV("finalize"); + sp<SoundTrigger> module = getSoundTrigger(env, thiz); + if (module != 0) { + ALOGW("SoundTrigger finalized without being detached"); + } + android_hardware_SoundTrigger_detach(env, thiz); +} + +static jint +android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz, + jobject jSoundModel, jintArray jHandle) +{ + jint status = SOUNDTRIGGER_STATUS_OK; + char *nData = NULL; + struct sound_trigger_sound_model *nSoundModel; + jbyteArray jData; + sp<MemoryDealer> memoryDealer; + sp<IMemory> memory; + size_t size; + sound_model_handle_t handle; + + ALOGV("loadSoundModel"); + sp<SoundTrigger> module = getSoundTrigger(env, thiz); + if (module == NULL) { + return SOUNDTRIGGER_STATUS_ERROR; + } + if (jHandle == NULL) { + return SOUNDTRIGGER_STATUS_BAD_VALUE; + } + jsize jHandleLen = env->GetArrayLength(jHandle); + if (jHandleLen == 0) { + return SOUNDTRIGGER_STATUS_BAD_VALUE; + } + jint *nHandle = env->GetIntArrayElements(jHandle, NULL); + if (nHandle == NULL) { + return SOUNDTRIGGER_STATUS_ERROR; + } + if (!env->IsInstanceOf(jSoundModel, gSoundModelClass)) { + status = SOUNDTRIGGER_STATUS_BAD_VALUE; + goto exit; + } + size_t offset; + sound_trigger_sound_model_type_t type; + if (env->IsInstanceOf(jSoundModel, gKeyPhraseSoundModelClass)) { + offset = sizeof(struct sound_trigger_phrase_sound_model); + type = SOUND_MODEL_TYPE_KEYPHRASE; + } else { + offset = sizeof(struct sound_trigger_sound_model); + type = SOUND_MODEL_TYPE_UNKNOWN; + } + jData = (jbyteArray)env->GetObjectField(jSoundModel, gSoundModelFields.data); + if (jData == NULL) { + status = SOUNDTRIGGER_STATUS_BAD_VALUE; + goto exit; + } + size = env->GetArrayLength(jData); + + nData = (char *)env->GetByteArrayElements(jData, NULL); + if (jData == NULL) { + status = SOUNDTRIGGER_STATUS_ERROR; + goto exit; + } + + memoryDealer = new MemoryDealer(offset + size, "SoundTrigge-JNI::LoadModel"); + if (memoryDealer == 0) { + status = SOUNDTRIGGER_STATUS_ERROR; + goto exit; + } + memory = memoryDealer->allocate(offset + size); + if (memory == 0 || memory->pointer() == NULL) { + status = SOUNDTRIGGER_STATUS_ERROR; + goto exit; + } + + nSoundModel = (struct sound_trigger_sound_model *)memory->pointer(); + + nSoundModel->type = type; + nSoundModel->data_size = size; + nSoundModel->data_offset = offset; + memcpy((char *)nSoundModel + offset, nData, size); + if (type == SOUND_MODEL_TYPE_KEYPHRASE) { + struct sound_trigger_phrase_sound_model *phraseModel = + (struct sound_trigger_phrase_sound_model *)nSoundModel; + + jobjectArray jPhrases = + (jobjectArray)env->GetObjectField(jSoundModel, gKeyPhraseSoundModelFields.keyPhrases); + if (jPhrases == NULL) { + status = SOUNDTRIGGER_STATUS_BAD_VALUE; + goto exit; + } + + size_t numPhrases = env->GetArrayLength(jPhrases); + phraseModel->num_phrases = numPhrases; + ALOGV("loadSoundModel numPhrases %d", numPhrases); + for (size_t i = 0; i < numPhrases; i++) { + jobject jPhrase = env->GetObjectArrayElement(jPhrases, i); + phraseModel->phrases[i].recognition_mode = + env->GetIntField(jPhrase,gKeyPhraseFields.recognitionModes); + phraseModel->phrases[i].num_users = + env->GetIntField(jPhrase, gKeyPhraseFields.numUsers); + jstring jLocale = (jstring)env->GetObjectField(jPhrase, gKeyPhraseFields.locale); + const char *nLocale = env->GetStringUTFChars(jLocale, NULL); + strncpy(phraseModel->phrases[i].locale, + nLocale, + SOUND_TRIGGER_MAX_LOCALE_LEN); + jstring jText = (jstring)env->GetObjectField(jPhrase, gKeyPhraseFields.text); + const char *nText = env->GetStringUTFChars(jText, NULL); + strncpy(phraseModel->phrases[i].text, + nText, + SOUND_TRIGGER_MAX_STRING_LEN); + + env->ReleaseStringUTFChars(jLocale, nLocale); + env->DeleteLocalRef(jLocale); + env->ReleaseStringUTFChars(jText, nText); + env->DeleteLocalRef(jText); + ALOGV("loadSoundModel phrases %d text %s locale %s", + i, phraseModel->phrases[i].text, phraseModel->phrases[i].locale); + } + env->DeleteLocalRef(jPhrases); + } + status = module->loadSoundModel(memory, &handle); + ALOGV("loadSoundModel status %d handle %d", status, handle); + +exit: + if (nHandle != NULL) { + nHandle[0] = (jint)handle; + env->ReleaseIntArrayElements(jHandle, nHandle, NULL); + } + if (nData != NULL) { + env->ReleaseByteArrayElements(jData, (jbyte *)nData, NULL); + } + return status; +} + +static jint +android_hardware_SoundTrigger_unloadSoundModel(JNIEnv *env, jobject thiz, + jint jHandle) +{ + jint status = SOUNDTRIGGER_STATUS_OK; + ALOGV("unloadSoundModel"); + sp<SoundTrigger> module = getSoundTrigger(env, thiz); + if (module == NULL) { + return SOUNDTRIGGER_STATUS_ERROR; + } + status = module->unloadSoundModel((sound_model_handle_t)jHandle); + + return status; +} + +static jint +android_hardware_SoundTrigger_startRecognition(JNIEnv *env, jobject thiz, + jint jHandle, jbyteArray jData) +{ + jint status = SOUNDTRIGGER_STATUS_OK; + ALOGV("startRecognition"); + sp<SoundTrigger> module = getSoundTrigger(env, thiz); + if (module == NULL) { + return SOUNDTRIGGER_STATUS_ERROR; + } + jsize dataSize = 0; + char *nData = NULL; + sp<IMemory> memory; + if (jData != NULL) { + dataSize = env->GetArrayLength(jData); + if (dataSize == 0) { + return SOUNDTRIGGER_STATUS_BAD_VALUE; + } + nData = (char *)env->GetByteArrayElements(jData, NULL); + if (nData == NULL) { + return SOUNDTRIGGER_STATUS_ERROR; + } + sp<MemoryDealer> memoryDealer = + new MemoryDealer(dataSize, "SoundTrigge-JNI::StartRecognition"); + if (memoryDealer == 0) { + return SOUNDTRIGGER_STATUS_ERROR; + } + memory = memoryDealer->allocate(dataSize); + if (memory == 0 || memory->pointer() == NULL) { + return SOUNDTRIGGER_STATUS_ERROR; + } + memcpy(memory->pointer(), nData, dataSize); + } + + status = module->startRecognition(jHandle, memory); + return status; +} + +static jint +android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz, + jint jHandle) +{ + jint status = SOUNDTRIGGER_STATUS_OK; + ALOGV("stopRecognition"); + sp<SoundTrigger> module = getSoundTrigger(env, thiz); + if (module == NULL) { + return SOUNDTRIGGER_STATUS_ERROR; + } + status = module->stopRecognition(jHandle); + return status; +} + +static JNINativeMethod gMethods[] = { + {"listModules", + "(Ljava/util/ArrayList;)I", + (void *)android_hardware_SoundTrigger_listModules}, +}; + + +static JNINativeMethod gModuleMethods[] = { + {"native_setup", + "(Ljava/lang/Object;)V", + (void *)android_hardware_SoundTrigger_setup}, + {"native_finalize", + "()V", + (void *)android_hardware_SoundTrigger_finalize}, + {"detach", + "()V", + (void *)android_hardware_SoundTrigger_detach}, + {"loadSoundModel", + "(Landroid/hardware/soundtrigger/SoundTrigger$SoundModel;[I)I", + (void *)android_hardware_SoundTrigger_loadSoundModel}, + {"unloadSoundModel", + "(I)I", + (void *)android_hardware_SoundTrigger_unloadSoundModel}, + {"startRecognition", + "(I[B)I", + (void *)android_hardware_SoundTrigger_startRecognition}, + {"stopRecognition", + "(I)I", + (void *)android_hardware_SoundTrigger_stopRecognition}, +}; + +int register_android_hardware_SoundTrigger(JNIEnv *env) +{ + jclass arrayListClass = env->FindClass("java/util/ArrayList"); + gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass); + gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); + + jclass lClass = env->FindClass(kSoundTriggerClassPathName); + gSoundTriggerClass = (jclass) env->NewGlobalRef(lClass); + + jclass moduleClass = env->FindClass(kModuleClassPathName); + gModuleClass = (jclass) env->NewGlobalRef(moduleClass); + gPostEventFromNative = env->GetStaticMethodID(moduleClass, "postEventFromNative", + "(Ljava/lang/Object;IIILjava/lang/Object;)V"); + gModuleFields.mNativeContext = env->GetFieldID(moduleClass, "mNativeContext", "J"); + gModuleFields.mId = env->GetFieldID(moduleClass, "mId", "I"); + + + jclass modulePropertiesClass = env->FindClass(kModulePropertiesClassPathName); + gModulePropertiesClass = (jclass) env->NewGlobalRef(modulePropertiesClass); + gModulePropertiesCstor = env->GetMethodID(modulePropertiesClass, "<init>", + "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZI)V"); + + jclass soundModelClass = env->FindClass(kSoundModelClassPathName); + gSoundModelClass = (jclass) env->NewGlobalRef(soundModelClass); + gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B"); + + jclass keyPhraseClass = env->FindClass(kKeyPhraseClassPathName); + gKeyPhraseClass = (jclass) env->NewGlobalRef(keyPhraseClass); + gKeyPhraseFields.recognitionModes = env->GetFieldID(keyPhraseClass, "recognitionModes", "I"); + gKeyPhraseFields.locale = env->GetFieldID(keyPhraseClass, "locale", "Ljava/lang/String;"); + gKeyPhraseFields.text = env->GetFieldID(keyPhraseClass, "text", "Ljava/lang/String;"); + gKeyPhraseFields.numUsers = env->GetFieldID(keyPhraseClass, "numUsers", "I"); + + jclass keyPhraseSoundModelClass = env->FindClass(kKeyPhraseSoundModelClassPathName); + gKeyPhraseSoundModelClass = (jclass) env->NewGlobalRef(keyPhraseSoundModelClass); + gKeyPhraseSoundModelFields.keyPhrases = env->GetFieldID(keyPhraseSoundModelClass, + "keyPhrases", + "[Landroid/hardware/soundtrigger/SoundTrigger$KeyPhrase;"); + + + jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName); + gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass); + gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>", + "(IIZII[B)V"); + + jclass keyPhraseRecognitionEventClass = env->FindClass(kKeyPhraseRecognitionEventClassPathName); + gKeyPhraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyPhraseRecognitionEventClass); + gKeyPhraseRecognitionEventCstor = env->GetMethodID(keyPhraseRecognitionEventClass, "<init>", + "(IIZII[BZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyPhraseRecognitionExtra;)V"); + + + jclass keyPhraseRecognitionExtraClass = env->FindClass(kKeyPhraseRecognitionExtraClassPathName); + gKeyPhraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyPhraseRecognitionExtraClass); + gKeyPhraseRecognitionExtraCstor = env->GetMethodID(keyPhraseRecognitionExtraClass, "<init>", + "([II)V"); + + int status = AndroidRuntime::registerNativeMethods(env, + kSoundTriggerClassPathName, gMethods, NELEM(gMethods)); + + if (status == 0) { + status = AndroidRuntime::registerNativeMethods(env, + kModuleClassPathName, gModuleMethods, NELEM(gModuleMethods)); + } + + return status; +} diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index 40e9544..57058a6 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "Legacy-CameraDevice-JNI" +// #define LOG_NDEBUG 0 #include <utils/Log.h> #include <utils/Errors.h> #include <utils/Trace.h> @@ -26,6 +27,7 @@ #include <ui/GraphicBuffer.h> #include <system/window.h> +#include <hardware/camera3.h> using namespace android; @@ -35,6 +37,8 @@ using namespace android; #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) +#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) + /** * Convert from RGB 888 to Y'CbCr using the conversion specified in ITU-R BT.601 for * digital RGB with K_b = 0.114, and K_r = 0.299. @@ -116,8 +120,9 @@ static status_t configureSurface(const sp<ANativeWindow>& anw, return err; } - ALOGV("%s: Setting buffer count to %d", __FUNCTION__, - maxBufferSlack + 1 + minUndequeuedBuffers); + ALOGV("%s: Setting buffer count to %d, size to (%dx%d), fmt (0x%x)", __FUNCTION__, + maxBufferSlack + 1 + minUndequeuedBuffers, + width, height, pixelFmt); err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers); if (err != NO_ERROR) { ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__, @@ -146,16 +151,41 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, int32_t width, // Width of the pixelBuffer int32_t height, // Height of the pixelBuffer int32_t pixelFmt, // Format of the pixelBuffer - int64_t bufSize) { + int32_t bufSize) { ATRACE_CALL(); status_t err = NO_ERROR; ANativeWindowBuffer* anb; - ALOGV("%s: Dequeue buffer from %p",__FUNCTION__, anw.get()); + ALOGV("%s: Dequeue buffer from %p %dx%d (fmt=%x, size=%x)", + __FUNCTION__, anw.get(), width, height, pixelFmt, bufSize); + + if (anw == 0) { + ALOGE("%s: anw must not be NULL", __FUNCTION__); + return BAD_VALUE; + } else if (pixelBuffer == NULL) { + ALOGE("%s: pixelBuffer must not be NULL", __FUNCTION__); + return BAD_VALUE; + } else if (width < 0) { + ALOGE("%s: width must be non-negative", __FUNCTION__); + return BAD_VALUE; + } else if (height < 0) { + ALOGE("%s: height must be non-negative", __FUNCTION__); + return BAD_VALUE; + } else if (bufSize < 0) { + ALOGE("%s: bufSize must be non-negative", __FUNCTION__); + return BAD_VALUE; + } + + if (width < 0 || height < 0 || bufSize < 0) { + ALOGE("%s: Illegal argument, negative dimension passed to produceFrame", __FUNCTION__); + return BAD_VALUE; + } // TODO: Switch to using Surface::lock and Surface::unlockAndPost err = native_window_dequeue_buffer_and_wait(anw.get(), &anb); if (err != NO_ERROR) return err; + // TODO: check anb is large enough to store the results + sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false)); switch(pixelFmt) { @@ -181,6 +211,41 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, uPlane, vPlane, chromaStep, yStride, chromaStride); break; } + case HAL_PIXEL_FORMAT_YV12: { + if (bufSize < width * height * 4) { + ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__, + bufSize); + return BAD_VALUE; + } + + if ((width & 1) || (height & 1)) { + ALOGE("%s: Dimens %dx%d are not divisible by 2.", __FUNCTION__, width, height); + return BAD_VALUE; + } + + uint8_t* img = NULL; + ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); + err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + if (err != NO_ERROR) { + ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__, + strerror(-err), err); + return err; + } + + uint32_t stride = buf->getStride(); + LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride); + + uint32_t cStride = ALIGN(stride / 2, 16); + size_t chromaStep = 1; + + uint8_t* yPlane = img; + uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride; + uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2; + + rgbToYuv420(pixelBuffer, width, height, yPlane, + crPlane, cbPlane, chromaStep, stride, cStride); + break; + } case HAL_PIXEL_FORMAT_YCbCr_420_888: { // Software writes with YCbCr_420_888 format are unsupported // by the gralloc module for now @@ -215,7 +280,12 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, err); return err; } + struct camera3_jpeg_blob footer = { + jpeg_blob_id: CAMERA3_JPEG_BLOB_ID, + jpeg_size: (uint32_t)width + }; memcpy(img, pixelBuffer, width); + memcpy(img + anb->width - sizeof(footer), &footer, sizeof(footer)); break; } default: { diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h index a2b1ed9..807dd32 100644 --- a/core/jni/android_media_AudioFormat.h +++ b/core/jni/android_media_AudioFormat.h @@ -20,11 +20,15 @@ #include <system/audio.h> // keep these values in sync with AudioFormat.java -#define ENCODING_PCM_16BIT 2 -#define ENCODING_PCM_8BIT 3 -#define ENCODING_PCM_FLOAT 4 -#define ENCODING_INVALID 0 -#define ENCODING_DEFAULT 1 +#define ENCODING_PCM_16BIT 2 +#define ENCODING_PCM_8BIT 3 +#define ENCODING_PCM_FLOAT 4 +#define ENCODING_AC3 5 +#define ENCODING_E_AC3 6 +#define ENCODING_INVALID 0 +#define ENCODING_DEFAULT 1 + + #define CHANNEL_INVALID 0 #define CHANNEL_OUT_DEFAULT 1 @@ -38,6 +42,10 @@ static inline audio_format_t audioFormatToNative(int audioFormat) return AUDIO_FORMAT_PCM_8_BIT; case ENCODING_PCM_FLOAT: return AUDIO_FORMAT_PCM_FLOAT; + case ENCODING_AC3: + return AUDIO_FORMAT_AC3; + case ENCODING_E_AC3: + return AUDIO_FORMAT_E_AC3; case ENCODING_DEFAULT: return AUDIO_FORMAT_DEFAULT; default: @@ -54,6 +62,10 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat) return ENCODING_PCM_8BIT; case AUDIO_FORMAT_PCM_FLOAT: return ENCODING_PCM_FLOAT; + case AUDIO_FORMAT_AC3: + return ENCODING_AC3; + case AUDIO_FORMAT_E_AC3: + return ENCODING_E_AC3; case AUDIO_FORMAT_DEFAULT: return ENCODING_DEFAULT; default: diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index bf47dd3..849531c 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -244,6 +244,12 @@ android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source) } static jint +android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz) +{ + return AudioSystem::newAudioSessionId(); +} + +static jint android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs) { const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0); @@ -281,6 +287,8 @@ android_media_AudioSystem_error_callback(status_t err) env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), check_AudioSystem_Command(err)); + + env->DeleteLocalRef(clazz); } static jint @@ -1295,6 +1303,7 @@ static JNINativeMethod gMethods[] = { {"isStreamActive", "(II)Z", (void *)android_media_AudioSystem_isStreamActive}, {"isStreamActiveRemotely","(II)Z", (void *)android_media_AudioSystem_isStreamActiveRemotely}, {"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive}, + {"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId}, {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState}, {"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState}, {"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState}, diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index e548e91..264a9ae 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -220,8 +220,13 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, } // compute the frame count - const size_t bytesPerSample = audio_bytes_per_sample(format); - size_t frameCount = buffSizeInBytes / (channelCount * bytesPerSample); + size_t frameCount; + if (audio_is_linear_pcm(format)) { + const size_t bytesPerSample = audio_bytes_per_sample(format); + frameCount = buffSizeInBytes / (channelCount * bytesPerSample); + } else { + frameCount = buffSizeInBytes; + } jclass clazz = env->GetObjectClass(thiz); if (clazz == NULL) { @@ -266,7 +271,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, format,// word length, PCM nativeChannelMask, frameCount, - AUDIO_OUTPUT_FLAG_NONE, + audio_is_linear_pcm(format) ? AUDIO_OUTPUT_FLAG_NONE : AUDIO_OUTPUT_FLAG_DIRECT, audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user) 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack 0,// shared mem @@ -478,14 +483,6 @@ jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const jbyte* da switch (format) { default: - // TODO Currently the only possible values for format are AUDIO_FORMAT_PCM_16_BIT, - // AUDIO_FORMAT_PCM_8_BIT, and AUDIO_FORMAT_PCM_FLOAT, - // due to the limited set of values for audioFormat. - // The next section of the switch will probably work for more formats, but it has only - // been tested for AUDIO_FORMAT_PCM_16_BIT and AUDIO_FORMAT_PCM_FLOAT, - // so that's why the "default" case fails. - break; - case AUDIO_FORMAT_PCM_FLOAT: case AUDIO_FORMAT_PCM_16_BIT: { // writing to shared memory, check for capacity @@ -904,8 +901,12 @@ static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thi return -1; } const audio_format_t format = audioFormatToNative(audioFormat); - const size_t bytesPerSample = audio_bytes_per_sample(format); - return frameCount * channelCount * bytesPerSample; + if (audio_is_linear_pcm(format)) { + const size_t bytesPerSample = audio_bytes_per_sample(format); + return frameCount * channelCount * bytesPerSample; + } else { + return frameCount; + } } // ---------------------------------------------------------------------------- diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 86207f0..87ee618 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -174,21 +174,21 @@ static int read_memtrack_memory(struct memtrack_proc* p, int pid, ssize_t pss = memtrack_proc_graphics_pss(p); if (pss < 0) { - ALOGW("failed to get graphics pss: %d", pss); + ALOGW("failed to get graphics pss: %zd", pss); return pss; } graphics_mem->graphics = pss / 1024; pss = memtrack_proc_gl_pss(p); if (pss < 0) { - ALOGW("failed to get gl pss: %d", pss); + ALOGW("failed to get gl pss: %zd", pss); return pss; } graphics_mem->gl = pss / 1024; pss = memtrack_proc_other_pss(p); if (pss < 0) { - ALOGW("failed to get other pss: %d", pss); + ALOGW("failed to get other pss: %zd", pss); return pss; } graphics_mem->other = pss / 1024; @@ -231,9 +231,9 @@ static void read_mapinfo(FILE *fp, stats_t* stats) unsigned referenced = 0; unsigned temp; - unsigned long int start; - unsigned long int end = 0; - unsigned long int prevEnd = 0; + uint64_t start; + uint64_t end = 0; + uint64_t prevEnd = 0; char* name; int name_pos; @@ -255,7 +255,7 @@ static void read_mapinfo(FILE *fp, stats_t* stats) if (len < 1) return; line[--len] = 0; - if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) { + if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) { skip = true; } else { while (isspace(line[name_pos])) { @@ -371,7 +371,7 @@ static void read_mapinfo(FILE *fp, stats_t* stats) referenced = temp; } else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) { swapped_out = temp; - } else if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') { + } else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) { // looks like a new mapping // example: "10000000-10001000 ---p 10000000 00:00 0" break; diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp index f8a1fd9..b174d1b 100644 --- a/core/jni/android_server_FingerprintManager.cpp +++ b/core/jni/android_server_FingerprintManager.cpp @@ -20,54 +20,185 @@ #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> +#include <hardware/hardware.h> +#include <hardware/fingerprint.h> #include <utils/Log.h> +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ + var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find static method" methodName); + +#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ + var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find method" methodName); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + namespace android { +static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(1, 0); + +static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService"; static struct { jclass clazz; jmethodID notify; -} gFingerprintManagerClassInfo; + jobject callbackObject; +} gFingerprintServiceClassInfo; + +static struct { + fingerprint_module_t const* module; + fingerprint_device_t *device; +} gContext; + +// Called by the HAL to notify us of fingerprint events +static void hal_notify_callback(fingerprint_msg_t msg) { + uint32_t arg1 = 0; + uint32_t arg2 = 0; + uint32_t arg3 = 0; // TODO + switch (msg.type) { + case FINGERPRINT_ERROR: + arg1 = msg.data.error; + break; + case FINGERPRINT_ACQUIRED: + arg1 = msg.data.acquired.acquired_info; + break; + case FINGERPRINT_PROCESSED: + arg1 = msg.data.processed.id; + break; + case FINGERPRINT_TEMPLATE_ENROLLING: + arg1 = msg.data.enroll.id; + arg2 = msg.data.enroll.samples_remaining; + arg3 = msg.data.enroll.data_collected_bmp; + break; + case FINGERPRINT_TEMPLATE_REMOVED: + arg1 = msg.data.removed.id; + break; + default: + ALOGE("fingerprint: invalid msg: %d", msg.type); + return; + } + //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2); + + // TODO: fix gross hack to attach JNI to calling thread + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (env == NULL) { + JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL}; + JavaVM* vm = AndroidRuntime::getJavaVM(); + int result = vm->AttachCurrentThread(&env, (void*) &args); + if (result != JNI_OK) { + ALOGE("Can't call JNI method: attach failed: %#x", result); + return; + } + } + env->CallVoidMethod(gFingerprintServiceClassInfo.callbackObject, + gFingerprintServiceClassInfo.notify, msg.type, arg1, arg2); +} + +static void nativeInit(JNIEnv *env, jobject clazz, jobject callbackObj) { + ALOG(LOG_VERBOSE, LOG_TAG, "nativeInit()\n"); + FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE); + GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz, + "notify", "(III)V"); + gFingerprintServiceClassInfo.callbackObject = env->NewGlobalRef(callbackObj); +} static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) { - return -1; // TODO + ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n"); + int ret = gContext.device->enroll(gContext.device, timeout); + return reinterpret_cast<jint>(ret); +} + +static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) { + ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnrollCancel()\n"); + int ret = gContext.device->enroll_cancel(gContext.device); + return reinterpret_cast<jint>(ret); } static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) { - return -1; // TODO + ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId); + int ret = gContext.device->remove(gContext.device, fingerprintId); + return reinterpret_cast<jint>(ret); +} + +static jint nativeOpenHal(JNIEnv* env, jobject clazz) { + ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n"); + int err; + const hw_module_t *hw_module = NULL; + if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) { + ALOGE("Can't open fingerprint HW Module, error: %d", err); + return 0; + } + if (NULL == hw_module) { + ALOGE("No valid fingerprint module"); + return 0; + } + + gContext.module = reinterpret_cast<const fingerprint_module_t*>(hw_module); + + if (gContext.module->common.methods->open == NULL) { + ALOGE("No valid open method"); + return 0; + } + + hw_device_t *device = NULL; + + if (0 != (err = gContext.module->common.methods->open(hw_module, NULL, &device))) { + ALOGE("Can't open fingerprint methods, error: %d", err); + return 0; + } + + if (kVersion != device->version) { + ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version); + // return 0; // FIXME + } + + gContext.device = reinterpret_cast<fingerprint_device_t*>(device); + err = gContext.device->set_notify(gContext.device, hal_notify_callback); + if (err < 0) { + ALOGE("Failed in call to set_notify(), err=%d", err); + return 0; + } + + // Sanity check - remove + if (gContext.device->notify != hal_notify_callback) { + ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback); + } + + ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized"); + return reinterpret_cast<jlong>(gContext.device); +} + +static jint nativeCloseHal(JNIEnv* env, jobject clazz) { + return -ENOSYS; // TODO } // ---------------------------------------------------------------------------- +// TODO: clean up void methods static const JNINativeMethod g_methods[] = { { "nativeEnroll", "(I)I", (void*)nativeEnroll }, + { "nativeEnrollCancel", "()I", (void*)nativeEnroll }, { "nativeRemove", "(I)I", (void*)nativeRemove }, + { "nativeOpenHal", "()I", (void*)nativeOpenHal }, + { "nativeCloseHal", "()I", (void*)nativeCloseHal }, + { "nativeInit", "(Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit } }; -#define FIND_CLASS(var, className) \ - var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); \ - var = jclass(env->NewGlobalRef(var)); - -#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ - var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \ - LOG_FATAL_IF(! var, "Unable to find static method" methodName); - -#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ - var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ - LOG_FATAL_IF(! var, "Unable to find method" methodName); - -#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ - var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ - LOG_FATAL_IF(! var, "Unable to find field " fieldName); - -int register_android_server_FingerprintManager(JNIEnv* env) { - FIND_CLASS(gFingerprintManagerClassInfo.clazz, - "android/service/fingerprint/FingerprintManager"); - GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz, - "notify", "(III)V"); - return AndroidRuntime::registerNativeMethods( - env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods)); +int register_android_server_fingerprint_FingerprintService(JNIEnv* env) { + FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE); + GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz, "notify", + "(III)V"); + int result = AndroidRuntime::registerNativeMethods( + env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods)); + ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n"); + return result; } } // namespace android diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 01f4d3a..a6b65cc 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -45,6 +45,8 @@ #define POLICY_DEBUG 0 #define GUARD_THREAD_PRIORITY 0 +#define DEBUG_PROC(x) //x + using namespace android; #if GUARD_THREAD_PRIORITY @@ -725,6 +727,7 @@ jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz, const char term = (char)(mode&PROC_TERM_MASK); const jsize start = i; if (i >= endIndex) { + DEBUG_PROC(ALOGW("Ran off end of data @%d", i)); res = JNI_FALSE; break; } @@ -822,19 +825,20 @@ jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz, return JNI_FALSE; } int fd = open(file8, O_RDONLY); - env->ReleaseStringUTFChars(file, file8); if (fd < 0) { - //ALOGW("Unable to open process file: %s\n", file8); + DEBUG_PROC(ALOGW("Unable to open process file: %s\n", file8)); + env->ReleaseStringUTFChars(file, file8); return JNI_FALSE; } + env->ReleaseStringUTFChars(file, file8); char buffer[256]; const int len = read(fd, buffer, sizeof(buffer)-1); close(fd); if (len < 0) { - //ALOGW("Unable to open process file: %s fd=%d\n", file8, fd); + DEBUG_PROC(ALOGW("Unable to open process file: %s fd=%d\n", file8, fd)); return JNI_FALSE; } buffer[len] = 0; diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index d032cb6..2a1fd1b 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -20,15 +20,10 @@ #include "GraphicsJNI.h" #include <nativehelper/JNIHelp.h> -#include "android_view_GraphicBuffer.h" - #include <android_runtime/AndroidRuntime.h> -#include <android_runtime/android_graphics_SurfaceTexture.h> #include <androidfw/ResourceTypes.h> -#include <gui/GLConsumer.h> - #include <private/hwui/DrawGlInfo.h> #include <cutils/properties.h> @@ -37,15 +32,13 @@ #include <SkCanvas.h> #include <SkMatrix.h> #include <SkPaint.h> +#include <SkPorterDuff.h> #include <SkRegion.h> #include <SkScalerContext.h> #include <SkTemplates.h> #include <SkXfermode.h> #include <DisplayListRenderer.h> -#include <LayerRenderer.h> -#include <OpenGLRenderer.h> -#include <Stencil.h> #include <Rect.h> #include <RenderNode.h> #include <CanvasProperty.h> @@ -64,7 +57,7 @@ namespace android { using namespace uirenderer; /** - * Note: OpenGLRenderer JNI layer is generated and compiled only on supported + * Note: DisplayListRenderer JNI layer is generated and compiled only on supported * devices. This means all the logic must be compiled only when the * preprocessor variable USE_OPENGL_RENDERER is defined. */ @@ -91,57 +84,13 @@ static struct { } gRectClassInfo; // ---------------------------------------------------------------------------- -// Caching -// ---------------------------------------------------------------------------- - -static void android_view_GLES20Canvas_flushCaches(JNIEnv* env, jobject clazz, - jint mode) { - if (Caches::hasInstance()) { - Caches::getInstance().flush(static_cast<Caches::FlushMode>(mode)); - } -} - -static jboolean android_view_GLES20Canvas_initCaches(JNIEnv* env, jobject clazz) { - if (Caches::hasInstance()) { - return Caches::getInstance().init() ? JNI_TRUE : JNI_FALSE; - } - return JNI_FALSE; -} - -static void android_view_GLES20Canvas_terminateCaches(JNIEnv* env, jobject clazz) { - if (Caches::hasInstance()) { - Caches::getInstance().terminate(); - } -} - -// ---------------------------------------------------------------------------- -// Caching -// ---------------------------------------------------------------------------- - -static void android_view_GLES20Canvas_initAtlas(JNIEnv* env, jobject clazz, - jobject graphicBuffer, jlongArray atlasMapArray, jint count) { - - sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer); - jlong* jAtlasMap = env->GetLongArrayElements(atlasMapArray, NULL); - Caches::getInstance().assetAtlas.init(buffer, jAtlasMap, count); - env->ReleaseLongArrayElements(atlasMapArray, jAtlasMap, 0); -} - -// ---------------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------------- -static jlong android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject clazz) { - RENDERER_LOGD("Create OpenGLRenderer"); - OpenGLRenderer* renderer = new OpenGLRenderer(); - renderer->initProperties(); - return reinterpret_cast<jlong>(renderer); -} - static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject clazz, jlong rendererPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - RENDERER_LOGD("Destroy OpenGLRenderer"); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); + RENDERER_LOGD("Destroy DisplayListRenderer"); delete renderer; } @@ -151,33 +100,29 @@ static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject clazz static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject clazz, jlong rendererPtr, jint width, jint height) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->setViewport(width, height); } static int android_view_GLES20Canvas_prepare(JNIEnv* env, jobject clazz, jlong rendererPtr, jboolean opaque) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); return renderer->prepare(opaque); } static int android_view_GLES20Canvas_prepareDirty(JNIEnv* env, jobject clazz, jlong rendererPtr, jint left, jint top, jint right, jint bottom, jboolean opaque) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); return renderer->prepareDirty(left, top, right, bottom, opaque); } static void android_view_GLES20Canvas_finish(JNIEnv* env, jobject clazz, jlong rendererPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->finish(); } -static jint android_view_GLES20Canvas_getStencilSize(JNIEnv* env, jobject clazz) { - return Stencil::getStencilSize(); -} - static void android_view_GLES20Canvas_setProperty(JNIEnv* env, jobject clazz, jstring name, jstring value) { if (!Caches::hasInstance()) { @@ -202,7 +147,7 @@ static void android_view_GLES20Canvas_setProperty(JNIEnv* env, static jint android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong functorPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); Functor* functor = reinterpret_cast<Functor*>(functorPtr); android::uirenderer::Rect dirty; return renderer->callDrawGLFunction(functor, dirty); @@ -226,25 +171,25 @@ static jint android_view_GLES20Canvas_getMaxTextureHeight(JNIEnv* env, jobject c static jint android_view_GLES20Canvas_save(JNIEnv* env, jobject clazz, jlong rendererPtr, jint flags) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); return renderer->save(flags); } static jint android_view_GLES20Canvas_getSaveCount(JNIEnv* env, jobject clazz, jlong rendererPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); return renderer->getSaveCount(); } static void android_view_GLES20Canvas_restore(JNIEnv* env, jobject clazz, jlong rendererPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->restore(); } static void android_view_GLES20Canvas_restoreToCount(JNIEnv* env, jobject clazz, jlong rendererPtr, jint saveCount) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->restoreToCount(saveCount); } @@ -255,14 +200,14 @@ static void android_view_GLES20Canvas_restoreToCount(JNIEnv* env, jobject clazz, static jint android_view_GLES20Canvas_saveLayer(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom, jlong paintPtr, jint saveFlags) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); return renderer->saveLayer(left, top, right, bottom, paint, saveFlags); } static jint android_view_GLES20Canvas_saveLayerClip(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong paintPtr, jint saveFlags) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds()); return renderer->saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, @@ -272,13 +217,13 @@ static jint android_view_GLES20Canvas_saveLayerClip(JNIEnv* env, jobject clazz, static jint android_view_GLES20Canvas_saveLayerAlpha(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom, jint alpha, jint saveFlags) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); return renderer->saveLayerAlpha(left, top, right, bottom, alpha, saveFlags); } static jint android_view_GLES20Canvas_saveLayerAlphaClip(JNIEnv* env, jobject clazz, jlong rendererPtr, jint alpha, jint saveFlags) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds()); return renderer->saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, alpha, saveFlags); @@ -290,7 +235,7 @@ static jint android_view_GLES20Canvas_saveLayerAlphaClip(JNIEnv* env, jobject cl static jboolean android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); const bool result = renderer->quickRejectConservative(left, top, right, bottom); return result ? JNI_TRUE : JNI_FALSE; } @@ -298,7 +243,7 @@ static jboolean android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz static jboolean android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom, jint op) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); const bool result = renderer->clipRect(left, top, right, bottom, static_cast<SkRegion::Op>(op)); return result ? JNI_TRUE : JNI_FALSE; @@ -307,7 +252,7 @@ static jboolean android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz, static jboolean android_view_GLES20Canvas_clipRect(JNIEnv* env, jobject clazz, jlong rendererPtr, jint left, jint top, jint right, jint bottom, jint op) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); const bool result = renderer->clipRect(float(left), float(top), float(right), float(bottom), static_cast<SkRegion::Op>(op)); @@ -316,7 +261,7 @@ static jboolean android_view_GLES20Canvas_clipRect(JNIEnv* env, jobject clazz, static jboolean android_view_GLES20Canvas_clipPath(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong pathPtr, jint op) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPath* path = reinterpret_cast<SkPath*>(pathPtr); const bool result = renderer->clipPath(path, static_cast<SkRegion::Op>(op)); return result ? JNI_TRUE : JNI_FALSE; @@ -324,7 +269,7 @@ static jboolean android_view_GLES20Canvas_clipPath(JNIEnv* env, jobject clazz, static jboolean android_view_GLES20Canvas_clipRegion(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong regionPtr, jint op) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr); const bool result = renderer->clipRegion(region, static_cast<SkRegion::Op>(op)); return result ? JNI_TRUE : JNI_FALSE; @@ -332,7 +277,7 @@ static jboolean android_view_GLES20Canvas_clipRegion(JNIEnv* env, jobject clazz, static jboolean android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject clazz, jlong rendererPtr, jobject rect) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); const android::uirenderer::Rect& bounds(renderer->getLocalClipBounds()); env->CallVoidMethod(rect, gRectClassInfo.set, @@ -347,47 +292,47 @@ static jboolean android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject cla static void android_view_GLES20Canvas_translate(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat dx, jfloat dy) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->translate(dx, dy); } static void android_view_GLES20Canvas_rotate(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat degrees) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->rotate(degrees); } static void android_view_GLES20Canvas_scale(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat sx, jfloat sy) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->scale(sx, sy); } static void android_view_GLES20Canvas_skew(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat sx, jfloat sy) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->skew(sx, sy); } static void android_view_GLES20Canvas_setMatrix(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong matrixPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); - renderer->setMatrix(matrix); + renderer->setMatrix(matrix ? *matrix : SkMatrix::I()); } static void android_view_GLES20Canvas_getMatrix(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong matrixPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); renderer->getMatrix(matrix); } static void android_view_GLES20Canvas_concatMatrix(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong matrixPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); - renderer->concatMatrix(matrix); + renderer->concatMatrix(*matrix); } // ---------------------------------------------------------------------------- @@ -401,7 +346,7 @@ static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject clazz, // This object allows the renderer to allocate a global JNI ref to the buffer object. JavaHeapBitmapRef bitmapRef(env, bitmap, buffer); - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawBitmap(bitmap, left, top, paint); } @@ -414,7 +359,7 @@ static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject clazz, // This object allows the renderer to allocate a global JNI ref to the buffer object. JavaHeapBitmapRef bitmapRef(env, bitmap, buffer); - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom, dstLeft, dstTop, dstRight, dstBottom, paint); @@ -427,20 +372,20 @@ static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject claz // This object allows the renderer to allocate a global JNI ref to the buffer object. JavaHeapBitmapRef bitmapRef(env, bitmap, buffer); - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); - renderer->drawBitmap(bitmap, matrix, paint); + renderer->drawBitmap(bitmap, *matrix, paint); } static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz, jlong rendererPtr, jintArray colors, jint offset, jint stride, jfloat left, jfloat top, jint width, jint height, jboolean hasAlpha, jlong paintPtr) { + const SkImageInfo info = SkImageInfo::Make(width, height, + hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType, + kPremul_SkAlphaType); SkBitmap* bitmap = new SkBitmap; - bitmap->setConfig(hasAlpha ? SkBitmap::kARGB_8888_Config : SkBitmap::kRGB_565_Config, - width, height); - - if (!bitmap->allocPixels()) { + if (!bitmap->allocPixels(info)) { delete bitmap; return; } @@ -450,7 +395,7 @@ static void android_view_GLES20Canvas_drawBitmapData(JNIEnv* env, jobject clazz, return; } - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawBitmapData(bitmap, left, top, paint); @@ -471,7 +416,7 @@ static void android_view_GLES20Canvas_drawBitmapMesh(JNIEnv* env, jobject clazz, jfloat* verticesArray = vertices ? env->GetFloatArrayElements(vertices, NULL) + offset : NULL; jint* colorsArray = colors ? env->GetIntArrayElements(colors, NULL) + colorOffset : NULL; - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawBitmapMesh(bitmap, meshWidth, meshHeight, verticesArray, colorsArray, paint); @@ -486,22 +431,23 @@ static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject clazz, // This object allows the renderer to allocate a global JNI ref to the buffer object. JavaHeapBitmapRef bitmapRef(env, bitmap, buffer); - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(patchPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint); } static void android_view_GLES20Canvas_drawColor(JNIEnv* env, jobject clazz, - jlong rendererPtr, jint color, jint mode) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - renderer->drawColor(color, static_cast<SkXfermode::Mode>(mode)); + jlong rendererPtr, jint color, jint modeHandle) { + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); + SkPorterDuff::Mode mode = static_cast<SkPorterDuff::Mode>(modeHandle); + renderer->drawColor(color, SkPorterDuff::ToXfermodeMode(mode)); } static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawRect(left, top, right, bottom, paint); } @@ -509,21 +455,21 @@ static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject clazz, static void android_view_GLES20Canvas_drawRoundRect(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawRoundRect(left, top, right, bottom, rx, ry, paint); } static void android_view_GLES20Canvas_drawCircle(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat x, jfloat y, jfloat radius, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawCircle(x, y, radius, paint); } static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr); CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr); CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr); @@ -534,7 +480,7 @@ static void android_view_GLES20Canvas_drawCircleProps(JNIEnv* env, jobject clazz static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawOval(left, top, right, bottom, paint); } @@ -542,14 +488,14 @@ static void android_view_GLES20Canvas_drawOval(JNIEnv* env, jobject clazz, static void android_view_GLES20Canvas_drawArc(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloat left, jfloat top, jfloat right, jfloat bottom, jfloat startAngle, jfloat sweepAngle, jboolean useCenter, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint); } static void android_view_GLES20Canvas_drawRegionAsRects(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong regionPtr, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkRegion* region = reinterpret_cast<SkRegion*>(regionPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); if (paint->getStyle() != SkPaint::kFill_Style || @@ -577,18 +523,9 @@ static void android_view_GLES20Canvas_drawRegionAsRects(JNIEnv* env, jobject cla } } -static void android_view_GLES20Canvas_drawRects(JNIEnv* env, jobject clazz, - jlong rendererPtr, jfloatArray rects, jint count, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - jfloat* storage = env->GetFloatArrayElements(rects, NULL); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); - renderer->drawRects(storage, count, paint); - env->ReleaseFloatArrayElements(rects, storage, 0); -} - static void android_view_GLES20Canvas_drawPoints(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloatArray points, jint offset, jint count, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); jfloat* storage = env->GetFloatArrayElements(points, NULL); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawPoints(storage + offset, count, paint); @@ -597,7 +534,7 @@ static void android_view_GLES20Canvas_drawPoints(JNIEnv* env, jobject clazz, static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong pathPtr, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); SkPath* path = reinterpret_cast<SkPath*>(pathPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawPath(path, paint); @@ -605,7 +542,7 @@ static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject clazz, static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz, jlong rendererPtr, jfloatArray points, jint offset, jint count, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); jfloat* storage = env->GetFloatArrayElements(points, NULL); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderer->drawLines(storage + offset, count, paint); @@ -618,13 +555,13 @@ static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz, static void android_view_GLES20Canvas_setupPaintFilter(JNIEnv* env, jobject clazz, jlong rendererPtr, jint clearBits, jint setBits) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->setupPaintFilter(clearBits, setBits); } static void android_view_GLES20Canvas_resetPaintFilter(JNIEnv* env, jobject clazz, jlong rendererPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); renderer->resetPaintFilter(); } @@ -651,7 +588,7 @@ static float xOffsetForTextAlign(SkPaint* paint, float totalAdvance) { class RenderTextFunctor { public: - RenderTextFunctor(const Layout& layout, OpenGLRenderer* renderer, jfloat x, jfloat y, + RenderTextFunctor(const Layout& layout, DisplayListRenderer* renderer, jfloat x, jfloat y, SkPaint* paint, uint16_t* glyphs, float* pos, float totalAdvance, uirenderer::Rect& bounds) : layout(layout), renderer(renderer), x(x), y(y), paint(paint), glyphs(glyphs), @@ -669,7 +606,7 @@ public: } private: const Layout& layout; - OpenGLRenderer* renderer; + DisplayListRenderer* renderer; jfloat x; jfloat y; SkPaint* paint; @@ -679,7 +616,7 @@ private: uirenderer::Rect& bounds; }; -static void renderTextLayout(OpenGLRenderer* renderer, Layout* layout, +static void renderTextLayout(DisplayListRenderer* renderer, Layout* layout, jfloat x, jfloat y, SkPaint* paint) { size_t nGlyphs = layout->nGlyphs(); float* pos = new float[nGlyphs * 2]; @@ -697,17 +634,17 @@ static void renderTextLayout(OpenGLRenderer* renderer, Layout* layout, } #endif -static void renderText(OpenGLRenderer* renderer, const jchar* text, int count, - jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) { +static void renderText(DisplayListRenderer* renderer, const jchar* text, int count, + jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { #ifdef USE_MINIKIN Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface); + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); layout.doLayout(text, 0, count, count, css); x += xOffsetForTextAlign(paint, layout.getAdvance()); renderTextLayout(renderer, &layout, x, y, paint); #else sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - text, 0, count, count, flags); + text, 0, count, count, bidiFlags); if (value == NULL) { return; } @@ -726,10 +663,50 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count, #endif } -static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count, - SkPath* path, jfloat hOffset, jfloat vOffset, int flags, SkPaint* paint) { +#ifdef USE_MINIKIN +class RenderTextOnPathFunctor { +public: + RenderTextOnPathFunctor(const Layout& layout, DisplayListRenderer* renderer, float hOffset, + float vOffset, SkPaint* paint, SkPath* path) + : layout(layout), renderer(renderer), hOffset(hOffset), vOffset(vOffset), + paint(paint), path(path) { + } + void operator()(size_t start, size_t end) { + uint16_t glyphs[1]; + for (size_t i = start; i < end; i++) { + glyphs[0] = layout.getGlyphId(i); + float x = hOffset + layout.getX(i); + float y = vOffset + layout.getY(i); + renderer->drawTextOnPath((const char*) glyphs, sizeof(glyphs), 1, path, x, y, paint); + } + } +private: + const Layout& layout; + DisplayListRenderer* renderer; + float hOffset; + float vOffset; + SkPaint* paint; + SkPath* path; +}; +#endif + +static void renderTextOnPath(DisplayListRenderer* renderer, const jchar* text, int count, + SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint, + TypefaceImpl* typeface) { +#ifdef USE_MINIKIN + Layout layout; + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); + layout.doLayout(text, 0, count, count, css); + hOffset += MinikinUtils::hOffsetForTextAlign(paint, layout, *path); + SkPaint::Align align = paint->getTextAlign(); + paint->setTextAlign(SkPaint::kLeft_Align); + + RenderTextOnPathFunctor f(layout, renderer, hOffset, vOffset, paint, path); + MinikinUtils::forFontRun(layout, paint, f); + paint->setTextAlign(align); +#else sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - text, 0, count, count, flags); + text, 0, count, count, bidiFlags); if (value == NULL) { return; } @@ -738,20 +715,21 @@ static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int co int bytesCount = glyphsCount * sizeof(jchar); renderer->drawTextOnPath((const char*) glyphs, bytesCount, glyphsCount, path, hOffset, vOffset, paint); +#endif } -static void renderTextRun(OpenGLRenderer* renderer, const jchar* text, +static void renderTextRun(DisplayListRenderer* renderer, const jchar* text, jint start, jint count, jint contextCount, jfloat x, jfloat y, - int flags, SkPaint* paint, TypefaceImpl* typeface) { + int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { #ifdef USE_MINIKIN Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface); + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); layout.doLayout(text, start, count, contextCount, css); x += xOffsetForTextAlign(paint, layout.getAdvance()); renderTextLayout(renderer, &layout, x, y, paint); #else sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - text, start, count, contextCount, flags); + text, start, count, contextCount, bidiFlags); if (value == NULL) { return; } @@ -772,124 +750,87 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text, static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz, jlong rendererPtr, jcharArray text, jint index, jint count, - jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) { + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); jchar* textArray = env->GetCharArrayElements(text, NULL); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); - renderText(renderer, textArray + index, count, x, y, flags, paint, typeface); + renderText(renderer, textArray + index, count, x, y, bidiFlags, paint, typeface); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz, jlong rendererPtr, jstring text, jint start, jint end, - jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) { + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); const jchar* textArray = env->GetStringChars(text, NULL); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); - renderText(renderer, textArray + start, end - start, x, y, flags, paint, typeface); + renderText(renderer, textArray + start, end - start, x, y, bidiFlags, paint, typeface); env->ReleaseStringChars(text, textArray); } static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz, jlong rendererPtr, jcharArray text, jint index, jint count, - jlong pathPtr, jfloat hOffset, jfloat vOffset, jint flags, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr, + jlong typefacePtr) { + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); jchar* textArray = env->GetCharArrayElements(text, NULL); SkPath* path = reinterpret_cast<SkPath*>(pathPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); renderTextOnPath(renderer, textArray + index, count, path, - hOffset, vOffset, flags, paint); + hOffset, vOffset, bidiFlags, paint, typeface); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz, jlong rendererPtr, jstring text, jint start, jint end, - jlong pathPtr, jfloat hOffset, jfloat vOffset, jint flags, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr, + jlong typefacePtr) { + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); const jchar* textArray = env->GetStringChars(text, NULL); SkPath* path = reinterpret_cast<SkPath*>(pathPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); + TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); renderTextOnPath(renderer, textArray + start, end - start, path, - hOffset, vOffset, flags, paint); + hOffset, vOffset, bidiFlags, paint, typeface); env->ReleaseStringChars(text, textArray); } static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz, jlong rendererPtr, jcharArray text, jint index, jint count, - jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags, + jint contextIndex, jint contextCount, jfloat x, jfloat y, jboolean isRtl, jlong paintPtr, jlong typefacePtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); jchar* textArray = env->GetCharArrayElements(text, NULL); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; renderTextRun(renderer, textArray + contextIndex, index - contextIndex, - count, contextCount, x, y, dirFlags, paint, typeface); + count, contextCount, x, y, bidiFlags, paint, typeface); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz, jlong rendererPtr, jstring text, jint start, jint end, - jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags, + jint contextStart, int contextEnd, jfloat x, jfloat y, jboolean isRtl, jlong paintPtr, jlong typefacePtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); const jchar* textArray = env->GetStringChars(text, NULL); jint count = end - start; jint contextCount = contextEnd - contextStart; SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; renderTextRun(renderer, textArray + contextStart, start - contextStart, - count, contextCount, x, y, dirFlags, paint, typeface); - env->ReleaseStringChars(text, textArray); -} - -static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count, - const jfloat* positions, jint dirFlags, SkPaint* paint) { - sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - text, 0, count, count, dirFlags); - if (value == NULL) { - return; - } - const jchar* glyphs = value->getGlyphs(); - size_t glyphsCount = value->getGlyphsCount(); - if (count < int(glyphsCount)) glyphsCount = count; - int bytesCount = glyphsCount * sizeof(jchar); - - renderer->drawPosText((const char*) glyphs, bytesCount, glyphsCount, positions, paint); -} - -static void android_view_GLES20Canvas_drawPosTextArray(JNIEnv* env, jobject clazz, - jlong rendererPtr, jcharArray text, jint index, jint count, - jfloatArray pos, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - jchar* textArray = env->GetCharArrayElements(text, NULL); - jfloat* positions = env->GetFloatArrayElements(pos, NULL); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); - - renderPosText(renderer, textArray + index, count, positions, kBidi_LTR, paint); - - env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT); - env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); -} - -static void android_view_GLES20Canvas_drawPosText(JNIEnv* env, jobject clazz, - jlong rendererPtr, jstring text, jint start, jint end, - jfloatArray pos, jlong paintPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - const jchar* textArray = env->GetStringChars(text, NULL); - jfloat* positions = env->GetFloatArrayElements(pos, NULL); - SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); - - renderPosText(renderer, textArray + start, end - start, positions, kBidi_LTR, paint); - - env->ReleaseFloatArrayElements(pos, positions, JNI_ABORT); + count, contextCount, x, y, bidiFlags, paint, typeface); env->ReleaseStringChars(text, textArray); } @@ -907,13 +848,13 @@ static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env, jo return reinterpret_cast<jlong>(new DisplayListRenderer); } -static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env, - jobject clazz, jlong rendererPtr, jlong displayListPtr, +static jint android_view_GLES20Canvas_drawRenderNode(JNIEnv* env, + jobject clazz, jlong rendererPtr, jlong renderNodePtr, jobject dirty, jint flags) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); android::uirenderer::Rect bounds; - status_t status = renderer->drawDisplayList(displayList, bounds, flags); + status_t status = renderer->drawRenderNode(renderNode, bounds, flags); if (status != DrawGlInfo::kStatusDone && dirty != NULL) { env->CallVoidMethod(dirty, gRectClassInfo.set, int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom)); @@ -927,44 +868,11 @@ static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env, static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); + DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr); Layer* layer = reinterpret_cast<Layer*>(layerPtr); renderer->drawLayer(layer, x, y); } -static jboolean android_view_GLES20Canvas_copyLayer(JNIEnv* env, jobject clazz, - jlong layerPtr, jlong bitmapPtr) { - Layer* layer = reinterpret_cast<Layer*>(layerPtr); - SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr); - return LayerRenderer::copyLayer(layer, bitmap); -} - -static void android_view_GLES20Canvas_pushLayerUpdate(JNIEnv* env, jobject clazz, - jlong rendererPtr, jlong layerPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - Layer* layer = reinterpret_cast<Layer*>(layerPtr); - renderer->pushLayerUpdate(layer); -} - -static void android_view_GLES20Canvas_cancelLayerUpdate(JNIEnv* env, jobject clazz, - jlong rendererPtr, jlong layerPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - Layer* layer = reinterpret_cast<Layer*>(layerPtr); - renderer->cancelLayerUpdate(layer); -} - -static void android_view_GLES20Canvas_clearLayerUpdates(JNIEnv* env, jobject clazz, - jlong rendererPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - renderer->clearLayerUpdates(); -} - -static void android_view_GLES20Canvas_flushLayerUpdates(JNIEnv* env, jobject clazz, - jlong rendererPtr) { - OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - renderer->flushLayerUpdates(); -} - #endif // USE_OPENGL_RENDERER // ---------------------------------------------------------------------------- @@ -1009,14 +917,7 @@ static JNINativeMethod gMethods[] = { { "nIsAvailable", "()Z", (void*) android_view_GLES20Canvas_isAvailable }, #ifdef USE_OPENGL_RENDERER - { "nFlushCaches", "(I)V", (void*) android_view_GLES20Canvas_flushCaches }, - { "nInitCaches", "()Z", (void*) android_view_GLES20Canvas_initCaches }, - { "nTerminateCaches", "()V", (void*) android_view_GLES20Canvas_terminateCaches }, - { "nInitAtlas", "(Landroid/view/GraphicBuffer;[JI)V", - (void*) android_view_GLES20Canvas_initAtlas }, - - { "nCreateRenderer", "()J", (void*) android_view_GLES20Canvas_createRenderer }, { "nDestroyRenderer", "(J)V", (void*) android_view_GLES20Canvas_destroyRenderer }, { "nSetViewport", "(JII)V", (void*) android_view_GLES20Canvas_setViewport }, { "nPrepare", "(JZ)I", (void*) android_view_GLES20Canvas_prepare }, @@ -1025,9 +926,6 @@ static JNINativeMethod gMethods[] = { { "nSetProperty", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) android_view_GLES20Canvas_setProperty }, - - { "nGetStencilSize", "()I", (void*) android_view_GLES20Canvas_getStencilSize }, - { "nCallDrawGLFunction", "(JJ)I", (void*) android_view_GLES20Canvas_callDrawGLFunction }, { "nSave", "(JI)I", (void*) android_view_GLES20Canvas_save }, @@ -1067,7 +965,6 @@ static JNINativeMethod gMethods[] = { { "nDrawColor", "(JII)V", (void*) android_view_GLES20Canvas_drawColor }, { "nDrawRect", "(JFFFFJ)V", (void*) android_view_GLES20Canvas_drawRect }, { "nDrawRects", "(JJJ)V", (void*) android_view_GLES20Canvas_drawRegionAsRects }, - { "nDrawRects", "(J[FIJ)V", (void*) android_view_GLES20Canvas_drawRects }, { "nDrawRoundRect", "(JFFFFFFJ)V", (void*) android_view_GLES20Canvas_drawRoundRect }, { "nDrawCircle", "(JFFFJ)V", (void*) android_view_GLES20Canvas_drawCircle }, { "nDrawCircle", "(JJJJJ)V", (void*) android_view_GLES20Canvas_drawCircleProps }, @@ -1085,33 +982,22 @@ static JNINativeMethod gMethods[] = { { "nDrawText", "(JLjava/lang/String;IIFFIJJ)V", (void*) android_view_GLES20Canvas_drawText }, - { "nDrawTextOnPath", "(J[CIIJFFIJ)V", (void*) android_view_GLES20Canvas_drawTextArrayOnPath }, - { "nDrawTextOnPath", "(JLjava/lang/String;IIJFFIJ)V", + { "nDrawTextOnPath", "(J[CIIJFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextArrayOnPath }, + { "nDrawTextOnPath", "(JLjava/lang/String;IIJFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextOnPath }, - { "nDrawTextRun", "(J[CIIIIFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray }, - { "nDrawTextRun", "(JLjava/lang/String;IIIIFFIJJ)V", + { "nDrawTextRun", "(J[CIIIIFFZJJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray }, + { "nDrawTextRun", "(JLjava/lang/String;IIIIFFZJJ)V", (void*) android_view_GLES20Canvas_drawTextRun }, - { "nDrawPosText", "(J[CII[FJ)V", (void*) android_view_GLES20Canvas_drawPosTextArray }, - { "nDrawPosText", "(JLjava/lang/String;II[FJ)V", - (void*) android_view_GLES20Canvas_drawPosText }, - - { "nGetClipBounds", "(JLandroid/graphics/Rect;)Z", - (void*) android_view_GLES20Canvas_getClipBounds }, + { "nGetClipBounds", "(JLandroid/graphics/Rect;)Z", (void*) android_view_GLES20Canvas_getClipBounds }, - { "nFinishRecording", "(J)J", (void*) android_view_GLES20Canvas_finishRecording }, - { "nDrawDisplayList", "(JJLandroid/graphics/Rect;I)I", - (void*) android_view_GLES20Canvas_drawDisplayList }, + { "nFinishRecording", "(J)J", (void*) android_view_GLES20Canvas_finishRecording }, + { "nDrawRenderNode", "(JJLandroid/graphics/Rect;I)I", (void*) android_view_GLES20Canvas_drawRenderNode }, { "nCreateDisplayListRenderer", "()J", (void*) android_view_GLES20Canvas_createDisplayListRenderer }, { "nDrawLayer", "(JJFF)V", (void*) android_view_GLES20Canvas_drawLayer }, - { "nCopyLayer", "(JJ)Z", (void*) android_view_GLES20Canvas_copyLayer }, - { "nClearLayerUpdates", "(J)V", (void*) android_view_GLES20Canvas_clearLayerUpdates }, - { "nFlushLayerUpdates", "(J)V", (void*) android_view_GLES20Canvas_flushLayerUpdates }, - { "nPushLayerUpdate", "(JJ)V", (void*) android_view_GLES20Canvas_pushLayerUpdate }, - { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_GLES20Canvas_cancelLayerUpdate }, { "nGetMaximumTextureWidth", "()I", (void*) android_view_GLES20Canvas_getMaxTextureWidth }, { "nGetMaximumTextureHeight", "()I", (void*) android_view_GLES20Canvas_getMaxTextureHeight }, diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp deleted file mode 100644 index d0269a3..0000000 --- a/core/jni/android_view_GLRenderer.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "GLRenderer" - -#include "jni.h" -#include <nativehelper/JNIHelp.h> -#include <android_runtime/AndroidRuntime.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <EGL/egl_cache.h> - -#include <utils/Timers.h> - -#include <private/hwui/DrawGlInfo.h> - -#include <Caches.h> -#include <Extensions.h> -#include <LayerRenderer.h> -#include <RenderNode.h> - -#ifdef USE_OPENGL_RENDERER - EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface); -#endif - -namespace android { - -/** - * Note: OpenGLRenderer JNI layer is generated and compiled only on supported - * devices. This means all the logic must be compiled only when the - * preprocessor variable USE_OPENGL_RENDERER is defined. - */ -#ifdef USE_OPENGL_RENDERER - -// ---------------------------------------------------------------------------- -// Defines -// ---------------------------------------------------------------------------- - -// Debug -#define DEBUG_RENDERER 0 - -// Debug -#if DEBUG_RENDERER - #define RENDERER_LOGD(...) ALOGD(__VA_ARGS__) -#else - #define RENDERER_LOGD(...) -#endif - -// ---------------------------------------------------------------------------- -// Surface and display management -// ---------------------------------------------------------------------------- - -static jboolean android_view_GLRenderer_preserveBackBuffer(JNIEnv* env, jobject clazz) { - EGLDisplay display = eglGetCurrentDisplay(); - EGLSurface surface = eglGetCurrentSurface(EGL_DRAW); - - eglGetError(); - eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); - - EGLint error = eglGetError(); - if (error != EGL_SUCCESS) { - RENDERER_LOGD("Could not enable buffer preserved swap behavior (%x)", error); - } - - return error == EGL_SUCCESS; -} - -static jboolean android_view_GLRenderer_isBackBufferPreserved(JNIEnv* env, jobject clazz) { - EGLDisplay display = eglGetCurrentDisplay(); - EGLSurface surface = eglGetCurrentSurface(EGL_DRAW); - EGLint value; - - eglGetError(); - eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &value); - - EGLint error = eglGetError(); - if (error != EGL_SUCCESS) { - RENDERER_LOGD("Could not query buffer preserved swap behavior (%x)", error); - } - - return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED; -} - -// ---------------------------------------------------------------------------- -// Tracing and debugging -// ---------------------------------------------------------------------------- - -static bool android_view_GLRenderer_loadProperties(JNIEnv* env, jobject clazz) { - if (uirenderer::Caches::hasInstance()) { - return uirenderer::Caches::getInstance().initProperties(); - } - return false; -} - -static void android_view_GLRenderer_beginFrame(JNIEnv* env, jobject clazz, - jintArray size) { - - EGLDisplay display = eglGetCurrentDisplay(); - EGLSurface surface = eglGetCurrentSurface(EGL_DRAW); - - if (size) { - EGLint value; - jint* storage = env->GetIntArrayElements(size, NULL); - - eglQuerySurface(display, surface, EGL_WIDTH, &value); - storage[0] = value; - - eglQuerySurface(display, surface, EGL_HEIGHT, &value); - storage[1] = value; - - env->ReleaseIntArrayElements(size, storage, 0); - } - - eglBeginFrame(display, surface); -} - -static jlong android_view_GLRenderer_getSystemTime(JNIEnv* env, jobject clazz) { - if (uirenderer::Extensions::getInstance().hasNvSystemTime()) { - return eglGetSystemTimeNV(); - } - return systemTime(SYSTEM_TIME_MONOTONIC); -} - -static void android_view_GLRenderer_destroyLayer(JNIEnv* env, jobject clazz, - jlong layerPtr) { - using namespace android::uirenderer; - Layer* layer = reinterpret_cast<Layer*>(layerPtr); - LayerRenderer::destroyLayer(layer); -} - -static void android_view_GLRenderer_prepareTree(JNIEnv* env, jobject clazz, - jlong renderNodePtr) { - using namespace android::uirenderer; - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - TreeInfo ignoredInfo; - renderNode->prepareTree(ignoredInfo); -} - -static void android_view_GLRenderer_invokeFunctor(JNIEnv* env, jobject clazz, - jlong functorPtr, jboolean hasContext) { - using namespace android::uirenderer; - Functor* functor = reinterpret_cast<Functor*>(functorPtr); - DrawGlInfo::Mode mode = hasContext ? DrawGlInfo::kModeProcess : DrawGlInfo::kModeProcessNoContext; - (*functor)(mode, NULL); -} - -#endif // USE_OPENGL_RENDERER - -// ---------------------------------------------------------------------------- -// Shaders -// ---------------------------------------------------------------------------- - -static void android_view_GLRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz, - jstring diskCachePath) { - - const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL); - egl_cache_t::get()->setCacheFilename(cacheArray); - env->ReleaseStringUTFChars(diskCachePath, cacheArray); -} - -// ---------------------------------------------------------------------------- -// JNI Glue -// ---------------------------------------------------------------------------- - -const char* const kClassPathName = "android/view/GLRenderer"; - -static JNINativeMethod gMethods[] = { -#ifdef USE_OPENGL_RENDERER - { "isBackBufferPreserved", "()Z", (void*) android_view_GLRenderer_isBackBufferPreserved }, - { "preserveBackBuffer", "()Z", (void*) android_view_GLRenderer_preserveBackBuffer }, - { "loadProperties", "()Z", (void*) android_view_GLRenderer_loadProperties }, - - { "beginFrame", "([I)V", (void*) android_view_GLRenderer_beginFrame }, - - { "getSystemTime", "()J", (void*) android_view_GLRenderer_getSystemTime }, - { "nDestroyLayer", "(J)V", (void*) android_view_GLRenderer_destroyLayer }, - { "nPrepareTree", "(J)V", (void*) android_view_GLRenderer_prepareTree }, - { "nInvokeFunctor", "(JZ)V", (void*) android_view_GLRenderer_invokeFunctor }, -#endif - - { "setupShadersDiskCache", "(Ljava/lang/String;)V", - (void*) android_view_GLRenderer_setupShadersDiskCache }, -}; - -int register_android_view_GLRenderer(JNIEnv* env) { - return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); -} - -}; diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp index 8a426ac..5ebed9c 100644 --- a/core/jni/android_view_GraphicBuffer.cpp +++ b/core/jni/android_view_GraphicBuffer.cpp @@ -21,6 +21,7 @@ #include "android_os_Parcel.h" #include "android_view_GraphicBuffer.h" +#include "android/graphics/GraphicsJNI.h" #include <android_runtime/AndroidRuntime.h> @@ -75,7 +76,7 @@ static struct { static struct { jfieldID mSurfaceFormat; - jmethodID safeCanvasSwap; + jmethodID setNativeBitmap; } gCanvasClassInfo; #define GET_INT(object, field) \ @@ -141,16 +142,16 @@ static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz, // Canvas management // ---------------------------------------------------------------------------- -static inline SkBitmap::Config convertPixelFormat(int32_t format) { +static inline SkColorType convertPixelFormat(int32_t format) { switch (format) { case PIXEL_FORMAT_RGBA_8888: - return SkBitmap::kARGB_8888_Config; + return kN32_SkColorType; case PIXEL_FORMAT_RGBX_8888: - return SkBitmap::kARGB_8888_Config; + return kN32_SkColorType; case PIXEL_FORMAT_RGB_565: - return SkBitmap::kRGB_565_Config; + return kRGB_565_SkColorType; default: - return SkBitmap::kNo_Config; + return kUnknown_SkColorType; } } @@ -187,8 +188,10 @@ static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject, ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat()); SkBitmap bitmap; - bitmap.setConfig(convertPixelFormat(buffer->getPixelFormat()), - buffer->getWidth(), buffer->getHeight(), bytesCount); + bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(), + convertPixelFormat(buffer->getPixelFormat()), + kPremul_SkAlphaType), + bytesCount); if (buffer->getWidth() > 0 && buffer->getHeight() > 0) { bitmap.setPixels(bits); @@ -197,12 +200,11 @@ static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject, } SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat()); - - SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap)); - INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false); + INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(&bitmap)); SkRect clipRect; clipRect.set(rect.left, rect.top, rect.right, rect.bottom); + SkCanvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); nativeCanvas->clipRect(clipRect); if (dirtyRect) { @@ -218,8 +220,7 @@ static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobj GraphicBufferWrapper* wrapper = reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); - SkCanvas* nativeCanvas = SkNEW(SkCanvas); - INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false); + INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, (jlong)0); if (wrapper) { status_t status = wrapper->buffer->unlock(); @@ -319,7 +320,7 @@ int register_android_view_GraphicBuffer(JNIEnv* env) { FIND_CLASS(clazz, "android/graphics/Canvas"); GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I"); - GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V"); + GET_METHOD_ID(gCanvasClassInfo.setNativeBitmap, clazz, "setNativeBitmap", "(J)V"); return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp index 33a2705..ace17ec 100644 --- a/core/jni/android_view_HardwareLayer.cpp +++ b/core/jni/android_view_HardwareLayer.cpp @@ -43,21 +43,6 @@ using namespace uirenderer; #ifdef USE_OPENGL_RENDERER -static jlong android_view_HardwareLayer_createTextureLayer(JNIEnv* env, jobject clazz) { - Layer* layer = LayerRenderer::createTextureLayer(); - if (!layer) return 0; - - return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer) ); -} - -static jlong android_view_HardwareLayer_createRenderLayer(JNIEnv* env, jobject clazz, - jint width, jint height) { - Layer* layer = LayerRenderer::createRenderLayer(width, height); - if (!layer) return 0; - - return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer) ); -} - static void android_view_HardwareLayer_onTextureDestroyed(JNIEnv* env, jobject clazz, jlong layerUpdaterPtr) { DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr); @@ -102,21 +87,6 @@ static void android_view_HardwareLayer_updateSurfaceTexture(JNIEnv* env, jobject layer->updateTexImage(); } -static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject clazz, - jlong layerUpdaterPtr, jlong displayListPtr, - jint left, jint top, jint right, jint bottom) { - DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr); - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - layer->setDisplayList(displayList, left, top, right, bottom); -} - -static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz, - jlong layerUpdaterPtr) { - DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr); - TreeInfo ignoredInfo; - return layer->apply(ignoredInfo); -} - static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz, jlong layerUpdaterPtr) { DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr); @@ -140,8 +110,6 @@ const char* const kClassPathName = "android/view/HardwareLayer"; static JNINativeMethod gMethods[] = { #ifdef USE_OPENGL_RENDERER - { "nCreateTextureLayer", "()J", (void*) android_view_HardwareLayer_createTextureLayer }, - { "nCreateRenderLayer", "(II)J", (void*) android_view_HardwareLayer_createRenderLayer }, { "nOnTextureDestroyed", "(J)V", (void*) android_view_HardwareLayer_onTextureDestroyed }, { "nPrepare", "(JIIZ)Z", (void*) android_view_HardwareLayer_prepare }, @@ -150,9 +118,6 @@ static JNINativeMethod gMethods[] = { { "nSetSurfaceTexture", "(JLandroid/graphics/SurfaceTexture;Z)V", (void*) android_view_HardwareLayer_setSurfaceTexture }, { "nUpdateSurfaceTexture", "(J)V", (void*) android_view_HardwareLayer_updateSurfaceTexture }, - { "nUpdateRenderLayer", "(JJIIII)V", (void*) android_view_HardwareLayer_updateRenderLayer }, - - { "nFlushChanges", "(J)Z", (void*) android_view_HardwareLayer_flushChanges }, { "nGetLayer", "(J)J", (void*) android_view_HardwareLayer_getLayer }, { "nGetTexName", "(J)I", (void*) android_view_HardwareLayer_getTexName }, diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 26022e0..3ffde2d 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -38,6 +38,11 @@ using namespace uirenderer; */ #ifdef USE_OPENGL_RENDERER +#define SET_AND_DIRTY(prop, val, dirtyFlag) \ + (reinterpret_cast<RenderNode*>(renderNodePtr)->mutateStagingProperties().prop(val) \ + ? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \ + : false) + // ---------------------------------------------------------------------------- // DisplayList view properties // ---------------------------------------------------------------------------- @@ -82,235 +87,199 @@ static void android_view_RenderNode_setDisplayListData(JNIEnv* env, // RenderProperties - setters // ---------------------------------------------------------------------------- -static void android_view_RenderNode_setCaching(JNIEnv* env, - jobject clazz, jlong renderNodePtr, jboolean caching) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setCaching(caching); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); +static jboolean android_view_RenderNode_setLayerType(JNIEnv* env, + jobject clazz, jlong renderNodePtr, jint jlayerType) { + LayerType layerType = static_cast<LayerType>(jlayerType); + return SET_AND_DIRTY(mutateLayerProperties().setType, layerType, RenderNode::GENERIC); +} + +static jboolean android_view_RenderNode_setLayerPaint(JNIEnv* env, + jobject clazz, jlong renderNodePtr, jlong paintPtr) { + SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); + return SET_AND_DIRTY(mutateLayerProperties().setFromPaint, paint, RenderNode::GENERIC); } -static void android_view_RenderNode_setStaticMatrix(JNIEnv* env, +static jboolean android_view_RenderNode_setStaticMatrix(JNIEnv* env, jobject clazz, jlong renderNodePtr, jlong matrixPtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); - renderNode->mutateStagingProperties().setStaticMatrix(matrix); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return SET_AND_DIRTY(setStaticMatrix, matrix, RenderNode::GENERIC); } -static void android_view_RenderNode_setAnimationMatrix(JNIEnv* env, +static jboolean android_view_RenderNode_setAnimationMatrix(JNIEnv* env, jobject clazz, jlong renderNodePtr, jlong matrixPtr) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); - renderNode->mutateStagingProperties().setAnimationMatrix(matrix); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return SET_AND_DIRTY(setAnimationMatrix, matrix, RenderNode::GENERIC); } -static void android_view_RenderNode_setClipToBounds(JNIEnv* env, +static jboolean android_view_RenderNode_setClipToBounds(JNIEnv* env, jobject clazz, jlong renderNodePtr, jboolean clipToBounds) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setClipToBounds(clipToBounds); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return SET_AND_DIRTY(setClipToBounds, clipToBounds, RenderNode::GENERIC); } -static void android_view_RenderNode_setProjectBackwards(JNIEnv* env, +static jboolean android_view_RenderNode_setProjectBackwards(JNIEnv* env, jobject clazz, jlong renderNodePtr, jboolean shouldProject) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setProjectBackwards(shouldProject); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return SET_AND_DIRTY(setProjectBackwards, shouldProject, RenderNode::GENERIC); } -static void android_view_RenderNode_setProjectionReceiver(JNIEnv* env, +static jboolean android_view_RenderNode_setProjectionReceiver(JNIEnv* env, jobject clazz, jlong renderNodePtr, jboolean shouldRecieve) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setProjectionReceiver(shouldRecieve); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return SET_AND_DIRTY(setProjectionReceiver, shouldRecieve, RenderNode::GENERIC); } -static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env, +static jboolean android_view_RenderNode_setOutlineRoundRect(JNIEnv* env, jobject clazz, jlong renderNodePtr, jint left, jint top, jint right, jint bottom, jfloat radius) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius); renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return true; } -static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env, +static jboolean android_view_RenderNode_setOutlineConvexPath(JNIEnv* env, jobject clazz, jlong renderNodePtr, jlong outlinePathPtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr); renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath); renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return true; } -static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env, +static jboolean android_view_RenderNode_setOutlineEmpty(JNIEnv* env, jobject clazz, jlong renderNodePtr) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->mutateStagingProperties().mutableOutline().setEmpty(); renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return true; } -static void android_view_RenderNode_setClipToOutline(JNIEnv* env, +static jboolean android_view_RenderNode_setClipToOutline(JNIEnv* env, jobject clazz, jlong renderNodePtr, jboolean clipToOutline) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline); renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return true; } -static void android_view_RenderNode_setRevealClip(JNIEnv* env, +static jboolean android_view_RenderNode_setRevealClip(JNIEnv* env, jobject clazz, jlong renderNodePtr, jboolean shouldClip, jboolean inverseClip, jfloat x, jfloat y, jfloat radius) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->mutateStagingProperties().mutableRevealClip().set( shouldClip, inverseClip, x, y, radius); renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return true; } -static void android_view_RenderNode_setAlpha(JNIEnv* env, +static jboolean android_view_RenderNode_setAlpha(JNIEnv* env, jobject clazz, jlong renderNodePtr, float alpha) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setAlpha(alpha); - renderNode->setPropertyFieldsDirty(RenderNode::ALPHA); + return SET_AND_DIRTY(setAlpha, alpha, RenderNode::ALPHA); } -static void android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env, +static jboolean android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env, jobject clazz, jlong renderNodePtr, bool hasOverlappingRendering) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return SET_AND_DIRTY(setHasOverlappingRendering, hasOverlappingRendering, + RenderNode::GENERIC); } -static void android_view_RenderNode_setElevation(JNIEnv* env, +static jboolean android_view_RenderNode_setElevation(JNIEnv* env, jobject clazz, jlong renderNodePtr, float elevation) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setElevation(elevation); - renderNode->setPropertyFieldsDirty(RenderNode::Z); + return SET_AND_DIRTY(setElevation, elevation, RenderNode::Z); } -static void android_view_RenderNode_setTranslationX(JNIEnv* env, +static jboolean android_view_RenderNode_setTranslationX(JNIEnv* env, jobject clazz, jlong renderNodePtr, float tx) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setTranslationX(tx); - renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_X | RenderNode::X); + return SET_AND_DIRTY(setTranslationX, tx, RenderNode::TRANSLATION_X | RenderNode::X); } -static void android_view_RenderNode_setTranslationY(JNIEnv* env, +static jboolean android_view_RenderNode_setTranslationY(JNIEnv* env, jobject clazz, jlong renderNodePtr, float ty) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setTranslationY(ty); - renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Y | RenderNode::Y); + return SET_AND_DIRTY(setTranslationY, ty, RenderNode::TRANSLATION_Y | RenderNode::Y); } -static void android_view_RenderNode_setTranslationZ(JNIEnv* env, +static jboolean android_view_RenderNode_setTranslationZ(JNIEnv* env, jobject clazz, jlong renderNodePtr, float tz) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setTranslationZ(tz); - renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z | RenderNode::Z); + return SET_AND_DIRTY(setTranslationZ, tz, RenderNode::TRANSLATION_Z | RenderNode::Z); } -static void android_view_RenderNode_setRotation(JNIEnv* env, +static jboolean android_view_RenderNode_setRotation(JNIEnv* env, jobject clazz, jlong renderNodePtr, float rotation) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setRotation(rotation); - renderNode->setPropertyFieldsDirty(RenderNode::ROTATION); + return SET_AND_DIRTY(setRotation, rotation, RenderNode::ROTATION); } -static void android_view_RenderNode_setRotationX(JNIEnv* env, +static jboolean android_view_RenderNode_setRotationX(JNIEnv* env, jobject clazz, jlong renderNodePtr, float rx) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setRotationX(rx); - renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_X); + return SET_AND_DIRTY(setRotationX, rx, RenderNode::ROTATION_X); } -static void android_view_RenderNode_setRotationY(JNIEnv* env, +static jboolean android_view_RenderNode_setRotationY(JNIEnv* env, jobject clazz, jlong renderNodePtr, float ry) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setRotationY(ry); - renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_Y); + return SET_AND_DIRTY(setRotationY, ry, RenderNode::ROTATION_Y); } -static void android_view_RenderNode_setScaleX(JNIEnv* env, +static jboolean android_view_RenderNode_setScaleX(JNIEnv* env, jobject clazz, jlong renderNodePtr, float sx) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setScaleX(sx); - renderNode->setPropertyFieldsDirty(RenderNode::SCALE_X); + return SET_AND_DIRTY(setScaleX, sx, RenderNode::SCALE_X); } -static void android_view_RenderNode_setScaleY(JNIEnv* env, +static jboolean android_view_RenderNode_setScaleY(JNIEnv* env, jobject clazz, jlong renderNodePtr, float sy) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setScaleY(sy); - renderNode->setPropertyFieldsDirty(RenderNode::SCALE_Y); + return SET_AND_DIRTY(setScaleY, sy, RenderNode::SCALE_Y); } -static void android_view_RenderNode_setPivotX(JNIEnv* env, +static jboolean android_view_RenderNode_setPivotX(JNIEnv* env, jobject clazz, jlong renderNodePtr, float px) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setPivotX(px); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return SET_AND_DIRTY(setPivotX, px, RenderNode::GENERIC); } -static void android_view_RenderNode_setPivotY(JNIEnv* env, +static jboolean android_view_RenderNode_setPivotY(JNIEnv* env, jobject clazz, jlong renderNodePtr, float py) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setPivotY(py); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return SET_AND_DIRTY(setPivotY, py, RenderNode::GENERIC); } -static void android_view_RenderNode_setCameraDistance(JNIEnv* env, +static jboolean android_view_RenderNode_setCameraDistance(JNIEnv* env, jobject clazz, jlong renderNodePtr, float distance) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setCameraDistance(distance); - renderNode->setPropertyFieldsDirty(RenderNode::GENERIC); + return SET_AND_DIRTY(setCameraDistance, distance, RenderNode::GENERIC); } -static void android_view_RenderNode_setLeft(JNIEnv* env, +static jboolean android_view_RenderNode_setLeft(JNIEnv* env, jobject clazz, jlong renderNodePtr, int left) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setLeft(left); - renderNode->setPropertyFieldsDirty(RenderNode::X); + return SET_AND_DIRTY(setLeft, left, RenderNode::X); } -static void android_view_RenderNode_setTop(JNIEnv* env, +static jboolean android_view_RenderNode_setTop(JNIEnv* env, jobject clazz, jlong renderNodePtr, int top) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setTop(top); - renderNode->setPropertyFieldsDirty(RenderNode::Y); + return SET_AND_DIRTY(setTop, top, RenderNode::Y); } -static void android_view_RenderNode_setRight(JNIEnv* env, +static jboolean android_view_RenderNode_setRight(JNIEnv* env, jobject clazz, jlong renderNodePtr, int right) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setRight(right); - renderNode->setPropertyFieldsDirty(RenderNode::X); + return SET_AND_DIRTY(setRight, right, RenderNode::X); } -static void android_view_RenderNode_setBottom(JNIEnv* env, +static jboolean android_view_RenderNode_setBottom(JNIEnv* env, jobject clazz, jlong renderNodePtr, int bottom) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setBottom(bottom); - renderNode->setPropertyFieldsDirty(RenderNode::Y); + return SET_AND_DIRTY(setBottom, bottom, RenderNode::Y); } -static void android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env, +static jboolean android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env, jobject clazz, jlong renderNodePtr, int left, int top, int right, int bottom) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom); - renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + if (renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom)) { + renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + return true; + } + return false; } -static void android_view_RenderNode_offsetLeftAndRight(JNIEnv* env, +static jboolean android_view_RenderNode_offsetLeftAndRight(JNIEnv* env, jobject clazz, jlong renderNodePtr, float offset) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().offsetLeftRight(offset); - renderNode->setPropertyFieldsDirty(RenderNode::X); + return SET_AND_DIRTY(offsetLeftRight, offset, RenderNode::X); } -static void android_view_RenderNode_offsetTopAndBottom(JNIEnv* env, +static jboolean android_view_RenderNode_offsetTopAndBottom(JNIEnv* env, jobject clazz, jlong renderNodePtr, float offset) { - RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); - renderNode->mutateStagingProperties().offsetTopBottom(offset); - renderNode->setPropertyFieldsDirty(RenderNode::Y); + return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y); } // ---------------------------------------------------------------------------- @@ -513,41 +482,42 @@ static JNINativeMethod gMethods[] = { { "nOutput", "(J)V", (void*) android_view_RenderNode_output }, { "nGetDebugSize", "(J)I", (void*) android_view_RenderNode_getDebugSize }, - { "nSetCaching", "(JZ)V", (void*) android_view_RenderNode_setCaching }, - { "nSetStaticMatrix", "(JJ)V", (void*) android_view_RenderNode_setStaticMatrix }, - { "nSetAnimationMatrix", "(JJ)V", (void*) android_view_RenderNode_setAnimationMatrix }, - { "nSetClipToBounds", "(JZ)V", (void*) android_view_RenderNode_setClipToBounds }, - { "nSetProjectBackwards", "(JZ)V", (void*) android_view_RenderNode_setProjectBackwards }, - { "nSetProjectionReceiver","(JZ)V", (void*) android_view_RenderNode_setProjectionReceiver }, - - { "nSetOutlineRoundRect", "(JIIIIF)V", (void*) android_view_RenderNode_setOutlineRoundRect }, - { "nSetOutlineConvexPath", "(JJ)V", (void*) android_view_RenderNode_setOutlineConvexPath }, - { "nSetOutlineEmpty", "(J)V", (void*) android_view_RenderNode_setOutlineEmpty }, - { "nSetClipToOutline", "(JZ)V", (void*) android_view_RenderNode_setClipToOutline }, - { "nSetRevealClip", "(JZZFFF)V", (void*) android_view_RenderNode_setRevealClip }, - - { "nSetAlpha", "(JF)V", (void*) android_view_RenderNode_setAlpha }, - { "nSetHasOverlappingRendering", "(JZ)V", + { "nSetLayerType", "(JI)Z", (void*) android_view_RenderNode_setLayerType }, + { "nSetLayerPaint", "(JJ)Z", (void*) android_view_RenderNode_setLayerPaint }, + { "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix }, + { "nSetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix }, + { "nSetClipToBounds", "(JZ)Z", (void*) android_view_RenderNode_setClipToBounds }, + { "nSetProjectBackwards", "(JZ)Z", (void*) android_view_RenderNode_setProjectBackwards }, + { "nSetProjectionReceiver","(JZ)Z", (void*) android_view_RenderNode_setProjectionReceiver }, + + { "nSetOutlineRoundRect", "(JIIIIF)Z", (void*) android_view_RenderNode_setOutlineRoundRect }, + { "nSetOutlineConvexPath", "(JJ)Z", (void*) android_view_RenderNode_setOutlineConvexPath }, + { "nSetOutlineEmpty", "(J)Z", (void*) android_view_RenderNode_setOutlineEmpty }, + { "nSetClipToOutline", "(JZ)Z", (void*) android_view_RenderNode_setClipToOutline }, + { "nSetRevealClip", "(JZZFFF)Z", (void*) android_view_RenderNode_setRevealClip }, + + { "nSetAlpha", "(JF)Z", (void*) android_view_RenderNode_setAlpha }, + { "nSetHasOverlappingRendering", "(JZ)Z", (void*) android_view_RenderNode_setHasOverlappingRendering }, - { "nSetElevation", "(JF)V", (void*) android_view_RenderNode_setElevation }, - { "nSetTranslationX", "(JF)V", (void*) android_view_RenderNode_setTranslationX }, - { "nSetTranslationY", "(JF)V", (void*) android_view_RenderNode_setTranslationY }, - { "nSetTranslationZ", "(JF)V", (void*) android_view_RenderNode_setTranslationZ }, - { "nSetRotation", "(JF)V", (void*) android_view_RenderNode_setRotation }, - { "nSetRotationX", "(JF)V", (void*) android_view_RenderNode_setRotationX }, - { "nSetRotationY", "(JF)V", (void*) android_view_RenderNode_setRotationY }, - { "nSetScaleX", "(JF)V", (void*) android_view_RenderNode_setScaleX }, - { "nSetScaleY", "(JF)V", (void*) android_view_RenderNode_setScaleY }, - { "nSetPivotX", "(JF)V", (void*) android_view_RenderNode_setPivotX }, - { "nSetPivotY", "(JF)V", (void*) android_view_RenderNode_setPivotY }, - { "nSetCameraDistance", "(JF)V", (void*) android_view_RenderNode_setCameraDistance }, - { "nSetLeft", "(JI)V", (void*) android_view_RenderNode_setLeft }, - { "nSetTop", "(JI)V", (void*) android_view_RenderNode_setTop }, - { "nSetRight", "(JI)V", (void*) android_view_RenderNode_setRight }, - { "nSetBottom", "(JI)V", (void*) android_view_RenderNode_setBottom }, - { "nSetLeftTopRightBottom","(JIIII)V", (void*) android_view_RenderNode_setLeftTopRightBottom }, - { "nOffsetLeftAndRight", "(JF)V", (void*) android_view_RenderNode_offsetLeftAndRight }, - { "nOffsetTopAndBottom", "(JF)V", (void*) android_view_RenderNode_offsetTopAndBottom }, + { "nSetElevation", "(JF)Z", (void*) android_view_RenderNode_setElevation }, + { "nSetTranslationX", "(JF)Z", (void*) android_view_RenderNode_setTranslationX }, + { "nSetTranslationY", "(JF)Z", (void*) android_view_RenderNode_setTranslationY }, + { "nSetTranslationZ", "(JF)Z", (void*) android_view_RenderNode_setTranslationZ }, + { "nSetRotation", "(JF)Z", (void*) android_view_RenderNode_setRotation }, + { "nSetRotationX", "(JF)Z", (void*) android_view_RenderNode_setRotationX }, + { "nSetRotationY", "(JF)Z", (void*) android_view_RenderNode_setRotationY }, + { "nSetScaleX", "(JF)Z", (void*) android_view_RenderNode_setScaleX }, + { "nSetScaleY", "(JF)Z", (void*) android_view_RenderNode_setScaleY }, + { "nSetPivotX", "(JF)Z", (void*) android_view_RenderNode_setPivotX }, + { "nSetPivotY", "(JF)Z", (void*) android_view_RenderNode_setPivotY }, + { "nSetCameraDistance", "(JF)Z", (void*) android_view_RenderNode_setCameraDistance }, + { "nSetLeft", "(JI)Z", (void*) android_view_RenderNode_setLeft }, + { "nSetTop", "(JI)Z", (void*) android_view_RenderNode_setTop }, + { "nSetRight", "(JI)Z", (void*) android_view_RenderNode_setRight }, + { "nSetBottom", "(JI)Z", (void*) android_view_RenderNode_setBottom }, + { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom }, + { "nOffsetLeftAndRight", "(JF)Z", (void*) android_view_RenderNode_offsetLeftAndRight }, + { "nOffsetTopAndBottom", "(JF)Z", (void*) android_view_RenderNode_offsetTopAndBottom }, { "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering }, { "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline }, diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 6c9d060..7018751 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -70,7 +70,7 @@ static struct { static struct { jfieldID mSurfaceFormat; - jmethodID safeCanvasSwap; + jmethodID setNativeBitmap; } gCanvasClassInfo; // ---------------------------------------------------------------------------- @@ -95,6 +95,7 @@ sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) { env->GetLongField(surfaceObj, gSurfaceClassInfo.mNativeObject)); env->MonitorExit(lock); } + env->DeleteLocalRef(lock); return sur; } @@ -172,17 +173,17 @@ static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jlong n return value; } -static inline SkBitmap::Config convertPixelFormat(PixelFormat format) { +static inline SkColorType convertPixelFormat(PixelFormat format) { /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then - we can map to SkBitmap::kARGB_8888_Config, and optionally call + we can map to kN32_SkColorType, and optionally call bitmap.setAlphaType(kOpaque_SkAlphaType) on the resulting SkBitmap (as an accelerator) */ switch (format) { - case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config; - case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config; - case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config; - default: return SkBitmap::kNo_Config; + case PIXEL_FORMAT_RGBX_8888: return kN32_SkColorType; + case PIXEL_FORMAT_RGBA_8888: return kN32_SkColorType; + case PIXEL_FORMAT_RGB_565: return kRGB_565_SkColorType; + default: return kUnknown_SkColorType; } } @@ -219,12 +220,16 @@ static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, // Associate a SkCanvas object to this surface env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format); - SkBitmap bitmap; - ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); - bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr); + SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height, + convertPixelFormat(outBuffer.format), + kPremul_SkAlphaType); if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) { - bitmap.setAlphaType(kOpaque_SkAlphaType); + info.fAlphaType = kOpaque_SkAlphaType; } + + SkBitmap bitmap; + ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); + bitmap.setInfo(info, bpr); if (outBuffer.width > 0 && outBuffer.height > 0) { bitmap.setPixels(outBuffer.bits); } else { @@ -232,10 +237,11 @@ static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, bitmap.setPixels(NULL); } - SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap)); - env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false); + env->CallVoidMethod(canvasObj, gCanvasClassInfo.setNativeBitmap, + reinterpret_cast<jlong>(&bitmap)); if (dirtyRectPtr) { + SkCanvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj); nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) ); } @@ -262,8 +268,7 @@ static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, } // detach the canvas from the surface - SkCanvas* nativeCanvas = SkNEW(SkCanvas); - env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false); + env->CallVoidMethod(canvasObj, gCanvasClassInfo.setNativeBitmap, (jlong)0); // unlock surface status_t err = surface->unlockAndPost(); @@ -375,7 +380,7 @@ int register_android_view_Surface(JNIEnv* env) clazz = env->FindClass("android/graphics/Canvas"); gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I"); - gCanvasClassInfo.safeCanvasSwap = env->GetMethodID(clazz, "safeCanvasSwap", "(JZ)V"); + gCanvasClassInfo.setNativeBitmap = env->GetMethodID(clazz, "setNativeBitmap", "(J)V"); clazz = env->FindClass("android/graphics/Rect"); gRectClassInfo.left = env->GetFieldID(clazz, "left", "I"); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 5a935a9..9783e91 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -42,6 +42,8 @@ #include <ScopedUtfChars.h> +#include "SkTemplates.h" + // ---------------------------------------------------------------------------- namespace android { @@ -59,8 +61,17 @@ static struct { jfieldID xDpi; jfieldID yDpi; jfieldID secure; + jfieldID appVsyncOffsetNanos; + jfieldID presentationDeadlineNanos; } gPhysicalDisplayInfoClassInfo; +static struct { + jfieldID bottom; + jfieldID left; + jfieldID right; + jfieldID top; +} gRectClassInfo; + // Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref. void DeleteScreenshot(void* addr, void* context) { SkASSERT(addr == ((ScreenshotClient*) context)->getPixels()); @@ -104,28 +115,34 @@ static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) { ctrl->decStrong((void *)nativeCreate); } -static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject displayTokenObj, - jint width, jint height, jint minLayer, jint maxLayer, bool allLayers, - bool useIdentityTransform) { +static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, + jobject displayTokenObj, jobject sourceCropObj, jint width, jint height, + jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) { sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj); if (displayToken == NULL) { return NULL; } - ScreenshotClient* screenshot = new ScreenshotClient(); + int left = env->GetIntField(sourceCropObj, gRectClassInfo.left); + int top = env->GetIntField(sourceCropObj, gRectClassInfo.top); + int right = env->GetIntField(sourceCropObj, gRectClassInfo.right); + int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom); + Rect sourceCrop(left, top, right, bottom); + + SkAutoTDelete<ScreenshotClient> screenshot(new ScreenshotClient()); status_t res; if (width > 0 && height > 0) { if (allLayers) { - res = screenshot->update(displayToken, width, height, useIdentityTransform); - } else { - res = screenshot->update(displayToken, width, height, minLayer, maxLayer, + res = screenshot->update(displayToken, sourceCrop, width, height, useIdentityTransform); + } else { + res = screenshot->update(displayToken, sourceCrop, width, height, + minLayer, maxLayer, useIdentityTransform); } } else { - res = screenshot->update(displayToken, useIdentityTransform); + res = screenshot->update(displayToken, sourceCrop, useIdentityTransform); } if (res != NO_ERROR) { - delete screenshot; return NULL; } @@ -150,7 +167,6 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject display break; } default: { - delete screenshot; return NULL; } } @@ -159,12 +175,12 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject display screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat()); SkBitmap* bitmap = new SkBitmap(); - bitmap->setConfig(screenshotInfo, (size_t)rowBytes); + bitmap->setInfo(screenshotInfo, (size_t)rowBytes); if (screenshotInfo.fWidth > 0 && screenshotInfo.fHeight > 0) { // takes ownership of ScreenshotClient SkMallocPixelRef* pixels = SkMallocPixelRef::NewWithProc(screenshotInfo, (size_t) rowBytes, NULL, (void*) screenshot->getPixels(), &DeleteScreenshot, - (void*) screenshot); + (void*) (screenshot.detach())); pixels->setImmutable(); bitmap->setPixelRef(pixels)->unref(); bitmap->lockPixels(); @@ -174,20 +190,25 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject display GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL); } -static void nativeScreenshot(JNIEnv* env, jclass clazz, - jobject displayTokenObj, jobject surfaceObj, - jint width, jint height, jint minLayer, jint maxLayer, bool allLayers, - bool useIdentityTransform) { +static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj, + jobject surfaceObj, jobject sourceCropObj, jint width, jint height, + jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) { sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj); if (displayToken != NULL) { sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj); if (consumer != NULL) { + int left = env->GetIntField(sourceCropObj, gRectClassInfo.left); + int top = env->GetIntField(sourceCropObj, gRectClassInfo.top); + int right = env->GetIntField(sourceCropObj, gRectClassInfo.right); + int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom); + Rect sourceCrop(left, top, right, bottom); + if (allLayers) { minLayer = 0; maxLayer = -1; } - ScreenshotClient::capture( - displayToken, consumer->getIGraphicBufferProducer(), + ScreenshotClient::capture(displayToken, + consumer->getIGraphicBufferProducer(), sourceCrop, width, height, uint32_t(minLayer), uint32_t(maxLayer), useIdentityTransform); } @@ -373,6 +394,10 @@ static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz, env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi); env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi); env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure); + env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos, + info.appVsyncOffset); + env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos, + info.presentationDeadline); env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj); env->DeleteLocalRef(infoObj); } @@ -393,20 +418,12 @@ static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenOb return err == NO_ERROR ? JNI_TRUE : JNI_FALSE; } -static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) { - sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); - if (token == NULL) return; - - ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off"); - SurfaceComposerClient::blankDisplay(token); -} - -static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) { +static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) { sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); if (token == NULL) return; - ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on"); - SurfaceComposerClient::unblankDisplay(token); + ALOGD_IF_SLOW(100, "Excessive delay in setPowerMode()"); + SurfaceComposerClient::setDisplayPowerMode(token, mode); } static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) { @@ -563,9 +580,9 @@ static JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeRelease }, {"nativeDestroy", "(J)V", (void*)nativeDestroy }, - {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZZ)Landroid/graphics/Bitmap;", + {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZ)Landroid/graphics/Bitmap;", (void*)nativeScreenshotBitmap }, - {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;IIIIZZ)V", + {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V", (void*)nativeScreenshot }, {"nativeOpenTransaction", "()V", (void*)nativeOpenTransaction }, @@ -609,10 +626,6 @@ static JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetActiveConfig }, {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z", (void*)nativeSetActiveConfig }, - {"nativeBlankDisplay", "(Landroid/os/IBinder;)V", - (void*)nativeBlankDisplay }, - {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V", - (void*)nativeUnblankDisplay }, {"nativeClearContentFrameStats", "(J)Z", (void*)nativeClearContentFrameStats }, {"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z", @@ -621,6 +634,8 @@ static JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeClearAnimationFrameStats }, {"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z", (void*)nativeGetAnimationFrameStats }, + {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V", + (void*)nativeSetDisplayPowerMode }, }; int register_android_view_SurfaceControl(JNIEnv* env) @@ -639,6 +654,16 @@ int register_android_view_SurfaceControl(JNIEnv* env) gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F"); gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F"); gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z"); + gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = env->GetFieldID(clazz, + "appVsyncOffsetNanos", "J"); + gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = env->GetFieldID(clazz, + "presentationDeadlineNanos", "J"); + + jclass rectClazz = env->FindClass("android/graphics/Rect"); + gRectClassInfo.bottom = env->GetFieldID(rectClazz, "bottom", "I"); + gRectClassInfo.left = env->GetFieldID(rectClazz, "left", "I"); + gRectClassInfo.right = env->GetFieldID(rectClazz, "right", "I"); + gRectClassInfo.top = env->GetFieldID(rectClazz, "top", "I"); jclass frameStatsClazz = env->FindClass("android/view/FrameStats"); jfieldID undefined_time_nano_field = env->GetStaticFieldID(frameStatsClazz, "UNDEFINED_TIME_NANO", "J"); diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp index 9258543..5c04a78 100644 --- a/core/jni/android_view_TextureView.cpp +++ b/core/jni/android_view_TextureView.cpp @@ -29,6 +29,8 @@ #include <SkCanvas.h> #include <SkImage.h> +#include "android/graphics/GraphicsJNI.h" + namespace android { // ---------------------------------------------------------------------------- @@ -45,7 +47,7 @@ static struct { static struct { jfieldID mSurfaceFormat; - jmethodID safeCanvasSwap; + jmethodID setNativeBitmap; } gCanvasClassInfo; static struct { @@ -71,17 +73,28 @@ static struct { // Native layer // ---------------------------------------------------------------------------- -static inline SkBitmap::Config convertPixelFormat(int32_t format) { - switch (format) { +// FIXME: consider exporting this to share (e.g. android_view_Surface.cpp) +static inline SkImageInfo convertPixelFormat(const ANativeWindow_Buffer& buffer) { + SkImageInfo info; + info.fWidth = buffer.width; + info.fHeight = buffer.height; + switch (buffer.format) { case WINDOW_FORMAT_RGBA_8888: - return SkBitmap::kARGB_8888_Config; + info.fColorType = kN32_SkColorType; + info.fAlphaType = kPremul_SkAlphaType; + break; case WINDOW_FORMAT_RGBX_8888: - return SkBitmap::kARGB_8888_Config; + info.fColorType = kN32_SkColorType; + info.fAlphaType = kOpaque_SkAlphaType; case WINDOW_FORMAT_RGB_565: - return SkBitmap::kRGB_565_Config; + info.fColorType = kRGB_565_SkColorType; + info.fAlphaType = kOpaque_SkAlphaType; default: - return SkBitmap::kNo_Config; + info.fColorType = kUnknown_SkColorType; + info.fAlphaType = kIgnore_SkAlphaType; + break; } + return info; } /** @@ -146,11 +159,7 @@ static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject, ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format); SkBitmap bitmap; - bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount); - - if (buffer.format == WINDOW_FORMAT_RGBX_8888) { - bitmap.setAlphaType(kOpaque_SkAlphaType); - } + bitmap.setInfo(convertPixelFormat(buffer), bytesCount); if (buffer.width > 0 && buffer.height > 0) { bitmap.setPixels(buffer.bits); @@ -159,12 +168,11 @@ static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject, } SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format); - - SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap)); - INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false); + INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(&bitmap)); SkRect clipRect; clipRect.set(rect.left, rect.top, rect.right, rect.bottom); + SkCanvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); nativeCanvas->clipRect(clipRect); if (dirtyRect) { @@ -178,8 +186,7 @@ static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject, static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject, jlong nativeWindow, jobject canvas) { - SkCanvas* nativeCanvas = SkNEW(SkCanvas); - INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false); + INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, (jlong)0); if (nativeWindow) { sp<ANativeWindow> window((ANativeWindow*) nativeWindow); @@ -228,7 +235,7 @@ int register_android_view_TextureView(JNIEnv* env) { FIND_CLASS(clazz, "android/graphics/Canvas"); GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I"); - GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V"); + GET_METHOD_ID(gCanvasClassInfo.setNativeBitmap, clazz, "setNativeBitmap", "(J)V"); FIND_CLASS(clazz, "android/view/TextureView"); GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "J"); diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 1397131..3e62d0b 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -22,6 +22,10 @@ #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <EGL/egl_cache.h> + #include <utils/StrongPointer.h> #include <android_runtime/android_view_Surface.h> #include <system/window.h> @@ -45,6 +49,14 @@ using namespace android::uirenderer::renderthread; static jmethodID gRunnableMethod; +static JNIEnv* getenv(JavaVM* vm) { + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm); + } + return env; +} + class JavaTask : public RenderTask { public: JavaTask(JNIEnv* env, jobject jrunnable) { @@ -53,44 +65,17 @@ public: } virtual void run() { - env()->CallVoidMethod(mRunnable, gRunnableMethod); - env()->DeleteGlobalRef(mRunnable); + JNIEnv* env = getenv(mVm); + env->CallVoidMethod(mRunnable, gRunnableMethod); + env->DeleteGlobalRef(mRunnable); delete this; }; private: - JNIEnv* env() { - JNIEnv* env; - if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - return 0; - } - return env; - } - JavaVM* mVm; jobject mRunnable; }; -class SetAtlasTask : public RenderTask { -public: - SetAtlasTask(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size) - : mBuffer(buffer) - , mMap(map) - , mMapSize(size) { - } - - virtual void run() { - CanvasContext::setTextureAtlas(mBuffer, mMap, mMapSize); - mMap = 0; - delete this; - } - -private: - sp<GraphicBuffer> mBuffer; - int64_t* mMap; - size_t mMapSize; -}; - class OnFinishedEvent { public: OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener) @@ -118,12 +103,34 @@ private: std::vector<OnFinishedEvent> mOnFinishedEvents; }; -class RootRenderNode : public RenderNode, public AnimationHook { +class RenderingException : public MessageHandler { +public: + RenderingException(JavaVM* vm, const std::string& message) + : mVm(vm) + , mMessage(message) { + } + + virtual void handleMessage(const Message&) { + throwException(mVm, mMessage); + } + + static void throwException(JavaVM* vm, const std::string& message) { + JNIEnv* env = getenv(vm); + jniThrowException(env, "java/lang/IllegalStateException", message.c_str()); + } + +private: + JavaVM* mVm; + std::string mMessage; +}; + +class RootRenderNode : public RenderNode, AnimationHook, ErrorHandler { public: - RootRenderNode() : RenderNode() { + RootRenderNode(JNIEnv* env) : RenderNode() { mLooper = Looper::getForThread(); LOG_ALWAYS_FATAL_IF(!mLooper.get(), "Must create RootRenderNode on a thread with a looper!"); + env->GetJavaVM(&mVm); } virtual ~RootRenderNode() {} @@ -133,10 +140,16 @@ public: mOnFinishedEvents.push_back(event); } + virtual void onError(const std::string& message) { + mLooper->sendMessage(new RenderingException(mVm, message), 0); + } + virtual void prepareTree(TreeInfo& info) { info.animationHook = this; + info.errorHandler = this; RenderNode::prepareTree(info); info.animationHook = NULL; + info.errorHandler = NULL; // post all the finished stuff if (mOnFinishedEvents.size()) { @@ -146,13 +159,21 @@ public: } } +protected: + virtual void damageSelf(TreeInfo& info) { + // Intentionally a no-op. As RootRenderNode gets a new DisplayListData + // every frame this would result in every draw push being a full inval, + // which is wrong. Only RootRenderNode has this issue. + } + private: sp<Looper> mLooper; std::vector<OnFinishedEvent> mOnFinishedEvents; + JavaVM* mVm; }; static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz, - jobject graphicBuffer, jlongArray atlasMapArray) { + jlong proxyPtr, jobject graphicBuffer, jlongArray atlasMapArray) { sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer); jsize len = env->GetArrayLength(atlasMapArray); if (len <= 0) { @@ -162,12 +183,12 @@ static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz, int64_t* map = new int64_t[len]; env->GetLongArrayRegion(atlasMapArray, 0, len, map); - SetAtlasTask* task = new SetAtlasTask(buffer, map, len); - RenderThread::getInstance().queue(task); + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + proxy->setTextureAtlas(buffer, map, len); } static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) { - RootRenderNode* node = new RootRenderNode(); + RootRenderNode* node = new RootRenderNode(env); node->incStrong(0); node->setName("RootRenderNode"); return reinterpret_cast<jlong>(node); @@ -238,11 +259,9 @@ static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz, } static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz, - jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density, - jint dirtyLeft, jint dirtyTop, jint dirtyRight, jint dirtyBottom) { + jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density, - dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); + return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density); } static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz, @@ -252,10 +271,9 @@ static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, j } static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz, - jlong proxyPtr, jlong functorPtr, jboolean waitForCompletion) { - RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + jlong functorPtr, jboolean waitForCompletion) { Functor* functor = reinterpret_cast<Functor*>(functorPtr); - proxy->invokeFunctor(functor, waitForCompletion); + RenderProxy::invokeFunctor(functor, waitForCompletion); } static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz, @@ -329,6 +347,18 @@ static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject c #endif // ---------------------------------------------------------------------------- +// Shaders +// ---------------------------------------------------------------------------- + +static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz, + jstring diskCachePath) { + + const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL); + egl_cache_t::get()->setCacheFilename(cacheArray); + env->ReleaseStringUTFChars(diskCachePath, cacheArray); +} + +// ---------------------------------------------------------------------------- // JNI Glue // ---------------------------------------------------------------------------- @@ -336,7 +366,7 @@ const char* const kClassPathName = "android/view/ThreadedRenderer"; static JNINativeMethod gMethods[] = { #ifdef USE_OPENGL_RENDERER - { "nSetAtlas", "(Landroid/view/GraphicBuffer;[J)V", (void*) android_view_ThreadedRenderer_setAtlas }, + { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V", (void*) android_view_ThreadedRenderer_setAtlas }, { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode }, { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy }, { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy }, @@ -347,9 +377,9 @@ static JNINativeMethod gMethods[] = { { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface }, { "nSetup", "(JIIFFFF)V", (void*) android_view_ThreadedRenderer_setup }, { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque }, - { "nSyncAndDrawFrame", "(JJJFIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, + { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface }, - { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, + { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext }, { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer }, { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer }, @@ -361,6 +391,8 @@ static JNINativeMethod gMethods[] = { { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending }, { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo }, #endif + { "setupShadersDiskCache", "(Ljava/lang/String;)V", + (void*) android_view_ThreadedRenderer_setupShadersDiskCache }, }; int register_android_view_ThreadedRenderer(JNIEnv* env) { diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index 381a5ee..226b764 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -46,6 +46,9 @@ #define LIB_SUFFIX ".so" #define LIB_SUFFIX_LEN (sizeof(LIB_SUFFIX) - 1) +#define RS_BITCODE_SUFFIX ".bc" +#define RS_BITCODE_SUFFIX_LEN (sizeof(RS_BITCODE_SUFFIX) -1) + #define GDBSERVER "gdbserver" #define GDBSERVER_LEN (sizeof(GDBSERVER) - 1) @@ -487,6 +490,42 @@ com_android_internal_content_NativeLibraryHelper_findSupportedAbi(JNIEnv *env, j return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch); } +enum bitcode_scan_result_t { + APK_SCAN_ERROR = -1, + NO_BITCODE_PRESENT = 0, + BITCODE_PRESENT = 1, +}; + +static jint +com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode(JNIEnv *env, jclass clazz, + jlong apkHandle) { + ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle); + void* cookie = NULL; + if (!zipFile->startIteration(&cookie)) { + return APK_SCAN_ERROR; + } + + char fileName[PATH_MAX]; + ZipEntryRO next = NULL; + while ((next = zipFile->nextEntry(cookie)) != NULL) { + if (zipFile->getEntryFileName(next, fileName, sizeof(fileName))) { + continue; + } + + const size_t fileNameLen = strlen(fileName); + const char* lastSlash = strrchr(fileName, '/'); + const char* baseName = (lastSlash == NULL) ? fileName : fileName + 1; + if (!strncmp(fileName + fileNameLen - RS_BITCODE_SUFFIX_LEN, RS_BITCODE_SUFFIX, + RS_BITCODE_SUFFIX_LEN) && isFilenameSafe(baseName)) { + zipFile->endIteration(cookie); + return BITCODE_PRESENT; + } + } + + zipFile->endIteration(cookie); + return NO_BITCODE_PRESENT; +} + static jlong com_android_internal_content_NativeLibraryHelper_openApk(JNIEnv *env, jclass, jstring apkPath) { @@ -518,6 +557,8 @@ static JNINativeMethod gMethods[] = { {"nativeFindSupportedAbi", "(J[Ljava/lang/String;)I", (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi}, + {"hasRenderscriptBitcode", "(J)I", + (void *)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode}, }; diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index c58bf04..0cdddba 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -14,46 +14,40 @@ * limitations under the License. */ -#include "android_runtime/AndroidRuntime.h" +#define LOG_TAG "Zygote" // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc #include <sys/mount.h> #include <linux/fs.h> #include <grp.h> +#include <fcntl.h> #include <paths.h> #include <signal.h> #include <stdlib.h> +#include <unistd.h> +#include <sys/capability.h> +#include <sys/personality.h> +#include <sys/prctl.h> #include <sys/resource.h> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> +#include <sys/utsname.h> #include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include "cutils/fs.h" -#include "cutils/multiuser.h" -#include "cutils/sched_policy.h" -#include "utils/String8.h" + +#include <cutils/fs.h> +#include <cutils/multiuser.h> +#include <cutils/sched_policy.h> +#include <utils/String8.h> +#include <selinux/android.h> + +#include "android_runtime/AndroidRuntime.h" #include "JNIHelp.h" #include "ScopedLocalRef.h" #include "ScopedPrimitiveArray.h" #include "ScopedUtfChars.h" -#if defined(HAVE_PRCTL) -#include <sys/prctl.h> -#endif - -#include <selinux/android.h> - -#if defined(__linux__) -#include <sys/personality.h> -#include <sys/utsname.h> -#if defined(HAVE_ANDROID_OS) -#include <sys/capability.h> -#endif -#endif - namespace { using android::String8; @@ -97,11 +91,9 @@ static void SigChldHandler(int /*signal_number*/) { if (WTERMSIG(status) != SIGKILL) { ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status)); } -#ifdef WCOREDUMP if (WCOREDUMP(status)) { ALOGI("Process %d dumped core.", pid); } -#endif /* ifdef WCOREDUMP */ } // If the just-crashed process is the system_server, bring down zygote @@ -199,8 +191,6 @@ static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) { } } -#if defined(HAVE_ANDROID_OS) - // The debug malloc library needs to know whether it's the zygote or a child. extern "C" int gMallocLeakZygoteChild; @@ -254,17 +244,6 @@ static void SetSchedulerPolicy(JNIEnv* env) { } } -#else - -static int gMallocLeakZygoteChild = 0; - -static void EnableKeepCapabilities(JNIEnv*) {} -static void DropCapabilitiesBoundingSet(JNIEnv*) {} -static void SetCapabilities(JNIEnv*, int64_t, int64_t) {} -static void SetSchedulerPolicy(JNIEnv*) {} - -#endif - // Create a private mount namespace and bind mount appropriate emulated // storage for the given user. static bool MountEmulatedStorage(uid_t uid, jint mount_mode) { @@ -337,7 +316,6 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode) { return true; } -#if defined(__linux__) static bool NeedsNoRandomizeWorkaround() { #if !defined(__arm__) return false; @@ -357,7 +335,6 @@ static bool NeedsNoRandomizeWorkaround() { return (major < 3) || ((major == 3) && (minor < 4)); #endif } -#endif // Utility to close down the Zygote socket file descriptors while // the child is still running as root with Zygote's privileges. Each @@ -474,7 +451,6 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra RuntimeAbort(env); } -#if defined(__linux__) if (NeedsNoRandomizeWorkaround()) { // Work around ARM kernel ASLR lossage (http://b/5817320). int old_personality = personality(0xffffffff); @@ -483,58 +459,49 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra ALOGW("personality(%d) failed", new_personality); } } -#endif SetCapabilities(env, permittedCapabilities, effectiveCapabilities); SetSchedulerPolicy(env); -#if defined(HAVE_ANDROID_OS) - { // NOLINT(whitespace/braces) - const char* se_info_c_str = NULL; - ScopedUtfChars* se_info = NULL; - if (java_se_info != NULL) { - se_info = new ScopedUtfChars(env, java_se_info); - se_info_c_str = se_info->c_str(); - if (se_info_c_str == NULL) { - ALOGE("se_info_c_str == NULL"); - RuntimeAbort(env); - } - } - const char* se_name_c_str = NULL; - ScopedUtfChars* se_name = NULL; - if (java_se_name != NULL) { - se_name = new ScopedUtfChars(env, java_se_name); - se_name_c_str = se_name->c_str(); - if (se_name_c_str == NULL) { - ALOGE("se_name_c_str == NULL"); - RuntimeAbort(env); - } - } - rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str); - if (rc == -1) { - ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid, - is_system_server, se_info_c_str, se_name_c_str); - RuntimeAbort(env); - } - - // Make it easier to debug audit logs by setting the main thread's name to the - // nice name rather than "app_process". - if (se_info_c_str == NULL && is_system_server) { - se_name_c_str = "system_server"; - } - if (se_info_c_str != NULL) { - SetThreadName(se_name_c_str); - } + const char* se_info_c_str = NULL; + ScopedUtfChars* se_info = NULL; + if (java_se_info != NULL) { + se_info = new ScopedUtfChars(env, java_se_info); + se_info_c_str = se_info->c_str(); + if (se_info_c_str == NULL) { + ALOGE("se_info_c_str == NULL"); + RuntimeAbort(env); + } + } + const char* se_name_c_str = NULL; + ScopedUtfChars* se_name = NULL; + if (java_se_name != NULL) { + se_name = new ScopedUtfChars(env, java_se_name); + se_name_c_str = se_name->c_str(); + if (se_name_c_str == NULL) { + ALOGE("se_name_c_str == NULL"); + RuntimeAbort(env); + } + } + rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str); + if (rc == -1) { + ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid, + is_system_server, se_info_c_str, se_name_c_str); + RuntimeAbort(env); + } - delete se_info; - delete se_name; + // Make it easier to debug audit logs by setting the main thread's name to the + // nice name rather than "app_process". + if (se_info_c_str == NULL && is_system_server) { + se_name_c_str = "system_server"; } -#else - UNUSED(is_system_server); - UNUSED(java_se_info); - UNUSED(java_se_name); -#endif + if (se_info_c_str != NULL) { + SetThreadName(se_name_c_str); + } + + delete se_info; + delete se_name; UnsetSigChldHandler(); |