| /* |
| * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
| * |
| * This is part of HarfBuzz, an OpenType Layout engine library. |
| * |
| * Permission is hereby granted, without written agreement and without |
| * license or royalty fees, to use, copy, modify, and distribute this |
| * software and its documentation for any purpose, provided that the |
| * above copyright notice and the following two paragraphs appear in |
| * all copies of this software. |
| * |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
| * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
| * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
| * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| * |
| * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
| * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
| * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
| * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| */ |
| |
| #include "harfbuzz-shaper.h" |
| #include "harfbuzz-shaper-private.h" |
| #include <assert.h> |
| |
| /* |
| // Uniscribe also defines dlig for Hebrew, but we leave this out for now, as it's mostly |
| // ligatures one does not want in modern Hebrew (as lam-alef ligatures). |
| */ |
| #ifndef NO_OPENTYPE |
| static const HB_OpenTypeFeature hebrew_features[] = { |
| { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, |
| {0, 0} |
| }; |
| #endif |
| |
| /* 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(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; |
| } |
| |