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