11512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod/*
21512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
31512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod *
41512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * This is part of HarfBuzz, an OpenType Layout engine library.
51512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod *
61512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * Permission is hereby granted, without written agreement and without
71512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
81512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * software and its documentation for any purpose, provided that the
91512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * above copyright notice and the following two paragraphs appear in
101512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * all copies of this software.
111512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod *
121512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
131512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
141512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
151512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
161512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * DAMAGE.
171512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod *
181512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
191512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
201512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
211512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
221512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
231512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod */
241512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
251512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#include "harfbuzz-shaper.h"
261512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#include "harfbuzz-shaper-private.h"
271512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
281512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#include <assert.h>
291512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
301512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod/*
311512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod tibetan syllables are of the form:
321512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    head position consonant
331512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    first sub-joined consonant
341512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    ....intermediate sub-joined consonants (if any)
351512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    last sub-joined consonant
361512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    sub-joined vowel (a-chung U+0F71)
371512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    standard or compound vowel sign (or 'virama' for devanagari transliteration)
381512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod*/
391512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
401512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbodtypedef enum {
411512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanOther,
421512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant,
431512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant,
441512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedVowel,
451512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanVowel
461512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod} TibetanForm;
471512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
481512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod/* this table starts at U+0f40 */
491512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbodstatic const unsigned char tibetanForm[0x80] = {
501512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
511512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
521512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
531512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
541512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
551512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
561512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
571512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
581512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
591512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
601512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
611512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
621512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
631512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanOther, TibetanOther, TibetanOther, TibetanOther,
641512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
651512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanOther, TibetanVowel, TibetanVowel, TibetanVowel,
661512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
671512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
681512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
691512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
701512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
711512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
721512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanOther, TibetanOther, TibetanOther, TibetanOther,
731512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanOther, TibetanOther, TibetanOther, TibetanOther,
741512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
751512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
761512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
771512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
781512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
791512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
801512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
811512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
821512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
831512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
841512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
851512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
861512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
871512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
881512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanSubjoinedConsonant, TibetanOther, TibetanOther, TibetanOther
891512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod};
901512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
911512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
921512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#define tibetan_form(c) \
931512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    ((c) >= 0x0f40 && (c) < 0x0fc0 ? (TibetanForm)tibetanForm[(c) - 0x0f40] : TibetanOther)
941512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
951512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbodstatic const HB_OpenTypeFeature tibetan_features[] = {
961512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
971512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    { HB_MAKE_TAG('a', 'b', 'v', 's'), AboveSubstProperty },
981512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    { HB_MAKE_TAG('b', 'l', 'w', 's'), BelowSubstProperty },
991512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    { HB_MAKE_TAG('c', 'a', 'l', 't'), CaltProperty },
1001512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    {0, 0}
1011512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod};
1021512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1031512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbodstatic HB_Bool tibetan_shape_syllable(HB_Bool openType, HB_ShaperItem *item, HB_Bool invalid)
1041512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod{
1051512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    hb_uint32 i;
1061512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    const HB_UChar16 *str = item->string + item->item.pos;
1071512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    int len = item->item.length;
1081512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#ifndef NO_OPENTYPE
1091512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    const int availableGlyphs = item->num_glyphs;
1101512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#endif
1111512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    HB_Bool haveGlyphs;
1121512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    HB_STACKARRAY(HB_UChar16, reordered, len + 4);
1131512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1141512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    if (item->num_glyphs < item->item.length + 4) {
1151512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        item->num_glyphs = item->item.length + 4;
116f2377155e35c15919af4d7db21b6edc6783146b6Behdad Esfahbod        HB_FREE_STACKARRAY(reordered);
1171512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        return FALSE;
1181512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    }
1191512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1201512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    if (invalid) {
1211512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        *reordered = 0x25cc;
1221512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        memcpy(reordered+1, str, len*sizeof(HB_UChar16));
1231512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        len++;
1241512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        str = reordered;
1251512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    }
1261512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1271512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    haveGlyphs = item->font->klass->convertStringToGlyphIndices(item->font,
1281512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod                                                                str, len,
1291512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod                                                                item->glyphs, &item->num_glyphs,
1301512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod                                                                item->item.bidiLevel % 2);
1311512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1321512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    HB_FREE_STACKARRAY(reordered);
1331512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1341512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    if (!haveGlyphs)
1351512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        return FALSE;
1361512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1371512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    for (i = 0; i < item->item.length; i++) {
1381512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        item->attributes[i].mark = FALSE;
1391512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        item->attributes[i].clusterStart = FALSE;
1401512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        item->attributes[i].justification = 0;
1411512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        item->attributes[i].zeroWidth = FALSE;
1421512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod/*        IDEBUG("    %d: %4x", i, str[i]); */
1431512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    }
1441512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1451512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    /* now we have the syllable in the right order, and can start running it through open type. */
1461512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1471512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#ifndef NO_OPENTYPE
1481512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    if (openType) {
1491512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        HB_OpenTypeShape(item, /*properties*/0);
1501512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE))
1511512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            return FALSE;
1521512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    } else {
1531512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        HB_HeuristicPosition(item);
1541512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    }
1551512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#endif
1561512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1571512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    item->attributes[0].clusterStart = TRUE;
1581512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    return TRUE;
1591512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod}
1601512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1611512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1621512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbodstatic int tibetan_nextSyllableBoundary(const HB_UChar16 *s, int start, int end, HB_Bool *invalid)
1631512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod{
1641512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    const HB_UChar16 *uc = s + start;
1651512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1661512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    int pos = 0;
1671512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    TibetanForm state = tibetan_form(*uc);
1681512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1691512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod/*     qDebug("state[%d]=%d (uc=%4x)", pos, state, uc[pos]);*/
1701512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    pos++;
1711512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1721512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    if (state != TibetanHeadConsonant) {
1731512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        if (state != TibetanOther)
1741512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            *invalid = TRUE;
1751512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        goto finish;
1761512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    }
1771512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
1781512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    while (pos < end - start) {
1791512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        TibetanForm newState = tibetan_form(uc[pos]);
1801512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        switch(newState) {
1811512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        case TibetanSubjoinedConsonant:
1821512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        case TibetanSubjoinedVowel:
1831512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            if (state != TibetanHeadConsonant &&
1841512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod                 state != TibetanSubjoinedConsonant)
1851512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod                goto finish;
1861512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            state = newState;
1871512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            break;
1881512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        case TibetanVowel:
1891512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            if (state != TibetanHeadConsonant &&
1901512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod                 state != TibetanSubjoinedConsonant &&
1911512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod                 state != TibetanSubjoinedVowel)
1921512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod                goto finish;
1931512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            break;
1941512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        case TibetanOther:
1951512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        case TibetanHeadConsonant:
1961512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            goto finish;
1971512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        }
1981512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        pos++;
1991512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    }
2001512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
2011512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbodfinish:
2021512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    *invalid = FALSE;
2031512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    return start+pos;
2041512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod}
2051512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
2061512a7357513b72e2a07dda706a176bb23d694e9Behdad EsfahbodHB_Bool HB_TibetanShape(HB_ShaperItem *item)
2071512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod{
2081512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
2091512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    HB_Bool openType = FALSE;
2101512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    unsigned short *logClusters = item->log_clusters;
2111512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
2121512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    HB_ShaperItem syllable = *item;
2131512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    int first_glyph = 0;
2141512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
2151512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    int sstart = item->item.pos;
2161512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    int end = sstart + item->item.length;
2171512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
2181512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    assert(item->item.script == HB_Script_Tibetan);
2191512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
2201512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#ifndef QT_NO_OPENTYPE
2211512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    openType = HB_SelectScript(item, tibetan_features);
2221512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod#endif
2231512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod
2241512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    while (sstart < end) {
2251512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        HB_Bool invalid;
2261512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        int i;
2271512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        int send = tibetan_nextSyllableBoundary(item->string, sstart, end, &invalid);
2281512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod/*        IDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
2291512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod                 invalid ? "TRUE" : "FALSE"); */
2301512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        syllable.item.pos = sstart;
2311512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        syllable.item.length = send-sstart;
2321512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        syllable.glyphs = item->glyphs + first_glyph;
2331512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        syllable.attributes = item->attributes + first_glyph;
2341512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        syllable.offsets = item->offsets + first_glyph;
2351512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        syllable.advances = item->advances + first_glyph;
2361512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        syllable.num_glyphs = item->num_glyphs - first_glyph;
2371512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        if (!tibetan_shape_syllable(openType, &syllable, invalid)) {
2381512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            item->num_glyphs += syllable.num_glyphs;
2391512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            return FALSE;
2401512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        }
2411512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        /* fix logcluster array */
2421512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        for (i = sstart; i < send; ++i)
2431512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod            logClusters[i-item->item.pos] = first_glyph;
2441512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        sstart = send;
2451512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod        first_glyph += syllable.num_glyphs;
2461512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    }
2471512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    item->num_glyphs = first_glyph;
2481512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod    return TRUE;
2491512a7357513b72e2a07dda706a176bb23d694e9Behdad Esfahbod}
250