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