/* Hebrew shaping. In the non opentype case we try to use the presentation forms specified for Hebrew. Especially for the ligatures with Dagesh this gives much better results than we could achieve manually. */ HB_Bool HB_HebrewShape(HB_ShaperItem *shaper_item) { enum { Dagesh = 0x5bc, ShinDot = 0x5c1, SinDot = 0x5c2, Patah = 0x5b7, Qamats = 0x5b8, Holam = 0x5b9, Rafe = 0x5bf }; assert(shaper_item->item.script == HB_Script_Hebrew); #ifndef NO_OPENTYPE if (HB_SelectScript(shaper_item, hebrew_features)) { const int availableGlyphs = shaper_item->num_glyphs; if (!HB_ConvertStringToGlyphIndices(shaper_item)) return FALSE; HB_HeuristicSetGlyphAttributes(shaper_item); HB_OpenTypeShape(shaper_item, /*properties*/0); return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE); } #endif { const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos; unsigned short *logClusters = shaper_item->log_clusters; HB_GlyphAttributes *attributes = shaper_item->attributes; HB_Bool haveGlyphs; int slen = 1; int cluster_start = 0; hb_uint32 i; HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length); *shapedChars = *uc; logClusters[0] = 0; for (i = 1; i < shaper_item->item.length; ++i) { hb_uint16 base = shapedChars[cluster_start]; hb_uint16 shaped = 0; HB_Bool invalid = FALSE; if (uc[i] == Dagesh) { if (base >= 0x5d0 && base <= 0x5ea && base != 0x5d7 && base != 0x5dd && base != 0x5df && base != 0x5e2 && base != 0x5e5) { shaped = base - 0x5d0 + 0xfb30; } else if (base == 0xfb2a || base == 0xfb2b /* Shin with Shin or Sin dot */) { shaped = base + 2; } else { invalid = TRUE; } } else if (uc[i] == ShinDot) { if (base == 0x05e9) shaped = 0xfb2a; else if (base == 0xfb49) shaped = 0xfb2c; else invalid = TRUE; } else if (uc[i] == SinDot) { if (base == 0x05e9) shaped = 0xfb2b; else if (base == 0xfb49) shaped = 0xfb2d; else invalid = TRUE; } else if (uc[i] == Patah) { if (base == 0x5d0) shaped = 0xfb2e; } else if (uc[i] == Qamats) { if (base == 0x5d0) shaped = 0xfb2f; } else if (uc[i] == Holam) { if (base == 0x5d5) shaped = 0xfb4b; } else if (uc[i] == Rafe) { if (base == 0x5d1) shaped = 0xfb4c; else if (base == 0x5db) shaped = 0xfb4d; else if (base == 0x5e4) shaped = 0xfb4e; } if (invalid) { shapedChars[slen] = 0x25cc; attributes[slen].clusterStart = TRUE; attributes[slen].mark = FALSE; attributes[slen].combiningClass = 0; cluster_start = slen; ++slen; } if (shaped) { if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar16 *)&shaped, 1)) { shapedChars[cluster_start] = shaped; } else shaped = 0; } if (!shaped) { HB_CharCategory category; int cmb; shapedChars[slen] = uc[i]; HB_GetUnicodeCharProperties(shaper_item->ufuncs, uc[i], &category, &cmb); if (category != HB_Mark_NonSpacing) { attributes[slen].clusterStart = TRUE; attributes[slen].mark = FALSE; attributes[slen].combiningClass = 0; attributes[slen].dontPrint = HB_IsControlChar(uc[i]); cluster_start = slen; } else { attributes[slen].clusterStart = FALSE; attributes[slen].mark = TRUE; attributes[slen].combiningClass = cmb; } ++slen; } logClusters[i] = cluster_start; } haveGlyphs = shaper_item->font->klass ->convertStringToGlyphIndices(shaper_item->font, shapedChars, slen, shaper_item->glyphs, &shaper_item->num_glyphs, shaper_item->item.bidiLevel % 2); HB_FREE_STACKARRAY(shapedChars); if (!haveGlyphs) return FALSE; HB_HeuristicPosition(shaper_item); } return TRUE; }
/* Greek shaping. Heuristic positioning can't render polytonic greek correctly. We're a lot better off mapping greek chars with diacritics to the characters in the extended greek region in Unicode if possible. */ HB_Bool HB_GreekShape(HB_ShaperItem *shaper_item) { const int availableGlyphs = shaper_item->num_glyphs; const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos; unsigned short *logClusters = shaper_item->log_clusters; HB_GlyphAttributes *attributes = shaper_item->attributes; HB_Bool haveGlyphs; int slen = 1; int cluster_start = 0; hb_uint32 i; HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length); assert(shaper_item->item.script == HB_Script_Greek); *shapedChars = *uc; logClusters[0] = 0; attributes[0].mark = false; attributes[0].clusterStart = true; attributes[0].dontPrint = false; for (i = 1; i < shaper_item->item.length; ++i) { hb_uint16 base = shapedChars[slen-1]; hb_uint16 shaped = 0; if (uc[i] == 0x300) shaped = compose_0x300(base); else if (uc[i] == 0x301) shaped = compose_0x301(base); else if (uc[i] == 0x304) shaped = compose_0x304(base); else if (uc[i] == 0x306) shaped = compose_0x306(base); else if (uc[i] == 0x308) shaped = compose_0x308(base); else if (uc[i] == 0x313) shaped = compose_0x313(base); else if (uc[i] == 0x314) shaped = compose_0x314(base); else if (uc[i] == 0x342) shaped = compose_0x342(base); else if (uc[i] == 0x345) shaped = compose_0x345(base); if (shaped) { if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar16 *)&shaped, 1)) { shapedChars[slen-1] = shaped; } else { shaped = 0; } } if (!shaped) { HB_CharCategory category; int cmb; shapedChars[slen] = uc[i]; HB_GetUnicodeCharProperties(uc[i], &category, &cmb); if (category != HB_Mark_NonSpacing) { attributes[slen].clusterStart = TRUE; attributes[slen].mark = FALSE; attributes[slen].combiningClass = 0; attributes[slen].dontPrint = HB_IsControlChar(uc[i]); cluster_start = slen; } else { attributes[slen].clusterStart = FALSE; attributes[slen].mark = TRUE; attributes[slen].combiningClass = cmb; } ++slen; } logClusters[i] = cluster_start; } haveGlyphs = shaper_item->font->klass ->convertStringToGlyphIndices(shaper_item->font, shapedChars, slen, shaper_item->glyphs, &shaper_item->num_glyphs, shaper_item->item.bidiLevel % 2); HB_FREE_STACKARRAY(shapedChars); if (!haveGlyphs) return FALSE; #ifndef NO_OPENTYPE if (HB_SelectScript(shaper_item, greek_features)) { HB_OpenTypeShape(shaper_item, /*properties*/0); return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE); } #endif HB_HeuristicPosition(shaper_item); return TRUE; }