1 /* QuesoGLC
2 * A free implementation of the OpenGL Character Renderer (GLC)
3 * Copyright (c) 2002, 2004-2008, Bertrand Coconnier
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 /* $Id: ocharmap.c 800 2008-06-04 21:47:50Z bcoconni $ */
20
21 /** \file
22 * defines the object __GLCcharMap which manage the charmaps of both the fonts
23 * and the masters. One of the purpose of this object is to encapsulate the
24 * FcCharSet structure from Fontconfig and to add it some more functionalities.
25 * It also allows to centralize the character map management for easier
26 * maintenance.
27 */
28
29 #include "internal.h"
30
31
32
33 /* Constructor of the object : it allocates memory and initializes the member
34 * of the new object.
35 * The user must give the FcPattern of the font or the master (which may be NULL
36 * in which case the character map will be empty).
37 */
__glcCharMapCreate(__GLCmaster * inMaster,__GLCcontext * inContext)38 __GLCcharMap* __glcCharMapCreate(__GLCmaster* inMaster, __GLCcontext* inContext)
39 {
40 __GLCcharMap* This = NULL;
41
42 This = (__GLCcharMap*)__glcMalloc(sizeof(__GLCcharMap));
43 if (!This) {
44 __glcRaiseError(GLC_RESOURCE_ERROR);
45 return NULL;
46 }
47
48 This->charSet = FcCharSetCreate();
49 if (!This->charSet) {
50 __glcRaiseError(GLC_RESOURCE_ERROR);
51 __glcFree(This);
52 return NULL;
53 }
54
55 if (inMaster) {
56 FcCharSet* charSet = NULL;
57 FcFontSet* fontSet = NULL;
58 int i = 0;
59 FcObjectSet* objectSet = NULL;
60 FcPattern* pattern = FcPatternCreate();
61
62 if (!pattern) {
63 __glcRaiseError(GLC_RESOURCE_ERROR);
64 FcCharSetDestroy(This->charSet);
65 __glcFree(This);
66 return NULL;
67 }
68
69 objectSet = FcObjectSetBuild(FC_FAMILY, FC_FOUNDRY, FC_SPACING, FC_OUTLINE,
70 FC_CHARSET, NULL);
71 if (!objectSet) {
72 __glcRaiseError(GLC_RESOURCE_ERROR);
73 FcPatternDestroy(pattern);
74 FcCharSetDestroy(This->charSet);
75 __glcFree(This);
76 return NULL;
77 }
78
79 fontSet = FcFontList(inContext->config, pattern, objectSet);
80 FcObjectSetDestroy(objectSet);
81 FcPatternDestroy(pattern);
82 if (!fontSet) {
83 __glcRaiseError(GLC_RESOURCE_ERROR);
84 FcCharSetDestroy(This->charSet);
85 __glcFree(This);
86 return NULL;
87 }
88
89 for (i = 0; i < fontSet->nfont; i++) {
90 FcChar8* family = NULL;
91 int fixed = 0;
92 FcChar8* foundry = NULL;
93 FcBool outline = FcFalse;
94 FcResult result = FcResultMatch;
95 FcBool equal = FcFalse;
96
97 /* Check whether the glyphs are outlines */
98 result = FcPatternGetBool(fontSet->fonts[i], FC_OUTLINE, 0, &outline);
99 assert(result != FcResultTypeMismatch);
100
101 if (!outline)
102 continue;
103
104 result = FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family);
105 assert(result != FcResultTypeMismatch);
106 result = FcPatternGetString(fontSet->fonts[i], FC_FOUNDRY, 0, &foundry);
107 assert(result != FcResultTypeMismatch);
108 result = FcPatternGetInteger(fontSet->fonts[i], FC_SPACING, 0, &fixed);
109 assert(result != FcResultTypeMismatch);
110
111 if (foundry)
112 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
113 FC_FOUNDRY, FcTypeString, foundry, FC_SPACING,
114 FcTypeInteger, fixed, NULL);
115 else
116 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, family,
117 FC_SPACING, FcTypeInteger, fixed, NULL);
118
119 if (!pattern) {
120 __glcRaiseError(GLC_RESOURCE_ERROR);
121 FcCharSetDestroy(This->charSet);
122 FcFontSetDestroy(fontSet);
123 __glcFree(This);
124 return NULL;
125 }
126
127 equal = FcPatternEqual(pattern, inMaster->pattern);
128 FcPatternDestroy(pattern);
129 if (equal) {
130 FcCharSet* newCharSet = NULL;
131
132 result = FcPatternGetCharSet(fontSet->fonts[i], FC_CHARSET, 0,
133 &charSet);
134 assert(result != FcResultTypeMismatch);
135
136 newCharSet = FcCharSetUnion(This->charSet, charSet);
137 if (!newCharSet) {
138 __glcRaiseError(GLC_RESOURCE_ERROR);
139 FcCharSetDestroy(This->charSet);
140 FcFontSetDestroy(fontSet);
141 __glcFree(This);
142 return NULL;
143 }
144
145 FcCharSetDestroy(This->charSet);
146 This->charSet = newCharSet;
147 }
148 }
149
150 FcFontSetDestroy(fontSet);
151 }
152
153 /* The array 'map' will contain the actual character map */
154 This->map = __glcArrayCreate(sizeof(__GLCcharMapElement));
155 if (!This->map) {
156 FcCharSetDestroy(This->charSet);
157 __glcFree(This);
158 return NULL;
159 }
160
161 return This;
162 }
163
164
165
166 /* Destructor of the object */
__glcCharMapDestroy(__GLCcharMap * This)167 void __glcCharMapDestroy(__GLCcharMap* This)
168 {
169 if (This->map)
170 __glcArrayDestroy(This->map);
171
172 FcCharSetDestroy(This->charSet);
173
174 __glcFree(This);
175 }
176
177
178
179 /* Add a given character to the character map. Afterwards, the character map
180 * will associate the glyph 'inGlyph' to the Unicode codepoint 'inCode'.
181 */
__glcCharMapAddChar(__GLCcharMap * This,GLint inCode,__GLCglyph * inGlyph)182 void __glcCharMapAddChar(__GLCcharMap* This, GLint inCode, __GLCglyph* inGlyph)
183 {
184 __GLCcharMapElement* element = NULL;
185 __GLCcharMapElement* newElement = NULL;
186 int start = 0, middle = 0, end = 0;
187
188 assert(This->map);
189 assert(GLC_ARRAY_DATA(This->map));
190 assert(inCode >= 0);
191
192 /* Characters are stored by ascending order of their mapped code */
193 element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
194
195 end = GLC_ARRAY_LENGTH(This->map) - 1;
196
197 /* Parse the array by dichotomy to look for the place where to add the new
198 * character.
199 */
200 while (start <= end) {
201 middle = (start + end) >> 1;
202 /* If the character map already contains the new character then update the
203 * glyph then return.
204 */
205 if (element[middle].mappedCode == (GLCulong)inCode) {
206 element[middle].glyph = inGlyph;
207 return;
208 }
209 else if (element[middle].mappedCode > (GLCulong)inCode)
210 end = middle - 1;
211 else
212 start = middle + 1;
213 }
214
215 /* If we have reached the end of the array then updated the rank 'middle'
216 * accordingly.
217 */
218 if ((end >= 0) && (element[middle].mappedCode < (GLCulong)inCode))
219 middle++;
220
221 /* Insert the new character in the character map */
222 newElement = (__GLCcharMapElement*)__glcArrayInsertCell(This->map, middle, 1);
223 if (!newElement)
224 return;
225
226 newElement->mappedCode = inCode;
227 newElement->glyph = inGlyph;
228 return;
229 }
230
231
232
233 /* Remove a character from the character map */
__glcCharMapRemoveChar(__GLCcharMap * This,GLint inCode)234 void __glcCharMapRemoveChar(__GLCcharMap* This, GLint inCode)
235 {
236 __GLCcharMapElement* element = NULL;
237 int start = 0, middle = 0, end = 0;
238
239 assert(This->map);
240 assert(GLC_ARRAY_DATA(This->map));
241 assert(inCode >= 0);
242
243 /* Characters are stored by ascending order of their mapped code */
244 element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
245
246 end = GLC_ARRAY_LENGTH(This->map) - 1;
247
248 /* Parse the array by dichotomy to look for the place where to add the new
249 * character.
250 */
251 while (start <= end) {
252 middle = (start + end) >> 1;
253 /* When the character is found remove it from the array and return */
254 if (element[middle].mappedCode == (GLCulong)inCode) {
255 __glcArrayRemove(This->map, middle);
256 break;
257 }
258 else if (element[middle].mappedCode > (GLCulong)inCode)
259 end = middle - 1;
260 else
261 start = middle + 1;
262 }
263 }
264
265
266
267 /* Get the Unicode character name of the character which codepoint is inCode.
268 * Note : since the character maps of the fonts can be altered, this function
269 * can return 'LATIN CAPITAL LETTER B' whereas inCode contained 65 (which is
270 * the Unicode code point of 'LATIN CAPITAL LETTER A').
271 */
__glcCharMapGetCharName(__GLCcharMap * This,GLint inCode)272 const GLCchar8* __glcCharMapGetCharName(__GLCcharMap* This, GLint inCode)
273 {
274 __GLCcharMapElement* element = NULL;
275 int start = 0, middle = 0, end = 0;
276 GLint code = 0;
277
278 assert(This->map);
279 assert(GLC_ARRAY_DATA(This->map));
280 assert(inCode >= 0);
281
282 /* Characters are stored by ascending order of their mapped code */
283 element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
284
285 end = GLC_ARRAY_LENGTH(This->map) - 1;
286
287 /* Parse the array by dichotomy to look for the Unicode codepoint that the
288 * request character maps to.
289 */
290 while (start <= end) {
291 middle = (start + end) >> 1;
292 if (element[middle].mappedCode == (GLCulong)inCode) {
293 code = element[middle].glyph->codepoint;
294 break;
295 }
296 else if (element[middle].mappedCode > (GLCulong)inCode)
297 end = middle - 1;
298 else
299 start = middle + 1;
300 }
301
302 if (!code) {
303 if (FcCharSetHasChar(This->charSet, inCode))
304 code = inCode;
305 else
306 return NULL;
307 }
308
309 return __glcNameFromCode(code);
310 }
311
312
313
314 /* Get the glyph corresponding to codepoint 'inCode' */
__glcCharMapGetGlyph(__GLCcharMap * This,GLint inCode)315 __GLCglyph* __glcCharMapGetGlyph(__GLCcharMap* This, GLint inCode)
316 {
317 __GLCcharMapElement* element = NULL;
318 int start = 0, middle = 0, end = 0;
319
320 assert(This->map);
321 assert(GLC_ARRAY_DATA(This->map));
322 assert(inCode >= 0);
323
324 /* Characters are stored by ascending order of their mapped code */
325 element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
326
327 end = GLC_ARRAY_LENGTH(This->map) - 1;
328
329 /* Parse the array by dichotomy to find the glyph of the requested
330 * character.
331 */
332 while (start <= end) {
333 middle = (start + end) >> 1;
334 if (element[middle].mappedCode == (GLCulong)inCode)
335 /* When the character is found return the corresponding glyph */
336 return element[middle].glyph;
337 else if (element[middle].mappedCode > (GLCulong)inCode)
338 end = middle - 1;
339 else
340 start = middle + 1;
341 }
342
343 /* No glyph has been defined yet for the requested character */
344 return NULL;
345 }
346
347
348
349 /* Check if a character is in the character map */
__glcCharMapHasChar(__GLCcharMap * This,GLint inCode)350 GLboolean __glcCharMapHasChar(__GLCcharMap* This, GLint inCode)
351 {
352 __GLCcharMapElement* element = NULL;
353 int start = 0, middle = 0, end = 0;
354
355 assert(This->map);
356 assert(GLC_ARRAY_DATA(This->map));
357 assert(inCode >= 0);
358
359 /* Characters are stored by ascending order of their mapped code */
360 element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
361
362 end = GLC_ARRAY_LENGTH(This->map) - 1;
363
364 /* Parse the array by dichotomy to find the requested character. */
365 while (start <= end) {
366 middle = (start + end) >> 1;
367 /* The character has been found : return GL_TRUE */
368 if (element[middle].mappedCode == (GLCulong)inCode)
369 return GL_TRUE;
370 else if (element[middle].mappedCode > (GLCulong)inCode)
371 end = middle - 1;
372 else
373 start = middle + 1;
374 }
375
376 /* Check if the character identified by inCode exists in the font */
377 return FcCharSetHasChar(This->charSet, inCode);
378 }
379
380
381
382 /* This function counts the number of bits that are set in c1
383 * Copied from Keith Packard's fontconfig
384 */
__glcCharSetPopCount(GLCchar32 c1)385 static GLCchar32 __glcCharSetPopCount(GLCchar32 c1)
386 {
387 /* hackmem 169 */
388 GLCchar32 c2 = (c1 >> 1) & 033333333333;
389 c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
390 return (((c2 + (c2 >> 3)) & 030707070707) % 077);
391 }
392
393
394
395 /* Get the name of the character which is stored at rank 'inIndex' in the
396 * FcCharSet of the face.
397 */
__glcCharMapGetCharNameByIndex(__GLCcharMap * This,GLint inIndex)398 const GLCchar8* __glcCharMapGetCharNameByIndex(__GLCcharMap* This,
399 GLint inIndex)
400 {
401 int i = 0;
402 int j = 0;
403
404 /* In Fontconfig the map in FcCharSet is organized as an array of integers.
405 * Each integer corresponds to a page of 32 characters (since it uses 32 bits
406 * integer). If a bit is set then character is in the character map otherwise
407 * it is not.
408 * In order not to store pages of 0's, the character map begins at the
409 * character which codepoint is 'base'.
410 * Pages are also gathered in blocks of 'FC_CHARSET_MAP_SIZE' pages in order
411 * to prevent Fontconfig to store heaps of 0's if the character codes are
412 * sparsed.
413 *
414 * The codepoint of a character located at bit 'j' of page 'i' is :
415 * 'base + (i << 5) + j'.
416 */
417 GLCchar32 map[FC_CHARSET_MAP_SIZE];
418 GLCchar32 next = 0;
419 GLCchar32 base = FcCharSetFirstPage(This->charSet, map, &next);
420 GLCchar32 count = 0;
421 GLCchar32 value = 0;
422
423 assert(inIndex >= 0);
424
425 do {
426 /* Parse the pages in FcCharSet */
427 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) {
428 /* Get the number of character located in the current page */
429 value = __glcCharSetPopCount(map[i]);
430
431 /* Check if the character we are looking for is in the current page */
432 if (count + value >= (GLCchar32)inIndex + 1) {
433 for (j = 0; j < 32; j++) {
434 /* Parse the page bit by bit */
435 if ((map[i] >> j) & 1) count++; /* A character is set at bit j */
436 /* Check if we have reached the rank inIndex */
437 if (count == (GLCchar32)inIndex + 1) {
438 /* Get the character name */
439 return __glcNameFromCode(base + (i << 5) + j);
440 }
441 }
442 }
443 /* Add the number of characters of the current page to the count and
444 * check the next page.
445 */
446 count += value;
447 }
448 /* The current block is finished, check the next one */
449 base = FcCharSetNextPage(This->charSet, map, &next);
450 } while (base != FC_CHARSET_DONE);
451
452 /* The character has not been found */
453 __glcRaiseError(GLC_PARAMETER_ERROR);
454 return GLC_NONE;
455 }
456
457
458
459 /* Return the number of characters in the character map */
__glcCharMapGetCount(__GLCcharMap * This)460 GLint __glcCharMapGetCount(__GLCcharMap* This)
461 {
462 return FcCharSetCount(This->charSet);
463 }
464
465
466
467 /* Get the maximum mapped code of a character set */
__glcCharMapGetMaxMappedCode(__GLCcharMap * This)468 GLint __glcCharMapGetMaxMappedCode(__GLCcharMap* This)
469 {
470 GLCchar32 base = 0;
471 GLCchar32 next = 0;
472 GLCchar32 prev_base = 0;
473 GLCchar32 map[FC_CHARSET_MAP_SIZE];
474 int i = 0, j = 0;
475 GLCulong maxMappedCode = 0;
476 __GLCcharMapElement* element = NULL;
477 int length = 0;
478
479 assert(This->map);
480 assert(GLC_ARRAY_DATA(This->map));
481
482 /* Look for the last block of pages of the FcCharSet structure */
483 base = FcCharSetFirstPage(This->charSet, map, &next);
484 assert(base != FC_CHARSET_DONE);
485
486 do {
487 prev_base = base;
488 base = FcCharSetNextPage(This->charSet, map, &next);
489 } while (base != FC_CHARSET_DONE);
490
491 /* Parse the pages in descending order to find the last page that contains
492 * one character.
493 */
494 for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
495 if (map[i]) break;
496
497 /* If the map contains no char then something went wrong... */
498 assert(i >= 0);
499
500 /* Parse the bits of the last page in descending order to find the last
501 * character of the page
502 */
503 for (j = 31; j >= 0; j--)
504 if ((map[i] >> j) & 1) break;
505
506 /* Calculate the max mapped code */
507 maxMappedCode = prev_base + (i << 5) + j;
508
509 /* Check that a code greater than the one found in the FcCharSet is not
510 * stored in the array 'map'.
511 */
512 element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
513 length = GLC_ARRAY_LENGTH(This->map);
514
515 /* Return the greater of the code of both the FcCharSet and the array 'map'*/
516 if (length)
517 return element[length-1].mappedCode > maxMappedCode ?
518 element[length-1].mappedCode : maxMappedCode;
519 else
520 return maxMappedCode;
521 }
522
523
524
525 /* Get the minimum mapped code of a character set */
__glcCharMapGetMinMappedCode(__GLCcharMap * This)526 GLint __glcCharMapGetMinMappedCode(__GLCcharMap* This)
527 {
528 GLCchar32 base = 0;
529 GLCchar32 next = 0;
530 GLCchar32 map[FC_CHARSET_MAP_SIZE];
531 int i = 0, j = 0;
532 GLCulong minMappedCode = 0xffffffff;
533 __GLCcharMapElement* element = NULL;
534 int length = 0;
535
536 assert(This->map);
537 assert(GLC_ARRAY_DATA(This->map));
538
539 /* Get the first block of pages of the FcCharSet structure */
540 base = FcCharSetFirstPage(This->charSet, map, &next);
541 assert(base != FC_CHARSET_DONE);
542
543 /* Parse the pages in ascending order to find the first page that contains
544 * one character.
545 */
546 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
547 if (map[i]) break;
548
549 /* If the map contains no char then something went wrong... */
550 assert(i >= 0);
551
552 /* Parse the bits of the first page in ascending order to find the first
553 * character of the page
554 */
555 for (j = 0; j < 32; j++)
556 if ((map[i] >> j) & 1) break;
557 minMappedCode = base + (i << 5) + j;
558
559 /* Check that a code lower than the one found in the FcCharSet is not
560 * stored in the array 'map'.
561 */
562 element = (__GLCcharMapElement*)GLC_ARRAY_DATA(This->map);
563 length = GLC_ARRAY_LENGTH(This->map);
564
565 /* Return the lower of the code of both the FcCharSet and the array 'map'*/
566 if (length > 0)
567 return element[0].mappedCode < minMappedCode ?
568 element[0].mappedCode : minMappedCode;
569 else
570 return minMappedCode;
571 }
572