1 /***************************************************************************/
5 /* Load the metrics tables common to TTF and OTF fonts (body). */
7 /* Copyright 2006, 2007, 2008, 2009 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 #ifndef 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 /* !FT_CONFIG_OPTION_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_TRACE0(( "tt_face_load_hmtx:"
165 " %cmtx has more metrics than glyphs.\n",
166 vertical
? "v" : "h" ));
168 /* Adobe simply ignores this problem. So we shall do the same. */
170 error
= vertical
? SFNT_Err_Invalid_Vert_Metrics
171 : SFNT_Err_Invalid_Horiz_Metrics
;
178 if ( FT_QNEW_ARRAY( *longs
, num_longs
) ||
179 FT_QNEW_ARRAY( *shorts
, num_shorts
) )
182 if ( FT_FRAME_ENTER( table_len
) )
188 TT_LongMetrics cur
= *longs
;
189 TT_LongMetrics limit
= cur
+ num_longs
;
192 for ( ; cur
< limit
; cur
++ )
194 cur
->advance
= FT_NEXT_USHORT( p
);
195 cur
->bearing
= FT_NEXT_SHORT( p
);
199 /* do we have an inconsistent number of metric values? */
201 TT_ShortMetrics
* cur
= *shorts
;
202 TT_ShortMetrics
* limit
= cur
+
203 FT_MIN( num_shorts
, num_shorts_checked
);
206 for ( ; cur
< limit
; cur
++ )
207 *cur
= FT_NEXT_SHORT( p
);
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 )
214 FT_Short val
= (*shorts
)[num_shorts_checked
- 1];
217 limit
= *shorts
+ num_shorts
;
218 for ( ; cur
< limit
; cur
++ )
226 face
->vertical
.number_Of_VMetrics
= (FT_UShort
)num_longs
;
228 face
->horizontal
.number_Of_HMetrics
= (FT_UShort
)num_longs
;
234 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */
237 /*************************************************************************/
240 /* tt_face_load_hhea */
243 /* Load the `hhea' or 'vhea' table into a face object. */
246 /* face :: A handle to the target face object. */
248 /* stream :: The input stream. */
250 /* vertical :: A boolean flag. If set, load `vhea'. */
253 /* FreeType error code. 0 means success. */
255 FT_LOCAL_DEF( FT_Error
)
256 tt_face_load_hhea( TT_Face face
,
261 TT_HoriHeader
* header
;
263 const FT_Frame_Field metrics_header_fields
[] =
266 #define FT_STRUCTURE TT_HoriHeader
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
),
292 void *v
= &face
->vertical
;
295 error
= face
->goto_table( face
, TTAG_vhea
, stream
, 0 );
299 header
= (TT_HoriHeader
*)v
;
303 error
= face
->goto_table( face
, TTAG_hhea
, stream
, 0 );
307 header
= &face
->horizontal
;
310 if ( FT_STREAM_READ_FIELDS( metrics_header_fields
, header
) )
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
));
317 header
->long_metrics
= NULL
;
318 header
->short_metrics
= NULL
;
325 /*************************************************************************/
328 /* tt_face_get_metrics */
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). */
336 /* header :: A pointer to either the horizontal or vertical metrics */
339 /* idx :: The glyph index. */
342 /* bearing :: The bearing, either left side or top side. */
344 /* advance :: The advance width resp. advance height. */
346 #ifndef FT_CONFIG_OPTION_OLD_INTERNALS
348 FT_LOCAL_DEF( FT_Error
)
349 tt_face_get_metrics( TT_Face face
,
353 FT_UShort
*aadvance
)
356 FT_Stream stream
= face
->root
.stream
;
357 TT_HoriHeader
* header
;
358 FT_ULong table_pos
, table_size
, table_end
;
364 void* v
= &face
->vertical
;
367 header
= (TT_HoriHeader
*)v
;
368 table_pos
= face
->vert_metrics_offset
;
369 table_size
= face
->vert_metrics_size
;
373 header
= &face
->horizontal
;
374 table_pos
= face
->horz_metrics_offset
;
375 table_size
= face
->horz_metrics_size
;
378 table_end
= table_pos
+ table_size
;
380 k
= header
->number_Of_HMetrics
;
384 if ( gindex
< (FT_UInt
)k
)
386 table_pos
+= 4 * gindex
;
387 if ( table_pos
+ 4 > table_end
)
390 if ( FT_STREAM_SEEK( table_pos
) ||
391 FT_READ_USHORT( *aadvance
) ||
392 FT_READ_SHORT( *abearing
) )
397 table_pos
+= 4 * ( k
- 1 );
398 if ( table_pos
+ 4 > table_end
)
401 if ( FT_STREAM_SEEK( table_pos
) ||
402 FT_READ_USHORT( *aadvance
) )
405 table_pos
+= 4 + 2 * ( gindex
- k
);
406 if ( table_pos
+ 2 > table_end
)
410 if ( !FT_STREAM_SEEK( table_pos
) )
411 (void)FT_READ_SHORT( *abearing
);
425 #else /* !FT_CONFIG_OPTION_OLD_INTERNALS */
427 FT_LOCAL_DEF( FT_Error
)
428 tt_face_get_metrics( TT_Face face
,
432 FT_UShort
* aadvance
)
434 void* v
= &face
->vertical
;
435 void* h
= &face
->horizontal
;
436 TT_HoriHeader
* header
= vertical
? (TT_HoriHeader
*)v
438 TT_LongMetrics longs_m
;
439 FT_UShort k
= header
->number_Of_HMetrics
;
443 !header
->long_metrics
||
444 gindex
>= (FT_UInt
)face
->max_profile
.numGlyphs
)
446 *abearing
= *aadvance
= 0;
450 if ( gindex
< (FT_UInt
)k
)
452 longs_m
= (TT_LongMetrics
)header
->long_metrics
+ gindex
;
453 *abearing
= longs_m
->bearing
;
454 *aadvance
= longs_m
->advance
;
458 *abearing
= ((TT_ShortMetrics
*)header
->short_metrics
)[gindex
- k
];
459 *aadvance
= ((TT_LongMetrics
)header
->long_metrics
)[k
- 1].advance
;
465 #endif /* !FT_CONFIG_OPTION_OLD_INTERNALS */