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<VariationStore> 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 float from_coord = 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 (from_coord, unmapped_range, triple_distances); 104 to_coord = renormalizeValue (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{unmapped_min, unmapped_middle, 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 (std::move (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 (version.major == 1 277 #ifndef HB_NO_AVAR2 278 || version.major == 2 279 #endif 280 ) && 281 c->check_struct (this))) 282 return_trace (false); 283 284 const SegmentMaps *map = &firstAxisSegmentMaps; 285 unsigned int count = axisCount; 286 for (unsigned int i = 0; i < count; i++) 287 { 288 if (unlikely (!map->sanitize (c))) 289 return_trace (false); 290 map = &StructAfter<SegmentMaps> (*map); 291 } 292 293 #ifndef HB_NO_AVAR2 294 if (version.major < 2) 295 return_trace (true); 296 297 const auto &v2 = * (const avarV2Tail *) map; 298 if (unlikely (!v2.sanitize (c, this))) 299 return_trace (false); 300 #endif 301 302 return_trace (true); 303 } 304 map_coordsOT::avar305 void map_coords (int *coords, unsigned int coords_length) const 306 { 307 unsigned int count = hb_min (coords_length, axisCount); 308 309 const SegmentMaps *map = &firstAxisSegmentMaps; 310 for (unsigned int i = 0; i < count; i++) 311 { 312 coords[i] = map->map (coords[i]); 313 map = &StructAfter<SegmentMaps> (*map); 314 } 315 316 #ifndef HB_NO_AVAR2 317 if (version.major < 2) 318 return; 319 320 for (; count < axisCount; count++) 321 map = &StructAfter<SegmentMaps> (*map); 322 323 const auto &v2 = * (const avarV2Tail *) map; 324 325 const auto &varidx_map = this+v2.varIdxMap; 326 const auto &var_store = this+v2.varStore; 327 auto *var_store_cache = var_store.create_cache (); 328 329 hb_vector_t<int> out; 330 out.alloc (coords_length); 331 for (unsigned i = 0; i < coords_length; i++) 332 { 333 int v = coords[i]; 334 uint32_t varidx = varidx_map.map (i); 335 float delta = var_store.get_delta (varidx, coords, coords_length, var_store_cache); 336 v += roundf (delta); 337 v = hb_clamp (v, -(1<<14), +(1<<14)); 338 out.push (v); 339 } 340 for (unsigned i = 0; i < coords_length; i++) 341 coords[i] = out[i]; 342 343 OT::VariationStore::destroy_cache (var_store_cache); 344 #endif 345 } 346 unmap_coordsOT::avar347 void unmap_coords (int *coords, unsigned int coords_length) const 348 { 349 unsigned int count = hb_min (coords_length, axisCount); 350 351 const SegmentMaps *map = &firstAxisSegmentMaps; 352 for (unsigned int i = 0; i < count; i++) 353 { 354 coords[i] = map->unmap (coords[i]); 355 map = &StructAfter<SegmentMaps> (*map); 356 } 357 } 358 subsetOT::avar359 bool subset (hb_subset_context_t *c) const 360 { 361 TRACE_SUBSET (this); 362 unsigned retained_axis_count = c->plan->axes_index_map.get_population (); 363 if (!retained_axis_count) //all axes are pinned/dropped 364 return_trace (false); 365 366 avar *out = c->serializer->allocate_min<avar> (); 367 if (unlikely (!out)) return_trace (false); 368 369 out->version.major = 1; 370 out->version.minor = 0; 371 if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW)) 372 return_trace (false); 373 374 const hb_map_t& axes_index_map = c->plan->axes_index_map; 375 const SegmentMaps *map = &firstAxisSegmentMaps; 376 unsigned count = axisCount; 377 for (unsigned int i = 0; i < count; i++) 378 { 379 if (axes_index_map.has (i)) 380 { 381 hb_tag_t *axis_tag; 382 if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) 383 return_trace (false); 384 if (!map->subset (c, *axis_tag)) 385 return_trace (false); 386 } 387 map = &StructAfter<SegmentMaps> (*map); 388 } 389 return_trace (true); 390 } 391 392 protected: 393 FixedVersion<>version; /* Version of the avar table 394 * initially set to 0x00010000u */ 395 HBUINT16 reserved; /* This field is permanently reserved. Set to 0. */ 396 HBUINT16 axisCount; /* The number of variation axes in the font. This 397 * must be the same number as axisCount in the 398 * 'fvar' table. */ 399 SegmentMaps firstAxisSegmentMaps; 400 401 public: 402 DEFINE_SIZE_MIN (8); 403 }; 404 405 } /* namespace OT */ 406 407 408 #endif /* HB_OT_VAR_AVAR_TABLE_HH */ 409