1 /***************************************************************************/ |
|
2 /* */ |
|
3 /* ttmtx.c */ |
|
4 /* */ |
|
5 /* Load the metrics tables common to TTF and OTF fonts (body). */ |
|
6 /* */ |
|
7 /* Copyright 2006-2009, 2011 by */ |
|
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
|
9 /* */ |
|
10 /* This file is part of the FreeType project, and may only be used, */ |
|
11 /* modified, and distributed under the terms of the FreeType project */ |
|
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
|
13 /* this file you indicate that you have read the license and */ |
|
14 /* understand and accept it fully. */ |
|
15 /* */ |
|
16 /***************************************************************************/ |
|
17 |
|
18 |
|
19 #include <ft2build.h> |
|
20 #include FT_INTERNAL_DEBUG_H |
|
21 #include FT_INTERNAL_STREAM_H |
|
22 #include FT_TRUETYPE_TAGS_H |
|
23 #include "ttmtx.h" |
|
24 |
|
25 #include "sferrors.h" |
|
26 |
|
27 |
|
28 /*************************************************************************/ |
|
29 /* */ |
|
30 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
|
31 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
|
32 /* messages during execution. */ |
|
33 /* */ |
|
34 #undef FT_COMPONENT |
|
35 #define FT_COMPONENT trace_ttmtx |
|
36 |
|
37 |
|
38 /* |
|
39 * Unfortunately, we can't enable our memory optimizations if |
|
40 * FT_CONFIG_OPTION_OLD_INTERNALS is defined. This is because at least |
|
41 * one rogue client (libXfont in the X.Org XServer) is directly accessing |
|
42 * the metrics. |
|
43 */ |
|
44 |
|
45 /*************************************************************************/ |
|
46 /* */ |
|
47 /* <Function> */ |
|
48 /* tt_face_load_hmtx */ |
|
49 /* */ |
|
50 /* <Description> */ |
|
51 /* Load the `hmtx' or `vmtx' table into a face object. */ |
|
52 /* */ |
|
53 /* <Input> */ |
|
54 /* face :: A handle to the target face object. */ |
|
55 /* */ |
|
56 /* stream :: The input stream. */ |
|
57 /* */ |
|
58 /* vertical :: A boolean flag. If set, load `vmtx'. */ |
|
59 /* */ |
|
60 /* <Return> */ |
|
61 /* FreeType error code. 0 means success. */ |
|
62 /* */ |
|
63 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS |
|
64 |
|
65 FT_LOCAL_DEF( FT_Error ) |
|
66 tt_face_load_hmtx( TT_Face face, |
|
67 FT_Stream stream, |
|
68 FT_Bool vertical ) |
|
69 { |
|
70 FT_Error error; |
|
71 FT_ULong tag, table_size; |
|
72 FT_ULong* ptable_offset; |
|
73 FT_ULong* ptable_size; |
|
74 |
|
75 |
|
76 if ( vertical ) |
|
77 { |
|
78 tag = TTAG_vmtx; |
|
79 ptable_offset = &face->vert_metrics_offset; |
|
80 ptable_size = &face->vert_metrics_size; |
|
81 } |
|
82 else |
|
83 { |
|
84 tag = TTAG_hmtx; |
|
85 ptable_offset = &face->horz_metrics_offset; |
|
86 ptable_size = &face->horz_metrics_size; |
|
87 } |
|
88 |
|
89 error = face->goto_table( face, tag, stream, &table_size ); |
|
90 if ( error ) |
|
91 goto Fail; |
|
92 |
|
93 *ptable_size = table_size; |
|
94 *ptable_offset = FT_STREAM_POS(); |
|
95 |
|
96 Fail: |
|
97 return error; |
|
98 } |
|
99 |
|
100 #else /* !FT_CONFIG_OPTION_OLD_INTERNALS */ |
|
101 |
|
102 FT_LOCAL_DEF( FT_Error ) |
|
103 tt_face_load_hmtx( TT_Face face, |
|
104 FT_Stream stream, |
|
105 FT_Bool vertical ) |
|
106 { |
|
107 FT_Error error; |
|
108 FT_Memory memory = stream->memory; |
|
109 |
|
110 FT_ULong table_len; |
|
111 FT_Long num_shorts, num_longs, num_shorts_checked; |
|
112 |
|
113 TT_LongMetrics* longs; |
|
114 TT_ShortMetrics** shorts; |
|
115 FT_Byte* p; |
|
116 |
|
117 |
|
118 if ( vertical ) |
|
119 { |
|
120 void* lm = &face->vertical.long_metrics; |
|
121 void** sm = &face->vertical.short_metrics; |
|
122 |
|
123 |
|
124 error = face->goto_table( face, TTAG_vmtx, stream, &table_len ); |
|
125 if ( error ) |
|
126 goto Fail; |
|
127 |
|
128 num_longs = face->vertical.number_Of_VMetrics; |
|
129 if ( (FT_ULong)num_longs > table_len / 4 ) |
|
130 num_longs = (FT_Long)( table_len / 4 ); |
|
131 |
|
132 face->vertical.number_Of_VMetrics = 0; |
|
133 |
|
134 longs = (TT_LongMetrics*)lm; |
|
135 shorts = (TT_ShortMetrics**)sm; |
|
136 } |
|
137 else |
|
138 { |
|
139 void* lm = &face->horizontal.long_metrics; |
|
140 void** sm = &face->horizontal.short_metrics; |
|
141 |
|
142 |
|
143 error = face->goto_table( face, TTAG_hmtx, stream, &table_len ); |
|
144 if ( error ) |
|
145 goto Fail; |
|
146 |
|
147 num_longs = face->horizontal.number_Of_HMetrics; |
|
148 if ( (FT_ULong)num_longs > table_len / 4 ) |
|
149 num_longs = (FT_Long)( table_len / 4 ); |
|
150 |
|
151 face->horizontal.number_Of_HMetrics = 0; |
|
152 |
|
153 longs = (TT_LongMetrics*)lm; |
|
154 shorts = (TT_ShortMetrics**)sm; |
|
155 } |
|
156 |
|
157 /* never trust derived values */ |
|
158 |
|
159 num_shorts = face->max_profile.numGlyphs - num_longs; |
|
160 num_shorts_checked = ( table_len - num_longs * 4L ) / 2; |
|
161 |
|
162 if ( num_shorts < 0 ) |
|
163 { |
|
164 FT_TRACE0(( "tt_face_load_hmtx:" |
|
165 " %cmtx has more metrics than glyphs.\n", |
|
166 vertical ? 'v' : 'h' )); |
|
167 |
|
168 /* Adobe simply ignores this problem. So we shall do the same. */ |
|
169 #if 0 |
|
170 error = vertical ? SFNT_Err_Invalid_Vert_Metrics |
|
171 : SFNT_Err_Invalid_Horiz_Metrics; |
|
172 goto Exit; |
|
173 #else |
|
174 num_shorts = 0; |
|
175 #endif |
|
176 } |
|
177 |
|
178 if ( FT_QNEW_ARRAY( *longs, num_longs ) || |
|
179 FT_QNEW_ARRAY( *shorts, num_shorts ) ) |
|
180 goto Fail; |
|
181 |
|
182 if ( FT_FRAME_ENTER( table_len ) ) |
|
183 goto Fail; |
|
184 |
|
185 p = stream->cursor; |
|
186 |
|
187 { |
|
188 TT_LongMetrics cur = *longs; |
|
189 TT_LongMetrics limit = cur + num_longs; |
|
190 |
|
191 |
|
192 for ( ; cur < limit; cur++ ) |
|
193 { |
|
194 cur->advance = FT_NEXT_USHORT( p ); |
|
195 cur->bearing = FT_NEXT_SHORT( p ); |
|
196 } |
|
197 } |
|
198 |
|
199 /* do we have an inconsistent number of metric values? */ |
|
200 { |
|
201 TT_ShortMetrics* cur = *shorts; |
|
202 TT_ShortMetrics* limit = cur + |
|
203 FT_MIN( num_shorts, num_shorts_checked ); |
|
204 |
|
205 |
|
206 for ( ; cur < limit; cur++ ) |
|
207 *cur = FT_NEXT_SHORT( p ); |
|
208 |
|
209 /* We fill up the missing left side bearings with the */ |
|
210 /* last valid value. Since this will occur for buggy CJK */ |
|
211 /* fonts usually only, nothing serious will happen. */ |
|
212 if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 ) |
|
213 { |
|
214 FT_Short val = (*shorts)[num_shorts_checked - 1]; |
|
215 |
|
216 |
|
217 limit = *shorts + num_shorts; |
|
218 for ( ; cur < limit; cur++ ) |
|
219 *cur = val; |
|
220 } |
|
221 } |
|
222 |
|
223 FT_FRAME_EXIT(); |
|
224 |
|
225 if ( vertical ) |
|
226 face->vertical.number_Of_VMetrics = (FT_UShort)num_longs; |
|
227 else |
|
228 face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs; |
|
229 |
|
230 Fail: |
|
231 return error; |
|
232 } |
|
233 |
|
234 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */ |
|
235 |
|
236 |
|
237 /*************************************************************************/ |
|
238 /* */ |
|
239 /* <Function> */ |
|
240 /* tt_face_load_hhea */ |
|
241 /* */ |
|
242 /* <Description> */ |
|
243 /* Load the `hhea' or 'vhea' table into a face object. */ |
|
244 /* */ |
|
245 /* <Input> */ |
|
246 /* face :: A handle to the target face object. */ |
|
247 /* */ |
|
248 /* stream :: The input stream. */ |
|
249 /* */ |
|
250 /* vertical :: A boolean flag. If set, load `vhea'. */ |
|
251 /* */ |
|
252 /* <Return> */ |
|
253 /* FreeType error code. 0 means success. */ |
|
254 /* */ |
|
255 FT_LOCAL_DEF( FT_Error ) |
|
256 tt_face_load_hhea( TT_Face face, |
|
257 FT_Stream stream, |
|
258 FT_Bool vertical ) |
|
259 { |
|
260 FT_Error error; |
|
261 TT_HoriHeader* header; |
|
262 |
|
263 const FT_Frame_Field metrics_header_fields[] = |
|
264 { |
|
265 #undef FT_STRUCTURE |
|
266 #define FT_STRUCTURE TT_HoriHeader |
|
267 |
|
268 FT_FRAME_START( 36 ), |
|
269 FT_FRAME_ULONG ( Version ), |
|
270 FT_FRAME_SHORT ( Ascender ), |
|
271 FT_FRAME_SHORT ( Descender ), |
|
272 FT_FRAME_SHORT ( Line_Gap ), |
|
273 FT_FRAME_USHORT( advance_Width_Max ), |
|
274 FT_FRAME_SHORT ( min_Left_Side_Bearing ), |
|
275 FT_FRAME_SHORT ( min_Right_Side_Bearing ), |
|
276 FT_FRAME_SHORT ( xMax_Extent ), |
|
277 FT_FRAME_SHORT ( caret_Slope_Rise ), |
|
278 FT_FRAME_SHORT ( caret_Slope_Run ), |
|
279 FT_FRAME_SHORT ( caret_Offset ), |
|
280 FT_FRAME_SHORT ( Reserved[0] ), |
|
281 FT_FRAME_SHORT ( Reserved[1] ), |
|
282 FT_FRAME_SHORT ( Reserved[2] ), |
|
283 FT_FRAME_SHORT ( Reserved[3] ), |
|
284 FT_FRAME_SHORT ( metric_Data_Format ), |
|
285 FT_FRAME_USHORT( number_Of_HMetrics ), |
|
286 FT_FRAME_END |
|
287 }; |
|
288 |
|
289 |
|
290 if ( vertical ) |
|
291 { |
|
292 void *v = &face->vertical; |
|
293 |
|
294 |
|
295 error = face->goto_table( face, TTAG_vhea, stream, 0 ); |
|
296 if ( error ) |
|
297 goto Fail; |
|
298 |
|
299 header = (TT_HoriHeader*)v; |
|
300 } |
|
301 else |
|
302 { |
|
303 error = face->goto_table( face, TTAG_hhea, stream, 0 ); |
|
304 if ( error ) |
|
305 goto Fail; |
|
306 |
|
307 header = &face->horizontal; |
|
308 } |
|
309 |
|
310 if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) ) |
|
311 goto Fail; |
|
312 |
|
313 FT_TRACE3(( "Ascender: %5d\n", header->Ascender )); |
|
314 FT_TRACE3(( "Descender: %5d\n", header->Descender )); |
|
315 FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics )); |
|
316 |
|
317 header->long_metrics = NULL; |
|
318 header->short_metrics = NULL; |
|
319 |
|
320 Fail: |
|
321 return error; |
|
322 } |
|
323 |
|
324 |
|
325 /*************************************************************************/ |
|
326 /* */ |
|
327 /* <Function> */ |
|
328 /* tt_face_get_metrics */ |
|
329 /* */ |
|
330 /* <Description> */ |
|
331 /* Returns the horizontal or vertical metrics in font units for a */ |
|
332 /* given glyph. The metrics are the left side bearing (resp. top */ |
|
333 /* side bearing) and advance width (resp. advance height). */ |
|
334 /* */ |
|
335 /* <Input> */ |
|
336 /* header :: A pointer to either the horizontal or vertical metrics */ |
|
337 /* structure. */ |
|
338 /* */ |
|
339 /* idx :: The glyph index. */ |
|
340 /* */ |
|
341 /* <Output> */ |
|
342 /* bearing :: The bearing, either left side or top side. */ |
|
343 /* */ |
|
344 /* advance :: The advance width resp. advance height. */ |
|
345 /* */ |
|
346 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS |
|
347 |
|
348 FT_LOCAL_DEF( FT_Error ) |
|
349 tt_face_get_metrics( TT_Face face, |
|
350 FT_Bool vertical, |
|
351 FT_UInt gindex, |
|
352 FT_Short *abearing, |
|
353 FT_UShort *aadvance ) |
|
354 { |
|
355 FT_Error error; |
|
356 FT_Stream stream = face->root.stream; |
|
357 TT_HoriHeader* header; |
|
358 FT_ULong table_pos, table_size, table_end; |
|
359 FT_UShort k; |
|
360 |
|
361 |
|
362 if ( vertical ) |
|
363 { |
|
364 void* v = &face->vertical; |
|
365 |
|
366 |
|
367 header = (TT_HoriHeader*)v; |
|
368 table_pos = face->vert_metrics_offset; |
|
369 table_size = face->vert_metrics_size; |
|
370 } |
|
371 else |
|
372 { |
|
373 header = &face->horizontal; |
|
374 table_pos = face->horz_metrics_offset; |
|
375 table_size = face->horz_metrics_size; |
|
376 } |
|
377 |
|
378 table_end = table_pos + table_size; |
|
379 |
|
380 k = header->number_Of_HMetrics; |
|
381 |
|
382 if ( k > 0 ) |
|
383 { |
|
384 if ( gindex < (FT_UInt)k ) |
|
385 { |
|
386 table_pos += 4 * gindex; |
|
387 if ( table_pos + 4 > table_end ) |
|
388 goto NoData; |
|
389 |
|
390 if ( FT_STREAM_SEEK( table_pos ) || |
|
391 FT_READ_USHORT( *aadvance ) || |
|
392 FT_READ_SHORT( *abearing ) ) |
|
393 goto NoData; |
|
394 } |
|
395 else |
|
396 { |
|
397 table_pos += 4 * ( k - 1 ); |
|
398 if ( table_pos + 4 > table_end ) |
|
399 goto NoData; |
|
400 |
|
401 if ( FT_STREAM_SEEK( table_pos ) || |
|
402 FT_READ_USHORT( *aadvance ) ) |
|
403 goto NoData; |
|
404 |
|
405 table_pos += 4 + 2 * ( gindex - k ); |
|
406 if ( table_pos + 2 > table_end ) |
|
407 *abearing = 0; |
|
408 else |
|
409 { |
|
410 if ( !FT_STREAM_SEEK( table_pos ) ) |
|
411 (void)FT_READ_SHORT( *abearing ); |
|
412 } |
|
413 } |
|
414 } |
|
415 else |
|
416 { |
|
417 NoData: |
|
418 *abearing = 0; |
|
419 *aadvance = 0; |
|
420 } |
|
421 |
|
422 return SFNT_Err_Ok; |
|
423 } |
|
424 |
|
425 #else /* !FT_CONFIG_OPTION_OLD_INTERNALS */ |
|
426 |
|
427 FT_LOCAL_DEF( FT_Error ) |
|
428 tt_face_get_metrics( TT_Face face, |
|
429 FT_Bool vertical, |
|
430 FT_UInt gindex, |
|
431 FT_Short* abearing, |
|
432 FT_UShort* aadvance ) |
|
433 { |
|
434 void* v = &face->vertical; |
|
435 void* h = &face->horizontal; |
|
436 TT_HoriHeader* header = vertical ? (TT_HoriHeader*)v |
|
437 : (TT_HoriHeader*)h; |
|
438 TT_LongMetrics longs_m; |
|
439 FT_UShort k = header->number_Of_HMetrics; |
|
440 |
|
441 |
|
442 if ( k == 0 || |
|
443 !header->long_metrics || |
|
444 gindex >= (FT_UInt)face->max_profile.numGlyphs ) |
|
445 { |
|
446 *abearing = *aadvance = 0; |
|
447 return SFNT_Err_Ok; |
|
448 } |
|
449 |
|
450 if ( gindex < (FT_UInt)k ) |
|
451 { |
|
452 longs_m = (TT_LongMetrics)header->long_metrics + gindex; |
|
453 *abearing = longs_m->bearing; |
|
454 *aadvance = longs_m->advance; |
|
455 } |
|
456 else |
|
457 { |
|
458 *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k]; |
|
459 *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance; |
|
460 } |
|
461 |
|
462 return SFNT_Err_Ok; |
|
463 } |
|
464 |
|
465 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */ |
|
466 |
|
467 |
|
468 /* END */ |
|