The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

GlyfData.vala in libbirdfont/OpenFontFormat

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git

Revisions

View the latest version of libbirdfont/OpenFontFormat/GlyfData.vala.
Merge ../birdfont-2.x
1 /* 2 Copyright (C) 2012, 2013, 2014 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 using Math; 16 17 namespace BirdFont { 18 19 public class CoordinateFlags : GLib.Object { 20 /** TTF coordinate flags. */ 21 22 public static const uint8 NONE = 0; 23 public static const uint8 ON_PATH = 1 << 0; 24 public static const uint8 X_SHORT_VECTOR = 1 << 1; 25 public static const uint8 Y_SHORT_VECTOR = 1 << 2; 26 public static const uint8 REPEAT = 1 << 3; 27 28 // same flag or short vector sign flag 29 public static const uint8 X_IS_SAME = 1 << 4; 30 public static const uint8 Y_IS_SAME = 1 << 5; 31 public static const uint8 X_SHORT_VECTOR_POSITIVE = 1 << 4; 32 public static const uint8 Y_SHORT_VECTOR_POSITIVE = 1 << 5; 33 34 } 35 36 /** Data for one entry in the glyf table. */ 37 public class GlyfData : GLib.Object { 38 public Gee.ArrayList<Path> paths = new Gee.ArrayList<Path> (); 39 public Gee.ArrayList<EditPoint> points = new Gee.ArrayList<EditPoint> (); 40 public Gee.ArrayList<uint16> end_points = new Gee.ArrayList<uint16> (); 41 public Gee.ArrayList<uint8> flags = new Gee.ArrayList<uint8> (); 42 public Gee.ArrayList<int16> coordinate_x = new Gee.ArrayList<int16> (); 43 public Gee.ArrayList<int16> coordinate_y = new Gee.ArrayList<int16> (); 44 45 uint16 end_point = 0; 46 uint16 nflags = 0; 47 48 Glyph glyph; 49 50 public int16 bounding_box_xmin = 0; 51 public int16 bounding_box_ymin = 0; 52 public int16 bounding_box_xmax = 0; 53 public int16 bounding_box_ymax = 0; 54 55 private static double UNITS { 56 get { return HeadTable.UNITS; } 57 } 58 59 public GlyfData (Glyph g) { 60 bool process; 61 PathList all_quadratic = g.get_quadratic_paths (); 62 PathList qp = new PathList (); 63 64 glyph = g; 65 66 int i = 0; 67 foreach (Path p in all_quadratic.paths) { 68 if (p.points.size > 0) { 69 if (likely (!is_empty (p))) { 70 // Add points at extrema 71 p.add_extrema (); 72 qp.add (p); 73 } else { 74 warning (@"Path number $i is empty in $(glyph.get_name ())"); 75 } 76 i++; 77 } 78 } 79 80 points.clear (); 81 paths.clear (); 82 foreach (Path p in qp.paths) { 83 paths.add (p); 84 85 foreach (EditPoint ep in p.points) { 86 points.add (ep); 87 } 88 } 89 90 if (paths.size > 0) { 91 process_end_points (); 92 process_flags (); 93 process_x (); 94 process_y (); 95 process_bounding_box (); 96 } 97 } 98 99 bool is_empty (Path p) { 100 EditPoint? last = null; 101 102 if (unlikely (p.points.size < 2)) { 103 return true; 104 } 105 106 foreach (EditPoint ep in p.points) { 107 if (last != null && !ep.equals ((!) last)) { 108 return false; 109 } 110 last = ep; 111 } 112 113 return true; 114 } 115 116 public uint16 get_end_point () { 117 return end_point; 118 } 119 120 public int16 get_ncontours () { 121 return (int16) paths.size; 122 } 123 124 public uint16 get_nflags () { 125 return nflags; 126 } 127 128 /** Count off curve points and on curve points. 129 * @return the number of points or uint16.MAX if more than uint16.MAX points where found. 130 */ 131 public int get_num_points () { 132 int points = 0; 133 134 foreach (Path quadratic in paths) { 135 points += 2 * quadratic.points.size; 136 137 if (points >= uint16.MAX) { 138 return uint16.MAX; 139 } 140 } 141 142 return points; 143 } 144 145 void process_end_points () { 146 uint16 last_end_point = 0; 147 PointType type; 148 149 end_points.clear (); 150 end_point = 0; 151 152 int path_number = 0; 153 foreach (Path quadratic in paths) { 154 if (unlikely (quadratic.points.size == 0)) { 155 warning (@"No points in path (before conversion $(quadratic.points.size))"); 156 continue; 157 } 158 159 if (unlikely (quadratic.points.size < 2)) { 160 warning ("A path contains less than three points, it will not be exported. Path number: $path_number"); 161 continue; 162 } 163 164 foreach (EditPoint e in quadratic.points) { 165 if (unlikely (nflags == uint16.MAX - 1)) { 166 warning (@"Too many end points in $(glyph.get_name ())"); 167 break; 168 } 169 170 end_point++; 171 type = e.get_right_handle ().type; 172 173 // off curve 174 if (unlikely (nflags == uint16.MAX - 1)) { 175 warning (@"Too many end points in $(glyph.get_name ())"); 176 break; 177 } 178 179 end_point++; 180 } 181 end_points.add (end_point - 1); 182 183 if (unlikely (end_point - 1 < last_end_point)) { 184 warning (@"Next endpoint has bad value. (end_point - 1 < last_end_point) ($(end_point - 1) < $last_end_point)"); 185 } 186 187 last_end_point = end_point - 1; 188 } 189 190 if (unlikely (end_point == 0)) { 191 warning (@"End point is zero for glyph $(glyph.get_name ())"); 192 } 193 } 194 195 void process_flags () { 196 PointType type; 197 198 flags = new Gee.ArrayList<uint8> (); 199 nflags = 0; 200 201 foreach (Path p in paths) { 202 foreach (EditPoint e in p.points) { 203 flags.add (CoordinateFlags.ON_PATH); 204 nflags++; 205 206 type = e.get_right_handle ().type; 207 208 // off curve 209 flags.add (CoordinateFlags.NONE); 210 211 if (unlikely (nflags == uint16.MAX)) { 212 warning (@"Too many flags in $(glyph.get_name ())"); 213 return; 214 } 215 216 nflags++; 217 } 218 } 219 } 220 221 public static double tie_to_ttf_grid_x (Glyph glyph, double x) { 222 double ttf_x; 223 ttf_x = rint (x * UNITS - glyph.left_limit * UNITS); 224 return (ttf_x / UNITS) + glyph.left_limit; 225 } 226 227 public static double tie_to_ttf_grid_y (Font font, double y) { 228 double ttf_y; 229 ttf_y = rint (y * UNITS - font.base_line * UNITS); 230 return (ttf_y / UNITS) + font.base_line; 231 } 232 233 void process_x () { 234 double prev = 0; 235 double x; 236 PointType type; 237 238 coordinate_x.clear (); 239 foreach (Path p in paths) { 240 foreach (EditPoint e in p.points) { 241 x = rint (e.x * UNITS - prev - glyph.left_limit * UNITS); 242 coordinate_x.add ((int16) x); 243 244 prev = rint (e.x * UNITS - glyph.left_limit * UNITS); 245 246 type = e.get_right_handle ().type; 247 248 // off curve 249 x = rint (e.get_right_handle ().x * UNITS - prev - glyph.left_limit * UNITS); 250 coordinate_x.add ((int16) x); 251 252 prev = rint (e.get_right_handle ().x * UNITS - glyph.left_limit * UNITS); 253 } 254 } 255 } 256 257 void process_y () { 258 double prev = 0; 259 double y; 260 Font font = OpenFontFormatWriter.get_current_font (); 261 PointType type; 262 int epi = 0; 263 264 coordinate_y.clear (); 265 266 int path_number = 0; 267 268 foreach (Path p in paths) { 269 foreach (EditPoint e in p.points) { 270 y = rint (e.y * UNITS - prev - font.base_line * UNITS); 271 coordinate_y.add ((int16) y); 272 273 if ((int16) y == 0 && (int16) coordinate_x.get (coordinate_y.size - 1) == 0) { 274 warning (@"Point on point in TTF. Index $(coordinate_y.size - 1) " 275 + @"Path: $path_number in $(glyph.get_name ())"); 276 } 277 278 prev = rint (e.y * UNITS - font.base_line * UNITS); 279 280 type = e.get_right_handle ().type; 281 282 // off curve 283 y = rint (e.get_right_handle ().y * UNITS - prev - font.base_line * UNITS); 284 coordinate_y.add ((int16) y); 285 286 prev = rint (e.get_right_handle ().y * UNITS - font.base_line * UNITS); 287 epi++; 288 } 289 290 path_number++; 291 } 292 } 293 294 void process_bounding_box () { 295 int16 last = 0; 296 int i = 0; 297 298 bounding_box_xmin = int16.MAX; 299 bounding_box_ymin = int16.MAX; 300 bounding_box_xmax = int16.MIN; 301 bounding_box_ymax = int16.MIN; 302 303 if (coordinate_x.size == 0) { 304 warning ("no points in coordinate_y"); 305 } 306 307 foreach (int16 c in coordinate_x) { 308 c += last; 309 310 if (c < bounding_box_xmin) { 311 bounding_box_xmin = c; 312 } 313 314 if (c > bounding_box_xmax) { 315 bounding_box_xmax = c; 316 } 317 318 last = c; 319 i++; 320 } 321 322 if (coordinate_y.size == 0) { 323 warning ("no points in coordinate_y"); 324 } 325 326 last = 0; 327 i = 0; 328 foreach (int16 c in coordinate_y) { 329 c += last; 330 331 if (c < bounding_box_ymin) { 332 bounding_box_ymin = c; 333 } 334 335 if (c > bounding_box_ymax) { 336 bounding_box_ymax = c; 337 } 338 339 last = c; 340 i++; 341 } 342 343 printd (@"Bounding box: $bounding_box_xmin,$bounding_box_ymin $bounding_box_xmax,$bounding_box_ymax\n"); 344 } 345 } 346 347 } 348 349