Home | History | Annotate | Download | only in layout
      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 
     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 
    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 
    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 
    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 
    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 
    229 le_int32 FontMap::getAscent() const
    230 {
    231     if (fAscent <= 0) {
    232         ((FontMap *) this)->getMaxMetrics();
    233     }
    234 
    235     return fAscent;
    236 }
    237 
    238 le_int32 FontMap::getDescent() const
    239 {
    240     if (fDescent <= 0) {
    241         ((FontMap *) this)->getMaxMetrics();
    242     }
    243 
    244     return fDescent;
    245 }
    246 
    247 le_int32 FontMap::getLeading() const
    248 {
    249     if (fLeading <= 0) {
    250         ((FontMap *) this)->getMaxMetrics();
    251     }
    252 
    253     return fLeading;
    254 }
    255 
    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