Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* | |
| 2 * Copyright © 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 | |
| 25 */ | |
| 26 | |
| 27 #ifndef HB_OT_SHAPER_ARABIC_FALLBACK_HH | |
| 28 #define HB_OT_SHAPER_ARABIC_FALLBACK_HH | |
| 29 | |
| 30 #include "hb.hh" | |
| 31 | |
| 32 #include "hb-ot-shape.hh" | |
| 33 #include "hb-ot-layout-gsub-table.hh" | |
| 34 | |
| 35 | |
| 36 /* Features ordered the same as the entries in shaping_table rows, | |
| 37 * followed by rlig. Don't change. | |
| 38 * | |
| 39 * We currently support one subtable per lookup, and one lookup | |
| 40 * per feature. But we allow duplicate features, so we use that! | |
| 41 */ | |
| 42 static const hb_tag_t arabic_fallback_features[] = | |
| 43 { | |
| 44 HB_TAG('i','n','i','t'), | |
| 45 HB_TAG('m','e','d','i'), | |
| 46 HB_TAG('f','i','n','a'), | |
| 47 HB_TAG('i','s','o','l'), | |
| 48 HB_TAG('r','l','i','g'), | |
| 49 HB_TAG('r','l','i','g'), | |
| 50 HB_TAG('r','l','i','g'), | |
| 51 }; | |
| 52 | |
| 53 static OT::SubstLookup * | |
| 54 arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED, | |
| 55 hb_font_t *font, | |
| 56 unsigned int feature_index) | |
| 57 { | |
| 58 OT::HBGlyphID16 glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1]; | |
| 59 OT::HBGlyphID16 substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1]; | |
| 60 unsigned int num_glyphs = 0; | |
| 61 | |
| 62 /* Populate arrays */ | |
| 63 for (hb_codepoint_t u = SHAPING_TABLE_FIRST; u < SHAPING_TABLE_LAST + 1; u++) | |
| 64 { | |
| 65 hb_codepoint_t s = shaping_table[u - SHAPING_TABLE_FIRST][feature_index]; | |
| 66 hb_codepoint_t u_glyph, s_glyph; | |
| 67 | |
| 68 if (!s || | |
| 69 !hb_font_get_glyph (font, u, 0, &u_glyph) || | |
| 70 !hb_font_get_glyph (font, s, 0, &s_glyph) || | |
| 71 u_glyph == s_glyph || | |
| 72 u_glyph > 0xFFFFu || s_glyph > 0xFFFFu) | |
| 73 continue; | |
| 74 | |
| 75 glyphs[num_glyphs] = u_glyph; | |
| 76 substitutes[num_glyphs] = s_glyph; | |
| 77 | |
| 78 num_glyphs++; | |
| 79 } | |
| 80 | |
| 81 if (!num_glyphs) | |
| 82 return nullptr; | |
| 83 | |
| 84 /* Bubble-sort or something equally good! | |
| 85 * May not be good-enough for presidential candidate interviews, but good-enough for us... */ | |
| 86 hb_stable_sort (&glyphs[0], num_glyphs, | |
| 87 (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID16::cmp, | |
| 88 &substitutes[0]); | |
| 89 | |
| 90 | |
| 91 /* Each glyph takes four bytes max, and there's some overhead. */ | |
| 92 char buf[(SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1) * 4 + 128]; | |
| 93 hb_serialize_context_t c (buf, sizeof (buf)); | |
| 94 OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> (); | |
| 95 bool ret = lookup->serialize_single (&c, | |
| 96 OT::LookupFlag::IgnoreMarks, | |
| 97 hb_sorted_array (glyphs, num_glyphs), | |
| 98 hb_array (substitutes, num_glyphs)); | |
| 99 c.end_serialize (); | |
| 100 | |
| 101 return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr; | |
| 102 } | |
| 103 | |
| 104 template <typename T> | |
| 105 static OT::SubstLookup * | |
| 106 arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED, | |
| 107 hb_font_t *font, | |
| 108 const T &ligature_table, | |
| 109 unsigned lookup_flags) | |
| 110 { | |
| 111 OT::HBGlyphID16 first_glyphs[ARRAY_LENGTH_CONST (ligature_table)]; | |
| 112 unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)]; | |
| 113 unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)]; | |
| 114 unsigned int num_first_glyphs = 0; | |
| 115 | |
| 116 /* We know that all our ligatures have the same number of components. */ | |
| 117 OT::HBGlyphID16 ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)]; | |
| 118 unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)]; | |
| 119 OT::HBGlyphID16 component_list[ARRAY_LENGTH_CONST (ligature_list) * | |
| 120 ARRAY_LENGTH_CONST (ligature_table[0].ligatures[0].components)]; | |
| 121 unsigned int num_ligatures = 0; | |
| 122 unsigned int num_components = 0; | |
| 123 | |
| 124 /* Populate arrays */ | |
| 125 | |
| 126 /* Sort out the first-glyphs */ | |
| 127 for (unsigned int first_glyph_idx = 0; first_glyph_idx < ARRAY_LENGTH (first_glyphs); first_glyph_idx++) | |
| 128 { | |
| 129 hb_codepoint_t first_u = ligature_table[first_glyph_idx].first; | |
| 130 hb_codepoint_t first_glyph; | |
| 131 if (!hb_font_get_glyph (font, first_u, 0, &first_glyph)) | |
| 132 continue; | |
| 133 first_glyphs[num_first_glyphs] = first_glyph; | |
| 134 ligature_per_first_glyph_count_list[num_first_glyphs] = 0; | |
| 135 first_glyphs_indirection[num_first_glyphs] = first_glyph_idx; | |
| 136 num_first_glyphs++; | |
| 137 } | |
| 138 hb_stable_sort (&first_glyphs[0], num_first_glyphs, | |
| 139 (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID16::cmp, | |
| 140 &first_glyphs_indirection[0]); | |
| 141 | |
| 142 /* Now that the first-glyphs are sorted, walk again, populate ligatures. */ | |
| 143 for (unsigned int i = 0; i < num_first_glyphs; i++) | |
| 144 { | |
| 145 unsigned int first_glyph_idx = first_glyphs_indirection[i]; | |
| 146 | |
| 147 for (unsigned int ligature_idx = 0; ligature_idx < ARRAY_LENGTH (ligature_table[0].ligatures); ligature_idx++) | |
| 148 { | |
| 149 hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[ligature_idx].ligature; | |
| 150 hb_codepoint_t ligature_glyph; | |
| 151 if (!hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph)) | |
| 152 continue; | |
| 153 | |
| 154 const auto &components = ligature_table[first_glyph_idx].ligatures[ligature_idx].components; | |
| 155 unsigned component_count = ARRAY_LENGTH_CONST (components); | |
| 156 | |
| 157 for (unsigned i = 0; i < component_count; i++) | |
| 158 { | |
| 159 hb_codepoint_t component_u = ligature_table[first_glyph_idx].ligatures[ligature_idx].components[i]; | |
| 160 hb_codepoint_t component_glyph; | |
| 161 if (!component_u || | |
| 162 !hb_font_get_glyph (font, component_u, 0, &component_glyph)) | |
| 163 continue; | |
| 164 | |
| 165 component_list[num_components++] = component_glyph; | |
| 166 } | |
| 167 | |
| 168 component_count_list[num_ligatures] = 1 + component_count; | |
| 169 ligature_list[num_ligatures] = ligature_glyph; | |
| 170 | |
| 171 ligature_per_first_glyph_count_list[i]++; | |
| 172 | |
| 173 num_ligatures++; | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 if (!num_ligatures) | |
| 178 return nullptr; | |
| 179 | |
| 180 | |
| 181 /* 16 bytes per ligature ought to be enough... */ | |
| 182 char buf[ARRAY_LENGTH_CONST (ligature_list) * 16 + 128]; | |
| 183 hb_serialize_context_t c (buf, sizeof (buf)); | |
| 184 OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> (); | |
| 185 bool ret = lookup->serialize_ligature (&c, | |
| 186 lookup_flags, | |
| 187 hb_sorted_array (first_glyphs, num_first_glyphs), | |
| 188 hb_array (ligature_per_first_glyph_count_list, num_first_glyphs), | |
| 189 hb_array (ligature_list, num_ligatures), | |
| 190 hb_array (component_count_list, num_ligatures), | |
| 191 hb_array (component_list, num_components)); | |
| 192 c.end_serialize (); | |
| 193 | |
| 194 return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr; | |
| 195 } | |
| 196 | |
| 197 static OT::SubstLookup * | |
| 198 arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan, | |
| 199 hb_font_t *font, | |
| 200 unsigned int feature_index) | |
| 201 { | |
| 202 if (feature_index < 4) | |
| 203 return arabic_fallback_synthesize_lookup_single (plan, font, feature_index); | |
| 204 else | |
| 205 { | |
| 206 switch (feature_index) { | |
| 207 case 4: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_3_table, OT::LookupFlag::IgnoreMarks); | |
| 208 case 5: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_table, OT::LookupFlag::IgnoreMarks); | |
| 209 case 6: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_mark_table, 0); | |
| 210 } | |
| 211 } | |
| 212 assert (false); | |
| 213 return nullptr; | |
| 214 } | |
| 215 | |
| 216 #define ARABIC_FALLBACK_MAX_LOOKUPS ARRAY_LENGTH_CONST (arabic_fallback_features) | |
| 217 | |
| 218 struct arabic_fallback_plan_t | |
| 219 { | |
| 220 unsigned int num_lookups; | |
| 221 bool free_lookups; | |
| 222 | |
| 223 hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS]; | |
| 224 OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS]; | |
| 225 OT::hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS]; | |
| 226 }; | |
| 227 | |
| 228 #if defined(_WIN32) && !defined(HB_NO_WIN1256) | |
| 229 #define HB_WITH_WIN1256 | |
| 230 #endif | |
| 231 | |
| 232 #ifdef HB_WITH_WIN1256 | |
| 233 #include "hb-ot-shaper-arabic-win1256.hh" | |
| 234 #endif | |
| 235 | |
| 236 struct ManifestLookup | |
| 237 { | |
| 238 public: | |
| 239 OT::Tag tag; | |
| 240 OT::Offset16To<OT::SubstLookup> lookupOffset; | |
| 241 public: | |
| 242 DEFINE_SIZE_STATIC (6); | |
| 243 }; | |
| 244 typedef OT::Array16Of<ManifestLookup> Manifest; | |
| 245 | |
| 246 static bool | |
| 247 arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUSED, | |
| 248 const hb_ot_shape_plan_t *plan HB_UNUSED, | |
| 249 hb_font_t *font HB_UNUSED) | |
| 250 { | |
| 251 #ifdef HB_WITH_WIN1256 | |
| 252 /* Does this font look like it's Windows-1256-encoded? */ | |
| 253 hb_codepoint_t g; | |
| 254 if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ && | |
| 255 hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ && | |
| 256 hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ && | |
| 257 hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ && | |
| 258 hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */)) | |
| 259 return false; | |
| 260 | |
| 261 const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest); | |
| 262 static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) <= | |
| 263 ARABIC_FALLBACK_MAX_LOOKUPS * sizeof (ManifestLookup), ""); | |
| 264 | |
| 265 unsigned j = 0; | |
| 266 unsigned int count = manifest.len; | |
| 267 for (unsigned int i = 0; i < count; i++) | |
| 268 { | |
| 269 fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag); | |
| 270 if (fallback_plan->mask_array[j]) | |
| 271 { | |
| 272 fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset)); | |
| 273 if (fallback_plan->lookup_array[j]) | |
| 274 { | |
| 275 fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]); | |
| 276 j++; | |
| 277 } | |
| 278 } | |
| 279 } | |
| 280 | |
| 281 fallback_plan->num_lookups = j; | |
| 282 fallback_plan->free_lookups = false; | |
| 283 | |
| 284 return j > 0; | |
| 285 #else | |
| 286 return false; | |
| 287 #endif | |
| 288 } | |
| 289 | |
| 290 static bool | |
| 291 arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan, | |
| 292 const hb_ot_shape_plan_t *plan, | |
| 293 hb_font_t *font) | |
| 294 { | |
| 295 static_assert ((ARRAY_LENGTH_CONST (arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), ""); | |
| 296 unsigned int j = 0; | |
| 297 for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++) | |
| 298 { | |
| 299 fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]); | |
| 300 if (fallback_plan->mask_array[j]) | |
| 301 { | |
| 302 fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i); | |
| 303 if (fallback_plan->lookup_array[j]) | |
| 304 { | |
| 305 fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]); | |
| 306 j++; | |
| 307 } | |
| 308 } | |
| 309 } | |
| 310 | |
| 311 fallback_plan->num_lookups = j; | |
| 312 fallback_plan->free_lookups = true; | |
| 313 | |
| 314 return j > 0; | |
| 315 } | |
| 316 | |
| 317 static arabic_fallback_plan_t * | |
| 318 arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, | |
| 319 hb_font_t *font) | |
| 320 { | |
| 321 arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_calloc (1, sizeof (arabic_fallback_plan_t)); | |
| 322 if (unlikely (!fallback_plan)) | |
| 323 return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t)); | |
| 324 | |
| 325 fallback_plan->num_lookups = 0; | |
| 326 fallback_plan->free_lookups = false; | |
| 327 | |
| 328 /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms, | |
| 329 * in case the font has cmap entries for the presentation-forms characters. */ | |
| 330 if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font)) | |
| 331 return fallback_plan; | |
| 332 | |
| 333 /* See if this looks like a Windows-1256-encoded font. If it does, use a | |
| 334 * hand-coded GSUB table. */ | |
| 335 if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font)) | |
| 336 return fallback_plan; | |
| 337 | |
| 338 assert (fallback_plan->num_lookups == 0); | |
| 339 hb_free (fallback_plan); | |
| 340 return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t)); | |
| 341 } | |
| 342 | |
| 343 static void | |
| 344 arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan) | |
| 345 { | |
| 346 if (!fallback_plan || fallback_plan->num_lookups == 0) | |
| 347 return; | |
| 348 | |
| 349 for (unsigned int i = 0; i < fallback_plan->num_lookups; i++) | |
| 350 if (fallback_plan->lookup_array[i]) | |
| 351 { | |
| 352 fallback_plan->accel_array[i].fini (); | |
| 353 if (fallback_plan->free_lookups) | |
| 354 hb_free (fallback_plan->lookup_array[i]); | |
| 355 } | |
| 356 | |
| 357 hb_free (fallback_plan); | |
| 358 } | |
| 359 | |
| 360 static void | |
| 361 arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan, | |
| 362 hb_font_t *font, | |
| 363 hb_buffer_t *buffer) | |
| 364 { | |
| 365 OT::hb_ot_apply_context_t c (0, font, buffer); | |
| 366 for (unsigned int i = 0; i < fallback_plan->num_lookups; i++) | |
| 367 if (fallback_plan->lookup_array[i]) { | |
| 368 c.set_lookup_mask (fallback_plan->mask_array[i]); | |
| 369 hb_ot_layout_substitute_lookup (&c, | |
| 370 *fallback_plan->lookup_array[i], | |
| 371 fallback_plan->accel_array[i]); | |
| 372 } | |
| 373 } | |
| 374 | |
| 375 | |
| 376 #endif /* HB_OT_SHAPER_ARABIC_FALLBACK_HH */ |
