android_view_GLES20Canvas.cpp revision 163935113919a184122b8b3bd672ef08c8df65dc
1/*
2 * Copyright (C) 2010 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#define LOG_TAG "OpenGLRenderer"
18
19#include "jni.h"
20#include <nativehelper/JNIHelp.h>
21#include <android_runtime/AndroidRuntime.h>
22#include <utils/ResourceTypes.h>
23
24#include <SkBitmap.h>
25#include <SkCanvas.h>
26#include <SkMatrix.h>
27#include <SkPaint.h>
28#include <SkRegion.h>
29#include <SkScalerContext.h>
30#include <SkXfermode.h>
31
32#include <OpenGLRenderer.h>
33#include <SkiaShader.h>
34#include <SkiaColorFilter.h>
35#include <Rect.h>
36#include <ui/Rect.h>
37
38#include "TextLayout.h"
39
40namespace android {
41
42using namespace uirenderer;
43
44/**
45 * Note: OpenGLRenderer JNI layer is generated and compiled only on supported
46 *       devices. This means all the logic must be compiled only when the
47 *       preprocessor variable USE_OPENGL_RENDERER is defined.
48 */
49#ifdef USE_OPENGL_RENDERER
50
51// ----------------------------------------------------------------------------
52// Java APIs
53// ----------------------------------------------------------------------------
54
55static struct {
56    jclass clazz;
57    jmethodID set;
58} gRectClassInfo;
59
60// ----------------------------------------------------------------------------
61// Constructors
62// ----------------------------------------------------------------------------
63
64static OpenGLRenderer* android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject canvas) {
65    return new OpenGLRenderer;
66}
67
68static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject canvas,
69        OpenGLRenderer* renderer) {
70    delete renderer;
71}
72
73// ----------------------------------------------------------------------------
74// Setup
75// ----------------------------------------------------------------------------
76
77static void android_view_GLES20Canvas_setViewport(JNIEnv* env, jobject canvas,
78        OpenGLRenderer* renderer, jint width, jint height) {
79    renderer->setViewport(width, height);
80}
81
82static void android_view_GLES20Canvas_prepare(JNIEnv* env, jobject canvas,
83        OpenGLRenderer* renderer) {
84    renderer->prepare();
85}
86
87// ----------------------------------------------------------------------------
88// State
89// ----------------------------------------------------------------------------
90
91static jint android_view_GLES20Canvas_save(JNIEnv* env, jobject canvas, OpenGLRenderer* renderer,
92        jint flags) {
93    return renderer->save(flags);
94}
95
96static jint android_view_GLES20Canvas_getSaveCount(JNIEnv* env, jobject canvas,
97        OpenGLRenderer* renderer) {
98    return renderer->getSaveCount();
99}
100
101static void android_view_GLES20Canvas_restore(JNIEnv* env, jobject canvas,
102        OpenGLRenderer* renderer) {
103    renderer->restore();
104}
105
106static void android_view_GLES20Canvas_restoreToCount(JNIEnv* env, jobject canvas,
107        OpenGLRenderer* renderer, jint saveCount) {
108    renderer->restoreToCount(saveCount);
109}
110
111// ----------------------------------------------------------------------------
112// Layers
113// ----------------------------------------------------------------------------
114
115static jint android_view_GLES20Canvas_saveLayer(JNIEnv* env, jobject canvas,
116        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
117        SkPaint* paint, jint saveFlags) {
118    return renderer->saveLayer(left, top, right, bottom, paint, saveFlags);
119}
120
121static jint android_view_GLES20Canvas_saveLayerAlpha(JNIEnv* env, jobject canvas,
122        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
123        jint alpha, jint saveFlags) {
124    return renderer->saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
125}
126
127// ----------------------------------------------------------------------------
128// Clipping
129// ----------------------------------------------------------------------------
130
131static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject canvas,
132        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
133        SkCanvas::EdgeType edge) {
134    return renderer->quickReject(left, top, right, bottom);
135}
136
137static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject canvas,
138        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
139        SkRegion::Op op) {
140    return renderer->clipRect(left, top, right, bottom, op);
141}
142
143static bool android_view_GLES20Canvas_clipRect(JNIEnv* env, jobject canvas,
144        OpenGLRenderer* renderer, jint left, jint top, jint right, jint bottom,
145        SkRegion::Op op) {
146    return renderer->clipRect(float(left), float(top), float(right), float(bottom), op);
147}
148
149static bool android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject canvas,
150        OpenGLRenderer* renderer, jobject rect) {
151    const android::uirenderer::Rect& bounds(renderer->getClipBounds());
152
153    env->CallVoidMethod(rect, gRectClassInfo.set,
154            int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
155
156    return !bounds.isEmpty();
157}
158
159// ----------------------------------------------------------------------------
160// Transforms
161// ----------------------------------------------------------------------------
162
163static void android_view_GLES20Canvas_translate(JNIEnv* env, jobject canvas,
164        OpenGLRenderer* renderer, jfloat dx, jfloat dy) {
165    renderer->translate(dx, dy);
166}
167
168static void android_view_GLES20Canvas_rotate(JNIEnv* env, jobject canvas,
169        OpenGLRenderer* renderer, jfloat degrees) {
170    renderer->rotate(degrees);
171}
172
173static void android_view_GLES20Canvas_scale(JNIEnv* env, jobject canvas,
174        OpenGLRenderer* renderer, jfloat sx, jfloat sy) {
175    renderer->scale(sx, sy);
176}
177
178static void android_view_GLES20Canvas_setMatrix(JNIEnv* env, jobject canvas,
179        OpenGLRenderer* renderer, SkMatrix* matrix) {
180    renderer->setMatrix(matrix);
181}
182
183static void android_view_GLES20Canvas_getMatrix(JNIEnv* env, jobject canvas,
184        OpenGLRenderer* renderer, SkMatrix* matrix) {
185    renderer->getMatrix(matrix);
186}
187
188static void android_view_GLES20Canvas_concatMatrix(JNIEnv* env, jobject canvas,
189        OpenGLRenderer* renderer, SkMatrix* matrix) {
190    renderer->concatMatrix(matrix);
191}
192
193// ----------------------------------------------------------------------------
194// Drawing
195// ----------------------------------------------------------------------------
196
197static void android_view_GLES20Canvas_drawBitmap(JNIEnv* env, jobject canvas,
198        OpenGLRenderer* renderer, SkBitmap* bitmap, float left, float top, SkPaint* paint) {
199    renderer->drawBitmap(bitmap, left, top, paint);
200}
201
202static void android_view_GLES20Canvas_drawBitmapRect(JNIEnv* env, jobject canvas,
203        OpenGLRenderer* renderer, SkBitmap* bitmap,
204        float srcLeft, float srcTop, float srcRight, float srcBottom,
205        float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint) {
206    renderer->drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
207            dstLeft, dstTop, dstRight, dstBottom, paint);
208}
209
210static void android_view_GLES20Canvas_drawBitmapMatrix(JNIEnv* env, jobject canvas,
211        OpenGLRenderer* renderer, SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
212    renderer->drawBitmap(bitmap, matrix, paint);
213}
214
215static void android_view_GLES20Canvas_drawPatch(JNIEnv* env, jobject canvas,
216        OpenGLRenderer* renderer, SkBitmap* bitmap, jbyteArray chunks,
217        float left, float top, float right, float bottom, SkPaint* paint) {
218    jbyte* storage = env->GetByteArrayElements(chunks, NULL);
219    Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(storage);
220    Res_png_9patch::deserialize(patch);
221
222    renderer->drawPatch(bitmap, patch, left, top, right, bottom, paint);
223
224    env->ReleaseByteArrayElements(chunks, storage, 0);
225}
226
227static void android_view_GLES20Canvas_drawColor(JNIEnv* env, jobject canvas,
228        OpenGLRenderer* renderer, jint color, SkXfermode::Mode mode) {
229    renderer->drawColor(color, mode);
230}
231
232static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject canvas,
233        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom,
234        SkPaint* paint) {
235    renderer->drawRect(left, top, right, bottom, paint);
236}
237
238static void android_view_GLES20Canvas_drawPath(JNIEnv* env, jobject canvas,
239        OpenGLRenderer* renderer, SkPath* path, SkPaint* paint) {
240    renderer->drawPath(path, paint);
241}
242
243// ----------------------------------------------------------------------------
244// Shaders and color filters
245// ----------------------------------------------------------------------------
246
247static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject canvas,
248        OpenGLRenderer* renderer) {
249    renderer->resetShader();
250    renderer->resetColorFilter();
251}
252
253static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject canvas,
254        OpenGLRenderer* renderer, SkiaShader* shader) {
255    renderer->setupShader(shader);
256}
257
258static void android_view_GLES20Canvas_setupColorFilter(JNIEnv* env, jobject canvas,
259        OpenGLRenderer* renderer, SkiaColorFilter* filter) {
260    renderer->setupColorFilter(filter);
261}
262
263// ----------------------------------------------------------------------------
264// Text
265// ----------------------------------------------------------------------------
266
267static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
268        jfloat x, jfloat y, int flags, SkPaint* paint) {
269    const jchar *workText;
270    jchar* buffer = NULL;
271    int32_t workBytes;
272    if (TextLayout::prepareText(paint, text, count, flags, &workText, &workBytes, &buffer)) {
273        renderer->drawText((const char*) workText, workBytes, count, x, y, paint);
274        free(buffer);
275    }
276}
277
278static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject canvas,
279        OpenGLRenderer* renderer, jcharArray text, int index, int count,
280        jfloat x, jfloat y, int flags, SkPaint* paint) {
281    jchar* textArray = env->GetCharArrayElements(text, NULL);
282    renderText(renderer, textArray + index, count, x, y, flags, paint);
283    env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
284}
285
286static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject canvas,
287        OpenGLRenderer* renderer, jstring text, int start, int end,
288        jfloat x, jfloat y, int flags, SkPaint* paint) {
289    const jchar* textArray = env->GetStringChars(text, NULL);
290    renderText(renderer, textArray + start, end - start, x, y, flags, paint);
291    env->ReleaseStringChars(text, textArray);
292}
293
294#endif // USE_OPENGL_RENDERER
295
296// ----------------------------------------------------------------------------
297// Common
298// ----------------------------------------------------------------------------
299
300static jboolean android_view_GLES20Canvas_isAvailable(JNIEnv* env, jobject clazz) {
301#ifdef USE_OPENGL_RENDERER
302    return JNI_TRUE;
303#else
304    return JNI_FALSE;
305#endif
306}
307
308// ----------------------------------------------------------------------------
309// JNI Glue
310// ----------------------------------------------------------------------------
311
312const char* const kClassPathName = "android/view/GLES20Canvas";
313
314static JNINativeMethod gMethods[] = {
315    {   "nIsAvailable",       "()Z",             (void*) android_view_GLES20Canvas_isAvailable },
316#ifdef USE_OPENGL_RENDERER
317
318    {   "nCreateRenderer",    "()I",             (void*) android_view_GLES20Canvas_createRenderer },
319    {   "nDestroyRenderer",   "(I)V",            (void*) android_view_GLES20Canvas_destroyRenderer },
320    {   "nSetViewport",       "(III)V",          (void*) android_view_GLES20Canvas_setViewport },
321    {   "nPrepare",           "(I)V",            (void*) android_view_GLES20Canvas_prepare },
322
323    {   "nSave",              "(II)I",           (void*) android_view_GLES20Canvas_save },
324    {   "nRestore",           "(I)V",            (void*) android_view_GLES20Canvas_restore },
325    {   "nRestoreToCount",    "(II)V",           (void*) android_view_GLES20Canvas_restoreToCount },
326    {   "nGetSaveCount",      "(I)I",            (void*) android_view_GLES20Canvas_getSaveCount },
327
328    {   "nSaveLayer",         "(IFFFFII)I",      (void*) android_view_GLES20Canvas_saveLayer },
329    {   "nSaveLayerAlpha",    "(IFFFFII)I",      (void*) android_view_GLES20Canvas_saveLayerAlpha },
330
331    {   "nQuickReject",       "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_quickReject },
332    {   "nClipRect",          "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_clipRectF },
333    {   "nClipRect",          "(IIIIII)Z",       (void*) android_view_GLES20Canvas_clipRect },
334
335    {   "nTranslate",         "(IFF)V",          (void*) android_view_GLES20Canvas_translate },
336    {   "nRotate",            "(IF)V",           (void*) android_view_GLES20Canvas_rotate },
337    {   "nScale",             "(IFF)V",          (void*) android_view_GLES20Canvas_scale },
338
339    {   "nSetMatrix",         "(II)V",           (void*) android_view_GLES20Canvas_setMatrix },
340    {   "nGetMatrix",         "(II)V",           (void*) android_view_GLES20Canvas_getMatrix },
341    {   "nConcatMatrix",      "(II)V",           (void*) android_view_GLES20Canvas_concatMatrix },
342
343    {   "nDrawBitmap",        "(IIFFI)V",        (void*) android_view_GLES20Canvas_drawBitmap },
344    {   "nDrawBitmap",        "(IIFFFFFFFFI)V",  (void*) android_view_GLES20Canvas_drawBitmapRect },
345    {   "nDrawBitmap",        "(IIII)V",         (void*) android_view_GLES20Canvas_drawBitmapMatrix },
346    {   "nDrawPatch",         "(II[BFFFFI)V",    (void*) android_view_GLES20Canvas_drawPatch },
347    {   "nDrawColor",         "(III)V",          (void*) android_view_GLES20Canvas_drawColor },
348    {   "nDrawRect",          "(IFFFFI)V",       (void*) android_view_GLES20Canvas_drawRect },
349    {   "nDrawPath",          "(III)V",          (void*) android_view_GLES20Canvas_drawPath },
350
351    {   "nResetModifiers",    "(I)V",            (void*) android_view_GLES20Canvas_resetModifiers },
352    {   "nSetupShader",       "(II)V",           (void*) android_view_GLES20Canvas_setupShader },
353    {   "nSetupColorFilter",  "(II)V",           (void*) android_view_GLES20Canvas_setupColorFilter },
354
355    {   "nDrawText",          "(I[CIIFFII)V",    (void*) android_view_GLES20Canvas_drawTextArray },
356    {   "nDrawText",          "(ILjava/lang/String;IIFFII)V",
357            (void*) android_view_GLES20Canvas_drawText },
358
359    {   "nGetClipBounds",     "(ILandroid/graphics/Rect;)Z",
360            (void*) android_view_GLES20Canvas_getClipBounds },
361#endif
362};
363
364#ifdef USE_OPENGL_RENDERER
365    #define FIND_CLASS(var, className) \
366            var = env->FindClass(className); \
367            LOG_FATAL_IF(! var, "Unable to find class " className); \
368            var = jclass(env->NewGlobalRef(var));
369
370    #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
371            var = env->GetMethodID(clazz, methodName, methodDescriptor); \
372            LOG_FATAL_IF(! var, "Unable to find method " methodName);
373#else
374    #define FIND_CLASS(var, className)
375    #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor)
376#endif
377
378int register_android_view_GLES20Canvas(JNIEnv* env) {
379    FIND_CLASS(gRectClassInfo.clazz, "android/graphics/Rect");
380    GET_METHOD_ID(gRectClassInfo.set, gRectClassInfo.clazz, "set", "(IIII)V");
381
382    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
383}
384
385};
386