xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-ot-hmtx-table.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 /*
2  * Copyright © 2011,2012  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, Roderick Sheeter
25  */
26 
27 #ifndef HB_OT_HMTX_TABLE_HH
28 #define HB_OT_HMTX_TABLE_HH
29 
30 #include "hb-open-type.hh"
31 #include "hb-ot-maxp-table.hh"
32 #include "hb-ot-hhea-table.hh"
33 #include "hb-ot-os2-table.hh"
34 #include "hb-ot-var-hvar-table.hh"
35 #include "hb-ot-var-mvar-table.hh"
36 #include "hb-ot-metrics.hh"
37 
38 /*
39  * hmtx -- Horizontal Metrics
40  * https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx
41  * vmtx -- Vertical Metrics
42  * https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx
43  */
44 #define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
45 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
46 
47 
48 HB_INTERNAL bool
49 _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, int *lsb);
50 
51 HB_INTERNAL unsigned
52 _glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
53 
54 HB_INTERNAL bool
55 _glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb);
56 
57 
58 namespace OT {
59 
60 
61 struct LongMetric
62 {
63   UFWORD	advance; /* Advance width/height. */
64   FWORD		sb; /* Leading (left/top) side bearing. */
65   public:
66   DEFINE_SIZE_STATIC (4);
67 };
68 
69 
70 template <typename T/*Data table type*/, typename H/*Header table type*/, typename V/*Var table type*/>
71 struct hmtxvmtx
72 {
sanitizeOT::hmtxvmtx73   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
74   {
75     TRACE_SANITIZE (this);
76     /* We don't check for anything specific here.  The users of the
77      * struct do all the hard work... */
78     return_trace (true);
79   }
80 
get_mtx_mapOT::hmtxvmtx81   const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>>* get_mtx_map (const hb_subset_plan_t *plan) const
82   { return T::is_horizontal ? &plan->hmtx_map : &plan->vmtx_map; }
83 
subset_update_headerOT::hmtxvmtx84   bool subset_update_header (hb_subset_context_t *c,
85 			     unsigned int num_hmetrics,
86 			     const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map,
87 			     const hb_vector_t<unsigned> &bounds_vec) const
88   {
89     hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (c->plan->source, H::tableTag);
90     hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
91     hb_blob_destroy (src_blob);
92 
93     if (unlikely (!dest_blob)) {
94       return false;
95     }
96 
97     unsigned int length;
98     H *table = (H *) hb_blob_get_data (dest_blob, &length);
99     c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW);
100 
101 #ifndef HB_NO_VAR
102     if (c->plan->normalized_coords)
103     {
104       auto &MVAR = *c->plan->source->table.MVAR;
105       if (T::is_horizontal)
106       {
107 	HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE,   caretSlopeRise);
108 	HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN,    caretSlopeRun);
109 	HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, caretOffset);
110       }
111       else
112       {
113 	HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RISE,     caretSlopeRise);
114 	HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RUN,      caretSlopeRun);
115 	HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET,   caretOffset);
116       }
117 
118       bool empty = true;
119       int min_lsb = 0x7FFF;
120       int min_rsb = 0x7FFF;
121       int max_extent = -0x7FFF;
122       unsigned max_adv = 0;
123       for (const auto _ : *mtx_map)
124       {
125         hb_codepoint_t gid = _.first;
126         unsigned adv = _.second.first;
127         int lsb = _.second.second;
128         max_adv = hb_max (max_adv, adv);
129 
130         if (bounds_vec[gid] != 0xFFFFFFFF)
131         {
132 	  empty = false;
133           unsigned bound_width = bounds_vec[gid];
134           int rsb = adv - lsb - bound_width;
135           int extent = lsb + bound_width;
136           min_lsb = hb_min (min_lsb, lsb);
137           min_rsb = hb_min (min_rsb, rsb);
138           max_extent = hb_max (max_extent, extent);
139         }
140       }
141 
142       table->advanceMax = max_adv;
143       if (!empty)
144       {
145         table->minLeadingBearing = min_lsb;
146         table->minTrailingBearing = min_rsb;
147         table->maxExtent = max_extent;
148       }
149 
150       if (T::is_horizontal)
151       {
152         const auto &OS2 = *c->plan->source->table.OS2;
153         if (OS2.has_data () &&
154             table->ascender == OS2.sTypoAscender &&
155             table->descender == OS2.sTypoDescender &&
156             table->lineGap == OS2.sTypoLineGap)
157         {
158           table->ascender = static_cast<int> (roundf (OS2.sTypoAscender +
159                                                       MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
160                                                                     c->plan->normalized_coords.arrayZ,
161                                                                     c->plan->normalized_coords.length)));
162           table->descender = static_cast<int> (roundf (OS2.sTypoDescender +
163                                                        MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,
164                                                                      c->plan->normalized_coords.arrayZ,
165                                                                      c->plan->normalized_coords.length)));
166           table->lineGap = static_cast<int> (roundf (OS2.sTypoLineGap +
167                                                      MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,
168                                                                    c->plan->normalized_coords.arrayZ,
169                                                                    c->plan->normalized_coords.length)));
170         }
171       }
172     }
173 #endif
174 
175     bool result = c->plan->add_table (H::tableTag, dest_blob);
176     hb_blob_destroy (dest_blob);
177 
178     return result;
179   }
180 
181   template<typename Iterator,
182 	   hb_requires (hb_is_iterator (Iterator))>
serializeOT::hmtxvmtx183   void serialize (hb_serialize_context_t *c,
184 		  Iterator it,
185 		  const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
186 		  unsigned num_long_metrics,
187                   unsigned total_num_metrics)
188   {
189     LongMetric* long_metrics = c->allocate_size<LongMetric> (num_long_metrics * LongMetric::static_size);
190     FWORD* short_metrics = c->allocate_size<FWORD> ((total_num_metrics - num_long_metrics) * FWORD::static_size);
191     if (!long_metrics || !short_metrics) return;
192 
193     short_metrics -= num_long_metrics;
194 
195     for (auto _ : new_to_old_gid_list)
196     {
197       hb_codepoint_t gid = _.first;
198       auto mtx = *it++;
199 
200       if (gid < num_long_metrics)
201       {
202 	LongMetric& lm = long_metrics[gid];
203 	lm.advance = mtx.first;
204 	lm.sb = mtx.second;
205       }
206       // TODO(beyond-64k): This assumes that maxp.numGlyphs is 0xFFFF.
207       else if (gid < 0x10000u)
208         short_metrics[gid] = mtx.second;
209       else
210         ((UFWORD*) short_metrics)[gid] = mtx.first;
211     }
212   }
213 
subsetOT::hmtxvmtx214   bool subset (hb_subset_context_t *c) const
215   {
216     TRACE_SUBSET (this);
217 
218     auto *table_prime = c->serializer->start_embed <T> ();
219 
220     accelerator_t _mtx (c->plan->source);
221     unsigned num_long_metrics;
222     const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map = get_mtx_map (c->plan);
223     {
224       /* Determine num_long_metrics to encode. */
225       auto& plan = c->plan;
226 
227       // TODO Don't consider retaingid holes here.
228 
229       num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu);
230       unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
231       while (num_long_metrics > 1 &&
232 	     last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
233       {
234 	num_long_metrics--;
235       }
236     }
237 
238     auto it =
239     + hb_iter (c->plan->new_to_old_gid_list)
240     | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _)
241 	      {
242 		hb_codepoint_t new_gid = _.first;
243 		hb_codepoint_t old_gid = _.second;
244 
245 		hb_pair_t<unsigned, int> *v = nullptr;
246 		if (!mtx_map->has (new_gid, &v))
247 		{
248 		  int lsb = 0;
249 		  if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
250 		    (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb);
251 		  return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
252 		}
253 		return *v;
254 	      })
255     ;
256 
257     table_prime->serialize (c->serializer,
258 			    it,
259 			    c->plan->new_to_old_gid_list,
260 			    num_long_metrics,
261 			    c->plan->num_output_glyphs ());
262 
263     if (unlikely (c->serializer->in_error ()))
264       return_trace (false);
265 
266     // Amend header num hmetrics
267     if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map,
268                                          T::is_horizontal ? c->plan->bounds_width_vec : c->plan->bounds_height_vec)))
269       return_trace (false);
270 
271     return_trace (true);
272   }
273 
274   struct accelerator_t
275   {
276     friend struct hmtxvmtx;
277 
accelerator_tOT::hmtxvmtx::accelerator_t278     accelerator_t (hb_face_t *face)
279     {
280       table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
281       var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag);
282 
283       default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
284 
285       /* Populate count variables and sort them out as we go */
286 
287       unsigned int len = table.get_length ();
288       if (len & 1)
289         len--;
290 
291       num_long_metrics = T::is_horizontal ?
292 			 face->table.hhea->numberOfLongMetrics :
293 #ifndef HB_NO_VERTICAL
294 			 face->table.vhea->numberOfLongMetrics
295 #else
296 			 0
297 #endif
298 			 ;
299       if (unlikely (num_long_metrics * 4 > len))
300 	num_long_metrics = len / 4;
301       len -= num_long_metrics * 4;
302 
303       num_bearings = face->table.maxp->get_num_glyphs ();
304 
305       if (unlikely (num_bearings < num_long_metrics))
306         num_bearings = num_long_metrics;
307       if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
308         num_bearings = num_long_metrics + len / 2;
309       len -= (num_bearings - num_long_metrics) * 2;
310 
311       /* We MUST set num_bearings to zero if num_long_metrics is zero.
312        * Our get_advance() depends on that. */
313       if (unlikely (!num_long_metrics))
314 	num_bearings = num_long_metrics = 0;
315 
316       num_advances = num_bearings + len / 2;
317       num_glyphs = face->get_num_glyphs ();
318       if (num_glyphs < num_advances)
319         num_glyphs = num_advances;
320     }
~accelerator_tOT::hmtxvmtx::accelerator_t321     ~accelerator_t ()
322     {
323       table.destroy ();
324       var_table.destroy ();
325     }
326 
has_dataOT::hmtxvmtx::accelerator_t327     bool has_data () const { return (bool) num_bearings; }
328 
get_leading_bearing_without_var_unscaledOT::hmtxvmtx::accelerator_t329     bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph,
330 						   int *lsb) const
331     {
332       if (glyph < num_long_metrics)
333       {
334 	*lsb = table->longMetricZ[glyph].sb;
335 	return true;
336       }
337 
338       if (unlikely (glyph >= num_bearings))
339 	return false;
340 
341       const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
342       *lsb = bearings[glyph - num_long_metrics];
343       return true;
344     }
345 
get_leading_bearing_with_var_unscaledOT::hmtxvmtx::accelerator_t346     bool get_leading_bearing_with_var_unscaled (hb_font_t *font,
347 						hb_codepoint_t glyph,
348 						int *lsb) const
349     {
350       if (!font->num_coords)
351 	return get_leading_bearing_without_var_unscaled (glyph, lsb);
352 
353 #ifndef HB_NO_VAR
354       float delta;
355       if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) &&
356 	  get_leading_bearing_without_var_unscaled (glyph, lsb))
357       {
358 	*lsb += roundf (delta);
359 	return true;
360       }
361 
362       return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb);
363 #else
364       return false;
365 #endif
366     }
367 
get_advance_without_var_unscaledOT::hmtxvmtx::accelerator_t368     unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const
369     {
370       /* OpenType case. */
371       if (glyph < num_bearings)
372 	return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
373 
374       /* If num_advances is zero, it means we don't have the metrics table
375        * for this direction: return default advance.  Otherwise, there's a
376        * well-defined answer. */
377       if (unlikely (!num_advances))
378 	return default_advance;
379 
380 #ifdef HB_NO_BEYOND_64K
381       return 0;
382 #endif
383 
384       if (unlikely (glyph >= num_glyphs))
385         return 0;
386 
387       /* num_bearings <= glyph < num_glyphs;
388        * num_bearings <= num_advances */
389 
390       if (num_bearings == num_advances)
391         return get_advance_without_var_unscaled (num_bearings - 1);
392 
393       const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
394       const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
395 
396       return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
397     }
398 
get_advance_with_var_unscaledOT::hmtxvmtx::accelerator_t399     unsigned get_advance_with_var_unscaled (hb_codepoint_t  glyph,
400 					    hb_font_t      *font,
401 					    ItemVariationStore::cache_t *store_cache = nullptr) const
402     {
403       unsigned int advance = get_advance_without_var_unscaled (glyph);
404 
405 #ifndef HB_NO_VAR
406       if (unlikely (glyph >= num_bearings) || !font->num_coords)
407 	return advance;
408 
409       if (var_table.get_length ())
410 	return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
411 									font->coords, font->num_coords,
412 									store_cache));
413 
414       unsigned glyf_advance = _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
415       return glyf_advance ? glyf_advance : advance;
416 #else
417       return advance;
418 #endif
419     }
420 
421     protected:
422     // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs
423     unsigned num_long_metrics;
424     unsigned num_bearings;
425     unsigned num_advances;
426     unsigned num_glyphs;
427 
428     unsigned int default_advance;
429 
430     public:
431     hb_blob_ptr_t<hmtxvmtx> table;
432     hb_blob_ptr_t<V> var_table;
433   };
434 
435   /* get advance: when no variations, call get_advance_without_var_unscaled.
436    * when there're variations, get advance value from mtx_map in subset_plan*/
get_new_gid_advance_unscaledOT::hmtxvmtx437   unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan,
438                                          const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map,
439                                          unsigned new_gid,
440                                          const accelerator_t &_mtx) const
441   {
442     if (mtx_map->is_empty ())
443     {
444       hb_codepoint_t old_gid = 0;
445       return plan->old_gid_for_new_gid (new_gid, &old_gid) ?
446              _mtx.get_advance_without_var_unscaled (old_gid) : 0;
447     }
448     return mtx_map->get (new_gid).first;
449   }
450 
451   protected:
452   UnsizedArrayOf<LongMetric>
453 		longMetricZ;	/* Paired advance width and leading
454 				 * bearing values for each glyph. The
455 				 * value numOfHMetrics comes from
456 				 * the 'hhea' table. If the font is
457 				 * monospaced, only one entry need
458 				 * be in the array, but that entry is
459 				 * required. The last entry applies to
460 				 * all subsequent glyphs. */
461 /*UnsizedArrayOf<FWORD>	leadingBearingX;*/
462 				/* Here the advance is assumed
463 				 * to be the same as the advance
464 				 * for the last entry above. The
465 				 * number of entries in this array is
466 				 * derived from numGlyphs (from 'maxp'
467 				 * table) minus numberOfLongMetrics.
468 				 * This generally is used with a run
469 				 * of monospaced glyphs (e.g., Kanji
470 				 * fonts or Courier fonts). Only one
471 				 * run is allowed and it must be at
472 				 * the end. This allows a monospaced
473 				 * font to vary the side bearing
474 				 * values for each glyph. */
475 /*UnsizedArrayOf<UFWORD>advancesX;*/
476 				/* TODO Document. */
477   public:
478   DEFINE_SIZE_ARRAY (0, longMetricZ);
479 };
480 
481 struct hmtx : hmtxvmtx<hmtx, hhea, HVAR> {
482   static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
483   static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
484   static constexpr bool is_horizontal = true;
485 };
486 struct vmtx : hmtxvmtx<vmtx, vhea, VVAR> {
487   static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
488   static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
489   static constexpr bool is_horizontal = false;
490 };
491 
492 struct hmtx_accelerator_t : hmtx::accelerator_t {
hmtx_accelerator_tOT::hmtx_accelerator_t493   hmtx_accelerator_t (hb_face_t *face) : hmtx::accelerator_t (face) {}
494 };
495 struct vmtx_accelerator_t : vmtx::accelerator_t {
vmtx_accelerator_tOT::vmtx_accelerator_t496   vmtx_accelerator_t (hb_face_t *face) : vmtx::accelerator_t (face) {}
497 };
498 
499 } /* namespace OT */
500 
501 
502 #endif /* HB_OT_HMTX_TABLE_HH */
503