1 #ifndef OT_GLYF_VARCOMPOSITEGLYPH_HH 2 #define OT_GLYF_VARCOMPOSITEGLYPH_HH 3 4 5 #include "../../hb-open-type.hh" 6 #include "coord-setter.hh" 7 8 9 namespace OT { 10 namespace glyf_impl { 11 12 13 struct VarCompositeGlyphRecord 14 { 15 protected: 16 enum var_composite_glyph_flag_t 17 { 18 USE_MY_METRICS = 0x0001, 19 AXIS_INDICES_ARE_SHORT = 0x0002, 20 UNIFORM_SCALE = 0x0004, 21 HAVE_TRANSLATE_X = 0x0008, 22 HAVE_TRANSLATE_Y = 0x0010, 23 HAVE_ROTATION = 0x0020, 24 HAVE_SCALE_X = 0x0040, 25 HAVE_SCALE_Y = 0x0080, 26 HAVE_SKEW_X = 0x0100, 27 HAVE_SKEW_Y = 0x0200, 28 HAVE_TCENTER_X = 0x0400, 29 HAVE_TCENTER_Y = 0x0800, 30 GID_IS_24 = 0x1000, 31 AXES_HAVE_VARIATION = 0x2000, 32 }; 33 34 public: 35 get_sizeOT::glyf_impl::VarCompositeGlyphRecord36 unsigned int get_size () const 37 { 38 unsigned int size = min_size; 39 40 unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3; 41 size += numAxes * axis_width; 42 43 // gid 44 size += 2; 45 if (flags & GID_IS_24) size += 1; 46 47 if (flags & HAVE_TRANSLATE_X) size += 2; 48 if (flags & HAVE_TRANSLATE_Y) size += 2; 49 if (flags & HAVE_ROTATION) size += 2; 50 if (flags & HAVE_SCALE_X) size += 2; 51 if (flags & HAVE_SCALE_Y) size += 2; 52 if (flags & HAVE_SKEW_X) size += 2; 53 if (flags & HAVE_SKEW_Y) size += 2; 54 if (flags & HAVE_TCENTER_X) size += 2; 55 if (flags & HAVE_TCENTER_Y) size += 2; 56 57 return size; 58 } 59 has_moreOT::glyf_impl::VarCompositeGlyphRecord60 bool has_more () const { return true; } 61 is_use_my_metricsOT::glyf_impl::VarCompositeGlyphRecord62 bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } 63 get_gidOT::glyf_impl::VarCompositeGlyphRecord64 hb_codepoint_t get_gid () const 65 { 66 if (flags & GID_IS_24) 67 return StructAfter<const HBGlyphID24> (numAxes); 68 else 69 return StructAfter<const HBGlyphID16> (numAxes); 70 } 71 get_numAxesOT::glyf_impl::VarCompositeGlyphRecord72 unsigned get_numAxes () const 73 { 74 return numAxes; 75 } 76 get_num_pointsOT::glyf_impl::VarCompositeGlyphRecord77 unsigned get_num_points () const 78 { 79 unsigned num = 0; 80 if (flags & AXES_HAVE_VARIATION) num += numAxes; 81 if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++; 82 if (flags & HAVE_ROTATION) num++; 83 if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++; 84 if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++; 85 if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++; 86 return num; 87 } 88 transform_pointsOT::glyf_impl::VarCompositeGlyphRecord89 void transform_points (hb_array_t<contour_point_t> record_points, 90 contour_point_vector_t &points) const 91 { 92 float matrix[4]; 93 contour_point_t trans; 94 95 get_transformation_from_points (record_points, matrix, trans); 96 97 points.transform (matrix); 98 points.translate (trans); 99 } 100 transformOT::glyf_impl::VarCompositeGlyphRecord101 static inline void transform (float (&matrix)[4], contour_point_t &trans, 102 float (other)[6]) 103 { 104 // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L268 105 float xx1 = other[0]; 106 float xy1 = other[1]; 107 float yx1 = other[2]; 108 float yy1 = other[3]; 109 float dx1 = other[4]; 110 float dy1 = other[5]; 111 float xx2 = matrix[0]; 112 float xy2 = matrix[1]; 113 float yx2 = matrix[2]; 114 float yy2 = matrix[3]; 115 float dx2 = trans.x; 116 float dy2 = trans.y; 117 118 matrix[0] = xx1*xx2 + xy1*yx2; 119 matrix[1] = xx1*xy2 + xy1*yy2; 120 matrix[2] = yx1*xx2 + yy1*yx2; 121 matrix[3] = yx1*xy2 + yy1*yy2; 122 trans.x = xx2*dx1 + yx2*dy1 + dx2; 123 trans.y = xy2*dx1 + yy2*dy1 + dy2; 124 } 125 translateOT::glyf_impl::VarCompositeGlyphRecord126 static void translate (float (&matrix)[4], contour_point_t &trans, 127 float translateX, float translateY) 128 { 129 // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213 130 float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY}; 131 transform (matrix, trans, other); 132 } 133 scaleOT::glyf_impl::VarCompositeGlyphRecord134 static void scale (float (&matrix)[4], contour_point_t &trans, 135 float scaleX, float scaleY) 136 { 137 // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224 138 float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f}; 139 transform (matrix, trans, other); 140 } 141 rotateOT::glyf_impl::VarCompositeGlyphRecord142 static void rotate (float (&matrix)[4], contour_point_t &trans, 143 float rotation) 144 { 145 // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240 146 rotation = rotation * float (M_PI); 147 float c = cosf (rotation); 148 float s = sinf (rotation); 149 float other[6] = {c, s, -s, c, 0.f, 0.f}; 150 transform (matrix, trans, other); 151 } 152 skewOT::glyf_impl::VarCompositeGlyphRecord153 static void skew (float (&matrix)[4], contour_point_t &trans, 154 float skewX, float skewY) 155 { 156 // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255 157 skewX = skewX * float (M_PI); 158 skewY = skewY * float (M_PI); 159 float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f}; 160 transform (matrix, trans, other); 161 } 162 get_pointsOT::glyf_impl::VarCompositeGlyphRecord163 bool get_points (contour_point_vector_t &points) const 164 { 165 float translateX = 0.f; 166 float translateY = 0.f; 167 float rotation = 0.f; 168 float scaleX = 1.f * (1 << 12); 169 float scaleY = 1.f * (1 << 12); 170 float skewX = 0.f; 171 float skewY = 0.f; 172 float tCenterX = 0.f; 173 float tCenterY = 0.f; 174 175 if (unlikely (!points.resize (points.length + get_num_points ()))) return false; 176 177 unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1; 178 unsigned axes_size = numAxes * axis_width; 179 180 const F2DOT14 *q = (const F2DOT14 *) (axes_size + 181 (flags & GID_IS_24 ? 3 : 2) + 182 &StructAfter<const HBUINT8> (numAxes)); 183 184 hb_array_t<contour_point_t> rec_points = points.as_array ().sub_array (points.length - get_num_points ()); 185 186 unsigned count = numAxes; 187 if (flags & AXES_HAVE_VARIATION) 188 { 189 for (unsigned i = 0; i < count; i++) 190 rec_points[i].x = *q++; 191 rec_points += count; 192 } 193 else 194 q += count; 195 196 const HBUINT16 *p = (const HBUINT16 *) q; 197 198 if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++; 199 if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++; 200 if (flags & HAVE_ROTATION) rotation = * (const F2DOT14 *) p++; 201 if (flags & HAVE_SCALE_X) scaleX = * (const F4DOT12 *) p++; 202 if (flags & HAVE_SCALE_Y) scaleY = * (const F4DOT12 *) p++; 203 if (flags & HAVE_SKEW_X) skewX = * (const F2DOT14 *) p++; 204 if (flags & HAVE_SKEW_Y) skewY = * (const F2DOT14 *) p++; 205 if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++; 206 if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++; 207 208 if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y)) 209 scaleY = scaleX; 210 211 if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) 212 { 213 rec_points[0].x = translateX; 214 rec_points[0].y = translateY; 215 rec_points++; 216 } 217 if (flags & HAVE_ROTATION) 218 { 219 rec_points[0].x = rotation; 220 rec_points++; 221 } 222 if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) 223 { 224 rec_points[0].x = scaleX; 225 rec_points[0].y = scaleY; 226 rec_points++; 227 } 228 if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) 229 { 230 rec_points[0].x = skewX; 231 rec_points[0].y = skewY; 232 rec_points++; 233 } 234 if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) 235 { 236 rec_points[0].x = tCenterX; 237 rec_points[0].y = tCenterY; 238 rec_points++; 239 } 240 assert (!rec_points); 241 242 return true; 243 } 244 get_transformation_from_pointsOT::glyf_impl::VarCompositeGlyphRecord245 void get_transformation_from_points (hb_array_t<contour_point_t> rec_points, 246 float (&matrix)[4], contour_point_t &trans) const 247 { 248 if (flags & AXES_HAVE_VARIATION) 249 rec_points += numAxes; 250 251 matrix[0] = matrix[3] = 1.f; 252 matrix[1] = matrix[2] = 0.f; 253 trans.init (0.f, 0.f); 254 255 float translateX = 0.f; 256 float translateY = 0.f; 257 float rotation = 0.f; 258 float scaleX = 1.f; 259 float scaleY = 1.f; 260 float skewX = 0.f; 261 float skewY = 0.f; 262 float tCenterX = 0.f; 263 float tCenterY = 0.f; 264 265 if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) 266 { 267 translateX = rec_points[0].x; 268 translateY = rec_points[0].y; 269 rec_points++; 270 } 271 if (flags & HAVE_ROTATION) 272 { 273 rotation = rec_points[0].x / (1 << 14); 274 rec_points++; 275 } 276 if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) 277 { 278 scaleX = rec_points[0].x / (1 << 12); 279 scaleY = rec_points[0].y / (1 << 12); 280 rec_points++; 281 } 282 if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) 283 { 284 skewX = rec_points[0].x / (1 << 14); 285 skewY = rec_points[0].y / (1 << 14); 286 rec_points++; 287 } 288 if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) 289 { 290 tCenterX = rec_points[0].x; 291 tCenterY = rec_points[0].y; 292 rec_points++; 293 } 294 assert (!rec_points); 295 296 translate (matrix, trans, translateX + tCenterX, translateY + tCenterY); 297 rotate (matrix, trans, rotation); 298 scale (matrix, trans, scaleX, scaleY); 299 skew (matrix, trans, -skewX, skewY); 300 translate (matrix, trans, -tCenterX, -tCenterY); 301 } 302 set_variationsOT::glyf_impl::VarCompositeGlyphRecord303 void set_variations (coord_setter_t &setter, 304 hb_array_t<contour_point_t> rec_points) const 305 { 306 bool have_variations = flags & AXES_HAVE_VARIATION; 307 unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1; 308 309 const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2)); 310 const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2)); 311 312 const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes))); 313 314 unsigned count = numAxes; 315 for (unsigned i = 0; i < count; i++) 316 { 317 unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++; 318 319 signed v = have_variations ? rec_points[i].x : *a++; 320 321 v += setter[axis_index]; 322 v = hb_clamp (v, -(1<<14), (1<<14)); 323 setter[axis_index] = v; 324 } 325 } 326 327 protected: 328 HBUINT16 flags; 329 HBUINT8 numAxes; 330 public: 331 DEFINE_SIZE_MIN (3); 332 }; 333 334 using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>; 335 336 struct VarCompositeGlyph 337 { 338 const GlyphHeader &header; 339 hb_bytes_t bytes; VarCompositeGlyphOT::glyf_impl::VarCompositeGlyph340 VarCompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : 341 header (header_), bytes (bytes_) {} 342 iterOT::glyf_impl::VarCompositeGlyph343 var_composite_iter_t iter () const 344 { return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); } 345 346 }; 347 348 349 } /* namespace glyf_impl */ 350 } /* namespace OT */ 351 352 353 #endif /* OT_GLYF_VARCOMPOSITEGLYPH_HH */ 354