LEFT | RIGHT |
(no file at all) | |
1 /* | 1 /* |
2 This file is part of LilyPond, the GNU music typesetter. | 2 This file is part of LilyPond, the GNU music typesetter. |
3 | 3 |
4 Copyright (C) 2004--2012 Han-Wen Nienhuys <hanwen@xs4all.nl> | 4 Copyright (C) 2004--2012 Han-Wen Nienhuys <hanwen@xs4all.nl> |
5 | 5 |
6 LilyPond is free software: you can redistribute it and/or modify | 6 LilyPond is free software: you can redistribute it and/or modify |
7 it under the terms of the GNU General Public License as published by | 7 it under the terms of the GNU General Public License as published by |
8 the Free Software Foundation, either version 3 of the License, or | 8 the Free Software Foundation, either version 3 of the License, or |
9 (at your option) any later version. | 9 (at your option) any later version. |
10 | 10 |
11 LilyPond is distributed in the hope that it will be useful, | 11 LilyPond is distributed in the hope that it will be useful, |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 GNU General Public License for more details. | 14 GNU General Public License for more details. |
15 | 15 |
16 You should have received a copy of the GNU General Public License | 16 You should have received a copy of the GNU General Public License |
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>. | 17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>. |
18 */ | 18 */ |
19 | 19 |
20 #include "freetype.hh" | 20 #include "freetype.hh" |
21 #include "warn.hh" | 21 #include "warn.hh" |
22 | 22 |
| 23 #include <freetype/ftoutln.h> |
| 24 #include <freetype/ftbbox.h> |
| 25 |
23 FT_Library freetype2_library; | 26 FT_Library freetype2_library; |
24 | 27 |
25 void | 28 void |
26 init_freetype () | 29 init_freetype () |
27 { | 30 { |
28 FT_Error errorcode = FT_Init_FreeType (&freetype2_library); | 31 FT_Error errorcode = FT_Init_FreeType (&freetype2_library); |
29 if (errorcode) | 32 if (errorcode) |
30 error ("cannot initialize FreeType"); | 33 error ("cannot initialize FreeType"); |
31 } | 34 } |
32 | 35 |
| 36 Box |
| 37 ly_FT_get_unscaled_indexed_char_dimensions (FT_Face const &face, size_t signed_i
dx) |
| 38 { |
| 39 FT_UInt idx = FT_UInt (signed_idx); |
| 40 FT_Load_Glyph (face, idx, FT_LOAD_NO_SCALE); |
| 41 |
| 42 FT_Glyph_Metrics m = face->glyph->metrics; |
| 43 FT_Pos hb = m.horiBearingX; |
| 44 FT_Pos vb = m.horiBearingY; |
| 45 |
| 46 // is this viable for all grobs? |
| 47 return Box (Interval (Real (hb), Real (hb + m.width)), |
| 48 Interval (Real (vb - m.height), Real (vb))); |
| 49 } |
| 50 |
| 51 SCM |
| 52 box_to_scheme_lines (Box b) |
| 53 { |
| 54 return scm_list_4 (scm_list_4 (scm_from_double (b[X_AXIS][LEFT]), |
| 55 scm_from_double (b[Y_AXIS][DOWN]), |
| 56 scm_from_double (b[X_AXIS][RIGHT]), |
| 57 scm_from_double (b[Y_AXIS][DOWN])), |
| 58 scm_list_4 (scm_from_double (b[X_AXIS][RIGHT]), |
| 59 scm_from_double (b[Y_AXIS][DOWN]), |
| 60 scm_from_double (b[X_AXIS][RIGHT]), |
| 61 scm_from_double (b[Y_AXIS][UP])), |
| 62 scm_list_4 (scm_from_double (b[X_AXIS][RIGHT]), |
| 63 scm_from_double (b[Y_AXIS][UP]), |
| 64 scm_from_double (b[X_AXIS][LEFT]), |
| 65 scm_from_double (b[Y_AXIS][UP])), |
| 66 scm_list_4 (scm_from_double (b[X_AXIS][LEFT]), |
| 67 scm_from_double (b[Y_AXIS][UP]), |
| 68 scm_from_double (b[X_AXIS][LEFT]), |
| 69 scm_from_double (b[Y_AXIS][DOWN]))); |
| 70 } |
| 71 |
| 72 Box |
| 73 ly_FT_get_glyph_outline_bbox (FT_Face const &face, size_t signed_idx) |
| 74 { |
| 75 FT_UInt idx = FT_UInt (signed_idx); |
| 76 FT_Load_Glyph (face, idx, FT_LOAD_NO_SCALE); |
| 77 |
| 78 if (!(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) |
| 79 { |
| 80 #if 0 |
| 81 // will generate a lot of warnings |
| 82 warning ("Cannot make glyph outline"); |
| 83 #endif |
| 84 return Box (Interval (infinity_f, -infinity_f), Interval (infinity_f, -inf
inity_f)); |
| 85 } |
| 86 FT_Outline *outline; |
| 87 outline = &(face->glyph->outline); |
| 88 |
| 89 FT_BBox bbox; |
| 90 FT_Outline_Get_BBox (outline, &bbox); |
| 91 |
| 92 return Box (Interval (bbox.xMin, bbox.xMax), Interval (bbox.yMin, bbox.yMax)); |
| 93 } |
| 94 |
| 95 SCM |
| 96 ly_FT_get_glyph_outline (FT_Face const &face, size_t signed_idx) |
| 97 { |
| 98 FT_UInt idx = FT_UInt (signed_idx); |
| 99 FT_Load_Glyph (face, idx, FT_LOAD_NO_SCALE); |
| 100 |
| 101 if (!(face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) |
| 102 { |
| 103 #if 0 |
| 104 // will generate a lot of warnings |
| 105 warning ("Cannot make glyph outline"); |
| 106 #endif |
| 107 return box_to_scheme_lines (ly_FT_get_unscaled_indexed_char_dimensions (fa
ce, signed_idx)); |
| 108 } |
| 109 |
| 110 FT_Outline *outline; |
| 111 outline = &(face->glyph->outline); |
| 112 SCM out = SCM_EOL; |
| 113 Offset lastpos; |
| 114 Offset firstpos; |
| 115 vsize j = 0; |
| 116 while (j < outline->n_points) |
| 117 { |
| 118 if (j == 0) |
| 119 { |
| 120 firstpos = Offset (outline->points[j].x, outline->points[j].y); |
| 121 lastpos = firstpos; |
| 122 j++; |
| 123 } |
| 124 else if (outline->tags[j] & 1) |
| 125 { |
| 126 // it is a line |
| 127 out = scm_cons (scm_list_4 (scm_from_double (lastpos[X_AXIS]), |
| 128 scm_from_double (lastpos[Y_AXIS]), |
| 129 scm_from_double (outline->points[j].x), |
| 130 scm_from_double (outline->points[j].y)), |
| 131 out); |
| 132 lastpos = Offset (outline->points[j].x, outline->points[j].y); |
| 133 j++; |
| 134 } |
| 135 else if (outline->tags[j] & 2) |
| 136 { |
| 137 // it is a third order bezier |
| 138 out = scm_cons (scm_list_n (scm_from_double (lastpos[X_AXIS]), |
| 139 scm_from_double (lastpos[Y_AXIS]), |
| 140 scm_from_double (outline->points[j].x), |
| 141 scm_from_double (outline->points[j].y), |
| 142 scm_from_double (outline->points[j + 1].x)
, |
| 143 scm_from_double (outline->points[j + 1].y)
, |
| 144 scm_from_double (outline->points[j + 2].x)
, |
| 145 scm_from_double (outline->points[j + 2].y)
, |
| 146 SCM_UNDEFINED), |
| 147 out); |
| 148 lastpos = Offset (outline->points[j + 2].x, outline->points[j + 2].y); |
| 149 j += 3; |
| 150 } |
| 151 else |
| 152 { |
| 153 // it is a second order bezier |
| 154 Real x0 = lastpos[X_AXIS]; |
| 155 Real x1 = outline->points[j].x; |
| 156 Real x2 = outline->points[j + 1].x; |
| 157 |
| 158 Real y0 = lastpos[Y_AXIS]; |
| 159 Real y1 = outline->points[j].y; |
| 160 Real y2 = outline->points[j + 1].y; |
| 161 |
| 162 Real qx2 = x0 + x2 - (2 * x1); |
| 163 Real qx1 = (2 * x1) - (2 * x0); |
| 164 Real qx0 = x0; |
| 165 |
| 166 Real qy2 = y0 + y2 - (2 * y1); |
| 167 Real qy1 = (2 * y1) - (2 * y0); |
| 168 Real qy0 = y0; |
| 169 |
| 170 Real cx0 = qx0; |
| 171 Real cx1 = qx0 + (qx1 / 3); |
| 172 Real cx2 = qx0 + (2 * qx1 / 3) + (qx2 / 3); |
| 173 Real cx3 = qx0 + qx1 + qx2; |
| 174 |
| 175 Real cy0 = qy0; |
| 176 Real cy1 = qy0 + (qy1 / 3); |
| 177 Real cy2 = qy0 + (2 * qy1 / 3) + (qy2 / 3); |
| 178 Real cy3 = qy0 + qy1 + qy2; |
| 179 |
| 180 out = scm_cons (scm_list_n (scm_from_double (cx0), |
| 181 scm_from_double (cy0), |
| 182 scm_from_double (cx1), |
| 183 scm_from_double (cy1), |
| 184 scm_from_double (cx2), |
| 185 scm_from_double (cy2), |
| 186 scm_from_double (cx3), |
| 187 scm_from_double (cy3), |
| 188 SCM_UNDEFINED), |
| 189 out); |
| 190 lastpos = Offset (outline->points[j + 1].x, outline->points[j + 1].y); |
| 191 j += 2; |
| 192 } |
| 193 } |
| 194 |
| 195 // just in case, close the figure |
| 196 out = scm_cons (scm_list_4 (scm_from_double (lastpos[X_AXIS]), |
| 197 scm_from_double (lastpos[Y_AXIS]), |
| 198 scm_from_double (firstpos[X_AXIS]), |
| 199 scm_from_double (firstpos[Y_AXIS])), |
| 200 out); |
| 201 |
| 202 out = scm_reverse_x (out, SCM_EOL); |
| 203 return out; |
| 204 } |
LEFT | RIGHT |