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