📄 t1hinter.c
字号:
zone->min = std_min; zone->max = std_max; num_zones++; } else num_zones = n_zones; /* save total number of stem snaps now */ if (direction) hints->num_snap_heights = num_zones; else hints->num_snap_widths = num_zones; /* print the scaled stem snap values in tracing modes */#ifdef FT_DEBUG_LEVEL_TRACE FT_TRACE2(( "Set_Snap_Zones : second %s pass\n", direction ? "vertical" : "horizontal" )); FT_TRACE2(( "Scaled clipped stem snap zones :\n" )); FT_TRACE2(( " orus pix min max\n" )); FT_TRACE2(( "-----------------------------\n" )); zone = base_zone; for ( n = 0; n < num_zones; n++, zone++ ) FT_TRACE2(( " %3d %.2f %.2f %.2f\n", zone->orus, zone->pix/64.0, zone->min/64.0, zone->max/64.0 )); FT_TRACE2(( "\n" )); FT_TRACE2(( "Standard width = %d\n", standard_width ));#endif /* continue with vertical snap zone */ direction++; standard_width = priv->standard_height; n_zones = priv->num_snap_heights; base_zone = hints->snap_heights; orgs = priv->stem_snap_heights; scale = size->root.metrics.y_scale; } return T1_Err_Ok; } /************************************************************************ * * <Function> * T1_New_Size_Hinter * * <Description> * Allocates a new hinter structure for a given size object * * <Input> * size :: handle to target size object * * <Return> * Error code. 0 means success * ************************************************************************/ LOCAL_FUNC T1_Error T1_New_Size_Hinter( T1_Size size ) { FT_Memory memory = size->root.face->memory; return MEM_Alloc( size->hints, sizeof(*size->hints) ); }/************************************************************************ * * <Function> * T1_Done_Size_Hinter * * <Description> * Releases a given size object's hinter structure * * <Input> * size :: handle to target size object * ************************************************************************/ LOCAL_FUNC void T1_Done_Size_Hinter( T1_Size size ) { FT_Memory memory = size->root.face->memory; FREE( size->hints ); }/************************************************************************ * * <Function> * T1_Reset_Size_Hinter * * <Description> * Recomputes hinting information when a given size object has * changed its resolutions/char sizes/pixel sizes * * <Input> * size :: handle to size object * * <Return> * Error code. 0 means success * ************************************************************************/ LOCAL_FUNC T1_Error T1_Reset_Size_Hinter( T1_Size size ) { return t1_set_blue_zones(size) || t1_set_snap_zones(size); }/************************************************************************ * * <Function> * T1_New_Glyph_Hinter * * <Description> * Allocates a new hinter structure for a given glyph slot * * <Input> * glyph :: handle to target glyph slot * * <Return> * Error code. 0 means success * ************************************************************************/ LOCAL_FUNC T1_Error T1_New_Glyph_Hinter( T1_GlyphSlot glyph ) { FT_Memory memory = glyph->root.face->memory; return MEM_Alloc( glyph->hints, sizeof(*glyph->hints) ); }/************************************************************************ * * <Function> * T1_Done_Glyph_Hinter * * <Description> * Releases a given glyph slot's hinter structure * * <Input> * glyph :: handle to glyph slot * ************************************************************************/ LOCAL_FUNC void T1_Done_Glyph_Hinter( T1_GlyphSlot glyph ) { FT_Memory memory = glyph->root.face->memory; FREE( glyph->hints ); } /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /********** *********/ /********** *********/ /********** HINTED GLYPH LOADER *********/ /********** *********/ /********** The following code is in charge of the first *********/ /********** and second pass when loading a single outline *********/ /********** *********/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ static T1_Error t1_hinter_ignore( void ) { /* do nothing, used for "dotsection" which is unsupported for now */ return 0; } static T1_Error t1_hinter_stem( T1_Builder* builder, T1_Pos pos, T1_Int width, T1_Bool vertical ) { T1_Stem_Table* stem_table; T1_Stem_Hint* stems; T1_Stem_Hint* cur_stem; T1_Int min, max, n, num_stems; T1_Bool new_stem; T1_Glyph_Hints* hinter = builder->glyph->hints; /* select the appropriate stem array */ stem_table = vertical ? &hinter->vert_stems : &hinter->hori_stems; stems = stem_table->stems; num_stems = stem_table->num_stems; /* Compute minimum and maximum orus for the stem */ min = pos + ( vertical ? builder->left_bearing.x : builder->left_bearing.y ); if ( width >= 0 ) max = min + width; else { /* a negative width indicates a ghost stem */ if ( width == -21 ) min += width; max = min; } /* now scan the array. If we find a stem with the same borders */ /* simply activate it.. */ cur_stem = stems; new_stem = 1; for ( n = 0; n < num_stems; n++, cur_stem++ ) { if ( cur_stem->min_edge.orus == min && cur_stem->max_edge.orus == max ) { /* This stem is already in the table, simply activate it */ if ( (cur_stem->hint_flags & T1_HINT_FLAG_ACTIVE) == 0) { cur_stem->hint_flags |= T1_HINT_FLAG_ACTIVE; stem_table->num_active ++; } new_stem = 0; break; } } /* add a new stem to the array when necessary */ if (new_stem) { if (cur_stem >= stems + T1_HINTER_MAX_EDGES) { FT_ERROR(( "T1.Hinter : too many stems in glyph charstring\n" )); return T1_Err_Syntax_Error; } /* on the first pass, we record the stem, otherwise, this is */ /* a bug in the glyph loader !! */ if ( builder->pass == 0 ) { cur_stem->min_edge.orus = min; cur_stem->max_edge.orus = max; cur_stem->hint_flags = T1_HINT_FLAG_ACTIVE; stem_table->num_stems++; stem_table->num_active++; } else { FT_ERROR(( "T1.Hinter : fatal glyph loader bug - pass2-stem\n" )); return T1_Err_Syntax_Error; } } return T1_Err_Ok; } static T1_Error t1_hinter_stem3( T1_Builder* builder, T1_Pos pos0, T1_Int width0, T1_Pos pos1, T1_Int width1, T1_Pos pos2, T1_Int width2, T1_Bool vertical ) { /* For now, don't be elitist and simply call "stem" 3 times */ return t1_hinter_stem( builder, pos0, width0, vertical ) || t1_hinter_stem( builder, pos1, width1, vertical ) || t1_hinter_stem( builder, pos2, width2, vertical ); } static T1_Error t1_hinter_changehints( T1_Builder* builder ) { T1_Int dimension; T1_Stem_Table* stem_table; T1_Glyph_Hints* hinter = builder->glyph->hints; /* if we're in the second pass of glyph hinting, we must */ /* call the function T1_Hint_Points on the builder in order */ /* to force the fit the latest points to the pixel grid */ if ( builder->pass == 1 ) T1_Hint_Points( builder ); /* Simply de-activate all hints in all arrays */ stem_table = &hinter->hori_stems; for ( dimension = 2; dimension > 0; dimension-- ) { T1_Stem_Hint* cur = stem_table->stems; T1_Stem_Hint* limit = cur + stem_table->num_stems; for ( ; cur < limit; cur++ ) cur->hint_flags &= ~T1_HINT_FLAG_ACTIVE; stem_table->num_active = 0; stem_table = &hinter->vert_stems; } return T1_Err_Ok; } LOCAL_FUNC const T1_Hinter_Funcs t1_hinter_funcs = { (T1_Hinter_ChangeHints) t1_hinter_changehints, (T1_Hinter_DotSection) t1_hinter_ignore, (T1_Hinter_Stem) t1_hinter_stem, (T1_Hinter_Stem3) t1_hinter_stem3 }; /**********************************************************************/ /**********************************************************************/ /**********************************************************************/ /********** *********/ /********** *********/ /********** STEM HINTS MANAGEMENT *********/ /********** *********/ /********** The following code is in charge of computing *********/ /********** the placement of each scaled stem hint.. *********/ /********** *********/ /**********************************************************************/ /**********************************************************************/ /**********************************************************************//************************************************************************ * * <Function> * t1_sort_hints * * <Description> * Sort the list of active stems in increasing order, through * the "sort" indexing table * * <Input> * table :: a stem hints table * ************************************************************************/ static void t1_sort_hints( T1_Stem_Table* table ) { T1_Int num_stems = table->num_stems; T1_Int num_active = 0; T1_Int* sort = table->sort; T1_Stem_Hint* stems = table->stems; T1_Int n; /* record active stems in sort table */ for ( n = 0; n < num_stems; n++ ) { if ( stems[n].hint_flags & T1_HINT_FLAG_ACTIVE ) sort[num_active++] = n; } /* now sort the indices. There are usually very few stems, */ /* and they are pre-sorted in 90% cases, so we choose a */ /* simple bubble sort (quicksort would be slower).. */ for ( n = 1; n < num_active; n++ ) { T1_Int p = n-1; T1_Stem_Hint* cur = stems + sort[n]; do { T1_Int swap; T1_Stem_Hint* prev = stems + sort[p]; /* note that by definition, the active stems cannot overlap */ /* so we simply compare their "min" to sort them.. */ /* (we could compare their max, this wouldn't change anything) */ if ( prev->min_edge.orus <= cur->min_edge.orus ) break; /* swap elements */ swap = sort[ p ]; sort[ p ] = sort[p+1]; sort[p+1] = swap; p--; } while ( p >= 0 ); } table->num_active = num_active; }/************************************************************************ * * <Function> * t1_hint_horizontal_stems * * <Description> * Compute the location of each scaled horizontal stem hint. * This takes care of the blue zones and the horizontal stem * snap table * * <Input> * table :: the horizontal stem hints table * hints :: the current size's hint structure * blueShift :: the value of the /BlueShift as taken from the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -