1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /***************************************************************************
5 * Copyright (C) 1998-2002, International Business Machines
6 * Corporation and others. All Rights Reserved.
8 ************************************************************************/
13 #include "FontObject.h"
16 FontObject::FontObject(char *fileName
)
17 : directory(NULL
), numTables(0), searchRange(0),entrySelector(0),
18 cmapTable(NULL
), cmSegCount(0), cmSearchRange(0), cmEntrySelector(0),
19 cmEndCodes(NULL
), cmStartCodes(NULL
), cmIdDelta(0), cmIdRangeOffset(0),
20 headTable(NULL
), hmtxTable(NULL
), numGlyphs(0), numOfLongHorMetrics(0), file(NULL
)
22 file
= fopen(fileName
, "rb");
25 printf("?? Couldn't open %s", fileName
);
29 SFNTDirectory tempDir
;
31 fread(&tempDir
, sizeof tempDir
, 1, file
);
33 numTables
= SWAPW(tempDir
.numTables
);
34 searchRange
= SWAPW(tempDir
.searchRange
) >> 4;
35 entrySelector
= SWAPW(tempDir
.entrySelector
);
36 rangeShift
= SWAPW(tempDir
.rangeShift
) >> 4;
38 int dirSize
= sizeof tempDir
+ ((numTables
- ANY_NUMBER
) * sizeof(DirectoryEntry
));
40 directory
= (SFNTDirectory
*) new char[dirSize
];
42 fseek(file
, 0L, SEEK_SET
);
43 fread(directory
, sizeof(char), dirSize
, file
);
48 FontObject::~FontObject()
57 void FontObject::deleteTable(void *table
)
59 delete[] (char *) table
;
62 DirectoryEntry
*FontObject::findTable(LETag tag
)
65 le_uint16 probe
= 1 << entrySelector
;
67 if (SWAPL(directory
->tableDirectory
[rangeShift
].tag
) <= tag
) {
71 while (probe
> (1 << 0)) {
74 if (SWAPL(directory
->tableDirectory
[table
+ probe
].tag
) <= tag
) {
79 if (SWAPL(directory
->tableDirectory
[table
].tag
) == tag
) {
80 return &directory
->tableDirectory
[table
];
86 void *FontObject::readTable(LETag tag
, le_uint32
*length
)
88 DirectoryEntry
*entry
= findTable(tag
);
95 *length
= SWAPL(entry
->length
);
97 void *table
= new char[*length
];
99 fseek(file
, SWAPL(entry
->offset
), SEEK_SET
);
100 fread(table
, sizeof(char), *length
, file
);
105 CMAPEncodingSubtable
*FontObject::findCMAP(le_uint16 platformID
, le_uint16 platformSpecificID
)
107 LETag cmapTag
= 0x636D6170; // 'cmap'
109 if (cmapTable
== NULL
) {
112 cmapTable
= (CMAPTable
*) readTable(cmapTag
, &length
);
115 if (cmapTable
!= NULL
) {
117 le_uint16 nSubtables
= SWAPW(cmapTable
->numberSubtables
);
120 for (i
= 0; i
< nSubtables
; i
+= 1) {
121 CMAPEncodingSubtableHeader
*esh
= &cmapTable
->encodingSubtableHeaders
[i
];
123 if (SWAPW(esh
->platformID
) == platformID
&&
124 SWAPW(esh
->platformSpecificID
) == platformSpecificID
) {
125 return (CMAPEncodingSubtable
*) ((char *) cmapTable
+ SWAPL(esh
->encodingOffset
));
133 void FontObject::initUnicodeCMAP()
135 CMAPEncodingSubtable
*encodingSubtable
= findCMAP(3, 1);
137 if (encodingSubtable
== 0 ||
138 SWAPW(encodingSubtable
->format
) != 4) {
139 printf("Can't find unicode 'cmap'");
143 CMAPFormat4Encoding
*header
= (CMAPFormat4Encoding
*) encodingSubtable
;
145 cmSegCount
= SWAPW(header
->segCountX2
) / 2;
146 cmSearchRange
= SWAPW(header
->searchRange
);
147 cmEntrySelector
= SWAPW(header
->entrySelector
);
148 cmRangeShift
= SWAPW(header
->rangeShift
) / 2;
149 cmEndCodes
= &header
->endCodes
[0];
150 cmStartCodes
= &header
->endCodes
[cmSegCount
+ 1]; // + 1 for reservedPad...
151 cmIdDelta
= &cmStartCodes
[cmSegCount
];
152 cmIdRangeOffset
= &cmIdDelta
[cmSegCount
];
155 LEGlyphID
FontObject::unicodeToGlyph(LEUnicode32 unicode32
)
157 if (unicode32
>= 0x10000) {
161 LEUnicode16 unicode
= (LEUnicode16
) unicode32
;
163 le_uint16 probe
= 1 << cmEntrySelector
;
164 LEGlyphID result
= 0;
166 if (SWAPW(cmStartCodes
[cmRangeShift
]) <= unicode
) {
167 index
= cmRangeShift
;
170 while (probe
> (1 << 0)) {
173 if (SWAPW(cmStartCodes
[index
+ probe
]) <= unicode
) {
178 if (unicode
>= SWAPW(cmStartCodes
[index
]) && unicode
<= SWAPW(cmEndCodes
[index
])) {
179 if (cmIdRangeOffset
[index
] == 0) {
180 result
= (LEGlyphID
) unicode
;
182 le_uint16 offset
= unicode
- SWAPW(cmStartCodes
[index
]);
183 le_uint16 rangeOffset
= SWAPW(cmIdRangeOffset
[index
]);
184 le_uint16
*glyphIndexTable
= (le_uint16
*) ((char *) &cmIdRangeOffset
[index
] + rangeOffset
);
186 result
= SWAPW(glyphIndexTable
[offset
]);
189 result
+= SWAPW(cmIdDelta
[index
]);
197 le_uint16
FontObject::getUnitsPerEM()
199 if (headTable
== NULL
) {
200 LETag headTag
= 0x68656164; // 'head'
203 headTable
= (HEADTable
*) readTable(headTag
, &length
);
206 return SWAPW(headTable
->unitsPerEm
);
209 le_uint16
FontObject::getGlyphAdvance(LEGlyphID glyph
)
211 if (hmtxTable
== NULL
) {
212 LETag maxpTag
= 0x6D617870; // 'maxp'
213 LETag hheaTag
= 0x68686561; // 'hhea'
214 LETag hmtxTag
= 0x686D7478; // 'hmtx'
216 HHEATable
*hheaTable
;
217 MAXPTable
*maxpTable
= (MAXPTable
*) readTable(maxpTag
, &length
);
219 numGlyphs
= SWAPW(maxpTable
->numGlyphs
);
220 deleteTable(maxpTable
);
222 hheaTable
= (HHEATable
*) readTable(hheaTag
, &length
);
223 numOfLongHorMetrics
= SWAPW(hheaTable
->numOfLongHorMetrics
);
224 deleteTable(hheaTable
);
226 hmtxTable
= (HMTXTable
*) readTable(hmtxTag
, &length
);
229 le_uint16 index
= glyph
;
231 if (glyph
>= numGlyphs
) {
235 if (glyph
>= numOfLongHorMetrics
) {
236 index
= numOfLongHorMetrics
- 1;
239 return SWAPW(hmtxTable
->hMetrics
[index
].advanceWidth
);