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 #include <android_runtime/android_view_Surface.h>
39
40 using namespace android;
41
42 // used to cache JNI method and field IDs for Surface Objects
43 static struct ANPSurfaceInterfaceJavaGlue {
44 bool initialized;
45 jmethodID getSurfaceHolder;
46 jmethodID getSurface;
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 env->DeleteLocalRef(surfaceViewClass);
65 env->DeleteLocalRef(surfaceHolderClass);
66
67 gSurfaceJavaGlue.initialized = true;
68 }
69
70 jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder);
71 jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface);
72
73 sp<android::Surface> sur = android_view_Surface_getSurface(env, surface);
74
75 env->DeleteLocalRef(holder);
76 env->DeleteLocalRef(surface);
77
78 return sur;
79 }
80
convertPixelFormat(PixelFormat format)81 static inline ANPBitmapFormat convertPixelFormat(PixelFormat format) {
82 switch (format) {
83 case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_ANPBitmapFormat;
84 case PIXEL_FORMAT_RGB_565: return kRGB_565_ANPBitmapFormat;
85 default: return kUnknown_ANPBitmapFormat;
86 }
87 }
88
anp_lock(JNIEnv * env,jobject surfaceView,ANPBitmap * bitmap,ANPRectI * dirtyRect)89 static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) {
90 if (!bitmap || !surfaceView) {
91 return false;
92 }
93
94 sp<android::Surface> surface = getSurface(env, surfaceView);
95
96 if (!bitmap || !android::Surface::isValid(surface)) {
97 return false;
98 }
99
100 Region dirtyRegion;
101 if (dirtyRect) {
102 Rect rect(dirtyRect->left, dirtyRect->top, dirtyRect->right, dirtyRect->bottom);
103 if (!rect.isEmpty()) {
104 dirtyRegion.set(rect);
105 }
106 } else {
107 dirtyRegion.set(Rect(0x3FFF, 0x3FFF));
108 }
109
110
111 ANativeWindow_Buffer outBuffer;
112 Rect dirtyBounds(dirtyRegion.getBounds());
113 status_t err = surface->lock(&outBuffer, &dirtyBounds);
114 if (err < 0) {
115 return false;
116 }
117
118 // the surface may have expanded the dirty region so we must to pass that
119 // information back to the plugin.
120 dirtyRegion.set(dirtyBounds);
121 if (dirtyRect) {
122 Rect dirtyBounds = dirtyRegion.getBounds();
123 dirtyRect->left = dirtyBounds.left;
124 dirtyRect->right = dirtyBounds.right;
125 dirtyRect->top = dirtyBounds.top;
126 dirtyRect->bottom = dirtyBounds.bottom;
127 }
128
129 ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
130
131 bitmap->format = convertPixelFormat(outBuffer.format);
132 bitmap->width = outBuffer.width;
133 bitmap->height = outBuffer.height;
134 bitmap->rowBytes = bpr;
135
136 if (outBuffer.width > 0 && outBuffer.height > 0) {
137 bitmap->baseAddr = outBuffer.bits;
138 } else {
139 bitmap->baseAddr = NULL;
140 return false;
141 }
142
143 return true;
144 }
145
anp_unlock(JNIEnv * env,jobject surfaceView)146 static void anp_unlock(JNIEnv* env, jobject surfaceView) {
147 if (!surfaceView) {
148 return;
149 }
150
151 sp<android::Surface> surface = getSurface(env, surfaceView);
152
153 if (!android::Surface::isValid(surface)) {
154 return;
155 }
156
157 surface->unlockAndPost();
158 }
159
160 ///////////////////////////////////////////////////////////////////////////////
161
162 #define ASSIGN(obj, name) (obj)->name = anp_##name
163
ANPSurfaceInterfaceV0_Init(ANPInterface * value)164 void ANPSurfaceInterfaceV0_Init(ANPInterface* value) {
165 ANPSurfaceInterfaceV0* i = reinterpret_cast<ANPSurfaceInterfaceV0*>(value);
166
167 ASSIGN(i, lock);
168 ASSIGN(i, unlock);
169
170 // setup the java glue struct
171 gSurfaceJavaGlue.initialized = false;
172 }
173