1 /* 2 * Copyright © 2017 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #ifndef HB_OT_VAR_AVAR_TABLE_HH 28 #define HB_OT_VAR_AVAR_TABLE_HH 29 30 #include "hb-open-type.hh" 31 #include "hb-ot-var-common.hh" 32 33 34 /* 35 * avar -- Axis Variations 36 * https://docs.microsoft.com/en-us/typography/opentype/spec/avar 37 */ 38 39 #define HB_OT_TAG_avar HB_TAG('a','v','a','r') 40 41 42 namespace OT { 43 44 45 /* "Spec": https://github.com/be-fonts/boring-expansion-spec/issues/14 */ 46 struct avarV2Tail 47 { 48 friend struct avar; 49 sanitizeOT::avarV2Tail50 bool sanitize (hb_sanitize_context_t *c, 51 const void *base) const 52 { 53 TRACE_SANITIZE (this); 54 return_trace (varIdxMap.sanitize (c, base) && 55 varStore.sanitize (c, base)); 56 } 57 58 protected: 59 Offset32To<DeltaSetIndexMap> varIdxMap; /* Offset from the beginning of 'avar' table. */ 60 Offset32To<ItemVariationStore> varStore; /* Offset from the beginning of 'avar' table. */ 61 62 public: 63 DEFINE_SIZE_STATIC (8); 64 }; 65 66 67 struct AxisValueMap 68 { sanitizeOT::AxisValueMap69 bool sanitize (hb_sanitize_context_t *c) const 70 { 71 TRACE_SANITIZE (this); 72 return_trace (c->check_struct (this)); 73 } 74 set_mappingOT::AxisValueMap75 void set_mapping (float from_coord, float to_coord) 76 { 77 coords[0].set_float (from_coord); 78 coords[1].set_float (to_coord); 79 } 80 is_outside_axis_rangeOT::AxisValueMap81 bool is_outside_axis_range (const Triple& axis_range) const 82 { 83 double from_coord = (double) coords[0].to_float (); 84 return !axis_range.contains (from_coord); 85 } 86 must_includeOT::AxisValueMap87 bool must_include () const 88 { 89 float from_coord = coords[0].to_float (); 90 float to_coord = coords[1].to_float (); 91 return (from_coord == -1.f && to_coord == -1.f) || 92 (from_coord == 0.f && to_coord == 0.f) || 93 (from_coord == 1.f && to_coord == 1.f); 94 } 95 instantiateOT::AxisValueMap96 void instantiate (const Triple& axis_range, 97 const Triple& unmapped_range, 98 const TripleDistances& triple_distances) 99 { 100 float from_coord = coords[0].to_float (); 101 float to_coord = coords[1].to_float (); 102 103 from_coord = renormalizeValue ((double) from_coord, unmapped_range, triple_distances); 104 to_coord = renormalizeValue ((double) to_coord, axis_range, triple_distances); 105 106 coords[0].set_float (from_coord); 107 coords[1].set_float (to_coord); 108 } 109 cmpOT::AxisValueMap110 HB_INTERNAL static int cmp (const void *pa, const void *pb) 111 { 112 const AxisValueMap *a = (const AxisValueMap *) pa; 113 const AxisValueMap *b = (const AxisValueMap *) pb; 114 115 int a_from = a->coords[0].to_int (); 116 int b_from = b->coords[0].to_int (); 117 if (a_from != b_from) 118 return a_from - b_from; 119 120 /* this should never be reached. according to the spec, all of the axis 121 * value map records for a given axis must have different fromCoord values 122 * */ 123 int a_to = a->coords[1].to_int (); 124 int b_to = b->coords[1].to_int (); 125 return a_to - b_to; 126 } 127 serializeOT::AxisValueMap128 bool serialize (hb_serialize_context_t *c) const 129 { 130 TRACE_SERIALIZE (this); 131 return_trace (c->embed (this)); 132 } 133 134 public: 135 F2DOT14 coords[2]; 136 // F2DOT14 fromCoord; /* A normalized coordinate value obtained using 137 // * default normalization. */ 138 // F2DOT14 toCoord; /* The modified, normalized coordinate value. */ 139 140 public: 141 DEFINE_SIZE_STATIC (4); 142 }; 143 144 struct SegmentMaps : Array16Of<AxisValueMap> 145 { mapOT::SegmentMaps146 int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const 147 { 148 #define fromCoord coords[from_offset].to_int () 149 #define toCoord coords[to_offset].to_int () 150 /* The following special-cases are not part of OpenType, which requires 151 * that at least -1, 0, and +1 must be mapped. But we include these as 152 * part of a better error recovery scheme. */ 153 if (len < 2) 154 { 155 if (!len) 156 return value; 157 else /* len == 1*/ 158 return value - arrayZ[0].fromCoord + arrayZ[0].toCoord; 159 } 160 161 if (value <= arrayZ[0].fromCoord) 162 return value - arrayZ[0].fromCoord + arrayZ[0].toCoord; 163 164 unsigned int i; 165 unsigned int count = len - 1; 166 for (i = 1; i < count && value > arrayZ[i].fromCoord; i++) 167 ; 168 169 if (value >= arrayZ[i].fromCoord) 170 return value - arrayZ[i].fromCoord + arrayZ[i].toCoord; 171 172 if (unlikely (arrayZ[i-1].fromCoord == arrayZ[i].fromCoord)) 173 return arrayZ[i-1].toCoord; 174 175 int denom = arrayZ[i].fromCoord - arrayZ[i-1].fromCoord; 176 return roundf (arrayZ[i-1].toCoord + ((float) (arrayZ[i].toCoord - arrayZ[i-1].toCoord) * 177 (value - arrayZ[i-1].fromCoord)) / denom); 178 #undef toCoord 179 #undef fromCoord 180 } 181 unmapOT::SegmentMaps182 int unmap (int value) const { return map (value, 1, 0); } 183 unmap_axis_rangeOT::SegmentMaps184 Triple unmap_axis_range (const Triple& axis_range) const 185 { 186 F2DOT14 val, unmapped_val; 187 188 val.set_float (axis_range.minimum); 189 unmapped_val.set_int (unmap (val.to_int ())); 190 float unmapped_min = unmapped_val.to_float (); 191 192 val.set_float (axis_range.middle); 193 unmapped_val.set_int (unmap (val.to_int ())); 194 float unmapped_middle = unmapped_val.to_float (); 195 196 val.set_float (axis_range.maximum); 197 unmapped_val.set_int (unmap (val.to_int ())); 198 float unmapped_max = unmapped_val.to_float (); 199 200 return Triple{(double) unmapped_min, (double) unmapped_middle, (double) unmapped_max}; 201 } 202 subsetOT::SegmentMaps203 bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const 204 { 205 TRACE_SUBSET (this); 206 /* avar mapped normalized axis range*/ 207 Triple *axis_range; 208 if (!c->plan->axes_location.has (axis_tag, &axis_range)) 209 return c->serializer->embed (*this); 210 211 TripleDistances *axis_triple_distances; 212 if (!c->plan->axes_triple_distances.has (axis_tag, &axis_triple_distances)) 213 return_trace (false); 214 215 auto *out = c->serializer->start_embed (this); 216 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 217 218 Triple unmapped_range = unmap_axis_range (*axis_range); 219 220 /* create a vector of retained mappings and sort */ 221 hb_vector_t<AxisValueMap> value_mappings; 222 for (const auto& _ : as_array ()) 223 { 224 if (_.is_outside_axis_range (unmapped_range)) 225 continue; 226 AxisValueMap mapping; 227 mapping = _; 228 mapping.instantiate (*axis_range, unmapped_range, *axis_triple_distances); 229 /* (-1, -1), (0, 0), (1, 1) mappings will be added later, so avoid 230 * duplicates here */ 231 if (mapping.must_include ()) 232 continue; 233 value_mappings.push (mapping); 234 } 235 236 AxisValueMap m; 237 m.set_mapping (-1.f, -1.f); 238 value_mappings.push (m); 239 240 m.set_mapping (0.f, 0.f); 241 value_mappings.push (m); 242 243 m.set_mapping (1.f, 1.f); 244 value_mappings.push (m); 245 246 value_mappings.qsort (); 247 248 for (const auto& _ : value_mappings) 249 { 250 if (!_.serialize (c->serializer)) 251 return_trace (false); 252 } 253 return_trace (c->serializer->check_assign (out->len, value_mappings.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)); 254 } 255 256 public: 257 DEFINE_SIZE_ARRAY (2, *this); 258 }; 259 260 struct avar 261 { 262 static constexpr hb_tag_t tableTag = HB_OT_TAG_avar; 263 has_dataOT::avar264 bool has_data () const { return version.to_int (); } 265 get_segment_mapsOT::avar266 const SegmentMaps* get_segment_maps () const 267 { return &firstAxisSegmentMaps; } 268 get_axis_countOT::avar269 unsigned get_axis_count () const 270 { return axisCount; } 271 sanitizeOT::avar272 bool sanitize (hb_sanitize_context_t *c) const 273 { 274 TRACE_SANITIZE (this); 275 if (!(version.sanitize (c) && 276 hb_barrier () && 277 (version.major == 1 278 #ifndef HB_NO_AVAR2 279 || version.major == 2 280 #endif 281 ) && 282 c->check_struct (this))) 283 return_trace (false); 284 285 const SegmentMaps *map = &firstAxisSegmentMaps; 286 unsigned int count = axisCount; 287 for (unsigned int i = 0; i < count; i++) 288 { 289 if (unlikely (!map->sanitize (c))) 290 return_trace (false); 291 map = &StructAfter<SegmentMaps> (*map); 292 } 293 294 #ifndef HB_NO_AVAR2 295 if (version.major < 2) 296 return_trace (true); 297 hb_barrier (); 298 299 const auto &v2 = * (const avarV2Tail *) map; 300 if (unlikely (!v2.sanitize (c, this))) 301 return_trace (false); 302 #endif 303 304 return_trace (true); 305 } 306 map_coordsOT::avar307 void map_coords (int *coords, unsigned int coords_length) const 308 { 309 unsigned int count = hb_min (coords_length, axisCount); 310 311 const SegmentMaps *map = &firstAxisSegmentMaps; 312 for (unsigned int i = 0; i < count; i++) 313 { 314 coords[i] = map->map (coords[i]); 315 map = &StructAfter<SegmentMaps> (*map); 316 } 317 318 #ifndef HB_NO_AVAR2 319 if (version.major < 2) 320 return; 321 hb_barrier (); 322 323 for (; count < axisCount; count++) 324 map = &StructAfter<SegmentMaps> (*map); 325 326 const auto &v2 = * (const avarV2Tail *) map; 327 328 const auto &varidx_map = this+v2.varIdxMap; 329 const auto &var_store = this+v2.varStore; 330 auto *var_store_cache = var_store.create_cache (); 331 332 hb_vector_t<int> out; 333 out.alloc (coords_length); 334 for (unsigned i = 0; i < coords_length; i++) 335 { 336 int v = coords[i]; 337 uint32_t varidx = varidx_map.map (i); 338 float delta = var_store.get_delta (varidx, coords, coords_length, var_store_cache); 339 v += roundf (delta); 340 v = hb_clamp (v, -(1<<14), +(1<<14)); 341 out.push (v); 342 } 343 for (unsigned i = 0; i < coords_length; i++) 344 coords[i] = out[i]; 345 346 OT::ItemVariationStore::destroy_cache (var_store_cache); 347 #endif 348 } 349 unmap_coordsOT::avar350 void unmap_coords (int *coords, unsigned int coords_length) const 351 { 352 unsigned int count = hb_min (coords_length, axisCount); 353 354 const SegmentMaps *map = &firstAxisSegmentMaps; 355 for (unsigned int i = 0; i < count; i++) 356 { 357 coords[i] = map->unmap (coords[i]); 358 map = &StructAfter<SegmentMaps> (*map); 359 } 360 } 361 subsetOT::avar362 bool subset (hb_subset_context_t *c) const 363 { 364 TRACE_SUBSET (this); 365 unsigned retained_axis_count = c->plan->axes_index_map.get_population (); 366 if (!retained_axis_count) //all axes are pinned/dropped 367 return_trace (false); 368 369 avar *out = c->serializer->allocate_min<avar> (); 370 if (unlikely (!out)) return_trace (false); 371 372 out->version.major = 1; 373 out->version.minor = 0; 374 if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 375 return_trace (false); 376 377 const hb_map_t& axes_index_map = c->plan->axes_index_map; 378 const SegmentMaps *map = &firstAxisSegmentMaps; 379 unsigned count = axisCount; 380 for (unsigned int i = 0; i < count; i++) 381 { 382 if (axes_index_map.has (i)) 383 { 384 hb_tag_t *axis_tag; 385 if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) 386 return_trace (false); 387 if (!map->subset (c, *axis_tag)) 388 return_trace (false); 389 } 390 map = &StructAfter<SegmentMaps> (*map); 391 } 392 return_trace (true); 393 } 394 395 protected: 396 FixedVersion<>version; /* Version of the avar table 397 * initially set to 0x00010000u */ 398 HBUINT16 reserved; /* This field is permanently reserved. Set to 0. */ 399 HBUINT16 axisCount; /* The number of variation axes in the font. This 400 * must be the same number as axisCount in the 401 * 'fvar' table. */ 402 SegmentMaps firstAxisSegmentMaps; 403 404 public: 405 DEFINE_SIZE_MIN (8); 406 }; 407 408 } /* namespace OT */ 409 410 411 #endif /* HB_OT_VAR_AVAR_TABLE_HH */ 412