1 /***************************************************************************
3 * © 2016 and later: Unicode, Inc. and others.
4 * License & terms of use: http://www.unicode.org/copyright.html#License
6 ****************************************************************************/
7 /***************************************************************************
9 * Copyright (C) 1998-2013, International Business Machines
10 * Corporation and others. All Rights Reserved.
12 ************************************************************************/
17 #include "FontObject.h"
20 FontObject::FontObject(char *fileName
)
21 : directory(NULL
), numTables(0), searchRange(0),entrySelector(0),
22 cmapTable(NULL
), cmSegCount(0), cmSearchRange(0), cmEntrySelector(0),
23 cmEndCodes(NULL
), cmStartCodes(NULL
), cmIdDelta(0), cmIdRangeOffset(0),
24 headTable(NULL
), hmtxTable(NULL
), numGlyphs(0), numOfLongHorMetrics(0), file(NULL
)
26 file
= fopen(fileName
, "rb");
29 printf("?? Couldn't open %s", fileName
);
33 SFNTDirectory tempDir
;
35 fread(&tempDir
, sizeof tempDir
, 1, file
);
37 numTables
= SWAPW(tempDir
.numTables
);
38 searchRange
= SWAPW(tempDir
.searchRange
) >> 4;
39 entrySelector
= SWAPW(tempDir
.entrySelector
);
40 rangeShift
= SWAPW(tempDir
.rangeShift
) >> 4;
42 int dirSize
= sizeof tempDir
+ ((numTables
- ANY_NUMBER
) * sizeof(DirectoryEntry
));
44 directory
= (SFNTDirectory
*) new char[dirSize
];
46 fseek(file
, 0L, SEEK_SET
);
47 fread(directory
, sizeof(char), dirSize
, file
);
52 FontObject::~FontObject()
61 void FontObject::deleteTable(void *table
)
63 delete[] (char *) table
;
66 DirectoryEntry
*FontObject::findTable(LETag tag
)
69 le_uint16 probe
= 1 << entrySelector
;
71 if (SWAPL(directory
->tableDirectory
[rangeShift
].tag
) <= tag
) {
75 while (probe
> (1 << 0)) {
78 if (SWAPL(directory
->tableDirectory
[table
+ probe
].tag
) <= tag
) {
83 if (SWAPL(directory
->tableDirectory
[table
].tag
) == tag
) {
84 return &directory
->tableDirectory
[table
];
90 void *FontObject::readTable(LETag tag
, le_uint32
*length
)
92 DirectoryEntry
*entry
= findTable(tag
);
99 *length
= SWAPL(entry
->length
);
101 void *table
= new char[*length
];
103 fseek(file
, SWAPL(entry
->offset
), SEEK_SET
);
104 fread(table
, sizeof(char), *length
, file
);
109 CMAPEncodingSubtable
*FontObject::findCMAP(le_uint16 platformID
, le_uint16 platformSpecificID
)
111 LETag cmapTag
= 0x636D6170; // 'cmap'
113 if (cmapTable
== NULL
) {
116 cmapTable
= (CMAPTable
*) readTable(cmapTag
, &length
);
119 if (cmapTable
!= NULL
) {
121 le_uint16 nSubtables
= SWAPW(cmapTable
->numberSubtables
);
124 for (i
= 0; i
< nSubtables
; i
+= 1) {
125 CMAPEncodingSubtableHeader
*esh
= &cmapTable
->encodingSubtableHeaders
[i
];
127 if (SWAPW(esh
->platformID
) == platformID
&&
128 SWAPW(esh
->platformSpecificID
) == platformSpecificID
) {
129 return (CMAPEncodingSubtable
*) ((char *) cmapTable
+ SWAPL(esh
->encodingOffset
));
137 void FontObject::initUnicodeCMAP()
139 CMAPEncodingSubtable
*encodingSubtable
= findCMAP(3, 1);
141 if (encodingSubtable
== 0 ||
142 SWAPW(encodingSubtable
->format
) != 4) {
143 printf("Can't find unicode 'cmap'");
147 CMAPFormat4Encoding
*header
= (CMAPFormat4Encoding
*) encodingSubtable
;
149 cmSegCount
= SWAPW(header
->segCountX2
) / 2;
150 cmSearchRange
= SWAPW(header
->searchRange
);
151 cmEntrySelector
= SWAPW(header
->entrySelector
);
152 cmRangeShift
= SWAPW(header
->rangeShift
) / 2;
153 cmEndCodes
= &header
->endCodes
[0];
154 cmStartCodes
= &header
->endCodes
[cmSegCount
+ 1]; // + 1 for reservedPad...
155 cmIdDelta
= &cmStartCodes
[cmSegCount
];
156 cmIdRangeOffset
= &cmIdDelta
[cmSegCount
];
159 LEGlyphID
FontObject::unicodeToGlyph(LEUnicode32 unicode32
)
161 if (unicode32
>= 0x10000) {
165 LEUnicode16 unicode
= (LEUnicode16
) unicode32
;
167 le_uint16 probe
= 1 << cmEntrySelector
;
168 LEGlyphID result
= 0;
170 if (SWAPW(cmStartCodes
[cmRangeShift
]) <= unicode
) {
171 index
= cmRangeShift
;
174 while (probe
> (1 << 0)) {
177 if (SWAPW(cmStartCodes
[index
+ probe
]) <= unicode
) {
182 if (unicode
>= SWAPW(cmStartCodes
[index
]) && unicode
<= SWAPW(cmEndCodes
[index
])) {
183 if (cmIdRangeOffset
[index
] == 0) {
184 result
= (LEGlyphID
) unicode
;
186 le_uint16 offset
= unicode
- SWAPW(cmStartCodes
[index
]);
187 le_uint16 rangeOffset
= SWAPW(cmIdRangeOffset
[index
]);
188 le_uint16
*glyphIndexTable
= (le_uint16
*) ((char *) &cmIdRangeOffset
[index
] + rangeOffset
);
190 result
= SWAPW(glyphIndexTable
[offset
]);
193 result
+= SWAPW(cmIdDelta
[index
]);
201 le_uint16
FontObject::getUnitsPerEM()
203 if (headTable
== NULL
) {
204 LETag headTag
= 0x68656164; // 'head'
207 headTable
= (HEADTable
*) readTable(headTag
, &length
);
210 return SWAPW(headTable
->unitsPerEm
);
213 le_uint16
FontObject::getGlyphAdvance(LEGlyphID glyph
)
215 if (hmtxTable
== NULL
) {
216 LETag maxpTag
= 0x6D617870; // 'maxp'
217 LETag hheaTag
= 0x68686561; // 'hhea'
218 LETag hmtxTag
= 0x686D7478; // 'hmtx'
220 HHEATable
*hheaTable
;
221 MAXPTable
*maxpTable
= (MAXPTable
*) readTable(maxpTag
, &length
);
223 numGlyphs
= SWAPW(maxpTable
->numGlyphs
);
224 deleteTable(maxpTable
);
226 hheaTable
= (HHEATable
*) readTable(hheaTag
, &length
);
227 numOfLongHorMetrics
= SWAPW(hheaTable
->numOfLongHorMetrics
);
228 deleteTable(hheaTable
);
230 hmtxTable
= (HMTXTable
*) readTable(hmtxTag
, &length
);
233 le_uint16 index
= glyph
;
235 if (glyph
>= numGlyphs
) {
239 if (glyph
>= numOfLongHorMetrics
) {
240 index
= numOfLongHorMetrics
- 1;
243 return SWAPW(hmtxTable
->hMetrics
[index
].advanceWidth
);