1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 1999-2015, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
10 * file name: PortableFontInstance.cpp
12 * created on: 11/22/1999
13 * created by: Eric R. Mader
18 #include "layout/LETypes.h"
19 #include "layout/LEFontInstance.h"
20 #include "layout/LESwaps.h"
22 #include "PortableFontInstance.h"
31 static const char *letagToStr(LETag tag
, char *str
) {
32 str
[0]= 0xFF & (tag
>>24);
33 str
[1]= 0xFF & (tag
>>16);
34 str
[2]= 0xFF & (tag
>>8);
35 str
[3]= 0xFF & (tag
>>0);
42 // Finds the high bit by binary searching
43 // through the bits in n.
45 le_int8
PortableFontInstance::highBit(le_int32 value
)
53 if (value
>= 1 << 16) {
58 if (value
>= 1 << 8) {
63 if (value
>= 1 << 4) {
68 if (value
>= 1 << 2) {
73 if (value
>= 1 << 1) {
81 PortableFontInstance::PortableFontInstance(const char *fileName
, float pointSize
, LEErrorCode
&status
)
82 : fFile(NULL
), fPointSize(pointSize
), fUnitsPerEM(0), fFontChecksum(0), fAscent(0), fDescent(0), fLeading(0),
83 fDirectory(NULL
), fNAMETable(NULL
), fNameCount(0), fNameStringOffset(0), fCMAPMapper(NULL
), fHMTXTable(NULL
), fNumGlyphs(0), fNumLongHorMetrics(0)
85 if (LE_FAILURE(status
)) {
90 fFile
= fopen(fileName
, "rb");
91 //printf("Open Font: %s\n", fileName);
94 printf("%s:%d: %s: FNF\n", __FILE__
, __LINE__
, fileName
);
95 status
= LE_FONT_FILE_NOT_FOUND_ERROR
;
99 // read in the directory
100 SFNTDirectory tempDir
;
102 size_t numRead
= fread(&tempDir
, sizeof tempDir
, 1, fFile
);
105 le_int32 dirSize
= sizeof tempDir
+ ((SWAPW(tempDir
.numTables
) - ANY_NUMBER
) * sizeof(DirectoryEntry
));
106 const LETag headTag
= LE_HEAD_TABLE_TAG
;
107 const LETag hheaTag
= LE_HHEA_TABLE_TAG
;
108 const HEADTable
*headTable
= NULL
;
109 const HHEATable
*hheaTable
= NULL
;
110 // const NAMETable *nameTable = NULL;
111 le_uint16 numTables
= 0;
113 fDirectory
= (const SFNTDirectory
*) LE_NEW_ARRAY(char, dirSize
);
115 if (fDirectory
== NULL
) {
116 printf("%s:%d: %s: malloc err\n", __FILE__
, __LINE__
, fileName
);
117 status
= LE_MEMORY_ALLOCATION_ERROR
;
121 fseek(fFile
, 0L, SEEK_SET
);
122 numRead
= fread((void *) fDirectory
, sizeof(char), dirSize
, fFile
);
125 // We calculate these numbers 'cause some fonts
126 // have bogus values for them in the directory header.
128 numTables
= SWAPW(fDirectory
->numTables
);
129 fDirPower
= 1 << highBit(numTables
);
130 fDirExtra
= numTables
- fDirPower
;
132 // read unitsPerEm from 'head' table
133 headTable
= (const HEADTable
*) readFontTable(headTag
);
135 if (headTable
== NULL
) {
136 status
= LE_MISSING_FONT_TABLE_ERROR
;
137 printf("%s:%d: %s: missing head table\n", __FILE__
, __LINE__
, fileName
);
141 fUnitsPerEM
= SWAPW(headTable
->unitsPerEm
);
142 fFontChecksum
= SWAPL(headTable
->checksumAdjustment
);
143 freeFontTable(headTable
);
145 //nameTable = (NAMETable *) readFontTable(nameTag);
147 //if (nameTable == NULL) {
148 // status = LE_MISSING_FONT_TABLE_ERROR;
152 //fFontVersionString = findName(nameTable, NAME_VERSION_STRING, PLATFORM_MACINTOSH, MACINTOSH_ROMAN, MACINTOSH_ENGLISH);
154 //if (fFontVersionString == NULL) {
155 // status = LE_MISSING_FONT_TABLE_ERROR;
159 //freeFontTable(nameTable);
161 hheaTable
= (HHEATable
*) readFontTable(hheaTag
);
163 if (hheaTable
== NULL
) {
164 printf("%s:%d: %s: missing hhea table\n", __FILE__
, __LINE__
, fileName
);
165 status
= LE_MISSING_FONT_TABLE_ERROR
;
169 fAscent
= (le_int32
) yUnitsToPoints((float) SWAPW(hheaTable
->ascent
));
170 fDescent
= (le_int32
) yUnitsToPoints((float) SWAPW(hheaTable
->descent
));
171 fLeading
= (le_int32
) yUnitsToPoints((float) SWAPW(hheaTable
->lineGap
));
173 fNumLongHorMetrics
= SWAPW(hheaTable
->numOfLongHorMetrics
);
175 freeFontTable((void *) hheaTable
);
177 fCMAPMapper
= findUnicodeMapper();
179 if (fCMAPMapper
== NULL
) {
180 printf("%s:%d: %s: can't load cmap\n", __FILE__
, __LINE__
, fileName
);
181 status
= LE_MISSING_FONT_TABLE_ERROR
;
193 PortableFontInstance::~PortableFontInstance()
198 freeFontTable(fHMTXTable
);
199 freeFontTable(fNAMETable
);
203 LE_DELETE_ARRAY(fDirectory
);
207 const DirectoryEntry
*PortableFontInstance::findTable(LETag tag
) const
209 if (fDirectory
!= NULL
) {
211 le_uint16 probe
= fDirPower
;
213 if (SWAPL(fDirectory
->tableDirectory
[fDirExtra
].tag
) <= tag
) {
217 while (probe
> (1 << 0)) {
220 if (SWAPL(fDirectory
->tableDirectory
[table
+ probe
].tag
) <= tag
) {
225 if (SWAPL(fDirectory
->tableDirectory
[table
].tag
) == tag
) {
226 return &fDirectory
->tableDirectory
[table
];
233 const void *PortableFontInstance::readTable(LETag tag
, le_uint32
*length
) const
235 const DirectoryEntry
*entry
= findTable(tag
);
242 *length
= SWAPL(entry
->length
);
244 void *table
= LE_NEW_ARRAY(char, *length
);
247 fseek(fFile
, SWAPL(entry
->offset
), SEEK_SET
);
248 size_t numRead
= fread(table
, sizeof(char), *length
, fFile
);
255 const void *PortableFontInstance::getFontTable(LETag tableTag
, size_t &length
) const
257 return FontTableCache::find(tableTag
, length
);
260 const void *PortableFontInstance::readFontTable(LETag tableTag
, size_t &length
) const
264 const void *data
= readTable(tableTag
, &len
);
267 //printf("Read %s, result %p #%d\n", letagToStr(tableTag,tag5), data,len);
271 CMAPMapper
*PortableFontInstance::findUnicodeMapper()
273 LETag cmapTag
= LE_CMAP_TABLE_TAG
;
274 const CMAPTable
*cmap
= (CMAPTable
*) readFontTable(cmapTag
);
280 return CMAPMapper::createUnicodeMapper(cmap
);
283 const char *PortableFontInstance::getNameString(le_uint16 nameID
, le_uint16 platformID
, le_uint16 encodingID
, le_uint16 languageID
) const
285 if (fNAMETable
== NULL
) {
286 LETag nameTag
= LE_NAME_TABLE_TAG
;
287 PortableFontInstance
*realThis
= (PortableFontInstance
*) this;
289 realThis
->fNAMETable
= (const NAMETable
*) readFontTable(nameTag
);
291 if (realThis
->fNAMETable
!= NULL
) {
292 realThis
->fNameCount
= SWAPW(realThis
->fNAMETable
->count
);
293 realThis
->fNameStringOffset
= SWAPW(realThis
->fNAMETable
->stringOffset
);
297 for(le_int32 i
= 0; i
< fNameCount
; i
+= 1) {
298 const NameRecord
*nameRecord
= &fNAMETable
->nameRecords
[i
];
300 if (SWAPW(nameRecord
->platformID
) == platformID
&& SWAPW(nameRecord
->encodingID
) == encodingID
&&
301 SWAPW(nameRecord
->languageID
) == languageID
&& SWAPW(nameRecord
->nameID
) == nameID
) {
302 char *name
= ((char *) fNAMETable
) + fNameStringOffset
+ SWAPW(nameRecord
->offset
);
303 le_uint16 length
= SWAPW(nameRecord
->length
);
304 char *result
= LE_NEW_ARRAY(char, length
+ 2);
306 LE_ARRAY_COPY(result
, name
, length
);
307 result
[length
] = result
[length
+ 1] = 0;
316 const LEUnicode16
*PortableFontInstance::getUnicodeNameString(le_uint16 nameID
, le_uint16 platformID
, le_uint16 encodingID
, le_uint16 languageID
) const
318 if (fNAMETable
== NULL
) {
319 LETag nameTag
= LE_NAME_TABLE_TAG
;
320 PortableFontInstance
*realThis
= (PortableFontInstance
*) this;
322 realThis
->fNAMETable
= (const NAMETable
*) readFontTable(nameTag
);
324 if (realThis
->fNAMETable
!= NULL
) {
325 realThis
->fNameCount
= SWAPW(realThis
->fNAMETable
->count
);
326 realThis
->fNameStringOffset
= SWAPW(realThis
->fNAMETable
->stringOffset
);
330 for(le_int32 i
= 0; i
< fNameCount
; i
+= 1) {
331 const NameRecord
*nameRecord
= &fNAMETable
->nameRecords
[i
];
333 if (SWAPW(nameRecord
->platformID
) == platformID
&& SWAPW(nameRecord
->encodingID
) == encodingID
&&
334 SWAPW(nameRecord
->languageID
) == languageID
&& SWAPW(nameRecord
->nameID
) == nameID
) {
335 LEUnicode16
*name
= (LEUnicode16
*) (((char *) fNAMETable
) + fNameStringOffset
+ SWAPW(nameRecord
->offset
));
336 le_uint16 length
= SWAPW(nameRecord
->length
) / 2;
337 LEUnicode16
*result
= LE_NEW_ARRAY(LEUnicode16
, length
+ 2);
339 for (le_int32 c
= 0; c
< length
; c
+= 1) {
340 result
[c
] = SWAPW(name
[c
]);
352 void PortableFontInstance::deleteNameString(const char *name
) const
354 LE_DELETE_ARRAY(name
);
357 void PortableFontInstance::deleteNameString(const LEUnicode16
*name
) const
359 LE_DELETE_ARRAY(name
);
362 void PortableFontInstance::getGlyphAdvance(LEGlyphID glyph
, LEPoint
&advance
) const
364 TTGlyphID ttGlyph
= (TTGlyphID
) LE_GET_GLYPH(glyph
);
366 if (fHMTXTable
== NULL
) {
367 LETag maxpTag
= LE_MAXP_TABLE_TAG
;
368 LETag hmtxTag
= LE_HMTX_TABLE_TAG
;
369 const MAXPTable
*maxpTable
= (MAXPTable
*) readFontTable(maxpTag
);
370 PortableFontInstance
*realThis
= (PortableFontInstance
*) this;
372 if (maxpTable
!= NULL
) {
373 realThis
->fNumGlyphs
= SWAPW(maxpTable
->numGlyphs
);
374 freeFontTable(maxpTable
);
377 realThis
->fHMTXTable
= (const HMTXTable
*) readFontTable(hmtxTag
);
380 le_uint16 index
= ttGlyph
;
382 if (ttGlyph
>= fNumGlyphs
|| fHMTXTable
== NULL
) {
383 advance
.fX
= advance
.fY
= 0;
387 if (ttGlyph
>= fNumLongHorMetrics
) {
388 index
= fNumLongHorMetrics
- 1;
391 advance
.fX
= xUnitsToPoints(SWAPW(fHMTXTable
->hMetrics
[index
].advanceWidth
));
395 le_bool
PortableFontInstance::getGlyphPoint(LEGlyphID
/*glyph*/, le_int32
/*pointNumber*/, LEPoint
&/*point*/) const
400 le_int32
PortableFontInstance::getUnitsPerEM() const
405 le_uint32
PortableFontInstance::getFontChecksum() const
407 return fFontChecksum
;
410 le_uint32
PortableFontInstance::getRawChecksum() const
413 // fseek(fFile, 0L, SEEK_END);
414 // long size = ftell(fFile);
417 fseek(fFile
, 0L, SEEK_SET
);
420 while((r
= fgetc(fFile
)) != EOF
) {
424 return (le_uint32
) chksum
; // cast to signed
427 le_int32
PortableFontInstance::getAscent() const
432 le_int32
PortableFontInstance::getDescent() const
437 le_int32
PortableFontInstance::getLeading() const
442 // We really want to inherit this method from the superclass, but some compilers
443 // issue a warning if we don't implement it...
444 LEGlyphID
PortableFontInstance::mapCharToGlyph(LEUnicode32 ch
, const LECharMapper
*mapper
, le_bool filterZeroWidth
) const
446 return LEFontInstance::mapCharToGlyph(ch
, mapper
, filterZeroWidth
);
449 // We really want to inherit this method from the superclass, but some compilers
450 // issue a warning if we don't implement it...
451 LEGlyphID
PortableFontInstance::mapCharToGlyph(LEUnicode32 ch
, const LECharMapper
*mapper
) const
453 return LEFontInstance::mapCharToGlyph(ch
, mapper
);
456 LEGlyphID
PortableFontInstance::mapCharToGlyph(LEUnicode32 ch
) const
458 return fCMAPMapper
->unicodeToGlyph(ch
);
461 float PortableFontInstance::getXPixelsPerEm() const
466 float PortableFontInstance::getYPixelsPerEm() const
471 float PortableFontInstance::getScaleFactorX() const
476 float PortableFontInstance::getScaleFactorY() const