1 /* 2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * 4 * This is part of HarfBuzz, an OpenType Layout engine 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 25 #include "harfbuzz-shaper.h" 26 #include "harfbuzz-shaper-private.h" 27 #include <assert.h> 28 29 /* 30 // Uniscribe also defines dlig for Hebrew, but we leave this out for now, as it's mostly 31 // ligatures one does not want in modern Hebrew (as lam-alef ligatures). 32 */ 33 #ifndef NO_OPENTYPE 34 static const HB_OpenTypeFeature hebrew_features[] = { 35 { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, 36 {0, 0} 37 }; 38 #endif 39 40 /* Hebrew shaping. In the non opentype case we try to use the 41 presentation forms specified for Hebrew. Especially for the 42 ligatures with Dagesh this gives much better results than we could 43 achieve manually. 44 */ 45 HB_Bool HB_HebrewShape(HB_ShaperItem *shaper_item) 46 { 47 enum { 48 Dagesh = 0x5bc, 49 ShinDot = 0x5c1, 50 SinDot = 0x5c2, 51 Patah = 0x5b7, 52 Qamats = 0x5b8, 53 Holam = 0x5b9, 54 Rafe = 0x5bf 55 }; 56 57 assert(shaper_item->item.script == HB_Script_Hebrew); 58 59 #ifndef NO_OPENTYPE 60 if (HB_SelectScript(shaper_item, hebrew_features)) { 61 62 const int availableGlyphs = shaper_item->num_glyphs; 63 if (!HB_ConvertStringToGlyphIndices(shaper_item)) 64 return FALSE; 65 66 HB_HeuristicSetGlyphAttributes(shaper_item); 67 HB_OpenTypeShape(shaper_item, /*properties*/0); 68 return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE); 69 } 70 #endif 71 72 { 73 const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos; 74 unsigned short *logClusters = shaper_item->log_clusters; 75 HB_GlyphAttributes *attributes = shaper_item->attributes; 76 77 HB_Bool haveGlyphs; 78 int slen = 1; 79 int cluster_start = 0; 80 hb_uint32 i; 81 82 HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length); 83 *shapedChars = *uc; 84 logClusters[0] = 0; 85 86 for (i = 1; i < shaper_item->item.length; ++i) { 87 hb_uint16 base = shapedChars[cluster_start]; 88 hb_uint16 shaped = 0; 89 HB_Bool invalid = FALSE; 90 if (uc[i] == Dagesh) { 91 if (base >= 0x5d0 92 && base <= 0x5ea 93 && base != 0x5d7 94 && base != 0x5dd 95 && base != 0x5df 96 && base != 0x5e2 97 && base != 0x5e5) { 98 shaped = base - 0x5d0 + 0xfb30; 99 } else if (base == 0xfb2a || base == 0xfb2b /* Shin with Shin or Sin dot */) { 100 shaped = base + 2; 101 } else { 102 invalid = TRUE; 103 } 104 } else if (uc[i] == ShinDot) { 105 if (base == 0x05e9) 106 shaped = 0xfb2a; 107 else if (base == 0xfb49) 108 shaped = 0xfb2c; 109 else 110 invalid = TRUE; 111 } else if (uc[i] == SinDot) { 112 if (base == 0x05e9) 113 shaped = 0xfb2b; 114 else if (base == 0xfb49) 115 shaped = 0xfb2d; 116 else 117 invalid = TRUE; 118 } else if (uc[i] == Patah) { 119 if (base == 0x5d0) 120 shaped = 0xfb2e; 121 } else if (uc[i] == Qamats) { 122 if (base == 0x5d0) 123 shaped = 0xfb2f; 124 } else if (uc[i] == Holam) { 125 if (base == 0x5d5) 126 shaped = 0xfb4b; 127 } else if (uc[i] == Rafe) { 128 if (base == 0x5d1) 129 shaped = 0xfb4c; 130 else if (base == 0x5db) 131 shaped = 0xfb4d; 132 else if (base == 0x5e4) 133 shaped = 0xfb4e; 134 } 135 136 if (invalid) { 137 shapedChars[slen] = 0x25cc; 138 attributes[slen].clusterStart = TRUE; 139 attributes[slen].mark = FALSE; 140 attributes[slen].combiningClass = 0; 141 cluster_start = slen; 142 ++slen; 143 } 144 if (shaped) { 145 if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar16 *)&shaped, 1)) { 146 shapedChars[cluster_start] = shaped; 147 } else 148 shaped = 0; 149 } 150 if (!shaped) { 151 HB_CharCategory category; 152 int cmb; 153 shapedChars[slen] = uc[i]; 154 HB_GetUnicodeCharProperties(uc[i], &category, &cmb); 155 if (category != HB_Mark_NonSpacing) { 156 attributes[slen].clusterStart = TRUE; 157 attributes[slen].mark = FALSE; 158 attributes[slen].combiningClass = 0; 159 attributes[slen].dontPrint = HB_IsControlChar(uc[i]); 160 cluster_start = slen; 161 } else { 162 attributes[slen].clusterStart = FALSE; 163 attributes[slen].mark = TRUE; 164 attributes[slen].combiningClass = cmb; 165 } 166 ++slen; 167 } 168 logClusters[i] = cluster_start; 169 } 170 171 haveGlyphs = shaper_item->font->klass 172 ->convertStringToGlyphIndices(shaper_item->font, 173 shapedChars, slen, 174 shaper_item->glyphs, &shaper_item->num_glyphs, 175 shaper_item->item.bidiLevel % 2); 176 177 HB_FREE_STACKARRAY(shapedChars); 178 179 if (!haveGlyphs) 180 return FALSE; 181 182 HB_HeuristicPosition(shaper_item); 183 } 184 185 return TRUE; 186 } 187 188