X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Ffreetype.cc;fp=lily%2Ffreetype.cc;h=55a3fb378095af6a0f7f35f7f3e89d55ad6a550a;hb=0ac07f31e0f95fc18e5916ce756b9c746af7cc58;hp=f19b1649686225c8bc4f67b5bcf555d5a24096da;hpb=2f1263e2ccdddcac2eb9f7d8ce2ed92867d3d160;p=lilypond.git diff --git a/lily/freetype.cc b/lily/freetype.cc index f19b164968..55a3fb3780 100644 --- a/lily/freetype.cc +++ b/lily/freetype.cc @@ -20,6 +20,9 @@ #include "freetype.hh" #include "warn.hh" +#include FT_OUTLINE_H +#include FT_BBOX_H + FT_Library freetype2_library; void @@ -30,3 +33,172 @@ init_freetype () error ("cannot initialize FreeType"); } +Box +ly_FT_get_unscaled_indexed_char_dimensions (FT_Face const &face, size_t signed_idx) +{ + FT_UInt idx = FT_UInt (signed_idx); + FT_Load_Glyph (face, idx, FT_LOAD_NO_SCALE); + + FT_Glyph_Metrics m = face->glyph->metrics; + FT_Pos hb = m.horiBearingX; + FT_Pos vb = m.horiBearingY; + + // is this viable for all grobs? + return Box (Interval (Real (hb), Real (hb + m.width)), + Interval (Real (vb - m.height), Real (vb))); +} + +SCM +box_to_scheme_lines (Box b) +{ + return scm_list_4 (scm_list_4 (scm_from_double (b[X_AXIS][LEFT]), + scm_from_double (b[Y_AXIS][DOWN]), + scm_from_double (b[X_AXIS][RIGHT]), + scm_from_double (b[Y_AXIS][DOWN])), + scm_list_4 (scm_from_double (b[X_AXIS][RIGHT]), + scm_from_double (b[Y_AXIS][DOWN]), + scm_from_double (b[X_AXIS][RIGHT]), + scm_from_double (b[Y_AXIS][UP])), + scm_list_4 (scm_from_double (b[X_AXIS][RIGHT]), + scm_from_double (b[Y_AXIS][UP]), + scm_from_double (b[X_AXIS][LEFT]), + scm_from_double (b[Y_AXIS][UP])), + scm_list_4 (scm_from_double (b[X_AXIS][LEFT]), + scm_from_double (b[Y_AXIS][UP]), + scm_from_double (b[X_AXIS][LEFT]), + scm_from_double (b[Y_AXIS][DOWN]))); +} + +Box +ly_FT_get_glyph_outline_bbox (FT_Face const &face, size_t signed_idx) +{ + FT_UInt idx = FT_UInt (signed_idx); + FT_Load_Glyph (face, idx, FT_LOAD_NO_SCALE); + + if (!(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) + { +#if 0 + // will generate a lot of warnings + warning ("Cannot make glyph outline"); +#endif + return Box (Interval (infinity_f, -infinity_f), Interval (infinity_f, -infinity_f)); + } + FT_Outline *outline; + outline = &(face->glyph->outline); + + FT_BBox bbox; + FT_Outline_Get_BBox (outline, &bbox); + + return Box (Interval (bbox.xMin, bbox.xMax), Interval (bbox.yMin, bbox.yMax)); +} + +SCM +ly_FT_get_glyph_outline (FT_Face const &face, size_t signed_idx) +{ + FT_UInt idx = FT_UInt (signed_idx); + FT_Load_Glyph (face, idx, FT_LOAD_NO_SCALE); + + if (!(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) + { +#if 0 + // will generate a lot of warnings + warning ("Cannot make glyph outline"); +#endif + return box_to_scheme_lines (ly_FT_get_unscaled_indexed_char_dimensions (face, signed_idx)); + } + + FT_Outline *outline; + outline = &(face->glyph->outline); + SCM out = SCM_EOL; + Offset lastpos; + Offset firstpos; + int j = 0; + while (j < outline->n_points) + { + if (j == 0) + { + firstpos = Offset (outline->points[j].x, outline->points[j].y); + lastpos = firstpos; + j++; + } + else if (outline->tags[j] & 1) + { + // it is a line + out = scm_cons (scm_list_4 (scm_from_double (lastpos[X_AXIS]), + scm_from_double (lastpos[Y_AXIS]), + scm_from_double (outline->points[j].x), + scm_from_double (outline->points[j].y)), + out); + lastpos = Offset (outline->points[j].x, outline->points[j].y); + j++; + } + else if (outline->tags[j] & 2) + { + // it is a third order bezier + out = scm_cons (scm_list_n (scm_from_double (lastpos[X_AXIS]), + scm_from_double (lastpos[Y_AXIS]), + scm_from_double (outline->points[j].x), + scm_from_double (outline->points[j].y), + scm_from_double (outline->points[j + 1].x), + scm_from_double (outline->points[j + 1].y), + scm_from_double (outline->points[j + 2].x), + scm_from_double (outline->points[j + 2].y), + SCM_UNDEFINED), + out); + lastpos = Offset (outline->points[j + 2].x, outline->points[j + 2].y); + j += 3; + } + else + { + // it is a second order bezier + Real x0 = lastpos[X_AXIS]; + Real x1 = outline->points[j].x; + Real x2 = outline->points[j + 1].x; + + Real y0 = lastpos[Y_AXIS]; + Real y1 = outline->points[j].y; + Real y2 = outline->points[j + 1].y; + + Real qx2 = x0 + x2 - (2 * x1); + Real qx1 = (2 * x1) - (2 * x0); + Real qx0 = x0; + + Real qy2 = y0 + y2 - (2 * y1); + Real qy1 = (2 * y1) - (2 * y0); + Real qy0 = y0; + + Real cx0 = qx0; + Real cx1 = qx0 + (qx1 / 3); + Real cx2 = qx0 + (2 * qx1 / 3) + (qx2 / 3); + Real cx3 = qx0 + qx1 + qx2; + + Real cy0 = qy0; + Real cy1 = qy0 + (qy1 / 3); + Real cy2 = qy0 + (2 * qy1 / 3) + (qy2 / 3); + Real cy3 = qy0 + qy1 + qy2; + + out = scm_cons (scm_list_n (scm_from_double (cx0), + scm_from_double (cy0), + scm_from_double (cx1), + scm_from_double (cy1), + scm_from_double (cx2), + scm_from_double (cy2), + scm_from_double (cx3), + scm_from_double (cy3), + SCM_UNDEFINED), + out); + lastpos = Offset (outline->points[j + 1].x, outline->points[j + 1].y); + j += 2; + } + } + + // just in case, close the figure + out = scm_cons (scm_list_4 (scm_from_double (lastpos[X_AXIS]), + scm_from_double (lastpos[Y_AXIS]), + scm_from_double (firstpos[X_AXIS]), + scm_from_double (firstpos[Y_AXIS])), + out); + + out = scm_reverse_x (out, SCM_EOL); + return out; +}