Home | History | Annotate | Download | only in layout
      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 
     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)
     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 
    114 FontMap::~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 
    131 le_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 
    175 char *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 
    199 const 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 
    233 le_int32 FontMap::getAscent() const
    234 {
    235     if (fAscent <= 0) {
    236         ((FontMap *) this)->getMaxMetrics();
    237     }
    238 
    239     return fAscent;
    240 }
    241 
    242 le_int32 FontMap::getDescent() const
    243 {
    244     if (fDescent <= 0) {
    245         ((FontMap *) this)->getMaxMetrics();
    246     }
    247 
    248     return fDescent;
    249 }
    250 
    251 le_int32 FontMap::getLeading() const
    252 {
    253     if (fLeading <= 0) {
    254         ((FontMap *) this)->getMaxMetrics();
    255     }
    256 
    257     return fLeading;
    258 }
    259 
    260 void 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 
    292