blob: ec8b6e07f325c658ce540893d9080221e05adbb1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Mathias Agopianfae5cb22010-06-04 18:26:32 -070017#define LOG_TAG "Surface"
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019#include <stdio.h>
20
21#include "android_util_Binder.h"
Dianne Hackborna1111872010-11-23 20:55:11 -080022#include "android/graphics/GraphicsJNI.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
Dianne Hackborna1111872010-11-23 20:55:11 -080024#include <binder/IMemory.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080025#include <surfaceflinger/SurfaceComposerClient.h>
Mathias Agopian8b138322010-04-12 16:22:15 -070026#include <surfaceflinger/Surface.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027#include <ui/Region.h>
28#include <ui/Rect.h>
29
Mathias Agopian8b73ae42010-06-10 17:02:51 -070030#include <EGL/egl.h>
31
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032#include <SkCanvas.h>
33#include <SkBitmap.h>
Mathias Agopian6158b1b2009-05-11 00:03:41 -070034#include <SkRegion.h>
Dianne Hackborn1f5b1952010-11-29 14:41:46 -080035#include <SkPixelRef.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
37#include "jni.h"
Elliott Hughes8451b252011-04-07 19:17:57 -070038#include "JNIHelp.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039#include <android_runtime/AndroidRuntime.h>
Dianne Hackborn289b9b62010-07-09 11:44:11 -070040#include <android_runtime/android_view_Surface.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041#include <utils/misc.h>
42
43
44// ----------------------------------------------------------------------------
45
46namespace android {
47
Mathias Agopianaf1e11b2010-03-23 15:31:21 -070048enum {
49 // should match Parcelable.java
50 PARCELABLE_WRITE_RETURN_VALUE = 0x0001
51};
52
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053// ----------------------------------------------------------------------------
54
55static const char* const OutOfResourcesException =
56 "android/view/Surface$OutOfResourcesException";
57
58struct sso_t {
59 jfieldID client;
60};
61static sso_t sso;
62
63struct so_t {
Mathias Agopian17f638b2009-04-16 20:04:08 -070064 jfieldID surfaceControl;
Romain Guy2a83f002011-01-18 18:28:21 -080065 jfieldID surfaceGenerationId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066 jfieldID surface;
67 jfieldID saveCount;
68 jfieldID canvas;
69};
70static so_t so;
71
72struct ro_t {
73 jfieldID l;
74 jfieldID t;
75 jfieldID r;
76 jfieldID b;
77};
78static ro_t ro;
79
80struct po_t {
81 jfieldID x;
82 jfieldID y;
83};
84static po_t po;
85
86struct co_t {
87 jfieldID surfaceFormat;
88};
89static co_t co;
90
91struct no_t {
92 jfieldID native_canvas;
93 jfieldID native_region;
94 jfieldID native_parcel;
95};
96static no_t no;
97
98
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099// ----------------------------------------------------------------------------
100// ----------------------------------------------------------------------------
101// ----------------------------------------------------------------------------
102
103static void SurfaceSession_init(JNIEnv* env, jobject clazz)
104{
105 sp<SurfaceComposerClient> client = new SurfaceComposerClient;
106 client->incStrong(clazz);
107 env->SetIntField(clazz, sso.client, (int)client.get());
108}
109
110static void SurfaceSession_destroy(JNIEnv* env, jobject clazz)
111{
112 SurfaceComposerClient* client =
113 (SurfaceComposerClient*)env->GetIntField(clazz, sso.client);
114 if (client != 0) {
115 client->decStrong(clazz);
116 env->SetIntField(clazz, sso.client, 0);
117 }
118}
119
120static void SurfaceSession_kill(JNIEnv* env, jobject clazz)
121{
122 SurfaceComposerClient* client =
123 (SurfaceComposerClient*)env->GetIntField(clazz, sso.client);
124 if (client != 0) {
125 client->dispose();
126 client->decStrong(clazz);
127 env->SetIntField(clazz, sso.client, 0);
128 }
129}
130
131// ----------------------------------------------------------------------------
132
Mathias Agopian17f638b2009-04-16 20:04:08 -0700133static sp<SurfaceControl> getSurfaceControl(JNIEnv* env, jobject clazz)
134{
Elliott Hughes8451b252011-04-07 19:17:57 -0700135 SurfaceControl* const p =
Mathias Agopian17f638b2009-04-16 20:04:08 -0700136 (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
137 return sp<SurfaceControl>(p);
138}
139
Elliott Hughes8451b252011-04-07 19:17:57 -0700140static void setSurfaceControl(JNIEnv* env, jobject clazz,
Mathias Agopian17f638b2009-04-16 20:04:08 -0700141 const sp<SurfaceControl>& surface)
142{
Elliott Hughes8451b252011-04-07 19:17:57 -0700143 SurfaceControl* const p =
Mathias Agopian17f638b2009-04-16 20:04:08 -0700144 (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
145 if (surface.get()) {
146 surface->incStrong(clazz);
147 }
148 if (p) {
149 p->decStrong(clazz);
150 }
151 env->SetIntField(clazz, so.surfaceControl, (int)surface.get());
152}
153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154static sp<Surface> getSurface(JNIEnv* env, jobject clazz)
155{
Mathias Agopian69d62092009-04-16 20:30:22 -0700156 sp<Surface> result((Surface*)env->GetIntField(clazz, so.surface));
157 if (result == 0) {
158 /*
159 * if this method is called from the WindowManager's process, it means
160 * the client is is not remote, and therefore is allowed to have
Elliott Hughes8451b252011-04-07 19:17:57 -0700161 * a Surface (data), so we create it here.
Mathias Agopian69d62092009-04-16 20:30:22 -0700162 * If we don't have a SurfaceControl, it means we're in a different
163 * process.
164 */
Elliott Hughes8451b252011-04-07 19:17:57 -0700165
166 SurfaceControl* const control =
Mathias Agopian69d62092009-04-16 20:30:22 -0700167 (SurfaceControl*)env->GetIntField(clazz, so.surfaceControl);
168 if (control) {
169 result = control->getSurface();
170 if (result != 0) {
171 result->incStrong(clazz);
172 env->SetIntField(clazz, so.surface, (int)result.get());
173 }
174 }
175 }
176 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177}
178
Dianne Hackborn54a181b2010-06-30 18:35:14 -0700179sp<ANativeWindow> android_Surface_getNativeWindow(
Mathias Agopian8b73ae42010-06-10 17:02:51 -0700180 JNIEnv* env, jobject clazz) {
Mathias Agopian32a55cf62011-02-25 16:11:44 -0800181 return getSurface(env, clazz);
Mathias Agopian8b73ae42010-06-10 17:02:51 -0700182}
183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
185{
186 Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
187 if (surface.get()) {
188 surface->incStrong(clazz);
189 }
190 if (p) {
191 p->decStrong(clazz);
192 }
193 env->SetIntField(clazz, so.surface, (int)surface.get());
Romain Guy2a83f002011-01-18 18:28:21 -0800194 // This test is conservative and it would be better to compare the ISurfaces
195 if (p && p != surface.get()) {
196 jint generationId = env->GetIntField(clazz, so.surfaceGenerationId);
197 generationId++;
198 env->SetIntField(clazz, so.surfaceGenerationId, generationId);
199 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200}
201
202// ----------------------------------------------------------------------------
203
204static void Surface_init(
Elliott Hughes8451b252011-04-07 19:17:57 -0700205 JNIEnv* env, jobject clazz,
Mathias Agopian5d26c1e2010-03-01 16:09:43 -0800206 jobject session,
Mathias Agopian9638e5c2011-04-20 14:19:32 -0700207 jint, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208{
209 if (session == NULL) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700210 doThrowNPE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 return;
212 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 SurfaceComposerClient* client =
215 (SurfaceComposerClient*)env->GetIntField(session, sso.client);
216
Mathias Agopian5d26c1e2010-03-01 16:09:43 -0800217 sp<SurfaceControl> surface;
218 if (jname == NULL) {
Mathias Agopian9638e5c2011-04-20 14:19:32 -0700219 surface = client->createSurface(dpy, w, h, format, flags);
Mathias Agopian5d26c1e2010-03-01 16:09:43 -0800220 } else {
221 const jchar* str = env->GetStringCritical(jname, 0);
222 const String8 name(str, env->GetStringLength(jname));
223 env->ReleaseStringCritical(jname, str);
Mathias Agopian9638e5c2011-04-20 14:19:32 -0700224 surface = client->createSurface(name, dpy, w, h, format, flags);
Mathias Agopian5d26c1e2010-03-01 16:09:43 -0800225 }
226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 if (surface == 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700228 jniThrowException(env, OutOfResourcesException, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 return;
230 }
Mathias Agopian17f638b2009-04-16 20:04:08 -0700231 setSurfaceControl(env, clazz, surface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232}
233
234static void Surface_initParcel(JNIEnv* env, jobject clazz, jobject argParcel)
235{
236 Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel);
237 if (parcel == NULL) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700238 doThrowNPE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 return;
240 }
Mathias Agopianfae5cb22010-06-04 18:26:32 -0700241
Jamie Gennis5ee65f02010-07-15 17:29:15 -0700242 sp<Surface> sur(Surface::readFromParcel(*parcel));
Mathias Agopianfae5cb22010-06-04 18:26:32 -0700243 setSurface(env, clazz, sur);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244}
245
Marco Nelissen8138cb42010-04-26 16:05:48 -0700246static jint Surface_getIdentity(JNIEnv* env, jobject clazz)
247{
248 const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
249 if (control != 0) return (jint) control->getIdentity();
250 const sp<Surface>& surface(getSurface(env, clazz));
251 if (surface != 0) return (jint) surface->getIdentity();
252 return -1;
253}
254
Dianne Hackborn0586a1b2009-09-06 21:08:27 -0700255static void Surface_destroy(JNIEnv* env, jobject clazz, uintptr_t *ostack)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700257 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
258 if (SurfaceControl::isValid(surface)) {
Mathias Agopian402c3462009-04-14 18:21:47 -0700259 surface->clear();
260 }
Mathias Agopian17f638b2009-04-16 20:04:08 -0700261 setSurfaceControl(env, clazz, 0);
Mathias Agopian402c3462009-04-14 18:21:47 -0700262 setSurface(env, clazz, 0);
263}
264
265static void Surface_release(JNIEnv* env, jobject clazz, uintptr_t *ostack)
266{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700267 setSurfaceControl(env, clazz, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 setSurface(env, clazz, 0);
269}
270
271static jboolean Surface_isValid(JNIEnv* env, jobject clazz)
272{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700273 const sp<SurfaceControl>& surfaceControl(getSurfaceControl(env, clazz));
274 if (surfaceControl != 0) {
275 return SurfaceControl::isValid(surfaceControl) ? JNI_TRUE : JNI_FALSE;
276 }
277 const sp<Surface>& surface(getSurface(env, clazz));
Mathias Agopian402c3462009-04-14 18:21:47 -0700278 return Surface::isValid(surface) ? JNI_TRUE : JNI_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279}
280
281static inline SkBitmap::Config convertPixelFormat(PixelFormat format)
282{
Mathias Agopianf1e5b0d2009-08-07 20:55:14 -0700283 /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 we can map to SkBitmap::kARGB_8888_Config, and optionally call
285 bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
286 */
Marco Nelissen8138cb42010-04-26 16:05:48 -0700287 switch (format) {
288 case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config;
290 case PIXEL_FORMAT_RGBA_4444: return SkBitmap::kARGB_4444_Config;
Marco Nelissen8138cb42010-04-26 16:05:48 -0700291 case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config;
292 case PIXEL_FORMAT_A_8: return SkBitmap::kA8_Config;
293 default: return SkBitmap::kNo_Config;
294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295}
296
297static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)
298{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700299 const sp<Surface>& surface(getSurface(env, clazz));
Romain Guyfea12b82011-01-27 15:36:40 -0800300 if (!Surface::isValid(surface)) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700301 doThrowIAE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 return 0;
Romain Guyfea12b82011-01-27 15:36:40 -0800303 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304
305 // get dirty region
306 Region dirtyRegion;
307 if (dirtyRect) {
308 Rect dirty;
309 dirty.left = env->GetIntField(dirtyRect, ro.l);
310 dirty.top = env->GetIntField(dirtyRect, ro.t);
311 dirty.right = env->GetIntField(dirtyRect, ro.r);
312 dirty.bottom= env->GetIntField(dirtyRect, ro.b);
Mathias Agopian6158b1b2009-05-11 00:03:41 -0700313 if (!dirty.isEmpty()) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700314 dirtyRegion.set(dirty);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316 } else {
317 dirtyRegion.set(Rect(0x3FFF,0x3FFF));
318 }
319
320 Surface::SurfaceInfo info;
321 status_t err = surface->lock(&info, &dirtyRegion);
322 if (err < 0) {
323 const char* const exception = (err == NO_MEMORY) ?
324 OutOfResourcesException :
325 "java/lang/IllegalArgumentException";
Elliott Hughes8451b252011-04-07 19:17:57 -0700326 jniThrowException(env, exception, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 return 0;
328 }
329
330 // Associate a SkCanvas object to this surface
331 jobject canvas = env->GetObjectField(clazz, so.canvas);
332 env->SetIntField(canvas, co.surfaceFormat, info.format);
333
334 SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
335 SkBitmap bitmap;
Mathias Agopian1473f462009-04-10 14:24:30 -0700336 ssize_t bpr = info.s * bytesPerPixel(info.format);
337 bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);
Mathias Agopianf1e5b0d2009-08-07 20:55:14 -0700338 if (info.format == PIXEL_FORMAT_RGBX_8888) {
339 bitmap.setIsOpaque(true);
340 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 if (info.w > 0 && info.h > 0) {
342 bitmap.setPixels(info.bits);
343 } else {
344 // be safe with an empty bitmap.
345 bitmap.setPixels(NULL);
346 }
347 nativeCanvas->setBitmapDevice(bitmap);
Elliott Hughes8451b252011-04-07 19:17:57 -0700348
Mathias Agopian6158b1b2009-05-11 00:03:41 -0700349 SkRegion clipReg;
350 if (dirtyRegion.isRect()) { // very common case
Mathias Agopiana8a0aa82010-04-21 15:24:11 -0700351 const Rect b(dirtyRegion.getBounds());
Mathias Agopian6158b1b2009-05-11 00:03:41 -0700352 clipReg.setRect(b.left, b.top, b.right, b.bottom);
353 } else {
354 size_t count;
355 Rect const* r = dirtyRegion.getArray(&count);
356 while (count) {
357 clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);
358 r++, count--;
359 }
360 }
361
362 nativeCanvas->clipRegion(clipReg);
Elliott Hughes8451b252011-04-07 19:17:57 -0700363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 int saveCount = nativeCanvas->save();
365 env->SetIntField(clazz, so.saveCount, saveCount);
366
367 if (dirtyRect) {
Mathias Agopian6158b1b2009-05-11 00:03:41 -0700368 const Rect& bounds(dirtyRegion.getBounds());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 env->SetIntField(dirtyRect, ro.l, bounds.left);
370 env->SetIntField(dirtyRect, ro.t, bounds.top);
371 env->SetIntField(dirtyRect, ro.r, bounds.right);
372 env->SetIntField(dirtyRect, ro.b, bounds.bottom);
373 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700374
Marco Nelissen8138cb42010-04-26 16:05:48 -0700375 return canvas;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376}
377
378static void Surface_unlockCanvasAndPost(
379 JNIEnv* env, jobject clazz, jobject argCanvas)
380{
381 jobject canvas = env->GetObjectField(clazz, so.canvas);
Carl Shapiro375aa0b2011-03-03 17:00:38 -0800382 if (env->IsSameObject(canvas, argCanvas) == JNI_FALSE) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700383 doThrowIAE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 return;
385 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700386
Mathias Agopian17f638b2009-04-16 20:04:08 -0700387 const sp<Surface>& surface(getSurface(env, clazz));
Mathias Agopian402c3462009-04-14 18:21:47 -0700388 if (!Surface::isValid(surface))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 return;
390
391 // detach the canvas from the surface
392 SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);
393 int saveCount = env->GetIntField(clazz, so.saveCount);
394 nativeCanvas->restoreToCount(saveCount);
395 nativeCanvas->setBitmapDevice(SkBitmap());
396 env->SetIntField(clazz, so.saveCount, 0);
397
398 // unlock surface
399 status_t err = surface->unlockAndPost();
400 if (err < 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700401 doThrowIAE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 }
403}
404
405static void Surface_unlockCanvas(
406 JNIEnv* env, jobject clazz, jobject argCanvas)
407{
Mathias Agopian1473f462009-04-10 14:24:30 -0700408 // XXX: this API has been removed
Elliott Hughes8451b252011-04-07 19:17:57 -0700409 doThrowIAE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410}
411
412static void Surface_openTransaction(
413 JNIEnv* env, jobject clazz)
414{
415 SurfaceComposerClient::openGlobalTransaction();
416}
417
418static void Surface_closeTransaction(
419 JNIEnv* env, jobject clazz)
420{
421 SurfaceComposerClient::closeGlobalTransaction();
422}
423
424static void Surface_setOrientation(
Mathias Agopianeb0c86e2009-03-27 18:11:38 -0700425 JNIEnv* env, jobject clazz, jint display, jint orientation, jint flags)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426{
Mathias Agopianeb0c86e2009-03-27 18:11:38 -0700427 int err = SurfaceComposerClient::setOrientation(display, orientation, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 if (err < 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700429 doThrowIAE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 }
431}
432
433static void Surface_freezeDisplay(
434 JNIEnv* env, jobject clazz, jint display)
435{
436 int err = SurfaceComposerClient::freezeDisplay(display, 0);
437 if (err < 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700438 doThrowIAE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 }
440}
441
442static void Surface_unfreezeDisplay(
443 JNIEnv* env, jobject clazz, jint display)
444{
445 int err = SurfaceComposerClient::unfreezeDisplay(display, 0);
446 if (err < 0) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700447 doThrowIAE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 }
449}
450
Dianne Hackborn1f5b1952010-11-29 14:41:46 -0800451class ScreenshotPixelRef : public SkPixelRef {
Dianne Hackborna1111872010-11-23 20:55:11 -0800452public:
Dianne Hackborn1f5b1952010-11-29 14:41:46 -0800453 ScreenshotPixelRef(SkColorTable* ctable) {
454 fCTable = ctable;
Derek Sollenberger6062c592011-02-22 13:55:04 -0500455 SkSafeRef(ctable);
Dianne Hackborn1f5b1952010-11-29 14:41:46 -0800456 setImmutable();
457 }
458 virtual ~ScreenshotPixelRef() {
459 SkSafeUnref(fCTable);
Dianne Hackborna1111872010-11-23 20:55:11 -0800460 }
461
Dianne Hackbornd2835932010-12-13 16:28:46 -0800462 status_t update(int width, int height, int minLayer, int maxLayer, bool allLayers) {
Dianne Hackborna1111872010-11-23 20:55:11 -0800463 status_t res = (width > 0 && height > 0)
Dianne Hackbornd2835932010-12-13 16:28:46 -0800464 ? (allLayers
465 ? mScreenshot.update(width, height)
466 : mScreenshot.update(width, height, minLayer, maxLayer))
Dianne Hackborna1111872010-11-23 20:55:11 -0800467 : mScreenshot.update();
468 if (res != NO_ERROR) {
469 return res;
470 }
471
Dianne Hackborna1111872010-11-23 20:55:11 -0800472 return NO_ERROR;
473 }
474
Dianne Hackborn1f5b1952010-11-29 14:41:46 -0800475 uint32_t getWidth() const {
476 return mScreenshot.getWidth();
477 }
478
479 uint32_t getHeight() const {
480 return mScreenshot.getHeight();
481 }
482
483 uint32_t getStride() const {
484 return mScreenshot.getStride();
485 }
486
487 uint32_t getFormat() const {
488 return mScreenshot.getFormat();
489 }
490
491protected:
492 // overrides from SkPixelRef
493 virtual void* onLockPixels(SkColorTable** ct) {
494 *ct = fCTable;
495 return (void*)mScreenshot.getPixels();
496 }
497
498 virtual void onUnlockPixels() {
499 }
500
Dianne Hackborna1111872010-11-23 20:55:11 -0800501private:
502 ScreenshotClient mScreenshot;
Dianne Hackborn1f5b1952010-11-29 14:41:46 -0800503 SkColorTable* fCTable;
504
505 typedef SkPixelRef INHERITED;
Dianne Hackborna1111872010-11-23 20:55:11 -0800506};
507
Dianne Hackbornd2835932010-12-13 16:28:46 -0800508static jobject doScreenshot(JNIEnv* env, jobject clazz, jint width, jint height,
509 jint minLayer, jint maxLayer, bool allLayers)
Dianne Hackborna1111872010-11-23 20:55:11 -0800510{
Dianne Hackborn1f5b1952010-11-29 14:41:46 -0800511 ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
Dianne Hackbornd2835932010-12-13 16:28:46 -0800512 if (pixels->update(width, height, minLayer, maxLayer, allLayers) != NO_ERROR) {
Dianne Hackborn1f5b1952010-11-29 14:41:46 -0800513 delete pixels;
Dianne Hackborna1111872010-11-23 20:55:11 -0800514 return 0;
515 }
516
Dianne Hackborn1f5b1952010-11-29 14:41:46 -0800517 uint32_t w = pixels->getWidth();
518 uint32_t h = pixels->getHeight();
519 uint32_t s = pixels->getStride();
520 uint32_t f = pixels->getFormat();
521 ssize_t bpr = s * android::bytesPerPixel(f);
522
523 SkBitmap* bitmap = new SkBitmap();
524 bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
525 if (f == PIXEL_FORMAT_RGBX_8888) {
526 bitmap->setIsOpaque(true);
527 }
528
529 if (w > 0 && h > 0) {
530 bitmap->setPixelRef(pixels)->unref();
531 bitmap->lockPixels();
532 } else {
533 // be safe with an empty bitmap.
534 delete pixels;
535 bitmap->setPixels(NULL);
536 }
537
Dianne Hackborna1111872010-11-23 20:55:11 -0800538 return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
539}
540
Dianne Hackbornd2835932010-12-13 16:28:46 -0800541static jobject Surface_screenshotAll(JNIEnv* env, jobject clazz, jint width, jint height)
542{
543 return doScreenshot(env, clazz, width, height, 0, 0, true);
544}
545
546static jobject Surface_screenshot(JNIEnv* env, jobject clazz, jint width, jint height,
547 jint minLayer, jint maxLayer, bool allLayers)
548{
549 return doScreenshot(env, clazz, width, height, minLayer, maxLayer, false);
550}
551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552static void Surface_setLayer(
553 JNIEnv* env, jobject clazz, jint zorder)
554{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700555 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
556 if (surface == 0) return;
557 status_t err = surface->setLayer(zorder);
Elliott Hughes8451b252011-04-07 19:17:57 -0700558 if (err<0 && err!=NO_INIT) {
559 doThrowIAE(env);
560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561}
562
563static void Surface_setPosition(
564 JNIEnv* env, jobject clazz, jint x, jint y)
565{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700566 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
567 if (surface == 0) return;
568 status_t err = surface->setPosition(x, y);
Elliott Hughes8451b252011-04-07 19:17:57 -0700569 if (err<0 && err!=NO_INIT) {
570 doThrowIAE(env);
571 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572}
573
574static void Surface_setSize(
575 JNIEnv* env, jobject clazz, jint w, jint h)
576{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700577 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
578 if (surface == 0) return;
579 status_t err = surface->setSize(w, h);
Elliott Hughes8451b252011-04-07 19:17:57 -0700580 if (err<0 && err!=NO_INIT) {
581 doThrowIAE(env);
582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583}
584
585static void Surface_hide(
586 JNIEnv* env, jobject clazz)
587{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700588 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
589 if (surface == 0) return;
590 status_t err = surface->hide();
Elliott Hughes8451b252011-04-07 19:17:57 -0700591 if (err<0 && err!=NO_INIT) {
592 doThrowIAE(env);
593 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594}
595
596static void Surface_show(
597 JNIEnv* env, jobject clazz)
598{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700599 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
600 if (surface == 0) return;
601 status_t err = surface->show();
Elliott Hughes8451b252011-04-07 19:17:57 -0700602 if (err<0 && err!=NO_INIT) {
603 doThrowIAE(env);
604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605}
606
607static void Surface_freeze(
608 JNIEnv* env, jobject clazz)
609{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700610 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
611 if (surface == 0) return;
612 status_t err = surface->freeze();
Elliott Hughes8451b252011-04-07 19:17:57 -0700613 if (err<0 && err!=NO_INIT) {
614 doThrowIAE(env);
615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616}
617
618static void Surface_unfreeze(
619 JNIEnv* env, jobject clazz)
620{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700621 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
622 if (surface == 0) return;
623 status_t err = surface->unfreeze();
Elliott Hughes8451b252011-04-07 19:17:57 -0700624 if (err<0 && err!=NO_INIT) {
625 doThrowIAE(env);
626 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627}
628
629static void Surface_setFlags(
630 JNIEnv* env, jobject clazz, jint flags, jint mask)
631{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700632 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
633 if (surface == 0) return;
634 status_t err = surface->setFlags(flags, mask);
Elliott Hughes8451b252011-04-07 19:17:57 -0700635 if (err<0 && err!=NO_INIT) {
636 doThrowIAE(env);
637 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638}
639
640static void Surface_setTransparentRegion(
641 JNIEnv* env, jobject clazz, jobject argRegion)
642{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700643 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
644 if (surface == 0) return;
645 SkRegion* nativeRegion = (SkRegion*)env->GetIntField(argRegion, no.native_region);
Elliott Hughes8451b252011-04-07 19:17:57 -0700646
Mathias Agopian6158b1b2009-05-11 00:03:41 -0700647 const SkIRect& b(nativeRegion->getBounds());
648 Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
649 if (nativeRegion->isComplex()) {
650 SkRegion::Iterator it(*nativeRegion);
651 while (!it.done()) {
652 const SkIRect& r(it.rect());
653 reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
654 it.next();
655 }
656 }
Elliott Hughes8451b252011-04-07 19:17:57 -0700657
Mathias Agopian6158b1b2009-05-11 00:03:41 -0700658 status_t err = surface->setTransparentRegionHint(reg);
Elliott Hughes8451b252011-04-07 19:17:57 -0700659 if (err<0 && err!=NO_INIT) {
660 doThrowIAE(env);
661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662}
663
664static void Surface_setAlpha(
665 JNIEnv* env, jobject clazz, jfloat alpha)
666{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700667 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
668 if (surface == 0) return;
669 status_t err = surface->setAlpha(alpha);
Elliott Hughes8451b252011-04-07 19:17:57 -0700670 if (err<0 && err!=NO_INIT) {
671 doThrowIAE(env);
672 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673}
674
675static void Surface_setMatrix(
676 JNIEnv* env, jobject clazz,
677 jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy)
678{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700679 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
680 if (surface == 0) return;
681 status_t err = surface->setMatrix(dsdx, dtdx, dsdy, dtdy);
Elliott Hughes8451b252011-04-07 19:17:57 -0700682 if (err<0 && err!=NO_INIT) {
683 doThrowIAE(env);
684 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685}
686
687static void Surface_setFreezeTint(
688 JNIEnv* env, jobject clazz,
689 jint tint)
690{
Mathias Agopian17f638b2009-04-16 20:04:08 -0700691 const sp<SurfaceControl>& surface(getSurfaceControl(env, clazz));
692 if (surface == 0) return;
693 status_t err = surface->setFreezeTint(tint);
Elliott Hughes8451b252011-04-07 19:17:57 -0700694 if (err<0 && err!=NO_INIT) {
695 doThrowIAE(env);
696 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697}
698
Mathias Agopian17f638b2009-04-16 20:04:08 -0700699// ----------------------------------------------------------------------------
700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701static void Surface_copyFrom(
702 JNIEnv* env, jobject clazz, jobject other)
703{
704 if (clazz == other)
705 return;
706
707 if (other == NULL) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700708 doThrowNPE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 return;
710 }
711
Mathias Agopian17f638b2009-04-16 20:04:08 -0700712 /*
713 * This is used by the WindowManagerService just after constructing
714 * a Surface and is necessary for returning the Surface reference to
715 * the caller. At this point, we should only have a SurfaceControl.
Mathias Agopian17f638b2009-04-16 20:04:08 -0700716 */
Mathias Agopianfae5cb22010-06-04 18:26:32 -0700717
Mathias Agopian17f638b2009-04-16 20:04:08 -0700718 const sp<SurfaceControl>& surface = getSurfaceControl(env, clazz);
719 const sp<SurfaceControl>& rhs = getSurfaceControl(env, other);
720 if (!SurfaceControl::isSameSurface(surface, rhs)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 // we reassign the surface only if it's a different one
722 // otherwise we would loose our client-side state.
Mathias Agopian17f638b2009-04-16 20:04:08 -0700723 setSurfaceControl(env, clazz, rhs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 }
725}
726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727static void Surface_readFromParcel(
728 JNIEnv* env, jobject clazz, jobject argParcel)
729{
730 Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);
731 if (parcel == NULL) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700732 doThrowNPE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 return;
734 }
735
Jamie Gennis5ee65f02010-07-15 17:29:15 -0700736 sp<Surface> sur(Surface::readFromParcel(*parcel));
Mathias Agopianfae5cb22010-06-04 18:26:32 -0700737 setSurface(env, clazz, sur);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738}
739
740static void Surface_writeToParcel(
741 JNIEnv* env, jobject clazz, jobject argParcel, jint flags)
742{
743 Parcel* parcel = (Parcel*)env->GetIntField(
744 argParcel, no.native_parcel);
745
746 if (parcel == NULL) {
Elliott Hughes8451b252011-04-07 19:17:57 -0700747 doThrowNPE(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 return;
749 }
750
Mathias Agopian17f638b2009-04-16 20:04:08 -0700751 const sp<SurfaceControl>& control(getSurfaceControl(env, clazz));
752 SurfaceControl::writeSurfaceToParcel(control, parcel);
Mathias Agopianaf1e11b2010-03-23 15:31:21 -0700753 if (flags & PARCELABLE_WRITE_RETURN_VALUE) {
754 setSurfaceControl(env, clazz, 0);
755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756}
757
758// ----------------------------------------------------------------------------
759// ----------------------------------------------------------------------------
760// ----------------------------------------------------------------------------
761
762const char* const kSurfaceSessionClassPathName = "android/view/SurfaceSession";
763const char* const kSurfaceClassPathName = "android/view/Surface";
764static void nativeClassInit(JNIEnv* env, jclass clazz);
765
766static JNINativeMethod gSurfaceSessionMethods[] = {
Marco Nelissen8138cb42010-04-26 16:05:48 -0700767 {"init", "()V", (void*)SurfaceSession_init },
768 {"destroy", "()V", (void*)SurfaceSession_destroy },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 {"kill", "()V", (void*)SurfaceSession_kill },
770};
771
772static JNINativeMethod gSurfaceMethods[] = {
773 {"nativeClassInit", "()V", (void*)nativeClassInit },
Mathias Agopian5d26c1e2010-03-01 16:09:43 -0800774 {"init", "(Landroid/view/SurfaceSession;ILjava/lang/String;IIIII)V", (void*)Surface_init },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 {"init", "(Landroid/os/Parcel;)V", (void*)Surface_initParcel },
Marco Nelissen8138cb42010-04-26 16:05:48 -0700776 {"getIdentity", "()I", (void*)Surface_getIdentity },
Dianne Hackborn0586a1b2009-09-06 21:08:27 -0700777 {"destroy", "()V", (void*)Surface_destroy },
Mathias Agopian402c3462009-04-14 18:21:47 -0700778 {"release", "()V", (void*)Surface_release },
Marco Nelissen8138cb42010-04-26 16:05:48 -0700779 {"copyFrom", "(Landroid/view/Surface;)V", (void*)Surface_copyFrom },
780 {"isValid", "()Z", (void*)Surface_isValid },
781 {"lockCanvasNative", "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", (void*)Surface_lockCanvas },
782 {"unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvasAndPost },
783 {"unlockCanvas", "(Landroid/graphics/Canvas;)V", (void*)Surface_unlockCanvas },
784 {"openTransaction", "()V", (void*)Surface_openTransaction },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 {"closeTransaction", "()V", (void*)Surface_closeTransaction },
Mathias Agopianeb0c86e2009-03-27 18:11:38 -0700786 {"setOrientation", "(III)V", (void*)Surface_setOrientation },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 {"freezeDisplay", "(I)V", (void*)Surface_freezeDisplay },
788 {"unfreezeDisplay", "(I)V", (void*)Surface_unfreezeDisplay },
Dianne Hackbornd2835932010-12-13 16:28:46 -0800789 {"screenshot", "(II)Landroid/graphics/Bitmap;", (void*)Surface_screenshotAll },
790 {"screenshot", "(IIII)Landroid/graphics/Bitmap;", (void*)Surface_screenshot },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 {"setLayer", "(I)V", (void*)Surface_setLayer },
Marco Nelissen8138cb42010-04-26 16:05:48 -0700792 {"setPosition", "(II)V",(void*)Surface_setPosition },
793 {"setSize", "(II)V",(void*)Surface_setSize },
794 {"hide", "()V", (void*)Surface_hide },
795 {"show", "()V", (void*)Surface_show },
796 {"freeze", "()V", (void*)Surface_freeze },
797 {"unfreeze", "()V", (void*)Surface_unfreeze },
798 {"setFlags", "(II)V",(void*)Surface_setFlags },
799 {"setTransparentRegionHint","(Landroid/graphics/Region;)V", (void*)Surface_setTransparentRegion },
800 {"setAlpha", "(F)V", (void*)Surface_setAlpha },
801 {"setMatrix", "(FFFF)V", (void*)Surface_setMatrix },
802 {"setFreezeTint", "(I)V", (void*)Surface_setFreezeTint },
803 {"readFromParcel", "(Landroid/os/Parcel;)V", (void*)Surface_readFromParcel },
804 {"writeToParcel", "(Landroid/os/Parcel;I)V", (void*)Surface_writeToParcel },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805};
806
807void nativeClassInit(JNIEnv* env, jclass clazz)
808{
Mathias Agopian8b138322010-04-12 16:22:15 -0700809 so.surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
Romain Guy2a83f002011-01-18 18:28:21 -0800810 so.surfaceGenerationId = env->GetFieldID(clazz, "mSurfaceGenerationId", "I");
Mathias Agopian17f638b2009-04-16 20:04:08 -0700811 so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I");
Marco Nelissen8138cb42010-04-26 16:05:48 -0700812 so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I");
813 so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814
815 jclass surfaceSession = env->FindClass("android/view/SurfaceSession");
Marco Nelissen8138cb42010-04-26 16:05:48 -0700816 sso.client = env->GetFieldID(surfaceSession, "mClient", "I");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817
818 jclass canvas = env->FindClass("android/graphics/Canvas");
819 no.native_canvas = env->GetFieldID(canvas, "mNativeCanvas", "I");
820 co.surfaceFormat = env->GetFieldID(canvas, "mSurfaceFormat", "I");
821
822 jclass region = env->FindClass("android/graphics/Region");
823 no.native_region = env->GetFieldID(region, "mNativeRegion", "I");
824
825 jclass parcel = env->FindClass("android/os/Parcel");
826 no.native_parcel = env->GetFieldID(parcel, "mObject", "I");
827
828 jclass rect = env->FindClass("android/graphics/Rect");
829 ro.l = env->GetFieldID(rect, "left", "I");
830 ro.t = env->GetFieldID(rect, "top", "I");
831 ro.r = env->GetFieldID(rect, "right", "I");
832 ro.b = env->GetFieldID(rect, "bottom", "I");
833
834 jclass point = env->FindClass("android/graphics/Point");
835 po.x = env->GetFieldID(point, "x", "I");
836 po.y = env->GetFieldID(point, "y", "I");
837}
838
839int register_android_view_Surface(JNIEnv* env)
840{
841 int err;
842 err = AndroidRuntime::registerNativeMethods(env, kSurfaceSessionClassPathName,
843 gSurfaceSessionMethods, NELEM(gSurfaceSessionMethods));
844
845 err |= AndroidRuntime::registerNativeMethods(env, kSurfaceClassPathName,
846 gSurfaceMethods, NELEM(gSurfaceMethods));
847 return err;
848}
849
850};