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