2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "Surface"
21 #include "android_util_Binder.h"
23 #include <surfaceflinger/SurfaceComposerClient.h>
24 #include <surfaceflinger/Surface.h>
25 #include <ui/Region.h>
35 #include <android_runtime/AndroidRuntime.h>
36 #include <android_runtime/android_view_Surface.h>
37 #include <utils/misc.h>
40 // ----------------------------------------------------------------------------
45 // should match Parcelable.java
46 PARCELABLE_WRITE_RETURN_VALUE = 0x0001
49 // ----------------------------------------------------------------------------
51 static const char* const OutOfResourcesException =
52 "android/view/Surface$OutOfResourcesException";
60 jfieldID surfaceControl;
82 jfieldID surfaceFormat;
87 jfieldID native_canvas;
88 jfieldID native_region;
89 jfieldID native_parcel;
94 static __attribute__((noinline))
95 void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
97 if (!env->ExceptionOccurred()) {
98 jclass npeClazz = env->FindClass(exc);
99 env->ThrowNew(npeClazz, msg);
103 // ----------------------------------------------------------------------------
104 // ----------------------------------------------------------------------------
105 // ----------------------------------------------------------------------------
107 static void SurfaceSession_init(JNIEnv* env, jobject clazz)
109 sp<SurfaceComposerClient> client = new SurfaceComposerClient;
110 client->incStrong(clazz);
111 env->SetIntField(clazz, sso.client, (int)client.get());
114 static void SurfaceSession_destroy(JNIEnv* env, jobject clazz)
116 SurfaceComposerClient* client =
117 (SurfaceComposerClient*)env->GetIntField(clazz, sso.client);
119 client->decStrong(clazz);
120 env->SetIntField(clazz, sso.client, 0);
124 static void SurfaceSession_kill(JNIEnv* env, jobject clazz)
126 SurfaceComposerClient* client =
127 (SurfaceComposerClient*)env->GetIntField(clazz, sso.client);
130 client->decStrong(clazz);
131 env->SetIntField(clazz, sso.client, 0);
135 // ----------------------------------------------------------------------------
137 static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject clazz)
139 SurfaceControl* const p =
140 (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
141 return sp<SurfaceControl>(p);
144 static void setSurfaceControl(JNIEnv* env, jobject clazz,
145 const sp<SurfaceControl>& surface)
147 SurfaceControl* const p =
148 (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
150 surface->incStrong(clazz);
155 env->SetIntField(clazz, so.surfaceControl, (int)surface.get());
158 static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
160 sp<Surface> result((Surface*)env->GetIntField(clazz, so.surface));
163 * if this method is called from the WindowManager's process, it means
164 * the client is is not remote, and therefore is allowed to have
165 * a Surface (data), so we create it here.
166 * If we don't have a SurfaceControl, it means we're in a different
170 SurfaceControl* const control =
171 (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
173 result = control->getSurface();
175 result->incStrong(clazz);
176 env->SetIntField(clazz, so.surface, (int)result.get());
183 sp<ANativeWindow> android_Surface_getNativeWindow(
184 JNIEnv* env, jobject clazz) {
185 return getSurface(env, clazz).get();
188 static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
190 Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
192 surface->incStrong(clazz);
197 env->SetIntField(clazz, so.surface, (int)surface.get());
200 // ----------------------------------------------------------------------------
202 static void Surface_init(
203 JNIEnv* env, jobject clazz,
205 jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)
207 if (session == NULL) {
208 doThrow(env, "java/lang/NullPointerException");
212 SurfaceComposerClient* client =
213 (SurfaceComposerClient*)env->GetIntField(session, sso.client);
215 sp<SurfaceControl> surface;
217 surface = client->createSurface(pid, dpy, w, h, format, flags);
219 const jchar* str = env->GetStringCritical(jname, 0);
220 const String8 name(str, env->GetStringLength(jname));
221 env->ReleaseStringCritical(jname, str);
222 surface = client->createSurface(pid, name, dpy, w, h, format, flags);
226 doThrow(env, OutOfResourcesException);
229 setSurfaceControl(env, clazz, surface);
232 static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
234 Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel);
235 if (parcel == NULL) {
236 doThrow(env, "java/lang/NullPointerException", NULL);
240 sp<Surface> sur(Surface::readFromParcel(*parcel));
241 setSurface(env, clazz, sur);
244 static jint Surface_getIdentity(JNIEnv* env, jobject clazz)
246 const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
247 if (control != 0) return (jint) control->getIdentity();
248 const sp<Surface>& surface(getSurface(env, clazz));
249 if (surface != 0) return (jint) surface->getIdentity();
253 static void Surface_destroy(JNIEnv* env, jobject clazz, uintptr_t *ostack)
255 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
256 if (SurfaceControl::isValid(surface)) {
259 setSurfaceControl(env, clazz, 0);
260 setSurface(env, clazz, 0);
263 static void Surface_release(JNIEnv* env, jobject clazz, uintptr_t *ostack)
265 setSurfaceControl(env, clazz, 0);
266 setSurface(env, clazz, 0);
269 static jboolean Surface_isValid(JNIEnv* env, jobject clazz)
271 const sp<SurfaceControl>& surfaceControl(getSurfaceControl(env, clazz));
272 if (surfaceControl != 0) {
273 return SurfaceControl::isValid(surfaceControl) ? JNI_TRUE : JNI_FALSE;
275 const sp<Surface>& surface(getSurface(env, clazz));
276 return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
279 static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
281 /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
282 we can map to SkBitmap::kARGB_8888_Config, and optionally call
283 bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
286 case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config;
287 case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config;
288 case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config;
289 case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config;
290 case PIXEL_FORMAT_A_8: return SkBitmap::kA8_Config;
291 default: return SkBitmap::kNo_Config;
295 static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
297 const sp<Surface>& surface(getSurface(env, clazz));
298 if (!Surface::isValid(surface))
305 dirty.left = env->GetIntField(dirtyRect, ro.l);
306 dirty.top = env->GetIntField(dirtyRect, ro.t);
307 dirty.right = env->GetIntField(dirtyRect, ro.r);
308 dirty.bottom= env->GetIntField(dirtyRect, ro.b);
309 if (!dirty.isEmpty()) {
310 dirtyRegion.set(dirty);
313 dirtyRegion.set(Rect(0x3FFF,0x3FFF));
316 Surface::SurfaceInfo info;
317 status_t err = surface->lock(&info, &dirtyRegion);
319 const char* const exception = (err == NO_MEMORY) ?
320 OutOfResourcesException :
321 "java/lang/IllegalArgumentException";
322 doThrow(env, exception, NULL);
326 // Associate a SkCanvas object to this surface
327 jobject canvas = env->GetObjectField(clazz, so.canvas);
328 env->SetIntField(canvas, co.surfaceFormat, info.format);
330 SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
332 ssize_t bpr = info.s * bytesPerPixel(info.format);
333 bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
334 if (info.format == PIXEL_FORMAT_RGBX_8888) {
335 bitmap.setIsOpaque(true);
337 if (info.w > 0 && info.h > 0) {
338 bitmap.setPixels(info.bits);
340 // be safe with an empty bitmap.
341 bitmap.setPixels(NULL);
343 nativeCanvas->setBitmapDevice(bitmap);
346 if (dirtyRegion.isRect()) { // very common case
347 const Rect b(dirtyRegion.getBounds());
348 clipReg.setRect(b.left, b.top, b.right, b.bottom);
351 Rect const* r = dirtyRegion.getArray(&count);
353 clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);
358 nativeCanvas->clipRegion(clipReg);
360 int saveCount = nativeCanvas->save();
361 env->SetIntField(clazz, so.saveCount, saveCount);
364 const Rect& bounds(dirtyRegion.getBounds());
365 env->SetIntField(dirtyRect, ro.l, bounds.left);
366 env->SetIntField(dirtyRect, ro.t, bounds.top);
367 env->SetIntField(dirtyRect, ro.r, bounds.right);
368 env->SetIntField(dirtyRect, ro.b, bounds.bottom);
374 static void Surface_unlockCanvasAndPost(
375 JNIEnv* env, jobject clazz, jobject argCanvas)
377 jobject canvas = env->GetObjectField(clazz, so.canvas);
378 if (canvas != argCanvas) {
379 doThrow(env, "java/lang/IllegalArgumentException", NULL);
383 const sp<Surface>& surface(getSurface(env, clazz));
384 if (!Surface::isValid(surface))
387 // detach the canvas from the surface
388 SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
389 int saveCount = env->GetIntField(clazz, so.saveCount);
390 nativeCanvas->restoreToCount(saveCount);
391 nativeCanvas->setBitmapDevice(SkBitmap());
392 env->SetIntField(clazz, so.saveCount, 0);
395 status_t err = surface->unlockAndPost();
397 doThrow(env, "java/lang/IllegalArgumentException", NULL);
401 static void Surface_unlockCanvas(
402 JNIEnv* env, jobject clazz, jobject argCanvas)
404 // XXX: this API has been removed
405 doThrow(env, "java/lang/IllegalArgumentException", NULL);
408 static void Surface_openTransaction(
409 JNIEnv* env, jobject clazz)
411 SurfaceComposerClient::openGlobalTransaction();
414 static void Surface_closeTransaction(
415 JNIEnv* env, jobject clazz)
417 SurfaceComposerClient::closeGlobalTransaction();
420 static void Surface_setOrientation(
421 JNIEnv* env, jobject clazz, jint display, jint orientation, jint flags)
423 int err = SurfaceComposerClient::setOrientation(display, orientation, flags);
425 doThrow(env, "java/lang/IllegalArgumentException", NULL);
429 static void Surface_freezeDisplay(
430 JNIEnv* env, jobject clazz, jint display)
432 int err = SurfaceComposerClient::freezeDisplay(display, 0);
434 doThrow(env, "java/lang/IllegalArgumentException", NULL);
438 static void Surface_unfreezeDisplay(
439 JNIEnv* env, jobject clazz, jint display)
441 int err = SurfaceComposerClient::unfreezeDisplay(display, 0);
443 doThrow(env, "java/lang/IllegalArgumentException", NULL);
447 static void Surface_setLayer(
448 JNIEnv* env, jobject clazz, jint zorder)
450 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
451 if (surface == 0) return;
452 status_t err = surface->setLayer(zorder);
453 if (err<0 && err!=NO_INIT)
454 doThrow(env, "java/lang/IllegalArgumentException", NULL);
457 static void Surface_setPosition(
458 JNIEnv* env, jobject clazz, jint x, jint y)
460 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
461 if (surface == 0) return;
462 status_t err = surface->setPosition(x, y);
463 if (err<0 && err!=NO_INIT)
464 doThrow(env, "java/lang/IllegalArgumentException", NULL);
467 static void Surface_setSize(
468 JNIEnv* env, jobject clazz, jint w, jint h)
470 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
471 if (surface == 0) return;
472 status_t err = surface->setSize(w, h);
473 if (err<0 && err!=NO_INIT)
474 doThrow(env, "java/lang/IllegalArgumentException", NULL);
477 static void Surface_hide(
478 JNIEnv* env, jobject clazz)
480 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
481 if (surface == 0) return;
482 status_t err = surface->hide();
483 if (err<0 && err!=NO_INIT)
484 doThrow(env, "java/lang/IllegalArgumentException", NULL);
487 static void Surface_show(
488 JNIEnv* env, jobject clazz)
490 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
491 if (surface == 0) return;
492 status_t err = surface->show();
493 if (err<0 && err!=NO_INIT)
494 doThrow(env, "java/lang/IllegalArgumentException", NULL);
497 static void Surface_freeze(
498 JNIEnv* env, jobject clazz)
500 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
501 if (surface == 0) return;
502 status_t err = surface->freeze();
503 if (err<0 && err!=NO_INIT)
504 doThrow(env, "java/lang/IllegalArgumentException", NULL);
507 static void Surface_unfreeze(
508 JNIEnv* env, jobject clazz)
510 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
511 if (surface == 0) return;
512 status_t err = surface->unfreeze();
513 if (err<0 && err!=NO_INIT)
514 doThrow(env, "java/lang/IllegalArgumentException", NULL);
517 static void Surface_setFlags(
518 JNIEnv* env, jobject clazz, jint flags, jint mask)
520 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
521 if (surface == 0) return;
522 status_t err = surface->setFlags(flags, mask);
523 if (err<0 && err!=NO_INIT)
524 doThrow(env, "java/lang/IllegalArgumentException", NULL);
527 static void Surface_setTransparentRegion(
528 JNIEnv* env, jobject clazz, jobject argRegion)
530 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
531 if (surface == 0) return;
532 SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
534 const SkIRect& b(nativeRegion->getBounds());
535 Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
536 if (nativeRegion->isComplex()) {
537 SkRegion::Iterator it(*nativeRegion);
539 const SkIRect& r(it.rect());
540 reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
545 status_t err = surface->setTransparentRegionHint(reg);
546 if (err<0 && err!=NO_INIT)
547 doThrow(env, "java/lang/IllegalArgumentException", NULL);
550 static void Surface_setAlpha(
551 JNIEnv* env, jobject clazz, jfloat alpha)
553 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
554 if (surface == 0) return;
555 status_t err = surface->setAlpha(alpha);
556 if (err<0 && err!=NO_INIT)
557 doThrow(env, "java/lang/IllegalArgumentException", NULL);
560 static void Surface_setMatrix(
561 JNIEnv* env, jobject clazz,
562 jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy)
564 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
565 if (surface == 0) return;
566 status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy);
567 if (err<0 && err!=NO_INIT)
568 doThrow(env, "java/lang/IllegalArgumentException", NULL);
571 static void Surface_setFreezeTint(
572 JNIEnv* env, jobject clazz,
575 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
576 if (surface == 0) return;
577 status_t err = surface->setFreezeTint(tint);
578 if (err<0 && err!=NO_INIT)
579 doThrow(env, "java/lang/IllegalArgumentException", NULL);
582 // ----------------------------------------------------------------------------
584 static void Surface_copyFrom(
585 JNIEnv* env, jobject clazz, jobject other)
591 doThrow(env, "java/lang/NullPointerException", NULL);
596 * This is used by the WindowManagerService just after constructing
597 * a Surface and is necessary for returning the Surface reference to
598 * the caller. At this point, we should only have a SurfaceControl.
601 const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);
602 const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);
603 if (!SurfaceControl::isSameSurface(surface, rhs)) {
604 // we reassign the surface only if it's a different one
605 // otherwise we would loose our client-side state.
606 setSurfaceControl(env, clazz, rhs);
610 static void Surface_readFromParcel(
611 JNIEnv* env, jobject clazz, jobject argParcel)
613 Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);
614 if (parcel == NULL) {
615 doThrow(env, "java/lang/NullPointerException", NULL);
619 sp<Surface> sur(Surface::readFromParcel(*parcel));
620 setSurface(env, clazz, sur);
623 static void Surface_writeToParcel(
624 JNIEnv* env, jobject clazz, jobject argParcel, jint flags)
626 Parcel* parcel = (Parcel*)env->GetIntField(
627 argParcel, no.native_parcel);
629 if (parcel == NULL) {
630 doThrow(env, "java/lang/NullPointerException", NULL);
634 const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
635 SurfaceControl::writeSurfaceToParcel(control, parcel);
636 if (flags & PARCELABLE_WRITE_RETURN_VALUE) {
637 setSurfaceControl(env, clazz, 0);
641 // ----------------------------------------------------------------------------
642 // ----------------------------------------------------------------------------
643 // ----------------------------------------------------------------------------
645 const char* const kSurfaceSessionClassPathName = "android/view/SurfaceSession";
646 const char* const kSurfaceClassPathName = "android/view/Surface";
647 static void nativeClassInit(JNIEnv* env, jclass clazz);
649 static JNINativeMethod gSurfaceSessionMethods[] = {
650 {"init", "()V", (void*)SurfaceSession_init },
651 {"destroy", "()V", (void*)SurfaceSession_destroy },
652 {"kill", "()V", (void*)SurfaceSession_kill },
655 static JNINativeMethod gSurfaceMethods[] = {
656 {"nativeClassInit", "()V", (void*)nativeClassInit },
657 {"init", "(Landroid/view/SurfaceSession;ILjava/lang/String;IIIII)V", (void*)Surface_init },
658 {"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel },
659 {"getIdentity", "()I", (void*)Surface_getIdentity },
660 {"destroy", "()V", (void*)Surface_destroy },
661 {"release", "()V", (void*)Surface_release },
662 {"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom },
663 {"isValid", "()Z", (void*)Surface_isValid },
664 {"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas },
665 {"unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvasAndPost },
666 {"unlockCanvas", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvas },
667 {"openTransaction", "()V", (void*)Surface_openTransaction },
668 {"closeTransaction", "()V", (void*)Surface_closeTransaction },
669 {"setOrientation", "(III)V", (void*)Surface_setOrientation },
670 {"freezeDisplay", "(I)V", (void*)Surface_freezeDisplay },
671 {"unfreezeDisplay", "(I)V", (void*)Surface_unfreezeDisplay },
672 {"setLayer", "(I)V", (void*)Surface_setLayer },
673 {"setPosition", "(II)V",(void*)Surface_setPosition },
674 {"setSize", "(II)V",(void*)Surface_setSize },
675 {"hide", "()V", (void*)Surface_hide },
676 {"show", "()V", (void*)Surface_show },
677 {"freeze", "()V", (void*)Surface_freeze },
678 {"unfreeze", "()V", (void*)Surface_unfreeze },
679 {"setFlags", "(II)V",(void*)Surface_setFlags },
680 {"setTransparentRegionHint","(Landroid/graphics/Region;)V", (void*)Surface_setTransparentRegion },
681 {"setAlpha", "(F)V", (void*)Surface_setAlpha },
682 {"setMatrix", "(FFFF)V", (void*)Surface_setMatrix },
683 {"setFreezeTint", "(I)V", (void*)Surface_setFreezeTint },
684 {"readFromParcel", "(Landroid/os/Parcel;)V", (void*)Surface_readFromParcel },
685 {"writeToParcel", "(Landroid/os/Parcel;I)V", (void*)Surface_writeToParcel },
688 void nativeClassInit(JNIEnv* env, jclass clazz)
690 so.surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
691 so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I");
692 so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
693 so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
695 jclass surfaceSession = env->FindClass("android/view/SurfaceSession");
696 sso.client = env->GetFieldID(surfaceSession, "mClient", "I");
698 jclass canvas = env->FindClass("android/graphics/Canvas");
699 no.native_canvas = env->GetFieldID(canvas, "mNativeCanvas", "I");
700 co.surfaceFormat = env->GetFieldID(canvas, "mSurfaceFormat", "I");
702 jclass region = env->FindClass("android/graphics/Region");
703 no.native_region = env->GetFieldID(region, "mNativeRegion", "I");
705 jclass parcel = env->FindClass("android/os/Parcel");
706 no.native_parcel = env->GetFieldID(parcel, "mObject", "I");
708 jclass rect = env->FindClass("android/graphics/Rect");
709 ro.l = env->GetFieldID(rect, "left", "I");
710 ro.t = env->GetFieldID(rect, "top", "I");
711 ro.r = env->GetFieldID(rect, "right", "I");
712 ro.b = env->GetFieldID(rect, "bottom", "I");
714 jclass point = env->FindClass("android/graphics/Point");
715 po.x = env->GetFieldID(point, "x", "I");
716 po.y = env->GetFieldID(point, "y", "I");
719 int register_android_view_Surface(JNIEnv* env)
722 err = AndroidRuntime::registerNativeMethods(env, kSurfaceSessionClassPathName,
723 gSurfaceSessionMethods, NELEM(gSurfaceSessionMethods));
725 err |= AndroidRuntime::registerNativeMethods(env, kSurfaceClassPathName,
726 gSurfaceMethods, NELEM(gSurfaceMethods));