android_view_Surface.cpp revision 402c34649f514669517c2208e35caa58ff8bb2b9
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdio.h> 18 19#include "android_util_Binder.h" 20 21#include <ui/SurfaceComposerClient.h> 22#include <ui/Region.h> 23#include <ui/Rect.h> 24 25#include <SkCanvas.h> 26#include <SkBitmap.h> 27 28#include "jni.h" 29#include <android_runtime/AndroidRuntime.h> 30#include <utils/misc.h> 31 32 33// ---------------------------------------------------------------------------- 34 35namespace android { 36 37// ---------------------------------------------------------------------------- 38 39static const char* const OutOfResourcesException = 40 "android/view/Surface$OutOfResourcesException"; 41 42struct sso_t { 43 jfieldID client; 44}; 45static sso_t sso; 46 47struct so_t { 48 jfieldID surface; 49 jfieldID saveCount; 50 jfieldID canvas; 51}; 52static so_t so; 53 54struct ro_t { 55 jfieldID l; 56 jfieldID t; 57 jfieldID r; 58 jfieldID b; 59}; 60static ro_t ro; 61 62struct po_t { 63 jfieldID x; 64 jfieldID y; 65}; 66static po_t po; 67 68struct co_t { 69 jfieldID surfaceFormat; 70}; 71static co_t co; 72 73struct no_t { 74 jfieldID native_canvas; 75 jfieldID native_region; 76 jfieldID native_parcel; 77}; 78static no_t no; 79 80 81static __attribute__((noinline)) 82void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL) 83{ 84 if (!env->ExceptionOccurred()) { 85 jclass npeClazz = env->FindClass(exc); 86 env->ThrowNew(npeClazz, msg); 87 } 88} 89 90// ---------------------------------------------------------------------------- 91// ---------------------------------------------------------------------------- 92// ---------------------------------------------------------------------------- 93 94static void SurfaceSession_init(JNIEnv* env, jobject clazz) 95{ 96 sp<SurfaceComposerClient> client = new SurfaceComposerClient; 97 client->incStrong(clazz); 98 env->SetIntField(clazz, sso.client, (int)client.get()); 99} 100 101static void SurfaceSession_destroy(JNIEnv* env, jobject clazz) 102{ 103 SurfaceComposerClient* client = 104 (SurfaceComposerClient*)env->GetIntField(clazz, sso.client); 105 if (client != 0) { 106 client->decStrong(clazz); 107 env->SetIntField(clazz, sso.client, 0); 108 } 109} 110 111static void SurfaceSession_kill(JNIEnv* env, jobject clazz) 112{ 113 SurfaceComposerClient* client = 114 (SurfaceComposerClient*)env->GetIntField(clazz, sso.client); 115 if (client != 0) { 116 client->dispose(); 117 client->decStrong(clazz); 118 env->SetIntField(clazz, sso.client, 0); 119 } 120} 121 122// ---------------------------------------------------------------------------- 123 124static sp<Surface> getSurface(JNIEnv* env, jobject clazz) 125{ 126 Surface* const p = (Surface*)env->GetIntField(clazz, so.surface); 127 return sp<Surface>(p); 128} 129 130static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface) 131{ 132 Surface* const p = (Surface*)env->GetIntField(clazz, so.surface); 133 if (surface.get()) { 134 surface->incStrong(clazz); 135 } 136 if (p) { 137 p->decStrong(clazz); 138 } 139 env->SetIntField(clazz, so.surface, (int)surface.get()); 140} 141 142// ---------------------------------------------------------------------------- 143 144static void Surface_init( 145 JNIEnv* env, jobject clazz, 146 jobject session, jint pid, jint dpy, jint w, jint h, jint format, jint flags) 147{ 148 if (session == NULL) { 149 doThrow(env, "java/lang/NullPointerException"); 150 return; 151 } 152 153 SurfaceComposerClient* client = 154 (SurfaceComposerClient*)env->GetIntField(session, sso.client); 155 156 sp<Surface> surface(client->createSurface(pid, dpy, w, h, format, flags)); 157 if (surface == 0) { 158 doThrow(env, OutOfResourcesException); 159 return; 160 } 161 setSurface(env, clazz, surface); 162} 163 164static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel) 165{ 166 Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel); 167 if (parcel == NULL) { 168 doThrow(env, "java/lang/NullPointerException", NULL); 169 return; 170 } 171 const sp<Surface>& rhs = Surface::readFromParcel(parcel); 172 setSurface(env, clazz, rhs); 173} 174 175static void Surface_clear(JNIEnv* env, jobject clazz, uintptr_t *ostack) 176{ 177 const sp<Surface>& surface = getSurface(env, clazz); 178 if (Surface::isValid(surface)) { 179 surface->clear(); 180 } 181 setSurface(env, clazz, 0); 182} 183 184static void Surface_release(JNIEnv* env, jobject clazz, uintptr_t *ostack) 185{ 186 setSurface(env, clazz, 0); 187} 188 189static jboolean Surface_isValid(JNIEnv* env, jobject clazz) 190{ 191 const sp<Surface>& surface = getSurface(env, clazz); 192 return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE; 193} 194 195static inline SkBitmap::Config convertPixelFormat(PixelFormat format) 196{ 197 /* note: if PIXEL_FORMAT_XRGB_8888 means that all alpha bytes are 0xFF, then 198 we can map to SkBitmap::kARGB_8888_Config, and optionally call 199 bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator) 200 */ 201 switch (format) { 202 case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config; 203 case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config; 204 case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config; 205 case PIXEL_FORMAT_A_8: return SkBitmap::kA8_Config; 206 default: return SkBitmap::kNo_Config; 207 } 208} 209 210static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect) 211{ 212 const sp<Surface>& surface = getSurface(env, clazz); 213 if (!Surface::isValid(surface)) 214 return 0; 215 216 // get dirty region 217 Region dirtyRegion; 218 if (dirtyRect) { 219 Rect dirty; 220 dirty.left = env->GetIntField(dirtyRect, ro.l); 221 dirty.top = env->GetIntField(dirtyRect, ro.t); 222 dirty.right = env->GetIntField(dirtyRect, ro.r); 223 dirty.bottom= env->GetIntField(dirtyRect, ro.b); 224 if (dirty.left < dirty.right && dirty.top < dirty.bottom) { 225 dirtyRegion.set(dirty); 226 } 227 } else { 228 dirtyRegion.set(Rect(0x3FFF,0x3FFF)); 229 } 230 231 Surface::SurfaceInfo info; 232 status_t err = surface->lock(&info, &dirtyRegion); 233 if (err < 0) { 234 const char* const exception = (err == NO_MEMORY) ? 235 OutOfResourcesException : 236 "java/lang/IllegalArgumentException"; 237 doThrow(env, exception, NULL); 238 return 0; 239 } 240 241 // Associate a SkCanvas object to this surface 242 jobject canvas = env->GetObjectField(clazz, so.canvas); 243 env->SetIntField(canvas, co.surfaceFormat, info.format); 244 245 SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas); 246 SkBitmap bitmap; 247 ssize_t bpr = info.s * bytesPerPixel(info.format); 248 bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr); 249 if (info.w > 0 && info.h > 0) { 250 bitmap.setPixels(info.bits); 251 } else { 252 // be safe with an empty bitmap. 253 bitmap.setPixels(NULL); 254 } 255 nativeCanvas->setBitmapDevice(bitmap); 256 nativeCanvas->clipRegion(dirtyRegion.toSkRegion()); 257 258 int saveCount = nativeCanvas->save(); 259 env->SetIntField(clazz, so.saveCount, saveCount); 260 261 if (dirtyRect) { 262 Rect bounds(dirtyRegion.bounds()); 263 env->SetIntField(dirtyRect, ro.l, bounds.left); 264 env->SetIntField(dirtyRect, ro.t, bounds.top); 265 env->SetIntField(dirtyRect, ro.r, bounds.right); 266 env->SetIntField(dirtyRect, ro.b, bounds.bottom); 267 } 268 269 return canvas; 270} 271 272static void Surface_unlockCanvasAndPost( 273 JNIEnv* env, jobject clazz, jobject argCanvas) 274{ 275 jobject canvas = env->GetObjectField(clazz, so.canvas); 276 if (canvas != argCanvas) { 277 doThrow(env, "java/lang/IllegalArgumentException", NULL); 278 return; 279 } 280 281 const sp<Surface>& surface = getSurface(env, clazz); 282 if (!Surface::isValid(surface)) 283 return; 284 285 // detach the canvas from the surface 286 SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas); 287 int saveCount = env->GetIntField(clazz, so.saveCount); 288 nativeCanvas->restoreToCount(saveCount); 289 nativeCanvas->setBitmapDevice(SkBitmap()); 290 env->SetIntField(clazz, so.saveCount, 0); 291 292 // unlock surface 293 status_t err = surface->unlockAndPost(); 294 if (err < 0) { 295 doThrow(env, "java/lang/IllegalArgumentException", NULL); 296 } 297} 298 299static void Surface_unlockCanvas( 300 JNIEnv* env, jobject clazz, jobject argCanvas) 301{ 302 // XXX: this API has been removed 303 doThrow(env, "java/lang/IllegalArgumentException", NULL); 304} 305 306static void Surface_openTransaction( 307 JNIEnv* env, jobject clazz) 308{ 309 SurfaceComposerClient::openGlobalTransaction(); 310} 311 312static void Surface_closeTransaction( 313 JNIEnv* env, jobject clazz) 314{ 315 SurfaceComposerClient::closeGlobalTransaction(); 316} 317 318static void Surface_setOrientation( 319 JNIEnv* env, jobject clazz, jint display, jint orientation, jint flags) 320{ 321 int err = SurfaceComposerClient::setOrientation(display, orientation, flags); 322 if (err < 0) { 323 doThrow(env, "java/lang/IllegalArgumentException", NULL); 324 } 325} 326 327static void Surface_freezeDisplay( 328 JNIEnv* env, jobject clazz, jint display) 329{ 330 int err = SurfaceComposerClient::freezeDisplay(display, 0); 331 if (err < 0) { 332 doThrow(env, "java/lang/IllegalArgumentException", NULL); 333 } 334} 335 336static void Surface_unfreezeDisplay( 337 JNIEnv* env, jobject clazz, jint display) 338{ 339 int err = SurfaceComposerClient::unfreezeDisplay(display, 0); 340 if (err < 0) { 341 doThrow(env, "java/lang/IllegalArgumentException", NULL); 342 } 343} 344 345static void Surface_setLayer( 346 JNIEnv* env, jobject clazz, jint zorder) 347{ 348 const sp<Surface>& surface = getSurface(env, clazz); 349 if (Surface::isValid(surface)) { 350 if (surface->setLayer(zorder) < 0) { 351 doThrow(env, "java/lang/IllegalArgumentException", NULL); 352 } 353 } 354} 355 356static void Surface_setPosition( 357 JNIEnv* env, jobject clazz, jint x, jint y) 358{ 359 const sp<Surface>& surface = getSurface(env, clazz); 360 if (Surface::isValid(surface)) { 361 if (surface->setPosition(x, y) < 0) { 362 doThrow(env, "java/lang/IllegalArgumentException", NULL); 363 } 364 } 365} 366 367static void Surface_setSize( 368 JNIEnv* env, jobject clazz, jint w, jint h) 369{ 370 const sp<Surface>& surface = getSurface(env, clazz); 371 if (Surface::isValid(surface)) { 372 if (surface->setSize(w, h) < 0) { 373 doThrow(env, "java/lang/IllegalArgumentException", NULL); 374 } 375 } 376} 377 378static void Surface_hide( 379 JNIEnv* env, jobject clazz) 380{ 381 const sp<Surface>& surface = getSurface(env, clazz); 382 if (Surface::isValid(surface)) { 383 if (surface->hide() < 0) { 384 doThrow(env, "java/lang/IllegalArgumentException", NULL); 385 } 386 } 387} 388 389static void Surface_show( 390 JNIEnv* env, jobject clazz) 391{ 392 const sp<Surface>& surface = getSurface(env, clazz); 393 if (Surface::isValid(surface)) { 394 if (surface->show() < 0) { 395 doThrow(env, "java/lang/IllegalArgumentException", NULL); 396 } 397 } 398} 399 400static void Surface_freeze( 401 JNIEnv* env, jobject clazz) 402{ 403 const sp<Surface>& surface = getSurface(env, clazz); 404 if (Surface::isValid(surface)) { 405 if (surface->freeze() < 0) { 406 doThrow(env, "java/lang/IllegalArgumentException", NULL); 407 } 408 } 409} 410 411static void Surface_unfreeze( 412 JNIEnv* env, jobject clazz) 413{ 414 const sp<Surface>& surface = getSurface(env, clazz); 415 if (Surface::isValid(surface)) { 416 if (surface->unfreeze() < 0) { 417 doThrow(env, "java/lang/IllegalArgumentException", NULL); 418 } 419 } 420} 421 422static void Surface_setFlags( 423 JNIEnv* env, jobject clazz, jint flags, jint mask) 424{ 425 const sp<Surface>& surface = getSurface(env, clazz); 426 if (Surface::isValid(surface)) { 427 if (surface->setFlags(flags, mask) < 0) { 428 doThrow(env, "java/lang/IllegalArgumentException", NULL); 429 } 430 } 431} 432 433static void Surface_setTransparentRegion( 434 JNIEnv* env, jobject clazz, jobject argRegion) 435{ 436 const sp<Surface>& surface = getSurface(env, clazz); 437 if (Surface::isValid(surface)) { 438 SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region); 439 if (surface->setTransparentRegionHint(Region(*nativeRegion)) < 0) { 440 doThrow(env, "java/lang/IllegalArgumentException", NULL); 441 } 442 } 443} 444 445static void Surface_setAlpha( 446 JNIEnv* env, jobject clazz, jfloat alpha) 447{ 448 const sp<Surface>& surface = getSurface(env, clazz); 449 if (Surface::isValid(surface)) { 450 if (surface->setAlpha(alpha) < 0) { 451 doThrow(env, "java/lang/IllegalArgumentException", NULL); 452 } 453 } 454} 455 456static void Surface_setMatrix( 457 JNIEnv* env, jobject clazz, 458 jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) 459{ 460 const sp<Surface>& surface = getSurface(env, clazz); 461 if (Surface::isValid(surface)) { 462 if (surface->setMatrix(dsdx, dtdx, dsdy, dtdy) < 0) { 463 doThrow(env, "java/lang/IllegalArgumentException", NULL); 464 } 465 } 466} 467 468static void Surface_setFreezeTint( 469 JNIEnv* env, jobject clazz, 470 jint tint) 471{ 472 const sp<Surface>& surface = getSurface(env, clazz); 473 if (Surface::isValid(surface)) { 474 if (surface->setFreezeTint(tint) < 0) { 475 doThrow(env, "java/lang/IllegalArgumentException", NULL); 476 } 477 } 478} 479 480static void Surface_copyFrom( 481 JNIEnv* env, jobject clazz, jobject other) 482{ 483 if (clazz == other) 484 return; 485 486 if (other == NULL) { 487 doThrow(env, "java/lang/NullPointerException", NULL); 488 return; 489 } 490 491 const sp<Surface>& surface = getSurface(env, clazz); 492 const sp<Surface>& rhs = getSurface(env, other); 493 if (!Surface::isSameSurface(surface, rhs)) { 494 // we reassign the surface only if it's a different one 495 // otherwise we would loose our client-side state. 496 setSurface(env, clazz, rhs); 497 } 498} 499 500 501static void Surface_readFromParcel( 502 JNIEnv* env, jobject clazz, jobject argParcel) 503{ 504 Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel); 505 if (parcel == NULL) { 506 doThrow(env, "java/lang/NullPointerException", NULL); 507 return; 508 } 509 510 const sp<Surface>& surface = getSurface(env, clazz); 511 const sp<Surface>& rhs = Surface::readFromParcel(parcel); 512 if (!Surface::isSameSurface(surface, rhs)) { 513 // we reassign the surface only if it's a different one 514 // otherwise we would loose our client-side state. 515 setSurface(env, clazz, rhs); 516 } 517} 518 519static void Surface_writeToParcel( 520 JNIEnv* env, jobject clazz, jobject argParcel, jint flags) 521{ 522 Parcel* parcel = (Parcel*)env->GetIntField( 523 argParcel, no.native_parcel); 524 525 if (parcel == NULL) { 526 doThrow(env, "java/lang/NullPointerException", NULL); 527 return; 528 } 529 530 const sp<Surface>& surface = getSurface(env, clazz); 531 Surface::writeToParcel(surface, parcel); 532} 533 534// ---------------------------------------------------------------------------- 535// ---------------------------------------------------------------------------- 536// ---------------------------------------------------------------------------- 537 538const char* const kSurfaceSessionClassPathName = "android/view/SurfaceSession"; 539const char* const kSurfaceClassPathName = "android/view/Surface"; 540static void nativeClassInit(JNIEnv* env, jclass clazz); 541 542static JNINativeMethod gSurfaceSessionMethods[] = { 543 {"init", "()V", (void*)SurfaceSession_init }, 544 {"destroy", "()V", (void*)SurfaceSession_destroy }, 545 {"kill", "()V", (void*)SurfaceSession_kill }, 546}; 547 548static JNINativeMethod gSurfaceMethods[] = { 549 {"nativeClassInit", "()V", (void*)nativeClassInit }, 550 {"init", "(Landroid/view/SurfaceSession;IIIIII)V", (void*)Surface_init }, 551 {"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel }, 552 {"clear", "()V", (void*)Surface_clear }, 553 {"release", "()V", (void*)Surface_release }, 554 {"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom }, 555 {"isValid", "()Z", (void*)Surface_isValid }, 556 {"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas }, 557 {"unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvasAndPost }, 558 {"unlockCanvas", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvas }, 559 {"openTransaction", "()V", (void*)Surface_openTransaction }, 560 {"closeTransaction", "()V", (void*)Surface_closeTransaction }, 561 {"setOrientation", "(III)V", (void*)Surface_setOrientation }, 562 {"freezeDisplay", "(I)V", (void*)Surface_freezeDisplay }, 563 {"unfreezeDisplay", "(I)V", (void*)Surface_unfreezeDisplay }, 564 {"setLayer", "(I)V", (void*)Surface_setLayer }, 565 {"setPosition", "(II)V",(void*)Surface_setPosition }, 566 {"setSize", "(II)V",(void*)Surface_setSize }, 567 {"hide", "()V", (void*)Surface_hide }, 568 {"show", "()V", (void*)Surface_show }, 569 {"freeze", "()V", (void*)Surface_freeze }, 570 {"unfreeze", "()V", (void*)Surface_unfreeze }, 571 {"setFlags", "(II)V",(void*)Surface_setFlags }, 572 {"setTransparentRegionHint","(Landroid/graphics/Region;)V", (void*)Surface_setTransparentRegion }, 573 {"setAlpha", "(F)V", (void*)Surface_setAlpha }, 574 {"setMatrix", "(FFFF)V", (void*)Surface_setMatrix }, 575 {"setFreezeTint", "(I)V", (void*)Surface_setFreezeTint }, 576 {"readFromParcel", "(Landroid/os/Parcel;)V", (void*)Surface_readFromParcel }, 577 {"writeToParcel", "(Landroid/os/Parcel;I)V", (void*)Surface_writeToParcel }, 578}; 579 580void nativeClassInit(JNIEnv* env, jclass clazz) 581{ 582 so.surface = env->GetFieldID(clazz, "mSurface", "I"); 583 so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I"); 584 so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;"); 585 586 jclass surfaceSession = env->FindClass("android/view/SurfaceSession"); 587 sso.client = env->GetFieldID(surfaceSession, "mClient", "I"); 588 589 jclass canvas = env->FindClass("android/graphics/Canvas"); 590 no.native_canvas = env->GetFieldID(canvas, "mNativeCanvas", "I"); 591 co.surfaceFormat = env->GetFieldID(canvas, "mSurfaceFormat", "I"); 592 593 jclass region = env->FindClass("android/graphics/Region"); 594 no.native_region = env->GetFieldID(region, "mNativeRegion", "I"); 595 596 jclass parcel = env->FindClass("android/os/Parcel"); 597 no.native_parcel = env->GetFieldID(parcel, "mObject", "I"); 598 599 jclass rect = env->FindClass("android/graphics/Rect"); 600 ro.l = env->GetFieldID(rect, "left", "I"); 601 ro.t = env->GetFieldID(rect, "top", "I"); 602 ro.r = env->GetFieldID(rect, "right", "I"); 603 ro.b = env->GetFieldID(rect, "bottom", "I"); 604 605 jclass point = env->FindClass("android/graphics/Point"); 606 po.x = env->GetFieldID(point, "x", "I"); 607 po.y = env->GetFieldID(point, "y", "I"); 608} 609 610int register_android_view_Surface(JNIEnv* env) 611{ 612 int err; 613 err = AndroidRuntime::registerNativeMethods(env, kSurfaceSessionClassPathName, 614 gSurfaceSessionMethods, NELEM(gSurfaceSessionMethods)); 615 616 err |= AndroidRuntime::registerNativeMethods(env, kSurfaceClassPathName, 617 gSurfaceMethods, NELEM(gSurfaceMethods)); 618 return err; 619} 620 621}; 622 623