2 ******************************************************************************
3 * Copyright (C) 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 ******************************************************************************
16 #include "unicode/utypes.h"
17 #include "unicode/uscript.h"
19 #include "layout/LETypes.h"
20 #include "layout/LEScripts.h"
21 #include "layout/LEFontInstance.h"
23 #include "GUISupport.h"
26 FontMap::FontMap(const char *fileName, le_int16 pointSize, GUISupport *guiSupport, LEErrorCode &status)
27 : fPointSize(pointSize), fFontCount(0), fAscent(0), fDescent(0), fLeading(0), fGUISupport(guiSupport)
29 le_int32 defaultFont = -1, i, script;
30 le_bool haveFonts = FALSE;
33 for (i = 0; i < scriptCodeCount; i += 1) {
36 fFontInstances[i] = NULL;
40 if (LE_FAILURE(status)) {
44 char *c, *scriptName, *fontName, *line, buffer[BUFFER_SIZE];
47 file = fopen(fileName, "r");
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;
56 while (fgets(buffer, BUFFER_SIZE, file) != NULL) {
57 UScriptCode scriptCode;
58 UErrorCode scriptStatus = U_ZERO_ERROR;
61 if (line[0] == '#' || line[0] == 0) {
65 c = strchr(line, ':');
68 fontName = strip(&c[1]);
69 scriptName = strip(line);
71 if (strcmp(scriptName, "DEFAULT") == 0) {
72 defaultFont = getFontIndex(fontName);
77 le_int32 fillCount = uscript_getCode(scriptName, &scriptCode, 1, &scriptStatus);
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");
86 script = (le_int32) scriptCode;
88 if (fFontIndices[script] >= 0) {
89 // FIXME: complain that this is a duplicate entry and bail (?)
90 fFontIndices[script] = -1;
93 fFontIndices[script] = getFontIndex(fontName);
97 if (defaultFont >= 0) {
98 for (script = 0; script < scriptCodeCount; script += 1) {
99 if (fFontIndices[script] < 0) {
100 fFontIndices[script] = defaultFont;
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;
118 for (font = 0; font < fFontCount; font += 1) {
119 if (fFontNames[font] != NULL) {
120 delete[] (char *) fFontNames[font];
124 for (font = 0; font < fFontCount; font += 1) {
125 if (fFontInstances[font] != NULL) {
126 delete fFontInstances[font];
131 le_int32 FontMap::getFontIndex(const char *fontName)
135 for (index = 0; index < fFontCount; index += 1) {
136 if (strcmp(fontName, fFontNames[index]) == 0) {
141 if (fFontCount < (le_int32) scriptCodeCount) {
142 index = fFontCount++;
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.
149 for (index = 0; index < fFontCount; index += 1) {
152 for (script = 0; script < scriptCodeCount; script += 1) {
153 if (fFontIndices[script] == index) {
158 if (script >= scriptCodeCount) {
164 if (index >= scriptCodeCount) {
168 le_int32 len = strlen(fontName);
169 char *s = new char[len + 1];
171 fFontNames[index] = strcpy(s, fontName);
175 char *FontMap::strip(char *s)
177 le_int32 start, end, len;
182 while (start < len && isspace(s[start])) {
188 while (end > start && isspace(s[end])) {
199 const LEFontInstance *FontMap::getScriptFont(le_int32 scriptCode, LEErrorCode &status)
201 if (LE_FAILURE(status)) {
205 if (scriptCode <= -1 || scriptCode >= scriptCodeCount) {
206 status = LE_ILLEGAL_ARGUMENT_ERROR;
211 le_int32 fontIndex = fFontIndices[scriptCode];
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;
220 if (fFontInstances[fontIndex] == NULL) {
221 fFontInstances[fontIndex] = openFont(fFontNames[fontIndex], fPointSize, status);
223 if (LE_FAILURE(status)) {
224 sprintf(errorMessage, "Could not open font file %s", fFontNames[fontIndex]);
225 fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
230 return fFontInstances[fontIndex];
233 le_int32 FontMap::getAscent() const
236 ((FontMap *) this)->getMaxMetrics();
242 le_int32 FontMap::getDescent() const
245 ((FontMap *) this)->getMaxMetrics();
251 le_int32 FontMap::getLeading() const
254 ((FontMap *) this)->getMaxMetrics();
260 void FontMap::getMaxMetrics()
262 for (le_int32 i = 0; i < fFontCount; i += 1) {
263 LEErrorCode status = LE_NO_ERROR;
264 le_int32 ascent, descent, leading;
266 if (fFontInstances[i] == NULL) {
267 fFontInstances[i] = openFont(fFontNames[i], fPointSize, status);
269 if (LE_FAILURE(status)) {
274 ascent = fFontInstances[i]->getAscent();
275 descent = fFontInstances[i]->getDescent();
276 leading = fFontInstances[i]->getLeading();
278 if (ascent > fAscent) {
282 if (descent > fDescent) {
286 if (leading > fLeading) {