1 /* 2 * Copyright © 2011,2012 Google, Inc. 3 * Copyright © 2018 Ebrahim Byagowi 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Google Author(s): Behdad Esfahbod 26 */ 27 28 #ifndef HB_OT_OS2_TABLE_HH 29 #define HB_OT_OS2_TABLE_HH 30 31 #include "hb-open-type.hh" 32 #include "hb-ot-os2-unicode-ranges.hh" 33 #include "hb-ot-cmap-table.hh" 34 35 #include "hb-set.hh" 36 37 /* 38 * OS/2 and Windows Metrics 39 * https://docs.microsoft.com/en-us/typography/opentype/spec/os2 40 */ 41 #define HB_OT_TAG_OS2 HB_TAG('O','S','/','2') 42 43 44 namespace OT { 45 46 struct OS2V1Tail 47 { sanitizeOT::OS2V1Tail48 bool sanitize (hb_sanitize_context_t *c) const 49 { 50 TRACE_SANITIZE (this); 51 return_trace (c->check_struct (this)); 52 } 53 54 public: 55 HBUINT32 ulCodePageRange1; 56 HBUINT32 ulCodePageRange2; 57 public: 58 DEFINE_SIZE_STATIC (8); 59 }; 60 61 struct OS2V2Tail 62 { has_dataOT::OS2V2Tail63 bool has_data () const { return sxHeight || sCapHeight; } 64 operator ->OT::OS2V2Tail65 const OS2V2Tail * operator -> () const { return this; } 66 sanitizeOT::OS2V2Tail67 bool sanitize (hb_sanitize_context_t *c) const 68 { 69 TRACE_SANITIZE (this); 70 return_trace (c->check_struct (this)); 71 } 72 73 public: 74 HBINT16 sxHeight; 75 HBINT16 sCapHeight; 76 HBUINT16 usDefaultChar; 77 HBUINT16 usBreakChar; 78 HBUINT16 usMaxContext; 79 public: 80 DEFINE_SIZE_STATIC (10); 81 }; 82 83 struct OS2V5Tail 84 { get_optical_sizeOT::OS2V5Tail85 inline bool get_optical_size (unsigned int *lower, unsigned int *upper) const 86 { 87 unsigned int lower_optical_size = usLowerOpticalPointSize; 88 unsigned int upper_optical_size = usUpperOpticalPointSize; 89 90 /* Per https://docs.microsoft.com/en-us/typography/opentype/spec/os2#lps */ 91 if (lower_optical_size < upper_optical_size && 92 lower_optical_size >= 1 && lower_optical_size <= 0xFFFE && 93 upper_optical_size >= 2 && upper_optical_size <= 0xFFFF) 94 { 95 *lower = lower_optical_size; 96 *upper = upper_optical_size; 97 return true; 98 } 99 return false; 100 } 101 sanitizeOT::OS2V5Tail102 bool sanitize (hb_sanitize_context_t *c) const 103 { 104 TRACE_SANITIZE (this); 105 return_trace (c->check_struct (this)); 106 } 107 108 public: 109 HBUINT16 usLowerOpticalPointSize; 110 HBUINT16 usUpperOpticalPointSize; 111 public: 112 DEFINE_SIZE_STATIC (4); 113 }; 114 115 struct OS2 116 { 117 static constexpr hb_tag_t tableTag = HB_OT_TAG_OS2; 118 has_dataOT::OS2119 bool has_data () const { return usWeightClass || usWidthClass || usFirstCharIndex || usLastCharIndex; } 120 v1OT::OS2121 const OS2V1Tail &v1 () const { return version >= 1 ? v1X : Null (OS2V1Tail); } v2OT::OS2122 const OS2V2Tail &v2 () const { return version >= 2 ? v2X : Null (OS2V2Tail); } v5OT::OS2123 const OS2V5Tail &v5 () const { return version >= 5 ? v5X : Null (OS2V5Tail); } 124 125 enum selection_flag_t { 126 ITALIC = 1u<<0, 127 UNDERSCORE = 1u<<1, 128 NEGATIVE = 1u<<2, 129 OUTLINED = 1u<<3, 130 STRIKEOUT = 1u<<4, 131 BOLD = 1u<<5, 132 REGULAR = 1u<<6, 133 USE_TYPO_METRICS = 1u<<7, 134 WWS = 1u<<8, 135 OBLIQUE = 1u<<9 136 }; 137 is_italicOT::OS2138 bool is_italic () const { return fsSelection & ITALIC; } is_obliqueOT::OS2139 bool is_oblique () const { return fsSelection & OBLIQUE; } use_typo_metricsOT::OS2140 bool use_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; } 141 142 enum width_class_t { 143 FWIDTH_ULTRA_CONDENSED = 1, /* 50% */ 144 FWIDTH_EXTRA_CONDENSED = 2, /* 62.5% */ 145 FWIDTH_CONDENSED = 3, /* 75% */ 146 FWIDTH_SEMI_CONDENSED = 4, /* 87.5% */ 147 FWIDTH_NORMAL = 5, /* 100% */ 148 FWIDTH_SEMI_EXPANDED = 6, /* 112.5% */ 149 FWIDTH_EXPANDED = 7, /* 125% */ 150 FWIDTH_EXTRA_EXPANDED = 8, /* 150% */ 151 FWIDTH_ULTRA_EXPANDED = 9 /* 200% */ 152 }; 153 get_widthOT::OS2154 float get_width () const 155 { 156 switch (usWidthClass) { 157 case FWIDTH_ULTRA_CONDENSED:return 50.f; 158 case FWIDTH_EXTRA_CONDENSED:return 62.5f; 159 case FWIDTH_CONDENSED: return 75.f; 160 case FWIDTH_SEMI_CONDENSED: return 87.5f; 161 default: 162 case FWIDTH_NORMAL: return 100.f; 163 case FWIDTH_SEMI_EXPANDED: return 112.5f; 164 case FWIDTH_EXPANDED: return 125.f; 165 case FWIDTH_EXTRA_EXPANDED: return 150.f; 166 case FWIDTH_ULTRA_EXPANDED: return 200.f; 167 } 168 } 169 subsetOT::OS2170 bool subset (hb_subset_context_t *c) const 171 { 172 TRACE_SUBSET (this); 173 OS2 *os2_prime = c->serializer->embed (this); 174 if (unlikely (!os2_prime)) return_trace (false); 175 176 hb_set_t unicodes; 177 if (!c->plan->glyphs_requested->is_empty ()) 178 { 179 hb_map_t unicode_glyphid_map; 180 181 OT::cmap::accelerator_t cmap; 182 cmap.init (c->plan->source); 183 cmap.collect_mapping (&unicodes, &unicode_glyphid_map); 184 cmap.fini (); 185 186 if (c->plan->unicodes->is_empty ()) unicodes.clear (); 187 else hb_set_set (&unicodes, c->plan->unicodes); 188 189 + unicode_glyphid_map.iter () 190 | hb_filter (c->plan->glyphs_requested, hb_second) 191 | hb_map (hb_first) 192 | hb_sink (unicodes) 193 ; 194 } 195 /* when --gids option is not used, no need to do collect_mapping that is 196 * iterating all codepoints in each subtable, which is not efficient */ 197 uint16_t min_cp, max_cp; 198 find_min_and_max_codepoint (unicodes.is_empty () ? c->plan->unicodes : &unicodes, &min_cp, &max_cp); 199 os2_prime->usFirstCharIndex = min_cp; 200 os2_prime->usLastCharIndex = max_cp; 201 202 _update_unicode_ranges (unicodes.is_empty () ? c->plan->unicodes : &unicodes, os2_prime->ulUnicodeRange); 203 204 return_trace (true); 205 } 206 _update_unicode_rangesOT::OS2207 void _update_unicode_ranges (const hb_set_t *codepoints, 208 HBUINT32 ulUnicodeRange[4]) const 209 { 210 HBUINT32 newBits[4]; 211 for (unsigned int i = 0; i < 4; i++) 212 newBits[i] = 0; 213 214 hb_codepoint_t cp = HB_SET_VALUE_INVALID; 215 while (codepoints->next (&cp)) { 216 unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp); 217 if (bit < 128) 218 { 219 unsigned int block = bit / 32; 220 unsigned int bit_in_block = bit % 32; 221 unsigned int mask = 1 << bit_in_block; 222 newBits[block] = newBits[block] | mask; 223 } 224 if (cp >= 0x10000 && cp <= 0x110000) 225 { 226 /* the spec says that bit 57 ("Non Plane 0") implies that there's 227 at least one codepoint beyond the BMP; so I also include all 228 the non-BMP codepoints here */ 229 newBits[1] = newBits[1] | (1 << 25); 230 } 231 } 232 233 for (unsigned int i = 0; i < 4; i++) 234 ulUnicodeRange[i] = ulUnicodeRange[i] & newBits[i]; // set bits only if set in the original 235 } 236 find_min_and_max_codepointOT::OS2237 static void find_min_and_max_codepoint (const hb_set_t *codepoints, 238 uint16_t *min_cp, /* OUT */ 239 uint16_t *max_cp /* OUT */) 240 { 241 *min_cp = hb_min (0xFFFFu, codepoints->get_min ()); 242 *max_cp = hb_min (0xFFFFu, codepoints->get_max ()); 243 } 244 245 /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 */ 246 enum font_page_t 247 { 248 FONT_PAGE_HEBREW = 0xB100, /* Hebrew Windows 3.1 font page */ 249 FONT_PAGE_SIMP_ARABIC = 0xB200, /* Simplified Arabic Windows 3.1 font page */ 250 FONT_PAGE_TRAD_ARABIC = 0xB300, /* Traditional Arabic Windows 3.1 font page */ 251 FONT_PAGE_OEM_ARABIC = 0xB400, /* OEM Arabic Windows 3.1 font page */ 252 FONT_PAGE_SIMP_FARSI = 0xBA00, /* Simplified Farsi Windows 3.1 font page */ 253 FONT_PAGE_TRAD_FARSI = 0xBB00, /* Traditional Farsi Windows 3.1 font page */ 254 FONT_PAGE_THAI = 0xDE00 /* Thai Windows 3.1 font page */ 255 }; get_font_pageOT::OS2256 font_page_t get_font_page () const 257 { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); } 258 get_sizeOT::OS2259 unsigned get_size () const 260 { 261 unsigned result = min_size; 262 if (version >= 1) result += v1X.get_size (); 263 if (version >= 2) result += v2X.get_size (); 264 if (version >= 5) result += v5X.get_size (); 265 return result; 266 } 267 sanitizeOT::OS2268 bool sanitize (hb_sanitize_context_t *c) const 269 { 270 TRACE_SANITIZE (this); 271 if (unlikely (!c->check_struct (this))) return_trace (false); 272 if (unlikely (version >= 1 && !v1X.sanitize (c))) return_trace (false); 273 if (unlikely (version >= 2 && !v2X.sanitize (c))) return_trace (false); 274 if (unlikely (version >= 5 && !v5X.sanitize (c))) return_trace (false); 275 return_trace (true); 276 } 277 278 public: 279 HBUINT16 version; 280 HBINT16 xAvgCharWidth; 281 HBUINT16 usWeightClass; 282 HBUINT16 usWidthClass; 283 HBUINT16 fsType; 284 HBINT16 ySubscriptXSize; 285 HBINT16 ySubscriptYSize; 286 HBINT16 ySubscriptXOffset; 287 HBINT16 ySubscriptYOffset; 288 HBINT16 ySuperscriptXSize; 289 HBINT16 ySuperscriptYSize; 290 HBINT16 ySuperscriptXOffset; 291 HBINT16 ySuperscriptYOffset; 292 HBINT16 yStrikeoutSize; 293 HBINT16 yStrikeoutPosition; 294 HBINT16 sFamilyClass; 295 HBUINT8 panose[10]; 296 HBUINT32 ulUnicodeRange[4]; 297 Tag achVendID; 298 HBUINT16 fsSelection; 299 HBUINT16 usFirstCharIndex; 300 HBUINT16 usLastCharIndex; 301 HBINT16 sTypoAscender; 302 HBINT16 sTypoDescender; 303 HBINT16 sTypoLineGap; 304 HBUINT16 usWinAscent; 305 HBUINT16 usWinDescent; 306 OS2V1Tail v1X; 307 OS2V2Tail v2X; 308 OS2V5Tail v5X; 309 public: 310 DEFINE_SIZE_MIN (78); 311 }; 312 313 } /* namespace OT */ 314 315 316 #endif /* HB_OT_OS2_TABLE_HH */ 317