1 /*
2 * Copyright 2009, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 // must include config.h first for webkit to fiddle with new/delete
27 #include "config.h"
28 #include "ANPSurface_npapi.h"
29
30 #include "PluginView.h"
31 #include "PluginWidgetAndroid.h"
32 #include "SkANP.h"
33 #include <JNIUtility.h>
34 #include <gui/Surface.h>
35 #include <ui/Rect.h>
36 #include <ui/Region.h>
37 #include <utils/RefBase.h>
38
39 using namespace android;
40
41 // used to cache JNI method and field IDs for Surface Objects
42 static struct ANPSurfaceInterfaceJavaGlue {
43 bool initialized;
44 jmethodID getSurfaceHolder;
45 jmethodID getSurface;
46 jfieldID surfacePointer;
47 } gSurfaceJavaGlue;
48
getSurface(JNIEnv * env,jobject view)49 static inline sp<android::Surface> getSurface(JNIEnv* env, jobject view) {
50 if (!env || !view) {
51 return NULL;
52 }
53
54 if (!gSurfaceJavaGlue.initialized) {
55
56 jclass surfaceViewClass = env->FindClass("android/view/SurfaceView");
57 gSurfaceJavaGlue.getSurfaceHolder = env->GetMethodID(surfaceViewClass, "getHolder",
58 "()Landroid/view/SurfaceHolder;");
59
60 jclass surfaceHolderClass = env->FindClass("android/view/SurfaceHolder");
61 gSurfaceJavaGlue.getSurface = env->GetMethodID(surfaceHolderClass, "getSurface",
62 "()Landroid/view/Surface;");
63
64 jclass surfaceClass = env->FindClass("android/view/Surface");
65 gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
66 ANDROID_VIEW_SURFACE_JNI_ID, "I");
67
68 env->DeleteLocalRef(surfaceClass);
69 env->DeleteLocalRef(surfaceViewClass);
70 env->DeleteLocalRef(surfaceHolderClass);
71
72 gSurfaceJavaGlue.initialized = true;
73 }
74
75 jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder);
76 jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface);
77 jint surfacePointer = env->GetIntField(surface, gSurfaceJavaGlue.surfacePointer);
78
79 env->DeleteLocalRef(holder);
80 env->DeleteLocalRef(surface);
81
82 return sp<android::Surface>((android::Surface*) surfacePointer);
83 }
84
convertPixelFormat(PixelFormat format)85 static inline ANPBitmapFormat convertPixelFormat(PixelFormat format) {
86 switch (format) {
87 case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_ANPBitmapFormat;
88 case PIXEL_FORMAT_RGB_565: return kRGB_565_ANPBitmapFormat;
89 default: return kUnknown_ANPBitmapFormat;
90 }
91 }
92
anp_lock(JNIEnv * env,jobject surfaceView,ANPBitmap * bitmap,ANPRectI * dirtyRect)93 static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) {
94 if (!bitmap || !surfaceView) {
95 return false;
96 }
97
98 sp<android::Surface> surface = getSurface(env, surfaceView);
99
100 if (!bitmap || !android::Surface::isValid(surface)) {
101 return false;
102 }
103
104 Region dirtyRegion;
105 if (dirtyRect) {
106 Rect rect(dirtyRect->left, dirtyRect->top, dirtyRect->right, dirtyRect->bottom);
107 if (!rect.isEmpty()) {
108 dirtyRegion.set(rect);
109 }
110 } else {
111 dirtyRegion.set(Rect(0x3FFF, 0x3FFF));
112 }
113
114 android::Surface::SurfaceInfo info;
115 status_t err = surface->lock(&info, &dirtyRegion);
116 if (err < 0) {
117 return false;
118 }
119
120 // the surface may have expanded the dirty region so we must to pass that
121 // information back to the plugin.
122 if (dirtyRect) {
123 Rect dirtyBounds = dirtyRegion.getBounds();
124 dirtyRect->left = dirtyBounds.left;
125 dirtyRect->right = dirtyBounds.right;
126 dirtyRect->top = dirtyBounds.top;
127 dirtyRect->bottom = dirtyBounds.bottom;
128 }
129
130 ssize_t bpr = info.s * bytesPerPixel(info.format);
131
132 bitmap->format = convertPixelFormat(info.format);
133 bitmap->width = info.w;
134 bitmap->height = info.h;
135 bitmap->rowBytes = bpr;
136
137 if (info.w > 0 && info.h > 0) {
138 bitmap->baseAddr = info.bits;
139 } else {
140 bitmap->baseAddr = NULL;
141 return false;
142 }
143
144 return true;
145 }
146
anp_unlock(JNIEnv * env,jobject surfaceView)147 static void anp_unlock(JNIEnv* env, jobject surfaceView) {
148 if (!surfaceView) {
149 return;
150 }
151
152 sp<android::Surface> surface = getSurface(env, surfaceView);
153
154 if (!android::Surface::isValid(surface)) {
155 return;
156 }
157
158 surface->unlockAndPost();
159 }
160
161 ///////////////////////////////////////////////////////////////////////////////
162
163 #define ASSIGN(obj, name) (obj)->name = anp_##name
164
ANPSurfaceInterfaceV0_Init(ANPInterface * value)165 void ANPSurfaceInterfaceV0_Init(ANPInterface* value) {
166 ANPSurfaceInterfaceV0* i = reinterpret_cast<ANPSurfaceInterfaceV0*>(value);
167
168 ASSIGN(i, lock);
169 ASSIGN(i, unlock);
170
171 // setup the java glue struct
172 gSurfaceJavaGlue.initialized = false;
173 }
174