summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu-xetex/layout/KernTable.cpp
blob: dbadaf576d93aec560b22b76f1bc088fcfef0796 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
 * @(#)KernTable.cpp	1.1 04/10/13
 *
 * (C) Copyright IBM Corp. 2004-2005 - All Rights Reserved
 *
 */

#include "KernTable.h"

#include "LESwaps.h"

#include <stdio.h>

#define DEBUG 0

U_NAMESPACE_BEGIN

struct PairInfo {
  le_uint32 key;   // sigh, MSVC compiler gags on union here
  le_int16  value; // fword, kern value in funits
};
#define KERN_PAIRINFO_SIZE 6

struct Subtable_0 {
  le_uint16 nPairs;
  le_uint16 searchRange;
  le_uint16 entrySelector;
  le_uint16 rangeShift;
};
#define KERN_SUBTABLE_0_HEADER_SIZE 8

// Kern table version 0 only
struct SubtableHeader {
  le_uint16 version;
  le_uint16 length;
  le_uint16 coverage;
};
#define KERN_SUBTABLE_HEADER_SIZE 6

// Version 0 only, version 1 has different layout
struct KernTableHeader {
  le_uint16 version;
  le_uint16 nTables;
};
#define KERN_TABLE_HEADER_SIZE 4

#define COVERAGE_HORIZONTAL 0x1
#define COVERAGE_MINIMUM 0x2
#define COVERAGE_CROSS 0x4
#define COVERAGE_OVERRIDE 0x8

KernTable::KernTable(const LEFontInstance* font, const void* tableData) 
  : pairs(0), font(font)
{
  const KernTableHeader* header = (const KernTableHeader*)tableData;
  if (header == 0) {
#if DEBUG
    fprintf(stderr, "no kern data\n");
    fflush(stderr);
#endif
    return;
  }

#if DEBUG
  // dump first 32 bytes of header
  for (int i = 0; i < 64; ++i) {
    fprintf(stderr, "%0.2x ", ((const char*)tableData)[i]&0xff);
    if (((i+1)&0xf) == 0) {
      fprintf(stderr, "\n");
    } else if (((i+1)&0x7) == 0) {
      fprintf(stderr, "  ");
    }
  }
  fflush(stderr);
#endif

  if (header->version == 0 && SWAPW(header->nTables) > 0) {
    const SubtableHeader* subhead = (const SubtableHeader*)((char*)tableData + KERN_TABLE_HEADER_SIZE);
    if (subhead->version == 0) {
      coverage = SWAPW(subhead->coverage);
      if (coverage & COVERAGE_HORIZONTAL) { // only handle horizontal kerning
	const Subtable_0* table = (const Subtable_0*)((char*)subhead + KERN_SUBTABLE_HEADER_SIZE);
	nPairs = SWAPW(table->nPairs);
	searchRange = SWAPW(table->searchRange);
	entrySelector = SWAPW(table->entrySelector);
	rangeShift = SWAPW(table->rangeShift);
	pairs = (const PairInfo*)((char*)table + KERN_SUBTABLE_0_HEADER_SIZE);

#if DEBUG
	fprintf(stderr, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairs);
	fprintf(stderr, "  searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange, entrySelector, rangeShift);
	fflush(stderr);

	{
	  // dump part of the pair list
	  char ids[256];
	  for (int i = 256; --i >= 0;) {
	    LEGlyphID id = font->mapCharToGlyph(i);
	    if (id < 256) {
	      ids[id] = (char)i;
	    }
	  }

	  const PairInfo* p = pairs;
	  for (i = 0; i < nPairs; ++i, p = (const PairInfo*)((char*)p+KERN_PAIRINFO_SIZE)) {
  	    le_uint32 k = SWAPL(p->key);
	    le_uint16 left = (k >> 16) & 0xffff;
	    le_uint16 right = k & 0xffff;
	    if (left < 256 && right < 256) {
	      char c = ids[left];
	      if (c > 0x20 && c < 0x7f) {
		fprintf(stderr, "%c/", c & 0xff);
	      } else {
		fprintf(stderr, "%0.2x/", c & 0xff);
	      }
	      c = ids[right];
	      if (c > 0x20 && c < 0x7f) {
		fprintf(stderr, "%c ", c & 0xff);
	      } else {
		fprintf(stderr, "%0.2x ", c & 0xff);
	      }
	    }
	  }
	  fflush(stderr);
	}
#endif
      }
    }
  }
}
  

/*
 * Process the glyph positions.  The positions array has two floats for each
 * glyph, plus a trailing pair to mark the end of the last glyph.
 */
//void KernTable::process(const LEGlyphID glyphs[], float* positions, le_int32 glyphCount) 
void KernTable::process(LEGlyphStorage& storage) 
{
  if (pairs) {
    LEErrorCode success = LE_NO_ERROR;

    le_uint32 key = storage[0]; // no need to mask off high bits
    float adjust = 0;
    for (int i = 1, e = storage.getGlyphCount(); i < e; ++i) {
      key = key << 16 | (storage[i] & 0xffff);

      // argh, to do a binary search, we need to have the pair list in sorted order
      // but it is not in sorted order on win32 platforms because of the endianness difference
      // so either I have to swap the element each time I examine it, or I have to swap
      // all the elements ahead of time and store them in the font

      const PairInfo* p = pairs;
      const PairInfo* tp = (const PairInfo*)((char*)p + rangeShift);
      if (key > SWAPL(tp->key)) {
	p = tp;
      }

#if DEBUG
      fprintf(stderr, "binary search for %0.8x\n", key);
      fflush(stderr);
#endif

      le_uint32 probe = searchRange;
      while (probe > KERN_PAIRINFO_SIZE) {
        probe >>= 1;
        tp = (const PairInfo*)((char*)p + probe);
	le_uint32 tkey = SWAPL(tp->key);
#if DEBUG
	fprintf(stdout, "   %.3d (%0.8x)\n", ((char*)tp - (char*)pairs)/KERN_PAIRINFO_SIZE, tkey);
	fflush(stdout);
#endif
        if (tkey <= key) {
	  if (tkey == key) {
	    le_int16 value = SWAPW(tp->value);
#if DEBUG
	    fprintf(stdout, "binary found kerning pair %x:%x at %d, value: 0x%x (%g)\n", 
		    storage[i-1], storage[i], i, value & 0xffff, font->xUnitsToPoints(value));
	    fflush(stdout);
#endif
	    adjust += font->xUnitsToPoints(value);
	    break;
	  }
	  p = tp;
        }
      }

      storage.adjustPosition(i, adjust, 0, success);
    }
    storage.adjustPosition(storage.getGlyphCount(), adjust, 0, success);
  }
}

U_NAMESPACE_END