OLD | NEW |
| (Empty) |
1 /***************************************************************************/ | |
2 /* */ | |
3 /* ttkern.c */ | |
4 /* */ | |
5 /* Load the basic TrueType kerning table. This doesn't handle */ | |
6 /* kerning data within the GPOS table at the moment. */ | |
7 /* */ | |
8 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 by */ | |
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ | |
10 /* */ | |
11 /* This file is part of the FreeType project, and may only be used, */ | |
12 /* modified, and distributed under the terms of the FreeType project */ | |
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ | |
14 /* this file you indicate that you have read the license and */ | |
15 /* understand and accept it fully. */ | |
16 /* */ | |
17 /***************************************************************************/ | |
18 | |
19 | |
20 #include "../../include/ft2build.h" | |
21 #include "../../include/freetype/internal/ftdebug.h" | |
22 #include "../../include/freetype/internal/ftstream.h" | |
23 #include "../../include/freetype/tttags.h" | |
24 #include "ttkern.h" | |
25 | |
26 #include "sferrors.h" | |
27 | |
28 | |
29 /*************************************************************************/ | |
30 /* */ | |
31 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
32 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
33 /* messages during execution. */ | |
34 /* */ | |
35 #undef FT_COMPONENT | |
36 #define FT_COMPONENT trace_ttkern | |
37 | |
38 | |
39 #undef TT_KERN_INDEX | |
40 #define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) | |
41 | |
42 | |
43 FT_LOCAL_DEF( FT_Error ) | |
44 tt_face_load_kern( TT_Face face, | |
45 FT_Stream stream ) | |
46 { | |
47 FT_Error error; | |
48 FT_ULong table_size; | |
49 FT_Byte* p; | |
50 FT_Byte* p_limit; | |
51 FT_UInt nn, num_tables; | |
52 FT_UInt32 avail = 0, ordered = 0; | |
53 | |
54 | |
55 /* the kern table is optional; exit silently if it is missing */ | |
56 error = face->goto_table( face, TTAG_kern, stream, &table_size ); | |
57 if ( error ) | |
58 goto Exit; | |
59 | |
60 if ( table_size < 4 ) /* the case of a malformed table */ | |
61 { | |
62 FT_ERROR(( "tt_face_load_kern:" | |
63 " kerning table is too small - ignored\n" )); | |
64 error = FT_THROW( Table_Missing ); | |
65 goto Exit; | |
66 } | |
67 | |
68 if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) | |
69 { | |
70 FT_ERROR(( "tt_face_load_kern:" | |
71 " could not extract kerning table\n" )); | |
72 goto Exit; | |
73 } | |
74 | |
75 face->kern_table_size = table_size; | |
76 | |
77 p = face->kern_table; | |
78 p_limit = p + table_size; | |
79 | |
80 p += 2; /* skip version */ | |
81 num_tables = FT_NEXT_USHORT( p ); | |
82 | |
83 if ( num_tables > 32 ) /* we only support up to 32 sub-tables */ | |
84 num_tables = 32; | |
85 | |
86 for ( nn = 0; nn < num_tables; nn++ ) | |
87 { | |
88 FT_UInt num_pairs, length, coverage; | |
89 FT_Byte* p_next; | |
90 FT_UInt32 mask = (FT_UInt32)1UL << nn; | |
91 | |
92 | |
93 if ( p + 6 > p_limit ) | |
94 break; | |
95 | |
96 p_next = p; | |
97 | |
98 p += 2; /* skip version */ | |
99 length = FT_NEXT_USHORT( p ); | |
100 coverage = FT_NEXT_USHORT( p ); | |
101 | |
102 if ( length <= 6 ) | |
103 break; | |
104 | |
105 p_next += length; | |
106 | |
107 if ( p_next > p_limit ) /* handle broken table */ | |
108 p_next = p_limit; | |
109 | |
110 /* only use horizontal kerning tables */ | |
111 if ( ( coverage & ~8 ) != 0x0001 || | |
112 p + 8 > p_limit ) | |
113 goto NextTable; | |
114 | |
115 num_pairs = FT_NEXT_USHORT( p ); | |
116 p += 6; | |
117 | |
118 if ( ( p_next - p ) < 6 * (int)num_pairs ) /* handle broken count */ | |
119 num_pairs = (FT_UInt)( ( p_next - p ) / 6 ); | |
120 | |
121 avail |= mask; | |
122 | |
123 /* | |
124 * Now check whether the pairs in this table are ordered. | |
125 * We then can use binary search. | |
126 */ | |
127 if ( num_pairs > 0 ) | |
128 { | |
129 FT_ULong count; | |
130 FT_ULong old_pair; | |
131 | |
132 | |
133 old_pair = FT_NEXT_ULONG( p ); | |
134 p += 2; | |
135 | |
136 for ( count = num_pairs - 1; count > 0; count-- ) | |
137 { | |
138 FT_UInt32 cur_pair; | |
139 | |
140 | |
141 cur_pair = FT_NEXT_ULONG( p ); | |
142 if ( cur_pair <= old_pair ) | |
143 break; | |
144 | |
145 p += 2; | |
146 old_pair = cur_pair; | |
147 } | |
148 | |
149 if ( count == 0 ) | |
150 ordered |= mask; | |
151 } | |
152 | |
153 NextTable: | |
154 p = p_next; | |
155 } | |
156 | |
157 face->num_kern_tables = nn; | |
158 face->kern_avail_bits = avail; | |
159 face->kern_order_bits = ordered; | |
160 | |
161 Exit: | |
162 return error; | |
163 } | |
164 | |
165 | |
166 FT_LOCAL_DEF( void ) | |
167 tt_face_done_kern( TT_Face face ) | |
168 { | |
169 FT_Stream stream = face->root.stream; | |
170 | |
171 | |
172 FT_FRAME_RELEASE( face->kern_table ); | |
173 face->kern_table_size = 0; | |
174 face->num_kern_tables = 0; | |
175 face->kern_avail_bits = 0; | |
176 face->kern_order_bits = 0; | |
177 } | |
178 | |
179 | |
180 FT_LOCAL_DEF( FT_Int ) | |
181 tt_face_get_kerning( TT_Face face, | |
182 FT_UInt left_glyph, | |
183 FT_UInt right_glyph ) | |
184 { | |
185 FT_Int result = 0; | |
186 FT_UInt count, mask = 1; | |
187 FT_Byte* p = face->kern_table; | |
188 FT_Byte* p_limit = p + face->kern_table_size; | |
189 | |
190 | |
191 p += 4; | |
192 mask = 0x0001; | |
193 | |
194 for ( count = face->num_kern_tables; | |
195 count > 0 && p + 6 <= p_limit; | |
196 count--, mask <<= 1 ) | |
197 { | |
198 FT_Byte* base = p; | |
199 FT_Byte* next = base; | |
200 FT_UInt version = FT_NEXT_USHORT( p ); | |
201 FT_UInt length = FT_NEXT_USHORT( p ); | |
202 FT_UInt coverage = FT_NEXT_USHORT( p ); | |
203 FT_UInt num_pairs; | |
204 FT_Int value = 0; | |
205 | |
206 FT_UNUSED( version ); | |
207 | |
208 | |
209 next = base + length; | |
210 | |
211 if ( next > p_limit ) /* handle broken table */ | |
212 next = p_limit; | |
213 | |
214 if ( ( face->kern_avail_bits & mask ) == 0 ) | |
215 goto NextTable; | |
216 | |
217 if ( p + 8 > next ) | |
218 goto NextTable; | |
219 | |
220 num_pairs = FT_NEXT_USHORT( p ); | |
221 p += 6; | |
222 | |
223 if ( ( next - p ) < 6 * (int)num_pairs ) /* handle broken count */ | |
224 num_pairs = (FT_UInt)( ( next - p ) / 6 ); | |
225 | |
226 switch ( coverage >> 8 ) | |
227 { | |
228 case 0: | |
229 { | |
230 FT_ULong key0 = TT_KERN_INDEX( left_glyph, right_glyph ); | |
231 | |
232 | |
233 if ( face->kern_order_bits & mask ) /* binary search */ | |
234 { | |
235 FT_UInt min = 0; | |
236 FT_UInt max = num_pairs; | |
237 | |
238 | |
239 while ( min < max ) | |
240 { | |
241 FT_UInt mid = ( min + max ) >> 1; | |
242 FT_Byte* q = p + 6 * mid; | |
243 FT_ULong key; | |
244 | |
245 | |
246 key = FT_NEXT_ULONG( q ); | |
247 | |
248 if ( key == key0 ) | |
249 { | |
250 value = FT_PEEK_SHORT( q ); | |
251 goto Found; | |
252 } | |
253 if ( key < key0 ) | |
254 min = mid + 1; | |
255 else | |
256 max = mid; | |
257 } | |
258 } | |
259 else /* linear search */ | |
260 { | |
261 FT_UInt count2; | |
262 | |
263 | |
264 for ( count2 = num_pairs; count2 > 0; count2-- ) | |
265 { | |
266 FT_ULong key = FT_NEXT_ULONG( p ); | |
267 | |
268 | |
269 if ( key == key0 ) | |
270 { | |
271 value = FT_PEEK_SHORT( p ); | |
272 goto Found; | |
273 } | |
274 p += 2; | |
275 } | |
276 } | |
277 } | |
278 break; | |
279 | |
280 /* | |
281 * We don't support format 2 because we haven't seen a single font | |
282 * using it in real life... | |
283 */ | |
284 | |
285 default: | |
286 ; | |
287 } | |
288 | |
289 goto NextTable; | |
290 | |
291 Found: | |
292 if ( coverage & 8 ) /* override or add */ | |
293 result = value; | |
294 else | |
295 result += value; | |
296 | |
297 NextTable: | |
298 p = next; | |
299 } | |
300 | |
301 return result; | |
302 } | |
303 | |
304 #undef TT_KERN_INDEX | |
305 | |
306 /* END */ | |
OLD | NEW |