J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 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 | |
| 42 | struct 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 | |
| 48 | struct 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 |
| 57 | struct 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 |
| 65 | struct 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 | */ |
| 91 | KernTable::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 | */ |
| 185 | void 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 | } |