Sync with trunk head
[reactos.git] / lib / 3rdparty / freetype / src / sfnt / ttmtx.c
1 /***************************************************************************/
2 /* */
3 /* ttmtx.c */
4 /* */
5 /* Load the metrics tables common to TTF and OTF fonts (body). */
6 /* */
7 /* Copyright 2006, 2007 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 #if !defined 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 /* !OPTIMIZE_MEMORY || 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_ERROR(( "%cmtx has more metrics than glyphs.\n" ));
165
166 /* Adobe simply ignores this problem. So we shall do the same. */
167 #if 0
168 error = vertical ? SFNT_Err_Invalid_Vert_Metrics
169 : SFNT_Err_Invalid_Horiz_Metrics;
170 goto Exit;
171 #else
172 num_shorts = 0;
173 #endif
174 }
175
176 if ( FT_QNEW_ARRAY( *longs, num_longs ) ||
177 FT_QNEW_ARRAY( *shorts, num_shorts ) )
178 goto Fail;
179
180 if ( FT_FRAME_ENTER( table_len ) )
181 goto Fail;
182
183 p = stream->cursor;
184
185 {
186 TT_LongMetrics cur = *longs;
187 TT_LongMetrics limit = cur + num_longs;
188
189
190 for ( ; cur < limit; cur++ )
191 {
192 cur->advance = FT_NEXT_USHORT( p );
193 cur->bearing = FT_NEXT_SHORT( p );
194 }
195 }
196
197 /* do we have an inconsistent number of metric values? */
198 {
199 TT_ShortMetrics* cur = *shorts;
200 TT_ShortMetrics* limit = cur +
201 FT_MIN( num_shorts, num_shorts_checked );
202
203
204 for ( ; cur < limit; cur++ )
205 *cur = FT_NEXT_SHORT( p );
206
207 /* We fill up the missing left side bearings with the */
208 /* last valid value. Since this will occur for buggy CJK */
209 /* fonts usually only, nothing serious will happen. */
210 if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
211 {
212 FT_Short val = (*shorts)[num_shorts_checked - 1];
213
214
215 limit = *shorts + num_shorts;
216 for ( ; cur < limit; cur++ )
217 *cur = val;
218 }
219 }
220
221 FT_FRAME_EXIT();
222
223 if ( vertical )
224 face->vertical.number_Of_VMetrics = (FT_UShort)num_longs;
225 else
226 face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs;
227
228 Fail:
229 return error;
230 }
231
232 #endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */
233
234
235 /*************************************************************************/
236 /* */
237 /* <Function> */
238 /* tt_face_load_hhea */
239 /* */
240 /* <Description> */
241 /* Load the `hhea' or 'vhea' table into a face object. */
242 /* */
243 /* <Input> */
244 /* face :: A handle to the target face object. */
245 /* */
246 /* stream :: The input stream. */
247 /* */
248 /* vertical :: A boolean flag. If set, load `vhea'. */
249 /* */
250 /* <Return> */
251 /* FreeType error code. 0 means success. */
252 /* */
253 FT_LOCAL_DEF( FT_Error )
254 tt_face_load_hhea( TT_Face face,
255 FT_Stream stream,
256 FT_Bool vertical )
257 {
258 FT_Error error;
259 TT_HoriHeader* header;
260
261 const FT_Frame_Field metrics_header_fields[] =
262 {
263 #undef FT_STRUCTURE
264 #define FT_STRUCTURE TT_HoriHeader
265
266 FT_FRAME_START( 36 ),
267 FT_FRAME_ULONG ( Version ),
268 FT_FRAME_SHORT ( Ascender ),
269 FT_FRAME_SHORT ( Descender ),
270 FT_FRAME_SHORT ( Line_Gap ),
271 FT_FRAME_USHORT( advance_Width_Max ),
272 FT_FRAME_SHORT ( min_Left_Side_Bearing ),
273 FT_FRAME_SHORT ( min_Right_Side_Bearing ),
274 FT_FRAME_SHORT ( xMax_Extent ),
275 FT_FRAME_SHORT ( caret_Slope_Rise ),
276 FT_FRAME_SHORT ( caret_Slope_Run ),
277 FT_FRAME_SHORT ( caret_Offset ),
278 FT_FRAME_SHORT ( Reserved[0] ),
279 FT_FRAME_SHORT ( Reserved[1] ),
280 FT_FRAME_SHORT ( Reserved[2] ),
281 FT_FRAME_SHORT ( Reserved[3] ),
282 FT_FRAME_SHORT ( metric_Data_Format ),
283 FT_FRAME_USHORT( number_Of_HMetrics ),
284 FT_FRAME_END
285 };
286
287
288 if ( vertical )
289 {
290 void *v = &face->vertical;
291
292
293 error = face->goto_table( face, TTAG_vhea, stream, 0 );
294 if ( error )
295 goto Fail;
296
297 header = (TT_HoriHeader*)v;
298 }
299 else
300 {
301 error = face->goto_table( face, TTAG_hhea, stream, 0 );
302 if ( error )
303 goto Fail;
304
305 header = &face->horizontal;
306 }
307
308 if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
309 goto Fail;
310
311 FT_TRACE3(( "Ascender: %5d\n", header->Ascender ));
312 FT_TRACE3(( "Descender: %5d\n", header->Descender ));
313 FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics ));
314
315 header->long_metrics = NULL;
316 header->short_metrics = NULL;
317
318 Fail:
319 return error;
320 }
321
322
323 /*************************************************************************/
324 /* */
325 /* <Function> */
326 /* tt_face_get_metrics */
327 /* */
328 /* <Description> */
329 /* Returns the horizontal or vertical metrics in font units for a */
330 /* given glyph. The metrics are the left side bearing (resp. top */
331 /* side bearing) and advance width (resp. advance height). */
332 /* */
333 /* <Input> */
334 /* header :: A pointer to either the horizontal or vertical metrics */
335 /* structure. */
336 /* */
337 /* idx :: The glyph index. */
338 /* */
339 /* <Output> */
340 /* bearing :: The bearing, either left side or top side. */
341 /* */
342 /* advance :: The advance width resp. advance height. */
343 /* */
344 #if !defined FT_CONFIG_OPTION_OLD_INTERNALS
345
346 FT_LOCAL_DEF( FT_Error )
347 tt_face_get_metrics( TT_Face face,
348 FT_Bool vertical,
349 FT_UInt gindex,
350 FT_Short *abearing,
351 FT_UShort *aadvance )
352 {
353 FT_Error error;
354 FT_Stream stream = face->root.stream;
355 TT_HoriHeader* header;
356 FT_ULong table_pos, table_size, table_end;
357 FT_UShort k;
358
359
360 if ( vertical )
361 {
362 void* v = &face->vertical;
363
364
365 header = (TT_HoriHeader*)v;
366 table_pos = face->vert_metrics_offset;
367 table_size = face->vert_metrics_size;
368 }
369 else
370 {
371 header = &face->horizontal;
372 table_pos = face->horz_metrics_offset;
373 table_size = face->horz_metrics_size;
374 }
375
376 table_end = table_pos + table_size;
377
378 k = header->number_Of_HMetrics;
379
380 if ( k > 0 )
381 {
382 if ( gindex < (FT_UInt)k )
383 {
384 table_pos += 4 * gindex;
385 if ( table_pos + 4 > table_end )
386 goto NoData;
387
388 if ( FT_STREAM_SEEK( table_pos ) ||
389 FT_READ_USHORT( *aadvance ) ||
390 FT_READ_SHORT( *abearing ) )
391 goto NoData;
392 }
393 else
394 {
395 table_pos += 4 * ( k - 1 );
396 if ( table_pos + 4 > table_end )
397 goto NoData;
398
399 if ( FT_STREAM_SEEK( table_pos ) ||
400 FT_READ_USHORT( *aadvance ) )
401 goto NoData;
402
403 table_pos += 4 + 2 * ( gindex - k );
404 if ( table_pos + 2 > table_end )
405 *abearing = 0;
406 else
407 {
408 if ( !FT_STREAM_SEEK( table_pos ) )
409 (void)FT_READ_SHORT( *abearing );
410 }
411 }
412 }
413 else
414 {
415 NoData:
416 *abearing = 0;
417 *aadvance = 0;
418 }
419
420 return SFNT_Err_Ok;
421 }
422
423 #else /* OLD_INTERNALS */
424
425 FT_LOCAL_DEF( FT_Error )
426 tt_face_get_metrics( TT_Face face,
427 FT_Bool vertical,
428 FT_UInt gindex,
429 FT_Short* abearing,
430 FT_UShort* aadvance )
431 {
432 void* v = &face->vertical;
433 void* h = &face->horizontal;
434 TT_HoriHeader* header = vertical ? (TT_HoriHeader*)v : h;
435 TT_LongMetrics longs_m;
436 FT_UShort k = header->number_Of_HMetrics;
437
438
439 if ( k == 0 ||
440 !header->long_metrics ||
441 gindex >= (FT_UInt)face->max_profile.numGlyphs )
442 {
443 *abearing = *aadvance = 0;
444 return SFNT_Err_Ok;
445 }
446
447 if ( gindex < (FT_UInt)k )
448 {
449 longs_m = (TT_LongMetrics)header->long_metrics + gindex;
450 *abearing = longs_m->bearing;
451 *aadvance = longs_m->advance;
452 }
453 else
454 {
455 *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k];
456 *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
457 }
458
459 return SFNT_Err_Ok;
460 }
461
462 #endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */
463
464
465 /* END */