• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ******************************************************************************
3  * Copyright (C) 1998-2006, International Business Machines Corporation and   *
4  * others. All Rights Reserved.                                               *
5  ******************************************************************************
6  */
7 
8 #include <stdio.h>
9 #include <string.h>
10 #include <ctype.h>
11 
12 #include "unicode/utypes.h"
13 #include "unicode/uscript.h"
14 
15 #include "layout/LETypes.h"
16 #include "layout/LEScripts.h"
17 #include "layout/LEFontInstance.h"
18 
19 #include "GUISupport.h"
20 #include "FontMap.h"
21 
FontMap(const char * fileName,le_int16 pointSize,GUISupport * guiSupport,LEErrorCode & status)22 FontMap::FontMap(const char *fileName, le_int16 pointSize, GUISupport *guiSupport, LEErrorCode &status)
23     : fPointSize(pointSize), fFontCount(0), fAscent(0), fDescent(0), fLeading(0), fGUISupport(guiSupport)
24 {
25     le_int32 defaultFont = -1, i, script;
26     le_bool haveFonts = FALSE;
27 
28 /**/
29     for (i = 0; i < scriptCodeCount; i += 1) {
30         fFontIndices[i] = -1;
31         fFontNames[i] = NULL;
32         fFontInstances[i] = NULL;
33     }
34  /**/
35 
36     if (LE_FAILURE(status)) {
37         return;
38     }
39 
40     char *c, *scriptName, *fontName, *line, buffer[BUFFER_SIZE];
41     FILE *file;
42 
43     file = fopen(fileName, "r");
44 
45     if (file == NULL) {
46         sprintf(errorMessage, "Could not open the font map file: %s.", fileName);
47         fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
48         status = LE_FONT_FILE_NOT_FOUND_ERROR;
49         return;
50     }
51 
52     while (fgets(buffer, BUFFER_SIZE, file) != NULL) {
53         UScriptCode scriptCode;
54         UErrorCode scriptStatus = U_ZERO_ERROR;
55 
56         line = strip(buffer);
57         if (line[0] == '#' || line[0] == 0) {
58             continue;
59         }
60 
61         c = strchr(line, ':');
62         c[0] = 0;
63 
64         fontName   = strip(&c[1]);
65         scriptName = strip(line);
66 
67         if (strcmp(scriptName, "DEFAULT") == 0) {
68             defaultFont = getFontIndex(fontName);
69             haveFonts = TRUE;
70             continue;
71         }
72 
73         le_int32 fillCount = uscript_getCode(scriptName, &scriptCode, 1, &scriptStatus);
74 
75         if (U_FAILURE(scriptStatus) || fillCount <= 0 ||
76             scriptStatus == U_USING_FALLBACK_WARNING || scriptStatus == U_USING_DEFAULT_WARNING) {
77             sprintf(errorMessage, "The script name %s is invalid.", line);
78             fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
79             continue;
80         }
81 
82         script = (le_int32) scriptCode;
83 
84         if (fFontIndices[script] >= 0) {
85             // FIXME: complain that this is a duplicate entry and bail (?)
86             fFontIndices[script] = -1;
87         }
88 
89         fFontIndices[script] = getFontIndex(fontName);
90         haveFonts = TRUE;
91     }
92 
93     if (defaultFont >= 0) {
94         for (script = 0; script < scriptCodeCount; script += 1) {
95             if (fFontIndices[script] < 0) {
96                 fFontIndices[script] = defaultFont;
97             }
98         }
99     }
100 
101     if (! haveFonts) {
102         sprintf(errorMessage, "The font map file %s does not contain any valid scripts.", fileName);
103         fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
104         status = LE_ILLEGAL_ARGUMENT_ERROR;
105     }
106 
107     fclose(file);
108 }
109 
~FontMap()110 FontMap::~FontMap()
111 {
112     le_int32 font;
113 
114     for (font = 0; font < fFontCount; font += 1) {
115         if (fFontNames[font] != NULL) {
116             delete[] (char *) fFontNames[font];
117         }
118     }
119 
120     for (font = 0; font < fFontCount; font += 1) {
121         if (fFontInstances[font] != NULL) {
122             delete fFontInstances[font];
123         }
124     }
125 }
126 
getFontIndex(const char * fontName)127 le_int32 FontMap::getFontIndex(const char *fontName)
128 {
129     le_int32 index;
130 
131     for (index = 0; index < fFontCount; index += 1) {
132         if (strcmp(fontName, fFontNames[index]) == 0) {
133             return index;
134         }
135     }
136 
137     if (fFontCount < (le_int32) scriptCodeCount) {
138         index = fFontCount++;
139     } else {
140         // The font name table is full. Since there can
141         // only be scriptCodeCount fonts in use at once,
142         // there should be at least one that's not being
143         // referenced; find it and resue it's index.
144 
145         for (index = 0; index < fFontCount; index += 1) {
146             le_int32 script;
147 
148             for (script = 0; script < scriptCodeCount; script += 1) {
149                 if (fFontIndices[script] == index) {
150                     break;
151                 }
152             }
153 
154             if (script >= scriptCodeCount) {
155                 break;
156             }
157         }
158     }
159 
160     if (index >= scriptCodeCount) {
161         return -1;
162     }
163 
164     le_int32 len = strlen(fontName);
165     char *s = new char[len + 1];
166 
167     fFontNames[index] = strcpy(s, fontName);
168     return index;
169 }
170 
strip(char * s)171 char *FontMap::strip(char *s)
172 {
173     le_int32 start, end, len;
174 
175     start = 0;
176     len = strlen(s);
177 
178     while (start < len && isspace(s[start])) {
179         start += 1;
180     }
181 
182     end = len - 1;
183 
184     while (end > start && isspace(s[end])) {
185         end -= 1;
186     }
187 
188     if (end < len) {
189         s[end + 1] = '\0';
190     }
191 
192     return &s[start];
193 }
194 
getScriptFont(le_int32 scriptCode,LEErrorCode & status)195 const LEFontInstance *FontMap::getScriptFont(le_int32 scriptCode, LEErrorCode &status)
196 {
197     if (LE_FAILURE(status)) {
198         return NULL;
199     }
200 
201     if (scriptCode <= -1 || scriptCode >= scriptCodeCount) {
202         status = LE_ILLEGAL_ARGUMENT_ERROR;
203         return NULL;
204     }
205 
206 
207     le_int32 fontIndex = fFontIndices[scriptCode];
208 
209     if (fontIndex < 0) {
210         sprintf(errorMessage, "No font was set for script %s", uscript_getName((UScriptCode) scriptCode));
211         fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
212         status = LE_FONT_FILE_NOT_FOUND_ERROR;
213         return NULL;
214     }
215 
216     if (fFontInstances[fontIndex] == NULL) {
217         fFontInstances[fontIndex] = openFont(fFontNames[fontIndex], fPointSize, status);
218 
219         if (LE_FAILURE(status)) {
220             sprintf(errorMessage, "Could not open font file %s", fFontNames[fontIndex]);
221             fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
222             return NULL;
223         }
224     }
225 
226     return fFontInstances[fontIndex];
227 }
228 
getAscent() const229 le_int32 FontMap::getAscent() const
230 {
231     if (fAscent <= 0) {
232         ((FontMap *) this)->getMaxMetrics();
233     }
234 
235     return fAscent;
236 }
237 
getDescent() const238 le_int32 FontMap::getDescent() const
239 {
240     if (fDescent <= 0) {
241         ((FontMap *) this)->getMaxMetrics();
242     }
243 
244     return fDescent;
245 }
246 
getLeading() const247 le_int32 FontMap::getLeading() const
248 {
249     if (fLeading <= 0) {
250         ((FontMap *) this)->getMaxMetrics();
251     }
252 
253     return fLeading;
254 }
255 
getMaxMetrics()256 void FontMap::getMaxMetrics()
257 {
258     for (le_int32 i = 0; i < fFontCount; i += 1) {
259         LEErrorCode status = LE_NO_ERROR;
260         le_int32 ascent, descent, leading;
261 
262         if (fFontInstances[i] == NULL) {
263             fFontInstances[i] = openFont(fFontNames[i], fPointSize, status);
264 
265             if (LE_FAILURE(status)) {
266                 continue;
267             }
268         }
269 
270         ascent  = fFontInstances[i]->getAscent();
271         descent = fFontInstances[i]->getDescent();
272         leading = fFontInstances[i]->getLeading();
273 
274         if (ascent > fAscent) {
275             fAscent = ascent;
276         }
277 
278         if (descent > fDescent) {
279             fDescent = descent;
280         }
281 
282         if (leading > fLeading) {
283             fLeading = leading;
284         }
285     }
286 }
287 
288