Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright © 2011,2014 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, Roozbeh Pournader |
| 25 | */ |
| 26 | |
| 27 | #include "hb-private.hh" |
| 28 | |
| 29 | #include "hb-ot.h" |
| 30 | |
| 31 | #include "hb-font-private.hh" |
| 32 | |
Behdad Esfahbod | 41ca1fb | 2014-05-09 15:35:56 -0400 | [diff] [blame] | 33 | #include "hb-ot-cmap-table.hh" |
Behdad Esfahbod | efca7bf | 2016-12-02 15:11:37 -0800 | [diff] [blame] | 34 | #include "hb-ot-cbdt-table.hh" |
Behdad Esfahbod | b50fcfa | 2015-08-23 14:42:20 +0100 | [diff] [blame] | 35 | #include "hb-ot-glyf-table.hh" |
| 36 | #include "hb-ot-head-table.hh" |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 37 | #include "hb-ot-hhea-table.hh" |
| 38 | #include "hb-ot-hmtx-table.hh" |
Behdad Esfahbod | 2a16f64 | 2017-11-01 17:31:29 -0600 | [diff] [blame] | 39 | #include "hb-ot-kern-table.hh" |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 40 | #include "hb-ot-os2-table.hh" |
Khaled Hosny | 9d4d2fb | 2017-10-16 10:05:42 +0200 | [diff] [blame] | 41 | #include "hb-ot-post-table.hh" |
Behdad Esfahbod | b0e33da | 2017-10-31 20:05:37 -0600 | [diff] [blame] | 42 | #include "hb-ot-var-hvar-table.hh" |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 43 | |
| 44 | |
Behdad Esfahbod | d088cca | 2014-09-25 17:26:56 +0300 | [diff] [blame] | 45 | struct hb_ot_face_metrics_accelerator_t |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 46 | { |
| 47 | unsigned int num_metrics; |
| 48 | unsigned int num_advances; |
Behdad Esfahbod | d7c160a | 2014-09-25 17:15:35 +0300 | [diff] [blame] | 49 | unsigned int default_advance; |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 50 | unsigned short ascender; |
| 51 | unsigned short descender; |
| 52 | unsigned short line_gap; |
Behdad Esfahbod | b3b0816 | 2016-10-26 17:19:07 +0200 | [diff] [blame] | 53 | bool has_font_extents; |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 54 | |
Behdad Esfahbod | a11d9a0 | 2017-01-22 20:09:47 -0800 | [diff] [blame] | 55 | const OT::hmtxvmtx *table; |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 56 | hb_blob_t *blob; |
| 57 | |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 58 | const OT::HVARVVAR *var; |
| 59 | hb_blob_t *var_blob; |
| 60 | |
Behdad Esfahbod | d088cca | 2014-09-25 17:26:56 +0300 | [diff] [blame] | 61 | inline void init (hb_face_t *face, |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 62 | hb_tag_t _hea_tag, |
| 63 | hb_tag_t _mtx_tag, |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 64 | hb_tag_t _var_tag, |
Behdad Esfahbod | 63635c7 | 2016-10-26 17:54:04 +0200 | [diff] [blame] | 65 | hb_tag_t os2_tag, |
| 66 | unsigned int default_advance = 0) |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 67 | { |
Behdad Esfahbod | 63635c7 | 2016-10-26 17:54:04 +0200 | [diff] [blame] | 68 | this->default_advance = default_advance ? default_advance : face->get_upem (); |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 69 | |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 70 | bool got_font_extents = false; |
| 71 | if (os2_tag) |
| 72 | { |
| 73 | hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag)); |
| 74 | const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob); |
Behdad Esfahbod | 3ad1604 | 2015-12-10 16:37:49 +0100 | [diff] [blame] | 75 | #define USE_TYPO_METRICS (1u<<7) |
| 76 | if (0 != (os2->fsSelection & USE_TYPO_METRICS)) |
| 77 | { |
| 78 | this->ascender = os2->sTypoAscender; |
| 79 | this->descender = os2->sTypoDescender; |
| 80 | this->line_gap = os2->sTypoLineGap; |
| 81 | got_font_extents = (this->ascender | this->descender) != 0; |
| 82 | } |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 83 | hb_blob_destroy (os2_blob); |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 84 | } |
| 85 | |
Behdad Esfahbod | d088cca | 2014-09-25 17:26:56 +0300 | [diff] [blame] | 86 | hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag)); |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 87 | const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob); |
| 88 | this->num_advances = _hea->numberOfLongMetrics; |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 89 | if (!got_font_extents) |
| 90 | { |
| 91 | this->ascender = _hea->ascender; |
| 92 | this->descender = _hea->descender; |
| 93 | this->line_gap = _hea->lineGap; |
Behdad Esfahbod | b3b0816 | 2016-10-26 17:19:07 +0200 | [diff] [blame] | 94 | got_font_extents = (this->ascender | this->descender) != 0; |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 95 | } |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 96 | hb_blob_destroy (_hea_blob); |
| 97 | |
Behdad Esfahbod | b3b0816 | 2016-10-26 17:19:07 +0200 | [diff] [blame] | 98 | this->has_font_extents = got_font_extents; |
| 99 | |
Behdad Esfahbod | a11d9a0 | 2017-01-22 20:09:47 -0800 | [diff] [blame] | 100 | this->blob = OT::Sanitizer<OT::hmtxvmtx>::sanitize (face->reference_table (_mtx_tag)); |
Behdad Esfahbod | 67f8821 | 2015-11-02 15:37:29 -0800 | [diff] [blame] | 101 | |
| 102 | /* Cap num_metrics() and num_advances() based on table length. */ |
| 103 | unsigned int len = hb_blob_get_length (this->blob); |
Behdad Esfahbod | df698f3 | 2015-11-03 12:15:12 -0800 | [diff] [blame] | 104 | if (unlikely (this->num_advances * 4 > len)) |
Behdad Esfahbod | 67f8821 | 2015-11-02 15:37:29 -0800 | [diff] [blame] | 105 | this->num_advances = len / 4; |
| 106 | this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2; |
| 107 | |
Behdad Esfahbod | df698f3 | 2015-11-03 12:15:12 -0800 | [diff] [blame] | 108 | /* We MUST set num_metrics to zero if num_advances is zero. |
Behdad Esfahbod | 67f8821 | 2015-11-02 15:37:29 -0800 | [diff] [blame] | 109 | * Our get_advance() depends on that. */ |
| 110 | if (unlikely (!this->num_advances)) |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 111 | { |
Behdad Esfahbod | d7c160a | 2014-09-25 17:15:35 +0300 | [diff] [blame] | 112 | this->num_metrics = this->num_advances = 0; |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 113 | hb_blob_destroy (this->blob); |
| 114 | this->blob = hb_blob_get_empty (); |
| 115 | } |
Behdad Esfahbod | a11d9a0 | 2017-01-22 20:09:47 -0800 | [diff] [blame] | 116 | this->table = OT::Sanitizer<OT::hmtxvmtx>::lock_instance (this->blob); |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 117 | |
| 118 | this->var_blob = OT::Sanitizer<OT::HVARVVAR>::sanitize (face->reference_table (_var_tag)); |
| 119 | this->var = OT::Sanitizer<OT::HVARVVAR>::lock_instance (this->var_blob); |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 120 | } |
| 121 | |
| 122 | inline void fini (void) |
| 123 | { |
| 124 | hb_blob_destroy (this->blob); |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 125 | hb_blob_destroy (this->var_blob); |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 126 | } |
| 127 | |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 128 | inline unsigned int get_advance (hb_codepoint_t glyph, |
| 129 | hb_font_t *font) const |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 130 | { |
| 131 | if (unlikely (glyph >= this->num_metrics)) |
Behdad Esfahbod | d7c160a | 2014-09-25 17:15:35 +0300 | [diff] [blame] | 132 | { |
| 133 | /* If this->num_metrics is zero, it means we don't have the metrics table |
Behdad Esfahbod | b50fcfa | 2015-08-23 14:42:20 +0100 | [diff] [blame] | 134 | * for this direction: return default advance. Otherwise, it means that the |
| 135 | * glyph index is out of bound: return zero. */ |
Behdad Esfahbod | d7c160a | 2014-09-25 17:15:35 +0300 | [diff] [blame] | 136 | if (this->num_metrics) |
| 137 | return 0; |
| 138 | else |
| 139 | return this->default_advance; |
| 140 | } |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 141 | |
Ebrahim Byagowi | 3b0e47c | 2017-06-19 14:47:09 +0430 | [diff] [blame] | 142 | return this->table->longMetric[MIN (glyph, (uint32_t) this->num_advances - 1)].advance |
Behdad Esfahbod | 79e8e27 | 2017-01-23 17:55:31 -0800 | [diff] [blame] | 143 | + this->var->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?! |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 144 | } |
| 145 | }; |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 146 | |
Behdad Esfahbod | e0f16a7 | 2016-02-24 19:52:36 +0900 | [diff] [blame] | 147 | typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, |
| 148 | hb_codepoint_t codepoint, |
| 149 | hb_codepoint_t *glyph); |
| 150 | |
| 151 | template <typename Type> |
| 152 | static inline bool get_glyph_from (const void *obj, |
| 153 | hb_codepoint_t codepoint, |
| 154 | hb_codepoint_t *glyph) |
| 155 | { |
| 156 | const Type *typed_obj = (const Type *) obj; |
| 157 | return typed_obj->get_glyph (codepoint, glyph); |
| 158 | } |
| 159 | |
Behdad Esfahbod | 34f9aa5 | 2016-07-20 02:35:54 -0700 | [diff] [blame] | 160 | template <typename Type> |
| 161 | static inline bool get_glyph_from_symbol (const void *obj, |
| 162 | hb_codepoint_t codepoint, |
| 163 | hb_codepoint_t *glyph) |
| 164 | { |
| 165 | const Type *typed_obj = (const Type *) obj; |
| 166 | if (likely (typed_obj->get_glyph (codepoint, glyph))) |
| 167 | return true; |
| 168 | |
| 169 | if (codepoint <= 0x00FFu) |
| 170 | { |
| 171 | /* For symbol-encoded OpenType fonts, we duplicate the |
| 172 | * U+F000..F0FF range at U+0000..U+00FF. That's what |
| 173 | * Windows seems to do, and that's hinted about at: |
| 174 | * http://www.microsoft.com/typography/otspec/recom.htm |
| 175 | * under "Non-Standard (Symbol) Fonts". */ |
| 176 | return typed_obj->get_glyph (0xF000u + codepoint, glyph); |
| 177 | } |
| 178 | |
| 179 | return false; |
| 180 | } |
| 181 | |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 182 | struct hb_ot_face_cmap_accelerator_t |
| 183 | { |
Behdad Esfahbod | e0f16a7 | 2016-02-24 19:52:36 +0900 | [diff] [blame] | 184 | hb_cmap_get_glyph_func_t get_glyph_func; |
| 185 | const void *get_glyph_data; |
Behdad Esfahbod | 23335de | 2016-02-24 20:27:13 +0900 | [diff] [blame] | 186 | OT::CmapSubtableFormat4::accelerator_t format4_accel; |
Behdad Esfahbod | e0f16a7 | 2016-02-24 19:52:36 +0900 | [diff] [blame] | 187 | |
Behdad Esfahbod | 5473ebf | 2016-02-24 19:32:43 +0900 | [diff] [blame] | 188 | const OT::CmapSubtableFormat14 *uvs_table; |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 189 | hb_blob_t *blob; |
| 190 | |
| 191 | inline void init (hb_face_t *face) |
| 192 | { |
| 193 | this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap)); |
| 194 | const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob); |
Behdad Esfahbod | dbdbfe3 | 2017-10-15 12:11:08 +0200 | [diff] [blame] | 195 | const OT::CmapSubtable *subtable = nullptr; |
| 196 | const OT::CmapSubtableFormat14 *subtable_uvs = nullptr; |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 197 | |
Behdad Esfahbod | 34f9aa5 | 2016-07-20 02:35:54 -0700 | [diff] [blame] | 198 | bool symbol = false; |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 199 | /* 32-bit subtables. */ |
| 200 | if (!subtable) subtable = cmap->find_subtable (3, 10); |
| 201 | if (!subtable) subtable = cmap->find_subtable (0, 6); |
| 202 | if (!subtable) subtable = cmap->find_subtable (0, 4); |
| 203 | /* 16-bit subtables. */ |
| 204 | if (!subtable) subtable = cmap->find_subtable (3, 1); |
| 205 | if (!subtable) subtable = cmap->find_subtable (0, 3); |
| 206 | if (!subtable) subtable = cmap->find_subtable (0, 2); |
| 207 | if (!subtable) subtable = cmap->find_subtable (0, 1); |
| 208 | if (!subtable) subtable = cmap->find_subtable (0, 0); |
Volker H. Simonis | ad27388 | 2016-12-14 18:56:17 +0100 | [diff] [blame] | 209 | if (!subtable) |
| 210 | { |
| 211 | subtable = cmap->find_subtable (3, 0); |
| 212 | if (subtable) symbol = true; |
| 213 | } |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 214 | /* Meh. */ |
| 215 | if (!subtable) subtable = &OT::Null(OT::CmapSubtable); |
| 216 | |
| 217 | /* UVS subtable. */ |
Behdad Esfahbod | 5473ebf | 2016-02-24 19:32:43 +0900 | [diff] [blame] | 218 | if (!subtable_uvs) |
| 219 | { |
| 220 | const OT::CmapSubtable *st = cmap->find_subtable (0, 5); |
| 221 | if (st && st->u.format == 14) |
| 222 | subtable_uvs = &st->u.format14; |
| 223 | } |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 224 | /* Meh. */ |
Behdad Esfahbod | 5473ebf | 2016-02-24 19:32:43 +0900 | [diff] [blame] | 225 | if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14); |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 226 | |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 227 | this->uvs_table = subtable_uvs; |
Behdad Esfahbod | e0f16a7 | 2016-02-24 19:52:36 +0900 | [diff] [blame] | 228 | |
Behdad Esfahbod | e0f16a7 | 2016-02-24 19:52:36 +0900 | [diff] [blame] | 229 | this->get_glyph_data = subtable; |
Behdad Esfahbod | 34f9aa5 | 2016-07-20 02:35:54 -0700 | [diff] [blame] | 230 | if (unlikely (symbol)) |
| 231 | this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>; |
| 232 | else |
| 233 | switch (subtable->u.format) { |
| 234 | /* Accelerate format 4 and format 12. */ |
| 235 | default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>; break; |
| 236 | case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; break; |
| 237 | case 4: |
| 238 | { |
| 239 | this->format4_accel.init (&subtable->u.format4); |
| 240 | this->get_glyph_data = &this->format4_accel; |
| 241 | this->get_glyph_func = this->format4_accel.get_glyph_func; |
| 242 | } |
| 243 | break; |
Behdad Esfahbod | 23335de | 2016-02-24 20:27:13 +0900 | [diff] [blame] | 244 | } |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 245 | } |
| 246 | |
| 247 | inline void fini (void) |
| 248 | { |
| 249 | hb_blob_destroy (this->blob); |
| 250 | } |
| 251 | |
Behdad Esfahbod | 8b5bc14 | 2016-02-24 19:05:23 +0900 | [diff] [blame] | 252 | inline bool get_nominal_glyph (hb_codepoint_t unicode, |
| 253 | hb_codepoint_t *glyph) const |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 254 | { |
Behdad Esfahbod | e0f16a7 | 2016-02-24 19:52:36 +0900 | [diff] [blame] | 255 | return this->get_glyph_func (this->get_glyph_data, unicode, glyph); |
Behdad Esfahbod | 8b5bc14 | 2016-02-24 19:05:23 +0900 | [diff] [blame] | 256 | } |
| 257 | |
| 258 | inline bool get_variation_glyph (hb_codepoint_t unicode, |
| 259 | hb_codepoint_t variation_selector, |
| 260 | hb_codepoint_t *glyph) const |
| 261 | { |
| 262 | switch (this->uvs_table->get_glyph_variant (unicode, |
| 263 | variation_selector, |
| 264 | glyph)) |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 265 | { |
Behdad Esfahbod | 8b5bc14 | 2016-02-24 19:05:23 +0900 | [diff] [blame] | 266 | case OT::GLYPH_VARIANT_NOT_FOUND: return false; |
| 267 | case OT::GLYPH_VARIANT_FOUND: return true; |
| 268 | case OT::GLYPH_VARIANT_USE_DEFAULT: break; |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 269 | } |
| 270 | |
Behdad Esfahbod | 8b5bc14 | 2016-02-24 19:05:23 +0900 | [diff] [blame] | 271 | return get_nominal_glyph (unicode, glyph); |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 272 | } |
| 273 | }; |
| 274 | |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 275 | struct hb_ot_font_t |
| 276 | { |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 277 | hb_ot_face_cmap_accelerator_t cmap; |
Behdad Esfahbod | d088cca | 2014-09-25 17:26:56 +0300 | [diff] [blame] | 278 | hb_ot_face_metrics_accelerator_t h_metrics; |
| 279 | hb_ot_face_metrics_accelerator_t v_metrics; |
Behdad Esfahbod | 7e2839c | 2017-11-14 19:52:09 -0800 | [diff] [blame^] | 280 | OT::hb_lazy_loader_t<OT::glyf::accelerator_t> glyf; |
Behdad Esfahbod | c4e18e5 | 2017-11-14 19:47:31 -0800 | [diff] [blame] | 281 | OT::hb_lazy_loader_t<OT::CBDT::accelerator_t> cbdt; |
Behdad Esfahbod | 9b04b03 | 2017-11-14 19:31:50 -0800 | [diff] [blame] | 282 | OT::hb_lazy_loader_t<OT::post::accelerator_t> post; |
Behdad Esfahbod | 702d86b | 2017-11-14 19:25:38 -0800 | [diff] [blame] | 283 | OT::hb_lazy_loader_t<OT::kern::accelerator_t> kern; |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 284 | }; |
| 285 | |
| 286 | |
| 287 | static hb_ot_font_t * |
Behdad Esfahbod | 3224a59 | 2015-10-07 17:33:02 -0400 | [diff] [blame] | 288 | _hb_ot_font_create (hb_face_t *face) |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 289 | { |
| 290 | hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); |
| 291 | |
| 292 | if (unlikely (!ot_font)) |
Behdad Esfahbod | dbdbfe3 | 2017-10-15 12:11:08 +0200 | [diff] [blame] | 293 | return nullptr; |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 294 | |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 295 | ot_font->cmap.init (face); |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 296 | ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_HVAR, HB_OT_TAG_os2); |
| 297 | ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_OT_TAG_VVAR, HB_TAG_NONE, |
Behdad Esfahbod | 63635c7 | 2016-10-26 17:54:04 +0200 | [diff] [blame] | 298 | ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */ |
Behdad Esfahbod | b50fcfa | 2015-08-23 14:42:20 +0100 | [diff] [blame] | 299 | ot_font->glyf.init (face); |
Behdad Esfahbod | efca7bf | 2016-12-02 15:11:37 -0800 | [diff] [blame] | 300 | ot_font->cbdt.init (face); |
Khaled Hosny | 9d4d2fb | 2017-10-16 10:05:42 +0200 | [diff] [blame] | 301 | ot_font->post.init (face); |
Behdad Esfahbod | 77acc11 | 2017-11-01 19:33:09 -0600 | [diff] [blame] | 302 | ot_font->kern.init (face); |
Behdad Esfahbod | 3608a68 | 2014-05-12 13:46:29 -0400 | [diff] [blame] | 303 | |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 304 | return ot_font; |
| 305 | } |
| 306 | |
| 307 | static void |
Behdad Esfahbod | e1b6d92 | 2017-10-11 15:51:31 +0200 | [diff] [blame] | 308 | _hb_ot_font_destroy (void *data) |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 309 | { |
Behdad Esfahbod | e1b6d92 | 2017-10-11 15:51:31 +0200 | [diff] [blame] | 310 | hb_ot_font_t *ot_font = (hb_ot_font_t *) data; |
| 311 | |
Behdad Esfahbod | 1568529 | 2014-09-25 17:45:49 +0300 | [diff] [blame] | 312 | ot_font->cmap.fini (); |
Behdad Esfahbod | be1cca2 | 2014-09-25 16:53:24 +0300 | [diff] [blame] | 313 | ot_font->h_metrics.fini (); |
| 314 | ot_font->v_metrics.fini (); |
Behdad Esfahbod | ed13e2c | 2015-10-13 10:32:56 -0300 | [diff] [blame] | 315 | ot_font->glyf.fini (); |
Behdad Esfahbod | efca7bf | 2016-12-02 15:11:37 -0800 | [diff] [blame] | 316 | ot_font->cbdt.fini (); |
Khaled Hosny | 9d4d2fb | 2017-10-16 10:05:42 +0200 | [diff] [blame] | 317 | ot_font->post.fini (); |
Behdad Esfahbod | 77acc11 | 2017-11-01 19:33:09 -0600 | [diff] [blame] | 318 | ot_font->kern.fini (); |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 319 | |
| 320 | free (ot_font); |
| 321 | } |
| 322 | |
| 323 | |
| 324 | static hb_bool_t |
Behdad Esfahbod | 8b5bc14 | 2016-02-24 19:05:23 +0900 | [diff] [blame] | 325 | hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, |
| 326 | void *font_data, |
| 327 | hb_codepoint_t unicode, |
| 328 | hb_codepoint_t *glyph, |
| 329 | void *user_data HB_UNUSED) |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 330 | |
| 331 | { |
Behdad Esfahbod | 3608a68 | 2014-05-12 13:46:29 -0400 | [diff] [blame] | 332 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
Behdad Esfahbod | 8b5bc14 | 2016-02-24 19:05:23 +0900 | [diff] [blame] | 333 | return ot_font->cmap.get_nominal_glyph (unicode, glyph); |
| 334 | } |
| 335 | |
| 336 | static hb_bool_t |
| 337 | hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, |
| 338 | void *font_data, |
| 339 | hb_codepoint_t unicode, |
| 340 | hb_codepoint_t variation_selector, |
| 341 | hb_codepoint_t *glyph, |
| 342 | void *user_data HB_UNUSED) |
| 343 | { |
| 344 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
| 345 | return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph); |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 346 | } |
| 347 | |
| 348 | static hb_position_t |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 349 | hb_ot_get_glyph_h_advance (hb_font_t *font, |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 350 | void *font_data, |
| 351 | hb_codepoint_t glyph, |
| 352 | void *user_data HB_UNUSED) |
| 353 | { |
| 354 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 355 | return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font)); |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 356 | } |
| 357 | |
| 358 | static hb_position_t |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 359 | hb_ot_get_glyph_v_advance (hb_font_t *font, |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 360 | void *font_data, |
| 361 | hb_codepoint_t glyph, |
| 362 | void *user_data HB_UNUSED) |
| 363 | { |
Behdad Esfahbod | d41b809 | 2014-09-25 13:04:08 +0300 | [diff] [blame] | 364 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
Behdad Esfahbod | bd3b11d | 2017-01-23 17:34:44 -0800 | [diff] [blame] | 365 | return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font)); |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 366 | } |
| 367 | |
Behdad Esfahbod | 77acc11 | 2017-11-01 19:33:09 -0600 | [diff] [blame] | 368 | static hb_position_t |
| 369 | hb_ot_get_glyph_h_kerning (hb_font_t *font, |
| 370 | void *font_data, |
| 371 | hb_codepoint_t left_glyph, |
| 372 | hb_codepoint_t right_glyph, |
| 373 | void *user_data HB_UNUSED) |
| 374 | { |
| 375 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
| 376 | return font->em_scale_x (ot_font->kern->get_h_kerning (left_glyph, right_glyph)); |
| 377 | } |
| 378 | |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 379 | static hb_bool_t |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 380 | hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED, |
| 381 | void *font_data, |
| 382 | hb_codepoint_t glyph, |
| 383 | hb_glyph_extents_t *extents, |
| 384 | void *user_data HB_UNUSED) |
| 385 | { |
Behdad Esfahbod | b50fcfa | 2015-08-23 14:42:20 +0100 | [diff] [blame] | 386 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
Behdad Esfahbod | f00ab2a | 2016-05-02 10:24:00 +0200 | [diff] [blame] | 387 | bool ret = ot_font->glyf->get_extents (glyph, extents); |
Behdad Esfahbod | 4b58c9e | 2016-12-02 19:25:54 -0800 | [diff] [blame] | 388 | if (!ret) |
Behdad Esfahbod | efca7bf | 2016-12-02 15:11:37 -0800 | [diff] [blame] | 389 | ret = ot_font->cbdt->get_extents (glyph, extents); |
Behdad Esfahbod | 79e8e27 | 2017-01-23 17:55:31 -0800 | [diff] [blame] | 390 | // TODO Hook up side-bearings variations. |
Behdad Esfahbod | b50fcfa | 2015-08-23 14:42:20 +0100 | [diff] [blame] | 391 | extents->x_bearing = font->em_scale_x (extents->x_bearing); |
| 392 | extents->y_bearing = font->em_scale_y (extents->y_bearing); |
| 393 | extents->width = font->em_scale_x (extents->width); |
| 394 | extents->height = font->em_scale_y (extents->height); |
| 395 | return ret; |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 396 | } |
| 397 | |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 398 | static hb_bool_t |
Khaled Hosny | 9d4d2fb | 2017-10-16 10:05:42 +0200 | [diff] [blame] | 399 | hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, |
| 400 | void *font_data, |
| 401 | hb_codepoint_t glyph, |
| 402 | char *name, unsigned int size, |
| 403 | void *user_data HB_UNUSED) |
| 404 | { |
| 405 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
| 406 | return ot_font->post->get_glyph_name (glyph, name, size); |
| 407 | } |
| 408 | |
| 409 | static hb_bool_t |
Khaled Hosny | d9e166f | 2017-10-18 20:49:16 +0200 | [diff] [blame] | 410 | hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, |
| 411 | void *font_data, |
| 412 | const char *name, int len, |
| 413 | hb_codepoint_t *glyph, |
| 414 | void *user_data HB_UNUSED) |
| 415 | { |
| 416 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
| 417 | return ot_font->post->get_glyph_from_name (name, len, glyph); |
| 418 | } |
| 419 | |
| 420 | static hb_bool_t |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 421 | hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED, |
| 422 | void *font_data, |
| 423 | hb_font_extents_t *metrics, |
| 424 | void *user_data HB_UNUSED) |
| 425 | { |
| 426 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
| 427 | metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender); |
| 428 | metrics->descender = font->em_scale_y (ot_font->h_metrics.descender); |
| 429 | metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap); |
Behdad Esfahbod | 79e8e27 | 2017-01-23 17:55:31 -0800 | [diff] [blame] | 430 | // TODO Hook up variations. |
Behdad Esfahbod | b3b0816 | 2016-10-26 17:19:07 +0200 | [diff] [blame] | 431 | return ot_font->h_metrics.has_font_extents; |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 432 | } |
| 433 | |
| 434 | static hb_bool_t |
| 435 | hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED, |
| 436 | void *font_data, |
| 437 | hb_font_extents_t *metrics, |
| 438 | void *user_data HB_UNUSED) |
| 439 | { |
| 440 | const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; |
| 441 | metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender); |
| 442 | metrics->descender = font->em_scale_x (ot_font->v_metrics.descender); |
| 443 | metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap); |
Behdad Esfahbod | 79e8e27 | 2017-01-23 17:55:31 -0800 | [diff] [blame] | 444 | // TODO Hook up variations. |
Behdad Esfahbod | b3b0816 | 2016-10-26 17:19:07 +0200 | [diff] [blame] | 445 | return ot_font->v_metrics.has_font_extents; |
Simon Cozens | 6f2e6de | 2015-10-26 16:23:22 +0900 | [diff] [blame] | 446 | } |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 447 | |
Behdad Esfahbod | dbdbfe3 | 2017-10-15 12:11:08 +0200 | [diff] [blame] | 448 | static hb_font_funcs_t *static_ot_funcs = nullptr; |
Behdad Esfahbod | 75ea2da | 2015-11-04 20:43:59 -0800 | [diff] [blame] | 449 | |
| 450 | #ifdef HB_USE_ATEXIT |
| 451 | static |
| 452 | void free_static_ot_funcs (void) |
| 453 | { |
| 454 | hb_font_funcs_destroy (static_ot_funcs); |
| 455 | } |
| 456 | #endif |
| 457 | |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 458 | static hb_font_funcs_t * |
| 459 | _hb_ot_get_font_funcs (void) |
| 460 | { |
Behdad Esfahbod | 75ea2da | 2015-11-04 20:43:59 -0800 | [diff] [blame] | 461 | retry: |
| 462 | hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs); |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 463 | |
Behdad Esfahbod | 75ea2da | 2015-11-04 20:43:59 -0800 | [diff] [blame] | 464 | if (unlikely (!funcs)) |
| 465 | { |
| 466 | funcs = hb_font_funcs_create (); |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 467 | |
Behdad Esfahbod | dbdbfe3 | 2017-10-15 12:11:08 +0200 | [diff] [blame] | 468 | hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr); |
| 469 | hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr); |
| 470 | hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr); |
| 471 | hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr); |
| 472 | hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, nullptr, nullptr); |
| 473 | hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, nullptr, nullptr); |
| 474 | //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr); |
| 475 | //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr); |
Behdad Esfahbod | 4b3278e | 2017-11-01 19:41:29 -0600 | [diff] [blame] | 476 | hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, nullptr, nullptr); |
Behdad Esfahbod | dbdbfe3 | 2017-10-15 12:11:08 +0200 | [diff] [blame] | 477 | //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, nullptr, nullptr); |
| 478 | hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr); |
| 479 | //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr); TODO |
Khaled Hosny | 9d4d2fb | 2017-10-16 10:05:42 +0200 | [diff] [blame] | 480 | hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr); |
Khaled Hosny | d9e166f | 2017-10-18 20:49:16 +0200 | [diff] [blame] | 481 | hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr); |
Behdad Esfahbod | 75ea2da | 2015-11-04 20:43:59 -0800 | [diff] [blame] | 482 | |
| 483 | hb_font_funcs_make_immutable (funcs); |
| 484 | |
Behdad Esfahbod | dbdbfe3 | 2017-10-15 12:11:08 +0200 | [diff] [blame] | 485 | if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, nullptr, funcs)) { |
Behdad Esfahbod | 75ea2da | 2015-11-04 20:43:59 -0800 | [diff] [blame] | 486 | hb_font_funcs_destroy (funcs); |
| 487 | goto retry; |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 488 | } |
Behdad Esfahbod | 75ea2da | 2015-11-04 20:43:59 -0800 | [diff] [blame] | 489 | |
| 490 | #ifdef HB_USE_ATEXIT |
| 491 | atexit (free_static_ot_funcs); /* First person registers atexit() callback. */ |
| 492 | #endif |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 493 | }; |
| 494 | |
Behdad Esfahbod | 75ea2da | 2015-11-04 20:43:59 -0800 | [diff] [blame] | 495 | return funcs; |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 496 | } |
| 497 | |
| 498 | |
Sascha Brawer | 01c3a88 | 2015-06-01 13:22:01 +0200 | [diff] [blame] | 499 | /** |
Behdad Esfahbod | 35d1858 | 2015-11-26 19:30:37 -0500 | [diff] [blame] | 500 | * hb_ot_font_set_funcs: |
| 501 | * |
Sascha Brawer | 01c3a88 | 2015-06-01 13:22:01 +0200 | [diff] [blame] | 502 | * Since: 0.9.28 |
| 503 | **/ |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 504 | void |
| 505 | hb_ot_font_set_funcs (hb_font_t *font) |
| 506 | { |
Behdad Esfahbod | 3224a59 | 2015-10-07 17:33:02 -0400 | [diff] [blame] | 507 | hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 508 | if (unlikely (!ot_font)) |
| 509 | return; |
| 510 | |
| 511 | hb_font_set_funcs (font, |
| 512 | _hb_ot_get_font_funcs (), |
| 513 | ot_font, |
Behdad Esfahbod | e1b6d92 | 2017-10-11 15:51:31 +0200 | [diff] [blame] | 514 | _hb_ot_font_destroy); |
Behdad Esfahbod | 9036484 | 2014-03-24 14:26:36 -0700 | [diff] [blame] | 515 | } |