... |
... |
@@ -2748,6 +2748,170 @@ |
2748
|
2748
|
#undef FT_COMPONENT
|
2749
|
2749
|
#define FT_COMPONENT afadjust
|
2750
|
2750
|
|
|
2751
|
+static void
|
|
2752
|
+af_move_contour_vertically( AF_Point contour,
|
|
2753
|
+ FT_Int movement )
|
|
2754
|
+{
|
|
2755
|
+ AF_Point point = contour;
|
|
2756
|
+ AF_Point first_point = point;
|
|
2757
|
+ if ( point != NULL )
|
|
2758
|
+ {
|
|
2759
|
+ do
|
|
2760
|
+ {
|
|
2761
|
+ point->y += movement;
|
|
2762
|
+ point = point->next;
|
|
2763
|
+ } while ( point != first_point );
|
|
2764
|
+ }
|
|
2765
|
+}
|
|
2766
|
+
|
|
2767
|
+static FT_Int
|
|
2768
|
+af_find_highest_contour( AF_GlyphHints hints ) {
|
|
2769
|
+ FT_Int highest_contour = -1;
|
|
2770
|
+ FT_Pos highest_min_y = 0;
|
|
2771
|
+ FT_Pos current_min_y = 0;
|
|
2772
|
+
|
|
2773
|
+ for ( FT_Int contour = 0; contour < hints->num_contours; contour++ )
|
|
2774
|
+ {
|
|
2775
|
+ AF_Point point = hints->contours[contour];
|
|
2776
|
+ AF_Point first_point = point;
|
|
2777
|
+ if ( point == NULL )
|
|
2778
|
+ {
|
|
2779
|
+ continue;
|
|
2780
|
+ }
|
|
2781
|
+ current_min_y = point->y;
|
|
2782
|
+
|
|
2783
|
+ do
|
|
2784
|
+ {
|
|
2785
|
+ if ( point->y < current_min_y )
|
|
2786
|
+ {
|
|
2787
|
+ current_min_y = point->y;
|
|
2788
|
+ }
|
|
2789
|
+ point = point->next;
|
|
2790
|
+ } while ( point != first_point );
|
|
2791
|
+
|
|
2792
|
+ if ( highest_contour == -1 || current_min_y > highest_min_y )
|
|
2793
|
+ {
|
|
2794
|
+ highest_min_y = current_min_y;
|
|
2795
|
+ highest_contour = contour;
|
|
2796
|
+ }
|
|
2797
|
+ }
|
|
2798
|
+
|
|
2799
|
+ return highest_contour;
|
|
2800
|
+}
|
|
2801
|
+
|
|
2802
|
+void
|
|
2803
|
+af_latin_stretch_tildes( AF_GlyphHints hints,
|
|
2804
|
+ FT_Int glyph_index,
|
|
2805
|
+ AF_ReverseCharacterMap reverse_charmap ) {
|
|
2806
|
+ if ( af_lookup_tilde_correction_type( reverse_charmap, glyph_index ) ) {
|
|
2807
|
+ FT_Int highest_contour = af_find_highest_contour( hints );
|
|
2808
|
+ AF_Point p = hints->contours[highest_contour];
|
|
2809
|
+ AF_Point first_point = p;
|
|
2810
|
+
|
|
2811
|
+ FT_Pos min_y, max_y;
|
|
2812
|
+ min_y = max_y = p->y;
|
|
2813
|
+
|
|
2814
|
+ FT_Short min_fy, max_fy;
|
|
2815
|
+ min_fy = max_fy = p->fy;
|
|
2816
|
+
|
|
2817
|
+ do {
|
|
2818
|
+ p = p->next;
|
|
2819
|
+ if ( p->y < min_y ) {
|
|
2820
|
+ min_y = p->y;
|
|
2821
|
+ }
|
|
2822
|
+ if ( p->y > max_y ) {
|
|
2823
|
+ max_y = p->y;
|
|
2824
|
+ }
|
|
2825
|
+
|
|
2826
|
+ if ( p->fy < min_fy ) {
|
|
2827
|
+ min_fy = p->fy;
|
|
2828
|
+ }
|
|
2829
|
+
|
|
2830
|
+ if ( p->fy > max_fy ) {
|
|
2831
|
+ max_fy = p->fy;
|
|
2832
|
+ }
|
|
2833
|
+
|
|
2834
|
+ } while ( p != first_point );
|
|
2835
|
+
|
|
2836
|
+ FT_Pos min_measurement = 32000;
|
|
2837
|
+ FT_UInt measurements_taken = 0;
|
|
2838
|
+
|
|
2839
|
+ do {
|
|
2840
|
+ p = p->next;
|
|
2841
|
+ if ( !(p->flags & AF_FLAG_CONTROL)
|
|
2842
|
+ && p->prev->y == p->y && p->next->y == p->y
|
|
2843
|
+ && p->y != min_y && p->y != max_y
|
|
2844
|
+ && p->prev->flags & AF_FLAG_CONTROL
|
|
2845
|
+ && p->next->flags & AF_FLAG_CONTROL ) {
|
|
2846
|
+ /* This point could be a candidate. Find the next and previous on-curve */
|
|
2847
|
+ /* points, and make sure they are both either above or below the point, */
|
|
2848
|
+ /* Then make the measurement */
|
|
2849
|
+ AF_Point prevOn = p->prev;
|
|
2850
|
+ AF_Point nextOn = p->next;
|
|
2851
|
+ while ( prevOn->flags & AF_FLAG_CONTROL ) {
|
|
2852
|
+ prevOn = prevOn->prev;
|
|
2853
|
+ }
|
|
2854
|
+ while ( nextOn->flags & AF_FLAG_CONTROL ) {
|
|
2855
|
+ nextOn = nextOn->next;
|
|
2856
|
+ }
|
|
2857
|
+ FT_Pos measurement;
|
|
2858
|
+ if ( nextOn->y > p->y && prevOn->y > p->y ) {
|
|
2859
|
+ measurement = p->y - min_y;
|
|
2860
|
+ } else if ( nextOn->y < p->y && prevOn->y < p->y ) {
|
|
2861
|
+ measurement = max_y - p->y;
|
|
2862
|
+ } else {
|
|
2863
|
+ continue;
|
|
2864
|
+ }
|
|
2865
|
+
|
|
2866
|
+ if (measurement < min_measurement) {
|
|
2867
|
+ min_measurement = measurement;
|
|
2868
|
+ }
|
|
2869
|
+ measurements_taken++;
|
|
2870
|
+ }
|
|
2871
|
+
|
|
2872
|
+ } while ( p != first_point );
|
|
2873
|
+
|
|
2874
|
+ FT_Pos height = max_y - min_y;
|
|
2875
|
+
|
|
2876
|
+ FT_Pos target_height = min_measurement + 64;
|
|
2877
|
+ if ( height >= target_height ) {
|
|
2878
|
+ return;
|
|
2879
|
+ }
|
|
2880
|
+
|
|
2881
|
+ p = first_point;
|
|
2882
|
+ do {
|
|
2883
|
+ p = p->next;
|
|
2884
|
+ /*if ( p->flags & AF_FLAG_CONTROL ) {
|
|
2885
|
+ continue;
|
|
2886
|
+ }*/
|
|
2887
|
+ p->y = ((p->y - min_y) * target_height / height) + min_y;
|
|
2888
|
+ p->fy = ((p->fy - min_fy) * target_height / height) + min_fy;
|
|
2889
|
+ p->oy = p->y;
|
|
2890
|
+ if ( !(p->flags & AF_FLAG_CONTROL) )
|
|
2891
|
+ p->flags |= AF_FLAG_TOUCH_Y;
|
|
2892
|
+ } while ( p != first_point );
|
|
2893
|
+
|
|
2894
|
+ FT_TRACE4(( "af_latin_stretch_tildes: Height: %d, measurement: %d, measurements taken: %d\n", height, min_measurement, measurements_taken ));
|
|
2895
|
+
|
|
2896
|
+ FT_Pos new_min_y, new_max_y;
|
|
2897
|
+ new_min_y = new_max_y = first_point->y;
|
|
2898
|
+ p = first_point;
|
|
2899
|
+ do {
|
|
2900
|
+ p = p->next;
|
|
2901
|
+ if ( p->y < new_min_y ) {
|
|
2902
|
+ new_min_y = p->y;
|
|
2903
|
+ }
|
|
2904
|
+ if ( p->y > new_max_y ) {
|
|
2905
|
+ new_max_y = p->y;
|
|
2906
|
+ }
|
|
2907
|
+ } while ( p != first_point );
|
|
2908
|
+
|
|
2909
|
+ FT_TRACE4(( "af_latin_stretch_tildes_merp: New height: %d\n, miny: %d, maxy: %d", new_max_y - new_min_y, new_min_y, new_max_y));
|
|
2910
|
+ }
|
|
2911
|
+
|
|
2912
|
+
|
|
2913
|
+}
|
|
2914
|
+
|
2751
|
2915
|
void
|
2752
|
2916
|
af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints,
|
2753
|
2917
|
AF_Dimension dim,
|
... |
... |
@@ -2776,7 +2940,7 @@ af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints, |
2776
|
2940
|
AF_Point point = hints->contours[contour];
|
2777
|
2941
|
AF_Point first_point = point;
|
2778
|
2942
|
if ( point == NULL )
|
2779
|
|
- { /*TODO: is this necessary?*/
|
|
2943
|
+ {
|
2780
|
2944
|
continue;
|
2781
|
2945
|
}
|
2782
|
2946
|
current_min_y = point->y;
|
... |
... |
@@ -2834,15 +2998,77 @@ af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints, |
2834
|
2998
|
FT_TRACE4(( " Pushing top contour %d units up\n", adjustment_amount ));
|
2835
|
2999
|
if ( adjustment_amount > 0 )
|
2836
|
3000
|
{
|
2837
|
|
- AF_Point point = hints->contours[highest_contour];
|
|
3001
|
+ af_move_contour_vertically(hints->contours[highest_contour], adjustment_amount);
|
|
3002
|
+ }
|
|
3003
|
+ } else if ( af_lookup_vertical_seperation_type( reverse_charmap, glyph_index ) == AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN
|
|
3004
|
+ && hints->num_contours >= 2 )
|
|
3005
|
+ {
|
|
3006
|
+ FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments: Applying vertical adjustment: AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN\n" ));
|
|
3007
|
+
|
|
3008
|
+ /*Find lowest contour*/
|
|
3009
|
+ FT_Int lowest_contour = -1;
|
|
3010
|
+ FT_Pos lowest_max_y = 0;
|
|
3011
|
+ FT_Pos current_max_y = 0;
|
|
3012
|
+
|
|
3013
|
+ for ( FT_Int contour = 0; contour < hints->num_contours; contour++ )
|
|
3014
|
+ {
|
|
3015
|
+ AF_Point point = hints->contours[contour];
|
2838
|
3016
|
AF_Point first_point = point;
|
2839
|
|
- if ( point != NULL )
|
|
3017
|
+ if ( point == NULL )
|
2840
|
3018
|
{
|
2841
|
|
- do
|
|
3019
|
+ continue;
|
|
3020
|
+ }
|
|
3021
|
+ current_max_y = point->y;
|
|
3022
|
+
|
|
3023
|
+ do
|
|
3024
|
+ {
|
|
3025
|
+ if ( point->y > current_max_y )
|
|
3026
|
+ {
|
|
3027
|
+ current_max_y = point->y;
|
|
3028
|
+ }
|
|
3029
|
+ point = point->next;
|
|
3030
|
+ } while ( point != first_point );
|
|
3031
|
+
|
|
3032
|
+ if ( lowest_contour == -1 || current_max_y < lowest_max_y )
|
|
3033
|
+ {
|
|
3034
|
+ lowest_max_y = current_max_y;
|
|
3035
|
+ lowest_contour = contour;
|
|
3036
|
+ }
|
|
3037
|
+ }
|
|
3038
|
+
|
|
3039
|
+ FT_Int adjustment_amount = 0;
|
|
3040
|
+ for ( FT_Int contour = 0; contour < hints->num_contours; contour++ )
|
|
3041
|
+ {
|
|
3042
|
+ if ( contour == lowest_contour )
|
|
3043
|
+ {
|
|
3044
|
+ continue;
|
|
3045
|
+ }
|
|
3046
|
+ AF_Point point = hints->contours[contour];
|
|
3047
|
+ AF_Point first_point = point;
|
|
3048
|
+ if ( point == NULL )
|
|
3049
|
+ {
|
|
3050
|
+ continue;
|
|
3051
|
+ }
|
|
3052
|
+ FT_Pos min_y = point->y;
|
|
3053
|
+
|
|
3054
|
+ do
|
|
3055
|
+ {
|
|
3056
|
+ if ( point->y < min_y )
|
2842
|
3057
|
{
|
2843
|
|
- point->y += adjustment_amount;
|
2844
|
|
- point = point->next;
|
2845
|
|
- } while ( point != first_point );
|
|
3058
|
+ min_y = point->y;
|
|
3059
|
+ }
|
|
3060
|
+ point = point->next;
|
|
3061
|
+ } while ( point != first_point );
|
|
3062
|
+
|
|
3063
|
+ if ( min_y <= lowest_max_y - 64 )
|
|
3064
|
+ {
|
|
3065
|
+ adjustment_amount = 64 - ( min_y - lowest_max_y );
|
|
3066
|
+ }
|
|
3067
|
+
|
|
3068
|
+ FT_TRACE4(( " Pushing bottom contour %d units down\n", adjustment_amount ));
|
|
3069
|
+ if ( adjustment_amount > 0 )
|
|
3070
|
+ {
|
|
3071
|
+ af_move_contour_vertically(hints->contours[lowest_contour], -adjustment_amount);
|
2846
|
3072
|
}
|
2847
|
3073
|
}
|
2848
|
3074
|
}
|
... |
... |
@@ -3666,6 +3892,31 @@ af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints, |
3666
|
3892
|
#endif
|
3667
|
3893
|
}
|
3668
|
3894
|
|
|
3895
|
+/*Print the height of the topmost contour for debugging purposes.
|
|
3896
|
+ TODO: remove this once the tilde unflattening works.*/
|
|
3897
|
+static void traceheight(FT_UInt num, AF_GlyphHints hints) {
|
|
3898
|
+ AF_Point p = hints->contours[af_find_highest_contour(hints)];
|
|
3899
|
+ AF_Point first_point = p;
|
|
3900
|
+
|
|
3901
|
+ FT_Pos min_y, max_y;
|
|
3902
|
+ min_y = max_y = p->y;
|
|
3903
|
+ FT_UInt candidates = 0;
|
|
3904
|
+
|
|
3905
|
+ do {
|
|
3906
|
+ p = p->next;
|
|
3907
|
+ if ( !(p->flags & AF_FLAG_CONTROL) ) {
|
|
3908
|
+ if ( p->y < min_y ) {
|
|
3909
|
+ min_y = p->y;
|
|
3910
|
+ }
|
|
3911
|
+ if ( p->y > max_y ) {
|
|
3912
|
+ max_y = p->y;
|
|
3913
|
+ }
|
|
3914
|
+ }
|
|
3915
|
+ } while ( p != first_point );
|
|
3916
|
+
|
|
3917
|
+ FT_Pos height = max_y - min_y;
|
|
3918
|
+ FT_TRACE4(( "height %d: %d\n", num, height ));
|
|
3919
|
+}
|
3669
|
3920
|
|
3670
|
3921
|
/* Apply the complete hinting algorithm to a latin glyph. */
|
3671
|
3922
|
|
... |
... |
@@ -3701,6 +3952,7 @@ af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints, |
3701
|
3952
|
|
3702
|
3953
|
if ( AF_HINTS_DO_VERTICAL( hints ) )
|
3703
|
3954
|
{
|
|
3955
|
+ af_latin_stretch_tildes( hints, glyph_index, metrics->root.reverse_charmap );
|
3704
|
3956
|
axis = &metrics->axis[AF_DIMENSION_VERT];
|
3705
|
3957
|
error = af_latin_hints_detect_features( hints,
|
3706
|
3958
|
axis->width_count,
|