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