blob: 8c7bae0d8f0fe7f5234920aa65746f20804dd8ba [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Sun designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Sun in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
22 * have any questions.
23 *
24 */
25
26/*
27 *
28 * (C) Copyright IBM Corp. 2004-2005 - All Rights Reserved
29 *
30 */
31
32#include "KernTable.h"
33#include "LEFontInstance.h"
34#include "LEGlyphStorage.h"
35
36#include "LESwaps.h"
37
38#include <stdio.h>
39
40#define DEBUG 0
41
42struct PairInfo {
43 le_uint32 key; // sigh, MSVC compiler gags on union here
44 le_int16 value; // fword, kern value in funits
45};
46#define KERN_PAIRINFO_SIZE 6
47
48struct Subtable_0 {
49 le_uint16 nPairs;
50 le_uint16 searchRange;
51 le_uint16 entrySelector;
52 le_uint16 rangeShift;
53};
54#define KERN_SUBTABLE_0_HEADER_SIZE 8
55
56// Kern table version 0 only
57struct SubtableHeader {
58 le_uint16 version;
59 le_uint16 length;
60 le_uint16 coverage;
61};
62#define KERN_SUBTABLE_HEADER_SIZE 6
63
64// Version 0 only, version 1 has different layout
65struct KernTableHeader {
66 le_uint16 version;
67 le_uint16 nTables;
68};
69#define KERN_TABLE_HEADER_SIZE 4
70
71#define COVERAGE_HORIZONTAL 0x1
72#define COVERAGE_MINIMUM 0x2
73#define COVERAGE_CROSS 0x4
74#define COVERAGE_OVERRIDE 0x8
75
76/*
77 * This implementation has support for only one subtable, so if the font has
78 * multiple subtables, only the first will be used. If this turns out to
79 * be a problem in practice we should add it.
80 *
81 * This also supports only version 0 of the kern table header, only
82 * Apple supports the latter.
83 *
84 * This implementation isn't careful about the kern table flags, and
85 * might invoke kerning when it is not supposed to. That too I'm
86 * leaving for a bug fix.
87 *
88 * TODO: support multiple subtables
89 * TODO: respect header flags
90 */
91KernTable::KernTable(const LEFontInstance* font, const void* tableData)
92 : pairs(0), font(font)
93{
94 const KernTableHeader* header = (const KernTableHeader*)tableData;
95 if (header == 0) {
96#if DEBUG
97 fprintf(stderr, "no kern data\n");
98#endif
99 return;
100 }
101
102#if DEBUG
103 // dump first 32 bytes of header
104 for (int i = 0; i < 64; ++i) {
105 fprintf(stderr, "%0.2x ", ((const char*)tableData)[i]&0xff);
106 if (((i+1)&0xf) == 0) {
107 fprintf(stderr, "\n");
108 } else if (((i+1)&0x7) == 0) {
109 fprintf(stderr, " ");
110 }
111 }
112#endif
113
114 if (header->version == 0 && SWAPW(header->nTables) > 0) {
115 const SubtableHeader* subhead = (const SubtableHeader*)((char*)tableData + KERN_TABLE_HEADER_SIZE);
116 if (subhead->version == 0) {
117 coverage = SWAPW(subhead->coverage);
118 if (coverage & COVERAGE_HORIZONTAL) { // only handle horizontal kerning
119 const Subtable_0* table = (const Subtable_0*)((char*)subhead + KERN_SUBTABLE_HEADER_SIZE);
120 nPairs = SWAPW(table->nPairs);
121 searchRange = SWAPW(table->searchRange) / KERN_PAIRINFO_SIZE ;
122 entrySelector = SWAPW(table->entrySelector);
123 rangeShift = SWAPW(table->rangeShift) / KERN_PAIRINFO_SIZE;
124
125 pairs = (PairInfo*)font->getKernPairs();
126 if (pairs == NULL) {
127 char *pairData = (char*)table + KERN_SUBTABLE_0_HEADER_SIZE;
128 char *pptr = pairData;
129 pairs = (PairInfo*)(malloc(nPairs*sizeof(PairInfo)));
130 PairInfo *p = (PairInfo*)pairs;
131 for (int i = 0; i < nPairs; i++, pptr += KERN_PAIRINFO_SIZE, p++) {
132 memcpy(p, pptr, KERN_PAIRINFO_SIZE);
133 p->key = SWAPL(p->key);
134 }
135 font->setKernPairs((void*)pairs);
136 }
137
138#if DEBUG
139 fprintf(stderr, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairs);
140 fprintf(stderr,
141 " searchRange(pairs): %d entrySelector: %d rangeShift(pairs): %d\n",
142 searchRange, entrySelector, rangeShift);
143
144 {
145 // dump part of the pair list
146 char ids[256];
147 for (int i = 256; --i >= 0;) {
148 LEGlyphID id = font->mapCharToGlyph(i);
149 if (id < 256) {
150 ids[id] = (char)i;
151 }
152 }
153 PairInfo *p = pairs;
154 for (int i = 0; i < nPairs; ++i, p++) {
155 le_uint32 k = p->key;
156 le_uint16 left = (k >> 16) & 0xffff;
157 le_uint16 right = k & 0xffff;
158 if (left < 256 && right < 256) {
159 char c = ids[left];
160 if (c > 0x20 && c < 0x7f) {
161 fprintf(stderr, "%c/", c & 0xff);
162 } else {
163 fprintf(stderr, "%0.2x/", c & 0xff);
164 }
165 c = ids[right];
166 if (c > 0x20 && c < 0x7f) {
167 fprintf(stderr, "%c ", c & 0xff);
168 } else {
169 fprintf(stderr, "%0.2x ", c & 0xff);
170 }
171 }
172 }
173 }
174#endif
175 }
176 }
177 }
178}
179
180
181/*
182 * Process the glyph positions. The positions array has two floats for each
183 * glyph, plus a trailing pair to mark the end of the last glyph.
184 */
185void KernTable::process(LEGlyphStorage& storage)
186{
187 if (pairs) {
188 LEErrorCode success = LE_NO_ERROR;
189
190 le_uint32 key = storage[0]; // no need to mask off high bits
191 float adjust = 0;
192 for (int i = 1, e = storage.getGlyphCount(); i < e; ++i) {
193 key = key << 16 | (storage[i] & 0xffff);
194 const PairInfo* p = pairs;
195 const PairInfo* tp = (const PairInfo*)(p + rangeShift);
196 if (key > tp->key) {
197 p = tp;
198 }
199
200#if DEBUG
201 fprintf(stderr, "binary search for %0.8x\n", key);
202#endif
203
204 le_uint32 probe = searchRange;
205 while (probe > 1) {
206 probe >>= 1;
207 tp = (const PairInfo*)(p + probe);
208 le_uint32 tkey = tp->key;
209#if DEBUG
210 fprintf(stdout, " %.3d (%0.8x)\n", (tp - pairs), tkey);
211#endif
212 if (tkey <= key) {
213 if (tkey == key) {
214 le_int16 value = SWAPW(tp->value);
215#if DEBUG
216 fprintf(stdout, "binary found kerning pair %x:%x at %d, value: 0x%x (%g)\n",
217 storage[i-1], storage[i], i, value & 0xffff, font->xUnitsToPoints(value));
218 fflush(stdout);
219#endif
220 // Have to undo the device transform.
221 // REMIND either find a way to do this only if there is a
222 // device transform, or a faster way, such as moving the
223 // entire kern table up to Java.
224 LEPoint pt;
225 pt.fX = font->xUnitsToPoints(value);
226 pt.fY = 0;
227
228 font->getKerningAdjustment(pt);
229 adjust += pt.fX;
230 break;
231 }
232 p = tp;
233 }
234 }
235
236 storage.adjustPosition(i, adjust, 0, success);
237 }
238 storage.adjustPosition(storage.getGlyphCount(), adjust, 0, success);
239 }
240}