hb-ot-shaper-hebrew.cc (5816B)
1 /* 2 * Copyright © 2010,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 #include "hb.hh" 28 29 #ifndef HB_NO_OT_SHAPE 30 31 #include "hb-ot-shaper.hh" 32 33 34 static bool 35 compose_hebrew (const hb_ot_shape_normalize_context_t *c, 36 hb_codepoint_t a, 37 hb_codepoint_t b, 38 hb_codepoint_t *ab) 39 { 40 /* Hebrew presentation-form shaping. 41 * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 42 * Hebrew presentation forms with dagesh, for characters U+05D0..05EA; 43 * Note that some letters do not have a dagesh presForm encoded. 44 */ 45 static const hb_codepoint_t sDageshForms[0x05EAu - 0x05D0u + 1] = { 46 0xFB30u, /* ALEF */ 47 0xFB31u, /* BET */ 48 0xFB32u, /* GIMEL */ 49 0xFB33u, /* DALET */ 50 0xFB34u, /* HE */ 51 0xFB35u, /* VAV */ 52 0xFB36u, /* ZAYIN */ 53 0x0000u, /* HET */ 54 0xFB38u, /* TET */ 55 0xFB39u, /* YOD */ 56 0xFB3Au, /* FINAL KAF */ 57 0xFB3Bu, /* KAF */ 58 0xFB3Cu, /* LAMED */ 59 0x0000u, /* FINAL MEM */ 60 0xFB3Eu, /* MEM */ 61 0x0000u, /* FINAL NUN */ 62 0xFB40u, /* NUN */ 63 0xFB41u, /* SAMEKH */ 64 0x0000u, /* AYIN */ 65 0xFB43u, /* FINAL PE */ 66 0xFB44u, /* PE */ 67 0x0000u, /* FINAL TSADI */ 68 0xFB46u, /* TSADI */ 69 0xFB47u, /* QOF */ 70 0xFB48u, /* RESH */ 71 0xFB49u, /* SHIN */ 72 0xFB4Au /* TAV */ 73 }; 74 75 bool found = (bool) c->unicode->compose (a, b, ab); 76 77 #ifdef HB_NO_OT_SHAPER_HEBREW_FALLBACK 78 return found; 79 #endif 80 81 if (!found && (c->plan && !c->plan->has_gpos_mark)) 82 { 83 /* Special-case Hebrew presentation forms that are excluded from 84 * standard normalization, but wanted for old fonts. */ 85 switch (b) { 86 case 0x05B4u: /* HIRIQ */ 87 if (a == 0x05D9u) { /* YOD */ 88 *ab = 0xFB1Du; 89 found = true; 90 } 91 break; 92 case 0x05B7u: /* PATAH */ 93 if (a == 0x05F2u) { /* YIDDISH YOD YOD */ 94 *ab = 0xFB1Fu; 95 found = true; 96 } else if (a == 0x05D0u) { /* ALEF */ 97 *ab = 0xFB2Eu; 98 found = true; 99 } 100 break; 101 case 0x05B8u: /* QAMATS */ 102 if (a == 0x05D0u) { /* ALEF */ 103 *ab = 0xFB2Fu; 104 found = true; 105 } 106 break; 107 case 0x05B9u: /* HOLAM */ 108 if (a == 0x05D5u) { /* VAV */ 109 *ab = 0xFB4Bu; 110 found = true; 111 } 112 break; 113 case 0x05BCu: /* DAGESH */ 114 if (a >= 0x05D0u && a <= 0x05EAu) { 115 *ab = sDageshForms[a - 0x05D0u]; 116 found = (*ab != 0); 117 } else if (a == 0xFB2Au) { /* SHIN WITH SHIN DOT */ 118 *ab = 0xFB2Cu; 119 found = true; 120 } else if (a == 0xFB2Bu) { /* SHIN WITH SIN DOT */ 121 *ab = 0xFB2Du; 122 found = true; 123 } 124 break; 125 case 0x05BFu: /* RAFE */ 126 switch (a) { 127 case 0x05D1u: /* BET */ 128 *ab = 0xFB4Cu; 129 found = true; 130 break; 131 case 0x05DBu: /* KAF */ 132 *ab = 0xFB4Du; 133 found = true; 134 break; 135 case 0x05E4u: /* PE */ 136 *ab = 0xFB4Eu; 137 found = true; 138 break; 139 } 140 break; 141 case 0x05C1u: /* SHIN DOT */ 142 if (a == 0x05E9u) { /* SHIN */ 143 *ab = 0xFB2Au; 144 found = true; 145 } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */ 146 *ab = 0xFB2Cu; 147 found = true; 148 } 149 break; 150 case 0x05C2u: /* SIN DOT */ 151 if (a == 0x05E9u) { /* SHIN */ 152 *ab = 0xFB2Bu; 153 found = true; 154 } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */ 155 *ab = 0xFB2Du; 156 found = true; 157 } 158 break; 159 } 160 } 161 162 return found; 163 } 164 165 static void 166 reorder_marks_hebrew (const hb_ot_shape_plan_t *plan HB_UNUSED, 167 hb_buffer_t *buffer, 168 unsigned int start, 169 unsigned int end) 170 { 171 hb_glyph_info_t *info = buffer->info; 172 173 for (unsigned i = start + 2; i < end; i++) 174 { 175 unsigned c0 = info_cc (info[i - 2]); 176 unsigned c1 = info_cc (info[i - 1]); 177 unsigned c2 = info_cc (info[i - 0]); 178 179 if ((c0 == HB_MODIFIED_COMBINING_CLASS_CCC17 || c0 == HB_MODIFIED_COMBINING_CLASS_CCC18) /* patach or qamats */ && 180 (c1 == HB_MODIFIED_COMBINING_CLASS_CCC10 || c1 == HB_MODIFIED_COMBINING_CLASS_CCC14) /* sheva or hiriq */ && 181 (c2 == HB_MODIFIED_COMBINING_CLASS_CCC22 || c2 == HB_UNICODE_COMBINING_CLASS_BELOW) /* meteg or below */) 182 { 183 buffer->merge_clusters (i - 1, i + 1); 184 hb_swap (info[i - 1], info[i]); 185 break; 186 } 187 } 188 189 190 } 191 192 const hb_ot_shaper_t _hb_ot_shaper_hebrew = 193 { 194 nullptr, /* collect_features */ 195 nullptr, /* override_features */ 196 nullptr, /* data_create */ 197 nullptr, /* data_destroy */ 198 nullptr, /* preprocess_text */ 199 nullptr, /* postprocess_glyphs */ 200 nullptr, /* decompose */ 201 compose_hebrew, 202 nullptr, /* setup_masks */ 203 reorder_marks_hebrew, 204 HB_TAG ('h','e','b','r'), /* gpos_tag. https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 */ 205 HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, 206 HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, 207 true, /* fallback_position */ 208 }; 209 210 211 #endif