static void af_warper_compute_line_best( AF_Warper warper, FT_Fixed scale, FT_Pos delta, FT_Pos xx1, FT_Pos xx2, AF_WarpScore base_distort, AF_Segment segments, FT_UInt num_segments ) { FT_Int idx_min, idx_max, idx0; FT_UInt nn; AF_WarpScore scores[64]; for ( nn = 0; nn < 64; nn++ ) scores[nn] = 0; idx0 = xx1 - warper->t1; /* compute minimum and maximum indices */ { FT_Pos xx1min = warper->x1min; FT_Pos xx1max = warper->x1max; FT_Pos w = xx2 - xx1; if ( xx1min + w < warper->x2min ) xx1min = warper->x2min - ( xx2 - xx1 ); xx1max = warper->x1max; if ( xx1max + w > warper->x2max ) xx1max = warper->x2max - ( xx2 - xx1 ); idx_min = xx1min - warper->t1; idx_max = xx1max - warper->t1; if ( idx_min > idx_max ) { AF_LOG(( "invalid indices:\n" " min=%d max=%d, xx1=%ld xx2=%ld,\n" " x1min=%ld x1max=%ld, x2min=%ld x2max=%ld\n", idx_min, idx_max, xx1, xx2, warper->x1min, warper->x1max, warper->x2min, warper->x2max )); return; } } for ( nn = 0; nn < num_segments; nn++ ) { FT_Pos len = segments[nn].max_coord - segments[nn].min_coord; FT_Pos y0 = FT_MulFix( segments[nn].pos, scale ) + delta; FT_Pos y = y0 + ( idx_min - idx0 ); FT_Int idx; for ( idx = idx_min; idx <= idx_max; idx++, y++ ) scores[idx] += af_warper_weights[y & 63] * len; } /* find best score */ { FT_Int idx; for ( idx = idx_min; idx <= idx_max; idx++ ) { AF_WarpScore score = scores[idx]; AF_WarpScore distort = base_distort + ( idx - idx0 ); if ( score > warper->best_score || ( score == warper->best_score && distort < warper->best_distort ) ) { warper->best_score = score; warper->best_distort = distort; warper->best_scale = scale; warper->best_delta = delta + ( idx - idx0 ); } } } }
static void af_latin_metrics_init_blues( AF_LatinMetrics metrics, FT_Face face ) { FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS]; FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS]; FT_Int num_flats; FT_Int num_rounds; FT_Int bb; AF_LatinBlue blue; FT_Error error; AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT]; FT_GlyphSlot glyph = face->glyph; /* we compute the blues simply by loading each character from the */ /* 'af_latin_blue_chars[blues]' string, then compute its top-most or */ /* bottom-most points (depending on `AF_IS_TOP_BLUE') */ AF_LOG(( "blue zones computation\n" )); AF_LOG(( "------------------------------------------------\n" )); for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ ) { const char* p = af_latin_blue_chars[bb]; const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS; FT_Pos* blue_ref; FT_Pos* blue_shoot; AF_LOG(( "blue %3d: ", bb )); num_flats = 0; num_rounds = 0; for ( ; p < limit && *p; p++ ) { FT_UInt glyph_index; FT_Int best_point, best_y, best_first, best_last; FT_Vector* points; FT_Bool round = 0; AF_LOG(( "'%c'", *p )); /* load the character in the face -- skip unknown or empty ones */ glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p ); if ( glyph_index == 0 ) continue; error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); if ( error || glyph->outline.n_points <= 0 ) continue; /* now compute min or max point indices and coordinates */ points = glyph->outline.points; best_point = -1; best_y = 0; /* make compiler happy */ best_first = 0; /* ditto */ best_last = 0; /* ditto */ { FT_Int nn; FT_Int first = 0; FT_Int last = -1; for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ ) { FT_Int old_best_point = best_point; FT_Int pp; last = glyph->outline.contours[nn]; /* Avoid single-point contours since they are never rasterized. */ /* In some fonts, they correspond to mark attachment points */ /* which are way outside of the glyph's real outline. */ if ( last <= first ) continue; if ( AF_LATIN_IS_TOP_BLUE( bb ) ) { for ( pp = first; pp <= last; pp++ ) if ( best_point < 0 || points[pp].y > best_y ) { best_point = pp; best_y = points[pp].y; } } else { for ( pp = first; pp <= last; pp++ ) if ( best_point < 0 || points[pp].y < best_y ) { best_point = pp; best_y = points[pp].y; } } if ( best_point != old_best_point ) { best_first = first; best_last = last; } } AF_LOG(( "%5d", best_y )); } /* now check whether the point belongs to a straight or round */ /* segment; we first need to find in which contour the extremum */ /* lies, then inspect its previous and next points */ if ( best_point >= 0 ) { FT_Int prev, next; FT_Pos dist; /* now look for the previous and next points that are not on the */ /* same Y coordinate. Threshold the `closeness'... */ prev = best_point; next = prev; do { if ( prev > best_first ) prev--; else prev = best_last; dist = points[prev].y - best_y; if ( dist < -5 || dist > 5 ) break; } while ( prev != best_point ); do { if ( next < best_last ) next++; else next = best_first; dist = points[next].y - best_y; if ( dist < -5 || dist > 5 ) break; } while ( next != best_point ); /* now, set the `round' flag depending on the segment's kind */ round = FT_BOOL( FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON || FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON ); AF_LOG(( "%c ", round ? 'r' : 'f' )); } if ( round ) rounds[num_rounds++] = best_y; else flats[num_flats++] = best_y; } AF_LOG(( "\n" )); if ( num_flats == 0 && num_rounds == 0 ) { /* * we couldn't find a single glyph to compute this blue zone, * we will simply ignore it then */ AF_LOG(( "empty!\n" )); continue; } /* we have computed the contents of the `rounds' and `flats' tables, */ /* now determine the reference and overshoot position of the blue -- */ /* we simply take the median value after a simple sort */ af_sort_pos( num_rounds, rounds ); af_sort_pos( num_flats, flats ); blue = & axis->blues[axis->blue_count]; blue_ref = & blue->ref.org; blue_shoot = & blue->shoot.org; axis->blue_count++; if ( num_flats == 0 ) { *blue_ref = *blue_shoot = rounds[num_rounds / 2]; } else if ( num_rounds == 0 ) { *blue_ref = *blue_shoot = flats[num_flats / 2]; } else { *blue_ref = flats[num_flats / 2]; *blue_shoot = rounds[num_rounds / 2]; } /* there are sometimes problems: if the overshoot position of top */ /* zones is under its reference position, or the opposite for bottom */ /* zones. We must thus check everything there and correct the errors */ if ( *blue_shoot != *blue_ref ) { FT_Pos ref = *blue_ref; FT_Pos shoot = *blue_shoot; FT_Bool over_ref = FT_BOOL( shoot > ref ); if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref ) *blue_shoot = *blue_ref = ( shoot + ref ) / 2; } blue->flags = 0; if ( AF_LATIN_IS_TOP_BLUE( bb ) ) blue->flags |= AF_LATIN_BLUE_TOP; /* * The following flags is used later to adjust the y and x scales * in order to optimize the pixel grid alignment of the top of small * letters. */ if ( bb == AF_LATIN_BLUE_SMALL_TOP ) blue->flags |= AF_LATIN_BLUE_ADJUSTMENT; AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot )); } return; }