xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-ot-os2-table.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2011,2012  Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2018  Ebrahim Byagowi
4*2d1272b8SAndroid Build Coastguard Worker  *
5*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
6*2d1272b8SAndroid Build Coastguard Worker  *
7*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
8*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
9*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
10*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
11*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
12*2d1272b8SAndroid Build Coastguard Worker  *
13*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
18*2d1272b8SAndroid Build Coastguard Worker  *
19*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24*2d1272b8SAndroid Build Coastguard Worker  *
25*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
26*2d1272b8SAndroid Build Coastguard Worker  */
27*2d1272b8SAndroid Build Coastguard Worker 
28*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_OT_OS2_TABLE_HH
29*2d1272b8SAndroid Build Coastguard Worker #define HB_OT_OS2_TABLE_HH
30*2d1272b8SAndroid Build Coastguard Worker 
31*2d1272b8SAndroid Build Coastguard Worker #include "hb-open-type.hh"
32*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-os2-unicode-ranges.hh"
33*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-var-mvar-table.hh"
34*2d1272b8SAndroid Build Coastguard Worker 
35*2d1272b8SAndroid Build Coastguard Worker #include "hb-set.hh"
36*2d1272b8SAndroid Build Coastguard Worker 
37*2d1272b8SAndroid Build Coastguard Worker /*
38*2d1272b8SAndroid Build Coastguard Worker  * OS/2 and Windows Metrics
39*2d1272b8SAndroid Build Coastguard Worker  * https://docs.microsoft.com/en-us/typography/opentype/spec/os2
40*2d1272b8SAndroid Build Coastguard Worker  */
41*2d1272b8SAndroid Build Coastguard Worker #define HB_OT_TAG_OS2 HB_TAG('O','S','/','2')
42*2d1272b8SAndroid Build Coastguard Worker 
43*2d1272b8SAndroid Build Coastguard Worker 
44*2d1272b8SAndroid Build Coastguard Worker namespace OT {
45*2d1272b8SAndroid Build Coastguard Worker 
46*2d1272b8SAndroid Build Coastguard Worker struct OS2V1Tail
47*2d1272b8SAndroid Build Coastguard Worker {
sanitizeOT::OS2V1Tail48*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
49*2d1272b8SAndroid Build Coastguard Worker   {
50*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
51*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
52*2d1272b8SAndroid Build Coastguard Worker   }
53*2d1272b8SAndroid Build Coastguard Worker 
54*2d1272b8SAndroid Build Coastguard Worker   public:
55*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	ulCodePageRange1;
56*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	ulCodePageRange2;
57*2d1272b8SAndroid Build Coastguard Worker   public:
58*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (8);
59*2d1272b8SAndroid Build Coastguard Worker };
60*2d1272b8SAndroid Build Coastguard Worker 
61*2d1272b8SAndroid Build Coastguard Worker struct OS2V2Tail
62*2d1272b8SAndroid Build Coastguard Worker {
has_dataOT::OS2V2Tail63*2d1272b8SAndroid Build Coastguard Worker   bool has_data () const { return sxHeight || sCapHeight; }
64*2d1272b8SAndroid Build Coastguard Worker 
operator ->OT::OS2V2Tail65*2d1272b8SAndroid Build Coastguard Worker   const OS2V2Tail * operator -> () const { return this; }
operator ->OT::OS2V2Tail66*2d1272b8SAndroid Build Coastguard Worker   OS2V2Tail * operator -> () { return this; }
67*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::OS2V2Tail68*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
69*2d1272b8SAndroid Build Coastguard Worker   {
70*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
71*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
72*2d1272b8SAndroid Build Coastguard Worker   }
73*2d1272b8SAndroid Build Coastguard Worker 
74*2d1272b8SAndroid Build Coastguard Worker   public:
75*2d1272b8SAndroid Build Coastguard Worker   HBINT16	sxHeight;
76*2d1272b8SAndroid Build Coastguard Worker   HBINT16	sCapHeight;
77*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usDefaultChar;
78*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usBreakChar;
79*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usMaxContext;
80*2d1272b8SAndroid Build Coastguard Worker   public:
81*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (10);
82*2d1272b8SAndroid Build Coastguard Worker };
83*2d1272b8SAndroid Build Coastguard Worker 
84*2d1272b8SAndroid Build Coastguard Worker struct OS2V5Tail
85*2d1272b8SAndroid Build Coastguard Worker {
get_optical_sizeOT::OS2V5Tail86*2d1272b8SAndroid Build Coastguard Worker   inline bool get_optical_size (unsigned int *lower, unsigned int *upper) const
87*2d1272b8SAndroid Build Coastguard Worker   {
88*2d1272b8SAndroid Build Coastguard Worker     unsigned int lower_optical_size = usLowerOpticalPointSize;
89*2d1272b8SAndroid Build Coastguard Worker     unsigned int upper_optical_size = usUpperOpticalPointSize;
90*2d1272b8SAndroid Build Coastguard Worker 
91*2d1272b8SAndroid Build Coastguard Worker     /* Per https://docs.microsoft.com/en-us/typography/opentype/spec/os2#lps */
92*2d1272b8SAndroid Build Coastguard Worker     if (lower_optical_size < upper_optical_size &&
93*2d1272b8SAndroid Build Coastguard Worker 	lower_optical_size >= 1 && lower_optical_size <= 0xFFFE &&
94*2d1272b8SAndroid Build Coastguard Worker 	upper_optical_size >= 2 && upper_optical_size <= 0xFFFF)
95*2d1272b8SAndroid Build Coastguard Worker     {
96*2d1272b8SAndroid Build Coastguard Worker       *lower = lower_optical_size;
97*2d1272b8SAndroid Build Coastguard Worker       *upper = upper_optical_size;
98*2d1272b8SAndroid Build Coastguard Worker       return true;
99*2d1272b8SAndroid Build Coastguard Worker     }
100*2d1272b8SAndroid Build Coastguard Worker     return false;
101*2d1272b8SAndroid Build Coastguard Worker   }
102*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::OS2V5Tail103*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
104*2d1272b8SAndroid Build Coastguard Worker   {
105*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
106*2d1272b8SAndroid Build Coastguard Worker     return_trace (c->check_struct (this));
107*2d1272b8SAndroid Build Coastguard Worker   }
108*2d1272b8SAndroid Build Coastguard Worker 
109*2d1272b8SAndroid Build Coastguard Worker   public:
110*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usLowerOpticalPointSize;
111*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usUpperOpticalPointSize;
112*2d1272b8SAndroid Build Coastguard Worker   public:
113*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_STATIC (4);
114*2d1272b8SAndroid Build Coastguard Worker };
115*2d1272b8SAndroid Build Coastguard Worker 
116*2d1272b8SAndroid Build Coastguard Worker struct OS2
117*2d1272b8SAndroid Build Coastguard Worker {
118*2d1272b8SAndroid Build Coastguard Worker   static constexpr hb_tag_t tableTag = HB_OT_TAG_OS2;
119*2d1272b8SAndroid Build Coastguard Worker 
has_dataOT::OS2120*2d1272b8SAndroid Build Coastguard Worker   bool has_data () const { return usWeightClass || usWidthClass || usFirstCharIndex || usLastCharIndex; }
121*2d1272b8SAndroid Build Coastguard Worker 
v1OT::OS2122*2d1272b8SAndroid Build Coastguard Worker   const OS2V1Tail &v1 () const { return version >= 1 ? v1X : Null (OS2V1Tail); }
v2OT::OS2123*2d1272b8SAndroid Build Coastguard Worker   const OS2V2Tail &v2 () const { return version >= 2 ? v2X : Null (OS2V2Tail); }
v5OT::OS2124*2d1272b8SAndroid Build Coastguard Worker   const OS2V5Tail &v5 () const { return version >= 5 ? v5X : Null (OS2V5Tail); }
125*2d1272b8SAndroid Build Coastguard Worker 
126*2d1272b8SAndroid Build Coastguard Worker   enum selection_flag_t {
127*2d1272b8SAndroid Build Coastguard Worker     ITALIC		= 1u<<0,
128*2d1272b8SAndroid Build Coastguard Worker     UNDERSCORE		= 1u<<1,
129*2d1272b8SAndroid Build Coastguard Worker     NEGATIVE		= 1u<<2,
130*2d1272b8SAndroid Build Coastguard Worker     OUTLINED		= 1u<<3,
131*2d1272b8SAndroid Build Coastguard Worker     STRIKEOUT		= 1u<<4,
132*2d1272b8SAndroid Build Coastguard Worker     BOLD		= 1u<<5,
133*2d1272b8SAndroid Build Coastguard Worker     REGULAR		= 1u<<6,
134*2d1272b8SAndroid Build Coastguard Worker     USE_TYPO_METRICS	= 1u<<7,
135*2d1272b8SAndroid Build Coastguard Worker     WWS			= 1u<<8,
136*2d1272b8SAndroid Build Coastguard Worker     OBLIQUE		= 1u<<9
137*2d1272b8SAndroid Build Coastguard Worker   };
138*2d1272b8SAndroid Build Coastguard Worker 
is_italicOT::OS2139*2d1272b8SAndroid Build Coastguard Worker   bool        is_italic () const { return fsSelection & ITALIC; }
is_obliqueOT::OS2140*2d1272b8SAndroid Build Coastguard Worker   bool       is_oblique () const { return fsSelection & OBLIQUE; }
use_typo_metricsOT::OS2141*2d1272b8SAndroid Build Coastguard Worker   bool use_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; }
142*2d1272b8SAndroid Build Coastguard Worker 
143*2d1272b8SAndroid Build Coastguard Worker   enum width_class_t {
144*2d1272b8SAndroid Build Coastguard Worker     FWIDTH_ULTRA_CONDENSED	= 1, /* 50% */
145*2d1272b8SAndroid Build Coastguard Worker     FWIDTH_EXTRA_CONDENSED	= 2, /* 62.5% */
146*2d1272b8SAndroid Build Coastguard Worker     FWIDTH_CONDENSED		= 3, /* 75% */
147*2d1272b8SAndroid Build Coastguard Worker     FWIDTH_SEMI_CONDENSED	= 4, /* 87.5% */
148*2d1272b8SAndroid Build Coastguard Worker     FWIDTH_NORMAL		= 5, /* 100% */
149*2d1272b8SAndroid Build Coastguard Worker     FWIDTH_SEMI_EXPANDED	= 6, /* 112.5% */
150*2d1272b8SAndroid Build Coastguard Worker     FWIDTH_EXPANDED		= 7, /* 125% */
151*2d1272b8SAndroid Build Coastguard Worker     FWIDTH_EXTRA_EXPANDED	= 8, /* 150% */
152*2d1272b8SAndroid Build Coastguard Worker     FWIDTH_ULTRA_EXPANDED	= 9  /* 200% */
153*2d1272b8SAndroid Build Coastguard Worker   };
154*2d1272b8SAndroid Build Coastguard Worker 
get_widthOT::OS2155*2d1272b8SAndroid Build Coastguard Worker   float get_width () const
156*2d1272b8SAndroid Build Coastguard Worker   {
157*2d1272b8SAndroid Build Coastguard Worker     switch (usWidthClass) {
158*2d1272b8SAndroid Build Coastguard Worker     case FWIDTH_ULTRA_CONDENSED:return 50.f;
159*2d1272b8SAndroid Build Coastguard Worker     case FWIDTH_EXTRA_CONDENSED:return 62.5f;
160*2d1272b8SAndroid Build Coastguard Worker     case FWIDTH_CONDENSED:	return 75.f;
161*2d1272b8SAndroid Build Coastguard Worker     case FWIDTH_SEMI_CONDENSED:	return 87.5f;
162*2d1272b8SAndroid Build Coastguard Worker     default:
163*2d1272b8SAndroid Build Coastguard Worker     case FWIDTH_NORMAL:		return 100.f;
164*2d1272b8SAndroid Build Coastguard Worker     case FWIDTH_SEMI_EXPANDED:	return 112.5f;
165*2d1272b8SAndroid Build Coastguard Worker     case FWIDTH_EXPANDED:	return 125.f;
166*2d1272b8SAndroid Build Coastguard Worker     case FWIDTH_EXTRA_EXPANDED:	return 150.f;
167*2d1272b8SAndroid Build Coastguard Worker     case FWIDTH_ULTRA_EXPANDED:	return 200.f;
168*2d1272b8SAndroid Build Coastguard Worker     }
169*2d1272b8SAndroid Build Coastguard Worker   }
170*2d1272b8SAndroid Build Coastguard Worker 
map_wdth_to_widthclassOT::OS2171*2d1272b8SAndroid Build Coastguard Worker   float map_wdth_to_widthclass(float width) const
172*2d1272b8SAndroid Build Coastguard Worker   {
173*2d1272b8SAndroid Build Coastguard Worker     if (width < 50) return 1.0f;
174*2d1272b8SAndroid Build Coastguard Worker     if (width > 200) return 9.0f;
175*2d1272b8SAndroid Build Coastguard Worker 
176*2d1272b8SAndroid Build Coastguard Worker     float ratio = (width - 50) / 12.5f;
177*2d1272b8SAndroid Build Coastguard Worker     int a = (int) floorf (ratio);
178*2d1272b8SAndroid Build Coastguard Worker     int b = (int) ceilf (ratio);
179*2d1272b8SAndroid Build Coastguard Worker 
180*2d1272b8SAndroid Build Coastguard Worker     /* follow this maping:
181*2d1272b8SAndroid Build Coastguard Worker      * https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswidthclass
182*2d1272b8SAndroid Build Coastguard Worker      */
183*2d1272b8SAndroid Build Coastguard Worker     if (b <= 6) // 50-125
184*2d1272b8SAndroid Build Coastguard Worker     {
185*2d1272b8SAndroid Build Coastguard Worker       if (a == b) return a + 1.0f;
186*2d1272b8SAndroid Build Coastguard Worker     }
187*2d1272b8SAndroid Build Coastguard Worker     else if (b == 7) // no mapping for 137.5
188*2d1272b8SAndroid Build Coastguard Worker     {
189*2d1272b8SAndroid Build Coastguard Worker       a = 6;
190*2d1272b8SAndroid Build Coastguard Worker       b = 8;
191*2d1272b8SAndroid Build Coastguard Worker     }
192*2d1272b8SAndroid Build Coastguard Worker     else if (b == 8)
193*2d1272b8SAndroid Build Coastguard Worker     {
194*2d1272b8SAndroid Build Coastguard Worker       if (a == b) return 8.0f; // 150
195*2d1272b8SAndroid Build Coastguard Worker       a = 6;
196*2d1272b8SAndroid Build Coastguard Worker     }
197*2d1272b8SAndroid Build Coastguard Worker     else
198*2d1272b8SAndroid Build Coastguard Worker     {
199*2d1272b8SAndroid Build Coastguard Worker       if (a == b && a == 12) return 9.0f; //200
200*2d1272b8SAndroid Build Coastguard Worker       b = 12;
201*2d1272b8SAndroid Build Coastguard Worker       a = 8;
202*2d1272b8SAndroid Build Coastguard Worker     }
203*2d1272b8SAndroid Build Coastguard Worker 
204*2d1272b8SAndroid Build Coastguard Worker     float va = 50 + a * 12.5f;
205*2d1272b8SAndroid Build Coastguard Worker     float vb = 50 + b * 12.5f;
206*2d1272b8SAndroid Build Coastguard Worker 
207*2d1272b8SAndroid Build Coastguard Worker     float ret =  a + (width - va) / (vb - va);
208*2d1272b8SAndroid Build Coastguard Worker     if (a <= 6) ret += 1.0f;
209*2d1272b8SAndroid Build Coastguard Worker     return ret;
210*2d1272b8SAndroid Build Coastguard Worker   }
211*2d1272b8SAndroid Build Coastguard Worker 
calc_avg_char_widthOT::OS2212*2d1272b8SAndroid Build Coastguard Worker   static unsigned calc_avg_char_width (const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>>& hmtx_map)
213*2d1272b8SAndroid Build Coastguard Worker   {
214*2d1272b8SAndroid Build Coastguard Worker     unsigned num = 0;
215*2d1272b8SAndroid Build Coastguard Worker     unsigned total_width = 0;
216*2d1272b8SAndroid Build Coastguard Worker     for (const auto& _ : hmtx_map.values_ref ())
217*2d1272b8SAndroid Build Coastguard Worker     {
218*2d1272b8SAndroid Build Coastguard Worker       unsigned width = _.first;
219*2d1272b8SAndroid Build Coastguard Worker       if (width)
220*2d1272b8SAndroid Build Coastguard Worker       {
221*2d1272b8SAndroid Build Coastguard Worker         total_width += width;
222*2d1272b8SAndroid Build Coastguard Worker         num++;
223*2d1272b8SAndroid Build Coastguard Worker       }
224*2d1272b8SAndroid Build Coastguard Worker     }
225*2d1272b8SAndroid Build Coastguard Worker 
226*2d1272b8SAndroid Build Coastguard Worker     return num ? (unsigned) roundf ((double) total_width / (double) num) : 0;
227*2d1272b8SAndroid Build Coastguard Worker   }
228*2d1272b8SAndroid Build Coastguard Worker 
subsetOT::OS2229*2d1272b8SAndroid Build Coastguard Worker   bool subset (hb_subset_context_t *c) const
230*2d1272b8SAndroid Build Coastguard Worker   {
231*2d1272b8SAndroid Build Coastguard Worker     TRACE_SUBSET (this);
232*2d1272b8SAndroid Build Coastguard Worker     OS2 *os2_prime = c->serializer->embed (this);
233*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!os2_prime)) return_trace (false);
234*2d1272b8SAndroid Build Coastguard Worker 
235*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_VAR
236*2d1272b8SAndroid Build Coastguard Worker     if (c->plan->normalized_coords)
237*2d1272b8SAndroid Build Coastguard Worker     {
238*2d1272b8SAndroid Build Coastguard Worker       auto &MVAR = *c->plan->source->table.MVAR;
239*2d1272b8SAndroid Build Coastguard Worker       auto *table = os2_prime;
240*2d1272b8SAndroid Build Coastguard Worker 
241*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,         sTypoAscender);
242*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,        sTypoDescender);
243*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,         sTypoLineGap);
244*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT,  usWinAscent);
245*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT, usWinDescent);
246*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE,         ySubscriptXSize);
247*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE,         ySubscriptYSize);
248*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET,       ySubscriptXOffset);
249*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET,       ySubscriptYOffset);
250*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE,       ySuperscriptXSize);
251*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE,       ySuperscriptYSize);
252*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET,     ySuperscriptXOffset);
253*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET,     ySuperscriptYOffset);
254*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_STRIKEOUT_SIZE,              yStrikeoutSize);
255*2d1272b8SAndroid Build Coastguard Worker       HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_STRIKEOUT_OFFSET,            yStrikeoutPosition);
256*2d1272b8SAndroid Build Coastguard Worker 
257*2d1272b8SAndroid Build Coastguard Worker       if (os2_prime->version >= 2)
258*2d1272b8SAndroid Build Coastguard Worker       {
259*2d1272b8SAndroid Build Coastguard Worker         hb_barrier ();
260*2d1272b8SAndroid Build Coastguard Worker         auto *table = & const_cast<OS2V2Tail &> (os2_prime->v2 ());
261*2d1272b8SAndroid Build Coastguard Worker         HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_X_HEIGHT,                   sxHeight);
262*2d1272b8SAndroid Build Coastguard Worker         HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_CAP_HEIGHT,                 sCapHeight);
263*2d1272b8SAndroid Build Coastguard Worker       }
264*2d1272b8SAndroid Build Coastguard Worker 
265*2d1272b8SAndroid Build Coastguard Worker       unsigned avg_char_width = calc_avg_char_width (c->plan->hmtx_map);
266*2d1272b8SAndroid Build Coastguard Worker       if (!c->serializer->check_assign (os2_prime->xAvgCharWidth, avg_char_width,
267*2d1272b8SAndroid Build Coastguard Worker                                         HB_SERIALIZE_ERROR_INT_OVERFLOW))
268*2d1272b8SAndroid Build Coastguard Worker         return_trace (false);
269*2d1272b8SAndroid Build Coastguard Worker     }
270*2d1272b8SAndroid Build Coastguard Worker #endif
271*2d1272b8SAndroid Build Coastguard Worker 
272*2d1272b8SAndroid Build Coastguard Worker     Triple *axis_range;
273*2d1272b8SAndroid Build Coastguard Worker     if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t'), &axis_range))
274*2d1272b8SAndroid Build Coastguard Worker     {
275*2d1272b8SAndroid Build Coastguard Worker       unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0, 1000.0)));
276*2d1272b8SAndroid Build Coastguard Worker       if (os2_prime->usWeightClass != weight_class)
277*2d1272b8SAndroid Build Coastguard Worker         os2_prime->usWeightClass = weight_class;
278*2d1272b8SAndroid Build Coastguard Worker     }
279*2d1272b8SAndroid Build Coastguard Worker 
280*2d1272b8SAndroid Build Coastguard Worker     if (c->plan->user_axes_location.has (HB_TAG ('w','d','t','h'), &axis_range))
281*2d1272b8SAndroid Build Coastguard Worker     {
282*2d1272b8SAndroid Build Coastguard Worker       unsigned width_class = static_cast<unsigned> (roundf (map_wdth_to_widthclass (axis_range->middle)));
283*2d1272b8SAndroid Build Coastguard Worker       if (os2_prime->usWidthClass != width_class)
284*2d1272b8SAndroid Build Coastguard Worker         os2_prime->usWidthClass = width_class;
285*2d1272b8SAndroid Build Coastguard Worker     }
286*2d1272b8SAndroid Build Coastguard Worker 
287*2d1272b8SAndroid Build Coastguard Worker     os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
288*2d1272b8SAndroid Build Coastguard Worker     os2_prime->usLastCharIndex  = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
289*2d1272b8SAndroid Build Coastguard Worker 
290*2d1272b8SAndroid Build Coastguard Worker     if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
291*2d1272b8SAndroid Build Coastguard Worker       return_trace (true);
292*2d1272b8SAndroid Build Coastguard Worker 
293*2d1272b8SAndroid Build Coastguard Worker     _update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange);
294*2d1272b8SAndroid Build Coastguard Worker 
295*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
296*2d1272b8SAndroid Build Coastguard Worker   }
297*2d1272b8SAndroid Build Coastguard Worker 
_update_unicode_rangesOT::OS2298*2d1272b8SAndroid Build Coastguard Worker   void _update_unicode_ranges (const hb_set_t *codepoints,
299*2d1272b8SAndroid Build Coastguard Worker 			       HBUINT32 ulUnicodeRange[4]) const
300*2d1272b8SAndroid Build Coastguard Worker   {
301*2d1272b8SAndroid Build Coastguard Worker     HBUINT32 newBits[4];
302*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < 4; i++)
303*2d1272b8SAndroid Build Coastguard Worker       newBits[i] = 0;
304*2d1272b8SAndroid Build Coastguard Worker 
305*2d1272b8SAndroid Build Coastguard Worker     /* This block doesn't show up in profiles. If it ever did,
306*2d1272b8SAndroid Build Coastguard Worker      * we can rewrite it to iterate over OS/2 ranges and use
307*2d1272b8SAndroid Build Coastguard Worker      * set iteration to check if the range matches. */
308*2d1272b8SAndroid Build Coastguard Worker     for (auto cp : *codepoints)
309*2d1272b8SAndroid Build Coastguard Worker     {
310*2d1272b8SAndroid Build Coastguard Worker       unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp);
311*2d1272b8SAndroid Build Coastguard Worker       if (bit < 128)
312*2d1272b8SAndroid Build Coastguard Worker       {
313*2d1272b8SAndroid Build Coastguard Worker 	unsigned int block = bit / 32;
314*2d1272b8SAndroid Build Coastguard Worker 	unsigned int bit_in_block = bit % 32;
315*2d1272b8SAndroid Build Coastguard Worker 	unsigned int mask = 1 << bit_in_block;
316*2d1272b8SAndroid Build Coastguard Worker 	newBits[block] = newBits[block] | mask;
317*2d1272b8SAndroid Build Coastguard Worker       }
318*2d1272b8SAndroid Build Coastguard Worker       if (cp >= 0x10000 && cp <= 0x110000)
319*2d1272b8SAndroid Build Coastguard Worker       {
320*2d1272b8SAndroid Build Coastguard Worker 	/* the spec says that bit 57 ("Non Plane 0") implies that there's
321*2d1272b8SAndroid Build Coastguard Worker 	   at least one codepoint beyond the BMP; so I also include all
322*2d1272b8SAndroid Build Coastguard Worker 	   the non-BMP codepoints here */
323*2d1272b8SAndroid Build Coastguard Worker 	newBits[1] = newBits[1] | (1 << 25);
324*2d1272b8SAndroid Build Coastguard Worker       }
325*2d1272b8SAndroid Build Coastguard Worker     }
326*2d1272b8SAndroid Build Coastguard Worker 
327*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < 4; i++)
328*2d1272b8SAndroid Build Coastguard Worker       ulUnicodeRange[i] = ulUnicodeRange[i] & newBits[i]; // set bits only if set in the original
329*2d1272b8SAndroid Build Coastguard Worker   }
330*2d1272b8SAndroid Build Coastguard Worker 
331*2d1272b8SAndroid Build Coastguard Worker   /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681
332*2d1272b8SAndroid Build Coastguard Worker    * https://docs.microsoft.com/en-us/typography/legacy/legacy_arabic_fonts */
333*2d1272b8SAndroid Build Coastguard Worker   enum font_page_t
334*2d1272b8SAndroid Build Coastguard Worker   {
335*2d1272b8SAndroid Build Coastguard Worker     FONT_PAGE_NONE		= 0,
336*2d1272b8SAndroid Build Coastguard Worker     FONT_PAGE_HEBREW		= 0xB100, /* Hebrew Windows 3.1 font page */
337*2d1272b8SAndroid Build Coastguard Worker     FONT_PAGE_SIMP_ARABIC	= 0xB200, /* Simplified Arabic Windows 3.1 font page */
338*2d1272b8SAndroid Build Coastguard Worker     FONT_PAGE_TRAD_ARABIC	= 0xB300, /* Traditional Arabic Windows 3.1 font page */
339*2d1272b8SAndroid Build Coastguard Worker     FONT_PAGE_OEM_ARABIC	= 0xB400, /* OEM Arabic Windows 3.1 font page */
340*2d1272b8SAndroid Build Coastguard Worker     FONT_PAGE_SIMP_FARSI	= 0xBA00, /* Simplified Farsi Windows 3.1 font page */
341*2d1272b8SAndroid Build Coastguard Worker     FONT_PAGE_TRAD_FARSI	= 0xBB00, /* Traditional Farsi Windows 3.1 font page */
342*2d1272b8SAndroid Build Coastguard Worker     FONT_PAGE_THAI		= 0xDE00  /* Thai Windows 3.1 font page */
343*2d1272b8SAndroid Build Coastguard Worker   };
get_font_pageOT::OS2344*2d1272b8SAndroid Build Coastguard Worker   font_page_t get_font_page () const
345*2d1272b8SAndroid Build Coastguard Worker   { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); }
346*2d1272b8SAndroid Build Coastguard Worker 
get_sizeOT::OS2347*2d1272b8SAndroid Build Coastguard Worker   unsigned get_size () const
348*2d1272b8SAndroid Build Coastguard Worker   {
349*2d1272b8SAndroid Build Coastguard Worker     unsigned result = min_size;
350*2d1272b8SAndroid Build Coastguard Worker     if (version >= 1) result += v1X.get_size ();
351*2d1272b8SAndroid Build Coastguard Worker     if (version >= 2) result += v2X.get_size ();
352*2d1272b8SAndroid Build Coastguard Worker     if (version >= 5) result += v5X.get_size ();
353*2d1272b8SAndroid Build Coastguard Worker     return result;
354*2d1272b8SAndroid Build Coastguard Worker   }
355*2d1272b8SAndroid Build Coastguard Worker 
sanitizeOT::OS2356*2d1272b8SAndroid Build Coastguard Worker   bool sanitize (hb_sanitize_context_t *c) const
357*2d1272b8SAndroid Build Coastguard Worker   {
358*2d1272b8SAndroid Build Coastguard Worker     TRACE_SANITIZE (this);
359*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (!c->check_struct (this))) return_trace (false);
360*2d1272b8SAndroid Build Coastguard Worker     hb_barrier ();
361*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (version >= 1 && !v1X.sanitize (c))) return_trace (false);
362*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (version >= 2 && !v2X.sanitize (c))) return_trace (false);
363*2d1272b8SAndroid Build Coastguard Worker     if (unlikely (version >= 5 && !v5X.sanitize (c))) return_trace (false);
364*2d1272b8SAndroid Build Coastguard Worker     return_trace (true);
365*2d1272b8SAndroid Build Coastguard Worker   }
366*2d1272b8SAndroid Build Coastguard Worker 
367*2d1272b8SAndroid Build Coastguard Worker   public:
368*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	version;
369*2d1272b8SAndroid Build Coastguard Worker   HBINT16	xAvgCharWidth;
370*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usWeightClass;
371*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usWidthClass;
372*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	fsType;
373*2d1272b8SAndroid Build Coastguard Worker   HBINT16	ySubscriptXSize;
374*2d1272b8SAndroid Build Coastguard Worker   HBINT16	ySubscriptYSize;
375*2d1272b8SAndroid Build Coastguard Worker   HBINT16	ySubscriptXOffset;
376*2d1272b8SAndroid Build Coastguard Worker   HBINT16	ySubscriptYOffset;
377*2d1272b8SAndroid Build Coastguard Worker   HBINT16	ySuperscriptXSize;
378*2d1272b8SAndroid Build Coastguard Worker   HBINT16	ySuperscriptYSize;
379*2d1272b8SAndroid Build Coastguard Worker   HBINT16	ySuperscriptXOffset;
380*2d1272b8SAndroid Build Coastguard Worker   HBINT16	ySuperscriptYOffset;
381*2d1272b8SAndroid Build Coastguard Worker   HBINT16	yStrikeoutSize;
382*2d1272b8SAndroid Build Coastguard Worker   HBINT16	yStrikeoutPosition;
383*2d1272b8SAndroid Build Coastguard Worker   HBINT16	sFamilyClass;
384*2d1272b8SAndroid Build Coastguard Worker   HBUINT8	panose[10];
385*2d1272b8SAndroid Build Coastguard Worker   HBUINT32	ulUnicodeRange[4];
386*2d1272b8SAndroid Build Coastguard Worker   Tag		achVendID;
387*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	fsSelection;
388*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usFirstCharIndex;
389*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usLastCharIndex;
390*2d1272b8SAndroid Build Coastguard Worker   HBINT16	sTypoAscender;
391*2d1272b8SAndroid Build Coastguard Worker   HBINT16	sTypoDescender;
392*2d1272b8SAndroid Build Coastguard Worker   HBINT16	sTypoLineGap;
393*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usWinAscent;
394*2d1272b8SAndroid Build Coastguard Worker   HBUINT16	usWinDescent;
395*2d1272b8SAndroid Build Coastguard Worker   OS2V1Tail	v1X;
396*2d1272b8SAndroid Build Coastguard Worker   OS2V2Tail	v2X;
397*2d1272b8SAndroid Build Coastguard Worker   OS2V5Tail	v5X;
398*2d1272b8SAndroid Build Coastguard Worker   public:
399*2d1272b8SAndroid Build Coastguard Worker   DEFINE_SIZE_MIN (78);
400*2d1272b8SAndroid Build Coastguard Worker };
401*2d1272b8SAndroid Build Coastguard Worker 
402*2d1272b8SAndroid Build Coastguard Worker } /* namespace OT */
403*2d1272b8SAndroid Build Coastguard Worker 
404*2d1272b8SAndroid Build Coastguard Worker 
405*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_OT_OS2_TABLE_HH */
406