improve FT_Outline_Get_Orientation for broken asian fonts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
diff --git a/ChangeLog b/ChangeLog
index 20b7bac..24cde48 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2006-10-23 Zhe Su <zsu@novell.com>
+
+ * src/base/ftoutln.c: re-implementing FT_Outline_Get_Orientation to
+ better deal with broken Asian fonts with funky glyphs with
+ self-intersections and other stupid things
+
2006-10-23 David Turner <david@freetype.org>
* src/sfnt/ttmtx.c, src/cff/cffload.c: speeding up the CFF font
diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c
index a6d5553..caee514 100644
--- a/src/base/ftoutln.c
+++ b/src/base/ftoutln.c
@@ -934,7 +934,8 @@
FT_Outline_Get_Orientation( FT_Outline* outline )
{
FT_Pos xmin = 32768L;
- FT_Vector* xmin_point = NULL;
+ FT_Pos xmin_ymin = 32768L;
+ FT_Pos xmin_ymax = -32768L;
FT_Vector* xmin_first = NULL;
FT_Vector* xmin_last = NULL;
@@ -943,8 +944,11 @@
FT_Vector* first;
FT_Vector* last;
FT_Vector* prev;
- FT_Vector* next;
+ FT_Vector* point;
+ int i;
+ FT_Pos ray_y [3];
+ int result [3];
if ( !outline || outline->n_points <= 0 )
return FT_ORIENTATION_TRUETYPE;
@@ -954,11 +958,10 @@
contour < outline->contours + outline->n_contours;
contour++, first = last + 1 )
{
- FT_Vector* point;
- FT_Int on_curve;
- FT_Int on_curve_count = 0;
- FT_Pos tmp_xmin = 32768L;
- FT_Vector* tmp_xmin_point = NULL;
+ FT_Pos contour_xmin = 32768L;
+ FT_Pos contour_xmax = -32768L;
+ FT_Pos contour_ymin = 32768L;
+ FT_Pos contour_ymax = -32768L;
last = outline->points + *contour;
@@ -968,74 +971,106 @@
for ( point = first; point <= last; ++point )
{
- /* Count on-curve points. If there are less than 3 on-curve */
- /* points, just bypass this contour. */
- on_curve = outline->tags[point - outline->points] & 1;
- on_curve_count += on_curve;
+ if ( point->x < contour_xmin )
+ contour_xmin = point->x;
- if ( point->x < tmp_xmin && on_curve )
- {
- tmp_xmin = point->x;
- tmp_xmin_point = point;
- }
+ if ( point->x > contour_xmax )
+ contour_xmax = point->x;
+
+ if ( point->y < contour_ymin )
+ contour_ymin = point->y;
+
+ if ( point->y > contour_ymax )
+ contour_ymax = point->y;
}
- if ( on_curve_count > 2 && tmp_xmin < xmin )
+ if ( contour_xmin < xmin &&
+ contour_xmin != contour_xmax &&
+ contour_ymin != contour_ymax )
{
- xmin = tmp_xmin;
- xmin_point = tmp_xmin_point;
+ xmin = contour_xmin;
+ xmin_ymin = contour_ymin;
+ xmin_ymax = contour_ymax;
xmin_first = first;
xmin_last = last;
}
}
- if ( !xmin_point )
+ if ( xmin == 32768 )
return FT_ORIENTATION_TRUETYPE;
- prev = ( xmin_point == xmin_first ) ? xmin_last : xmin_point - 1;
- next = ( xmin_point == xmin_last ) ? xmin_first : xmin_point + 1;
+ ray_y[0] = (xmin_ymin*3 + xmin_ymax) >> 2;
+ ray_y[1] = (xmin_ymin + xmin_ymax) >> 1;
+ ray_y[2] = (xmin_ymin + xmin_ymax*3) >> 2;
- /* Skip off-curve points */
- while ( ( outline->tags[prev - outline->points] & 1 ) == 0 )
+ for ( i = 0; i < 3; i++ )
{
- if ( prev == xmin_first )
- prev = xmin_last;
- else
- --prev;
- }
+ FT_Pos left_x;
+ FT_Pos right_x;
+ FT_Vector* left1;
+ FT_Vector* left2;
+ FT_Vector* right1;
+ FT_Vector* right2;
- while ( ( outline->tags[next - outline->points] & 1 ) == 0 )
- {
- if ( next == xmin_last )
- next = xmin_first;
- else
- ++next;
- }
+ RedoRay:
+ left_x = 32768L;
+ right_x = -32768L;
-#if 1
+ left1 = left2 = right1 = right2 = NULL;
- {
- FT_Pos dx1 = prev->x - xmin_point->x;
- FT_Pos dy1 = prev->y - xmin_point->y;
- FT_Pos dx2 = next->x - xmin_point->x;
- FT_Pos dy2 = next->y - xmin_point->y;
+ prev = xmin_last;
+ for ( point = xmin_first; point <= xmin_last; prev = point, ++point )
+ {
+ FT_Pos tmp_x;
+ if ( point->y == ray_y[i] || prev->y == ray_y[i] )
+ {
+ ++ ray_y[i];
+ goto RedoRay;
+ }
- if ( dy1 * dx2 > dy2 * dx1 )
- return FT_ORIENTATION_POSTSCRIPT;
- else
- return FT_ORIENTATION_TRUETYPE;
+ if ( (point->y < ray_y[i] && prev->y < ray_y[i]) ||
+ (point->y > ray_y[i] && prev->y > ray_y[i]) )
+ {
+ continue;
+ }
+
+ tmp_x = FT_MulDiv( point->x - prev->x, ray_y[i] - prev->y, point->y - prev->y ) + prev->x;
+
+ if ( tmp_x < left_x )
+ {
+ left_x = tmp_x;
+ left1 = prev;
+ left2 = point;
+ }
+
+ if ( tmp_x > right_x )
+ {
+ right_x = tmp_x;
+ right1 = prev;
+ right2 = point;
+ }
+ }
+
+ if ( left1 && right1 )
+ {
+ if ( left1->y < left2->y && right1->y > right2->y )
+ result[i] = FT_ORIENTATION_TRUETYPE;
+ else if ( left1->y > left2->y && right1->y < right2->y )
+ result[i] = FT_ORIENTATION_POSTSCRIPT;
+ else
+ result[i] = FT_ORIENTATION_NONE;
+ }
}
-#else /* 0 */
+ if ( result[0] != FT_ORIENTATION_NONE &&
+ (result[0] == result[1] || result[0] == result[2]) )
+ return result[0];
- if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) >
- FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) )
- return FT_ORIENTATION_POSTSCRIPT;
- else
- return FT_ORIENTATION_TRUETYPE;
+ if ( result[1] != FT_ORIENTATION_NONE && result[1] == result[2] )
+ return result[1];
-#endif /* 0 */
+ return FT_ORIENTATION_TRUETYPE;
}