summaryrefslogtreecommitdiffstats
path: root/src/sfnt/ttmtx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sfnt/ttmtx.c')
-rw-r--r--src/sfnt/ttmtx.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/src/sfnt/ttmtx.c b/src/sfnt/ttmtx.c
new file mode 100644
index 0000000..55f681a
--- /dev/null
+++ b/src/sfnt/ttmtx.c
@@ -0,0 +1,466 @@
+/***************************************************************************/
+/* */
+/* ttmtx.c */
+/* */
+/* Load the metrics tables common to TTF and OTF fonts (body). */
+/* */
+/* Copyright 2006, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttmtx.h"
+
+#include "sferrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttmtx
+
+
+ /*
+ * Unfortunately, we can't enable our memory optimizations if
+ * FT_CONFIG_OPTION_OLD_INTERNALS is defined. This is because at least
+ * one rogue client (libXfont in the X.Org XServer) is directly accessing
+ * the metrics.
+ */
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_hmtx */
+ /* */
+ /* <Description> */
+ /* Load the `hmtx' or `vmtx' table into a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* vertical :: A boolean flag. If set, load `vmtx'. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+#if !defined FT_CONFIG_OPTION_OLD_INTERNALS
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_hmtx( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical )
+ {
+ FT_Error error;
+ FT_ULong tag, table_size;
+ FT_ULong* ptable_offset;
+ FT_ULong* ptable_size;
+
+
+ if ( vertical )
+ {
+ tag = TTAG_vmtx;
+ ptable_offset = &face->vert_metrics_offset;
+ ptable_size = &face->vert_metrics_size;
+ }
+ else
+ {
+ tag = TTAG_hmtx;
+ ptable_offset = &face->horz_metrics_offset;
+ ptable_size = &face->horz_metrics_size;
+ }
+
+ error = face->goto_table( face, tag, stream, &table_size );
+ if ( error )
+ goto Fail;
+
+ *ptable_size = table_size;
+ *ptable_offset = FT_STREAM_POS();
+
+ Fail:
+ return error;
+ }
+
+#else /* !OPTIMIZE_MEMORY || OLD_INTERNALS */
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_hmtx( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ FT_ULong table_len;
+ FT_Long num_shorts, num_longs, num_shorts_checked;
+
+ TT_LongMetrics* longs;
+ TT_ShortMetrics** shorts;
+ FT_Byte* p;
+
+
+ if ( vertical )
+ {
+ void* lm = &face->vertical.long_metrics;
+ void** sm = &face->vertical.short_metrics;
+
+
+ error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
+ if ( error )
+ goto Fail;
+
+ num_longs = face->vertical.number_Of_VMetrics;
+ if ( (FT_ULong)num_longs > table_len / 4 )
+ num_longs = (FT_Long)( table_len / 4 );
+
+ face->vertical.number_Of_VMetrics = 0;
+
+ longs = (TT_LongMetrics*)lm;
+ shorts = (TT_ShortMetrics**)sm;
+ }
+ else
+ {
+ void* lm = &face->horizontal.long_metrics;
+ void** sm = &face->horizontal.short_metrics;
+
+
+ error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
+ if ( error )
+ goto Fail;
+
+ num_longs = face->horizontal.number_Of_HMetrics;
+ if ( (FT_ULong)num_longs > table_len / 4 )
+ num_longs = (FT_Long)( table_len / 4 );
+
+ face->horizontal.number_Of_HMetrics = 0;
+
+ longs = (TT_LongMetrics*)lm;
+ shorts = (TT_ShortMetrics**)sm;
+ }
+
+ /* never trust derived values */
+
+ num_shorts = face->max_profile.numGlyphs - num_longs;
+ num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
+
+ if ( num_shorts < 0 )
+ {
+ FT_ERROR(( "%cmtx has more metrics than glyphs.\n" ));
+
+ /* Adobe simply ignores this problem. So we shall do the same. */
+#if 0
+ error = vertical ? SFNT_Err_Invalid_Vert_Metrics
+ : SFNT_Err_Invalid_Horiz_Metrics;
+ goto Exit;
+#else
+ num_shorts = 0;
+#endif
+ }
+
+ if ( FT_QNEW_ARRAY( *longs, num_longs ) ||
+ FT_QNEW_ARRAY( *shorts, num_shorts ) )
+ goto Fail;
+
+ if ( FT_FRAME_ENTER( table_len ) )
+ goto Fail;
+
+ p = stream->cursor;
+
+ {
+ TT_LongMetrics cur = *longs;
+ TT_LongMetrics limit = cur + num_longs;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ cur->advance = FT_NEXT_USHORT( p );
+ cur->bearing = FT_NEXT_SHORT( p );
+ }
+ }
+
+ /* do we have an inconsistent number of metric values? */
+ {
+ TT_ShortMetrics* cur = *shorts;
+ TT_ShortMetrics* limit = cur +
+ FT_MIN( num_shorts, num_shorts_checked );
+
+
+ for ( ; cur < limit; cur++ )
+ *cur = FT_NEXT_SHORT( p );
+
+ /* We fill up the missing left side bearings with the */
+ /* last valid value. Since this will occur for buggy CJK */
+ /* fonts usually only, nothing serious will happen. */
+ if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
+ {
+ FT_Short val = (*shorts)[num_shorts_checked - 1];
+
+
+ limit = *shorts + num_shorts;
+ for ( ; cur < limit; cur++ )
+ *cur = val;
+ }
+ }
+
+ FT_FRAME_EXIT();
+
+ if ( vertical )
+ face->vertical.number_Of_VMetrics = (FT_UShort)num_longs;
+ else
+ face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs;
+
+ Fail:
+ return error;
+ }
+
+#endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_load_hhea */
+ /* */
+ /* <Description> */
+ /* Load the `hhea' or 'vhea' table into a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* vertical :: A boolean flag. If set, load `vhea'. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_hhea( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical )
+ {
+ FT_Error error;
+ TT_HoriHeader* header;
+
+ const FT_Frame_Field metrics_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_HoriHeader
+
+ FT_FRAME_START( 36 ),
+ FT_FRAME_ULONG ( Version ),
+ FT_FRAME_SHORT ( Ascender ),
+ FT_FRAME_SHORT ( Descender ),
+ FT_FRAME_SHORT ( Line_Gap ),
+ FT_FRAME_USHORT( advance_Width_Max ),
+ FT_FRAME_SHORT ( min_Left_Side_Bearing ),
+ FT_FRAME_SHORT ( min_Right_Side_Bearing ),
+ FT_FRAME_SHORT ( xMax_Extent ),
+ FT_FRAME_SHORT ( caret_Slope_Rise ),
+ FT_FRAME_SHORT ( caret_Slope_Run ),
+ FT_FRAME_SHORT ( caret_Offset ),
+ FT_FRAME_SHORT ( Reserved[0] ),
+ FT_FRAME_SHORT ( Reserved[1] ),
+ FT_FRAME_SHORT ( Reserved[2] ),
+ FT_FRAME_SHORT ( Reserved[3] ),
+ FT_FRAME_SHORT ( metric_Data_Format ),
+ FT_FRAME_USHORT( number_Of_HMetrics ),
+ FT_FRAME_END
+ };
+
+
+ if ( vertical )
+ {
+ void *v = &face->vertical;
+
+
+ error = face->goto_table( face, TTAG_vhea, stream, 0 );
+ if ( error )
+ goto Fail;
+
+ header = (TT_HoriHeader*)v;
+ }
+ else
+ {
+ error = face->goto_table( face, TTAG_hhea, stream, 0 );
+ if ( error )
+ goto Fail;
+
+ header = &face->horizontal;
+ }
+
+ if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
+ goto Fail;
+
+ FT_TRACE3(( "Ascender: %5d\n", header->Ascender ));
+ FT_TRACE3(( "Descender: %5d\n", header->Descender ));
+ FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics ));
+
+ header->long_metrics = NULL;
+ header->short_metrics = NULL;
+
+ Fail:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_face_get_metrics */
+ /* */
+ /* <Description> */
+ /* Returns the horizontal or vertical metrics in font units for a */
+ /* given glyph. The metrics are the left side bearing (resp. top */
+ /* side bearing) and advance width (resp. advance height). */
+ /* */
+ /* <Input> */
+ /* header :: A pointer to either the horizontal or vertical metrics */
+ /* structure. */
+ /* */
+ /* idx :: The glyph index. */
+ /* */
+ /* <Output> */
+ /* bearing :: The bearing, either left side or top side. */
+ /* */
+ /* advance :: The advance width resp. advance height. */
+ /* */
+#if !defined FT_CONFIG_OPTION_OLD_INTERNALS
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_get_metrics( TT_Face face,
+ FT_Bool vertical,
+ FT_UInt gindex,
+ FT_Short *abearing,
+ FT_UShort *aadvance )
+ {
+ FT_Error error;
+ FT_Stream stream = face->root.stream;
+ TT_HoriHeader* header;
+ FT_ULong table_pos, table_size, table_end;
+ FT_UShort k;
+
+
+ if ( vertical )
+ {
+ void* v = &face->vertical;
+
+
+ header = (TT_HoriHeader*)v;
+ table_pos = face->vert_metrics_offset;
+ table_size = face->vert_metrics_size;
+ }
+ else
+ {
+ header = &face->horizontal;
+ table_pos = face->horz_metrics_offset;
+ table_size = face->horz_metrics_size;
+ }
+
+ table_end = table_pos + table_size;
+
+ k = header->number_Of_HMetrics;
+
+ if ( k > 0 )
+ {
+ if ( gindex < (FT_UInt)k )
+ {
+ table_pos += 4 * gindex;
+ if ( table_pos + 4 > table_end )
+ goto NoData;
+
+ if ( FT_STREAM_SEEK( table_pos ) ||
+ FT_READ_USHORT( *aadvance ) ||
+ FT_READ_SHORT( *abearing ) )
+ goto NoData;
+ }
+ else
+ {
+ table_pos += 4 * ( k - 1 );
+ if ( table_pos + 4 > table_end )
+ goto NoData;
+
+ if ( FT_STREAM_SEEK( table_pos ) ||
+ FT_READ_USHORT( *aadvance ) )
+ goto NoData;
+
+ table_pos += 4 + 2 * ( gindex - k );
+ if ( table_pos + 2 > table_end )
+ *abearing = 0;
+ else
+ {
+ if ( !FT_STREAM_SEEK( table_pos ) )
+ (void)FT_READ_SHORT( *abearing );
+ }
+ }
+ }
+ else
+ {
+ NoData:
+ *abearing = 0;
+ *aadvance = 0;
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+#else /* OLD_INTERNALS */
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_get_metrics( TT_Face face,
+ FT_Bool vertical,
+ FT_UInt gindex,
+ FT_Short* abearing,
+ FT_UShort* aadvance )
+ {
+ void* v = &face->vertical;
+ void* h = &face->horizontal;
+ TT_HoriHeader* header = vertical ? (TT_HoriHeader*)v
+ : (TT_HoriHeader*)h;
+ TT_LongMetrics longs_m;
+ FT_UShort k = header->number_Of_HMetrics;
+
+
+ if ( k == 0 ||
+ !header->long_metrics ||
+ gindex >= (FT_UInt)face->max_profile.numGlyphs )
+ {
+ *abearing = *aadvance = 0;
+ return SFNT_Err_Ok;
+ }
+
+ if ( gindex < (FT_UInt)k )
+ {
+ longs_m = (TT_LongMetrics)header->long_metrics + gindex;
+ *abearing = longs_m->bearing;
+ *aadvance = longs_m->advance;
+ }
+ else
+ {
+ *abearing = ((TT_ShortMetrics*)header->short_metrics)[gindex - k];
+ *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+#endif /* !OPTIMIZE_MEMORY || OLD_INTERNALS */
+
+
+/* END */