15569331642446be05292e3e1f8a51218827168cdclaireho/*
25569331642446be05292e3e1f8a51218827168cdclaireho * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
35569331642446be05292e3e1f8a51218827168cdclaireho *
45569331642446be05292e3e1f8a51218827168cdclaireho * This is part of HarfBuzz, an OpenType Layout engine library.
55569331642446be05292e3e1f8a51218827168cdclaireho *
65569331642446be05292e3e1f8a51218827168cdclaireho * Permission is hereby granted, without written agreement and without
75569331642446be05292e3e1f8a51218827168cdclaireho * license or royalty fees, to use, copy, modify, and distribute this
85569331642446be05292e3e1f8a51218827168cdclaireho * software and its documentation for any purpose, provided that the
95569331642446be05292e3e1f8a51218827168cdclaireho * above copyright notice and the following two paragraphs appear in
105569331642446be05292e3e1f8a51218827168cdclaireho * all copies of this software.
115569331642446be05292e3e1f8a51218827168cdclaireho *
125569331642446be05292e3e1f8a51218827168cdclaireho * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
135569331642446be05292e3e1f8a51218827168cdclaireho * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
145569331642446be05292e3e1f8a51218827168cdclaireho * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
155569331642446be05292e3e1f8a51218827168cdclaireho * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
165569331642446be05292e3e1f8a51218827168cdclaireho * DAMAGE.
175569331642446be05292e3e1f8a51218827168cdclaireho *
185569331642446be05292e3e1f8a51218827168cdclaireho * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
195569331642446be05292e3e1f8a51218827168cdclaireho * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
205569331642446be05292e3e1f8a51218827168cdclaireho * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
215569331642446be05292e3e1f8a51218827168cdclaireho * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
225569331642446be05292e3e1f8a51218827168cdclaireho * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
235569331642446be05292e3e1f8a51218827168cdclaireho */
245569331642446be05292e3e1f8a51218827168cdclaireho
255569331642446be05292e3e1f8a51218827168cdclaireho#include "harfbuzz-shaper.h"
265569331642446be05292e3e1f8a51218827168cdclaireho#include "harfbuzz-shaper-private.h"
275569331642446be05292e3e1f8a51218827168cdclaireho#include <assert.h>
285569331642446be05292e3e1f8a51218827168cdclaireho
295569331642446be05292e3e1f8a51218827168cdclaireho/*
305569331642446be05292e3e1f8a51218827168cdclaireho// Uniscribe also defines dlig for Hebrew, but we leave this out for now, as it's mostly
315569331642446be05292e3e1f8a51218827168cdclaireho// ligatures one does not want in modern Hebrew (as lam-alef ligatures).
325569331642446be05292e3e1f8a51218827168cdclaireho*/
335569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE
345569331642446be05292e3e1f8a51218827168cdclairehostatic const HB_OpenTypeFeature hebrew_features[] = {
355569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
365569331642446be05292e3e1f8a51218827168cdclaireho    {0, 0}
375569331642446be05292e3e1f8a51218827168cdclaireho};
385569331642446be05292e3e1f8a51218827168cdclaireho#endif
395569331642446be05292e3e1f8a51218827168cdclaireho
405569331642446be05292e3e1f8a51218827168cdclaireho/* Hebrew shaping. In the non opentype case we try to use the
415569331642446be05292e3e1f8a51218827168cdclaireho   presentation forms specified for Hebrew. Especially for the
425569331642446be05292e3e1f8a51218827168cdclaireho   ligatures with Dagesh this gives much better results than we could
435569331642446be05292e3e1f8a51218827168cdclaireho   achieve manually.
445569331642446be05292e3e1f8a51218827168cdclaireho*/
455569331642446be05292e3e1f8a51218827168cdclairehoHB_Bool HB_HebrewShape(HB_ShaperItem *shaper_item)
465569331642446be05292e3e1f8a51218827168cdclaireho{
475569331642446be05292e3e1f8a51218827168cdclaireho    enum {
485569331642446be05292e3e1f8a51218827168cdclaireho        Dagesh = 0x5bc,
495569331642446be05292e3e1f8a51218827168cdclaireho        ShinDot = 0x5c1,
505569331642446be05292e3e1f8a51218827168cdclaireho        SinDot = 0x5c2,
515569331642446be05292e3e1f8a51218827168cdclaireho        Patah = 0x5b7,
525569331642446be05292e3e1f8a51218827168cdclaireho        Qamats = 0x5b8,
535569331642446be05292e3e1f8a51218827168cdclaireho        Holam = 0x5b9,
545569331642446be05292e3e1f8a51218827168cdclaireho        Rafe = 0x5bf
555569331642446be05292e3e1f8a51218827168cdclaireho    };
565569331642446be05292e3e1f8a51218827168cdclaireho
575569331642446be05292e3e1f8a51218827168cdclaireho    assert(shaper_item->item.script == HB_Script_Hebrew);
585569331642446be05292e3e1f8a51218827168cdclaireho
595569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE
605569331642446be05292e3e1f8a51218827168cdclaireho    if (HB_SelectScript(shaper_item, hebrew_features)) {
615569331642446be05292e3e1f8a51218827168cdclaireho
625569331642446be05292e3e1f8a51218827168cdclaireho        const int availableGlyphs = shaper_item->num_glyphs;
635569331642446be05292e3e1f8a51218827168cdclaireho        if (!HB_ConvertStringToGlyphIndices(shaper_item))
645569331642446be05292e3e1f8a51218827168cdclaireho            return FALSE;
655569331642446be05292e3e1f8a51218827168cdclaireho
6657e6107a9d66a9a97b146def0ef38c010f954be6claireho        HB_HeuristicSetGlyphAttributes(shaper_item);
675569331642446be05292e3e1f8a51218827168cdclaireho        HB_OpenTypeShape(shaper_item, /*properties*/0);
685569331642446be05292e3e1f8a51218827168cdclaireho        return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE);
695569331642446be05292e3e1f8a51218827168cdclaireho    }
705569331642446be05292e3e1f8a51218827168cdclaireho#endif
715569331642446be05292e3e1f8a51218827168cdclaireho
725569331642446be05292e3e1f8a51218827168cdclaireho    {
735569331642446be05292e3e1f8a51218827168cdclaireho        const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos;
745569331642446be05292e3e1f8a51218827168cdclaireho        unsigned short *logClusters = shaper_item->log_clusters;
755569331642446be05292e3e1f8a51218827168cdclaireho        HB_GlyphAttributes *attributes = shaper_item->attributes;
765569331642446be05292e3e1f8a51218827168cdclaireho
775569331642446be05292e3e1f8a51218827168cdclaireho        HB_Bool haveGlyphs;
785569331642446be05292e3e1f8a51218827168cdclaireho        int slen = 1;
795569331642446be05292e3e1f8a51218827168cdclaireho        int cluster_start = 0;
805569331642446be05292e3e1f8a51218827168cdclaireho        hb_uint32 i;
815569331642446be05292e3e1f8a51218827168cdclaireho
825569331642446be05292e3e1f8a51218827168cdclaireho        HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length);
835569331642446be05292e3e1f8a51218827168cdclaireho        *shapedChars = *uc;
845569331642446be05292e3e1f8a51218827168cdclaireho        logClusters[0] = 0;
855569331642446be05292e3e1f8a51218827168cdclaireho
865569331642446be05292e3e1f8a51218827168cdclaireho        for (i = 1; i < shaper_item->item.length; ++i) {
87ca4c6948f69f807967f91d0e995716dd0f421dc5claireho            hb_uint16 base = shapedChars[cluster_start];
885569331642446be05292e3e1f8a51218827168cdclaireho            hb_uint16 shaped = 0;
895569331642446be05292e3e1f8a51218827168cdclaireho            HB_Bool invalid = FALSE;
905569331642446be05292e3e1f8a51218827168cdclaireho            if (uc[i] == Dagesh) {
915569331642446be05292e3e1f8a51218827168cdclaireho                if (base >= 0x5d0
925569331642446be05292e3e1f8a51218827168cdclaireho                    && base <= 0x5ea
935569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5d7
945569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5dd
955569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5df
965569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5e2
975569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5e5) {
985569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = base - 0x5d0 + 0xfb30;
995569331642446be05292e3e1f8a51218827168cdclaireho                } else if (base == 0xfb2a || base == 0xfb2b /* Shin with Shin or Sin dot */) {
1005569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = base + 2;
1015569331642446be05292e3e1f8a51218827168cdclaireho                } else {
1025569331642446be05292e3e1f8a51218827168cdclaireho                    invalid = TRUE;
1035569331642446be05292e3e1f8a51218827168cdclaireho                }
1045569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == ShinDot) {
1055569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x05e9)
1065569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2a;
1075569331642446be05292e3e1f8a51218827168cdclaireho                else if (base == 0xfb49)
1085569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2c;
1095569331642446be05292e3e1f8a51218827168cdclaireho                else
1105569331642446be05292e3e1f8a51218827168cdclaireho                    invalid = TRUE;
1115569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == SinDot) {
1125569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x05e9)
1135569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2b;
1145569331642446be05292e3e1f8a51218827168cdclaireho                else if (base == 0xfb49)
1155569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2d;
1165569331642446be05292e3e1f8a51218827168cdclaireho                else
1175569331642446be05292e3e1f8a51218827168cdclaireho                    invalid = TRUE;
1185569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == Patah) {
1195569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x5d0)
1205569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2e;
1215569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == Qamats) {
1225569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x5d0)
1235569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2f;
1245569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == Holam) {
1255569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x5d5)
1265569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb4b;
1275569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == Rafe) {
1285569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x5d1)
1295569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb4c;
1305569331642446be05292e3e1f8a51218827168cdclaireho                else if (base == 0x5db)
1315569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb4d;
1325569331642446be05292e3e1f8a51218827168cdclaireho                else if (base == 0x5e4)
1335569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb4e;
1345569331642446be05292e3e1f8a51218827168cdclaireho            }
1355569331642446be05292e3e1f8a51218827168cdclaireho
1365569331642446be05292e3e1f8a51218827168cdclaireho            if (invalid) {
1375569331642446be05292e3e1f8a51218827168cdclaireho                shapedChars[slen] = 0x25cc;
1385569331642446be05292e3e1f8a51218827168cdclaireho                attributes[slen].clusterStart = TRUE;
1395569331642446be05292e3e1f8a51218827168cdclaireho                attributes[slen].mark = FALSE;
1405569331642446be05292e3e1f8a51218827168cdclaireho                attributes[slen].combiningClass = 0;
1415569331642446be05292e3e1f8a51218827168cdclaireho                cluster_start = slen;
1425569331642446be05292e3e1f8a51218827168cdclaireho                ++slen;
1435569331642446be05292e3e1f8a51218827168cdclaireho            }
1445569331642446be05292e3e1f8a51218827168cdclaireho            if (shaped) {
1455569331642446be05292e3e1f8a51218827168cdclaireho                if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar16 *)&shaped, 1)) {
146ca4c6948f69f807967f91d0e995716dd0f421dc5claireho                    shapedChars[cluster_start] = shaped;
1475569331642446be05292e3e1f8a51218827168cdclaireho                } else
1485569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0;
1495569331642446be05292e3e1f8a51218827168cdclaireho            }
1505569331642446be05292e3e1f8a51218827168cdclaireho            if (!shaped) {
1515569331642446be05292e3e1f8a51218827168cdclaireho                HB_CharCategory category;
1525569331642446be05292e3e1f8a51218827168cdclaireho                int cmb;
1535569331642446be05292e3e1f8a51218827168cdclaireho                shapedChars[slen] = uc[i];
1545569331642446be05292e3e1f8a51218827168cdclaireho                HB_GetUnicodeCharProperties(uc[i], &category, &cmb);
1555569331642446be05292e3e1f8a51218827168cdclaireho                if (category != HB_Mark_NonSpacing) {
1565569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].clusterStart = TRUE;
1575569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].mark = FALSE;
1585569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].combiningClass = 0;
1595569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].dontPrint = HB_IsControlChar(uc[i]);
1605569331642446be05292e3e1f8a51218827168cdclaireho                    cluster_start = slen;
1615569331642446be05292e3e1f8a51218827168cdclaireho                } else {
1625569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].clusterStart = FALSE;
1635569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].mark = TRUE;
1645569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].combiningClass = cmb;
1655569331642446be05292e3e1f8a51218827168cdclaireho                }
1665569331642446be05292e3e1f8a51218827168cdclaireho                ++slen;
1675569331642446be05292e3e1f8a51218827168cdclaireho            }
1685569331642446be05292e3e1f8a51218827168cdclaireho            logClusters[i] = cluster_start;
1695569331642446be05292e3e1f8a51218827168cdclaireho        }
1705569331642446be05292e3e1f8a51218827168cdclaireho
1715569331642446be05292e3e1f8a51218827168cdclaireho        haveGlyphs = shaper_item->font->klass
1725569331642446be05292e3e1f8a51218827168cdclaireho            ->convertStringToGlyphIndices(shaper_item->font,
1735569331642446be05292e3e1f8a51218827168cdclaireho                                          shapedChars, slen,
1745569331642446be05292e3e1f8a51218827168cdclaireho                                          shaper_item->glyphs, &shaper_item->num_glyphs,
1755569331642446be05292e3e1f8a51218827168cdclaireho                                          shaper_item->item.bidiLevel % 2);
1765569331642446be05292e3e1f8a51218827168cdclaireho
1775569331642446be05292e3e1f8a51218827168cdclaireho        HB_FREE_STACKARRAY(shapedChars);
1785569331642446be05292e3e1f8a51218827168cdclaireho
1795569331642446be05292e3e1f8a51218827168cdclaireho        if (!haveGlyphs)
1805569331642446be05292e3e1f8a51218827168cdclaireho            return FALSE;
1815569331642446be05292e3e1f8a51218827168cdclaireho
1825569331642446be05292e3e1f8a51218827168cdclaireho        HB_HeuristicPosition(shaper_item);
1835569331642446be05292e3e1f8a51218827168cdclaireho    }
1845569331642446be05292e3e1f8a51218827168cdclaireho
1855569331642446be05292e3e1f8a51218827168cdclaireho    return TRUE;
1865569331642446be05292e3e1f8a51218827168cdclaireho}
1875569331642446be05292e3e1f8a51218827168cdclaireho
188