static void Surface_unlockCanvasAndPost( JNIEnv* env, jobject clazz, jobject argCanvas) { jobject canvas = env->GetObjectField(clazz, so.canvas); if (env->IsSameObject(canvas, argCanvas) == JNI_FALSE) { doThrowIAE(env); return; } const sp<Surface>& surface(getSurface(env, clazz)); if (!Surface::isValid(surface)) return; // detach the canvas from the surface SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas); int saveCount = env->GetIntField(clazz, so.saveCount); nativeCanvas->restoreToCount(saveCount); nativeCanvas->setBitmapDevice(SkBitmap()); env->SetIntField(clazz, so.saveCount, 0); // unlock surface status_t err = surface->unlockAndPost(); if (err < 0) { doThrowIAE(env); } }
jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) { const SkImageInfo& info = bitmap->info(); if (info.fColorType == kUnknown_SkColorType) { doThrowIAE(env, "unknown bitmap configuration"); return NULL; } const int64_t size64 = bitmap->computeSize64(); if (!sk_64_isS32(size64)) { doThrowIAE(env, "bitmap size exceeds 32 bits"); return NULL; } const size_t size = sk_64_asS32(size64); jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime, gVMRuntime_newNonMovableArray, gByte_class, size); if (env->ExceptionCheck() != 0) { return NULL; } SkASSERT(arrayObj); jbyte* addr = (jbyte*) env->CallLongMethod(gVMRuntime, gVMRuntime_addressOf, arrayObj); if (env->ExceptionCheck() != 0) { return NULL; } SkASSERT(addr); SkPixelRef* pr = new AndroidPixelRef(env, info, (void*) addr, bitmap->rowBytes(), arrayObj, ctable); bitmap->setPixelRef(pr)->unref(); // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too bitmap->lockPixels(); return arrayObj; }
static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong nativeObject, jint layerStack) { SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); status_t err = ctrl->setLayerStack(layerStack); if (err < 0 && err != NO_INIT) { doThrowIAE(env); } }
static void nativeSetAlpha(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat alpha) { SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); status_t err = ctrl->setAlpha(alpha); if (err < 0 && err != NO_INIT) { doThrowIAE(env); } }
static void Surface_unfreezeDisplay( JNIEnv* env, jobject clazz, jint display) { int err = SurfaceComposerClient::unfreezeDisplay(display, 0); if (err < 0) { doThrowIAE(env); } }
static void Surface_setOrientation( JNIEnv* env, jobject clazz, jint display, jint orientation, jint flags) { int err = SurfaceComposerClient::setOrientation(display, orientation, flags); if (err < 0) { doThrowIAE(env); } }
static void nativeSetPositionAppliesWithResize(JNIEnv* env, jclass clazz, jlong nativeObject) { SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); status_t err = ctrl->setPositionAppliesWithResize(); if (err < 0 && err != NO_INIT) { doThrowIAE(env); } }
static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount) { Canvas* canvas = get_canvas(canvasHandle); if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) { doThrowIAE(env, "Underflow in restoreToCount"); return; } canvas->restoreToCount(restoreCount); }
static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) { SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); status_t err = ctrl->setMatrix(dsdx, dtdx, dsdy, dtdy); if (err < 0 && err != NO_INIT) { doThrowIAE(env); } }
static void restoreToCount(JNIEnv* env, jobject jcanvas, int restoreCount) { NPE_CHECK_RETURN_VOID(env, jcanvas); SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas); if (restoreCount < 1) { doThrowIAE(env, "Underflow in restoreToCount"); return; } canvas->restoreToCount(restoreCount); }
static void nativeSetFinalCrop(JNIEnv* env, jclass clazz, jlong nativeObject, jint l, jint t, jint r, jint b) { SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); Rect crop(l, t, r, b); status_t err = ctrl->setFinalCrop(crop); if (err < 0 && err != NO_INIT) { doThrowIAE(env); } }
static void Surface_setSize( JNIEnv* env, jobject clazz, jint w, jint h) { const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz)); if (surface == 0) return; status_t err = surface->setSize(w, h); if (err<0 && err!=NO_INIT) { doThrowIAE(env); } }
static void Surface_unfreeze( JNIEnv* env, jobject clazz) { const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz)); if (surface == 0) return; status_t err = surface->unfreeze(); if (err<0 && err!=NO_INIT) { doThrowIAE(env); } }
static void Surface_setAlpha( JNIEnv* env, jobject clazz, jfloat alpha) { const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz)); if (surface == 0) return; status_t err = surface->setAlpha(alpha); if (err<0 && err!=NO_INIT) { doThrowIAE(env); } }
static void Surface_setFlags( JNIEnv* env, jobject clazz, jint flags, jint mask) { const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz)); if (surface == 0) return; status_t err = surface->setFlags(flags, mask); if (err<0 && err!=NO_INIT) { doThrowIAE(env); } }
static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jlong nativeObject) { sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(sur)) { doThrowIAE(env); return JNI_FALSE; } int value = 0; ANativeWindow* anw = static_cast<ANativeWindow*>(sur.get()); anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value); return value; }
static void Surface_setMatrix( JNIEnv* env, jobject clazz, jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) { const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz)); if (surface == 0) return; status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy); if (err<0 && err!=NO_INIT) { doThrowIAE(env); } }
static jboolean nativeClearAnimationFrameStats(JNIEnv* env, jclass clazz) { status_t err = SurfaceComposerClient::clearAnimationFrameStats(); if (err < 0 && err != NO_INIT) { doThrowIAE(env); } // The other end is not ready, just report we failed. if (err == NO_INIT) { return JNI_FALSE; } return JNI_TRUE; }
static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) { SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); status_t err = ctrl->clearLayerFrameStats(); if (err < 0 && err != NO_INIT) { doThrowIAE(env); } // The other end is not ready, just report we failed. if (err == NO_INIT) { return JNI_FALSE; } return JNI_TRUE; }
static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong nativeObject, jobject regionObj) { SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj); if (!region) { doThrowIAE(env); return; } const SkIRect& b(region->getBounds()); Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom)); if (region->isComplex()) { SkRegion::Iterator it(*region); while (!it.done()) { const SkIRect& r(it.rect()); reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom); it.next(); } } status_t err = ctrl->setTransparentRegionHint(reg); if (err < 0 && err != NO_INIT) { doThrowIAE(env); } }
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj) { sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(surface)) { return; } // detach the canvas from the surface env->CallVoidMethod(canvasObj, gCanvasClassInfo.setNativeBitmap, (jlong)0); // unlock surface status_t err = surface->unlockAndPost(); if (err < 0) { doThrowIAE(env); } }
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj) { sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(surface)) { return; } // detach the canvas from the surface Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj); nativeCanvas->setBitmap(SkBitmap()); // unlock surface status_t err = surface->unlockAndPost(); if (err < 0) { doThrowIAE(env); } }
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj) { sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(surface)) { return; } // detach the canvas from the surface SkCanvas* nativeCanvas = SkNEW(SkCanvas); swapCanvasPtr(env, canvasObj, nativeCanvas); // unlock surface status_t err = surface->unlockAndPost(); if (err < 0) { doThrowIAE(env); } }
static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, jint width, jint height, jint configHandle, jint allocSize, jboolean requestPremul) { SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); // 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(); 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, // colortype and alphatype) has changed. ref->notifyPixelsChanged(); ref->unref(); }
static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject outStats) { FrameStats stats; status_t err = SurfaceComposerClient::getAnimationFrameStats(&stats); if (err < 0 && err != NO_INIT) { doThrowIAE(env); } // The other end is not ready, fine just return empty stats. if (err == NO_INIT) { return JNI_FALSE; } jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano); size_t frameCount = stats.desiredPresentTimesNano.size(); jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount); if (presentedTimesNanoDst == NULL) { return JNI_FALSE; } nsecs_t presentedTimesNanoSrc[frameCount]; for (size_t i = 0; i < frameCount; i++) { nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i]; if (presentedTimeNano == INT64_MAX) { presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO; } presentedTimesNanoSrc[i] = presentedTimeNano; } env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc); env->CallVoidMethod(outStats, gWindowAnimationFrameStatsClassInfo.init, refreshPeriodNano, presentedTimesNanoDst); if (env->ExceptionCheck()) { return JNI_FALSE; } return JNI_TRUE; }
static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, jint width, jint height, jint configHandle, jint allocSize) { SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle); if (width * height * SkBitmap::ComputeBytesPerPixel(config) > 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); 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. ref->notifyPixelsChanged(); SkSafeUnref(ref); }
static void nativeSetDirtyRect(JNIEnv* env, jclass clazz, jlong nativeObject, jobject dirtyRect) { #ifdef QCOM_BSP sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(surface)) { doThrowIAE(env); return; } Rect rect; rect.left = env->GetIntField(dirtyRect, gRectClassInfo.left); rect.top = env->GetIntField(dirtyRect, gRectClassInfo.top); rect.right = env->GetIntField(dirtyRect, gRectClassInfo.right); rect.bottom = env->GetIntField(dirtyRect, gRectClassInfo.bottom); surface->setDirtyRect(&rect); #endif }
static void Surface_setTransparentRegion( JNIEnv* env, jobject clazz, jobject argRegion) { const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz)); if (surface == 0) return; SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region); const SkIRect& b(nativeRegion->getBounds()); Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom)); if (nativeRegion->isComplex()) { SkRegion::Iterator it(*nativeRegion); while (!it.done()) { const SkIRect& r(it.rect()); reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom); it.next(); } } status_t err = surface->setTransparentRegionHint(reg); if (err<0 && err!=NO_INIT) { doThrowIAE(env); } }
static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) { if (NULL == ptr) { doThrowIAE(env); } }
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) { sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); if (!isSurfaceValid(surface)) { doThrowIAE(env); return 0; } Rect dirtyRect; Rect* dirtyRectPtr = NULL; if (dirtyRectObj) { dirtyRect.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left); dirtyRect.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top); dirtyRect.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right); dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom); dirtyRectPtr = &dirtyRect; } ANativeWindow_Buffer outBuffer; status_t err = surface->lock(&outBuffer, dirtyRectPtr); if (err < 0) { const char* const exception = (err == NO_MEMORY) ? OutOfResourcesException : "java/lang/IllegalArgumentException"; jniThrowException(env, exception, NULL); return 0; } // Associate a SkCanvas object to this surface env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format); SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height, convertPixelFormat(outBuffer.format), kPremul_SkAlphaType); if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) { 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 { // be safe with an empty bitmap. bitmap.setPixels(NULL); } 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)) ); } if (dirtyRectObj) { env->SetIntField(dirtyRectObj, gRectClassInfo.left, dirtyRect.left); env->SetIntField(dirtyRectObj, gRectClassInfo.top, dirtyRect.top); env->SetIntField(dirtyRectObj, gRectClassInfo.right, dirtyRect.right); env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom); } // Create another reference to the surface and return it. This reference // should be passed to nativeUnlockCanvasAndPost in place of mNativeObject, // because the latter could be replaced while the surface is locked. sp<Surface> lockedSurface(surface); lockedSurface->incStrong(&sRefBaseOwner); return (jlong) lockedSurface.get(); }