2 * @(#)KernTable.cpp 1.1 04/10/13
4 * (C) Copyright IBM Corp. 2004-2007 - All Rights Reserved
9 #include "LEFontInstance.h"
10 #include "LEGlyphStorage.h"
13 #include "OpenTypeUtilities.h"
22 le_uint16 left
; // left glyph of kern pair
23 le_uint16 right
; // right glyph of kern pair
24 le_int16 value
; // fword, kern value in funits
26 #define KERN_PAIRINFO_SIZE 6
28 #define SWAP_KEY(p) (((le_uint32) SWAPW((p)->left) << 16) | SWAPW((p)->right))
32 le_uint16 searchRange
;
33 le_uint16 entrySelector
;
36 #define KERN_SUBTABLE_0_HEADER_SIZE 8
38 // Kern table version 0 only
39 struct SubtableHeader
{
44 #define KERN_SUBTABLE_HEADER_SIZE 6
46 // Version 0 only, version 1 has different layout
47 struct KernTableHeader
{
51 #define KERN_TABLE_HEADER_SIZE 4
53 #define COVERAGE_HORIZONTAL 0x1
54 #define COVERAGE_MINIMUM 0x2
55 #define COVERAGE_CROSS 0x4
56 #define COVERAGE_OVERRIDE 0x8
59 * This implementation has support for only one subtable, so if the font has
60 * multiple subtables, only the first will be used. If this turns out to
61 * be a problem in practice we should add it.
63 * This also supports only version 0 of the kern table header, only
64 * Apple supports the latter.
66 * This implementation isn't careful about the kern table flags, and
67 * might invoke kerning when it is not supposed to. That too I'm
68 * leaving for a bug fix.
70 * TODO: support multiple subtables
71 * TODO: respect header flags
73 KernTable::KernTable(const LEFontInstance
* font
, const void* tableData
)
74 : pairs(0), font(font
)
76 const KernTableHeader
* header
= (const KernTableHeader
*)tableData
;
79 fprintf(stderr
, "no kern data\n");
85 // dump first 32 bytes of header
86 for (int i
= 0; i
< 64; ++i
) {
87 fprintf(stderr
, "%0.2x ", ((const char*)tableData
)[i
]&0xff);
88 if (((i
+1)&0xf) == 0) {
89 fprintf(stderr
, "\n");
90 } else if (((i
+1)&0x7) == 0) {
96 if (header
->version
== 0 && SWAPW(header
->nTables
) > 0) {
97 const SubtableHeader
* subhead
= (const SubtableHeader
*)((char*)tableData
+ KERN_TABLE_HEADER_SIZE
);
99 if (subhead
->version
== 0) {
100 coverage
= SWAPW(subhead
->coverage
);
102 if (coverage
& COVERAGE_HORIZONTAL
) { // only handle horizontal kerning
103 const Subtable_0
* table
= (const Subtable_0
*)((char*)subhead
+ KERN_SUBTABLE_HEADER_SIZE
);
105 nPairs
= SWAPW(table
->nPairs
);
107 #if 0 // some old fonts have bad values here...
108 searchRange
= SWAPW(table
->searchRange
);
109 entrySelector
= SWAPW(table
->entrySelector
);
110 rangeShift
= SWAPW(table
->rangeShift
);
112 entrySelector
= OpenTypeUtilities::highBit(nPairs
);
113 searchRange
= (1 << entrySelector
) * KERN_PAIRINFO_SIZE
;
114 rangeShift
= (nPairs
* KERN_PAIRINFO_SIZE
) - searchRange
;
117 pairs
= (const PairInfo
*)((char*)table
+ KERN_SUBTABLE_0_HEADER_SIZE
);
120 fprintf(stderr
, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage
, nPairs
, pairs
);
121 fprintf(stderr
, " searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange
, entrySelector
, rangeShift
);
124 // dump part of the pair list
127 for (int i
= 256; --i
>= 0;) {
128 LEGlyphID id
= font
->mapCharToGlyph(i
);
135 const PairInfo
* p
= pairs
;
137 for (i
= 0; i
< nPairs
; ++i
, p
= (const PairInfo
*)((char*)p
+KERN_PAIRINFO_SIZE
)) {
138 le_uint16 left
= p
->left
;
139 le_uint16 right
= p
->right
;
141 if (left
< 256 && right
< 256) {
144 if (c
> 0x20 && c
< 0x7f) {
145 fprintf(stderr
, "%c/", c
& 0xff);
147 printf(stderr
, "%0.2x/", c
& 0xff);
151 if (c
> 0x20 && c
< 0x7f) {
152 fprintf(stderr
, "%c ", c
& 0xff);
154 fprintf(stderr
, "%0.2x ", c
& 0xff);
167 * Process the glyph positions. The positions array has two floats for each
168 * glyph, plus a trailing pair to mark the end of the last glyph.
170 void KernTable::process(LEGlyphStorage
& storage
)
173 LEErrorCode success
= LE_NO_ERROR
;
175 le_uint32 key
= storage
[0]; // no need to mask off high bits
178 for (int i
= 1, e
= storage
.getGlyphCount(); i
< e
; ++i
) {
179 key
= key
<< 16 | (storage
[i
] & 0xffff);
181 // argh, to do a binary search, we need to have the pair list in sorted order
182 // but it is not in sorted order on win32 platforms because of the endianness difference
183 // so either I have to swap the element each time I examine it, or I have to swap
184 // all the elements ahead of time and store them in the font
186 const PairInfo
* p
= pairs
;
187 const PairInfo
* tp
= (const PairInfo
*)((char*)p
+ rangeShift
);
189 if (key
> SWAP_KEY(tp
)) {
194 fprintf(stderr
, "binary search for %0.8x\n", key
);
197 le_uint32 probe
= searchRange
;
199 while (probe
> KERN_PAIRINFO_SIZE
) {
201 tp
= (const PairInfo
*)((char*)p
+ probe
);
203 le_uint32 tkey
= SWAP_KEY(tp
);
205 fprintf(stdout
, " %.3d (%0.8x)\n", ((char*)tp
- (char*)pairs
)/KERN_PAIRINFO_SIZE
, tkey
);
209 le_int16 value
= SWAPW(tp
->value
);
211 fprintf(stdout
, "binary found kerning pair %x:%x at %d, value: 0x%x (%g)\n",
212 storage
[i
-1], storage
[i
], i
, value
& 0xffff, font
->xUnitsToPoints(value
));
215 adjust
+= font
->xUnitsToPoints(value
);
223 storage
.adjustPosition(i
, adjust
, 0, success
);
226 storage
.adjustPosition(storage
.getGlyphCount(), adjust
, 0, success
);