2 * Copyright © 2017 Google, Inc.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Google Author(s): Behdad Esfahbod
27 #ifndef HB_OT_VAR_AVAR_TABLE_HH
28 #define HB_OT_VAR_AVAR_TABLE_HH
30 #include "hb-open-type.hh"
31 #include "hb-ot-var-common.hh"
35 * avar -- Axis Variations
36 * https://docs.microsoft.com/en-us/typography/opentype/spec/avar
39 #define HB_OT_TAG_avar HB_TAG('a','v','a','r')
45 /* "Spec": https://github.com/be-fonts/boring-expansion-spec/issues/14 */
50 bool sanitize (hb_sanitize_context_t
*c
,
51 const void *base
) const
53 TRACE_SANITIZE (this);
54 return_trace (varIdxMap
.sanitize (c
, base
) &&
55 varStore
.sanitize (c
, base
));
59 Offset32To
<DeltaSetIndexMap
> varIdxMap
; /* Offset from the beginning of 'avar' table. */
60 Offset32To
<VariationStore
> varStore
; /* Offset from the beginning of 'avar' table. */
63 DEFINE_SIZE_STATIC (8);
69 bool sanitize (hb_sanitize_context_t
*c
) const
71 TRACE_SANITIZE (this);
72 return_trace (c
->check_struct (this));
75 void set_mapping (float from_coord
, float to_coord
)
77 coords
[0].set_float (from_coord
);
78 coords
[1].set_float (to_coord
);
81 bool is_outside_axis_range (const Triple
& axis_range
) const
83 float from_coord
= coords
[0].to_float ();
84 return !axis_range
.contains (from_coord
);
87 bool must_include () const
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
);
96 void instantiate (const Triple
& axis_range
,
97 const Triple
& unmapped_range
,
98 const TripleDistances
& triple_distances
)
100 float from_coord
= coords
[0].to_float ();
101 float to_coord
= coords
[1].to_float ();
103 from_coord
= renormalizeValue (from_coord
, unmapped_range
, triple_distances
);
104 to_coord
= renormalizeValue (to_coord
, axis_range
, triple_distances
);
106 coords
[0].set_float (from_coord
);
107 coords
[1].set_float (to_coord
);
110 HB_INTERNAL
static int cmp (const void *pa
, const void *pb
)
112 const AxisValueMap
*a
= (const AxisValueMap
*) pa
;
113 const AxisValueMap
*b
= (const AxisValueMap
*) pb
;
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
;
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
123 int a_to
= a
->coords
[1].to_int ();
124 int b_to
= b
->coords
[1].to_int ();
128 bool serialize (hb_serialize_context_t
*c
) const
130 TRACE_SERIALIZE (this);
131 return_trace (c
->embed (this));
136 // F2DOT14 fromCoord; /* A normalized coordinate value obtained using
137 // * default normalization. */
138 // F2DOT14 toCoord; /* The modified, normalized coordinate value. */
141 DEFINE_SIZE_STATIC (4);
144 struct SegmentMaps
: Array16Of
<AxisValueMap
>
146 int map (int value
, unsigned int from_offset
= 0, unsigned int to_offset
= 1) const
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. */
158 return value
- arrayZ
[0].fromCoord
+ arrayZ
[0].toCoord
;
161 if (value
<= arrayZ
[0].fromCoord
)
162 return value
- arrayZ
[0].fromCoord
+ arrayZ
[0].toCoord
;
165 unsigned int count
= len
- 1;
166 for (i
= 1; i
< count
&& value
> arrayZ
[i
].fromCoord
; i
++)
169 if (value
>= arrayZ
[i
].fromCoord
)
170 return value
- arrayZ
[i
].fromCoord
+ arrayZ
[i
].toCoord
;
172 if (unlikely (arrayZ
[i
-1].fromCoord
== arrayZ
[i
].fromCoord
))
173 return arrayZ
[i
-1].toCoord
;
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
);
182 int unmap (int value
) const { return map (value
, 1, 0); }
184 Triple
unmap_axis_range (const Triple
& axis_range
) const
186 F2DOT14 val
, unmapped_val
;
188 val
.set_float (axis_range
.minimum
);
189 unmapped_val
.set_int (unmap (val
.to_int ()));
190 float unmapped_min
= unmapped_val
.to_float ();
192 val
.set_float (axis_range
.middle
);
193 unmapped_val
.set_int (unmap (val
.to_int ()));
194 float unmapped_middle
= unmapped_val
.to_float ();
196 val
.set_float (axis_range
.maximum
);
197 unmapped_val
.set_int (unmap (val
.to_int ()));
198 float unmapped_max
= unmapped_val
.to_float ();
200 return Triple
{unmapped_min
, unmapped_middle
, unmapped_max
};
203 bool subset (hb_subset_context_t
*c
, hb_tag_t axis_tag
) const
206 /* avar mapped normalized axis range*/
208 if (!c
->plan
->axes_location
.has (axis_tag
, &axis_range
))
209 return c
->serializer
->embed (*this);
211 TripleDistances
*axis_triple_distances
;
212 if (!c
->plan
->axes_triple_distances
.has (axis_tag
, &axis_triple_distances
))
213 return_trace (false);
215 auto *out
= c
->serializer
->start_embed (this);
216 if (unlikely (!c
->serializer
->extend_min (out
))) return_trace (false);
218 Triple unmapped_range
= unmap_axis_range (*axis_range
);
220 /* create a vector of retained mappings and sort */
221 hb_vector_t
<AxisValueMap
> value_mappings
;
222 for (const auto& _
: as_array ())
224 if (_
.is_outside_axis_range (unmapped_range
))
226 AxisValueMap 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
231 if (mapping
.must_include ())
233 value_mappings
.push (std::move (mapping
));
237 m
.set_mapping (-1.f
, -1.f
);
238 value_mappings
.push (m
);
240 m
.set_mapping (0.f
, 0.f
);
241 value_mappings
.push (m
);
243 m
.set_mapping (1.f
, 1.f
);
244 value_mappings
.push (m
);
246 value_mappings
.qsort ();
248 for (const auto& _
: value_mappings
)
250 if (!_
.serialize (c
->serializer
))
251 return_trace (false);
253 return_trace (c
->serializer
->check_assign (out
->len
, value_mappings
.length
, HB_SERIALIZE_ERROR_INT_OVERFLOW
));
257 DEFINE_SIZE_ARRAY (2, *this);
262 static constexpr hb_tag_t tableTag
= HB_OT_TAG_avar
;
264 bool has_data () const { return version
.to_int (); }
266 const SegmentMaps
* get_segment_maps () const
267 { return &firstAxisSegmentMaps
; }
269 unsigned get_axis_count () const
270 { return axisCount
; }
272 bool sanitize (hb_sanitize_context_t
*c
) const
274 TRACE_SANITIZE (this);
275 if (!(version
.sanitize (c
) &&
279 || version
.major
== 2
282 c
->check_struct (this)))
283 return_trace (false);
285 const SegmentMaps
*map
= &firstAxisSegmentMaps
;
286 unsigned int count
= axisCount
;
287 for (unsigned int i
= 0; i
< count
; i
++)
289 if (unlikely (!map
->sanitize (c
)))
290 return_trace (false);
291 map
= &StructAfter
<SegmentMaps
> (*map
);
295 if (version
.major
< 2)
299 const auto &v2
= * (const avarV2Tail
*) map
;
300 if (unlikely (!v2
.sanitize (c
, this)))
301 return_trace (false);
307 void map_coords (int *coords
, unsigned int coords_length
) const
309 unsigned int count
= hb_min (coords_length
, axisCount
);
311 const SegmentMaps
*map
= &firstAxisSegmentMaps
;
312 for (unsigned int i
= 0; i
< count
; i
++)
314 coords
[i
] = map
->map (coords
[i
]);
315 map
= &StructAfter
<SegmentMaps
> (*map
);
319 if (version
.major
< 2)
323 for (; count
< axisCount
; count
++)
324 map
= &StructAfter
<SegmentMaps
> (*map
);
326 const auto &v2
= * (const avarV2Tail
*) map
;
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 ();
332 hb_vector_t
<int> out
;
333 out
.alloc (coords_length
);
334 for (unsigned i
= 0; i
< coords_length
; i
++)
337 uint32_t varidx
= varidx_map
.map (i
);
338 float delta
= var_store
.get_delta (varidx
, coords
, coords_length
, var_store_cache
);
340 v
= hb_clamp (v
, -(1<<14), +(1<<14));
343 for (unsigned i
= 0; i
< coords_length
; i
++)
346 OT::VariationStore::destroy_cache (var_store_cache
);
350 void unmap_coords (int *coords
, unsigned int coords_length
) const
352 unsigned int count
= hb_min (coords_length
, axisCount
);
354 const SegmentMaps
*map
= &firstAxisSegmentMaps
;
355 for (unsigned int i
= 0; i
< count
; i
++)
357 coords
[i
] = map
->unmap (coords
[i
]);
358 map
= &StructAfter
<SegmentMaps
> (*map
);
362 bool subset (hb_subset_context_t
*c
) const
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);
369 avar
*out
= c
->serializer
->allocate_min
<avar
> ();
370 if (unlikely (!out
)) return_trace (false);
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);
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
++)
382 if (axes_index_map
.has (i
))
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);
390 map
= &StructAfter
<SegmentMaps
> (*map
);
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
402 SegmentMaps firstAxisSegmentMaps
;
411 #endif /* HB_OT_VAR_AVAR_TABLE_HH */