size_t ScreenshotClient::getSize() const { return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format); }
void SpriteController::doUpdateSprites() { // Collect information about sprite updates. // Each sprite update record includes a reference to its associated sprite so we can // be certain the sprites will not be deleted while this function runs. Sprites // may invalidate themselves again during this time but we will handle those changes // in the next iteration. Vector<SpriteUpdate> updates; size_t numSprites; { // acquire lock AutoMutex _l(mLock); numSprites = mLocked.invalidatedSprites.size(); for (size_t i = 0; i < numSprites; i++) { const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i); updates.push(SpriteUpdate(sprite, sprite->getStateLocked())); sprite->resetDirtyLocked(); } mLocked.invalidatedSprites.clear(); } // release lock // Create missing surfaces. bool surfaceChanged = false; for (size_t i = 0; i < numSprites; i++) { SpriteUpdate& update = updates.editItemAt(i); if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) { update.state.surfaceWidth = update.state.icon.bitmap.width(); update.state.surfaceHeight = update.state.icon.bitmap.height(); update.state.surfaceDrawn = false; update.state.surfaceVisible = false; update.state.surfaceControl = obtainSurface( update.state.surfaceWidth, update.state.surfaceHeight); if (update.state.surfaceControl != NULL) { update.surfaceChanged = surfaceChanged = true; } } } // Resize sprites if needed, inside a global transaction. bool haveGlobalTransaction = false; for (size_t i = 0; i < numSprites; i++) { SpriteUpdate& update = updates.editItemAt(i); if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) { int32_t desiredWidth = update.state.icon.bitmap.width(); int32_t desiredHeight = update.state.icon.bitmap.height(); if (update.state.surfaceWidth < desiredWidth || update.state.surfaceHeight < desiredHeight) { if (!haveGlobalTransaction) { SurfaceComposerClient::openGlobalTransaction(); haveGlobalTransaction = true; } status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight); if (status) { ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d", status, update.state.surfaceWidth, update.state.surfaceHeight, desiredWidth, desiredHeight); } else { update.state.surfaceWidth = desiredWidth; update.state.surfaceHeight = desiredHeight; update.state.surfaceDrawn = false; update.surfaceChanged = surfaceChanged = true; if (update.state.surfaceVisible) { status = update.state.surfaceControl->hide(); if (status) { ALOGE("Error %d hiding sprite surface after resize.", status); } else { update.state.surfaceVisible = false; } } } } } } if (haveGlobalTransaction) { SurfaceComposerClient::closeGlobalTransaction(); } // Redraw sprites if needed. for (size_t i = 0; i < numSprites; i++) { SpriteUpdate& update = updates.editItemAt(i); if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) { update.state.surfaceDrawn = false; update.surfaceChanged = surfaceChanged = true; } if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn && update.state.wantSurfaceVisible()) { sp<Surface> surface = update.state.surfaceControl->getSurface(); ANativeWindow_Buffer outBuffer; status_t status = surface->lock(&outBuffer, NULL); if (status) { ALOGE("Error %d locking sprite surface before drawing.", status); } else { SkBitmap surfaceBitmap; ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); surfaceBitmap.installPixels(SkImageInfo::MakeN32Premul(outBuffer.width, outBuffer.height), outBuffer.bits, bpr); SkCanvas surfaceCanvas(surfaceBitmap); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint); if (outBuffer.width > update.state.icon.bitmap.width()) { paint.setColor(0); // transparent fill color surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0, outBuffer.width, update.state.icon.bitmap.height(), paint); } if (outBuffer.height > update.state.icon.bitmap.height()) { paint.setColor(0); // transparent fill color surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(), outBuffer.width, outBuffer.height, paint); } status = surface->unlockAndPost(); if (status) { ALOGE("Error %d unlocking and posting sprite surface after drawing.", status); } else { update.state.surfaceDrawn = true; update.surfaceChanged = surfaceChanged = true; } } } } // Set sprite surface properties and make them visible. bool haveTransaction = false; for (size_t i = 0; i < numSprites; i++) { SpriteUpdate& update = updates.editItemAt(i); bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible() && update.state.surfaceDrawn; bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible; bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible; if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) { status_t status; if (!haveTransaction) { SurfaceComposerClient::openGlobalTransaction(); haveTransaction = true; } if (wantSurfaceVisibleAndDrawn && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) { status = update.state.surfaceControl->setAlpha(update.state.alpha); if (status) { ALOGE("Error %d setting sprite surface alpha.", status); } } if (wantSurfaceVisibleAndDrawn && (becomingVisible || (update.state.dirty & (DIRTY_POSITION | DIRTY_HOTSPOT)))) { status = update.state.surfaceControl->setPosition( update.state.positionX - update.state.icon.hotSpotX, update.state.positionY - update.state.icon.hotSpotY); if (status) { ALOGE("Error %d setting sprite surface position.", status); } } if (wantSurfaceVisibleAndDrawn && (becomingVisible || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) { status = update.state.surfaceControl->setMatrix( update.state.transformationMatrix.dsdx, update.state.transformationMatrix.dtdx, update.state.transformationMatrix.dsdy, update.state.transformationMatrix.dtdy); if (status) { ALOGE("Error %d setting sprite surface transformation matrix.", status); } } int32_t surfaceLayer = mOverlayLayer + update.state.layer; if (wantSurfaceVisibleAndDrawn && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) { status = update.state.surfaceControl->setLayer(surfaceLayer); if (status) { ALOGE("Error %d setting sprite surface layer.", status); } } if (becomingVisible) { status = update.state.surfaceControl->show(); if (status) { ALOGE("Error %d showing sprite surface.", status); } else { update.state.surfaceVisible = true; update.surfaceChanged = surfaceChanged = true; } } else if (becomingHidden) { status = update.state.surfaceControl->hide(); if (status) { ALOGE("Error %d hiding sprite surface.", status); } else { update.state.surfaceVisible = false; update.surfaceChanged = surfaceChanged = true; } } } } if (haveTransaction) { SurfaceComposerClient::closeGlobalTransaction(); } // If any surfaces were changed, write back the new surface properties to the sprites. if (surfaceChanged) { // acquire lock AutoMutex _l(mLock); for (size_t i = 0; i < numSprites; i++) { const SpriteUpdate& update = updates.itemAt(i); if (update.surfaceChanged) { update.sprite->setSurfaceLocked(update.state.surfaceControl, update.state.surfaceWidth, update.state.surfaceHeight, update.state.surfaceDrawn, update.state.surfaceVisible); } } } // release lock // Clear the sprite update vector outside the lock. It is very important that // we do not clear sprite references inside the lock since we could be releasing // the last remaining reference to the sprite here which would result in the // sprite being deleted and the lock being reacquired by the sprite destructor // while already held. updates.clear(); }
static bool anp_surface_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) { if (!bitmap || !surfaceView) { return false; } void* surface = getSurface(env, surfaceView); if (!bitmap || !surface) { return false; } if (!init()) { return false; } void* region = NULL; if (dirtyRect) { region = malloc(ANDROID_REGION_SIZE); gSurfaceFunctions.regionConstructor(region); ARect rect; rect.left = dirtyRect->left; rect.top = dirtyRect->top; rect.right = dirtyRect->right; rect.bottom = dirtyRect->bottom; gSurfaceFunctions.setRegion(region, rect); } SurfaceInfo info; int err = gSurfaceFunctions.lock(surface, &info, region); if (err < 0) { LOG("Failed to lock surface"); return false; } // the surface may have expanded the dirty region so we must to pass that // information back to the plugin. if (dirtyRect) { ARect* dirtyBounds = (ARect*)region; // The bounds are the first member, so this should work! dirtyRect->left = dirtyBounds->left; dirtyRect->right = dirtyBounds->right; dirtyRect->top = dirtyBounds->top; dirtyRect->bottom = dirtyBounds->bottom; } if (region) free(region); int bpr = info.s * bytesPerPixel(info.format); bitmap->format = convertPixelFormat(info.format); bitmap->width = info.w; bitmap->height = info.h; bitmap->rowBytes = bpr; if (info.w > 0 && info.h > 0) { bitmap->baseAddr = info.bits; } else { bitmap->baseAddr = NULL; return false; } return true; }
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); SkBitmap bitmap; ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr); if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) { bitmap.setIsOpaque(true); } if (outBuffer.width > 0 && outBuffer.height > 0) { bitmap.setPixels(outBuffer.bits); } else { // be safe with an empty bitmap. bitmap.setPixels(NULL); } SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap)); swapCanvasPtr(env, canvasObj, nativeCanvas); if (dirtyRectPtr) { 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(); }
unsigned int ImageBase::bytesPerPlane() const { return bytesPerPixel() / planes(); }
static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect) { const sp<Surface>& surface(getSurface(env, clazz)); if (!Surface::isValid(surface)) { doThrowIAE(env); return 0; } // get dirty region Region dirtyRegion; if (dirtyRect) { Rect dirty; dirty.left = env->GetIntField(dirtyRect, ro.l); dirty.top = env->GetIntField(dirtyRect, ro.t); dirty.right = env->GetIntField(dirtyRect, ro.r); dirty.bottom= env->GetIntField(dirtyRect, ro.b); if (!dirty.isEmpty()) { dirtyRegion.set(dirty); } } else { dirtyRegion.set(Rect(0x3FFF,0x3FFF)); } Surface::SurfaceInfo info; status_t err = surface->lock(&info, &dirtyRegion); 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 jobject canvas = env->GetObjectField(clazz, so.canvas); env->SetIntField(canvas, co.surfaceFormat, info.format); SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas); SkBitmap bitmap; ssize_t bpr = info.s * bytesPerPixel(info.format); bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr); if (info.format == PIXEL_FORMAT_RGBX_8888) { bitmap.setIsOpaque(true); } if (info.w > 0 && info.h > 0) { bitmap.setPixels(info.bits); } else { // be safe with an empty bitmap. bitmap.setPixels(NULL); } nativeCanvas->setBitmapDevice(bitmap); SkRegion clipReg; if (dirtyRegion.isRect()) { // very common case const Rect b(dirtyRegion.getBounds()); clipReg.setRect(b.left, b.top, b.right, b.bottom); } else { size_t count; Rect const* r = dirtyRegion.getArray(&count); while (count) { clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op); r++, count--; } } nativeCanvas->clipRegion(clipReg); int saveCount = nativeCanvas->save(); env->SetIntField(clazz, so.saveCount, saveCount); if (dirtyRect) { const Rect& bounds(dirtyRegion.getBounds()); env->SetIntField(dirtyRect, ro.l, bounds.left); env->SetIntField(dirtyRect, ro.t, bounds.top); env->SetIntField(dirtyRect, ro.r, bounds.right); env->SetIntField(dirtyRect, ro.b, bounds.bottom); } return canvas; }
void LayerBase::loadTexture(const Region& dirty, GLint textureName, const GGLSurface& t, GLuint& textureWidth, GLuint& textureHeight) const { // TODO: defer the actual texture reload until LayerBase::validateTexture // is called. uint32_t flags = mFlags; glBindTexture(GL_TEXTURE_2D, textureName); GLuint tw = t.width; GLuint th = t.height; /* * In OpenGL ES we can't specify a stride with glTexImage2D (however, * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of * stride). * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we * need to do something reasonable (here creating a bigger texture). * * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); * * This situation doesn't happen often, but some h/w have a limitation * for their framebuffer (eg: must be multiple of 8 pixels), and * we need to take that into account when using these buffers as * textures. * * This should never be a problem with POT textures */ tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4); /* * round to POT if needed */ GLuint texture_w = tw; GLuint texture_h = th; if (!(flags & DisplayHardware::NPOT_EXTENSION)) { // find the smallest power-of-two that will accommodate our surface texture_w = 1 << (31 - clz(t.width)); texture_h = 1 << (31 - clz(t.height)); if (texture_w < t.width) texture_w <<= 1; if (texture_h < t.height) texture_h <<= 1; if (texture_w != tw || texture_h != th) { // we can't use DIRECT_TEXTURE since we changed the size // of the texture flags &= ~DisplayHardware::DIRECT_TEXTURE; } } if (flags & DisplayHardware::DIRECT_TEXTURE) { // here we're guaranteed that texture_{w|h} == t{w|h} if (t.format == GGL_PIXEL_FORMAT_RGB_565) { glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0, GL_RGB, tw, th, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) { glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE, t.data); } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) { // TODO: add GL_BGRA extension } else { // oops, we don't handle this format, try the regular path goto regular; } textureWidth = tw; textureHeight = th; } else { regular: Rect bounds(dirty.bounds()); GLvoid* data = 0; if (texture_w!=textureWidth || texture_h!=textureHeight) { // texture size changed, we need to create a new one if (!textureWidth || !textureHeight) { // this is the first time, load the whole texture if (texture_w==tw && texture_h==th) { // we can do it one pass data = t.data; } else { // we have to create the texture first because it // doesn't match the size of the buffer bounds.set(Rect(tw, th)); } } if (t.format == GGL_PIXEL_FORMAT_RGB_565) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture_w, texture_h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_w, texture_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_w, texture_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP || t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) { // just show the Y plane of YUV buffers data = t.data; glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texture_w, texture_h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); } else { // oops, we don't handle this format! LOGE("layer %p, texture=%d, using format %d, which is not " "supported by the GL", this, textureName, t.format); textureName = -1; } textureWidth = texture_w; textureHeight = texture_h; } if (!data && textureName>=0) { if (t.format == GGL_PIXEL_FORMAT_RGB_565) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data + bounds.top*t.width*2); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data + bounds.top*t.width*2); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGBA, GL_UNSIGNED_BYTE, t.data + bounds.top*t.width*4); } } } }
int Mouse::DrawCursor(CursorBounds desireBounds) { status_t status; if (mWantChange && mSurfaceVisible) { SurfaceComposerClient::openGlobalTransaction(); status = mSurfaceControl->show(); if (status) { printf("Error %d setting sprite surface show.\n", status); } SurfaceComposerClient::closeGlobalTransaction(); mWantChange = false; } if (mWantChange && !mSurfaceVisible) { SurfaceComposerClient::openGlobalTransaction(); status = mSurfaceControl->hide(); if (status) { printf("Error %d setting sprite surface hide.\n", status); } SurfaceComposerClient::closeGlobalTransaction(); mWantChange = false; } if (mUpdateCursor && mSurfaceVisible) { SurfaceComposerClient::openGlobalTransaction(); status = mSurfaceControl->setLayer(INT_MAX - 1); if (status) { printf("Error %d setting sprite surface setlayer.\n", status); } SurfaceComposerClient::closeGlobalTransaction(); SurfaceComposerClient::openGlobalTransaction(); if (desireBounds.width != mWidth || desireBounds.height != mHeight) { //SurfaceComposerClient::openGlobalTransaction(); status = mSurfaceControl->setSize(mWidth, mHeight); if (status) { printf("Error %d setting sprite surface show.\n", status); } mWidth = desireBounds.width; mHeight = desireBounds.height; } SurfaceComposerClient::closeGlobalTransaction(); sp<Surface> surface = mSurfaceControl->getSurface(); ANativeWindow_Buffer outBuffer; status = surface->lock(&outBuffer, NULL); SkBitmap surfaceBitmap; ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, outBuffer.width, outBuffer.height, bpr); printf("surface bpr size %d stride %d width %d height %d\n", bpr, outBuffer.stride, outBuffer.width, outBuffer.height); SkBitmap srcBitmap; bpr = desireBounds.width * bytesPerPixel(outBuffer.format); srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, desireBounds.width, desireBounds.height, bpr); printf("srcbitmap bpr size %d width %d height %d\n", bpr, desireBounds.width, desireBounds.height); surfaceBitmap.setPixels(outBuffer.bits); srcBitmap.setPixels(mDrawBitmaps); SkCanvas surfaceCanvas(surfaceBitmap); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); surfaceCanvas.drawBitmap(srcBitmap, 0, 0, &paint); if (outBuffer.width > uint32_t(srcBitmap.width())) { paint.setColor(0); // transparent fill color surfaceCanvas.drawRectCoords(srcBitmap.width(), 0, outBuffer.width, srcBitmap.height(), paint); } if (outBuffer.height > uint32_t(srcBitmap.height())) { paint.setColor(0); // transparent fill color surfaceCanvas.drawRectCoords(0, srcBitmap.height(), outBuffer.width, outBuffer.height, paint); } status = surface->unlockAndPost(); if (status) { printf("Error %d unlocking and posting sprite surface after drawing.\n", status); } mUpdateCursor = false; } if (mMove && mSurfaceVisible) { if (desireBounds.spotX != mSpotX) { mSpotX = desireBounds.spotX; } if (desireBounds.spotY != mSpotY) { mSpotY = desireBounds.spotY; } SurfaceComposerClient::openGlobalTransaction(); status = mSurfaceControl->setPosition(mPos.x - mSpotX, mPos.y - mSpotY); if (status) { printf("Error %d setting sprite surface position.\n", status); } SurfaceComposerClient::closeGlobalTransaction(); mMove = false; } return 0; }
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); SkRect r; android::Point lt = dirtyRect.leftTop(); android::Point rb = dirtyRect.rightBottom(); r.set(SkIntToScalar(lt.x), SkIntToScalar(lt.y), SkIntToScalar(rb.x), SkIntToScalar(rb.y)); nativeCanvas->clipRect(r); } 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(); }