1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /* ********************************************************************** */
34 
35 #include "coindefs.h"
36 #include "fonts/fontlib_wrapper.h"
37 
38 #include <cstdio>
39 #include <cstring>
40 #include <cstdlib>
41 #include <cassert>
42 #include <cstddef>
43 
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif /* HAVE_CONFIG_H */
47 
48 #include <Inventor/C/tidbits.h>
49 #include <Inventor/C/base/string.h>
50 #include <Inventor/C/errors/debugerror.h>
51 
52 #include "base/dict.h"
53 #include "base/dynarray.h"
54 #include "fonts/freetype.h"
55 #include "fonts/win32.h"
56 #include "fonts/defaultfonts.h"
57 #include "threads/threadsutilp.h"
58 #include "tidbitsp.h"
59 
60 /* ********************************************************************** */
61 
62 /*
63   All public interface functions are protected with this "file-global"
64   lock, to simplify the implementation of the underlying font-import
65   modules (as they won't have to be made reentrant in any way).
66 */
67 
68 static void * flw_global_lock = NULL;
69 static int flw_global_font_index = 0;
70 static SbBool initialized = FALSE;
71 static SbBool tried_init_freetype_fontlib = FALSE;
72 static SbBool tried_init_win32_fontlib = FALSE;
73 static SbBool fontlib_freetype_available = FALSE;
74 static SbBool fontlib_win32_available = FALSE;
75 
76 
77 /* Debug: enable this in case code hangs waiting for a lock.  A hang
78    will typically happen for one out of two reasons:
79 
80    1) The mutex is locked but not released. To check whether or not
81    this is the cause, look for multiple exit points (return
82    statements) in a function.
83 
84    2) A cc_flw_*() function locks the global mutex, then calls another
85    cc_flw_*() function, which when attempting to lock the same
86    mutex will simply hang.
87 
88    -- mortene.
89 */
90 #if 0
91 
92 #define FLW_MUTEX_LOCK(m) \
93   do { \
94     (void)fprintf(stderr, "mutex lock in %s\n", __func__); \
95     CC_MUTEX_LOCK(m); \
96   } while (0)
97 
98 #define FLW_MUTEX_UNLOCK(m) \
99   do { \
100     (void)fprintf(stderr, "mutex unlock in %s\n", __func__); \
101     CC_MUTEX_UNLOCK(m); \
102   } while (0)
103 
104 #else
105 
106 #define FLW_MUTEX_LOCK(m) CC_MUTEX_LOCK(m)
107 #define FLW_MUTEX_UNLOCK(m) CC_MUTEX_UNLOCK(m)
108 
109 #endif
110 
111 /* ********************************************************************** */
112 
113 struct cc_flw_glyph {
114   unsigned int nativeglyphidx;
115   unsigned int character;
116   SbBool fromdefaultfont;
117 
118   /* FIXME: these should have their own "fromdefaultfont" flags, since
119      they may both be, even though the glyph was set up in FreeType or
120      Win32 API. 20050624 mortene. */
121   struct cc_font_bitmap * bitmap;
122   struct cc_font_vector_glyph * vector;
123 };
124 
125 struct cc_flw_font {
126   void * nativefonthandle;
127   cc_string * fontname;
128   cc_string * requestname;
129   cc_dict * glyphdict;
130   unsigned int sizey;
131   float angle;
132   float complexity;
133   SbBool defaultfont;
134   int fontindex;
135   int refcount;
136 };
137 
138 static cc_dynarray * fontarray = NULL;
139 
140 /* ********************************************************************** */
141 
142 static void
dump_cc_flw_font(const char * srcfunc,struct cc_flw_font * f)143 dump_cc_flw_font(const char * srcfunc, struct cc_flw_font * f)
144 {
145   cc_debugerror_postinfo(srcfunc,
146                          "nativefonthandle==%p, fontname=='%s', requestname=='%s', "
147                          "glyphdict==%p, sizey==%u, angle==%f, "
148                          "complexity==%f, defaultfont==%s, fontindex==%d, "
149                          "refcount==%d",
150                          f->nativefonthandle,
151                          cc_string_get_text(f->fontname),
152                          cc_string_get_text(f->requestname),
153                          f->glyphdict, f->sizey, f->angle,
154                          f->complexity,
155                          f->defaultfont ? "TRUE" : "FALSE",
156                          f->fontindex, f->refcount);
157 }
158 
159 static void
dump_cc_flw_glyph(const char * srcfunc,struct cc_flw_glyph * g)160 dump_cc_flw_glyph(const char * srcfunc, struct cc_flw_glyph * g)
161 {
162   cc_debugerror_postinfo(srcfunc,
163                          "nativeglyphidx==%u, bitmap==%p, vector==%p, "
164                          "fromdefaultfont==%s, character=='%c'",
165                          g->nativeglyphidx, g->bitmap, g->vector,
166                          g->fromdefaultfont ? "TRUE" : "FALSE",
167                          g->character);
168 }
169 
170 /* ********************************************************************** */
171 
freetype_cleanup(void)172 static void freetype_cleanup(void) { cc_flwft_exit(); }
173 
174 static SbBool
using_freetype(void)175 using_freetype(void)
176 {
177   if (!tried_init_freetype_fontlib) {
178     const char * env;
179 
180     tried_init_freetype_fontlib = TRUE;
181 
182     env = coin_getenv("COIN_FORCE_FREETYPE_OFF");
183     fontlib_freetype_available = (env && (atoi(env) > 0)) ? FALSE : TRUE;
184     fontlib_freetype_available = fontlib_freetype_available && cc_flwft_initialize();
185     if (cc_font_debug()) {
186       cc_debugerror_postinfo("using_freetype",
187                              "FreeType library will%s be used",
188                              fontlib_freetype_available ? "" : " not");
189     }
190 
191     if (fontlib_freetype_available) {
192       coin_atexit((coin_atexit_f *)freetype_cleanup,
193                   /* priority must be lower than for abstraction
194                      interface, so don't change this willy-nilly: */
195                   CC_ATEXIT_FONT_SUBSYSTEM_LOWPRIORITY);
196     }
197   }
198 
199   return fontlib_freetype_available;
200 }
201 
win32api_cleanup(void)202 static void win32api_cleanup(void) { cc_flww32_exit(); }
203 
204 static SbBool
using_win32api(void)205 using_win32api(void)
206 {
207   if (!tried_init_win32_fontlib) {
208     const char * env;
209 
210     tried_init_win32_fontlib = TRUE;
211 
212     env = coin_getenv("COIN_FORCE_WIN32FONTS_OFF");
213     fontlib_win32_available = (env && (atoi(env) > 0)) ? FALSE : TRUE;
214     fontlib_win32_available = fontlib_win32_available && cc_flww32_initialize();
215     if (cc_font_debug()) {
216       cc_debugerror_postinfo("cc_flw_initialize",
217                              "Win32 API can%s be used for font support",
218                              fontlib_win32_available ? "" : " not");
219     }
220 
221     /* Allow only one of the availability flags to be set, as it's too
222        easy to get bugs in our code in this file if we depend on
223        always checking one particular flag before the other.
224 
225        We prefer to consistently use the FreeType library over the
226        Win32 API if available -- assuming that FreeType has been
227        installed for a good reason on the Windows machine in question.
228     */
229 
230     if (fontlib_win32_available && using_freetype()) {
231       if (cc_font_debug()) {
232         cc_debugerror_postinfo("using_win32api",
233                                "FreeType library will take precedence "
234                                "over Win32 API");
235       }
236       cc_flww32_exit();
237       fontlib_win32_available = FALSE;
238     }
239 
240     if (fontlib_win32_available) {
241       coin_atexit((coin_atexit_f *)win32api_cleanup,
242                   /* priority must be lower than for abstraction
243                      interface, so don't change this willy-nilly: */
244                   CC_ATEXIT_FONT_SUBSYSTEM_LOWPRIORITY);
245     }
246   }
247 
248   return fontlib_win32_available;
249 }
250 
251 /* ********************************************************************** */
252 
253 static struct cc_font_bitmap *
get_default_bitmap(unsigned int character,float wantedsize)254 get_default_bitmap(unsigned int character, float wantedsize)
255 {
256   struct cc_font_bitmap * bm;
257 
258   if (character < 256) { /* FIXME: should this be an assert? 20050622 mortene. */
259     const int fontheight = coin_default2dfont_get_height(wantedsize);
260     unsigned char * fontdata =
261       (unsigned char *) coin_default2dfont_get_data(wantedsize);
262 
263     bm = (struct cc_font_bitmap *) malloc(sizeof(struct cc_font_bitmap));
264     bm->buffer = fontdata + fontheight * 4 * character;
265     bm->bearingX = 0;
266     bm->bearingY = fontheight;
267     bm->rows = fontheight;
268     bm->width = coin_default2dfont_get_width(wantedsize);
269     bm->pitch = 4;
270     bm->mono = 1;
271     return bm;
272   }
273   return NULL;
274 }
275 
276 static struct cc_flw_glyph *
flw_glyphidx2glyphptr(struct cc_flw_font * fs,unsigned int glyphidx)277 flw_glyphidx2glyphptr(struct cc_flw_font * fs, unsigned int glyphidx)
278 {
279   void * tmp;
280   struct cc_flw_glyph * gs = NULL;
281 
282   if (cc_dict_get(fs->glyphdict, glyphidx, &tmp)) {
283     gs = (struct cc_flw_glyph *) tmp;
284   }
285 
286   return gs;
287 }
288 
289 static void
fontstruct_rmglyph(struct cc_flw_font * fs,unsigned int glyph)290 fontstruct_rmglyph(struct cc_flw_font * fs, unsigned int glyph)
291 {
292   struct cc_flw_glyph * gs = flw_glyphidx2glyphptr(fs, glyph);
293   assert(gs);
294 
295   if (gs->bitmap) {
296     if (!gs->fromdefaultfont && gs->bitmap->buffer) { free(gs->bitmap->buffer); }
297     free(gs->bitmap);
298   }
299 
300   if (gs->vector && !gs->fromdefaultfont) {
301     free(gs->vector->vertices);
302     free(gs->vector->faceindices);
303     free(gs->vector->edgeindices);
304     free(gs->vector);
305   }
306 
307   if (!cc_dict_remove(fs->glyphdict, glyph)) {
308     assert(0 && "glyph to remove not found");
309   }
310 
311   free(gs);
312 }
313 
314 static void
fontstruct_rmglyph_apply(uintptr_t key,void * COIN_UNUSED_ARG (val),void * closure)315 fontstruct_rmglyph_apply(uintptr_t key, void * COIN_UNUSED_ARG(val), void * closure)
316 {
317   fontstruct_rmglyph((struct cc_flw_font *)closure, (unsigned int)key);
318 }
319 
320 static void
fontstruct_rmfont(int font)321 fontstruct_rmfont(int font)
322 {
323   int i, n;
324   int arrayindex;
325   struct cc_flw_font * fs = NULL;
326 
327   n = cc_dynarray_length(fontarray);
328   for (i = 0; i < n; i++) {
329     fs = (struct cc_flw_font *)cc_dynarray_get(fontarray, i);
330     if (fs->fontindex == font) break;
331   }
332   assert(i < n);
333   arrayindex = i;
334 
335   if (fs->fontname) cc_string_destruct(fs->fontname);
336   if (fs->requestname) cc_string_destruct(fs->requestname);
337 
338   cc_dict_apply(fs->glyphdict, fontstruct_rmglyph_apply, fs);
339   cc_dict_destruct(fs->glyphdict);
340   free(fs);
341   cc_dynarray_remove_idx(fontarray, arrayindex);
342 }
343 
344 static struct cc_flw_font *
flw_fontidx2fontptr(int fontidx)345 flw_fontidx2fontptr(int fontidx)
346 {
347   struct cc_flw_font * fs = NULL;
348   int i, n;
349 
350   n = (int) cc_dynarray_length(fontarray);
351   for (i = 0; i < n; i++) {
352     fs = (struct cc_flw_font *) cc_dynarray_get(fontarray, i);
353     if (fs->fontindex == fontidx) break;
354   }
355   assert(i < n);
356 
357   return fs;
358 }
359 
360 static void
flw_exit(void)361 flw_exit(void)
362 {
363   unsigned int n;
364 
365   n = cc_dynarray_length(fontarray);
366   while (n--) {
367     struct cc_flw_font * fs = (struct cc_flw_font *)cc_dynarray_get(fontarray, n);
368 
369 #if COIN_DEBUG
370     /* don't use cc_debugerror_post_* here since this will be called when Coin is
371        exiting => we cannot allocate new resources */
372     fprintf(stderr, "flw_exit: font instance resource leak:\n");
373     fprintf(stderr, "nativefonthandle==%p, fontname=='%s', requestname=='%s', "
374             "glyphdict==%p, sizey==%u, angle==%f, "
375             "complexity==%f, defaultfont==%s, fontindex==%d, "
376             "refcount==%d",
377             fs->nativefonthandle,
378             cc_string_get_text(fs->fontname),
379             cc_string_get_text(fs->requestname),
380             fs->glyphdict, fs->sizey, fs->angle,
381             fs->complexity,
382             fs->defaultfont ? "TRUE" : "FALSE",
383             fs->fontindex, fs->refcount);
384 #endif /* COIN_DEBUG */
385 
386     fontstruct_rmfont(fs->fontindex);
387   }
388 
389   cc_dynarray_destruct(fontarray);
390 
391   fontarray = NULL;
392   initialized = FALSE;
393 
394   tried_init_freetype_fontlib = tried_init_win32_fontlib = FALSE;
395   fontlib_freetype_available = fontlib_win32_available = FALSE;
396 
397   CC_MUTEX_DESTRUCT(flw_global_lock);
398   flw_global_font_index = 0;
399 }
400 
401 static void
flw_initialize(void)402 flw_initialize(void)
403 {
404   /* CC_MUTEX_CONSTRUCT uses a global mutex to be thread safe */
405   CC_MUTEX_CONSTRUCT(flw_global_lock);
406   FLW_MUTEX_LOCK(flw_global_lock);
407 
408   if (initialized) {
409     FLW_MUTEX_UNLOCK(flw_global_lock);
410     return;
411   }
412   initialized = TRUE;
413 
414   fontarray = cc_dynarray_new();
415 
416   coin_atexit((coin_atexit_f *)flw_exit,
417               /* priority must be higher than for atexit cleanup of
418                  underlying, native interfaces (so this is done
419                  first), so keep this correctly in sync with other
420                  coin_atexit() invocations in the font sub-system: */
421               CC_ATEXIT_FONT_SUBSYSTEM);
422 
423   FLW_MUTEX_UNLOCK(flw_global_lock);
424 }
425 
426 /* ********************************************************************** */
427 
428 /*
429   Returns internal index of given font specification, for subsequent
430   use as input argument to other functions as identification.
431 
432   Returns -1 if no font with the given name and size has been made
433   yet.
434 */
435 static int
flw_find_font(const char * fontname,const unsigned int sizey,const float angle,const float complexity)436 flw_find_font(const char * fontname, const unsigned int sizey,
437               const float angle, const float complexity)
438 {
439   unsigned int i, n;
440 
441   /* This function is a common entry spot for first access into the
442      wrapper (unless client code is doing something wrong, but then
443      we'll likely catch that with an assert somewhere), so we call the
444      initialization code from here.
445 
446      flw_initialize() is re-entrant, so this should be safe in a
447      multithreaded environment.
448   */
449   if (flw_global_lock == NULL) { flw_initialize(); }
450 
451   FLW_MUTEX_LOCK(flw_global_lock);
452 
453   n = cc_dynarray_length(fontarray);
454   for (i = 0; i < n; i++) {
455     struct cc_flw_font * fs = (struct cc_flw_font *)cc_dynarray_get(fontarray, i);
456     if ((fs->sizey == sizey) &&
457         (strcmp(fontname, cc_string_get_text(fs->requestname))==0) &&
458         (fs->angle == angle) &&
459         (fs->complexity == complexity)) {
460       FLW_MUTEX_UNLOCK(flw_global_lock);
461       return fs->fontindex;
462     }
463   }
464   FLW_MUTEX_UNLOCK(flw_global_lock);
465   return -1;
466 }
467 
468 
469 void
cc_flw_ref_font(int fontid)470 cc_flw_ref_font(int fontid)
471 {
472   int i, n;
473   struct cc_flw_font * fs;
474   FLW_MUTEX_LOCK(flw_global_lock);
475   n = (int) cc_dynarray_length(fontarray);
476   for (i = 0; i < n; i++) {
477     fs = (struct cc_flw_font *)cc_dynarray_get(fontarray, i);
478     if (fs->fontindex == fontid) {
479       fs->refcount++;
480       break;
481     }
482   }
483   assert(i < n);
484   FLW_MUTEX_UNLOCK(flw_global_lock);
485 }
486 
487 void
cc_flw_unref_font(int fontid)488 cc_flw_unref_font(int fontid)
489 {
490   int i, n;
491   struct cc_flw_font * fs;
492 
493   FLW_MUTEX_LOCK(flw_global_lock);
494 
495   n = (int) cc_dynarray_length(fontarray);
496   for (i = 0; i < n; i++) {
497     fs = (struct cc_flw_font *)cc_dynarray_get(fontarray, i);
498     if (fs->fontindex == fontid) {
499       fs->refcount--;
500       if (fs->refcount == 0) {
501         if (!fs->defaultfont) {
502           if (using_win32api()) { cc_flww32_done_font(fs->nativefonthandle); }
503           else if (using_freetype()) { cc_flwft_done_font(fs->nativefonthandle); }
504         }
505         fontstruct_rmfont(fontid);
506       }
507       break;
508     }
509   }
510   assert(i < n);
511 
512   FLW_MUTEX_UNLOCK(flw_global_lock);
513 }
514 
515 /*!
516   Set up an internal representation of a font from the \a fontname,
517   and returns a font id >= 0 to be used in successive calls.
518 
519   \a fontname is the name and style \e requested. The actual font
520   created will typically differ slightly, depending on what is
521   available on the run-time system.  If a font has already been
522   created for this \a fontname and size, the function will not create
523   a duplicate, but simply return that font.
524 
525   If no font could sensibly be made from the given \a fontname, the
526   internal, hard-coded default font will be used. One is therefore
527   guaranteed that this function will execute and return without
528   needing any error checking on behalf of the client code.
529 */
530 int
cc_flw_get_font_id(const char * fontname,unsigned int sizey,float angle,float complexity)531 cc_flw_get_font_id(const char * fontname, unsigned int sizey,
532                    float angle, float complexity)
533 {
534   /* FIXME: complexity (and angle, if we're keeping it) needs to be
535      clamped to single-digit precision, to make sure we don't set up
536      gazillions of fonts, for instance if end-user can change
537      SoComplexity::value with a GUI slider component. 20050624 mortene. */
538 
539   struct cc_flw_font * fs;
540   void * font;
541   int idx;
542 
543   /* Don't create font if one has already been created for this name
544      and size. */
545   idx = flw_find_font(fontname, sizey, angle, complexity);
546 
547   if (idx != -1) { return idx; }
548 
549   font = NULL;
550 
551   FLW_MUTEX_LOCK(flw_global_lock);
552 
553   /* Avoid having the underlying font import libraries try to find a
554      best match for "defaultFont" (and get a positive result for some
555      random font). */
556   if (strcmp(fontname, "defaultFont") != 0) {
557     if (using_win32api()) {
558       font = cc_flww32_get_font(fontname, sizey, angle, complexity);
559     }
560     else if (using_freetype()) {
561      font = cc_flwft_get_font(fontname, sizey);
562     }
563   }
564 
565   fs = (struct cc_flw_font *)malloc(sizeof(struct cc_flw_font));
566   fs->nativefonthandle = font;
567   fs->defaultfont = font ? FALSE : TRUE;
568   fs->complexity = complexity;
569   fs->glyphdict = cc_dict_construct(256, 0.7f);
570   fs->fontindex = flw_global_font_index++;
571   fs->refcount = 0;
572   fs->requestname = cc_string_construct_new();
573   cc_string_set_text(fs->requestname, fontname);
574   fs->fontname = cc_string_construct_new();
575   fs->sizey = sizey;
576 
577   if (font) {
578     cc_string realname;
579     cc_string_construct(&realname);
580 
581     fs->angle = angle;
582 
583     if (using_win32api()) {
584       cc_flww32_get_font_name(font, &realname);
585     }
586     else if (using_freetype()) {
587       cc_flwft_set_char_size(font, sizey);
588       cc_flwft_set_font_rotation(font, angle);
589       cc_flwft_get_font_name(font, &realname);
590     }
591     else {
592       assert(FALSE && "incomplete code path");
593     }
594 
595     cc_string_set_text(fs->fontname, cc_string_get_text(&realname));
596 
597     if (cc_font_debug()) {
598       cc_debugerror_postinfo("cc_flw_get_font",
599                              "'%s', size==%u => realname='%s'",
600                              fontname, sizey,
601                              cc_string_get_text(&realname));
602     }
603 
604     cc_string_clean(&realname);
605   }
606   else {
607     /* Using a built-in default font for the given fontname and size,
608        trying to match as close as possible to the requested size.
609     */
610     cc_string_set_text(fs->fontname, "defaultFont");
611     fs->angle = 0.0f;
612   }
613 
614   cc_dynarray_append(fontarray, fs);
615 
616   FLW_MUTEX_UNLOCK(flw_global_lock);
617   return fs->fontindex;
618 }
619 
620 /*!
621   Returns a unique glyph index for the given character.
622 */
623 unsigned int
cc_flw_get_glyph(int font,unsigned int character)624 cc_flw_get_glyph(int font, unsigned int character)
625 {
626   unsigned int glyph = 0;
627   struct cc_flw_font * fs;
628   struct cc_flw_glyph * gs;
629 
630   FLW_MUTEX_LOCK(flw_global_lock);
631 
632   fs = flw_fontidx2fontptr(font);
633 
634   /* Check if it has already been set up, and if so, just return. */
635   gs = flw_glyphidx2glyphptr(fs, character);
636 
637   /* FIXME: should this perhaps rather be an assert()? 20050623 mortene. */
638   if (gs == NULL) {
639 
640     gs = (struct cc_flw_glyph *)malloc(sizeof(struct cc_flw_glyph));
641     gs->character = character;
642     gs->bitmap = NULL;
643     gs->vector = NULL;
644     /* These will be changed below if the glyph is found in a
645        non-default font: */
646     gs->nativeglyphidx = character;
647     gs->fromdefaultfont = TRUE;
648 
649     if (!cc_dict_put(fs->glyphdict, character, gs)) {
650       assert(0 && "glyph already exists");
651     }
652 
653     if (!fs->defaultfont) {
654       if (using_win32api()) { glyph = cc_flww32_get_glyph(fs->nativefonthandle, character); }
655       else if (using_freetype()) { glyph = cc_flwft_get_glyph(fs->nativefonthandle, character); }
656 
657       if (glyph > 0) {
658         gs->nativeglyphidx = glyph;
659         gs->fromdefaultfont = FALSE;
660       }
661       else {
662         /* Create glyph from default font, mark as default. */
663 
664         /* FIXME: shouldn't it rather be handled by making an empty
665            rectangle glyph of the correct size, like it's at least done
666            for X11 (and probably other systems aswell)?
667 
668            Or perhaps this strategy _is_ better, but then we should at
669            least scale the defaultfont glyph to the correct size.
670            20030317 mortene. */
671 
672         /* Correct fix is to make an empty rectangle. Using a char from
673            the default font only gives a blank since most fonts contain
674            a superset of the chars in the default font. (The default
675            font characters being rendered was due to a bug in the
676            character mapping, causing failure to find special chars such
677            as '���'. The bug has since been fixed).  20030327 preng */
678 
679         if (cc_font_debug()) {
680           cc_debugerror_postwarning("cc_flw_get_glyph",
681                                     "no character 0x%x was found in font '%s'",
682                                     character, cc_string_get_text(fs->fontname));
683         }
684       }
685     }
686   }
687 
688   FLW_MUTEX_UNLOCK(flw_global_lock);
689 
690   /* Since we're simply using the character value as the hash key into
691      the glyph hash for the font: */
692   return character;
693 }
694 
695 void
cc_flw_get_bitmap_advance(int font,unsigned int glyph,int * x,int * y)696 cc_flw_get_bitmap_advance(int font, unsigned int glyph, int * x, int * y)
697 {
698   struct cc_flw_font * fs;
699   struct cc_flw_glyph * gs;
700 
701   FLW_MUTEX_LOCK(flw_global_lock);
702 
703   fs = flw_fontidx2fontptr(font);
704   gs = flw_glyphidx2glyphptr(fs, glyph);
705   assert(gs);
706 
707   /* the rest should be mt-safe, and we need to give up the lock,
708      since we're calling into another cc_flw_*() function (which will
709      also want to lock the mutex */
710   FLW_MUTEX_UNLOCK(flw_global_lock);
711 
712   if (gs->fromdefaultfont) {
713     /* FIXME: should be simplified, so we could just use the else{}
714        block below unconditionally. 20050623 mortene.*/
715     *x = coin_default2dfont_get_width((float)fs->sizey);
716     *y = coin_default2dfont_get_height((float)fs->sizey);
717   }
718   else {
719     struct cc_font_bitmap * bm = cc_flw_get_bitmap(font, glyph);
720     assert(bm);
721     *x = bm->advanceX;
722     *y = bm->advanceY;
723   }
724 }
725 
726 void
cc_flw_get_vector_advance(int font,unsigned int glyph,float * x,float * y)727 cc_flw_get_vector_advance(int font, unsigned int glyph, float * x, float * y)
728 {
729   struct cc_flw_font * fs;
730   struct cc_flw_glyph * gs;
731 
732   FLW_MUTEX_LOCK(flw_global_lock);
733 
734   fs = flw_fontidx2fontptr(font);
735   gs = flw_glyphidx2glyphptr(fs, glyph);
736   assert(gs);
737 
738   *x = *y = 0.0f;
739 
740   if (gs->fromdefaultfont) {
741     *x = coin_default3dfont_get_advance(gs->character);
742   }
743   else {
744     if (using_win32api()) {
745       cc_flww32_get_vector_advance(fs->nativefonthandle, gs->nativeglyphidx,
746                                    x, y);
747     }
748     else if (using_freetype()) {
749       cc_flwft_get_vector_advance(fs->nativefonthandle, gs->nativeglyphidx,
750                                   x, y);
751     }
752   }
753 
754   FLW_MUTEX_UNLOCK(flw_global_lock);
755 }
756 
757 void
cc_flw_get_bitmap_kerning(int font,unsigned int glyph1,unsigned int glyph2,int * x,int * y)758 cc_flw_get_bitmap_kerning(int font, unsigned int glyph1, unsigned int glyph2,
759                           int * x, int * y)
760 {
761   struct cc_flw_font * fs;
762   struct cc_flw_glyph * gs1, * gs2;
763 
764   FLW_MUTEX_LOCK(flw_global_lock);
765 
766   *x = *y = 0;
767 
768   fs = flw_fontidx2fontptr(font);
769 
770   if (!fs->defaultfont) {
771     gs1 = flw_glyphidx2glyphptr(fs, glyph1);
772     gs2 = flw_glyphidx2glyphptr(fs, glyph2);
773     assert(gs1 && gs2);
774     if (using_win32api()) {
775       cc_flww32_get_bitmap_kerning(fs->nativefonthandle,
776                                    gs1->nativeglyphidx,
777                                    gs2->nativeglyphidx, x, y);
778     }
779     else if (using_freetype()) {
780       cc_flwft_get_bitmap_kerning(fs->nativefonthandle,
781                                   gs1->nativeglyphidx,
782                                   gs2->nativeglyphidx, x, y);
783     }
784   }
785 
786   FLW_MUTEX_UNLOCK(flw_global_lock);
787 }
788 
789 
790 void
cc_flw_get_vector_kerning(int font,unsigned int glyph1,unsigned int glyph2,float * x,float * y)791 cc_flw_get_vector_kerning(int font, unsigned int glyph1, unsigned int glyph2,
792                           float * x, float * y)
793 {
794   struct cc_flw_font * fs;
795   struct cc_flw_glyph * gs1, * gs2;
796 
797   FLW_MUTEX_LOCK(flw_global_lock);
798 
799   fs = flw_fontidx2fontptr(font);
800   gs1 = flw_glyphidx2glyphptr(fs, glyph1);
801   gs2 = flw_glyphidx2glyphptr(fs, glyph2);
802   assert(gs1 && gs2);
803 
804   *x = *y = 0.0f;
805 
806   if (!fs->defaultfont) {
807     if (using_win32api()) {
808       cc_flww32_get_vector_kerning(fs->nativefonthandle,
809                                    gs1->nativeglyphidx,
810                                    gs2->nativeglyphidx, x, y);
811     }
812     else if (using_freetype()) {
813       cc_flwft_get_vector_kerning(fs->nativefonthandle,
814                                   gs1->nativeglyphidx,
815                                   gs2->nativeglyphidx, x, y);
816     }
817   }
818 
819   FLW_MUTEX_UNLOCK(flw_global_lock);
820 }
821 
822 void
cc_flw_done_glyph(int fontidx,unsigned int glyphidx)823 cc_flw_done_glyph(int fontidx, unsigned int glyphidx)
824 {
825   struct cc_flw_font * fs;
826   struct cc_flw_glyph * gs;
827 
828   FLW_MUTEX_LOCK(flw_global_lock);
829 
830   fs = flw_fontidx2fontptr(fontidx);
831   assert(fs);
832 
833   if (cc_font_debug()) { dump_cc_flw_font("cc_flw_done_glyph", fs); }
834 
835   gs = flw_glyphidx2glyphptr(fs, glyphidx);
836   assert(gs);
837 
838   if (cc_font_debug()) { dump_cc_flw_glyph("cc_flw_done_glyph", gs); }
839 
840   if (!gs->fromdefaultfont) {
841     if (using_win32api()) {
842       cc_flww32_done_glyph(fs->nativefonthandle, gs->nativeglyphidx);
843     }
844     else if (using_freetype()) {
845       cc_flwft_done_glyph(fs->nativefonthandle, gs->nativeglyphidx);
846     }
847   }
848 
849   fontstruct_rmglyph(fs, glyphidx);
850 
851   FLW_MUTEX_UNLOCK(flw_global_lock);
852 }
853 
854 struct cc_font_bitmap *
cc_flw_get_bitmap(int font,unsigned int glyph)855 cc_flw_get_bitmap(int font, unsigned int glyph)
856 {
857   unsigned char * buf;
858   struct cc_flw_font * fs;
859   struct cc_flw_glyph * gs;
860   struct cc_font_bitmap * bm = NULL;
861   unsigned int i;
862 
863   FLW_MUTEX_LOCK(flw_global_lock);
864 
865   fs = flw_fontidx2fontptr(font);
866   gs = flw_glyphidx2glyphptr(fs, glyph);
867   assert(gs);
868 
869   if (gs->bitmap == NULL) {
870 
871     if (!gs->fromdefaultfont) {
872       if (using_win32api()) {
873         bm = cc_flww32_get_bitmap(fs->nativefonthandle, gs->nativeglyphidx);
874       }
875       else if (using_freetype()) {
876         bm = cc_flwft_get_bitmap(fs->nativefonthandle, gs->nativeglyphidx);
877       }
878     }
879 
880     if (!bm) {
881       /* glyph handle == char value in default font. &255 to avoid
882          index out of range. */
883       bm = get_default_bitmap(gs->nativeglyphidx & 0xff, (float)fs->sizey);
884     }
885     else if (bm && bm->buffer) {
886       buf = (unsigned char *)malloc(bm->pitch * bm->rows);
887       /* Copy & reverse buffer to OpenGL "up" direction. */
888       for (i = 0; i < bm->rows; i++) {
889         (void)memcpy(buf + i*bm->pitch,
890                      bm->buffer + (bm->rows-i-1) * bm->pitch,
891                      bm->pitch);
892       }
893       free(bm->buffer);
894       bm->buffer = buf;
895     }
896 
897     gs->bitmap = bm;
898   }
899 
900   FLW_MUTEX_UNLOCK(flw_global_lock);
901 
902   return gs->bitmap;
903 }
904 
905 struct cc_font_vector_glyph *
cc_flw_get_vector_glyph(int font,unsigned int glyph)906 cc_flw_get_vector_glyph(int font, unsigned int glyph)
907 {
908   struct cc_flw_font * fs;
909   struct cc_flw_glyph * gs;
910 
911   FLW_MUTEX_LOCK(flw_global_lock);
912 
913   fs = flw_fontidx2fontptr(font);
914   gs = flw_glyphidx2glyphptr(fs, glyph);
915   assert(gs);
916 
917   if (gs->vector == NULL && !gs->fromdefaultfont) {
918     struct cc_font_vector_glyph * vector_glyph = NULL;
919 
920     if (using_freetype()) {
921       vector_glyph = cc_flwft_get_vector_glyph(fs->nativefonthandle,
922                                                gs->nativeglyphidx,
923                                                fs->complexity);
924       if (!vector_glyph) { gs->fromdefaultfont = TRUE; }
925     }
926     else if (using_win32api()) {
927       vector_glyph = cc_flww32_get_vector_glyph(fs->nativefonthandle,
928                                                 gs->nativeglyphidx,
929                                                 fs->complexity);
930       if (!vector_glyph) { gs->fromdefaultfont = TRUE; }
931     }
932 
933     gs->vector = vector_glyph;
934   }
935 
936   FLW_MUTEX_UNLOCK(flw_global_lock);
937 
938   return gs->vector;
939 }
940 
941 const float *
cc_flw_get_vector_glyph_coords(struct cc_font_vector_glyph * vecglyph)942 cc_flw_get_vector_glyph_coords(struct cc_font_vector_glyph * vecglyph)
943 {
944   assert(vecglyph);
945   assert(vecglyph->vertices);
946 
947   return vecglyph->vertices;
948 }
949 
950 const int *
cc_flw_get_vector_glyph_faceidx(struct cc_font_vector_glyph * vecglyph)951 cc_flw_get_vector_glyph_faceidx(struct cc_font_vector_glyph * vecglyph)
952 {
953   assert(vecglyph);
954   assert(vecglyph->faceindices);
955 
956   return vecglyph->faceindices;
957 }
958 
959 const int *
cc_flw_get_vector_glyph_edgeidx(struct cc_font_vector_glyph * vecglyph)960 cc_flw_get_vector_glyph_edgeidx(struct cc_font_vector_glyph * vecglyph)
961 {
962   assert(vecglyph);
963   assert(vecglyph->edgeindices);
964 
965   return vecglyph->edgeindices;
966 }
967 
968 #undef FLW_MUTEX_LOCK
969 #undef FLW_MUTEX_UNLOCK
970