1 /* gnu_java_awt_FreetypeGlyphVector.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 #define PANGO_ENABLE_ENGINE
39 #include <jni.h>
40 #include <gtk/gtk.h>
41 #include <string.h>
42 #include <pango/pango.h>
43 #include <pango/pangoft2.h>
44 #include <pango/pangofc-font.h>
45 #include <ft2build.h>
46 #include FT_GLYPH_H
47 #include FT_OUTLINE_H
48 #include "jcl.h"
49 #include "gdkfont.h"
50 #include "gnu_java_awt_peer_gtk_FreetypeGlyphVector.h"
51 #include "cairographics2d.h"
52 
53 typedef struct gp
54 {
55   JNIEnv *env;
56   jobject obj;
57   double px;
58   double py;
59   double sx;
60   double sy;
61 } generalpath ;
62 
63 static PangoFcFont *
getFont(JNIEnv * env,jobject obj)64 getFont(JNIEnv *env, jobject obj)
65 {
66   jfieldID fid;
67   jobject data;
68   jclass cls;
69   struct peerfont *pfont;
70 
71   cls = (*env)->GetObjectClass (env, obj);
72   fid = (*env)->GetFieldID (env, cls, "peer",
73 				 "Lgnu/java/awt/peer/gtk/GdkFontPeer;");
74   g_assert (fid != 0);
75 
76   data = (*env)->GetObjectField (env, obj, fid);
77   g_assert (data != NULL);
78 
79   pfont = (struct peerfont *) gtkpeer_get_font(env, data);
80   g_assert (pfont != NULL);
81   g_assert (pfont->font != NULL);
82 
83   return (PangoFcFont *)pfont->font;
84 }
85 
86 static PangoFontset *
getFontSet(JNIEnv * env,jobject obj)87 getFontSet(JNIEnv *env, jobject obj)
88 {
89   jfieldID fid;
90   jobject data;
91   jclass cls;
92   struct peerfont *pfont;
93 
94   cls = (*env)->GetObjectClass (env, obj);
95   fid = (*env)->GetFieldID (env, cls, "peer",
96 				 "Lgnu/java/awt/peer/gtk/GdkFontPeer;");
97   g_assert (fid != 0);
98 
99   data = (*env)->GetObjectField (env, obj, fid);
100   g_assert (data != NULL);
101 
102   pfont = (struct peerfont *) gtkpeer_get_font (env, data);
103   g_assert (pfont != NULL);
104   g_assert (pfont->font != NULL);
105 
106   return (PangoFontset *)pfont->set;
107 }
108 
109 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getGlyphs(JNIEnv * env,jobject obj,jintArray codepoints,jintArray glyphs,jlongArray fonts)110 Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getGlyphs
111   (JNIEnv *env, jobject obj, jintArray codepoints, jintArray glyphs,
112    jlongArray fonts)
113 {
114   PangoFcFont *default_font, *current_font;
115   PangoFontset *pfs;
116   jint *cpvals;
117   jint length;
118   int i;
119 
120   /* Set up default font and fontset */
121   default_font = getFont(env, obj);
122   current_font = default_font;
123   pfs = getFontSet(env, obj);
124 
125   /* Retrieve string information */
126   length = (*env)->GetArrayLength (env, codepoints);
127   cpvals = (*env)->GetIntArrayElements (env, codepoints, NULL);
128 
129   jint *glyphArray = (*env)->GetIntArrayElements (env, glyphs, NULL);
130   jlong *fontArray = (*env)->GetLongArrayElements (env, fonts, NULL);
131 
132   /* A design goal of Pango is to be threadsafe, but it's admitted that it is
133    * not actually threadsafe at the moment.  Using gdk locking here to be safe,
134    * but I don't know if if actually helps at all... */
135   gdk_threads_enter();
136 
137   for( i = 0; i < length; i++ )
138   {
139   	/* Ensure the current font has the requested character; if it doesn't,
140   	 * try the default font before pulling a new font out of the fontset.
141   	 * Once chosen, a font will be used until a character not in the font is
142   	 * encountered. */
143   	if (!pango_fc_font_has_char(current_font, cpvals[i]))
144   	  {
145   	    if (pango_fc_font_has_char(default_font, cpvals[i]))
146   	      {
147   	        current_font = default_font;
148             g_object_ref(current_font);
149   	      }
150   	    else
151   	      {
152   	        current_font = (PangoFcFont*)pango_fontset_get_font(pfs, cpvals[i]);
153   	      }
154   	  }
155   	else
156       {
157         g_object_ref(current_font);
158       }
159 
160   	/* Get glyph, and store both glyph and pointer to font */
161     glyphArray[i] = (int)pango_fc_font_get_glyph(current_font,
162                                                  (gunichar)cpvals[i]);
163     fontArray[i] = PTR_TO_JLONG(current_font);
164   }
165 
166   gdk_threads_leave();
167 
168   (*env)->ReleaseIntArrayElements (env, glyphs, glyphArray, 0);
169   (*env)->ReleaseIntArrayElements (env, codepoints, cpvals, 0);
170   (*env)->ReleaseLongArrayElements (env, fonts, fontArray, 0);
171 }
172 
173 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getKerning(JNIEnv * env,jobject obj,jint rightGlyph,jint leftGlyph,jlong fnt,jfloatArray p)174 Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getKerning
175   (JNIEnv *env, jobject obj __attribute__((unused)), jint rightGlyph,
176    jint leftGlyph, jlong fnt, jfloatArray p)
177 {
178   FT_Face ft_face;
179   FT_Vector kern;
180   PangoFcFont *font;
181 
182   font = JLONG_TO_PTR(PangoFcFont, fnt);
183   ft_face = pango_fc_font_lock_face( font );
184   g_assert (ft_face != NULL);
185   FT_Get_Kerning( ft_face, rightGlyph, leftGlyph, FT_KERNING_DEFAULT, &kern );
186 
187   pango_fc_font_unlock_face( font );
188 
189   jfloat *pelements = (*env)->GetPrimitiveArrayCritical(env, p, NULL);
190   pelements[0] = (jfloat)kern.x/64.0;
191   pelements[1] = (jfloat)kern.y/64.0;
192   (*env)->ReleasePrimitiveArrayCritical (env, p, pelements, 0);
193 }
194 
195 JNIEXPORT jdoubleArray JNICALL
Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getMetricsNative(JNIEnv * env,jobject obj,jint glyphIndex,jlong fnt)196 Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getMetricsNative
197 (JNIEnv *env, jobject obj __attribute__((unused)), jint glyphIndex, jlong fnt)
198 {
199   FT_Face ft_face;
200   jdouble *values;
201   jdoubleArray retArray = NULL;
202   PangoFcFont *font;
203 
204   font = JLONG_TO_PTR(PangoFcFont, fnt);
205   ft_face = pango_fc_font_lock_face( font );
206 
207   g_assert (ft_face != NULL);
208 
209   FT_Set_Transform( ft_face, NULL, NULL );
210 
211   if( FT_Load_Glyph( ft_face, glyphIndex, FT_LOAD_NO_BITMAP ) != 0 )
212     {
213       pango_fc_font_unlock_face( font );
214       printf("Couldn't load glyph %i\n", glyphIndex);
215       return NULL;
216     }
217 
218   retArray = (*env)->NewDoubleArray (env, 8);
219   values = (*env)->GetDoubleArrayElements (env, retArray, NULL);
220 
221   values[0] = 0;
222   values[1] = (jdouble)ft_face->glyph->advance.x/64.0;
223   values[2] = (jdouble)ft_face->glyph->advance.y/64.0;
224   values[3] = (jdouble)ft_face->glyph->metrics.horiBearingX/64.0;
225   values[4] = -(jdouble)ft_face->glyph->metrics.horiBearingY/64.0;
226   values[5] = (jdouble)ft_face->glyph->metrics.width/64.0;
227   values[6] = (jdouble)ft_face->glyph->metrics.height/64.0;
228   values[7] = 0;
229 
230   (*env)->ReleaseDoubleArrayElements (env, retArray, values, 0);
231   pango_fc_font_unlock_face( font );
232 
233   return retArray;
234 }
235 
236 /* GetOutline code follows ****************************/
237 /********* Freetype callback functions *****************************/
238 
_moveTo(const FT_Vector * to,void * p)239 static int _moveTo( const FT_Vector* to,
240 		    void *p)
241 {
242   JNIEnv *env;
243   jobject obj;
244   jclass cls;
245   jmethodID method;
246   jvalue values[2];
247   generalpath *path = (generalpath *) p;
248 
249   env = path->env;
250   obj = path->obj;
251 
252   values[0].f = (jfloat)(to->x * path->sx + path->px);
253   values[1].f = (jfloat)(to->y * path->sy + path->py);
254 
255   cls = (*env)->FindClass (env, "java/awt/geom/GeneralPath");
256   method = (*env)->GetMethodID (env, cls, "moveTo", "(FF)V");
257   (*env)->CallVoidMethodA(env, obj, method, values );
258 
259   return 0;
260 }
261 
_lineTo(const FT_Vector * to,void * p)262 static int _lineTo( const FT_Vector*  to,
263 		    void *p)
264 {
265   JNIEnv *env;
266   jobject obj;
267   jclass cls;
268   jmethodID method;
269   jvalue values[2];
270   generalpath *path = (generalpath *) p;
271 
272   env = path->env;
273   obj = path->obj;
274   values[0].f = (jfloat)(to->x * path->sx + path->px);
275   values[1].f = (jfloat)(to->y * path->sy + path->py);
276 
277   cls = (*env)->FindClass (env, "java/awt/geom/GeneralPath");
278   method = (*env)->GetMethodID (env, cls, "lineTo", "(FF)V");
279   (*env)->CallVoidMethodA(env, obj, method, values );
280 
281   return 0;
282 }
283 
_quadTo(const FT_Vector * cp,const FT_Vector * to,void * p)284 static int _quadTo( const FT_Vector*  cp,
285 		    const FT_Vector*  to,
286 		    void *p)
287 {
288   JNIEnv *env;
289   jobject obj;
290   jclass cls;
291   jmethodID method;
292   jvalue values[4];
293   generalpath *path = (generalpath *) p;
294 
295   env = path->env;
296   obj = path->obj;
297   values[0].f = (jfloat)(cp->x * path->sx + path->px);
298   values[1].f = (jfloat)(cp->y * path->sy + path->py);
299   values[2].f = (jfloat)(to->x * path->sx + path->px);
300   values[3].f = (jfloat)(to->y * path->sy + path->py);
301 
302   cls = (*env)->FindClass (env, "java/awt/geom/GeneralPath");
303   method = (*env)->GetMethodID (env, cls, "quadTo", "(FFFF)V");
304   (*env)->CallVoidMethodA(env, obj, method, values );
305 
306   return 0;
307 }
308 
_curveTo(const FT_Vector * cp1,const FT_Vector * cp2,const FT_Vector * to,void * p)309 static int _curveTo( const FT_Vector*  cp1,
310 		     const FT_Vector*  cp2,
311 		     const FT_Vector*  to,
312 		     void *p)
313 {
314   JNIEnv *env;
315   jobject obj;
316   jclass cls;
317   jmethodID method;
318   jvalue values[6];
319   generalpath *path = (generalpath *) p;
320 
321   env = path->env;
322   obj = path->obj;
323   values[0].f = (jfloat)(cp1->x * path->sx + path->px);
324   values[1].f = (jfloat)(cp1->y * path->sy + path->py);
325   values[2].f = (jfloat)(cp2->x * path->sx + path->px);
326   values[3].f = (jfloat)(cp2->y * path->sy + path->py);
327   values[4].f = (jfloat)(to->x * path->sx + path->px);
328   values[5].f = (jfloat)(to->y * path->sy + path->py);
329 
330   cls = (*env)->FindClass (env, "java/awt/geom/GeneralPath");
331   method = (*env)->GetMethodID (env, cls, "curveTo", "(FFFFFF)V");
332   (*env)->CallVoidMethodA(env, obj, method, values );
333 
334   return 0;
335 }
336 
337 
338 JNIEXPORT jobject JNICALL
Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getGlyphOutlineNative(JNIEnv * env,jobject obj,jint glyphIndex,jlong fnt)339 Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getGlyphOutlineNative
340  (JNIEnv *env, jobject obj __attribute__((unused)), jint glyphIndex, jlong fnt)
341 {
342   generalpath *path;
343   jobject gp;
344   FT_Outline_Funcs ftCallbacks =
345     {
346       (FT_Outline_MoveToFunc) _moveTo,
347       (FT_Outline_LineToFunc) _lineTo,
348       (FT_Outline_ConicToFunc) _quadTo,
349       (FT_Outline_CubicToFunc) _curveTo,
350       0,
351       0
352     };
353   PangoFcFont *font;
354   FT_Face ft_face;
355   FT_Glyph glyph;
356 
357   font = JLONG_TO_PTR(PangoFcFont, fnt);
358   ft_face = pango_fc_font_lock_face( font );
359 
360   g_assert (ft_face != NULL);
361 
362   path = g_malloc0 (sizeof (generalpath));
363   g_assert(path != NULL);
364   path->env = env;
365 
366   path->px = path->py = 0.0;
367   path->sx = 1.0/64.0;
368   path->sy = -1.0/64.0;
369 
370   {  /* create a GeneralPath instance */
371     jclass cls;
372     jmethodID method;
373 
374     cls = (*env)->FindClass (env, "java/awt/geom/GeneralPath");
375     method = (*env)->GetMethodID (env, cls, "<init>", "()V");
376     gp = path->obj = (*env)->NewObject (env, cls, method);
377   }
378 
379   if(FT_Load_Glyph(ft_face,
380 		   (FT_UInt)(glyphIndex),
381 		   FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP) != 0)
382     {
383       pango_fc_font_unlock_face( font );
384       g_free(path);
385       return NULL;
386     }
387 
388   FT_Get_Glyph( ft_face->glyph, &glyph );
389   if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
390     {
391       FT_Outline_Decompose (&(((FT_OutlineGlyph)glyph)->outline),
392 			    &ftCallbacks, path);
393     }
394   else
395     {
396       char format[5];
397 
398       format[0] = (glyph->format & 0xFF000000) >> 24;
399       format[1] = (glyph->format & 0x00FF0000) >> 16;
400       format[2] = (glyph->format & 0x0000FF00) >> 8;
401       format[3] = (glyph->format & 0x000000FF);
402       format[4] = '\0';
403       printf("WARNING: Unable to create outline for font %s %s of format %s\n",
404 	     ft_face->family_name, ft_face->style_name, format);
405     }
406   FT_Done_Glyph( glyph );
407 
408   pango_fc_font_unlock_face( font );
409 
410   g_free(path);
411 
412   return gp;
413 }
414 
415 JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_dispose(JNIEnv * env,jobject obj,jlongArray fontset)416 Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_dispose
417  (JNIEnv *env, jobject obj __attribute__((unused)), jlongArray fontset)
418 {
419   PangoFcFont *font;
420   jlong *fontArray;
421   int i, length;
422 
423   length = (*env)->GetArrayLength (env, fontset);
424   fontArray = (*env)->GetLongArrayElements (env, fontset, NULL);
425 
426   gdk_threads_enter();
427 
428   for( i = 0; i < length; i++ )
429   {
430     font = JLONG_TO_PTR(PangoFcFont, fontArray[i]);
431     g_object_unref(font);
432   }
433 
434   gdk_threads_leave();
435 
436   (*env)->ReleaseLongArrayElements (env, fontset, fontArray, 0);
437 }
438 
439 JNIEXPORT jlong JNICALL
Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getNativeFontPointer(JNIEnv * env,jobject obj,jint n)440 Java_gnu_java_awt_peer_gtk_FreetypeGlyphVector_getNativeFontPointer
441  (JNIEnv *env, jobject obj, jint n)
442 {
443   int i;
444   PangoFcFont *font = getFont(env, obj);
445 
446   for (i = 0; i < n; i++)
447     g_object_ref(font);
448 
449   return PTR_TO_JLONG(font);
450 }
451