2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / jni / gtk-peer / gnu_java_awt_peer_gtk_GdkGlyphVector.c
blob29616c738edfb7879412934afb8611d2d3e78d5b
1 /* gdkglyphvector.c
2 Copyright (C) 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
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.
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. */
38 #include "gdkfont.h"
39 #include "gnu_java_awt_peer_gtk_GdkGlyphVector.h"
41 struct state_table *native_glyphvector_state_table;
43 typedef struct {
44 double x;
45 double y;
46 double width;
47 double height;
48 } rect_t;
50 #define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 63.0))
51 #define DOUBLE_FROM_26_6(t) (((double)((t) >> 6)) \
52 + ((double)((t) & 0x3F) / 63.0))
54 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_initStaticState
55 (JNIEnv *env, jclass clazz)
57 NSA_GV_INIT (env, clazz);
60 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_initState
61 (JNIEnv *env, jobject self, jobject font, jobject ctx)
63 struct glyphvec *vec = NULL;
64 struct peerfont *pfont = NULL;
66 gdk_threads_enter ();
67 g_assert (font != NULL);
68 pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, font);
69 g_assert (pfont != NULL);
70 g_assert (pfont->ctx != NULL);
71 g_assert (pfont->desc != NULL);
73 g_assert (self != NULL);
74 vec = (struct glyphvec *) g_malloc0 (sizeof (struct glyphvec));
75 g_assert (vec != NULL);
77 vec->desc = pango_font_describe (pfont->font);
78 g_assert (vec->desc != NULL);
80 vec->font = pfont->font;
81 g_object_ref (vec->font);
83 vec->ctx = pfont->ctx;
84 g_object_ref (vec->ctx);
86 NSA_SET_GV_PTR (env, self, vec);
87 gdk_threads_leave ();
90 static void free_glyphitems (GList *list)
92 GList *i = NULL;
93 PangoGlyphItem *gi = NULL;
95 for (i = g_list_first (list); i != NULL; i = g_list_next (i))
97 g_assert (i->data != NULL);
98 gi = (PangoGlyphItem *)i->data;
100 if (gi->glyphs != NULL)
101 pango_glyph_string_free (gi->glyphs);
103 if (gi->item != NULL)
104 g_free (gi->item);
106 g_list_free (list);
109 static void seek_glyphstring_idx (GList *list, int idx,
110 int *nidx,
111 PangoGlyphString **gs,
112 PangoFont **fnt)
114 GList *i = NULL;
115 PangoGlyphItem *gi = NULL;
117 g_assert (list != NULL);
118 g_assert (gs != NULL);
119 g_assert (nidx != NULL);
121 int begin = 0;
122 for (i = g_list_first (list); i != NULL; i = g_list_next (i))
124 g_assert (i->data != NULL);
125 gi = (PangoGlyphItem *)i->data;
127 g_assert (gi->glyphs != NULL);
129 if (begin <= idx && idx < begin + gi->glyphs->num_glyphs)
131 *gs = gi->glyphs;
132 *nidx = idx - begin;
133 if (fnt && gi->item)
134 *fnt = gi->item->analysis.font;
135 return;
137 else
139 begin += gi->glyphs->num_glyphs;
142 *gs = NULL;
143 *nidx = -1;
146 static void seek_glyph_idx (GList *list, int idx,
147 PangoGlyphInfo **g,
148 PangoFont **fnt)
150 PangoGlyphString *gs = NULL;
151 int nidx = -1;
153 g_assert (list != NULL);
154 g_assert (g != NULL);
156 seek_glyphstring_idx (list, idx, &nidx, &gs, fnt);
158 g_assert (gs != NULL);
159 g_assert (nidx != -1);
160 g_assert (nidx < gs->num_glyphs);
161 g_assert (gs->glyphs != NULL);
163 *g = gs->glyphs + nidx;
166 static void union_rects (rect_t *r1,
167 const rect_t *r2)
169 rect_t r;
171 g_assert (r1 != NULL);
172 g_assert (r2 != NULL);
175 x is the left edge of the rect,
176 y is the top edge of the rect
179 #ifndef min
180 #define min(x,y) ((x) < (y) ? (x) : (y))
181 #endif
183 #ifndef max
184 #define max(x,y) ((x) < (y) ? (y) : (x))
185 #endif
187 r.x = min(r1->x, r2->x);
189 r.y = min(r1->y, r2->y);
191 r.width = max(r1->x + r1->width,
192 r2->x + r2->width) - r.x;
194 r.height = max(r1->y + r1->height,
195 r2->y + r2->height) - r.y;
197 *r1 = r;
200 static jdoubleArray rect_to_array (JNIEnv *env, const rect_t *r)
202 /* We often return rectangles as arrays : { x, y, w, h } */
203 jdoubleArray ret;
204 double *rp = NULL;
205 g_assert (r != NULL);
206 ret = (*env)->NewDoubleArray (env, 4);
207 rp = (*env)->GetDoubleArrayElements (env, ret, NULL);
208 g_assert (rp != NULL);
209 rp[0] = r->x;
210 /* freetype and pango's view of space is upside down from java2d's */
211 rp[1] = r->y * -1;
212 rp[2] = r->width;
213 rp[3] = r->height;
214 (*env)->ReleaseDoubleArrayElements (env, ret, rp, 0);
215 return ret;
219 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_dispose
220 (JNIEnv *env, jobject self)
222 struct glyphvec *vec = NULL;
224 gdk_threads_enter ();
225 g_assert (self != NULL);
226 vec = (struct glyphvec *)NSA_DEL_GV_PTR (env, self);
227 g_assert (vec != NULL);
229 if (vec->glyphitems != NULL)
231 free_glyphitems (vec->glyphitems);
232 vec->glyphitems = NULL;
235 if (vec->desc != NULL)
236 pango_font_description_free (vec->desc);
238 if (vec->ctx != NULL)
239 g_object_unref (vec->ctx);
241 g_free (vec);
242 gdk_threads_leave ();
246 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_setChars
247 (JNIEnv *env, jobject self, jstring chars)
249 struct glyphvec *vec = NULL;
250 gchar *str = NULL;
251 GList *items = NULL, *item = NULL;
252 PangoGlyphItem *gi;
253 PangoAttrList *attrs = NULL;
254 gint len = 0;
256 gdk_threads_enter ();
257 g_assert (self != NULL);
258 vec = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
259 g_assert (vec != NULL);
260 g_assert (vec->desc != NULL);
261 g_assert (vec->ctx != NULL);
263 len = (*gdk_env)->GetStringUTFLength (env, chars);
264 str = (gchar *)(*env)->GetStringUTFChars (env, chars, NULL);
265 g_assert (str != NULL);
267 /* step 1: set our FontFescription in the context, then "itemize" the
268 text */
270 attrs = pango_attr_list_new ();
271 g_assert (attrs != NULL);
273 pango_context_set_font_description (vec->ctx, vec->desc);
275 items = pango_itemize (vec->ctx, str, 0, len, attrs, NULL);
276 g_assert (items != NULL);
279 step 2: for each item:
280 - shape the item into a glyphstring
281 - store the (item, glyphstring) pair in the vec->glyphitems list
284 if (vec->glyphitems != NULL)
286 free_glyphitems (vec->glyphitems);
287 vec->glyphitems = NULL;
290 for (item = g_list_first (items); item != NULL; item = g_list_next (item))
292 g_assert (item->data != NULL);
294 gi = NULL;
295 gi = g_malloc0 (sizeof(PangoGlyphItem));
296 g_assert (gi != NULL);
298 gi->item = (PangoItem *)item->data;
299 gi->glyphs = pango_glyph_string_new ();
300 g_assert (gi->glyphs != NULL);
302 pango_shape (str + gi->item->offset,
303 gi->item->length,
304 &(gi->item->analysis),
305 gi->glyphs);
307 vec->glyphitems = g_list_append (vec->glyphitems, gi);
311 ownership of each item has been transferred to glyphitems,
312 but the list should be freed.
315 g_list_free (items);
316 pango_attr_list_unref (attrs);
318 (*env)->ReleaseStringUTFChars (env, chars, str);
319 gdk_threads_leave ();
323 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_setGlyphCodes
324 (JNIEnv *env, jobject self, jintArray codes)
326 struct glyphvec *vec = NULL;
328 gdk_threads_enter ();
329 g_assert (self != NULL);
330 vec = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
331 g_assert (vec != NULL);
334 FIXME: setting glyph codes doesn't seem particularly plausible at the
335 moment.
338 gdk_threads_leave ();
343 JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_glyphCode
344 (JNIEnv *env, jobject self, jint idx)
346 struct glyphvec *vec = NULL;
347 PangoGlyphInfo *gi = NULL;
348 jint ret = 0;
350 gdk_threads_enter ();
351 g_assert (self != NULL);
352 vec = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
353 g_assert (vec != NULL);
354 g_assert (vec->glyphitems != NULL);
356 seek_glyph_idx (vec->glyphitems, idx, &gi, NULL);
357 g_assert (gi != NULL);
358 ret = gi->glyph;
359 gdk_threads_leave ();
361 return (jint)(ret);
365 JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_numGlyphs
366 (JNIEnv *env, jobject self)
368 GList *i = NULL;
369 PangoGlyphItem *gi = NULL;
370 struct glyphvec *vec = NULL;
371 jint count = 0;
373 gdk_threads_enter ();
374 g_assert (self != NULL);
375 vec = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
376 g_assert (vec != NULL);
378 for (i = g_list_first (vec->glyphitems); i != NULL; i = g_list_next (i))
380 g_assert (i->data != NULL);
381 gi = (PangoGlyphItem *)i->data;
382 g_assert (gi->glyphs != NULL);
383 count += gi->glyphs->num_glyphs;
385 gdk_threads_leave ();
387 return count;
391 JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_glyphCharIndex
392 (JNIEnv *env, jobject self, jint idx)
395 FIXME: this is not correct, rather it assumes a (broken) 1:1
396 glyph:char model. it can be implemented in terms of bytes (also
397 broken) using pango's current interface, or perhaps in terms of
398 characters if some better byte->character conversion operator is
399 found. for the time being we leave it broken.
401 return idx;
405 JNIEXPORT jdoubleArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_allInkExtents
406 (JNIEnv *env, jobject self)
408 struct glyphvec *vec = NULL;
409 int j;
410 GList *i;
411 PangoGlyphItem *gi = NULL;
412 rect_t rect = {0,0,0,0};
413 rect_t tmp;
414 jdoubleArray ret;
415 double x = 0, y = 0;
416 double pointsize;
417 FT_Face face;
419 gdk_threads_enter ();
420 g_assert (self != NULL);
421 vec = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
422 g_assert (vec != NULL);
423 g_assert (vec->glyphitems != NULL);
425 pointsize = pango_font_description_get_size (vec->desc);
426 pointsize /= (double) PANGO_SCALE;
428 for (i = g_list_first (vec->glyphitems); i != NULL; i = g_list_next (i))
430 g_assert (i->data != NULL);
431 gi = (PangoGlyphItem *)i->data;
432 g_assert (gi->glyphs != NULL);
434 face = pango_ft2_font_get_face (gi->item->analysis.font);
435 FT_Set_Char_Size( face,
436 DOUBLE_TO_26_6 (pointsize),
437 DOUBLE_TO_26_6 (pointsize),
438 0, 0);
440 for (j = 0; j < gi->glyphs->num_glyphs; ++j)
442 FT_Load_Glyph (face, gi->glyphs->glyphs[j].glyph, FT_LOAD_DEFAULT);
443 /* FIXME: this needs to change for vertical layouts */
444 tmp.x = x + DOUBLE_FROM_26_6 (face->glyph->metrics.horiBearingX);
445 tmp.y = y + DOUBLE_FROM_26_6 (face->glyph->metrics.horiBearingY);
446 tmp.width = DOUBLE_FROM_26_6 (face->glyph->metrics.width);
447 tmp.height = DOUBLE_FROM_26_6 (face->glyph->metrics.height);
448 union_rects (&rect, &tmp);
449 x += DOUBLE_FROM_26_6 (face->glyph->advance.x);
450 y += DOUBLE_FROM_26_6 (face->glyph->advance.y);
454 ret = rect_to_array (env, &rect);
455 gdk_threads_leave ();
456 return ret;
460 JNIEXPORT jdoubleArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_allLogicalExtents
461 (JNIEnv *env, jobject self)
463 struct glyphvec *vec = NULL;
464 int j;
465 GList *i;
466 PangoGlyphItem *gi = NULL;
467 rect_t rect = {0,0,0,0};
468 rect_t tmp;
469 jdoubleArray ret;
470 double x = 0, y = 0;
471 double pointsize;
472 FT_Face face;
474 gdk_threads_enter ();
475 g_assert (self != NULL);
476 vec = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
477 g_assert (vec != NULL);
478 g_assert (vec->glyphitems != NULL);
480 pointsize = pango_font_description_get_size (vec->desc);
481 pointsize /= (double) PANGO_SCALE;
483 for (i = g_list_first (vec->glyphitems); i != NULL; i = g_list_next (i))
485 g_assert (i->data != NULL);
486 gi = (PangoGlyphItem *)i->data;
487 g_assert (gi->glyphs != NULL);
489 face = pango_ft2_font_get_face (gi->item->analysis.font);
490 FT_Set_Char_Size( face,
491 DOUBLE_TO_26_6 (pointsize),
492 DOUBLE_TO_26_6 (pointsize),
493 0, 0);
495 for (j = 0; j < gi->glyphs->num_glyphs; ++j)
497 FT_Load_Glyph (face, gi->glyphs->glyphs[j].glyph, FT_LOAD_DEFAULT);
499 /* FIXME: also, this is probably not the correct set of metrics;
500 the "logical bounds" are some fancy combination of hori
501 advance and height such that it's good for inverting as a
502 highlight. revisit. */
504 tmp.x = x;
505 tmp.y = y;
506 tmp.width = DOUBLE_FROM_26_6 (face->glyph->advance.x);
507 tmp.height = DOUBLE_FROM_26_6 (face->glyph->advance.y);
508 union_rects (&rect, &tmp);
509 x += DOUBLE_FROM_26_6 (face->glyph->advance.x);
510 y += DOUBLE_FROM_26_6 (face->glyph->advance.y);
514 ret = rect_to_array (env, &rect);
515 gdk_threads_leave ();
516 return ret;
520 JNIEXPORT jdoubleArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_glyphLogicalExtents
521 (JNIEnv *env, jobject self, jint idx)
523 struct glyphvec *vec = NULL;
524 rect_t rect = {0,0,0,0};
525 PangoGlyphInfo *gi = NULL;
526 PangoFont *font = NULL;
527 jdoubleArray ret;
528 double pointsize;
529 FT_Face face;
531 gdk_threads_enter ();
532 g_assert (self != NULL);
533 vec = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
534 g_assert (vec != NULL);
535 g_assert (vec->glyphitems != NULL);
537 seek_glyph_idx (vec->glyphitems, idx, &gi, &font);
538 g_assert (gi != NULL);
539 g_assert (font != NULL);
541 pointsize = pango_font_description_get_size (vec->desc);
542 pointsize /= (double) PANGO_SCALE;
543 face = pango_ft2_font_get_face (font);
544 FT_Set_Char_Size( face,
545 DOUBLE_TO_26_6 (pointsize),
546 DOUBLE_TO_26_6 (pointsize),
547 0, 0);
549 FT_Load_Glyph (face, gi->glyph, FT_LOAD_DEFAULT);
551 /* FIXME: this is probably not the correct set of metrics;
552 the "logical bounds" are some fancy combination of hori
553 advance and height such that it's good for inverting as a
554 highlight. revisit. */
556 rect.x = 0;
557 rect.y = 0;
558 rect.width = DOUBLE_FROM_26_6 (face->glyph->advance.x);
559 rect.height = DOUBLE_FROM_26_6 (face->glyph->advance.y);
561 ret = rect_to_array (env, &rect);
562 gdk_threads_leave ();
563 return ret;
567 JNIEXPORT jdoubleArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_glyphInkExtents
568 (JNIEnv *env, jobject self, jint idx)
570 struct glyphvec *vec = NULL;
571 rect_t rect = {0,0,0,0};
572 PangoGlyphInfo *gi = NULL;
573 PangoFont *font = NULL;
574 jdoubleArray ret;
575 double pointsize;
576 FT_Face face;
578 gdk_threads_enter ();
579 g_assert (self != NULL);
580 vec = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
581 g_assert (vec != NULL);
582 g_assert (vec->glyphitems != NULL);
584 seek_glyph_idx (vec->glyphitems, idx, &gi, &font);
585 g_assert (gi != NULL);
586 g_assert (font != NULL);
588 pointsize = pango_font_description_get_size (vec->desc);
589 pointsize /= (double) PANGO_SCALE;
590 face = pango_ft2_font_get_face (font);
591 FT_Set_Char_Size( face,
592 DOUBLE_TO_26_6 (pointsize),
593 DOUBLE_TO_26_6 (pointsize),
594 0, 0);
596 FT_Load_Glyph (face, gi->glyph, FT_LOAD_DEFAULT);
597 /* FIXME: this needs to change for vertical layouts */
598 rect.x = DOUBLE_FROM_26_6 (face->glyph->metrics.horiBearingX);
599 rect.y = DOUBLE_FROM_26_6 (face->glyph->metrics.horiBearingY);
600 rect.width = DOUBLE_FROM_26_6 (face->glyph->metrics.width);
601 rect.height = DOUBLE_FROM_26_6 (face->glyph->metrics.height);
603 ret = rect_to_array (env, &rect);
604 gdk_threads_leave ();
605 return ret;
609 JNIEXPORT jboolean JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_glyphIsHorizontal
610 (JNIEnv *env, jobject self, jint idx)
612 struct glyphvec *vec = NULL;
613 PangoDirection dir;
615 gdk_threads_enter ();
616 g_assert (self != NULL);
617 vec = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
618 g_assert (vec != NULL);
619 g_assert (vec->desc != NULL);
620 g_assert (vec->ctx != NULL);
623 FIXME: this is an approximation; it's not clear to me whether
624 glyphs themselves are horizontal or vertical so much as the
625 writing system or writing context. pango thinks it's a context
626 issue, so we use that for now.
629 dir = pango_context_get_base_dir (vec->ctx);
631 gdk_threads_leave ();
633 return
634 ((dir == PANGO_DIRECTION_LTR) ||
635 (dir == PANGO_DIRECTION_RTL));
639 JNIEXPORT jboolean JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_isEqual
640 (JNIEnv *env, jobject self, jobject other)
642 struct glyphvec *vec1 = NULL, *vec2 = NULL;
643 jboolean eq = 0;
645 gdk_threads_enter ();
646 g_assert (self != NULL);
647 vec1 = (struct glyphvec *)NSA_GET_GV_PTR (env, self);
648 vec2 = (struct glyphvec *)NSA_GET_GV_PTR (env, other);
649 g_assert (vec1 != NULL);
650 g_assert (vec2 != NULL);
652 /* FIXME: is there some more advantageous definition of equality for
653 glyph vectors? */
654 eq = (vec1 == vec2);
656 gdk_threads_leave ();
657 return eq;