📄 ahhint.c
字号:
*ahinter = hinter; Exit: if ( error ) ah_hinter_done( hinter ); return error; } /* create a face's autohint globals */ FT_LOCAL_DEF FT_Error ah_hinter_new_face_globals( AH_Hinter* hinter, FT_Face face, AH_Globals* globals ) { FT_Error error; FT_Memory memory = hinter->memory; AH_Face_Globals* face_globals; if ( ALLOC( face_globals, sizeof ( *face_globals ) ) ) goto Exit; hinter->face = face; hinter->globals = face_globals; if ( globals ) face_globals->design = *globals; else ah_hinter_compute_globals( hinter ); face->autohint.data = face_globals; face->autohint.finalizer = (FT_Generic_Finalizer) ah_hinter_done_face_globals; face_globals->face = face; Exit: return error; } /* discard a face's autohint globals */ FT_LOCAL_DEF void ah_hinter_done_face_globals( AH_Face_Globals* globals ) { FT_Face face = globals->face; FT_Memory memory = face->memory; FREE( globals ); } static FT_Error ah_hinter_load( AH_Hinter* hinter, FT_UInt glyph_index, FT_UInt load_flags, FT_UInt depth ) { FT_Face face = hinter->face; FT_GlyphSlot slot = face->glyph; FT_Fixed x_scale = face->size->metrics.x_scale; FT_Fixed y_scale = face->size->metrics.y_scale; FT_Glyph_Metrics metrics; /* temporary metrics */ FT_Error error; AH_Outline* outline = hinter->glyph; AH_Loader* gloader = hinter->loader; FT_Bool no_horz_hints = ( load_flags & AH_HINT_NO_HORZ_EDGES ) != 0; FT_Bool no_vert_hints = ( load_flags & AH_HINT_NO_VERT_EDGES ) != 0; /* load the glyph */ error = FT_Load_Glyph( face, glyph_index, load_flags ); if ( error ) goto Exit; /* save current glyph metrics */ metrics = slot->metrics; /* set linear horizontal metrics */ slot->linearHoriAdvance = slot->metrics.horiAdvance; slot->linearVertAdvance = slot->metrics.vertAdvance; switch ( slot->format ) { case ft_glyph_format_outline: /* translate glyph outline if we need to */ if ( hinter->transformed ) { FT_UInt n = slot->outline.n_points; FT_Vector* point = slot->outline.points; for ( ; n > 0; point++, n-- ) { point->x += hinter->trans_delta.x; point->y += hinter->trans_delta.y; } } /* copy the outline points in the loader's current */ /* extra points, which is used to keep original glyph coordinates */ error = ah_loader_check_points( gloader, slot->outline.n_points + 2, slot->outline.n_contours ); if ( error ) goto Exit; MEM_Copy( gloader->current.extra_points, slot->outline.points, slot->outline.n_points * sizeof ( FT_Vector ) ); MEM_Copy( gloader->current.outline.contours, slot->outline.contours, slot->outline.n_contours * sizeof ( short ) ); MEM_Copy( gloader->current.outline.tags, slot->outline.tags, slot->outline.n_points * sizeof ( char ) ); gloader->current.outline.n_points = slot->outline.n_points; gloader->current.outline.n_contours = slot->outline.n_contours; /* compute original phantom points */ hinter->pp1.x = 0; hinter->pp1.y = 0; hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale ); hinter->pp2.y = 0; /* be sure to check for spacing glyphs */ if ( slot->outline.n_points == 0 ) goto Hint_Metrics; /* now, load the slot image into the auto-outline, and run the */ /* automatic hinting process */ error = ah_outline_load( outline, face ); /* XXX: change to slot */ if ( error ) goto Exit; /* perform feature detection */ ah_outline_detect_features( outline ); if ( !no_horz_hints ) { ah_outline_compute_blue_edges( outline, hinter->globals ); ah_outline_scale_blue_edges( outline, hinter->globals ); } /* perform alignment control */ ah_hinter_hint_edges( hinter, no_horz_hints, no_vert_hints ); ah_hinter_align( hinter ); /* now save the current outline into the loader's current table */ ah_outline_save( outline, gloader ); /* we now need to hint the metrics according to the change in */ /* width/positioning that occured during the hinting process */ { FT_Pos old_width, new_width; FT_Pos old_advance, new_advance; FT_Pos old_lsb, new_lsb; AH_Edge* edge1 = outline->vert_edges; /* leftmost edge */ AH_Edge* edge2 = edge1 + outline->num_vedges - 1; /* rightmost edge */ old_width = edge2->opos - edge1->opos; new_width = edge2->pos - edge1->pos; old_advance = hinter->pp2.x; old_lsb = edge1->opos; new_lsb = edge1->pos; new_advance = old_advance + ( new_width + new_lsb - old_width - old_lsb ); hinter->pp1.x = ( ( new_lsb - old_lsb ) + 32 ) & -64; hinter->pp2.x = ( ( edge2->pos + ( old_advance - edge2->opos ) ) + 32 ) & -64; } /* good, we simply add the glyph to our loader's base */ ah_loader_add( gloader ); break; case ft_glyph_format_composite: { FT_UInt nn, num_subglyphs = slot->num_subglyphs; FT_UInt num_base_subgs, start_point, start_contour; FT_SubGlyph* subglyph; start_point = gloader->base.outline.n_points; start_contour = gloader->base.outline.n_contours; /* first of all, copy the subglyph descriptors in the glyph loader */ error = ah_loader_check_subglyphs( gloader, num_subglyphs ); if ( error ) goto Exit; MEM_Copy( gloader->current.subglyphs, slot->subglyphs, num_subglyphs * sizeof ( FT_SubGlyph ) ); gloader->current.num_subglyphs = num_subglyphs; num_base_subgs = gloader->base.num_subglyphs; /* now, read each subglyph independently */ for ( nn = 0; nn < num_subglyphs; nn++ ) { FT_Vector pp1, pp2; FT_Pos x, y; FT_UInt num_points, num_new_points, num_base_points; /* gloader.current.subglyphs can change during glyph loading due */ /* to re-allocation -- we must recompute the current subglyph on */ /* each iteration */ subglyph = gloader->base.subglyphs + num_base_subgs + nn; pp1 = hinter->pp1; pp2 = hinter->pp2; num_base_points = gloader->base.outline.n_points; error = ah_hinter_load( hinter, subglyph->index, load_flags, depth + 1 ); if ( error ) goto Exit; /* recompute subglyph pointer */ subglyph = gloader->base.subglyphs + num_base_subgs + nn; if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS ) { pp1 = hinter->pp1; pp2 = hinter->pp2; } else { hinter->pp1 = pp1; hinter->pp2 = pp2; } num_points = gloader->base.outline.n_points; num_new_points = num_points - num_base_points; /* now perform the transform required for this subglyph */ if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE | FT_SUBGLYPH_FLAG_XY_SCALE | FT_SUBGLYPH_FLAG_2X2 ) ) { FT_Vector* cur = gloader->base.outline.points + num_base_points; FT_Vector* org = gloader->base.extra_points + num_base_points; FT_Vector* limit = cur + num_new_points; for ( ; cur < limit; cur++, org++ ) { FT_Vector_Transform( cur, &subglyph->transform ); FT_Vector_Transform( org, &subglyph->transform ); } } /* apply offset */ if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) ) { FT_Int k = subglyph->arg1; FT_UInt l = subglyph->arg2; FT_Vector* p1; FT_Vector* p2; if ( start_point + k >= num_base_points || l >= (FT_UInt)num_new_points ) { error = FT_Err_Invalid_Composite; goto Exit; } l += num_base_points; /* for now, only use the current point coordinates */ /* we may consider another approach in the near future */ p1 = gloader->base.outline.points + start_point + k; p2 = gloader->base.outline.points + start_point + l; x = p1->x - p2->x; y = p1->y - p2->y; } else { x = FT_MulFix( subglyph->arg1, x_scale ); y = FT_MulFix( subglyph->arg2, y_scale ); x = ( x + 32 ) & -64; y = ( y + 32 ) & -64; } { FT_Outline dummy = gloader->base.outline; dummy.points += num_base_points; dummy.n_points = num_new_points; FT_Outline_Translate( &dummy, x, y ); } } } break; default: /* we don't support other formats (yet?) */ error = FT_Err_Unimplemented_Feature; } Hint_Metrics: if ( depth == 0 ) { FT_BBox bbox; /* transform the hinted outline if needed */ if ( hinter->transformed ) FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix ); /* we must translate our final outline by -pp1.x, and compute */ /* the new metrics */ if ( hinter->pp1.x ) FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 ); FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); bbox.xMin &= -64; bbox.yMin &= -64; bbox.xMax = ( bbox.xMax + 63 ) & -64; bbox.yMax = ( bbox.yMax + 63 ) & -64; slot->metrics.width = bbox.xMax - bbox.xMin; slot->metrics.height = bbox.yMax - bbox.yMin; slot->metrics.horiBearingX = bbox.xMin; slot->metrics.horiBearingY = bbox.yMax; slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x; /* XXX: TO DO - slot->linearHoriAdvance */ /* now copy outline into glyph slot */ ah_loader_rewind( slot->internal->loader ); error = ah_loader_copy_points( slot->internal->loader, gloader ); if ( error ) goto Exit; slot->outline = slot->internal->loader->base.outline; slot->format = ft_glyph_format_outline; } Exit: return error; } /* load and hint a given glyph */ FT_LOCAL_DEF FT_Error ah_hinter_load_glyph( AH_Hinter* hinter, FT_GlyphSlot slot, FT_Size size, FT_UInt glyph_index, FT_Int load_flags ) { FT_Face face = slot->face; FT_Error error; FT_Fixed x_scale = size->metrics.x_scale; FT_Fixed y_scale = size->metrics.y_scale; AH_Face_Globals* face_globals = FACE_GLOBALS( face ); /* first of all, we need to check that we're using the correct face and */ /* global hints to load the glyph */ if ( hinter->face != face || hinter->globals != face_globals ) { hinter->face = face; if ( !face_globals ) { error = ah_hinter_new_face_globals( hinter, face, 0 ); if ( error ) goto Exit; } hinter->globals = FACE_GLOBALS( face ); face_globals = FACE_GLOBALS( face ); } /* now, we must check the current character pixel size to see if we */ /* need to rescale the global metrics */ if ( face_globals->x_scale != x_scale || face_globals->y_scale != y_scale ) ah_hinter_scale_globals( hinter, x_scale, y_scale ); load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE; ah_loader_rewind( hinter->loader ); { FT_Slot_Internal internal = slot->internal; hinter->transformed = internal->glyph_transformed; if ( hinter->transformed ) { FT_Matrix imatrix; imatrix = internal->glyph_matrix; hinter->trans_delta = internal->glyph_delta; hinter->trans_matrix = imatrix; FT_Matrix_Invert( &imatrix ); FT_Vector_Transform( &hinter->trans_delta, &imatrix ); } } error = ah_hinter_load( hinter, glyph_index, load_flags, 0 ); Exit: return error; } /* retrieve a face's autohint globals for client applications */ FT_LOCAL_DEF void ah_hinter_get_global_hints( AH_Hinter* hinter, FT_Face face, void** global_hints, long* global_len ) { AH_Globals* globals = 0; FT_Memory memory = hinter->memory; FT_Error error; /* allocate new master globals */ if ( ALLOC( globals, sizeof ( *globals ) ) ) goto Fail; /* compute face globals if needed */ if ( !FACE_GLOBALS( face ) ) { error = ah_hinter_new_face_globals( hinter, face, 0 ); if ( error ) goto Fail; } *globals = FACE_GLOBALS( face )->design; *global_hints = globals; *global_len = sizeof( *globals ); return; Fail: FREE( globals ); *global_hints = 0; *global_len = 0; } FT_LOCAL_DEF void ah_hinter_done_global_hints( AH_Hinter* hinter, void* global_hints ) { FT_Memory memory = hinter->memory; FREE( global_hints ); }/* END */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -