12e5b6d6dSopenharmony_ci/*
22e5b6d6dSopenharmony_ci ******************************************************************************
32e5b6d6dSopenharmony_ci * © 2016 and later: Unicode, Inc. and others.                    *
42e5b6d6dSopenharmony_ci * License & terms of use: http://www.unicode.org/copyright.html      *
52e5b6d6dSopenharmony_ci ******************************************************************************
62e5b6d6dSopenharmony_ci ******************************************************************************
72e5b6d6dSopenharmony_ci * Copyright (C) 1998-2006, International Business Machines Corporation and   *
82e5b6d6dSopenharmony_ci * others. All Rights Reserved.                                               *
92e5b6d6dSopenharmony_ci ******************************************************************************
102e5b6d6dSopenharmony_ci */
112e5b6d6dSopenharmony_ci
122e5b6d6dSopenharmony_ci#include <stdio.h>
132e5b6d6dSopenharmony_ci#include <string.h>
142e5b6d6dSopenharmony_ci#include <ctype.h>
152e5b6d6dSopenharmony_ci
162e5b6d6dSopenharmony_ci#include "unicode/utypes.h"
172e5b6d6dSopenharmony_ci#include "unicode/uscript.h"
182e5b6d6dSopenharmony_ci
192e5b6d6dSopenharmony_ci#include "layout/LETypes.h"
202e5b6d6dSopenharmony_ci#include "layout/LEScripts.h"
212e5b6d6dSopenharmony_ci#include "layout/LEFontInstance.h"
222e5b6d6dSopenharmony_ci
232e5b6d6dSopenharmony_ci#include "GUISupport.h"
242e5b6d6dSopenharmony_ci#include "FontMap.h"
252e5b6d6dSopenharmony_ci
262e5b6d6dSopenharmony_ciFontMap::FontMap(const char *fileName, le_int16 pointSize, GUISupport *guiSupport, LEErrorCode &status)
272e5b6d6dSopenharmony_ci    : fPointSize(pointSize), fFontCount(0), fAscent(0), fDescent(0), fLeading(0), fGUISupport(guiSupport)
282e5b6d6dSopenharmony_ci{
292e5b6d6dSopenharmony_ci    le_int32 defaultFont = -1, i, script;
302e5b6d6dSopenharmony_ci    le_bool haveFonts = false;
312e5b6d6dSopenharmony_ci
322e5b6d6dSopenharmony_ci/**/
332e5b6d6dSopenharmony_ci    for (i = 0; i < scriptCodeCount; i += 1) {
342e5b6d6dSopenharmony_ci        fFontIndices[i] = -1;
352e5b6d6dSopenharmony_ci        fFontNames[i] = NULL;
362e5b6d6dSopenharmony_ci        fFontInstances[i] = NULL;
372e5b6d6dSopenharmony_ci    }
382e5b6d6dSopenharmony_ci /**/
392e5b6d6dSopenharmony_ci
402e5b6d6dSopenharmony_ci    if (LE_FAILURE(status)) {
412e5b6d6dSopenharmony_ci        return;
422e5b6d6dSopenharmony_ci    }
432e5b6d6dSopenharmony_ci
442e5b6d6dSopenharmony_ci    char *c, *scriptName, *fontName, *line, buffer[BUFFER_SIZE];
452e5b6d6dSopenharmony_ci    FILE *file;
462e5b6d6dSopenharmony_ci
472e5b6d6dSopenharmony_ci    file = fopen(fileName, "r");
482e5b6d6dSopenharmony_ci
492e5b6d6dSopenharmony_ci    if (file == NULL) {
502e5b6d6dSopenharmony_ci        sprintf(errorMessage, "Could not open the font map file: %s.", fileName);
512e5b6d6dSopenharmony_ci        fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
522e5b6d6dSopenharmony_ci        status = LE_FONT_FILE_NOT_FOUND_ERROR;
532e5b6d6dSopenharmony_ci        return;
542e5b6d6dSopenharmony_ci    }
552e5b6d6dSopenharmony_ci
562e5b6d6dSopenharmony_ci    while (fgets(buffer, BUFFER_SIZE, file) != NULL) {
572e5b6d6dSopenharmony_ci        UScriptCode scriptCode;
582e5b6d6dSopenharmony_ci        UErrorCode scriptStatus = U_ZERO_ERROR;
592e5b6d6dSopenharmony_ci
602e5b6d6dSopenharmony_ci        line = strip(buffer);
612e5b6d6dSopenharmony_ci        if (line[0] == '#' || line[0] == 0) {
622e5b6d6dSopenharmony_ci            continue;
632e5b6d6dSopenharmony_ci        }
642e5b6d6dSopenharmony_ci
652e5b6d6dSopenharmony_ci        c = strchr(line, ':');
662e5b6d6dSopenharmony_ci        c[0] = 0;
672e5b6d6dSopenharmony_ci
682e5b6d6dSopenharmony_ci        fontName   = strip(&c[1]);
692e5b6d6dSopenharmony_ci        scriptName = strip(line);
702e5b6d6dSopenharmony_ci
712e5b6d6dSopenharmony_ci        if (strcmp(scriptName, "DEFAULT") == 0) {
722e5b6d6dSopenharmony_ci            defaultFont = getFontIndex(fontName);
732e5b6d6dSopenharmony_ci            haveFonts = true;
742e5b6d6dSopenharmony_ci            continue;
752e5b6d6dSopenharmony_ci        }
762e5b6d6dSopenharmony_ci
772e5b6d6dSopenharmony_ci        le_int32 fillCount = uscript_getCode(scriptName, &scriptCode, 1, &scriptStatus);
782e5b6d6dSopenharmony_ci
792e5b6d6dSopenharmony_ci        if (U_FAILURE(scriptStatus) || fillCount <= 0 ||
802e5b6d6dSopenharmony_ci            scriptStatus == U_USING_FALLBACK_WARNING || scriptStatus == U_USING_DEFAULT_WARNING) {
812e5b6d6dSopenharmony_ci            sprintf(errorMessage, "The script name %s is invalid.", line);
822e5b6d6dSopenharmony_ci            fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
832e5b6d6dSopenharmony_ci            continue;
842e5b6d6dSopenharmony_ci        }
852e5b6d6dSopenharmony_ci
862e5b6d6dSopenharmony_ci        script = (le_int32) scriptCode;
872e5b6d6dSopenharmony_ci
882e5b6d6dSopenharmony_ci        if (fFontIndices[script] >= 0) {
892e5b6d6dSopenharmony_ci            // FIXME: complain that this is a duplicate entry and bail (?)
902e5b6d6dSopenharmony_ci            fFontIndices[script] = -1;
912e5b6d6dSopenharmony_ci        }
922e5b6d6dSopenharmony_ci
932e5b6d6dSopenharmony_ci        fFontIndices[script] = getFontIndex(fontName);
942e5b6d6dSopenharmony_ci        haveFonts = true;
952e5b6d6dSopenharmony_ci    }
962e5b6d6dSopenharmony_ci
972e5b6d6dSopenharmony_ci    if (defaultFont >= 0) {
982e5b6d6dSopenharmony_ci        for (script = 0; script < scriptCodeCount; script += 1) {
992e5b6d6dSopenharmony_ci            if (fFontIndices[script] < 0) {
1002e5b6d6dSopenharmony_ci                fFontIndices[script] = defaultFont;
1012e5b6d6dSopenharmony_ci            }
1022e5b6d6dSopenharmony_ci        }
1032e5b6d6dSopenharmony_ci    }
1042e5b6d6dSopenharmony_ci
1052e5b6d6dSopenharmony_ci    if (! haveFonts) {
1062e5b6d6dSopenharmony_ci        sprintf(errorMessage, "The font map file %s does not contain any valid scripts.", fileName);
1072e5b6d6dSopenharmony_ci        fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
1082e5b6d6dSopenharmony_ci        status = LE_ILLEGAL_ARGUMENT_ERROR;
1092e5b6d6dSopenharmony_ci    }
1102e5b6d6dSopenharmony_ci
1112e5b6d6dSopenharmony_ci    fclose(file);
1122e5b6d6dSopenharmony_ci}
1132e5b6d6dSopenharmony_ci
1142e5b6d6dSopenharmony_ciFontMap::~FontMap()
1152e5b6d6dSopenharmony_ci{
1162e5b6d6dSopenharmony_ci    le_int32 font;
1172e5b6d6dSopenharmony_ci
1182e5b6d6dSopenharmony_ci    for (font = 0; font < fFontCount; font += 1) {
1192e5b6d6dSopenharmony_ci        if (fFontNames[font] != NULL) {
1202e5b6d6dSopenharmony_ci            delete[] (char *) fFontNames[font];
1212e5b6d6dSopenharmony_ci        }
1222e5b6d6dSopenharmony_ci    }
1232e5b6d6dSopenharmony_ci
1242e5b6d6dSopenharmony_ci    for (font = 0; font < fFontCount; font += 1) {
1252e5b6d6dSopenharmony_ci        if (fFontInstances[font] != NULL) {
1262e5b6d6dSopenharmony_ci            delete fFontInstances[font];
1272e5b6d6dSopenharmony_ci        }
1282e5b6d6dSopenharmony_ci    }
1292e5b6d6dSopenharmony_ci}
1302e5b6d6dSopenharmony_ci
1312e5b6d6dSopenharmony_cile_int32 FontMap::getFontIndex(const char *fontName)
1322e5b6d6dSopenharmony_ci{
1332e5b6d6dSopenharmony_ci    le_int32 index;
1342e5b6d6dSopenharmony_ci
1352e5b6d6dSopenharmony_ci    for (index = 0; index < fFontCount; index += 1) {
1362e5b6d6dSopenharmony_ci        if (strcmp(fontName, fFontNames[index]) == 0) {
1372e5b6d6dSopenharmony_ci            return index;
1382e5b6d6dSopenharmony_ci        }
1392e5b6d6dSopenharmony_ci    }
1402e5b6d6dSopenharmony_ci
1412e5b6d6dSopenharmony_ci    if (fFontCount < (le_int32) scriptCodeCount) {
1422e5b6d6dSopenharmony_ci        index = fFontCount++;
1432e5b6d6dSopenharmony_ci    } else {
1442e5b6d6dSopenharmony_ci        // The font name table is full. Since there can
1452e5b6d6dSopenharmony_ci        // only be scriptCodeCount fonts in use at once,
1462e5b6d6dSopenharmony_ci        // there should be at least one that's not being
1472e5b6d6dSopenharmony_ci        // referenced; find it and reuse it's index.
1482e5b6d6dSopenharmony_ci
1492e5b6d6dSopenharmony_ci        for (index = 0; index < fFontCount; index += 1) {
1502e5b6d6dSopenharmony_ci            le_int32 script;
1512e5b6d6dSopenharmony_ci
1522e5b6d6dSopenharmony_ci            for (script = 0; script < scriptCodeCount; script += 1) {
1532e5b6d6dSopenharmony_ci                if (fFontIndices[script] == index) {
1542e5b6d6dSopenharmony_ci                    break;
1552e5b6d6dSopenharmony_ci                }
1562e5b6d6dSopenharmony_ci            }
1572e5b6d6dSopenharmony_ci
1582e5b6d6dSopenharmony_ci            if (script >= scriptCodeCount) {
1592e5b6d6dSopenharmony_ci                break;
1602e5b6d6dSopenharmony_ci            }
1612e5b6d6dSopenharmony_ci        }
1622e5b6d6dSopenharmony_ci    }
1632e5b6d6dSopenharmony_ci
1642e5b6d6dSopenharmony_ci    if (index >= scriptCodeCount) {
1652e5b6d6dSopenharmony_ci        return -1;
1662e5b6d6dSopenharmony_ci    }
1672e5b6d6dSopenharmony_ci
1682e5b6d6dSopenharmony_ci    le_int32 len = strlen(fontName);
1692e5b6d6dSopenharmony_ci    char *s = new char[len + 1];
1702e5b6d6dSopenharmony_ci
1712e5b6d6dSopenharmony_ci    fFontNames[index] = strcpy(s, fontName);
1722e5b6d6dSopenharmony_ci    return index;
1732e5b6d6dSopenharmony_ci}
1742e5b6d6dSopenharmony_ci
1752e5b6d6dSopenharmony_cichar *FontMap::strip(char *s)
1762e5b6d6dSopenharmony_ci{
1772e5b6d6dSopenharmony_ci    le_int32 start, end, len;
1782e5b6d6dSopenharmony_ci
1792e5b6d6dSopenharmony_ci    start = 0;
1802e5b6d6dSopenharmony_ci    len = strlen(s);
1812e5b6d6dSopenharmony_ci
1822e5b6d6dSopenharmony_ci    while (start < len && isspace(s[start])) {
1832e5b6d6dSopenharmony_ci        start += 1;
1842e5b6d6dSopenharmony_ci    }
1852e5b6d6dSopenharmony_ci
1862e5b6d6dSopenharmony_ci    end = len - 1;
1872e5b6d6dSopenharmony_ci
1882e5b6d6dSopenharmony_ci    while (end > start && isspace(s[end])) {
1892e5b6d6dSopenharmony_ci        end -= 1;
1902e5b6d6dSopenharmony_ci    }
1912e5b6d6dSopenharmony_ci
1922e5b6d6dSopenharmony_ci    if (end < len) {
1932e5b6d6dSopenharmony_ci        s[end + 1] = '\0';
1942e5b6d6dSopenharmony_ci    }
1952e5b6d6dSopenharmony_ci
1962e5b6d6dSopenharmony_ci    return &s[start];
1972e5b6d6dSopenharmony_ci}
1982e5b6d6dSopenharmony_ci
1992e5b6d6dSopenharmony_ciconst LEFontInstance *FontMap::getScriptFont(le_int32 scriptCode, LEErrorCode &status)
2002e5b6d6dSopenharmony_ci{
2012e5b6d6dSopenharmony_ci    if (LE_FAILURE(status)) {
2022e5b6d6dSopenharmony_ci        return NULL;
2032e5b6d6dSopenharmony_ci    }
2042e5b6d6dSopenharmony_ci
2052e5b6d6dSopenharmony_ci    if (scriptCode <= -1 || scriptCode >= scriptCodeCount) {
2062e5b6d6dSopenharmony_ci        status = LE_ILLEGAL_ARGUMENT_ERROR;
2072e5b6d6dSopenharmony_ci        return NULL;
2082e5b6d6dSopenharmony_ci    }
2092e5b6d6dSopenharmony_ci
2102e5b6d6dSopenharmony_ci
2112e5b6d6dSopenharmony_ci    le_int32 fontIndex = fFontIndices[scriptCode];
2122e5b6d6dSopenharmony_ci
2132e5b6d6dSopenharmony_ci    if (fontIndex < 0) {
2142e5b6d6dSopenharmony_ci        sprintf(errorMessage, "No font was set for script %s", uscript_getName((UScriptCode) scriptCode));
2152e5b6d6dSopenharmony_ci        fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
2162e5b6d6dSopenharmony_ci        status = LE_FONT_FILE_NOT_FOUND_ERROR;
2172e5b6d6dSopenharmony_ci        return NULL;
2182e5b6d6dSopenharmony_ci    }
2192e5b6d6dSopenharmony_ci
2202e5b6d6dSopenharmony_ci    if (fFontInstances[fontIndex] == NULL) {
2212e5b6d6dSopenharmony_ci        fFontInstances[fontIndex] = openFont(fFontNames[fontIndex], fPointSize, status);
2222e5b6d6dSopenharmony_ci
2232e5b6d6dSopenharmony_ci        if (LE_FAILURE(status)) {
2242e5b6d6dSopenharmony_ci            sprintf(errorMessage, "Could not open font file %s", fFontNames[fontIndex]);
2252e5b6d6dSopenharmony_ci            fGUISupport->postErrorMessage(errorMessage, "Font Map Error");
2262e5b6d6dSopenharmony_ci            return NULL;
2272e5b6d6dSopenharmony_ci        }
2282e5b6d6dSopenharmony_ci    }
2292e5b6d6dSopenharmony_ci
2302e5b6d6dSopenharmony_ci    return fFontInstances[fontIndex];
2312e5b6d6dSopenharmony_ci}
2322e5b6d6dSopenharmony_ci
2332e5b6d6dSopenharmony_cile_int32 FontMap::getAscent() const
2342e5b6d6dSopenharmony_ci{
2352e5b6d6dSopenharmony_ci    if (fAscent <= 0) {
2362e5b6d6dSopenharmony_ci        ((FontMap *) this)->getMaxMetrics();
2372e5b6d6dSopenharmony_ci    }
2382e5b6d6dSopenharmony_ci
2392e5b6d6dSopenharmony_ci    return fAscent;
2402e5b6d6dSopenharmony_ci}
2412e5b6d6dSopenharmony_ci
2422e5b6d6dSopenharmony_cile_int32 FontMap::getDescent() const
2432e5b6d6dSopenharmony_ci{
2442e5b6d6dSopenharmony_ci    if (fDescent <= 0) {
2452e5b6d6dSopenharmony_ci        ((FontMap *) this)->getMaxMetrics();
2462e5b6d6dSopenharmony_ci    }
2472e5b6d6dSopenharmony_ci
2482e5b6d6dSopenharmony_ci    return fDescent;
2492e5b6d6dSopenharmony_ci}
2502e5b6d6dSopenharmony_ci
2512e5b6d6dSopenharmony_cile_int32 FontMap::getLeading() const
2522e5b6d6dSopenharmony_ci{
2532e5b6d6dSopenharmony_ci    if (fLeading <= 0) {
2542e5b6d6dSopenharmony_ci        ((FontMap *) this)->getMaxMetrics();
2552e5b6d6dSopenharmony_ci    }
2562e5b6d6dSopenharmony_ci
2572e5b6d6dSopenharmony_ci    return fLeading;
2582e5b6d6dSopenharmony_ci}
2592e5b6d6dSopenharmony_ci
2602e5b6d6dSopenharmony_civoid FontMap::getMaxMetrics()
2612e5b6d6dSopenharmony_ci{
2622e5b6d6dSopenharmony_ci    for (le_int32 i = 0; i < fFontCount; i += 1) {
2632e5b6d6dSopenharmony_ci        LEErrorCode status = LE_NO_ERROR;
2642e5b6d6dSopenharmony_ci        le_int32 ascent, descent, leading;
2652e5b6d6dSopenharmony_ci
2662e5b6d6dSopenharmony_ci        if (fFontInstances[i] == NULL) {
2672e5b6d6dSopenharmony_ci            fFontInstances[i] = openFont(fFontNames[i], fPointSize, status);
2682e5b6d6dSopenharmony_ci
2692e5b6d6dSopenharmony_ci            if (LE_FAILURE(status)) {
2702e5b6d6dSopenharmony_ci                continue;
2712e5b6d6dSopenharmony_ci            }
2722e5b6d6dSopenharmony_ci        }
2732e5b6d6dSopenharmony_ci
2742e5b6d6dSopenharmony_ci        ascent  = fFontInstances[i]->getAscent();
2752e5b6d6dSopenharmony_ci        descent = fFontInstances[i]->getDescent();
2762e5b6d6dSopenharmony_ci        leading = fFontInstances[i]->getLeading();
2772e5b6d6dSopenharmony_ci
2782e5b6d6dSopenharmony_ci        if (ascent > fAscent) {
2792e5b6d6dSopenharmony_ci            fAscent = ascent;
2802e5b6d6dSopenharmony_ci        }
2812e5b6d6dSopenharmony_ci
2822e5b6d6dSopenharmony_ci        if (descent > fDescent) {
2832e5b6d6dSopenharmony_ci            fDescent = descent;
2842e5b6d6dSopenharmony_ci        }
2852e5b6d6dSopenharmony_ci
2862e5b6d6dSopenharmony_ci        if (leading > fLeading) {
2872e5b6d6dSopenharmony_ci            fLeading = leading;
2882e5b6d6dSopenharmony_ci        }
2892e5b6d6dSopenharmony_ci    }
2902e5b6d6dSopenharmony_ci}
2912e5b6d6dSopenharmony_ci
292