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/fontlib_wrapper.h"
34 
35 #include <cstring>
36 #include <cassert>
37 #include <cstdio>
38 
39 #include <Inventor/C/base/string.h>
40 
41 #include "base/dict.h"
42 #include "threads/threadsutilp.h"
43 #include "tidbitsp.h"
44 #include "fonts/glyph2d.h"
45 #include "fonts/glyph.h"
46 #include "coindefs.h"
47 
48 #ifndef COIN_WORKAROUND_NO_USING_STD_FUNCS
49 using namespace std;
50 #endif // !COIN_WORKAROUND_NO_USING_STD_FUNCS
51 
52 static SbBool glyph2d_specmatch(const cc_font_specification * spec1, const cc_font_specification * spec2);
53 
54 struct cc_glyph2d {
55   struct cc_glyph c; /* "c" for "common" glyph data (2d & 3d). */
56 
57   float angle; /* FIXME: is this one really in use? 20060109 mortene. */
58   unsigned short width; /* FIXME: is this one really in use? 20060109 mortene. */
59 
60   unsigned short height;
61   unsigned short bitmapwidth;
62   unsigned short bitmapheight;
63   short bitmapoffsetx;
64   short bitmapoffsety;
65   unsigned char * bitmap;
66   SbBool mono;
67 };
68 
69 static cc_dict * glyph2d_fonthash = NULL;
70 static SbBool glyph2d_initialized = FALSE;
71 
72 /*
73   Mutex lock for the static ang global font hash
74 */
75 static void * glyph2d_fonthash_lock = NULL;
76 
77 /* Set '#if 1' to enable debug output to stderr for tracking mutex locking. */
78 #if 0
79 #define GLYPH2D_MUTEX_LOCK(m) \
80   do { \
81     (void)fprintf(stderr, "glyph2d mutex lock in %s\n", __func__); \
82     CC_MUTEX_LOCK(m); \
83   } while (0)
84 #define GLYPH2D_MUTEX_UNLOCK(m) \
85   do { \
86     (void)fprintf(stderr, "glyph2d mutex unlock in %s\n", __func__); \
87     CC_MUTEX_UNLOCK(m); \
88   } while (0)
89 #else
90 #define GLYPH2D_MUTEX_LOCK(m) CC_MUTEX_LOCK(m)
91 #define GLYPH2D_MUTEX_UNLOCK(m) CC_MUTEX_UNLOCK(m)
92 #endif
93 
94 static void
cc_glyph2d_cleanup(void)95 cc_glyph2d_cleanup(void)
96 {
97   CC_MUTEX_DESTRUCT(glyph2d_fonthash_lock);
98   cc_dict_destruct(glyph2d_fonthash);
99   glyph2d_fonthash = NULL;
100   glyph2d_initialized = FALSE;
101 }
102 
103 static void
cc_glyph2d_initialize()104 cc_glyph2d_initialize()
105 {
106   CC_MUTEX_CONSTRUCT(glyph2d_fonthash_lock);
107   GLYPH2D_MUTEX_LOCK(glyph2d_fonthash_lock);
108 
109   if (glyph2d_initialized) {
110     GLYPH2D_MUTEX_UNLOCK(glyph2d_fonthash_lock);
111     return;
112   }
113   glyph2d_initialized = TRUE;
114 
115   glyph2d_fonthash = cc_dict_construct(15, 0.75);
116 
117   /* +1, so it happens before the underlying font abstraction layer
118      cleans itself up: */
119   coin_atexit((coin_atexit_f*) cc_glyph2d_cleanup, CC_ATEXIT_FONT_SUBSYSTEM_HIGHPRIORITY);
120 
121   GLYPH2D_MUTEX_UNLOCK(glyph2d_fonthash_lock);
122 }
123 
124 cc_glyph2d *
cc_glyph2d_ref(uint32_t character,const cc_font_specification * spec,float angle)125 cc_glyph2d_ref(uint32_t character, const cc_font_specification * spec, float angle)
126 {
127   void * val;
128   cc_glyph2d * glyph;
129   int fontidx;
130   int glyphidx;
131   int i;
132   struct cc_font_bitmap * bm;
133   cc_font_specification * newspec;
134   cc_string * fonttoload;
135   cc_list * glyphlist;
136 
137 
138   /* Beacuse this function is the entry point for glyph2d, the mutex
139      is initialized here. */
140   if (glyph2d_fonthash_lock == NULL)
141     cc_glyph2d_initialize();
142 
143   assert(spec);
144 
145   GLYPH2D_MUTEX_LOCK(glyph2d_fonthash_lock);
146 
147   /* Has the glyph been created before? */
148   if (cc_dict_get(glyph2d_fonthash, (uintptr_t)character, &val)) {
149     glyphlist = (cc_list *) val;
150     for (i = 0; i < cc_list_get_length(glyphlist); ++i) {
151       glyph = (cc_glyph2d *) cc_list_get(glyphlist, i);
152       if (glyph2d_specmatch(spec, glyph->c.fontspec)) {
153         GLYPH2D_MUTEX_UNLOCK(glyph2d_fonthash_lock);
154         glyph->c.refcount++;
155         return glyph;
156       }
157     }
158   }
159   else {
160     /* No glyphlist for this character is found. Create one and
161        add it to the hashtable. */
162     glyphlist = cc_list_construct();
163     cc_dict_put(glyph2d_fonthash, (uintptr_t)character, glyphlist);
164   }
165 
166   assert(glyphlist);
167 
168   /* build a new glyph struct with bitmap */
169   glyph = (cc_glyph2d *) malloc(sizeof(cc_glyph2d));
170   glyph->c.character = character;
171 
172   newspec = (cc_font_specification *) malloc(sizeof(cc_font_specification));
173   assert(newspec);
174   cc_fontspec_copy(spec, newspec);
175 
176   glyph->c.fontspec = newspec;
177 
178   /* FIXME: fonttoload variable should be allocated on the
179      stack. 20030921 mortene. */
180   fonttoload = cc_string_construct_new();
181   cc_string_set_text(fonttoload, cc_string_get_text(&spec->name));
182   if (cc_string_length(&spec->style) > 0) {
183     cc_string_append_text(fonttoload, " ");
184     cc_string_append_string(fonttoload, &spec->style);
185   }
186 
187   /* FIXME: get rid of angle -- not used. 20050516 mortene. */
188   fontidx =
189     cc_flw_get_font_id(cc_string_get_text(fonttoload),
190                        (unsigned int)(newspec->size), angle,
191                        /* FIXME: passing in -1 for complexity below is
192                           necessary because the Win32 API code in
193                           win32.c cc_flww32_get_font() detects this
194                           and uses this as a hack to *not* change the
195                           font size. (Changing the font size is
196                           necessary for *3D* fonts because otherwise
197                           the resolution will be too low for
198                           vectorization.)
199 
200                           What an ugly mess. Should be cleaned up
201                           properly -- the worst offender against any
202                           good design taste is the code in
203                           win32.c. 20050706 mortene.*/
204                        -1.0f);
205 
206   cc_string_destruct(fonttoload);
207   assert(fontidx >= 0);
208 
209   cc_flw_ref_font(fontidx);
210 
211   /* Should _always_ be able to get hold of a glyph -- if no glyph is
212      available for a specific character, a default empty rectangle
213      should be used.  -mortene. */
214   glyphidx = cc_flw_get_glyph(fontidx, character);
215   assert(glyphidx >= 0);
216 
217   glyph->c.glyphidx = glyphidx;
218   glyph->c.fontidx = fontidx;
219   glyph->angle = angle;
220 
221   bm = cc_flw_get_bitmap(fontidx, glyphidx);
222   assert(bm);
223   glyph->width = bm->width;
224   glyph->height = bm->rows;
225   glyph->bitmapwidth = bm->mono ? bm->pitch * 8 : bm->pitch;
226   glyph->bitmapheight = bm->rows;
227   glyph->bitmapoffsetx = bm->bearingX;
228   glyph->bitmapoffsety = bm->bearingY;
229   glyph->bitmap = bm->buffer;
230   glyph->mono = bm->mono;
231   glyph->c.refcount = 1;
232 
233   /* Store newly created glyph in the list for this character */
234   cc_list_append(glyphlist, glyph);
235 
236   GLYPH2D_MUTEX_UNLOCK(glyph2d_fonthash_lock);
237   return glyph;
238 }
239 
240 void
cc_glyph2d_unref(cc_glyph2d * glyph)241 cc_glyph2d_unref(cc_glyph2d * glyph)
242 {
243   cc_glyph_unref(glyph2d_fonthash, &(glyph->c), NULL);
244 }
245 
246 static SbBool
glyph2d_specmatch(const cc_font_specification * spec1,const cc_font_specification * spec2)247 glyph2d_specmatch(const cc_font_specification * spec1,
248                   const cc_font_specification * spec2)
249 {
250   assert(spec1);
251   assert(spec2);
252 
253   if ((!cc_string_compare(&spec1->name, &spec2->name)) &&
254       (!cc_string_compare(&spec1->style, &spec2->style)) &&
255       (int(spec1->size) == int(spec2->size))) {
256     /* No need to compare complexity for 2D fonts */
257     return TRUE;
258   }
259   else return FALSE;
260 
261 }
262 
263 void
cc_glyph2d_getadvance(const cc_glyph2d * g,int * x,int * y)264 cc_glyph2d_getadvance(const cc_glyph2d * g, int * x, int * y)
265 {
266   cc_flw_get_bitmap_advance(g->c.fontidx, g->c.glyphidx, x, y);
267 }
268 
269 void
cc_glyph2d_getkerning(const cc_glyph2d * left,const cc_glyph2d * right,int * x,int * y)270 cc_glyph2d_getkerning(const cc_glyph2d * left, const cc_glyph2d * right, int * x, int * y)
271 {
272   cc_flw_get_bitmap_kerning(right->c.fontidx, left->c.glyphidx, right->c.glyphidx, x, y);
273 }
274 
275 unsigned int
cc_glyph2d_getwidth(const cc_glyph2d * g)276 cc_glyph2d_getwidth(const cc_glyph2d * g)
277 {
278   return (int) g->width;
279 }
280 
281 const unsigned char *
cc_glyph2d_getbitmap(const cc_glyph2d * g,int * size,int * offset)282 cc_glyph2d_getbitmap(const cc_glyph2d * g, int * size, int * offset)
283 {
284   size[0] = g->bitmapwidth;
285   size[1] = g->bitmapheight;
286   offset[0] = g->bitmapoffsetx;
287   offset[1] = g->bitmapoffsety;
288 
289   return g->bitmap;
290 }
291 
292 SbBool
cc_glyph2d_getmono(const cc_glyph2d * g)293 cc_glyph2d_getmono(const cc_glyph2d * g)
294 {
295   return g->mono;
296 }
297 
298 #undef GLYPH2D_MUTEX_LOCK
299 #undef GLYPH2D_MUTEX_UNLOCK
300