Commit 8fe65b2
Use quatratic control points for estimating SVG arc instruction before converting TTF
Changed files (5)
modifiedlibbirdfont/OpenFontFormat/OpenFontFormatReader.valamodifiedlibbirdfont/OpenFontFormat/load_font.cmodifiedlibbirdfont/Path.valamodifiedlibbirdfont/SvgArc.valamodifiedlibbirdfont/SvgParser.vala
Diff
@@ -147,7 +147,7 @@ public class OpenFontFormatReader : Object { return directory_table.head_table.get_adjusted_checksum (); } - public static string parse_kerning (string file_name) {+ public static string? parse_kerning (string file_name) { KernTable kern_table; CmapTable cmap_table; HeadTable head_table;@@ -156,6 +156,7 @@ public class OpenFontFormatReader : Object { unichar left, right; double kerning, units_per_em; uint npairs = 0;+ string result = ""; try { reader.parse_index (file_name);@@ -194,7 +195,13 @@ public class OpenFontFormatReader : Object { warning (@"Failed to parse font. $(e.message)"); } - return bf_kerning.str;+ result = bf_kerning.str;+ + if (result == "") {+ return null;+ }+ + return result.dup (); } } }@@ -757,6 +757,7 @@ GString* get_bf_font (FT_Face face, char* file, int* err) { g_string_append_printf (bf, "</collection>\n"); } + // glyph outlines for (i = 0; i < face->num_glyphs; i++) { error = FT_Load_Glyph (face, i, FT_LOAD_DEFAULT | FT_LOAD_NO_SCALE);@@ -792,9 +793,9 @@ GString* get_bf_font (FT_Face face, char* file, int* err) { g_string_append (bf, glyph->str); g_string_free (glyph, 0); }- + kerning = (gchar*) bird_font_open_font_format_reader_parse_kerning (file); - + if (kerning != NULL) { g_string_append (bf, kerning); g_free (kerning); @@ -1063,10 +1063,11 @@ public class Path { foreach (EditPoint next in points) { left = first.get_right_handle ().type; right = next.get_left_handle ().type;+ if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) { first.get_right_handle ().type = PointType.QUADRATIC; - // half the way between handles+ // half way between handles x = first.get_right_handle ().x () + (next.get_left_handle ().x () - first.get_right_handle ().x ()) / 2; y = first.get_right_handle ().y () + (next.get_left_handle ().y () - first.get_right_handle ().y ()) / 2; @@ -1090,6 +1091,10 @@ public class Path { } for (int i = 0; i < middle_points.size; i++) {+ + hidden = middle_points.get (i);+ print (@"middle $(hidden.x) $(hidden.y)\n");+ add_point_after (middle_points.get (i), first_points.get (i)); } }@@ -1108,7 +1113,7 @@ public class Path { warning ("Less than 2 points in path."); return quadratic_path; }- + i = points.get (0); next = i.get_next (); @@ -1155,7 +1160,9 @@ public class Path { } else { quadratic_path.reopen (); }- + + quadratic_path.remove_points_on_points ();+ return quadratic_path; } @@ -1184,7 +1191,9 @@ public class Path { e = new EditPoint (x, y, PointType.QUADRATIC); added_points++;-+ + e = quadratic_path.add_point (e);+/* prev = e; e = quadratic_path.add_point (e);@@ -1193,9 +1202,14 @@ public class Path { prev.recalculate_linear_handles (); new_quadratic_points.add (prev);+*/ return true; }, steps); + foreach (EditPoint e in quadratic_path.points) {+ e.recalculate_linear_handles ();+ }+ quadratic_path.close (); } @@ -2148,6 +2162,52 @@ public class Path { } return i; }+ + public void remove_points_on_points () + requires (points.size > 0) {+ Gee.ArrayList<EditPoint> remove = new Gee.ArrayList<EditPoint> ();+ EditPoint n;+ EditPointHandle hr, h;+ + create_list ();+ + foreach (EditPoint ep in points) {+ if (ep.next != null) {+ n = ep.get_next ();+ } else {+ warning ("NEXT IS NULL");+ n = points.get (0);+ }+ + if (fabs (n.x - ep.x) < 0.00001 && fabs (n.y - ep.y) < 0.00001) {+ remove.add (ep);+ }+ }++ foreach (EditPoint r in remove) {+ if (r.next != null) {+ n = r.get_next ();+ } else {+ n = points.get (0);+ }+ + points.remove (r);+ h = n.get_left_handle ();+ hr = r.get_left_handle ();+ h.length = hr.length;+ h.angle = hr.angle;+ h.type = hr.type;+ + if (h.length < 0.00001) {+ h.length = 0.00001;+ h.angle = n.get_right_handle ().angle - PI;+ }+ + create_list ();+ }+ + recalculate_linear_handles ();+ } } }@@ -79,9 +79,11 @@ static void add_arc_points (BezierPoints[] bezier_points, ref int bi, double x0, Pry = ry * ry; Px1 = x1 * x1; Py1 = y1 * y1;+ // Check that radii are large enough radiiCheck = Px1 / Prx + Py1 / Pry;+ if (radiiCheck > 1) { rx = sqrt (radiiCheck) * rx; ry = sqrt (radiiCheck) * ry;@@ -93,7 +95,7 @@ static void add_arc_points (BezierPoints[] bezier_points, ref int bi, double x0, // Step 2 : Compute (cx1, cy1) // sign = (largeArcFlag == sweepFlag) ? -1 : 1;- sq = ((Prx*Pry)-(Prx*Py1)-(Pry*Px1)) / ((Prx*Py1)+(Pry*Px1));+ sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1)) / ((Prx * Py1) + (Pry * Px1)); sq = (sq < 0) ? 0 : sq; coef = (sign * Math.sqrt(sq)); cx1 = coef * ((rx * y1) / ry);@@ -142,7 +144,7 @@ static void add_arc_points (BezierPoints[] bezier_points, ref int bi, double x0, // Approximate the path with Beziér points s = (angleExtent > 0) ? 1 : -1;- step = fabs (angleExtent) / (3 * fabs (angleExtent));+ step = fabs (angleExtent) / (2 * fabs (angleExtent)); theta = PI - angleStart - angleExtent; @@ -163,11 +165,11 @@ static void add_arc_points (BezierPoints[] bezier_points, ref int bi, double x0, bezier_points[bi].x0 = cx + rx * cos (theta); bezier_points[bi].y0 = cy + ry * sin (theta); - bezier_points[bi].x1 = cx + rx * cos (theta + 1 * step / 3);- bezier_points[bi].y1 = cy + ry * sin (theta + 1 * step / 3);+ bezier_points[bi].x1 = cx + rx * cos (theta + 1 * step / 4);+ bezier_points[bi].y1 = cy + ry * sin (theta + 1 * step / 4); - bezier_points[bi].x2 = cx + rx * cos (theta + 2 * step / 3);- bezier_points[bi].y2 = cy + ry * sin (theta + 2 * step / 3);+ bezier_points[bi].x2 = cx + rx * cos (theta + 2 * step / 4);+ bezier_points[bi].y2 = cy + ry * sin (theta + 2 * step / 4); bi++; }@@ -904,7 +904,6 @@ public class SvgParser { PathList path_list = new PathList (); EditPoint ep = new EditPoint (); Gee.ArrayList<EditPoint> smooth_points = new Gee.ArrayList<EditPoint> ();- EditPoint next, prev; path = new Path (); @@ -1021,28 +1020,31 @@ public class SvgParser { } foreach (EditPoint e in smooth_points) {- e.set_tie_handle (true);- e.process_tied_handle ();- - e.set_point_type (PointType.CUBIC);- e.get_right_handle ().set_point_type (PointType.CUBIC);- e.get_left_handle ().set_point_type (PointType.CUBIC);- - if (e.next != null) {- next = e.get_next ();- next.get_left_handle ().angle = next.get_right_handle ().angle - PI;- }+ e.set_point_type (PointType.LINE_DOUBLE_CURVE);+ e.get_right_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);+ e.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);+ } - if (e.prev != null) {- prev = e.get_prev ();- prev.get_right_handle ().angle = prev.get_left_handle ().angle - PI;+ foreach (EditPoint e in smooth_points) {+ e.recalculate_linear_handles ();+ }+ ++ for (int i = 0; i < 3; i++) {+ foreach (EditPoint e in smooth_points) {+ e.set_tie_handle (true);+ e.process_tied_handle (); } } if (path.points.size > 0) { path_list.add (path); }- ++ foreach (Path p in path_list.paths) {+ p.remove_points_on_points ();+ }+ return path_list; } @@ -1053,7 +1055,6 @@ public class SvgParser { bool first_point = true; double first_left_x, first_left_y; Gee.ArrayList<EditPoint> smooth_points = new Gee.ArrayList<EditPoint> ();- EditPoint next, prev; path = new Path (); @@ -1140,21 +1141,20 @@ public class SvgParser { } foreach (EditPoint e in smooth_points) {- e.set_tie_handle (true);- e.process_tied_handle ();+ e.set_point_type (PointType.LINE_DOUBLE_CURVE);+ e.get_right_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);+ e.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);+ } - e.set_point_type (PointType.CUBIC);- e.get_right_handle ().set_point_type (PointType.CUBIC);- e.get_left_handle ().set_point_type (PointType.CUBIC);+ foreach (EditPoint e in smooth_points) {+ e.recalculate_linear_handles ();+ }+ - if (e.next != null) {- next = e.get_next ();- next.get_left_handle ().angle = next.get_right_handle ().angle - PI;- }- - if (e.prev != null) {- prev = e.get_prev ();- prev.get_right_handle ().angle = prev.get_left_handle ().angle - PI;+ for (int i = 0; i < 3; i++) {+ foreach (EditPoint e in smooth_points) {+ e.set_tie_handle (true);+ e.process_tied_handle (); } } @@ -1163,6 +1163,10 @@ public class SvgParser { path_list.add (path); } + foreach (Path p in path_list.paths) {+ p.remove_points_on_points ();+ }+ return path_list; }