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 22FontMap::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 110FontMap::~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 127le_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 171char *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 195const 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 229le_int32 FontMap::getAscent() const 230{ 231 if (fAscent <= 0) { 232 ((FontMap *) this)->getMaxMetrics(); 233 } 234 235 return fAscent; 236} 237 238le_int32 FontMap::getDescent() const 239{ 240 if (fDescent <= 0) { 241 ((FontMap *) this)->getMaxMetrics(); 242 } 243 244 return fDescent; 245} 246 247le_int32 FontMap::getLeading() const 248{ 249 if (fLeading <= 0) { 250 ((FontMap *) this)->getMaxMetrics(); 251 } 252 253 return fLeading; 254} 255 256void 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