harfbuzz-hebrew.c revision 5569331642446be05292e3e1f8a51218827168cd
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    HB_HeuristicSetGlyphAttributes(shaper_item);
605569331642446be05292e3e1f8a51218827168cdclaireho
615569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE
625569331642446be05292e3e1f8a51218827168cdclaireho    if (HB_SelectScript(shaper_item, hebrew_features)) {
635569331642446be05292e3e1f8a51218827168cdclaireho
645569331642446be05292e3e1f8a51218827168cdclaireho        const int availableGlyphs = shaper_item->num_glyphs;
655569331642446be05292e3e1f8a51218827168cdclaireho        if (!HB_ConvertStringToGlyphIndices(shaper_item))
665569331642446be05292e3e1f8a51218827168cdclaireho            return FALSE;
675569331642446be05292e3e1f8a51218827168cdclaireho
685569331642446be05292e3e1f8a51218827168cdclaireho
695569331642446be05292e3e1f8a51218827168cdclaireho        HB_OpenTypeShape(shaper_item, /*properties*/0);
705569331642446be05292e3e1f8a51218827168cdclaireho        return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE);
715569331642446be05292e3e1f8a51218827168cdclaireho    }
725569331642446be05292e3e1f8a51218827168cdclaireho#endif
735569331642446be05292e3e1f8a51218827168cdclaireho
745569331642446be05292e3e1f8a51218827168cdclaireho    {
755569331642446be05292e3e1f8a51218827168cdclaireho        const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos;
765569331642446be05292e3e1f8a51218827168cdclaireho        unsigned short *logClusters = shaper_item->log_clusters;
775569331642446be05292e3e1f8a51218827168cdclaireho        HB_GlyphAttributes *attributes = shaper_item->attributes;
785569331642446be05292e3e1f8a51218827168cdclaireho
795569331642446be05292e3e1f8a51218827168cdclaireho        HB_Bool haveGlyphs;
805569331642446be05292e3e1f8a51218827168cdclaireho        int slen = 1;
815569331642446be05292e3e1f8a51218827168cdclaireho        int cluster_start = 0;
825569331642446be05292e3e1f8a51218827168cdclaireho        hb_uint32 i;
835569331642446be05292e3e1f8a51218827168cdclaireho
845569331642446be05292e3e1f8a51218827168cdclaireho        HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length);
855569331642446be05292e3e1f8a51218827168cdclaireho        *shapedChars = *uc;
865569331642446be05292e3e1f8a51218827168cdclaireho        logClusters[0] = 0;
875569331642446be05292e3e1f8a51218827168cdclaireho
885569331642446be05292e3e1f8a51218827168cdclaireho        for (i = 1; i < shaper_item->item.length; ++i) {
895569331642446be05292e3e1f8a51218827168cdclaireho            hb_uint16 base = shapedChars[cluster_start];
905569331642446be05292e3e1f8a51218827168cdclaireho            hb_uint16 shaped = 0;
915569331642446be05292e3e1f8a51218827168cdclaireho            HB_Bool invalid = FALSE;
925569331642446be05292e3e1f8a51218827168cdclaireho            if (uc[i] == Dagesh) {
935569331642446be05292e3e1f8a51218827168cdclaireho                if (base >= 0x5d0
945569331642446be05292e3e1f8a51218827168cdclaireho                    && base <= 0x5ea
955569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5d7
965569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5dd
975569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5df
985569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5e2
995569331642446be05292e3e1f8a51218827168cdclaireho                    && base != 0x5e5) {
1005569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = base - 0x5d0 + 0xfb30;
1015569331642446be05292e3e1f8a51218827168cdclaireho                } else if (base == 0xfb2a || base == 0xfb2b /* Shin with Shin or Sin dot */) {
1025569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = base + 2;
1035569331642446be05292e3e1f8a51218827168cdclaireho                } else {
1045569331642446be05292e3e1f8a51218827168cdclaireho                    invalid = TRUE;
1055569331642446be05292e3e1f8a51218827168cdclaireho                }
1065569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == ShinDot) {
1075569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x05e9)
1085569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2a;
1095569331642446be05292e3e1f8a51218827168cdclaireho                else if (base == 0xfb49)
1105569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2c;
1115569331642446be05292e3e1f8a51218827168cdclaireho                else
1125569331642446be05292e3e1f8a51218827168cdclaireho                    invalid = TRUE;
1135569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == SinDot) {
1145569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x05e9)
1155569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2b;
1165569331642446be05292e3e1f8a51218827168cdclaireho                else if (base == 0xfb49)
1175569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2d;
1185569331642446be05292e3e1f8a51218827168cdclaireho                else
1195569331642446be05292e3e1f8a51218827168cdclaireho                    invalid = TRUE;
1205569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == Patah) {
1215569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x5d0)
1225569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2e;
1235569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == Qamats) {
1245569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x5d0)
1255569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb2f;
1265569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == Holam) {
1275569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x5d5)
1285569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb4b;
1295569331642446be05292e3e1f8a51218827168cdclaireho            } else if (uc[i] == Rafe) {
1305569331642446be05292e3e1f8a51218827168cdclaireho                if (base == 0x5d1)
1315569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb4c;
1325569331642446be05292e3e1f8a51218827168cdclaireho                else if (base == 0x5db)
1335569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb4d;
1345569331642446be05292e3e1f8a51218827168cdclaireho                else if (base == 0x5e4)
1355569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0xfb4e;
1365569331642446be05292e3e1f8a51218827168cdclaireho            }
1375569331642446be05292e3e1f8a51218827168cdclaireho
1385569331642446be05292e3e1f8a51218827168cdclaireho            if (invalid) {
1395569331642446be05292e3e1f8a51218827168cdclaireho                shapedChars[slen] = 0x25cc;
1405569331642446be05292e3e1f8a51218827168cdclaireho                attributes[slen].clusterStart = TRUE;
1415569331642446be05292e3e1f8a51218827168cdclaireho                attributes[slen].mark = FALSE;
1425569331642446be05292e3e1f8a51218827168cdclaireho                attributes[slen].combiningClass = 0;
1435569331642446be05292e3e1f8a51218827168cdclaireho                cluster_start = slen;
1445569331642446be05292e3e1f8a51218827168cdclaireho                ++slen;
1455569331642446be05292e3e1f8a51218827168cdclaireho            }
1465569331642446be05292e3e1f8a51218827168cdclaireho            if (shaped) {
1475569331642446be05292e3e1f8a51218827168cdclaireho                if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar16 *)&shaped, 1)) {
1485569331642446be05292e3e1f8a51218827168cdclaireho                    shapedChars[cluster_start] = shaped;
1495569331642446be05292e3e1f8a51218827168cdclaireho                } else
1505569331642446be05292e3e1f8a51218827168cdclaireho                    shaped = 0;
1515569331642446be05292e3e1f8a51218827168cdclaireho            }
1525569331642446be05292e3e1f8a51218827168cdclaireho            if (!shaped) {
1535569331642446be05292e3e1f8a51218827168cdclaireho                HB_CharCategory category;
1545569331642446be05292e3e1f8a51218827168cdclaireho                int cmb;
1555569331642446be05292e3e1f8a51218827168cdclaireho                shapedChars[slen] = uc[i];
1565569331642446be05292e3e1f8a51218827168cdclaireho                HB_GetUnicodeCharProperties(uc[i], &category, &cmb);
1575569331642446be05292e3e1f8a51218827168cdclaireho                if (category != HB_Mark_NonSpacing) {
1585569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].clusterStart = TRUE;
1595569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].mark = FALSE;
1605569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].combiningClass = 0;
1615569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].dontPrint = HB_IsControlChar(uc[i]);
1625569331642446be05292e3e1f8a51218827168cdclaireho                    cluster_start = slen;
1635569331642446be05292e3e1f8a51218827168cdclaireho                } else {
1645569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].clusterStart = FALSE;
1655569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].mark = TRUE;
1665569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[slen].combiningClass = cmb;
1675569331642446be05292e3e1f8a51218827168cdclaireho                }
1685569331642446be05292e3e1f8a51218827168cdclaireho                ++slen;
1695569331642446be05292e3e1f8a51218827168cdclaireho            }
1705569331642446be05292e3e1f8a51218827168cdclaireho            logClusters[i] = cluster_start;
1715569331642446be05292e3e1f8a51218827168cdclaireho        }
1725569331642446be05292e3e1f8a51218827168cdclaireho
1735569331642446be05292e3e1f8a51218827168cdclaireho        haveGlyphs = shaper_item->font->klass
1745569331642446be05292e3e1f8a51218827168cdclaireho            ->convertStringToGlyphIndices(shaper_item->font,
1755569331642446be05292e3e1f8a51218827168cdclaireho                                          shapedChars, slen,
1765569331642446be05292e3e1f8a51218827168cdclaireho                                          shaper_item->glyphs, &shaper_item->num_glyphs,
1775569331642446be05292e3e1f8a51218827168cdclaireho                                          shaper_item->item.bidiLevel % 2);
1785569331642446be05292e3e1f8a51218827168cdclaireho
1795569331642446be05292e3e1f8a51218827168cdclaireho        HB_FREE_STACKARRAY(shapedChars);
1805569331642446be05292e3e1f8a51218827168cdclaireho
1815569331642446be05292e3e1f8a51218827168cdclaireho        if (!haveGlyphs)
1825569331642446be05292e3e1f8a51218827168cdclaireho            return FALSE;
1835569331642446be05292e3e1f8a51218827168cdclaireho
1845569331642446be05292e3e1f8a51218827168cdclaireho        HB_HeuristicPosition(shaper_item);
1855569331642446be05292e3e1f8a51218827168cdclaireho    }
1865569331642446be05292e3e1f8a51218827168cdclaireho
1875569331642446be05292e3e1f8a51218827168cdclaireho    return TRUE;
1885569331642446be05292e3e1f8a51218827168cdclaireho}
1895569331642446be05292e3e1f8a51218827168cdclaireho
190