android_view_Surface.cpp revision 3001a035439d8134a7d70d796376d1dfbff3cdcd
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 setSurface(env, clazz, 0); 178} 179 180static jboolean Surface_isValid(JNIEnv* env, jobject clazz) 181{ 182 const sp<Surface>& surface = getSurface(env, clazz); 183 return surface->isValid() ? JNI_TRUE : JNI_FALSE; 184} 185 186static inline SkBitmap::Config convertPixelFormat(PixelFormat format) 187{ 188 /* note: if PIXEL_FORMAT_XRGB_8888 means that all alpha bytes are 0xFF, then 189 we can map to SkBitmap::kARGB_8888_Config, and optionally call 190 bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator) 191 */ 192 switch (format) { 193 case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config; 194 case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config; 195 case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config; 196 case PIXEL_FORMAT_A_8: return SkBitmap::kA8_Config; 197 default: return SkBitmap::kNo_Config; 198 } 199} 200 201static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect) 202{ 203 const sp<Surface>& surface = getSurface(env, clazz); 204 if (!surface->isValid()) 205 return 0; 206 207 // get dirty region 208 Region dirtyRegion; 209 if (dirtyRect) { 210 Rect dirty; 211 dirty.left = env->GetIntField(dirtyRect, ro.l); 212 dirty.top = env->GetIntField(dirtyRect, ro.t); 213 dirty.right = env->GetIntField(dirtyRect, ro.r); 214 dirty.bottom= env->GetIntField(dirtyRect, ro.b); 215 if (dirty.left < dirty.right && dirty.top < dirty.bottom) { 216 dirtyRegion.set(dirty); 217 } 218 } else { 219 dirtyRegion.set(Rect(0x3FFF,0x3FFF)); 220 } 221 222 Surface::SurfaceInfo info; 223 status_t err = surface->lock(&info, &dirtyRegion); 224 if (err < 0) { 225 const char* const exception = (err == NO_MEMORY) ? 226 OutOfResourcesException : 227 "java/lang/IllegalArgumentException"; 228 doThrow(env, exception, NULL); 229 return 0; 230 } 231 232 // Associate a SkCanvas object to this surface 233 jobject canvas = env->GetObjectField(clazz, so.canvas); 234 env->SetIntField(canvas, co.surfaceFormat, info.format); 235 236 SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas); 237 SkBitmap bitmap; 238 bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, info.bpr); 239 if (info.w > 0 && info.h > 0) { 240 bitmap.setPixels(info.bits); 241 } else { 242 // be safe with an empty bitmap. 243 bitmap.setPixels(NULL); 244 } 245 nativeCanvas->setBitmapDevice(bitmap); 246 nativeCanvas->clipRegion(dirtyRegion.toSkRegion()); 247 248 int saveCount = nativeCanvas->save(); 249 env->SetIntField(clazz, so.saveCount, saveCount); 250 251 if (dirtyRect) { 252 Rect bounds(dirtyRegion.bounds()); 253 env->SetIntField(dirtyRect, ro.l, bounds.left); 254 env->SetIntField(dirtyRect, ro.t, bounds.top); 255 env->SetIntField(dirtyRect, ro.r, bounds.right); 256 env->SetIntField(dirtyRect, ro.b, bounds.bottom); 257 } 258 259 return canvas; 260} 261 262static void Surface_unlockCanvasAndPost( 263 JNIEnv* env, jobject clazz, jobject argCanvas) 264{ 265 jobject canvas = env->GetObjectField(clazz, so.canvas); 266 if (canvas != argCanvas) { 267 doThrow(env, "java/lang/IllegalArgumentException", NULL); 268 return; 269 } 270 271 const sp<Surface>& surface = getSurface(env, clazz); 272 if (!surface->isValid()) 273 return; 274 275 // detach the canvas from the surface 276 SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas); 277 int saveCount = env->GetIntField(clazz, so.saveCount); 278 nativeCanvas->restoreToCount(saveCount); 279 nativeCanvas->setBitmapDevice(SkBitmap()); 280 env->SetIntField(clazz, so.saveCount, 0); 281 282 // unlock surface 283 status_t err = surface->unlockAndPost(); 284 if (err < 0) { 285 doThrow(env, "java/lang/IllegalArgumentException", NULL); 286 } 287} 288 289static void Surface_unlockCanvas( 290 JNIEnv* env, jobject clazz, jobject argCanvas) 291{ 292 jobject canvas = env->GetObjectField(clazz, so.canvas); 293 if (canvas != argCanvas) { 294 doThrow(env, "java/lang/IllegalArgumentException", NULL); 295 return; 296 } 297 298 const sp<Surface>& surface = getSurface(env, clazz); 299 if (!surface->isValid()) 300 return; 301 302 status_t err = surface->unlock(); 303 if (err < 0) { 304 doThrow(env, "java/lang/IllegalArgumentException", NULL); 305 return; 306 } 307 SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas); 308 int saveCount = env->GetIntField(clazz, so.saveCount); 309 nativeCanvas->restoreToCount(saveCount); 310 nativeCanvas->setBitmapDevice(SkBitmap()); 311 env->SetIntField(clazz, so.saveCount, 0); 312} 313 314static void Surface_openTransaction( 315 JNIEnv* env, jobject clazz) 316{ 317 SurfaceComposerClient::openGlobalTransaction(); 318} 319 320static void Surface_closeTransaction( 321 JNIEnv* env, jobject clazz) 322{ 323 SurfaceComposerClient::closeGlobalTransaction(); 324} 325 326static void Surface_setOrientation( 327 JNIEnv* env, jobject clazz, jint display, jint orientation) 328{ 329 int err = SurfaceComposerClient::setOrientation(display, orientation); 330 if (err < 0) { 331 doThrow(env, "java/lang/IllegalArgumentException", NULL); 332 } 333} 334 335static void Surface_freezeDisplay( 336 JNIEnv* env, jobject clazz, jint display) 337{ 338 int err = SurfaceComposerClient::freezeDisplay(display, 0); 339 if (err < 0) { 340 doThrow(env, "java/lang/IllegalArgumentException", NULL); 341 } 342} 343 344static void Surface_unfreezeDisplay( 345 JNIEnv* env, jobject clazz, jint display) 346{ 347 int err = SurfaceComposerClient::unfreezeDisplay(display, 0); 348 if (err < 0) { 349 doThrow(env, "java/lang/IllegalArgumentException", NULL); 350 } 351} 352 353static void Surface_setLayer( 354 JNIEnv* env, jobject clazz, jint zorder) 355{ 356 const sp<Surface>& surface = getSurface(env, clazz); 357 if (surface->isValid()) { 358 if (surface->setLayer(zorder) < 0) { 359 doThrow(env, "java/lang/IllegalArgumentException", NULL); 360 } 361 } 362} 363 364static void Surface_setPosition( 365 JNIEnv* env, jobject clazz, jint x, jint y) 366{ 367 const sp<Surface>& surface = getSurface(env, clazz); 368 if (surface->isValid()) { 369 if (surface->setPosition(x, y) < 0) { 370 doThrow(env, "java/lang/IllegalArgumentException", NULL); 371 } 372 } 373} 374 375static void Surface_setSize( 376 JNIEnv* env, jobject clazz, jint w, jint h) 377{ 378 const sp<Surface>& surface = getSurface(env, clazz); 379 if (surface->isValid()) { 380 if (surface->setSize(w, h) < 0) { 381 doThrow(env, "java/lang/IllegalArgumentException", NULL); 382 } 383 } 384} 385 386static void Surface_hide( 387 JNIEnv* env, jobject clazz) 388{ 389 const sp<Surface>& surface = getSurface(env, clazz); 390 if (surface->isValid()) { 391 if (surface->hide() < 0) { 392 doThrow(env, "java/lang/IllegalArgumentException", NULL); 393 } 394 } 395} 396 397static void Surface_show( 398 JNIEnv* env, jobject clazz) 399{ 400 const sp<Surface>& surface = getSurface(env, clazz); 401 if (surface->isValid()) { 402 if (surface->show() < 0) { 403 doThrow(env, "java/lang/IllegalArgumentException", NULL); 404 } 405 } 406} 407 408static void Surface_freeze( 409 JNIEnv* env, jobject clazz) 410{ 411 const sp<Surface>& surface = getSurface(env, clazz); 412 if (surface->isValid()) { 413 if (surface->freeze() < 0) { 414 doThrow(env, "java/lang/IllegalArgumentException", NULL); 415 } 416 } 417} 418 419static void Surface_unfreeze( 420 JNIEnv* env, jobject clazz) 421{ 422 const sp<Surface>& surface = getSurface(env, clazz); 423 if (surface->isValid()) { 424 if (surface->unfreeze() < 0) { 425 doThrow(env, "java/lang/IllegalArgumentException", NULL); 426 } 427 } 428} 429 430static void Surface_setFlags( 431 JNIEnv* env, jobject clazz, jint flags, jint mask) 432{ 433 const sp<Surface>& surface = getSurface(env, clazz); 434 if (surface->isValid()) { 435 if (surface->setFlags(flags, mask) < 0) { 436 doThrow(env, "java/lang/IllegalArgumentException", NULL); 437 } 438 } 439} 440 441static void Surface_setTransparentRegion( 442 JNIEnv* env, jobject clazz, jobject argRegion) 443{ 444 const sp<Surface>& surface = getSurface(env, clazz); 445 if (surface->isValid()) { 446 SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region); 447 if (surface->setTransparentRegionHint(Region(*nativeRegion)) < 0) { 448 doThrow(env, "java/lang/IllegalArgumentException", NULL); 449 } 450 } 451} 452 453static void Surface_setAlpha( 454 JNIEnv* env, jobject clazz, jfloat alpha) 455{ 456 const sp<Surface>& surface = getSurface(env, clazz); 457 if (surface->isValid()) { 458 if (surface->setAlpha(alpha) < 0) { 459 doThrow(env, "java/lang/IllegalArgumentException", NULL); 460 } 461 } 462} 463 464static void Surface_setMatrix( 465 JNIEnv* env, jobject clazz, 466 jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) 467{ 468 const sp<Surface>& surface = getSurface(env, clazz); 469 if (surface->isValid()) { 470 if (surface->setMatrix(dsdx, dtdx, dsdy, dtdy) < 0) { 471 doThrow(env, "java/lang/IllegalArgumentException", NULL); 472 } 473 } 474} 475 476static void Surface_setFreezeTint( 477 JNIEnv* env, jobject clazz, 478 jint tint) 479{ 480 const sp<Surface>& surface = getSurface(env, clazz); 481 if (surface->isValid()) { 482 if (surface->setFreezeTint(tint) < 0) { 483 doThrow(env, "java/lang/IllegalArgumentException", NULL); 484 } 485 } 486} 487 488static void Surface_copyFrom( 489 JNIEnv* env, jobject clazz, jobject other) 490{ 491 if (clazz == other) 492 return; 493 494 if (other == NULL) { 495 doThrow(env, "java/lang/NullPointerException", NULL); 496 return; 497 } 498 499 const sp<Surface>& surface = getSurface(env, clazz); 500 const sp<Surface>& rhs = getSurface(env, other); 501 if (!Surface::isSameSurface(surface, rhs)) { 502 // we reassign the surface only if it's a different one 503 // otherwise we would loose our client-side state. 504 setSurface(env, clazz, rhs->dup()); 505 } 506} 507 508 509static void Surface_readFromParcel( 510 JNIEnv* env, jobject clazz, jobject argParcel) 511{ 512 Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel); 513 if (parcel == NULL) { 514 doThrow(env, "java/lang/NullPointerException", NULL); 515 return; 516 } 517 518 const sp<Surface>& surface = getSurface(env, clazz); 519 const sp<Surface>& rhs = Surface::readFromParcel(parcel); 520 if (!Surface::isSameSurface(surface, rhs)) { 521 // we reassign the surface only if it's a different one 522 // otherwise we would loose our client-side state. 523 setSurface(env, clazz, rhs); 524 } 525} 526 527static void Surface_writeToParcel( 528 JNIEnv* env, jobject clazz, jobject argParcel, jint flags) 529{ 530 Parcel* parcel = (Parcel*)env->GetIntField( 531 argParcel, no.native_parcel); 532 533 if (parcel == NULL) { 534 doThrow(env, "java/lang/NullPointerException", NULL); 535 return; 536 } 537 538 const sp<Surface>& surface = getSurface(env, clazz); 539 Surface::writeToParcel(surface, parcel); 540} 541 542// ---------------------------------------------------------------------------- 543// ---------------------------------------------------------------------------- 544// ---------------------------------------------------------------------------- 545 546const char* const kSurfaceSessionClassPathName = "android/view/SurfaceSession"; 547const char* const kSurfaceClassPathName = "android/view/Surface"; 548static void nativeClassInit(JNIEnv* env, jclass clazz); 549 550static JNINativeMethod gSurfaceSessionMethods[] = { 551 {"init", "()V", (void*)SurfaceSession_init }, 552 {"destroy", "()V", (void*)SurfaceSession_destroy }, 553 {"kill", "()V", (void*)SurfaceSession_kill }, 554}; 555 556static JNINativeMethod gSurfaceMethods[] = { 557 {"nativeClassInit", "()V", (void*)nativeClassInit }, 558 {"init", "(Landroid/view/SurfaceSession;IIIIII)V", (void*)Surface_init }, 559 {"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel }, 560 {"clear", "()V", (void*)Surface_clear }, 561 {"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom }, 562 {"isValid", "()Z", (void*)Surface_isValid }, 563 {"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas }, 564 {"unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvasAndPost }, 565 {"unlockCanvas", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvas }, 566 {"openTransaction", "()V", (void*)Surface_openTransaction }, 567 {"closeTransaction", "()V", (void*)Surface_closeTransaction }, 568 {"setOrientation", "(II)V", (void*)Surface_setOrientation }, 569 {"freezeDisplay", "(I)V", (void*)Surface_freezeDisplay }, 570 {"unfreezeDisplay", "(I)V", (void*)Surface_unfreezeDisplay }, 571 {"setLayer", "(I)V", (void*)Surface_setLayer }, 572 {"setPosition", "(II)V",(void*)Surface_setPosition }, 573 {"setSize", "(II)V",(void*)Surface_setSize }, 574 {"hide", "()V", (void*)Surface_hide }, 575 {"show", "()V", (void*)Surface_show }, 576 {"freeze", "()V", (void*)Surface_freeze }, 577 {"unfreeze", "()V", (void*)Surface_unfreeze }, 578 {"setFlags", "(II)V",(void*)Surface_setFlags }, 579 {"setTransparentRegionHint","(Landroid/graphics/Region;)V", (void*)Surface_setTransparentRegion }, 580 {"setAlpha", "(F)V", (void*)Surface_setAlpha }, 581 {"setMatrix", "(FFFF)V", (void*)Surface_setMatrix }, 582 {"setFreezeTint", "(I)V", (void*)Surface_setFreezeTint }, 583 {"readFromParcel", "(Landroid/os/Parcel;)V", (void*)Surface_readFromParcel }, 584 {"writeToParcel", "(Landroid/os/Parcel;I)V", (void*)Surface_writeToParcel }, 585}; 586 587void nativeClassInit(JNIEnv* env, jclass clazz) 588{ 589 so.surface = env->GetFieldID(clazz, "mSurface", "I"); 590 so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I"); 591 so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;"); 592 593 jclass surfaceSession = env->FindClass("android/view/SurfaceSession"); 594 sso.client = env->GetFieldID(surfaceSession, "mClient", "I"); 595 596 jclass canvas = env->FindClass("android/graphics/Canvas"); 597 no.native_canvas = env->GetFieldID(canvas, "mNativeCanvas", "I"); 598 co.surfaceFormat = env->GetFieldID(canvas, "mSurfaceFormat", "I"); 599 600 jclass region = env->FindClass("android/graphics/Region"); 601 no.native_region = env->GetFieldID(region, "mNativeRegion", "I"); 602 603 jclass parcel = env->FindClass("android/os/Parcel"); 604 no.native_parcel = env->GetFieldID(parcel, "mObject", "I"); 605 606 jclass rect = env->FindClass("android/graphics/Rect"); 607 ro.l = env->GetFieldID(rect, "left", "I"); 608 ro.t = env->GetFieldID(rect, "top", "I"); 609 ro.r = env->GetFieldID(rect, "right", "I"); 610 ro.b = env->GetFieldID(rect, "bottom", "I"); 611 612 jclass point = env->FindClass("android/graphics/Point"); 613 po.x = env->GetFieldID(point, "x", "I"); 614 po.y = env->GetFieldID(point, "y", "I"); 615} 616 617int register_android_view_Surface(JNIEnv* env) 618{ 619 int err; 620 err = AndroidRuntime::registerNativeMethods(env, kSurfaceSessionClassPathName, 621 gSurfaceSessionMethods, NELEM(gSurfaceSessionMethods)); 622 623 err |= AndroidRuntime::registerNativeMethods(env, kSurfaceClassPathName, 624 gSurfaceMethods, NELEM(gSurfaceMethods)); 625 return err; 626} 627 628}; 629 630