1 /***************************************************************************/
5 /* Load the metrics tables common to TTF and OTF fonts (body). */
7 /* Copyright 2006, 2007 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_STREAM_H
22 #include FT_TRUETYPE_TAGS_H
28 /*************************************************************************/
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. */
35 #define FT_COMPONENT trace_ttmtx
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
45 /*************************************************************************/
48 /* tt_face_load_hmtx */
51 /* Load the `hmtx' or `vmtx' table into a face object. */
54 /* face :: A handle to the target face object. */
56 /* stream :: The input stream. */
58 /* vertical :: A boolean flag. If set, load `vmtx'. */
61 /* FreeType error code. 0 means success. */
63 #if !defined FT_CONFIG_OPTION_OLD_INTERNALS
65 FT_LOCAL_DEF( FT_Error
)
66 tt_face_load_hmtx( TT_Face face
,
71 FT_ULong tag
, table_size
;
72 FT_ULong
* ptable_offset
;
73 FT_ULong
* ptable_size
;
79 ptable_offset
= &face
->vert_metrics_offset
;
80 ptable_size
= &face
->vert_metrics_size
;
85 ptable_offset
= &face
->horz_metrics_offset
;
86 ptable_size
= &face
->horz_metrics_size
;
89 error
= face
->goto_table( face
, tag
, stream
, &table_size
);
93 *ptable_size
= table_size
;
94 *ptable_offset
= FT_STREAM_POS();
100 #else /* !OPTIMIZE_MEMORY || OLD_INTERNALS */
102 FT_LOCAL_DEF( FT_Error
)
103 tt_face_load_hmtx( TT_Face face
,
108 FT_Memory memory
= stream
->memory
;
111 FT_Long num_shorts
, num_longs
, num_shorts_checked
;
113 TT_LongMetrics
* longs
;
114 TT_ShortMetrics
** shorts
;
120 void* lm
= &face
->vertical
.long_metrics
;
121 void** sm
= &face
->vertical
.short_metrics
;
124 error
= face
->goto_table( face
, TTAG_vmtx
, stream
, &table_len
);
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 );
132 face
->vertical
.number_Of_VMetrics
= 0;
134 longs
= (TT_LongMetrics
*)lm
;
135 shorts
= (TT_ShortMetrics
**)sm
;
139 void* lm
= &face
->horizontal
.long_metrics
;
140 void** sm
= &face
->horizontal
.short_metrics
;
143 error
= face
->goto_table( face
, TTAG_hmtx
, stream
, &table_len
);
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 );
151 face
->horizontal
.number_Of_HMetrics
= 0;
153 longs
= (TT_LongMetrics
*)lm
;
154 shorts
= (TT_ShortMetrics
**)sm
;
157 /* never trust derived values */
159 num_shorts
= face
->max_profile
.numGlyphs
- num_longs
;
160 num_shorts_checked
= ( table_len
- num_longs
* 4L ) / 2;
162 if ( num_shorts
< 0 )
164 FT_ERROR(( "%cmtx has more metrics than glyphs.\n" ));
166 /* Adobe simply ignores this problem. So we shall do the same. */
168 error
= vertical
? SFNT_Err_Invalid_Vert_Metrics
169 : SFNT_Err_Invalid_Horiz_Metrics
;
176 if ( FT_QNEW_ARRAY( *longs
, num_longs
) ||
177 FT_QNEW_ARRAY( *shorts
, num_shorts
) )
180 if ( FT_FRAME_ENTER( table_len
) )
186 TT_LongMetrics cur
= *longs
;
187 TT_LongMetrics limit
= cur
+ num_longs
;
190 for ( ; cur
< limit
; cur
++ )
192 cur
->advance
= FT_NEXT_USHORT( p
);
193 cur
->bearing
= FT_NEXT_SHORT( p
);
197 /* do we have an inconsistent number of metric values? */
199 TT_ShortMetrics
* cur
= *shorts
;
200 TT_ShortMetrics
* limit
= cur
+
201 FT_MIN( num_shorts
, num_shorts_checked
);
204 for ( ; cur
< limit
; cur
++ )
205 *cur
= FT_NEXT_SHORT( p
);
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 )
212 FT_Short val
= (*shorts
)[num_shorts_checked
- 1];
215 limit
= *shorts
+ num_shorts
;
216 for ( ; cur
< limit
; cur
++ )
224 face
->vertical
.number_Of_VMetrics
= (FT_UShort
)num_longs
;
226 face
->horizontal
.number_Of_HMetrics
= (FT_UShort
)num_longs
;
232 #endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */
235 /*************************************************************************/
238 /* tt_face_load_hhea */
241 /* Load the `hhea' or 'vhea' table into a face object. */
244 /* face :: A handle to the target face object. */
246 /* stream :: The input stream. */
248 /* vertical :: A boolean flag. If set, load `vhea'. */
251 /* FreeType error code. 0 means success. */
253 FT_LOCAL_DEF( FT_Error
)
254 tt_face_load_hhea( TT_Face face
,
259 TT_HoriHeader
* header
;
261 const FT_Frame_Field metrics_header_fields
[] =
264 #define FT_STRUCTURE TT_HoriHeader
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
),
290 void *v
= &face
->vertical
;
293 error
= face
->goto_table( face
, TTAG_vhea
, stream
, 0 );
297 header
= (TT_HoriHeader
*)v
;
301 error
= face
->goto_table( face
, TTAG_hhea
, stream
, 0 );
305 header
= &face
->horizontal
;
308 if ( FT_STREAM_READ_FIELDS( metrics_header_fields
, header
) )
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
));
315 header
->long_metrics
= NULL
;
316 header
->short_metrics
= NULL
;
323 /*************************************************************************/
326 /* tt_face_get_metrics */
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). */
334 /* header :: A pointer to either the horizontal or vertical metrics */
337 /* idx :: The glyph index. */
340 /* bearing :: The bearing, either left side or top side. */
342 /* advance :: The advance width resp. advance height. */
344 #if !defined FT_CONFIG_OPTION_OLD_INTERNALS
346 FT_LOCAL_DEF( FT_Error
)
347 tt_face_get_metrics( TT_Face face
,
351 FT_UShort
*aadvance
)
354 FT_Stream stream
= face
->root
.stream
;
355 TT_HoriHeader
* header
;
356 FT_ULong table_pos
, table_size
, table_end
;
362 void* v
= &face
->vertical
;
365 header
= (TT_HoriHeader
*)v
;
366 table_pos
= face
->vert_metrics_offset
;
367 table_size
= face
->vert_metrics_size
;
371 header
= &face
->horizontal
;
372 table_pos
= face
->horz_metrics_offset
;
373 table_size
= face
->horz_metrics_size
;
376 table_end
= table_pos
+ table_size
;
378 k
= header
->number_Of_HMetrics
;
382 if ( gindex
< (FT_UInt
)k
)
384 table_pos
+= 4 * gindex
;
385 if ( table_pos
+ 4 > table_end
)
388 if ( FT_STREAM_SEEK( table_pos
) ||
389 FT_READ_USHORT( *aadvance
) ||
390 FT_READ_SHORT( *abearing
) )
395 table_pos
+= 4 * ( k
- 1 );
396 if ( table_pos
+ 4 > table_end
)
399 if ( FT_STREAM_SEEK( table_pos
) ||
400 FT_READ_USHORT( *aadvance
) )
403 table_pos
+= 4 + 2 * ( gindex
- k
);
404 if ( table_pos
+ 2 > table_end
)
408 if ( !FT_STREAM_SEEK( table_pos
) )
409 (void)FT_READ_SHORT( *abearing
);
423 #else /* OLD_INTERNALS */
425 FT_LOCAL_DEF( FT_Error
)
426 tt_face_get_metrics( TT_Face face
,
430 FT_UShort
* aadvance
)
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
;
440 !header
->long_metrics
||
441 gindex
>= (FT_UInt
)face
->max_profile
.numGlyphs
)
443 *abearing
= *aadvance
= 0;
447 if ( gindex
< (FT_UInt
)k
)
449 longs_m
= (TT_LongMetrics
)header
->long_metrics
+ gindex
;
450 *abearing
= longs_m
->bearing
;
451 *aadvance
= longs_m
->advance
;
455 *abearing
= ((TT_ShortMetrics
*)header
->short_metrics
)[gindex
- k
];
456 *aadvance
= ((TT_LongMetrics
)header
->long_metrics
)[k
- 1].advance
;
462 #endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */