📄 ahglyph.c
字号:
} } /* compute directions of in & out vectors */ { for ( point = points; point < point_limit; point++ ) { AH_Point* prev; AH_Point* next; FT_Vector vec; prev = point->prev; vec.x = point->fx - prev->fx; vec.y = point->fy - prev->fy; point->in_dir = ah_compute_direction( vec.x, vec.y );#ifndef AH_OPTION_NO_WEAK_INTERPOLATION point->in_angle = ah_angle( &vec );#endif next = point->next; vec.x = next->fx - point->fx; vec.y = next->fy - point->fy; point->out_dir = ah_compute_direction( vec.x, vec.y );#ifndef AH_OPTION_NO_WEAK_INTERPOLATION point->out_angle = ah_angle( &vec ); { AH_Angle delta = point->in_angle - point->out_angle; if ( delta < 0 ) delta = -delta; if ( delta < 2 ) point->flags |= ah_flah_weak_interpolation; }#if 0 if ( point->flags & ( ah_flah_conic | ah_flah_cubic ) ) point->flags |= ah_flah_weak_interpolation;#endif#endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */#ifdef AH_OPTION_NO_STRONG_INTERPOLATION point->flags |= ah_flah_weak_interpolation;#endif } } } Exit: return error; } FT_LOCAL_DEF void ah_setup_uv( AH_Outline* outline, AH_UV source ) { AH_Point* point = outline->points; AH_Point* point_limit = point + outline->num_points; for ( ; point < point_limit; point++ ) { FT_Pos u, v; switch ( source ) { case ah_uv_fxy: u = point->fx; v = point->fy; break; case ah_uv_fyx: u = point->fy; v = point->fx; break; case ah_uv_oxy: u = point->ox; v = point->oy; break; case ah_uv_oyx: u = point->oy; v = point->ox; break; case ah_uv_yx: u = point->y; v = point->x; break; case ah_uv_ox: u = point->x; v = point->ox; break; case ah_uv_oy: u = point->y; v = point->oy; break; default: u = point->x; v = point->y; break; } point->u = u; point->v = v; } } FT_LOCAL_DEF void ah_outline_compute_segments( AH_Outline* outline ) { int dimension; AH_Segment* segments; FT_Int* p_num_segments; AH_Direction segment_dir; AH_Direction major_dir; segments = outline->horz_segments; p_num_segments = &outline->num_hsegments; major_dir = ah_dir_right; /* This value must be positive! */ segment_dir = major_dir; /* set up (u,v) in each point */ ah_setup_uv( outline, ah_uv_fyx ); for ( dimension = 1; dimension >= 0; dimension-- ) { AH_Point** contour = outline->contours; AH_Point** contour_limit = contour + outline->num_contours; AH_Segment* segment = segments; FT_Int num_segments = 0;#ifdef AH_HINT_METRICS AH_Point* min_point = 0; AH_Point* max_point = 0; FT_Pos min_coord = 32000; FT_Pos max_coord = -32000;#endif /* do each contour separately */ for ( ; contour < contour_limit; contour++ ) { AH_Point* point = contour[0]; AH_Point* last = point->prev; int on_edge = 0; FT_Pos min_pos = +32000; /* minimum segment pos != min_coord */ FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */ FT_Bool passed;#ifdef AH_HINT_METRICS if ( point->u < min_coord ) { min_coord = point->u; min_point = point; } if ( point->u > max_coord ) { max_coord = point->u; max_point = point; }#endif if ( point == last ) /* skip singletons -- just in case? */ continue; if ( ABS( last->out_dir ) == major_dir && ABS( point->out_dir ) == major_dir ) { /* we are already on an edge, try to locate its start */ last = point; for (;;) { point = point->prev; if ( ABS( point->out_dir ) != major_dir ) { point = point->next; break; } if ( point == last ) break; } } last = point; passed = 0; for (;;) { FT_Pos u, v; if ( on_edge ) { u = point->u; if ( u < min_pos ) min_pos = u; if ( u > max_pos ) max_pos = u; if ( point->out_dir != segment_dir || point == last ) { /* we are just leaving an edge; record a new segment! */ segment->last = point; segment->pos = ( min_pos + max_pos ) >> 1; /* a segment is round if either its first or last point */ /* is a control point */ if ( ( segment->first->flags | point->flags ) & ah_flah_control ) segment->flags |= ah_edge_round; /* compute segment size */ min_pos = max_pos = point->v; v = segment->first->v; if ( v < min_pos ) min_pos = v; if ( v > max_pos ) max_pos = v; segment->min_coord = min_pos; segment->max_coord = max_pos; on_edge = 0; num_segments++; segment++; /* fallthrough */ } } /* now exit if we are at the start/end point */ if ( point == last ) { if ( passed ) break; passed = 1; } if ( !on_edge && ABS( point->out_dir ) == major_dir ) { /* this is the start of a new segment! */ segment_dir = point->out_dir; /* clear all segment fields */ memset( segment, 0, sizeof ( *segment ) ); segment->dir = segment_dir; segment->flags = ah_edge_normal; min_pos = max_pos = point->u; segment->first = point; segment->last = point; segment->contour = contour; on_edge = 1;#ifdef AH_HINT_METRICS if ( point == max_point ) max_point = 0; if ( point == min_point ) min_point = 0;#endif } point = point->next; } } /* contours */#ifdef AH_HINT_METRICS /* we need to ensure that there are edges on the left-most and */ /* right-most points of the glyph in order to hint the metrics; */ /* we do this by inserting fake segments when needed */ if ( dimension == 0 ) { AH_Point* point = outline->points; AH_Point* point_limit = point + outline->num_points; FT_Pos min_pos = 32000; FT_Pos max_pos = -32000; min_point = 0; max_point = 0; /* compute minimum and maximum points */ for ( ; point < point_limit; point++ ) { FT_Pos x = point->fx; if ( x < min_pos ) { min_pos = x; min_point = point; } if ( x > max_pos ) { max_pos = x; max_point = point; } } /* insert minimum segment */ if ( min_point ) { /* clear all segment fields */ memset( segment, 0, sizeof ( *segment ) ); segment->dir = segment_dir; segment->flags = ah_edge_normal; segment->first = min_point; segment->last = min_point; segment->pos = min_pos; num_segments++; segment++; } /* insert maximum segment */ if ( max_point ) { /* clear all segment fields */ memset( segment, 0, sizeof ( *segment ) ); segment->dir = segment_dir; segment->flags = ah_edge_normal; segment->first = max_point; segment->last = max_point; segment->pos = max_pos; num_segments++; segment++; } }#endif /* AH_HINT_METRICS */ *p_num_segments = num_segments; segments = outline->vert_segments; major_dir = ah_dir_up; p_num_segments = &outline->num_vsegments; ah_setup_uv( outline, ah_uv_fxy ); } } FT_LOCAL_DEF void ah_outline_link_segments( AH_Outline* outline ) { AH_Segment* segments; AH_Segment* segment_limit; int dimension; ah_setup_uv( outline, ah_uv_fyx ); segments = outline->horz_segments; segment_limit = segments + outline->num_hsegments; for ( dimension = 1; dimension >= 0; dimension-- ) { AH_Segment* seg1; AH_Segment* seg2; /* now compare each segment to the others */ for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { FT_Pos best_score = 32000; AH_Segment* best_segment = 0; /* the fake segments are introduced to hint the metrics -- */ /* we must never link them to anything */ if ( seg1->first == seg1->last ) continue; for ( seg2 = segments; seg2 < segment_limit; seg2++ ) if ( seg1 != seg2 && seg1->dir + seg2->dir == 0 ) { FT_Pos pos1 = seg1->pos; FT_Pos pos2 = seg2->pos; FT_Bool is_dir; FT_Bool is_pos; /* check that the segments are correctly oriented and */ /* positioned to form a black distance */ is_dir = ( seg1->dir == outline->horz_major_dir || seg1->dir == outline->vert_major_dir ); is_pos = pos1 > pos2; if ( pos1 == pos2 || !(is_dir ^ is_pos) ) continue; /* Check the two segments. We now have a better algorithm */ /* that doesn't rely on the segment points themselves but */ /* on their relative position. This gets rids of many */ /* unpleasant artefacts and incorrect stem/serifs */ /* computations. */ /* first of all, compute the size of the `common' height */ { FT_Pos min = seg1->min_coord; FT_Pos max = seg1->max_coord; FT_Pos len, score; FT_Pos size1, size2; size1 = max - min; size2 = seg2->max_coord - seg2->min_coord; if ( min < seg2->min_coord ) min = seg2->min_coord; if ( max < seg2->max_coord ) max = seg2->max_coord; len = max - min; score = seg2->pos - seg1->pos; if ( score < 0 ) score = -score; /* before comparing the scores, take care that the segments */ /* are really facing each other (often not for italics..) */ if ( 4 * len >= size1 && 4 * len >= size2 ) if ( score < best_score ) { best_score = score; best_segment = seg2; } } } if ( best_segment ) { seg1->link = best_segment; seg1->score = best_score; best_segment->num_linked++; } } /* edges 1 */ /* now, compute the `serif' segments */ for ( seg1 = segments; seg1 < segment_limit; seg1++ ) { seg2 = seg1->link; if ( seg2 && seg2->link != seg1 ) { seg1->link = 0; seg1->serif = seg2->link; } } ah_setup_uv( outline, ah_uv_fxy ); segments = outline->vert_segments; segment_limit = segments + outline->num_vsegments; } }#ifdef AH_DEBUG_GLYPH /* A function used to dump the array of linked segments */ void ah_dump_segments( AH_Outline* outline ) { AH_Segment* segments; AH_Segment* segment_limit; AH_Point* points; FT_Int dimension;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -