1 /***************************************************************************
3 * Copyright (C) 1998-2002, International Business Machines
4 * Corporation and others. All Rights Reserved.
6 ************************************************************************/
11 #include "FontObject.h"
14 FontObject::FontObject(char *fileName
)
15 : directory(NULL
), numTables(0), searchRange(0),entrySelector(0),
16 cmapTable(NULL
), cmSegCount(0), cmSearchRange(0), cmEntrySelector(0),
17 cmEndCodes(NULL
), cmStartCodes(NULL
), cmIdDelta(0), cmIdRangeOffset(0),
18 headTable(NULL
), hmtxTable(NULL
), numGlyphs(0), numOfLongHorMetrics(0), file(NULL
)
20 file
= fopen(fileName
, "rb");
23 printf("?? Couldn't open %s", fileName
);
27 SFNTDirectory tempDir
;
29 fread(&tempDir
, sizeof tempDir
, 1, file
);
31 numTables
= SWAPW(tempDir
.numTables
);
32 searchRange
= SWAPW(tempDir
.searchRange
) >> 4;
33 entrySelector
= SWAPW(tempDir
.entrySelector
);
34 rangeShift
= SWAPW(tempDir
.rangeShift
) >> 4;
36 int dirSize
= sizeof tempDir
+ ((numTables
- ANY_NUMBER
) * sizeof(DirectoryEntry
));
38 directory
= (SFNTDirectory
*) new char[dirSize
];
40 fseek(file
, 0L, SEEK_SET
);
41 fread(directory
, sizeof(char), dirSize
, file
);
46 FontObject::~FontObject()
55 void FontObject::deleteTable(void *table
)
57 delete[] (char *) table
;
60 DirectoryEntry
*FontObject::findTable(LETag tag
)
63 le_uint16 probe
= 1 << entrySelector
;
65 if (SWAPL(directory
->tableDirectory
[rangeShift
].tag
) <= tag
) {
69 while (probe
> (1 << 0)) {
72 if (SWAPL(directory
->tableDirectory
[table
+ probe
].tag
) <= tag
) {
77 if (SWAPL(directory
->tableDirectory
[table
].tag
) == tag
) {
78 return &directory
->tableDirectory
[table
];
84 void *FontObject::readTable(LETag tag
, le_uint32
*length
)
86 DirectoryEntry
*entry
= findTable(tag
);
93 *length
= SWAPL(entry
->length
);
95 void *table
= new char[*length
];
97 fseek(file
, SWAPL(entry
->offset
), SEEK_SET
);
98 fread(table
, sizeof(char), *length
, file
);
103 CMAPEncodingSubtable
*FontObject::findCMAP(le_uint16 platformID
, le_uint16 platformSpecificID
)
105 LETag cmapTag
= 0x636D6170; // 'cmap'
107 if (cmapTable
== NULL
) {
110 cmapTable
= (CMAPTable
*) readTable(cmapTag
, &length
);
113 if (cmapTable
!= NULL
) {
115 le_uint16 nSubtables
= SWAPW(cmapTable
->numberSubtables
);
118 for (i
= 0; i
< nSubtables
; i
+= 1) {
119 CMAPEncodingSubtableHeader
*esh
= &cmapTable
->encodingSubtableHeaders
[i
];
121 if (SWAPW(esh
->platformID
) == platformID
&&
122 SWAPW(esh
->platformSpecificID
) == platformSpecificID
) {
123 return (CMAPEncodingSubtable
*) ((char *) cmapTable
+ SWAPL(esh
->encodingOffset
));
131 void FontObject::initUnicodeCMAP()
133 CMAPEncodingSubtable
*encodingSubtable
= findCMAP(3, 1);
135 if (encodingSubtable
== 0 ||
136 SWAPW(encodingSubtable
->format
) != 4) {
137 printf("Can't find unicode 'cmap'");
141 CMAPFormat4Encoding
*header
= (CMAPFormat4Encoding
*) encodingSubtable
;
143 cmSegCount
= SWAPW(header
->segCountX2
) / 2;
144 cmSearchRange
= SWAPW(header
->searchRange
);
145 cmEntrySelector
= SWAPW(header
->entrySelector
);
146 cmRangeShift
= SWAPW(header
->rangeShift
) / 2;
147 cmEndCodes
= &header
->endCodes
[0];
148 cmStartCodes
= &header
->endCodes
[cmSegCount
+ 1]; // + 1 for reservedPad...
149 cmIdDelta
= &cmStartCodes
[cmSegCount
];
150 cmIdRangeOffset
= &cmIdDelta
[cmSegCount
];
153 LEGlyphID
FontObject::unicodeToGlyph(LEUnicode32 unicode32
)
155 if (unicode32
>= 0x10000) {
159 LEUnicode16 unicode
= (LEUnicode16
) unicode32
;
161 le_uint16 probe
= 1 << cmEntrySelector
;
162 LEGlyphID result
= 0;
164 if (SWAPW(cmStartCodes
[cmRangeShift
]) <= unicode
) {
165 index
= cmRangeShift
;
168 while (probe
> (1 << 0)) {
171 if (SWAPW(cmStartCodes
[index
+ probe
]) <= unicode
) {
176 if (unicode
>= SWAPW(cmStartCodes
[index
]) && unicode
<= SWAPW(cmEndCodes
[index
])) {
177 if (cmIdRangeOffset
[index
] == 0) {
178 result
= (LEGlyphID
) unicode
;
180 le_uint16 offset
= unicode
- SWAPW(cmStartCodes
[index
]);
181 le_uint16 rangeOffset
= SWAPW(cmIdRangeOffset
[index
]);
182 le_uint16
*glyphIndexTable
= (le_uint16
*) ((char *) &cmIdRangeOffset
[index
] + rangeOffset
);
184 result
= SWAPW(glyphIndexTable
[offset
]);
187 result
+= SWAPW(cmIdDelta
[index
]);
195 le_uint16
FontObject::getUnitsPerEM()
197 if (headTable
== NULL
) {
198 LETag headTag
= 0x68656164; // 'head'
201 headTable
= (HEADTable
*) readTable(headTag
, &length
);
204 return SWAPW(headTable
->unitsPerEm
);
207 le_uint16
FontObject::getGlyphAdvance(LEGlyphID glyph
)
209 if (hmtxTable
== NULL
) {
210 LETag maxpTag
= 0x6D617870; // 'maxp'
211 LETag hheaTag
= 0x68686561; // 'hhea'
212 LETag hmtxTag
= 0x686D7478; // 'hmtx'
214 HHEATable
*hheaTable
;
215 MAXPTable
*maxpTable
= (MAXPTable
*) readTable(maxpTag
, &length
);
217 numGlyphs
= SWAPW(maxpTable
->numGlyphs
);
218 deleteTable(maxpTable
);
220 hheaTable
= (HHEATable
*) readTable(hheaTag
, &length
);
221 numOfLongHorMetrics
= SWAPW(hheaTable
->numOfLongHorMetrics
);
222 deleteTable(hheaTable
);
224 hmtxTable
= (HMTXTable
*) readTable(hmtxTag
, &length
);
227 le_uint16 index
= glyph
;
229 if (glyph
>= numGlyphs
) {
233 if (glyph
>= numOfLongHorMetrics
) {
234 index
= numOfLongHorMetrics
- 1;
237 return SWAPW(hmtxTable
->hMetrics
[index
].advanceWidth
);