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