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