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.
Fix warnings
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 { 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 PathList all_quadratic = g.get_quadratic_paths (); 61 PathList qp = new PathList (); 62 63 glyph = g; 64 65 int i = 0; 66 foreach (Path p in all_quadratic.paths) { 67 if (p.points.size > 0) { 68 if (likely (!is_empty (p))) { 69 // Add points at extrema 70 p.add_extrema (); 71 qp.add (p); 72 } else { 73 warning (@"Path number $i is empty in $(glyph.get_name ())"); 74 } 75 i++; 76 } 77 } 78 79 points.clear (); 80 paths.clear (); 81 foreach (Path p in qp.paths) { 82 paths.add (p); 83 84 foreach (EditPoint ep in p.points) { 85 points.add (ep); 86 } 87 } 88 89 if (paths.size > 0) { 90 process_end_points (); 91 process_flags (); 92 process_x (); 93 process_y (); 94 process_bounding_box (); 95 } 96 } 97 98 bool is_empty (Path p) { 99 EditPoint? last = null; 100 101 if (unlikely (p.points.size < 2)) { 102 return true; 103 } 104 105 foreach (EditPoint ep in p.points) { 106 if (last != null && !ep.equals ((!) last)) { 107 return false; 108 } 109 last = ep; 110 } 111 112 return true; 113 } 114 115 public uint16 get_end_point () { 116 return end_point; 117 } 118 119 public int16 get_ncontours () { 120 return (int16) paths.size; 121 } 122 123 public uint16 get_nflags () { 124 return nflags; 125 } 126 127 /** Count off curve points and on curve points. 128 * @return the number of points or uint16.MAX if more than uint16.MAX points where found. 129 */ 130 public int get_num_points () { 131 int points = 0; 132 133 foreach (Path quadratic in paths) { 134 points += 2 * quadratic.points.size; 135 136 if (points >= uint16.MAX) { 137 return uint16.MAX; 138 } 139 } 140 141 return points; 142 } 143 144 void process_end_points () { 145 uint16 last_end_point = 0; 146 PointType type; 147 148 end_points.clear (); 149 end_point = 0; 150 151 foreach (Path quadratic in paths) { 152 if (unlikely (quadratic.points.size == 0)) { 153 warning (@"No points in path (before conversion $(quadratic.points.size))"); 154 continue; 155 } 156 157 if (unlikely (quadratic.points.size < 2)) { 158 warning ("A path contains less than three points, it will not be exported. Path number: $path_number"); 159 continue; 160 } 161 162 foreach (EditPoint e in quadratic.points) { 163 if (unlikely (nflags == uint16.MAX - 1)) { 164 warning (@"Too many end points in $(glyph.get_name ())"); 165 break; 166 } 167 168 end_point++; 169 type = e.get_right_handle ().type; 170 171 // off curve 172 if (unlikely (nflags == uint16.MAX - 1)) { 173 warning (@"Too many end points in $(glyph.get_name ())"); 174 break; 175 } 176 177 end_point++; 178 } 179 end_points.add (end_point - 1); 180 181 if (unlikely (end_point - 1 < last_end_point)) { 182 warning (@"Next endpoint has bad value. (end_point - 1 < last_end_point) ($(end_point - 1) < $last_end_point)"); 183 } 184 185 last_end_point = end_point - 1; 186 } 187 188 if (unlikely (end_point == 0)) { 189 warning (@"End point is zero for glyph $(glyph.get_name ())"); 190 } 191 } 192 193 void process_flags () { 194 PointType type; 195 196 flags = new Gee.ArrayList<uint8> (); 197 nflags = 0; 198 199 foreach (Path p in paths) { 200 foreach (EditPoint e in p.points) { 201 flags.add (CoordinateFlags.ON_PATH); 202 nflags++; 203 204 type = e.get_right_handle ().type; 205 206 // off curve 207 flags.add (CoordinateFlags.NONE); 208 209 if (unlikely (nflags == uint16.MAX)) { 210 warning (@"Too many flags in $(glyph.get_name ())"); 211 return; 212 } 213 214 nflags++; 215 } 216 } 217 } 218 219 public static double tie_to_ttf_grid_x (Glyph glyph, double x) { 220 double ttf_x; 221 ttf_x = rint (x * UNITS - glyph.left_limit * UNITS); 222 return (ttf_x / UNITS) + glyph.left_limit; 223 } 224 225 public static double tie_to_ttf_grid_y (Font font, double y) { 226 double ttf_y; 227 ttf_y = rint (y * UNITS - font.base_line * UNITS); 228 return (ttf_y / UNITS) + font.base_line; 229 } 230 231 void process_x () { 232 double prev = 0; 233 double x; 234 PointType type; 235 236 coordinate_x.clear (); 237 foreach (Path p in paths) { 238 foreach (EditPoint e in p.points) { 239 x = rint (e.x * UNITS - prev - glyph.left_limit * UNITS); 240 coordinate_x.add ((int16) x); 241 242 prev = rint (e.x * UNITS - glyph.left_limit * UNITS); 243 244 type = e.get_right_handle ().type; 245 246 // off curve 247 x = rint (e.get_right_handle ().x * UNITS - prev - glyph.left_limit * UNITS); 248 coordinate_x.add ((int16) x); 249 250 prev = rint (e.get_right_handle ().x * UNITS - glyph.left_limit * UNITS); 251 } 252 } 253 } 254 255 void process_y () { 256 double prev = 0; 257 double y; 258 Font font = OpenFontFormatWriter.get_current_font (); 259 PointType type; 260 int epi = 0; 261 262 coordinate_y.clear (); 263 264 int path_number = 0; 265 266 foreach (Path p in paths) { 267 foreach (EditPoint e in p.points) { 268 y = rint (e.y * UNITS - prev - font.base_line * UNITS); 269 coordinate_y.add ((int16) y); 270 271 if ((int16) y == 0 && (int16) coordinate_x.get (coordinate_y.size - 1) == 0) { 272 warning (@"Point on point in TTF. Index $(coordinate_y.size - 1) " 273 + @"Path: $path_number in $(glyph.get_name ())"); 274 } 275 276 prev = rint (e.y * UNITS - font.base_line * UNITS); 277 278 type = e.get_right_handle ().type; 279 280 // off curve 281 y = rint (e.get_right_handle ().y * UNITS - prev - font.base_line * UNITS); 282 coordinate_y.add ((int16) y); 283 284 prev = rint (e.get_right_handle ().y * UNITS - font.base_line * UNITS); 285 epi++; 286 } 287 288 path_number++; 289 } 290 } 291 292 void process_bounding_box () { 293 int16 last = 0; 294 int i = 0; 295 296 bounding_box_xmin = int16.MAX; 297 bounding_box_ymin = int16.MAX; 298 bounding_box_xmax = int16.MIN; 299 bounding_box_ymax = int16.MIN; 300 301 if (coordinate_x.size == 0) { 302 warning ("no points in coordinate_y"); 303 } 304 305 foreach (int16 c in coordinate_x) { 306 c += last; 307 308 if (c < bounding_box_xmin) { 309 bounding_box_xmin = c; 310 } 311 312 if (c > bounding_box_xmax) { 313 bounding_box_xmax = c; 314 } 315 316 last = c; 317 i++; 318 } 319 320 if (coordinate_y.size == 0) { 321 warning ("no points in coordinate_y"); 322 } 323 324 last = 0; 325 i = 0; 326 foreach (int16 c in coordinate_y) { 327 c += last; 328 329 if (c < bounding_box_ymin) { 330 bounding_box_ymin = c; 331 } 332 333 if (c > bounding_box_ymax) { 334 bounding_box_ymax = c; 335 } 336 337 last = c; 338 i++; 339 } 340 341 printd (@"Bounding box: $bounding_box_xmin,$bounding_box_ymin $bounding_box_xmax,$bounding_box_ymax\n"); 342 } 343 } 344 345 } 346 347