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-hhea-table.hh"
32 #include "hb-ot-var-hvar-table.hh"
33 #include "hb-ot-metrics.hh"
34 
35 /*
36  * hmtx -- Horizontal Metrics
37  * https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx
38  * vmtx -- Vertical Metrics
39  * https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx
40  */
41 #define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
42 #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
43 
44 
45 HB_INTERNAL int
46 _glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
47 
48 HB_INTERNAL unsigned
49 _glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
50 
51 
52 namespace OT {
53 
54 
55 struct LongMetric
56 {
57   UFWORD	advance; /* Advance width/height. */
58   FWORD		sb; /* Leading (left/top) side bearing. */
59   public:
60   DEFINE_SIZE_STATIC (4);
61 };
62 
63 
64 template <typename T, typename H>
65 struct hmtxvmtx
66 {
sanitizeOT::hmtxvmtx67   bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
68   {
69     TRACE_SANITIZE (this);
70     /* We don't check for anything specific here.  The users of the
71      * struct do all the hard work... */
72     return_trace (true);
73   }
74 
75 
subset_update_headerOT::hmtxvmtx76   bool subset_update_header (hb_subset_plan_t *plan,
77 			     unsigned int num_hmetrics) const
78   {
79     hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (plan->source, H::tableTag);
80     hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
81     hb_blob_destroy (src_blob);
82 
83     if (unlikely (!dest_blob)) {
84       return false;
85     }
86 
87     unsigned int length;
88     H *table = (H *) hb_blob_get_data (dest_blob, &length);
89     table->numberOfLongMetrics = num_hmetrics;
90 
91     bool result = plan->add_table (H::tableTag, dest_blob);
92     hb_blob_destroy (dest_blob);
93 
94     return result;
95   }
96 
97   template<typename Iterator,
98 	   hb_requires (hb_is_iterator (Iterator))>
serializeOT::hmtxvmtx99   void serialize (hb_serialize_context_t *c,
100 		  Iterator it,
101 		  unsigned num_advances)
102   {
103     unsigned idx = 0;
104     for (auto _ : it)
105     {
106       if (idx < num_advances)
107       {
108 	LongMetric lm;
109 	lm.advance = _.first;
110 	lm.sb = _.second;
111 	if (unlikely (!c->embed<LongMetric> (&lm))) return;
112       }
113       else
114       {
115 	FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
116 	if (unlikely (!sb)) return;
117 	*sb = _.second;
118       }
119       idx++;
120     }
121   }
122 
subsetOT::hmtxvmtx123   bool subset (hb_subset_context_t *c) const
124   {
125     TRACE_SUBSET (this);
126 
127     T *table_prime = c->serializer->start_embed <T> ();
128     if (unlikely (!table_prime)) return_trace (false);
129 
130     accelerator_t _mtx;
131     _mtx.init (c->plan->source);
132     unsigned num_advances = _mtx.num_advances_for_subset (c->plan);
133 
134     auto it =
135     + hb_range (c->plan->num_output_glyphs ())
136     | hb_map ([c, &_mtx] (unsigned _)
137 	      {
138 		hb_codepoint_t old_gid;
139 		if (!c->plan->old_gid_for_new_gid (_, &old_gid))
140 		  return hb_pair (0u, 0);
141 		return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid));
142 	      })
143     ;
144 
145     table_prime->serialize (c->serializer, it, num_advances);
146 
147     _mtx.fini ();
148 
149     if (unlikely (c->serializer->in_error ()))
150       return_trace (false);
151 
152     // Amend header num hmetrics
153     if (unlikely (!subset_update_header (c->plan, num_advances)))
154       return_trace (false);
155 
156     return_trace (true);
157   }
158 
159   struct accelerator_t
160   {
161     friend struct hmtxvmtx;
162 
initOT::hmtxvmtx::accelerator_t163     void init (hb_face_t *face,
164 	       unsigned int default_advance_ = 0)
165     {
166       default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
167 
168       num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics;
169 
170       table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
171 
172       /* Cap num_metrics() and num_advances() based on table length. */
173       unsigned int len = table.get_length ();
174       if (unlikely (num_advances * 4 > len))
175 	num_advances = len / 4;
176       num_metrics = num_advances + (len - 4 * num_advances) / 2;
177 
178       /* We MUST set num_metrics to zero if num_advances is zero.
179        * Our get_advance() depends on that. */
180       if (unlikely (!num_advances))
181       {
182 	num_metrics = num_advances = 0;
183 	table.destroy ();
184 	table = hb_blob_get_empty ();
185       }
186 
187       var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
188     }
189 
finiOT::hmtxvmtx::accelerator_t190     void fini ()
191     {
192       table.destroy ();
193       var_table.destroy ();
194     }
195 
get_side_bearingOT::hmtxvmtx::accelerator_t196     int get_side_bearing (hb_codepoint_t glyph) const
197     {
198       if (glyph < num_advances)
199 	return table->longMetricZ[glyph].sb;
200 
201       if (unlikely (glyph >= num_metrics))
202 	return 0;
203 
204       const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances];
205       return bearings[glyph - num_advances];
206     }
207 
get_side_bearingOT::hmtxvmtx::accelerator_t208     int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
209     {
210       int side_bearing = get_side_bearing (glyph);
211 
212 #ifndef HB_NO_VAR
213       if (unlikely (glyph >= num_metrics) || !font->num_coords)
214 	return side_bearing;
215 
216       if (var_table.get_length ())
217 	return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
218 
219       return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
220 #else
221       return side_bearing;
222 #endif
223     }
224 
get_advanceOT::hmtxvmtx::accelerator_t225     unsigned int get_advance (hb_codepoint_t glyph) const
226     {
227       if (unlikely (glyph >= num_metrics))
228       {
229 	/* If num_metrics is zero, it means we don't have the metrics table
230 	 * for this direction: return default advance.  Otherwise, it means that the
231 	 * glyph index is out of bound: return zero. */
232 	if (num_metrics)
233 	  return 0;
234 	else
235 	  return default_advance;
236       }
237 
238       return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
239     }
240 
get_advanceOT::hmtxvmtx::accelerator_t241     unsigned int get_advance (hb_codepoint_t  glyph,
242 			      hb_font_t      *font) const
243     {
244       unsigned int advance = get_advance (glyph);
245 
246 #ifndef HB_NO_VAR
247       if (unlikely (glyph >= num_metrics) || !font->num_coords)
248 	return advance;
249 
250       if (var_table.get_length ())
251 	return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?!
252 
253       return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
254 #else
255       return advance;
256 #endif
257     }
258 
num_advances_for_subsetOT::hmtxvmtx::accelerator_t259     unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const
260     {
261       unsigned int num_advances = plan->num_output_glyphs ();
262       unsigned int last_advance = _advance_for_new_gid (plan,
263 							num_advances - 1);
264       while (num_advances > 1 &&
265 	     last_advance == _advance_for_new_gid (plan,
266 						   num_advances - 2))
267       {
268 	num_advances--;
269       }
270 
271       return num_advances;
272     }
273 
274     private:
_advance_for_new_gidOT::hmtxvmtx::accelerator_t275     unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan,
276 				       hb_codepoint_t new_gid) const
277     {
278       hb_codepoint_t old_gid;
279       if (!plan->old_gid_for_new_gid (new_gid, &old_gid))
280 	return 0;
281 
282       return get_advance (old_gid);
283     }
284 
285     protected:
286     unsigned int num_metrics;
287     unsigned int num_advances;
288     unsigned int default_advance;
289 
290     private:
291     hb_blob_ptr_t<hmtxvmtx> table;
292     hb_blob_ptr_t<HVARVVAR> var_table;
293   };
294 
295   protected:
296   UnsizedArrayOf<LongMetric>
297 		longMetricZ;	/* Paired advance width and leading
298 				 * bearing values for each glyph. The
299 				 * value numOfHMetrics comes from
300 				 * the 'hhea' table. If the font is
301 				 * monospaced, only one entry need
302 				 * be in the array, but that entry is
303 				 * required. The last entry applies to
304 				 * all subsequent glyphs. */
305 /*UnsizedArrayOf<FWORD>	leadingBearingX;*/
306 				/* Here the advance is assumed
307 				 * to be the same as the advance
308 				 * for the last entry above. The
309 				 * number of entries in this array is
310 				 * derived from numGlyphs (from 'maxp'
311 				 * table) minus numberOfLongMetrics.
312 				 * This generally is used with a run
313 				 * of monospaced glyphs (e.g., Kanji
314 				 * fonts or Courier fonts). Only one
315 				 * run is allowed and it must be at
316 				 * the end. This allows a monospaced
317 				 * font to vary the side bearing
318 				 * values for each glyph. */
319   public:
320   DEFINE_SIZE_ARRAY (0, longMetricZ);
321 };
322 
323 struct hmtx : hmtxvmtx<hmtx, hhea> {
324   static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
325   static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
326   static constexpr bool is_horizontal = true;
327 };
328 struct vmtx : hmtxvmtx<vmtx, vhea> {
329   static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
330   static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
331   static constexpr bool is_horizontal = false;
332 };
333 
334 struct hmtx_accelerator_t : hmtx::accelerator_t {};
335 struct vmtx_accelerator_t : vmtx::accelerator_t {};
336 
337 } /* namespace OT */
338 
339 
340 #endif /* HB_OT_HMTX_TABLE_HH */
341