Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7 andreas 1
/*
21 andreas 2
 * Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
7 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
67 andreas 19
#include <codecvt>
20
 
21
#include "tresources.h"
7 andreas 22
#include "tfont.h"
75 andreas 23
#include "texpat++.h"
7 andreas 24
#include "tconfig.h"
25
#include "terror.h"
68 andreas 26
#include "tnameformat.h"
7 andreas 27
 
28
#include <include/core/SkFontStyle.h>
29
 
67 andreas 30
#define FTABLE_DSIG     0x44534947
31
#define FTABLE_EBDT     0x45424454
32
#define FTABLE_EBLC     0x45424c43
33
#define FTABLE_GDEF     0x47444546
34
#define FTABLE_GPOS     0x47504f53
35
#define FTABLE_GSUB     0x47535542
36
#define FTABLE_LTSH     0x4c545348
37
#define FTABLE_OS_2     0x4f532f32
38
#define FTABLE_VDMX     0x56444d58
39
#define FTABLE_cmap     0x636d6170
40
#define FTABLE_cvt      0x63767420
41
#define FTABLE_fpgm     0x6670676d
42
#define FTABLE_gasp     0x67617370
43
#define FTABLE_glyf     0x676c7966
44
#define FTABLE_head     0x68656164
45
#define FTABLE_hhea     0x68686561
46
#define FTABLE_hmtx     0x686d7478
47
#define FTABLE_kern     0x6b65726e
48
#define FTABLE_loca     0x6c6f6361
49
#define FTABLE_maxp     0x6d617870
50
#define FTABLE_name     0x6e616d65
51
#define FTABLE_post     0x706f7374
52
#define FTABLE_prep     0x70726570
53
 
54
#define FTABLE_PID_UNICODE          0
55
#define FTABLE_PID_MACINTOSH        1
56
#define FTABLE_PID_MICROSOFT        3
57
 
58
#define FTABLE_SID_UNI_VERSION1     0
59
#define FTABLE_SID_UNI_VERSION2     1
60
#define FTABLE_SID_UNI_ISO10646     2
61
#define FTABLE_SID_UNI_UNI2BMP      3
62
#define FTABLE_SID_UNI_UNI2         4
63
#define FTABLE_SID_UNI_UNIVS        5
64
#define FTABLE_SID_UNI_LASTRES      6
65
 
66
#define FTABLE_SID_MSC_SYMBOL       0
67
#define FTABLE_SID_MSC_UNICODE      1
68
#define FTABLE_SID_MSC_SHIFTJIS     2
69
#define FTABLE_SID_MSC_PRC          3
70
#define FTABLE_SID_MSC_BIGFIVE      4
71
#define FTABLE_SID_MSC_JOHAB        5
72
#define FTABLE_SID_MSC_UNIUCS4      10
73
 
74
typedef struct FTABLE_FORMAT0_t
75
{
76
    uint16_t length;
77
    uint16_t language;
78
    unsigned char glyphIndex[256];
79
}FTABLE_FORMAT0_t;
80
 
81
typedef struct FTABLE_FORMAT4_t
82
{
83
    uint16_t length;
84
    uint16_t language;
85
    uint16_t segCountX2;
86
    uint16_t searchRange;
87
    uint16_t entrySelector;
88
    uint16_t rangeShift;
89
    uint16_t *endCode;
90
    uint16_t reservedPad;
91
    uint16_t *startCode;
92
    uint16_t *idDelta;
93
    uint16_t *idRangeOffset;
94
    uint16_t *glyphIndexArray;
95
}FTABLE_FORMAT4_t;
96
 
97
typedef struct FTABLE_FORMATS_t
98
{
99
    uint16_t format{0};
100
    union fdef
101
    {
102
        FTABLE_FORMAT0_t format0;
103
        FTABLE_FORMAT4_t format4;
104
    }fdef;
105
}FTABLE_FORMATS_t;
106
 
107
typedef struct FTABLE_SUBTABLE_t
108
{
109
    uint16_t platformID;
110
    uint16_t platformSpecificID;
111
    uint32_t offset;
112
    FTABLE_FORMATS_t format;
113
}FTABLE_SUBTABLE_t;
114
 
115
typedef struct FTABLE_CMAP_t
116
{
117
    uint16_t version{0};
118
    uint16_t numSubtables{0};
119
    FTABLE_SUBTABLE_t *subtables;
120
}FTABLE_CMAP_t;
121
 
7 andreas 122
using std::string;
51 andreas 123
using std::vector;
7 andreas 124
using std::map;
125
using std::pair;
75 andreas 126
using namespace Expat;
7 andreas 127
 
128
TFont::TFont()
129
{
130
    DECL_TRACER("TFont::TFont()");
131
    initialize();
132
}
133
 
134
TFont::~TFont()
135
{
136
    DECL_TRACER("TFont::~TFont()");
137
}
138
 
139
void TFont::initialize()
140
{
141
    DECL_TRACER("TFont::initialize()");
142
 
11 andreas 143
    if (mFonts.size() > 0)
144
        mFonts.clear();
145
 
7 andreas 146
    // System fonts first
147
    FONT_T font;
148
 
44 andreas 149
    if (!systemFonts())
150
    {
151
        TError::clear();
152
        MSG_INFO("Initializing virtual system fonts because no system files installed!");
7 andreas 153
 
44 andreas 154
        font.number = 1;
155
        font.file = "cour.ttf";
156
        font.faceIndex = 1;
157
        font.fullName = "Courier New";
158
        font.name = "Courier New";
159
        font.size = 9;
160
        font.subfamilyName = "normal";
161
        font.fileSize = 0;
162
        font.usageCount = 0;
163
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 164
 
44 andreas 165
        font.number = 2;
166
        font.faceIndex = 2;
167
        font.size = 12;
168
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 169
 
44 andreas 170
        font.number = 3;
171
        font.faceIndex = 3;
172
        font.size = 18;
173
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 174
 
44 andreas 175
        font.number = 4;
176
        font.faceIndex = 4;
177
        font.size = 26;
178
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 179
 
44 andreas 180
        font.number = 5;
181
        font.faceIndex = 5;
182
        font.size = 32;
183
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 184
 
44 andreas 185
        font.number = 6;
186
        font.faceIndex = 6;
187
        font.size = 18;
188
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 189
 
44 andreas 190
        font.number = 7;
191
        font.faceIndex = 7;
192
        font.size = 26;
193
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 194
 
44 andreas 195
        font.number = 8;
196
        font.faceIndex = 8;
197
        font.size = 34;
198
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 199
 
44 andreas 200
        font.number = 9;
201
        font.file = "Amxbold_.ttf";
202
        font.faceIndex = 9;
203
        font.fullName = "AMX Bold";
204
        font.name = "AMX Bold";
205
        font.size = 14;
206
        font.subfamilyName = "bold";
207
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 208
 
44 andreas 209
        font.number = 10;
210
        font.faceIndex = 10;
211
        font.size = 20;
212
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 213
 
44 andreas 214
        font.number = 11;
215
        font.faceIndex = 11;
216
        font.size = 36;
217
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 218
 
44 andreas 219
        font.number = 19;
220
        font.file = "arial.ttf";
221
        font.faceIndex = 19;
222
        font.fullName = "Arial";
223
        font.name = "Arial";
224
        font.size = 9;
225
        font.subfamilyName = "normal";
226
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 227
 
44 andreas 228
        font.number = 20;
229
        font.faceIndex = 20;
230
        font.size = 10;
231
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 232
 
44 andreas 233
        font.number = 21;
234
        font.faceIndex = 21;
235
        font.size = 12;
236
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 237
 
44 andreas 238
        font.number = 22;
239
        font.faceIndex = 22;
240
        font.size = 14;
241
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 242
 
44 andreas 243
        font.number = 23;
244
        font.faceIndex = 23;
245
        font.size = 16;
246
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 247
 
44 andreas 248
        font.number = 24;
249
        font.faceIndex = 24;
250
        font.size = 18;
251
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 252
 
44 andreas 253
        font.number = 25;
254
        font.faceIndex = 25;
255
        font.size = 20;
256
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 257
 
44 andreas 258
        font.number = 26;
259
        font.faceIndex = 26;
260
        font.size = 24;
261
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 262
 
44 andreas 263
        font.number = 27;
264
        font.faceIndex = 27;
265
        font.size = 36;
266
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 267
 
44 andreas 268
        font.number = 28;
269
        font.file = "arialbd.ttf";
270
        font.faceIndex = 28;
271
        font.fullName = "Arial Bold";
272
        font.name = "Arial Bold";
273
        font.size = 10;
274
        font.subfamilyName = "bold";
275
        mFonts.insert(pair<int, FONT_T>(font.number, font));
7 andreas 276
 
44 andreas 277
        font.number = 29;
278
        font.faceIndex = 29;
279
        font.size = 8;
280
        mFonts.insert(pair<int, FONT_T>(font.number, font));
281
    }
282
 
7 andreas 283
    // read the individual fonts from file
284
    TError::clear();
285
    string path = makeFileName(TConfig::getProjectPath(), "fnt.xma");
286
 
287
    if (!isValidFile())
288
    {
289
        MSG_ERROR("File " << path << " doesn't exist or is not readable!");
290
        TError::setError();
291
        return;
292
    }
293
 
75 andreas 294
    TExpat xml(path);
295
    xml.setEncoding(ENC_CP1250);
7 andreas 296
 
75 andreas 297
    if (!xml.parse())
7 andreas 298
        return;
299
 
75 andreas 300
    int depth = 0;
301
    size_t index = 0;
302
    size_t oldIndex = 0;
7 andreas 303
 
75 andreas 304
    if ((index = xml.getElementIndex("fontList", &depth)) == TExpat::npos)
7 andreas 305
    {
306
        MSG_DEBUG("File does not contain the element \"fontList\"!");
307
        TError::setError();
308
        return;
309
    }
310
 
75 andreas 311
    depth++;
7 andreas 312
 
75 andreas 313
    while ((index = xml.getNextElementIndex("font", depth)) != TExpat::npos)
7 andreas 314
    {
75 andreas 315
        string name, content;
316
        FONT_T ft;
317
        vector<ATTRIBUTE_t> attrs = xml.getAttributes(index);
7 andreas 318
 
75 andreas 319
        if (!attrs.empty())
320
            ft.number = xml.getAttributeInt("number", attrs);
321
        else
7 andreas 322
        {
75 andreas 323
            MSG_ERROR("Element font contains no or invalid attribute!");
324
            TError::setError();
325
            return;
326
        }
7 andreas 327
 
75 andreas 328
        while ((index = xml.getNextElementFromIndex(index, &name, &content, &attrs)) != TExpat::npos)
329
        {
330
            string e = name;
7 andreas 331
 
75 andreas 332
            if (e.compare("file") == 0)
333
                ft.file = content;
334
            else if (e.compare("fileSize") == 0)
335
                ft.fileSize = xml.convertElementToInt(content);
336
            else if (e.compare("faceIndex") == 0)
337
                ft.faceIndex = xml.convertElementToInt(content);
338
            else if (e.compare("name") == 0)
339
                ft.name = content;
340
            else if (e.compare("subfamilyName") == 0)
341
                ft.subfamilyName = content;
342
            else if (e.compare("fullName") == 0)
343
                ft.fullName = content;
344
            else if (e.compare("size") == 0)
345
                ft.size = xml.convertElementToInt(content);
346
            else if (e.compare("usageCount") == 0)
347
                ft.usageCount = xml.convertElementToInt(content);
7 andreas 348
 
75 andreas 349
            oldIndex = index;
350
        }
7 andreas 351
 
75 andreas 352
        mFonts.insert(pair<int, FONT_T>(ft.number, ft));
7 andreas 353
 
75 andreas 354
        if (index == TExpat::npos)
355
            index = oldIndex + 1;
7 andreas 356
 
75 andreas 357
        xml.setIndex(index);
7 andreas 358
    }
359
}
360
 
44 andreas 361
bool TFont::systemFonts()
362
{
363
    DECL_TRACER("TFont::systemFonts()");
364
 
365
    string path = makeFileName(TConfig::getProjectPath(), "__system/graphics/fnt.xma");
366
 
367
    if (!isValidFile())
368
    {
369
        MSG_ERROR("File " << path << " doesn't exist or is not readable!");
370
        TError::setError();
371
        return false;
372
    }
373
 
75 andreas 374
    TExpat xml(path);
375
    xml.setEncoding(ENC_CP1250);
44 andreas 376
 
75 andreas 377
    if (!xml.parse())
44 andreas 378
        return false;
379
 
75 andreas 380
    int depth = 0;
381
    size_t index = 0;
382
    size_t oldIndex = 0;
44 andreas 383
 
75 andreas 384
    if ((index = xml.getElementIndex("fontList", &depth)) == TExpat::npos)
44 andreas 385
    {
386
        MSG_DEBUG("File does not contain the element \"fontList\"!");
387
        TError::setError();
388
        return false;
389
    }
390
 
75 andreas 391
    depth++;
44 andreas 392
 
75 andreas 393
    while ((index = xml.getNextElementIndex("font", depth)) != TExpat::npos)
44 andreas 394
    {
75 andreas 395
        string name, content;
396
        FONT_T ft;
397
        vector<ATTRIBUTE_t> attrs = xml.getAttributes(index);
44 andreas 398
 
75 andreas 399
        if (!attrs.empty())
400
            ft.number = xml.getAttributeInt("number", attrs);
401
        else
44 andreas 402
        {
75 andreas 403
            MSG_ERROR("Element font contains no or invalid attribute!");
404
            TError::setError();
405
            return false;
406
        }
44 andreas 407
 
75 andreas 408
        while ((index = xml.getNextElementFromIndex(index, &name, &content, &attrs)) != TExpat::npos)
409
        {
410
            string e = name;
44 andreas 411
 
75 andreas 412
            if (e.compare("file") == 0)
413
                ft.file = content;
414
            else if (e.compare("fileSize") == 0)
415
                ft.fileSize = xml.convertElementToInt(content);
416
            else if (e.compare("faceIndex") == 0)
417
                ft.faceIndex = xml.convertElementToInt(content);
418
            else if (e.compare("name") == 0)
419
                ft.name = content;
420
            else if (e.compare("subfamilyName") == 0)
421
                ft.subfamilyName = content;
422
            else if (e.compare("fullName") == 0)
423
                ft.fullName = content;
424
            else if (e.compare("size") == 0)
425
                ft.size = xml.convertElementToInt(content);
426
            else if (e.compare("usageCount") == 0)
427
                ft.usageCount = xml.convertElementToInt(content);
44 andreas 428
 
75 andreas 429
            oldIndex = index;
430
        }
44 andreas 431
 
75 andreas 432
        mFonts.insert(pair<int, FONT_T>(ft.number, ft));
44 andreas 433
 
75 andreas 434
        if (index == TExpat::npos)
435
            index = oldIndex + 1;
44 andreas 436
 
75 andreas 437
        xml.setIndex(index);
44 andreas 438
    }
439
 
440
    return true;
441
}
442
 
7 andreas 443
FONT_T TFont::getFont(int number)
444
{
445
    DECL_TRACER("TFont::getFont(int number)");
446
 
447
    if (mFonts.size() == 0)
448
    {
449
        MSG_WARNING("No fonts found!");
450
        return FONT_T();
451
    }
452
 
453
    map<int, FONT_T>::iterator iter = mFonts.find(number);
454
 
455
    if (iter == mFonts.end())
40 andreas 456
    {
457
        MSG_WARNING("No font with number " << number << " found!");
7 andreas 458
        return FONT_T();
40 andreas 459
    }
7 andreas 460
 
461
    return iter->second;
462
}
463
 
464
FONT_STYLE TFont::getStyle(int number)
465
{
466
    DECL_TRACER("TFont::getStyle(int number)");
467
 
468
    map<int, FONT_T>::iterator iter = mFonts.find(number);
469
 
470
    if (iter == mFonts.end())
471
        return FONT_NONE;
472
 
473
    if (iter->second.subfamilyName.compare("Regular") == 0)
474
        return FONT_NORMAL;
475
    else if (iter->second.subfamilyName.compare("Italic") == 0)
476
        return FONT_ITALIC;
477
    else if (iter->second.subfamilyName.compare("Bold") == 0)
478
        return FONT_BOLD;
479
    else if (iter->second.subfamilyName.compare("Bold Italic") == 0)
480
        return FONT_BOLD_ITALIC;
481
 
482
    return FONT_NORMAL;
483
}
484
 
485
FONT_STYLE TFont::getStyle(FONT_T& font)
486
{
487
    DECL_TRACER("TFont::getStyle(int number)");
488
 
489
    if (font.subfamilyName.compare("Regular") == 0)
490
        return FONT_NORMAL;
491
    else if (font.subfamilyName.compare("Italic") == 0)
492
        return FONT_ITALIC;
493
    else if (font.subfamilyName.compare("Bold") == 0)
494
        return FONT_BOLD;
495
    else if (font.subfamilyName.compare("Bold Italic") == 0)
496
        return FONT_BOLD_ITALIC;
497
 
498
    return FONT_NORMAL;
499
}
500
 
40 andreas 501
SkFontStyle TFont::getSkiaStyle(int number)
502
{
503
    DECL_TRACER("TFont::getSkiaStyle(int number)");
7 andreas 504
 
40 andreas 505
    map<int, FONT_T>::iterator iter = mFonts.find(number);
506
 
507
    if (iter == mFonts.end())
508
        return SkFontStyle(SkFontStyle::kInvisible_Weight, SkFontStyle::kUltraCondensed_Width, SkFontStyle::kUpright_Slant);
509
 
510
    if (iter->second.subfamilyName.compare("Regular") == 0)
511
        return SkFontStyle::Normal();
512
    else if (iter->second.subfamilyName.compare("Italic") == 0)
513
        return SkFontStyle::Italic();
514
    else if (iter->second.subfamilyName.compare("Bold") == 0)
515
        return SkFontStyle::Bold();
516
    else if (iter->second.subfamilyName.compare("Bold Italic") == 0)
517
        return SkFontStyle::BoldItalic();
518
 
519
    return SkFontStyle::Normal();
520
}
521
 
7 andreas 522
#define MAX_FACES   10
523
 
524
sk_sp<SkTypeface> TFont::getTypeFace(int number)
525
{
526
    DECL_TRACER("TFont::getTypeFace(int number)");
527
 
528
    map<int, FONT_T>::iterator iter = mFonts.find(number);
529
 
530
    if (iter == mFonts.end())
531
    {
532
        MSG_ERROR("No font with index " << number << " found!");
533
        TError::setError();
534
        return sk_sp<SkTypeface>();
535
    }
536
 
45 andreas 537
    string path;
538
 
539
    if (number < 32)    // System font?
540
        path = TConfig::getProjectPath() + "/__system/graphics/fonts/" + iter->second.file;
541
    else
542
        path = TConfig::getProjectPath() + "/fonts/" + iter->second.file;
543
 
7 andreas 544
    sk_sp<SkTypeface> tf;
545
    MSG_TRACE("Loading font \"" << path << "\" ...");
546
 
45 andreas 547
    if (isValidFile(path))
67 andreas 548
        tf = MakeResourceAsTypeface(path.c_str(), iter->second.faceIndex);
45 andreas 549
    else
550
        MSG_WARNING("File " << path << " is not a valid file or does not exist!");
551
 
7 andreas 552
    if (!tf)
553
    {
554
        MSG_ERROR("Error loading font \"" << path << "\"");
40 andreas 555
        MSG_TRACE("Trying with alternative function ...");
7 andreas 556
        TError::setError();
40 andreas 557
 
558
        tf = SkTypeface::MakeFromName(iter->second.fullName.c_str(), getSkiaStyle(number));
559
 
560
        if (tf)
561
            TError::clear();
562
        else
45 andreas 563
        {
564
            MSG_ERROR("Alternative method failed loading the font " << iter->second.fullName);
40 andreas 565
            return tf;
45 andreas 566
        }
7 andreas 567
    }
568
    else
569
    {
570
        MSG_TRACE("Font \"" << path << "\" was loaded successfull.");
571
    }
572
 
573
    SkString sname;
574
    tf->getFamilyName(&sname);
575
    MSG_DEBUG("Found font name \"" << sname.c_str() << "\" with attributes: bold=" << ((tf->isBold())?"TRUE":"FALSE") << ", italic=" << ((tf->isItalic())?"TRUE":"FALSE") << ", fixed=" << ((tf->isFixedPitch())?"TRUE":"FALSE"));
576
 
577
    if (iter->second.name.compare(sname.c_str()) != 0)
578
    {
579
        MSG_WARNING("The loaded font \"" << sname.c_str() << "\" is not the wanted font \"" << iter->second.name << "\"!");
580
    }
581
 
582
    FONT_STYLE style = getStyle(iter->second);
583
 
584
    if (style == FONT_BOLD && tf->isBold())
585
        return tf;
586
    else if (style == FONT_ITALIC && tf->isItalic())
587
        return tf;
588
    else if (style == FONT_BOLD_ITALIC && tf->isBold() && tf->isItalic())
589
        return tf;
590
    else if (style == FONT_NORMAL && !tf->isBold() && !tf->isItalic())
591
        return tf;
592
 
593
    MSG_WARNING("The wanted font style " << iter->second.subfamilyName << " was not found!");
594
    return tf;
595
}
51 andreas 596
 
597
vector<string> TFont::getFontPathList()
598
{
599
    DECL_TRACER("TFont::getFontPathList()");
600
 
601
    vector<string> list;
602
    string path = TConfig::getProjectPath() + "/fonts";
603
    list.push_back(path);
604
    path = TConfig::getProjectPath() + "/__system/graphics/fonts";
605
    list.push_back(path);
606
    return list;
607
}
67 andreas 608
 
609
size_t _numTables;
610
FTABLE_CMAP_t _cmapTable;
611
 
612
void TFont::parseCmap(const unsigned char* cmaps)
613
{
614
    DECL_TRACER("TFont::parseCmap(const unsigned char* cmaps)");
615
 
616
    if (!cmaps)
617
        return;
618
 
619
    _cmapTable.version = getUint16(cmaps);
620
    _cmapTable.numSubtables = getUint16(cmaps+sizeof(uint16_t));
621
    MSG_DEBUG("Found version " << _cmapTable.version << ", found " << _cmapTable.numSubtables << " cmap tables.");
622
    _cmapTable.subtables = new FTABLE_SUBTABLE_t[_cmapTable.numSubtables];
623
    size_t pos = sizeof(uint16_t) * 2;
624
 
625
    for (uint16_t i = 0; i < _cmapTable.numSubtables; i++)
626
    {
627
        FTABLE_SUBTABLE_t st;
628
        st.platformID = getUint16(cmaps+pos);
629
        pos += sizeof(uint16_t);
630
        st.platformSpecificID = getUint16(cmaps+pos);
631
        pos += sizeof(uint16_t);
632
        st.offset = getUint32(cmaps+pos);
633
        pos += sizeof(uint32_t);
634
        memmove(&_cmapTable.subtables[i], &st, sizeof(st));
635
        MSG_DEBUG("Table " << (i+1) << ": platformID=" << st.platformID << ", platformSpecificID=" << st.platformSpecificID << ", offset=" << st.offset);
636
    }
637
 
638
    // Get the format and read the mapping
639
    for (uint16_t i = 0; i < _cmapTable.numSubtables; i++)
640
    {
641
        if (_cmapTable.subtables[i].platformID == FTABLE_PID_MACINTOSH)   // We ignore old Macintosh format
642
        {
643
            _cmapTable.subtables[i].format.format = -1;
644
            continue;
645
        }
646
 
647
        FTABLE_FORMATS_t format;
648
        format.format = getUint16(cmaps+_cmapTable.subtables[i].offset);
649
        pos = _cmapTable.subtables[i].offset + sizeof(uint16_t);
650
 
651
        switch(format.format)
652
        {
653
            case 0:
654
                format.fdef.format0.length = getUint16(cmaps+pos);
655
                pos += sizeof(uint16_t);
656
                format.fdef.format0.language = getUint16(cmaps+pos);
657
                pos += sizeof(uint16_t);
658
                memcpy(format.fdef.format0.glyphIndex, cmaps+pos, sizeof(format.fdef.format0.glyphIndex));
659
            break;
660
 
661
            case 4:
662
                format.fdef.format4.length = getUint16(cmaps+pos);
663
                pos += sizeof(uint16_t);
664
                format.fdef.format4.language = getUint16(cmaps+pos);
665
                pos += sizeof(uint16_t);
666
                format.fdef.format4.segCountX2 = getUint16(cmaps+pos);
667
                pos += sizeof(uint16_t);
668
                format.fdef.format4.searchRange = getUint16(cmaps+pos);
669
                pos += sizeof(uint16_t);
670
                format.fdef.format4.entrySelector = getUint16(cmaps+pos);
671
                pos += sizeof(uint16_t);
672
                format.fdef.format4.rangeShift = getUint16(cmaps+pos);
673
                pos += sizeof(uint16_t);
674
                uint16_t segCount = format.fdef.format4.segCountX2 / 2;
675
                format.fdef.format4.endCode = new uint16_t[segCount];
676
 
677
                for (uint16_t j = 0; j < segCount; j++)
678
                {
679
                    format.fdef.format4.endCode[j] = getUint16(cmaps+pos);
680
                    pos += sizeof(uint16_t);
681
                }
682
 
683
                format.fdef.format4.reservedPad = getUint16(cmaps+pos);
684
                pos += sizeof(uint16_t);
685
                format.fdef.format4.startCode = new uint16_t[segCount];
686
 
687
                for (uint16_t j = 0; j < segCount; j++)
688
                {
689
                    format.fdef.format4.startCode[j] = getUint16(cmaps+pos);
690
                    pos += sizeof(uint16_t);
691
                }
692
 
693
                format.fdef.format4.idDelta = new uint16_t[segCount];
694
 
695
                for (uint16_t j = 0; j < segCount; j++)
696
                {
697
                    format.fdef.format4.idDelta[j] = getUint16(cmaps+pos);
698
                    pos += sizeof(uint16_t);
699
                }
700
 
701
                format.fdef.format4.idRangeOffset = new uint16_t[segCount];
702
 
703
                for (uint16_t j = 0; j < segCount; j++)
704
                {
705
                    format.fdef.format4.idRangeOffset[j] = getUint16(cmaps+pos);
706
                    pos += sizeof(uint16_t);
707
                }
708
 
709
                format.fdef.format4.glyphIndexArray = (uint16_t *)(cmaps+pos);
710
                memcpy(&_cmapTable.subtables[i].format, &format, sizeof(FTABLE_FORMATS_t));
711
            break;
712
        }
713
    }
714
}
715
 
716
uint16_t TFont::getGlyphIndex(SkUnichar ch)
717
{
718
    DECL_TRACER("TFont::getGlyphIndex(const char* ch)");
719
 
68 andreas 720
    uint16_t lCh = ch;
67 andreas 721
    bool symbol = false;
722
 
723
    for (uint16_t nTbs = 0; nTbs < _cmapTable.numSubtables; nTbs++)
724
    {
725
        if (_cmapTable.subtables[nTbs].platformID == FTABLE_PID_UNICODE ||
726
            _cmapTable.subtables[nTbs].platformID == FTABLE_PID_MICROSOFT)
727
        {
728
            if ((_cmapTable.subtables[nTbs].platformID == FTABLE_PID_UNICODE &&_cmapTable.subtables[nTbs].platformSpecificID == FTABLE_SID_UNI_VERSION1) ||
729
                (_cmapTable.subtables[nTbs].platformID == FTABLE_PID_MICROSOFT && _cmapTable.subtables[nTbs].platformSpecificID == FTABLE_SID_MSC_SYMBOL))
730
                symbol = true;  // Table does not have unicode table mapping (wingding)
731
 
732
            // Find the segment where the wanted character is in.
733
            if (_cmapTable.subtables[nTbs].format.format == 4)
734
            {
735
                FTABLE_FORMAT4_t form = _cmapTable.subtables[nTbs].format.fdef.format4;
736
                uint16_t segCount = form.segCountX2 / 2;
737
                uint16_t segment = 0xffff;
68 andreas 738
                MSG_DEBUG("segCountX2: " << form.segCountX2 << ", # segments: " << segCount);
67 andreas 739
 
740
                for (uint16_t sc = 0; sc < segCount; sc++)
741
                {
742
                    MSG_DEBUG("Table: " << nTbs << ": Checking range " << std::hex << std::setw(4) << std::setfill('0') << form.startCode[sc] << " to " << std::setw(4) << std::setfill('0') << form.endCode[sc] << std::dec);
743
 
744
                    if (symbol)
745
                    {
746
                        if (ch <= 0x00ff)
747
                            lCh = ch + (form.startCode[sc] & 0xff00);
748
                        else
749
                            lCh = ch + (form.startCode[sc] & 0xf000);
750
                    }
751
 
752
                    if (lCh >= form.startCode[sc] && lCh <= form.endCode[sc])
753
                    {
754
                        segment = sc;
755
                        break;
756
                    }
757
                }
758
 
759
                if (segment == 0xffff || form.startCode[segment] == 0xffff || form.endCode[segment] == 0xffff)
760
                {
761
                    MSG_WARNING("The character " << std::hex << std::setw(4) << std::setfill('0') << lCh << " is not supported by any segment!" << std::dec);
76 andreas 762
                    continue;
763
//                    return 0xffff;
67 andreas 764
                }
765
 
76 andreas 766
                MSG_DEBUG("Table: " << (nTbs+1) << ": idRangeOffset: " << std::hex << std::setw(4) << std::setfill('0') << form.idRangeOffset[segment] << ", idDelta: " << std::setw(4) << std::setfill('0') << form.idDelta[segment] << std::dec);
67 andreas 767
                uint16_t glyphIndex;
768
 
769
                if (form.idRangeOffset[segment] == 0)
770
                    glyphIndex = form.idDelta[segment] + lCh;
771
                else
68 andreas 772
                {
773
                    uint16_t gArray = getUint16((unsigned char *)(form.glyphIndexArray + (form.idRangeOffset[segment] / 2)));
774
                    MSG_DEBUG("Value from glyphArray: " << std::hex << std::setw(4) << std::setfill('0') << gArray);
67 andreas 775
 
68 andreas 776
                    if (symbol && segment > 0 && gArray != 0)
777
                        glyphIndex = gArray + (lCh - form.startCode[segment]) - 2;
778
                    else
779
                        glyphIndex = gArray / 2 + (lCh - form.startCode[segment]);
780
                }
781
 
67 andreas 782
                MSG_DEBUG("Found index 0x" << std::hex << std::setw(4) << std::setfill('0') << glyphIndex << " for unichar 0x" << std::setw(4) << std::setfill('0') << lCh << std::dec);
783
                return glyphIndex;
784
            }
76 andreas 785
            else
786
            {
787
                MSG_WARNING("Ignoring table with unsupported format " << _cmapTable.subtables[nTbs].format.format);
788
            }
67 andreas 789
        }
790
    }
791
 
792
    return 0xffff;
793
}
794
 
795
void TFont::_freeCmap()
796
{
797
    DECL_TRACER("TFont::_freeCmap()");
798
 
799
    for (uint16_t nTbs = 0; nTbs < _cmapTable.numSubtables; nTbs++)
800
    {
801
        if (_cmapTable.subtables[nTbs].platformID == FTABLE_PID_UNICODE ||
802
            _cmapTable.subtables[nTbs].platformID == FTABLE_PID_MICROSOFT)
803
        {
804
            if (_cmapTable.subtables[nTbs].format.format == 4)
805
            {
806
                delete[] _cmapTable.subtables[nTbs].format.fdef.format4.endCode;
807
                delete[] _cmapTable.subtables[nTbs].format.fdef.format4.startCode;
808
                delete[] _cmapTable.subtables[nTbs].format.fdef.format4.idDelta;
809
                delete[] _cmapTable.subtables[nTbs].format.fdef.format4.idRangeOffset;
810
            }
811
        }
812
    }
813
 
814
    delete[] _cmapTable.subtables;
815
}
816
 
817
SkGlyphID *TFont::textToGlyphs(const string& str, sk_sp<SkTypeface>& typeFace, size_t *size)
818
{
819
    DECL_TRACER("TFont::textToGlyphs(const string& str, SkTypeface& typeFace)");
820
 
821
    *size = 0;
822
    int tables = typeFace->countTables();
823
    SkFontTableTag *tbTags = new SkFontTableTag[tables];
824
    int tags = typeFace->getTableTags(tbTags);
825
    bool haveCmap = false;
826
    unsigned char *cmaps = nullptr;
827
 
828
    // Find the "cmap" and the "glyph" tables and get them
829
    for (int i = 0; i < tags; i++)
830
    {
831
        SkFontTableTag fttg = tbTags[i];
832
 
833
        if (fttg == FTABLE_cmap)
834
        {
835
            size_t tbSize = typeFace->getTableSize(fttg);
836
            cmaps = new unsigned char[tbSize];
837
            typeFace->getTableData(fttg, 0, tbSize, cmaps);
838
            haveCmap = true;
839
            break;
840
        }
841
    }
842
 
843
    if (!haveCmap)
844
    {
845
        MSG_ERROR("Invalid font. Missing CMAP table!");
846
        TError::setError();
847
        delete[] tbTags;
848
        return nullptr;
849
    }
850
 
851
    delete[] tbTags;
852
    parseCmap(cmaps);
853
 
854
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
855
    std::u16string dest = convert.from_bytes(str);
856
    SkGlyphID *gIds = new SkGlyphID[dest.length()];
857
    *size = dest.length();
858
 
859
    for (size_t i = 0; i < dest.length(); i++)
860
    {
861
        SkUnichar uniChar = (SkUnichar)dest[i];
862
        gIds[i] = getGlyphIndex(uniChar);
863
    }
864
 
865
    _freeCmap();
866
    delete[] cmaps;
867
 
868
    return gIds;
869
}
870
 
871
bool TFont::isSymbol(sk_sp<SkTypeface>& typeFace)
872
{
873
    DECL_TRACER("TFont::isSymbol(sk_sp<SkTypeface>& typeFace)");
874
 
875
    int tables = typeFace->countTables();
876
    SkFontTableTag *tbTags = new SkFontTableTag[tables];
877
    int tags = typeFace->getTableTags(tbTags);
878
    bool haveCmap = false;
879
    unsigned char *cmaps = nullptr;
880
 
881
    // Find the "cmap" table and get them
882
    for (int i = 0; i < tags; i++)
883
    {
884
        SkFontTableTag fttg = tbTags[i];
885
 
886
        if (fttg == FTABLE_cmap)
887
        {
888
            size_t tbSize = typeFace->getTableSize(fttg);
889
            cmaps = new unsigned char[tbSize];
890
            typeFace->getTableData(fttg, 0, tbSize, cmaps);
891
            haveCmap = true;
892
            break;
893
        }
894
    }
895
 
896
    if (!haveCmap)
897
    {
898
        MSG_ERROR("Invalid font. Missing CMAP table!");
899
        TError::setError();
900
        delete[] tbTags;
901
        return false;
902
    }
903
 
904
    delete[] tbTags;
905
    parseCmap(cmaps);
906
 
907
    for (uint16_t nTbs = 0; nTbs < _cmapTable.numSubtables; nTbs++)
908
    {
909
        if ((_cmapTable.subtables[nTbs].platformID == FTABLE_PID_UNICODE && _cmapTable.subtables[nTbs].platformSpecificID == FTABLE_SID_UNI_VERSION1) ||
910
            (_cmapTable.subtables[nTbs].platformID == FTABLE_PID_MICROSOFT && _cmapTable.subtables[nTbs].platformSpecificID == FTABLE_SID_MSC_SYMBOL))
911
        {
912
            _freeCmap();
913
            delete[] cmaps;
914
            return true;
915
        }
916
    }
917
 
918
    _freeCmap();
919
    delete[] cmaps;
920
    return false;
921
}
922
 
923
size_t TFont::utf8ToUtf16(const string& str, uint16_t **uni, bool toSymbol)
924
{
925
    DECL_TRACER("TFont::utf8ToUtf16(const string& str, uint16_t **uni, bool toSymbol)");
926
 
927
    if (str.empty() || !uni)
928
    {
929
        *uni = nullptr;
930
        return 0;
931
    }
932
 
933
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
934
    std::u16string dest = convert.from_bytes(str);
935
 
936
    *uni = new uint16_t[dest.length()+1];
937
    memset(*uni, 0, sizeof(SkUnichar) * (dest.length()+1));
938
 
939
    for (size_t i = 0; i < dest.length(); i++)
940
    {
941
        *uni[i] = dest[i];
942
 
943
        if (toSymbol && *uni[i] < 0xf000)
944
            *uni[i] += 0xf000;
945
    }
946
 
947
    return dest.length();
948
}