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 #include "fonts/glyph3d.h"
34
35 #include <cfloat> /* FLT_MIN */
36 #include <cstring>
37 #include <cassert>
38 #include <cstdio>
39
40 #include <Inventor/C/basic.h>
41 #include <Inventor/C/base/list.h>
42 #include <Inventor/C/base/string.h>
43
44 #include "tidbitsp.h"
45 #include "base/dict.h"
46 #include "threads/threadsutilp.h"
47 #include "fonts/fontlib_wrapper.h"
48 #include "fonts/glyph.h"
49 #include "fonts/defaultfonts.h"
50 #include "coindefs.h"
51
52 #ifndef COIN_WORKAROUND_NO_USING_STD_FUNCS
53 using namespace std;
54 #endif // !COIN_WORKAROUND_NO_USING_STD_FUNCS
55
56 /* ********************************************************************** */
57
58 static SbBool glyph3d_specmatch(const cc_font_specification * spec1,
59 const cc_font_specification * spec2);
60 static void glyph3d_calcboundingbox(cc_glyph3d * g);
61
62 struct cc_glyph3d {
63 struct cc_glyph c; /* "c" for "common" glyph data (2d & 3d). */
64
65 float width; /* FIXME: is this one really in use? 20060109 mortene. */
66 float bbox[4];
67 struct cc_font_vector_glyph * vectorglyph;
68 SbBool didallocvectorglyph;
69 };
70
71 /* ********************************************************************** */
72
73 static cc_dict * glyph3d_fonthash = NULL;
74 static int glyph3d_spaceglyphindices[] = { -1, -1 };
75 static float glyph3d_spaceglyphvertices[] = { 0, 0 };
76 static SbBool glyph3d_initialized = FALSE;
77
78 /* Mutex lock for the static ang global font hash */
79 static void * glyph3d_fonthash_lock = NULL;
80
81 /* Because the 3D glyphs are normalized when generated, a standard
82 fontsize is used for all glyphs. This also prevent Windows from
83 quantizing advancement and kerning values for very small fontsizes
84 (size<4).
85 */
86 static unsigned int glyph3d_standardfontsize = 50;
87
88 /* ********************************************************************** */
89
90 /* Set '#if 1' to enable debug info to stderr when tracking mutex locking. */
91 #if 0
92 #define GLYPH3D_MUTEX_LOCK(m) \
93 do { \
94 (void)fprintf(stderr, "glyph3d mutex lock in %s\n", __func__); \
95 CC_MUTEX_LOCK(m); \
96 } while (0)
97 #define GLYPH3D_MUTEX_UNLOCK(m) \
98 do { \
99 (void)fprintf(stderr, "glyph3d mutex unlock in %s\n", __func__); \
100 CC_MUTEX_UNLOCK(m); \
101 } while (0)
102 #else
103 #define GLYPH3D_MUTEX_LOCK(m) CC_MUTEX_LOCK(m)
104 #define GLYPH3D_MUTEX_UNLOCK(m) CC_MUTEX_UNLOCK(m)
105 #endif
106
107 static void
cc_glyph3d_cleanup(void)108 cc_glyph3d_cleanup(void)
109 {
110 CC_MUTEX_DESTRUCT(glyph3d_fonthash_lock);
111 cc_dict_destruct(glyph3d_fonthash);
112 glyph3d_fonthash = NULL;
113 glyph3d_initialized = FALSE;
114 }
115
116 static void
cc_glyph3d_initialize()117 cc_glyph3d_initialize()
118 {
119 CC_MUTEX_CONSTRUCT(glyph3d_fonthash_lock);
120 GLYPH3D_MUTEX_LOCK(glyph3d_fonthash_lock);
121
122 if (glyph3d_initialized) {
123 GLYPH3D_MUTEX_UNLOCK(glyph3d_fonthash_lock);
124 return;
125 }
126 glyph3d_initialized = TRUE;
127
128 glyph3d_fonthash = cc_dict_construct(15, 0.75);
129
130 /* +1, so it happens before the underlying font abstraction layer
131 cleans itself up: */
132 coin_atexit((coin_atexit_f*) cc_glyph3d_cleanup, CC_ATEXIT_FONT_SUBSYSTEM_HIGHPRIORITY);
133
134 GLYPH3D_MUTEX_UNLOCK(glyph3d_fonthash_lock);
135 }
136
137 cc_glyph3d *
cc_glyph3d_ref(uint32_t character,const cc_font_specification * spec)138 cc_glyph3d_ref(uint32_t character, const cc_font_specification * spec)
139 {
140 cc_glyph3d * glyph;
141 int glyphidx;
142 int fontidx;
143 void * val;
144 cc_font_specification * newspec;
145 cc_string * fonttoload;
146 cc_list * glyphlist = NULL;
147
148 /* Beacuse this function is the entry point for glyph3d, the mutex
149 is initialized here. */
150 if (glyph3d_fonthash_lock == NULL)
151 cc_glyph3d_initialize();
152
153 assert(spec);
154
155 GLYPH3D_MUTEX_LOCK(glyph3d_fonthash_lock);
156
157 /* Has the glyph been created before? */
158 if (cc_dict_get(glyph3d_fonthash, (uintptr_t)character, &val)) {
159 int i;
160 glyphlist = (cc_list *) val;
161 for (i=0;i<cc_list_get_length(glyphlist);++i) {
162 glyph = (cc_glyph3d *) cc_list_get(glyphlist, i);
163 if (glyph3d_specmatch(spec, glyph->c.fontspec)) {
164 GLYPH3D_MUTEX_UNLOCK(glyph3d_fonthash_lock);
165 glyph->c.refcount++;
166 return glyph;
167 }
168 }
169 } else {
170 /* No glyphlist for this character is found. Create one and
171 add it to the hashtable. */
172 glyphlist = cc_list_construct();
173 cc_dict_put(glyph3d_fonthash, (uintptr_t)character, glyphlist);
174 }
175
176 assert(glyphlist);
177
178 /* build a new glyph struct */
179 glyph = (cc_glyph3d *) malloc(sizeof(cc_glyph3d));
180
181 glyph->c.character = character;
182 glyph->c.refcount = 1;
183
184
185 newspec = (cc_font_specification *) malloc(sizeof(cc_font_specification));
186 assert(newspec);
187 cc_fontspec_copy(spec, newspec);
188
189 glyph->c.fontspec = newspec;
190
191 /* FIXME: fonttoload variable should be allocated on the
192 stack. 20030921 mortene. */
193 fonttoload = cc_string_construct_new();
194 cc_string_set_text(fonttoload, cc_string_get_text(&spec->name));
195 if (cc_string_length(&spec->style) > 0) {
196 cc_string_append_text(fonttoload, " ");
197 cc_string_append_string(fonttoload, &spec->style);
198 }
199
200 fontidx = cc_flw_get_font_id(cc_string_get_text(fonttoload),
201 glyph3d_standardfontsize,
202 0.0f,
203 newspec->complexity);
204
205 cc_string_destruct(fonttoload);
206 assert(fontidx >= 0);
207
208 cc_flw_ref_font(fontidx);
209
210 glyphidx = cc_flw_get_glyph(fontidx, character);
211
212 /* Should _always_ be able to get hold of a glyph -- if no glyph is
213 available for a specific character, a default empty rectangle
214 should be used. -mortene. */
215 assert(glyphidx >= 0);
216
217 glyph->c.glyphidx = glyphidx;
218 glyph->c.fontidx = fontidx;
219 glyph->didallocvectorglyph = FALSE;
220
221 glyph->vectorglyph = cc_flw_get_vector_glyph(fontidx, glyphidx);
222
223 /* Setup builtin default font if no character was found */
224 /* FIXME: this should be moved to fontlib_wrapper.c. 20050623 mortene. */
225 if (glyph->vectorglyph == NULL) {
226 glyph->vectorglyph = (struct cc_font_vector_glyph *) malloc(sizeof(struct cc_font_vector_glyph));
227 glyph->didallocvectorglyph = TRUE;
228
229 if (character <= 32 || character >= 127) {
230
231 /* FIXME: Characters other than space, should be replaced with
232 squares. (20030910 handegar) */
233
234 /* treat all these characters as spaces*/
235 glyph->vectorglyph->vertices = (float *) glyph3d_spaceglyphvertices;
236 glyph->vectorglyph->faceindices = (int *) glyph3d_spaceglyphindices;
237 glyph->vectorglyph->edgeindices = (int *) glyph3d_spaceglyphindices;
238 }
239 else {
240 glyph->vectorglyph->vertices = (float *) coin_default3dfont_get_coords()[character-33];
241 glyph->vectorglyph->faceindices = (int *) coin_default3dfont_get_faceidx()[character-33];
242 glyph->vectorglyph->edgeindices = (int *) coin_default3dfont_get_edgeidx()[character-33];
243 }
244 }
245
246 glyph3d_calcboundingbox(glyph);
247 glyph->width = glyph->bbox[2] - glyph->bbox[0];
248
249 /* Store newly created glyph in the list for this character */
250 cc_list_append(glyphlist, glyph);
251
252 GLYPH3D_MUTEX_UNLOCK(glyph3d_fonthash_lock);
253 return glyph;
254 }
255
256 static void
finalize_glyph3d(cc_glyph * g)257 finalize_glyph3d(cc_glyph * g)
258 {
259 cc_glyph3d * g3d = (cc_glyph3d *)g;
260 if (g3d->didallocvectorglyph) { free(g3d->vectorglyph); }
261 }
262
263 void
cc_glyph3d_unref(cc_glyph3d * glyph)264 cc_glyph3d_unref(cc_glyph3d * glyph)
265 {
266 cc_glyph_unref(glyph3d_fonthash, &(glyph->c), finalize_glyph3d);
267 }
268
269 const float *
cc_glyph3d_getcoords(const cc_glyph3d * g)270 cc_glyph3d_getcoords(const cc_glyph3d * g)
271 {
272 const float * ptr = cc_flw_get_vector_glyph_coords(g->vectorglyph);
273 if (ptr == NULL) {
274 assert(g->vectorglyph->vertices && "Default vertices has not been initialized as expected!");
275 return g->vectorglyph->vertices;
276 }
277 return ptr;
278 }
279
280 const int *
cc_glyph3d_getfaceindices(const cc_glyph3d * g)281 cc_glyph3d_getfaceindices(const cc_glyph3d * g)
282 {
283 const int * ptr = cc_flw_get_vector_glyph_faceidx(g->vectorglyph);
284 if (ptr == NULL) {
285 assert(g->vectorglyph->faceindices && "Default face indices has not been initialized as expected!");
286 return g->vectorglyph->faceindices;
287 }
288 return ptr;
289 }
290
291 const int *
cc_glyph3d_getedgeindices(const cc_glyph3d * g)292 cc_glyph3d_getedgeindices(const cc_glyph3d * g)
293 {
294 const int * ptr = cc_flw_get_vector_glyph_edgeidx(g->vectorglyph);
295 if (ptr == NULL) {
296 assert(g->vectorglyph->edgeindices && "Default edge indices has not been initialized as expected!");
297 return g->vectorglyph->edgeindices;
298 }
299 return ptr;
300 }
301
302 const int *
cc_glyph3d_getnextcwedge(const cc_glyph3d * g,int edgeidx)303 cc_glyph3d_getnextcwedge(const cc_glyph3d * g, int edgeidx)
304 {
305
306 int findidx;
307 const int * ptr;
308 const int * edgeptr;
309 int idx = edgeidx * 2;
310
311 edgeptr = cc_glyph3d_getedgeindices(g);
312
313 /* test for common case */
314 if (edgeidx > 0) {
315 if (edgeptr[idx] == edgeptr[idx-1])
316 return &edgeptr[idx-2];
317 }
318 /* do a linear search */
319 findidx = edgeptr[idx];
320 ptr = edgeptr;
321 while (*ptr >= 0) {
322 if (ptr[1] == findidx) return ptr;
323 ptr += 2;
324 }
325
326 return NULL;
327 }
328
329 const int *
cc_glyph3d_getnextccwedge(const cc_glyph3d * g,int edgeidx)330 cc_glyph3d_getnextccwedge(const cc_glyph3d * g, int edgeidx)
331 {
332 int findidx;
333 const int * ptr;
334 const int * edgeptr;
335 int idx = edgeidx * 2;
336
337 edgeptr = cc_glyph3d_getedgeindices(g);
338
339 /* test for common case */
340 if (edgeptr[idx+1] == edgeptr[idx+2])
341 return &edgeptr[idx+2];
342
343 /* do a linear search */
344 findidx = edgeptr[idx+1];
345 ptr = edgeptr;
346 while (*ptr >= 0) {
347 if (*ptr == findidx)
348 return ptr;
349 ptr += 2;
350 }
351
352 return NULL;
353
354 }
355
356
357 float
cc_glyph3d_getwidth(const cc_glyph3d * g)358 cc_glyph3d_getwidth(const cc_glyph3d * g)
359 {
360 assert(g && "Parameter cc_glyph3d == NULL!");
361 return g->width;
362 }
363
364 static void
glyph3d_calcboundingbox(cc_glyph3d * g)365 glyph3d_calcboundingbox(cc_glyph3d * g)
366 {
367 float * coordptr;
368 int * edgeptr;
369
370 g->bbox[0] = 0.0f;
371 g->bbox[1] = 0.0f;
372 g->bbox[2] = 0.0f;
373 g->bbox[3] = 0.0f;
374
375 coordptr = (float *) cc_glyph3d_getcoords(g);
376 edgeptr = (int *) cc_glyph3d_getedgeindices(g);
377
378 while ((*edgeptr >= 0) && (*edgeptr != -1)) {
379
380 g->bbox[0] = cc_min(coordptr[(*edgeptr)*2], g->bbox[0]);
381 g->bbox[1] = cc_min(coordptr[(*edgeptr)*2 + 1], g->bbox[1]);
382 g->bbox[2] = cc_max(coordptr[(*edgeptr)*2], g->bbox[2]);
383 g->bbox[3] = cc_max(coordptr[(*edgeptr)*2 + 1], g->bbox[3]);
384
385 edgeptr++;
386 }
387
388 }
389
390 const float *
cc_glyph3d_getboundingbox(const cc_glyph3d * g)391 cc_glyph3d_getboundingbox(const cc_glyph3d * g)
392 {
393 return g->bbox;
394 }
395
396 void
cc_glyph3d_getadvance(const cc_glyph3d * g,float * x,float * y)397 cc_glyph3d_getadvance(const cc_glyph3d * g, float * x, float * y)
398 {
399 cc_flw_get_vector_advance(g->c.fontidx, g->c.glyphidx, x, y);
400 }
401
402 void
cc_glyph3d_getkerning(const cc_glyph3d * left,const cc_glyph3d * right,float * x,float * y)403 cc_glyph3d_getkerning(const cc_glyph3d * left, const cc_glyph3d * right,
404 float * x, float * y)
405 {
406 cc_flw_get_vector_kerning(right->c.fontidx, left->c.glyphidx, right->c.glyphidx, x, y);
407 }
408
409 static SbBool
glyph3d_specmatch(const cc_font_specification * spec1,const cc_font_specification * spec2)410 glyph3d_specmatch(const cc_font_specification * spec1,
411 const cc_font_specification * spec2)
412 {
413 float c1, c2;
414 int temp1,temp2;
415
416 assert(spec1);
417 assert(spec2);
418
419 /* Reducing precision of the complexity variable. This is done to
420 prevent the user from flooding the memory with generated glyphs
421 which might be more or less identical */
422 c1 = spec1->complexity;
423 c2 = spec2->complexity;
424
425 /* Clamp values to [0...1] */
426 if (c1 > 1.0f) c1 = 1.0f;
427 if (c1 < 0.0f) c1 = 0.0f;
428 if (c2 > 1.0f) c2 = 1.0f;
429 if (c2 < 0.0f) c2 = 0.0f;
430
431 temp1 = (int) (c1 * 10.0f);
432 temp2 = (int) (c2 * 10.0f);
433
434 if ((!cc_string_compare(&spec1->name, &spec2->name)) &&
435 (!cc_string_compare(&spec1->style, &spec2->style)) &&
436 (temp1 == temp2)) {
437 /* No need to compare size for 3D fonts */
438 return TRUE;
439 }
440
441 return FALSE;
442 }
443
444 #undef GLYPH3D_MUTEX_LOCK
445 #undef GLYPH3D_MUTEX_UNLOCK
446