1 /* gnu_java_awt_peer_gtk_CairoSurface.c
2    Copyright (C)  2006 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 #include "jcl.h"
39 #include "gtkpeer.h"
40 
41 #include "gnu_java_awt_peer_gtk_CairoSurface.h"
42 #include "cairographics2d.h"
43 
44 /**
45  * Field names in CairoSurface.java
46  */
47 #define SURFACE "surfacePointer"
48 #define SHARED "sharedBuffer"
49 
50 /* prototypes */
51 static void setNativeObject( JNIEnv *env, jobject obj, void *ptr, const char *pointer );
52 
53 /**
54  * Creates a cairo surface, ARGB32, native ordering, premultiplied alpha.
55  */
56 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoSurface_create(JNIEnv * env,jobject obj,jint width,jint height,jint stride,jintArray buf)57 Java_gnu_java_awt_peer_gtk_CairoSurface_create
58 (JNIEnv *env, jobject obj, jint width, jint height, jint stride,
59  jintArray buf )
60 {
61   cairo_surface_t* surface;
62   jboolean isCopy;
63 
64   /* Retrieve java-created data array */
65   void *data = (*env)->GetIntArrayElements (env, buf, &isCopy);
66 
67   /* Set sharedBuffer variable */
68   jclass cls = (*env)->GetObjectClass (env, obj);
69   jfieldID field = (*env)->GetFieldID (env, cls, SHARED, "Z");
70   g_assert (field != 0);
71 
72   if (isCopy == JNI_TRUE)
73     {
74       (*env)->SetBooleanField (env, obj, field, JNI_FALSE);
75       void* temp = g_malloc(stride * height * 4);
76       memcpy(temp, data, stride * height * 4);
77       (*env)->ReleaseIntArrayElements (env, buf, data, 0);
78       data = temp;
79     }
80   else
81     (*env)->SetBooleanField (env, obj, field, JNI_TRUE);
82 
83   /* Create the cairo surface and set the java pointer */
84   surface = cairo_image_surface_create_for_data
85     (data, CAIRO_FORMAT_ARGB32, width, height, stride * 4);
86 
87   setNativeObject(env, obj, surface, SURFACE);
88 }
89 
90 /**
91  * Destroy the surface
92  */
93 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoSurface_destroy(JNIEnv * env,jobject obj,jlong surfacePointer,jintArray buf)94 Java_gnu_java_awt_peer_gtk_CairoSurface_destroy
95 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
96  jlong surfacePointer, jintArray buf)
97 {
98   cairo_surface_t* surface = JLONG_TO_PTR(void, surfacePointer);
99   void *data = cairo_image_surface_get_data(surface);
100   if( surface != NULL )
101   {
102   	/* Release or free the data buffer as appropriate */
103     jclass cls = (*env)->GetObjectClass (env, obj);
104     jfieldID field = (*env)->GetFieldID (env, cls, SHARED, "Z");
105     g_assert (field != 0);
106     jboolean sharedBuffer = (*env)->GetBooleanField (env, obj, field);
107 
108     if (sharedBuffer == JNI_TRUE)
109   	  (*env)->ReleaseIntArrayElements (env, buf, data, 0);
110   	else
111   	  g_free(data);
112 
113   	/* Destroy the cairo surface itself */
114     cairo_surface_destroy(surface);
115   }
116 }
117 
118 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoSurface_nativeDrawSurface(JNIEnv * env,jobject obj,jlong surfacePointer,jlong context,jdoubleArray java_matrix,double alpha,jint interpolation)119 Java_gnu_java_awt_peer_gtk_CairoSurface_nativeDrawSurface
120 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
121  jlong surfacePointer, jlong context, jdoubleArray java_matrix, double alpha,
122  jint interpolation)
123 {
124   struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, context);
125   cairo_t *cr = gr->cr;
126   jdouble *native_matrix = NULL;
127   cairo_surface_t* surface = JLONG_TO_PTR(void, surfacePointer);
128   g_assert(surface != NULL);
129   g_assert(cr != NULL);
130 
131   native_matrix = (*env)->GetDoubleArrayElements (env, java_matrix, NULL);
132   g_assert (native_matrix != NULL);
133   g_assert ((*env)->GetArrayLength (env, java_matrix) == 6);
134 
135  {
136    cairo_matrix_t mat;
137    cairo_pattern_t *p;
138    cairo_matrix_init_identity (&mat);
139    cairo_matrix_init (&mat,
140                       native_matrix[0], native_matrix[1],
141                       native_matrix[2], native_matrix[3],
142                       native_matrix[4], native_matrix[5]);
143 
144    p = cairo_pattern_create_for_surface (surface);
145    cairo_pattern_set_matrix (p, &mat);
146    switch ((enum java_awt_rendering_hints_filter) interpolation)
147      {
148      case java_awt_rendering_hints_VALUE_INTERPOLATION_NEAREST_NEIGHBOR:
149        cairo_pattern_set_filter (p, CAIRO_FILTER_NEAREST);
150        break;
151      case java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR:
152        cairo_pattern_set_filter (p, CAIRO_FILTER_BILINEAR);
153        break;
154      case java_awt_rendering_hints_VALUE_INTERPOLATION_BICUBIC:
155        cairo_pattern_set_filter (p, CAIRO_FILTER_GAUSSIAN);
156        break;
157      case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED:
158        cairo_pattern_set_filter (p, CAIRO_FILTER_FAST);
159        break;
160      case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT:
161        cairo_pattern_set_filter (p, CAIRO_FILTER_NEAREST);
162        break;
163      case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY:
164        cairo_pattern_set_filter (p, CAIRO_FILTER_BEST);
165        break;
166      }
167 
168    cairo_set_source(cr, p);
169    if (alpha == 1.0)
170      cairo_paint(cr);
171    else
172      cairo_paint_with_alpha(cr, alpha);
173 
174    cairo_pattern_destroy(p);
175  }
176 
177  (*env)->ReleaseDoubleArrayElements (env, java_matrix, native_matrix, 0);
178 }
179 
180 JNIEXPORT jlong JNICALL
Java_gnu_java_awt_peer_gtk_CairoSurface_getFlippedBuffer(JNIEnv * env,jobject obj,jlong surfacePointer)181 Java_gnu_java_awt_peer_gtk_CairoSurface_getFlippedBuffer
182 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
183  jlong surfacePointer)
184 {
185   cairo_surface_t* surface;
186   jint *src;
187   jint *dst;
188   int i, t, width, height;
189   jclass cls;
190   jfieldID field;
191 
192   /* Retrieve pointer to cairo data buffer */
193   surface = JLONG_TO_PTR(void, surfacePointer);
194   src = (jint*)cairo_image_surface_get_data(surface);
195 
196   /* Retrieve dimensions of surface, from java fields */
197   cls = (*env)->GetObjectClass (env, obj);
198   field = (*env)->GetFieldID (env, cls, "width", "I");
199   g_assert (field != 0);
200   width = (*env)->GetIntField (env, obj, field);
201 
202   field = (*env)->GetFieldID (env, cls, "height", "I");
203   g_assert (field != 0);
204   height = (*env)->GetIntField (env, obj, field);
205 
206   /* Create destination array */
207   g_assert( src != NULL );
208   dst = g_malloc( width * height * sizeof( jint ) );
209 
210   /* Copy data into destination array, reversing sample order of each pixel */
211   for(i = 0; i < (height * width); i++ )
212     {
213       t = (src[i] & 0x0000FF) << 16;
214       dst[i] = (src[i] & 0x00FF0000) >> 16;
215       dst[i] |= (src[i] & 0xFF00FF00);
216       dst[i] |= t;
217     }
218 
219   return PTR_TO_JLONG(dst);
220 }
221 
222 /**
223  * Create and return a cairo context for drawing to the surface.
224  */
225 JNIEXPORT jlong JNICALL
Java_gnu_java_awt_peer_gtk_CairoSurface_nativeNewCairoContext(JNIEnv * env __attribute ((unused)),jobject obj __attribute ((unused)),jlong surfacePointer)226 Java_gnu_java_awt_peer_gtk_CairoSurface_nativeNewCairoContext
227 (JNIEnv *env __attribute((unused)), jobject obj __attribute((unused)),
228  jlong surfacePointer)
229 {
230   cairo_surface_t* surface = JLONG_TO_PTR(cairo_surface_t, surfacePointer);
231   cairo_t *ptr;
232   g_assert(surface != NULL);
233   ptr = cairo_create(surface);
234   g_assert(ptr != NULL);
235 
236   return PTR_TO_JLONG(ptr);
237 }
238 
239 /**
240  * copyArea.
241  */
242 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoSurface_copyAreaNative2(JNIEnv * env,jobject obj,jlong surfacePointer,jint x,jint y,jint w,jint h,jint dx,jint dy,jint stride)243 Java_gnu_java_awt_peer_gtk_CairoSurface_copyAreaNative2
244 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
245  jlong surfacePointer,
246  jint x, jint y, jint w, jint h, jint dx, jint dy, jint stride)
247 {
248   int row;
249   int srcOffset, dstOffset;
250   jint *temp;
251 
252   /* Retrieve pointer to cairo data buffer */
253   cairo_surface_t* surface = JLONG_TO_PTR(void, surfacePointer);
254   jint *pixeldata = (jint*)cairo_image_surface_get_data(surface);
255   g_assert( pixeldata != NULL );
256 
257   /* Create temporary buffer and calculate offsets */
258   temp = g_malloc( h * w * 4 );
259   g_assert( temp != NULL );
260 
261   srcOffset = x + (y * stride);
262   dstOffset = (x + dx) + ((y + dy) * stride);
263 
264   /* Copy desired region into temporary buffer */
265   for( row = 0; row < h; row++ )
266     memcpy( temp + (w * row), pixeldata + srcOffset + (stride * row), w * 4 );
267 
268   /* Copy out of buffer and to destination */
269   for( row = 0; row < h; row++ )
270     memcpy( pixeldata + dstOffset + (stride * row), temp + (w * row), w * 4 );
271 
272   g_free( temp );
273 }
274 
275 /*
276  * Synchronizes the java and native data buffers, copying any changes made in
277  * the java array into the native array.
278  * This method should only be called if (sharedBuffer == false).
279  */
280 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoSurface_syncJavaToNative(JNIEnv * env,jobject obj,jlong surfacePointer,jintArray buffer)281 Java_gnu_java_awt_peer_gtk_CairoSurface_syncJavaToNative
282 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
283  jlong surfacePointer, jintArray buffer)
284 {
285   /* Get size of java array */
286   int size = (*env)->GetArrayLength(env, buffer);
287 
288   /* Get native data buffer */
289   cairo_surface_t* surface = JLONG_TO_PTR(void, surfacePointer);
290   g_assert(surface != NULL);
291   void* nativeBuffer = cairo_image_surface_get_data(surface);
292 
293   /* Sync buffers */
294   (*env)->GetIntArrayRegion(env, buffer, 0, size, nativeBuffer);
295 }
296 
297 /*
298  * Synchronizes the java and native data buffers, copying any changes made in
299  * the native array into the java array.
300  * This method should only be called if (sharedBuffer == false).
301  */
302 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_CairoSurface_syncNativeToJava(JNIEnv * env,jobject obj,jlong surfacePointer,jintArray buffer)303 Java_gnu_java_awt_peer_gtk_CairoSurface_syncNativeToJava
304 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
305  jlong surfacePointer, jintArray buffer)
306 {
307   /* Get size of java array */
308   int size = (*env)->GetArrayLength(env, buffer);
309 
310   /* Get native data buffer */
311   cairo_surface_t* surface = JLONG_TO_PTR(void, surfacePointer);
312   g_assert(surface != NULL);
313   void* nativeBuffer = cairo_image_surface_get_data(surface);
314 
315   /* Sync buffers */
316   (*env)->SetIntArrayRegion(env, buffer, 0, size, nativeBuffer);
317 }
318 
319 /*
320  * Sets the native object field.
321  */
322 static void
setNativeObject(JNIEnv * env,jobject obj,void * ptr,const char * pointer)323 setNativeObject( JNIEnv *env, jobject obj, void *ptr, const char *pointer )
324 {
325   jclass cls;
326   jlong value;
327   jfieldID nofid;
328   cls = (*env)->GetObjectClass( env, obj );
329   value = PTR_TO_JLONG(ptr);
330   nofid = (*env)->GetFieldID( env, cls, pointer, "J" );
331   (*env)->SetLongField( env, obj, nofid, value );
332   (*env)->DeleteLocalRef( env, cls );
333 }
334