harfbuzz-shaper.cpp 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
285569331642446be05292e3e1f8a51218827168cdclaireho#include "harfbuzz-stream-private.h"
295569331642446be05292e3e1f8a51218827168cdclaireho#include <assert.h>
305569331642446be05292e3e1f8a51218827168cdclaireho#include <stdio.h>
315569331642446be05292e3e1f8a51218827168cdclaireho
325569331642446be05292e3e1f8a51218827168cdclaireho#define HB_MIN(a, b) ((a) < (b) ? (a) : (b))
335569331642446be05292e3e1f8a51218827168cdclaireho#define HB_MAX(a, b) ((a) > (b) ? (a) : (b))
345569331642446be05292e3e1f8a51218827168cdclaireho
355569331642446be05292e3e1f8a51218827168cdclaireho// -----------------------------------------------------------------------------------------------------
365569331642446be05292e3e1f8a51218827168cdclaireho//
375569331642446be05292e3e1f8a51218827168cdclaireho// The line break algorithm. See http://www.unicode.org/reports/tr14/tr14-13.html
385569331642446be05292e3e1f8a51218827168cdclaireho//
395569331642446be05292e3e1f8a51218827168cdclaireho// -----------------------------------------------------------------------------------------------------
405569331642446be05292e3e1f8a51218827168cdclaireho
415569331642446be05292e3e1f8a51218827168cdclaireho/* The Unicode algorithm does in our opinion allow line breaks at some
425569331642446be05292e3e1f8a51218827168cdclaireho   places they shouldn't be allowed. The following changes were thus
435569331642446be05292e3e1f8a51218827168cdclaireho   made in comparison to the Unicode reference:
445569331642446be05292e3e1f8a51218827168cdclaireho
455569331642446be05292e3e1f8a51218827168cdclaireho   EX->AL from DB to IB
465569331642446be05292e3e1f8a51218827168cdclaireho   SY->AL from DB to IB
475569331642446be05292e3e1f8a51218827168cdclaireho   SY->PO from DB to IB
485569331642446be05292e3e1f8a51218827168cdclaireho   SY->PR from DB to IB
495569331642446be05292e3e1f8a51218827168cdclaireho   SY->OP from DB to IB
505569331642446be05292e3e1f8a51218827168cdclaireho   AL->PR from DB to IB
515569331642446be05292e3e1f8a51218827168cdclaireho   AL->PO from DB to IB
525569331642446be05292e3e1f8a51218827168cdclaireho   PR->PR from DB to IB
535569331642446be05292e3e1f8a51218827168cdclaireho   PO->PO from DB to IB
545569331642446be05292e3e1f8a51218827168cdclaireho   PR->PO from DB to IB
555569331642446be05292e3e1f8a51218827168cdclaireho   PO->PR from DB to IB
565569331642446be05292e3e1f8a51218827168cdclaireho   HY->PO from DB to IB
575569331642446be05292e3e1f8a51218827168cdclaireho   HY->PR from DB to IB
585569331642446be05292e3e1f8a51218827168cdclaireho   HY->OP from DB to IB
595569331642446be05292e3e1f8a51218827168cdclaireho   NU->EX from PB to IB
605569331642446be05292e3e1f8a51218827168cdclaireho   EX->PO from DB to IB
615569331642446be05292e3e1f8a51218827168cdclaireho*/
625569331642446be05292e3e1f8a51218827168cdclaireho
635569331642446be05292e3e1f8a51218827168cdclaireho// The following line break classes are not treated by the table:
645569331642446be05292e3e1f8a51218827168cdclaireho//  AI, BK, CB, CR, LF, NL, SA, SG, SP, XX
655569331642446be05292e3e1f8a51218827168cdclaireho
665569331642446be05292e3e1f8a51218827168cdclairehoenum break_class {
675569331642446be05292e3e1f8a51218827168cdclaireho    // the first 4 values have to agree with the enum in QCharAttributes
685569331642446be05292e3e1f8a51218827168cdclaireho    ProhibitedBreak,            // PB in table
695569331642446be05292e3e1f8a51218827168cdclaireho    DirectBreak,                // DB in table
705569331642446be05292e3e1f8a51218827168cdclaireho    IndirectBreak,              // IB in table
715569331642446be05292e3e1f8a51218827168cdclaireho    CombiningIndirectBreak,     // CI in table
725569331642446be05292e3e1f8a51218827168cdclaireho    CombiningProhibitedBreak    // CP in table
735569331642446be05292e3e1f8a51218827168cdclaireho};
745569331642446be05292e3e1f8a51218827168cdclaireho#define DB DirectBreak
755569331642446be05292e3e1f8a51218827168cdclaireho#define IB IndirectBreak
765569331642446be05292e3e1f8a51218827168cdclaireho#define CI CombiningIndirectBreak
775569331642446be05292e3e1f8a51218827168cdclaireho#define CP CombiningProhibitedBreak
785569331642446be05292e3e1f8a51218827168cdclaireho#define PB ProhibitedBreak
795569331642446be05292e3e1f8a51218827168cdclaireho
805569331642446be05292e3e1f8a51218827168cdclairehostatic const hb_uint8 breakTable[HB_LineBreak_JT+1][HB_LineBreak_JT+1] =
815569331642446be05292e3e1f8a51218827168cdclaireho{
825569331642446be05292e3e1f8a51218827168cdclaireho/*          OP  CL  QU  GL  NS  EX  SY  IS  PR  PO  NU  AL  ID  IN  HY  BA  BB  B2  ZW  CM  WJ  H2  H3  JL  JV  JT */
835569331642446be05292e3e1f8a51218827168cdclaireho/* OP */ { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, CP, PB, PB, PB, PB, PB, PB },
845569331642446be05292e3e1f8a51218827168cdclaireho/* CL */ { DB, PB, IB, IB, PB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
855569331642446be05292e3e1f8a51218827168cdclaireho/* QU */ { PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
865569331642446be05292e3e1f8a51218827168cdclaireho/* GL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
875569331642446be05292e3e1f8a51218827168cdclaireho/* NS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
885569331642446be05292e3e1f8a51218827168cdclaireho/* EX */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
895569331642446be05292e3e1f8a51218827168cdclaireho/* SY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
905569331642446be05292e3e1f8a51218827168cdclaireho/* IS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
915569331642446be05292e3e1f8a51218827168cdclaireho/* PR */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, IB },
925569331642446be05292e3e1f8a51218827168cdclaireho/* PO */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
935569331642446be05292e3e1f8a51218827168cdclaireho/* NU */ { IB, PB, IB, IB, IB, IB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
945569331642446be05292e3e1f8a51218827168cdclaireho/* AL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
955569331642446be05292e3e1f8a51218827168cdclaireho/* ID */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
965569331642446be05292e3e1f8a51218827168cdclaireho/* IN */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
975569331642446be05292e3e1f8a51218827168cdclaireho/* HY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
985569331642446be05292e3e1f8a51218827168cdclaireho/* BA */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
995569331642446be05292e3e1f8a51218827168cdclaireho/* BB */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
1005569331642446be05292e3e1f8a51218827168cdclaireho/* B2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, PB, PB, CI, PB, DB, DB, DB, DB, DB },
1015569331642446be05292e3e1f8a51218827168cdclaireho/* ZW */ { DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, PB, DB, DB, DB, DB, DB, DB, DB },
1025569331642446be05292e3e1f8a51218827168cdclaireho/* CM */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
1035569331642446be05292e3e1f8a51218827168cdclaireho/* WJ */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
1045569331642446be05292e3e1f8a51218827168cdclaireho/* H2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },
1055569331642446be05292e3e1f8a51218827168cdclaireho/* H3 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB },
1065569331642446be05292e3e1f8a51218827168cdclaireho/* JL */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, DB },
1075569331642446be05292e3e1f8a51218827168cdclaireho/* JV */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },
1085569331642446be05292e3e1f8a51218827168cdclaireho/* JT */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB }
1095569331642446be05292e3e1f8a51218827168cdclaireho};
1105569331642446be05292e3e1f8a51218827168cdclaireho#undef DB
1115569331642446be05292e3e1f8a51218827168cdclaireho#undef IB
1125569331642446be05292e3e1f8a51218827168cdclaireho#undef CI
1135569331642446be05292e3e1f8a51218827168cdclaireho#undef CP
1145569331642446be05292e3e1f8a51218827168cdclaireho#undef PB
1155569331642446be05292e3e1f8a51218827168cdclaireho
1165569331642446be05292e3e1f8a51218827168cdclairehostatic const hb_uint8 graphemeTable[HB_Grapheme_LVT + 1][HB_Grapheme_LVT + 1] =
1175569331642446be05292e3e1f8a51218827168cdclaireho{
1185569331642446be05292e3e1f8a51218827168cdclaireho//      Other, CR,    LF,    Control,Extend,L,    V,     T,     LV,    LVT
1195569331642446be05292e3e1f8a51218827168cdclaireho    { true , true , true , true , true , true , true , true , true , true  }, // Other,
1205569331642446be05292e3e1f8a51218827168cdclaireho    { true , true , true , true , true , true , true , true , true , true  }, // CR,
1215569331642446be05292e3e1f8a51218827168cdclaireho    { true , false, true , true , true , true , true , true , true , true  }, // LF,
1225569331642446be05292e3e1f8a51218827168cdclaireho    { true , true , true , true , true , true , true , true , true , true  }, // Control,
1235569331642446be05292e3e1f8a51218827168cdclaireho    { false, true , true , true , false, false, false, false, false, false }, // Extend,
1245569331642446be05292e3e1f8a51218827168cdclaireho    { true , true , true , true , true , false, true , true , true , true  }, // L,
1255569331642446be05292e3e1f8a51218827168cdclaireho    { true , true , true , true , true , false, false, true , false, true  }, // V,
1265569331642446be05292e3e1f8a51218827168cdclaireho    { true , true , true , true , true , true , false, false, false, false }, // T,
1275569331642446be05292e3e1f8a51218827168cdclaireho    { true , true , true , true , true , false, true , true , true , true  }, // LV,
1285569331642446be05292e3e1f8a51218827168cdclaireho    { true , true , true , true , true , false, true , true , true , true  }, // LVT
1295569331642446be05292e3e1f8a51218827168cdclaireho};
1305569331642446be05292e3e1f8a51218827168cdclaireho
1315569331642446be05292e3e1f8a51218827168cdclairehostatic void calcLineBreaks(const HB_UChar16 *uc, hb_uint32 len, HB_CharAttributes *charAttributes)
1325569331642446be05292e3e1f8a51218827168cdclaireho{
1335569331642446be05292e3e1f8a51218827168cdclaireho    if (!len)
1345569331642446be05292e3e1f8a51218827168cdclaireho        return;
1355569331642446be05292e3e1f8a51218827168cdclaireho
1365569331642446be05292e3e1f8a51218827168cdclaireho    // ##### can this fail if the first char is a surrogate?
1375569331642446be05292e3e1f8a51218827168cdclaireho    HB_LineBreakClass cls;
1385569331642446be05292e3e1f8a51218827168cdclaireho    HB_GraphemeClass grapheme;
1395569331642446be05292e3e1f8a51218827168cdclaireho    HB_GetGraphemeAndLineBreakClass(*uc, &grapheme, &cls);
1405569331642446be05292e3e1f8a51218827168cdclaireho    // handle case where input starts with an LF
1415569331642446be05292e3e1f8a51218827168cdclaireho    if (cls == HB_LineBreak_LF)
1425569331642446be05292e3e1f8a51218827168cdclaireho        cls = HB_LineBreak_BK;
1435569331642446be05292e3e1f8a51218827168cdclaireho
1445569331642446be05292e3e1f8a51218827168cdclaireho    charAttributes[0].whiteSpace = (cls == HB_LineBreak_SP || cls == HB_LineBreak_BK);
1455569331642446be05292e3e1f8a51218827168cdclaireho    charAttributes[0].charStop = true;
1465569331642446be05292e3e1f8a51218827168cdclaireho
1475569331642446be05292e3e1f8a51218827168cdclaireho    int lcls = cls;
1485569331642446be05292e3e1f8a51218827168cdclaireho    for (hb_uint32 i = 1; i < len; ++i) {
1495569331642446be05292e3e1f8a51218827168cdclaireho        charAttributes[i].whiteSpace = false;
1505569331642446be05292e3e1f8a51218827168cdclaireho        charAttributes[i].charStop = true;
1515569331642446be05292e3e1f8a51218827168cdclaireho
1525569331642446be05292e3e1f8a51218827168cdclaireho        HB_UChar32 code = uc[i];
1535569331642446be05292e3e1f8a51218827168cdclaireho        HB_GraphemeClass ngrapheme;
1545569331642446be05292e3e1f8a51218827168cdclaireho        HB_LineBreakClass ncls;
1555569331642446be05292e3e1f8a51218827168cdclaireho        HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls);
1565569331642446be05292e3e1f8a51218827168cdclaireho        charAttributes[i].charStop = graphemeTable[ngrapheme][grapheme];
1575569331642446be05292e3e1f8a51218827168cdclaireho        // handle surrogates
1585569331642446be05292e3e1f8a51218827168cdclaireho        if (ncls == HB_LineBreak_SG) {
1595569331642446be05292e3e1f8a51218827168cdclaireho            if (HB_IsHighSurrogate(uc[i]) && i < len - 1 && HB_IsLowSurrogate(uc[i+1])) {
1605569331642446be05292e3e1f8a51218827168cdclaireho                continue;
1615569331642446be05292e3e1f8a51218827168cdclaireho            } else if (HB_IsLowSurrogate(uc[i]) && HB_IsHighSurrogate(uc[i-1])) {
1625569331642446be05292e3e1f8a51218827168cdclaireho                code = HB_SurrogateToUcs4(uc[i-1], uc[i]);
1635569331642446be05292e3e1f8a51218827168cdclaireho                HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls);
1645569331642446be05292e3e1f8a51218827168cdclaireho                charAttributes[i].charStop = false;
1655569331642446be05292e3e1f8a51218827168cdclaireho            } else {
1665569331642446be05292e3e1f8a51218827168cdclaireho                ncls = HB_LineBreak_AL;
1675569331642446be05292e3e1f8a51218827168cdclaireho            }
1685569331642446be05292e3e1f8a51218827168cdclaireho        }
1695569331642446be05292e3e1f8a51218827168cdclaireho
1705569331642446be05292e3e1f8a51218827168cdclaireho        // set white space and char stop flag
1715569331642446be05292e3e1f8a51218827168cdclaireho        if (ncls >= HB_LineBreak_SP)
1725569331642446be05292e3e1f8a51218827168cdclaireho            charAttributes[i].whiteSpace = true;
1735569331642446be05292e3e1f8a51218827168cdclaireho
1745569331642446be05292e3e1f8a51218827168cdclaireho        HB_LineBreakType lineBreakType = HB_NoBreak;
1755569331642446be05292e3e1f8a51218827168cdclaireho        if (cls >= HB_LineBreak_LF) {
1765569331642446be05292e3e1f8a51218827168cdclaireho            lineBreakType = HB_ForcedBreak;
1775569331642446be05292e3e1f8a51218827168cdclaireho        } else if(cls == HB_LineBreak_CR) {
1785569331642446be05292e3e1f8a51218827168cdclaireho            lineBreakType = (ncls == HB_LineBreak_LF) ? HB_NoBreak : HB_ForcedBreak;
1795569331642446be05292e3e1f8a51218827168cdclaireho        }
1805569331642446be05292e3e1f8a51218827168cdclaireho
1815569331642446be05292e3e1f8a51218827168cdclaireho        if (ncls == HB_LineBreak_SP)
1825569331642446be05292e3e1f8a51218827168cdclaireho            goto next_no_cls_update;
1835569331642446be05292e3e1f8a51218827168cdclaireho        if (ncls >= HB_LineBreak_CR)
1845569331642446be05292e3e1f8a51218827168cdclaireho            goto next;
1855569331642446be05292e3e1f8a51218827168cdclaireho
1865569331642446be05292e3e1f8a51218827168cdclaireho        // two complex chars (thai or lao), thai_attributes might override, but here we do a best guess
1875569331642446be05292e3e1f8a51218827168cdclaireho	if (cls == HB_LineBreak_SA && ncls == HB_LineBreak_SA) {
1885569331642446be05292e3e1f8a51218827168cdclaireho            lineBreakType = HB_Break;
1895569331642446be05292e3e1f8a51218827168cdclaireho            goto next;
1905569331642446be05292e3e1f8a51218827168cdclaireho        }
1915569331642446be05292e3e1f8a51218827168cdclaireho
1925569331642446be05292e3e1f8a51218827168cdclaireho        {
1935569331642446be05292e3e1f8a51218827168cdclaireho            int tcls = ncls;
1945569331642446be05292e3e1f8a51218827168cdclaireho            if (tcls >= HB_LineBreak_SA)
1955569331642446be05292e3e1f8a51218827168cdclaireho                tcls = HB_LineBreak_ID;
1965569331642446be05292e3e1f8a51218827168cdclaireho            if (cls >= HB_LineBreak_SA)
1975569331642446be05292e3e1f8a51218827168cdclaireho                cls = HB_LineBreak_ID;
1985569331642446be05292e3e1f8a51218827168cdclaireho
1995569331642446be05292e3e1f8a51218827168cdclaireho            int brk = breakTable[cls][tcls];
2005569331642446be05292e3e1f8a51218827168cdclaireho            switch (brk) {
2015569331642446be05292e3e1f8a51218827168cdclaireho            case DirectBreak:
2025569331642446be05292e3e1f8a51218827168cdclaireho                lineBreakType = HB_Break;
2035569331642446be05292e3e1f8a51218827168cdclaireho                if (uc[i-1] == 0xad) // soft hyphen
2045569331642446be05292e3e1f8a51218827168cdclaireho                    lineBreakType = HB_SoftHyphen;
2055569331642446be05292e3e1f8a51218827168cdclaireho                break;
2065569331642446be05292e3e1f8a51218827168cdclaireho            case IndirectBreak:
2075569331642446be05292e3e1f8a51218827168cdclaireho                lineBreakType = (lcls == HB_LineBreak_SP) ? HB_Break : HB_NoBreak;
2085569331642446be05292e3e1f8a51218827168cdclaireho                break;
2095569331642446be05292e3e1f8a51218827168cdclaireho            case CombiningIndirectBreak:
2105569331642446be05292e3e1f8a51218827168cdclaireho                lineBreakType = HB_NoBreak;
2115569331642446be05292e3e1f8a51218827168cdclaireho                if (lcls == HB_LineBreak_SP){
2125569331642446be05292e3e1f8a51218827168cdclaireho                    if (i > 1)
2135569331642446be05292e3e1f8a51218827168cdclaireho                        charAttributes[i-2].lineBreakType = HB_Break;
2145569331642446be05292e3e1f8a51218827168cdclaireho                } else {
2155569331642446be05292e3e1f8a51218827168cdclaireho                    goto next_no_cls_update;
2165569331642446be05292e3e1f8a51218827168cdclaireho                }
2175569331642446be05292e3e1f8a51218827168cdclaireho                break;
2185569331642446be05292e3e1f8a51218827168cdclaireho            case CombiningProhibitedBreak:
2195569331642446be05292e3e1f8a51218827168cdclaireho                lineBreakType = HB_NoBreak;
2205569331642446be05292e3e1f8a51218827168cdclaireho                if (lcls != HB_LineBreak_SP)
2215569331642446be05292e3e1f8a51218827168cdclaireho                    goto next_no_cls_update;
2225569331642446be05292e3e1f8a51218827168cdclaireho            case ProhibitedBreak:
2235569331642446be05292e3e1f8a51218827168cdclaireho            default:
2245569331642446be05292e3e1f8a51218827168cdclaireho                break;
2255569331642446be05292e3e1f8a51218827168cdclaireho            }
2265569331642446be05292e3e1f8a51218827168cdclaireho        }
2275569331642446be05292e3e1f8a51218827168cdclaireho    next:
2285569331642446be05292e3e1f8a51218827168cdclaireho        cls = ncls;
2295569331642446be05292e3e1f8a51218827168cdclaireho    next_no_cls_update:
2305569331642446be05292e3e1f8a51218827168cdclaireho        lcls = ncls;
2315569331642446be05292e3e1f8a51218827168cdclaireho        grapheme = ngrapheme;
2325569331642446be05292e3e1f8a51218827168cdclaireho        charAttributes[i-1].lineBreakType = lineBreakType;
2335569331642446be05292e3e1f8a51218827168cdclaireho    }
2345569331642446be05292e3e1f8a51218827168cdclaireho    charAttributes[len-1].lineBreakType = HB_ForcedBreak;
2355569331642446be05292e3e1f8a51218827168cdclaireho}
2365569331642446be05292e3e1f8a51218827168cdclaireho
2375569331642446be05292e3e1f8a51218827168cdclaireho// --------------------------------------------------------------------------------------------------------------------------------------------
2385569331642446be05292e3e1f8a51218827168cdclaireho//
2395569331642446be05292e3e1f8a51218827168cdclaireho// Basic processing
2405569331642446be05292e3e1f8a51218827168cdclaireho//
2415569331642446be05292e3e1f8a51218827168cdclaireho// --------------------------------------------------------------------------------------------------------------------------------------------
2425569331642446be05292e3e1f8a51218827168cdclaireho
2435569331642446be05292e3e1f8a51218827168cdclairehostatic inline void positionCluster(HB_ShaperItem *item, int gfrom,  int glast)
2445569331642446be05292e3e1f8a51218827168cdclaireho{
2455569331642446be05292e3e1f8a51218827168cdclaireho    int nmarks = glast - gfrom;
2465569331642446be05292e3e1f8a51218827168cdclaireho    assert(nmarks > 0);
2475569331642446be05292e3e1f8a51218827168cdclaireho
2485569331642446be05292e3e1f8a51218827168cdclaireho    HB_Glyph *glyphs = item->glyphs;
2495569331642446be05292e3e1f8a51218827168cdclaireho    HB_GlyphAttributes *attributes = item->attributes;
2505569331642446be05292e3e1f8a51218827168cdclaireho
2515569331642446be05292e3e1f8a51218827168cdclaireho    HB_GlyphMetrics baseMetrics;
2525569331642446be05292e3e1f8a51218827168cdclaireho    item->font->klass->getGlyphMetrics(item->font, glyphs[gfrom], &baseMetrics);
2535569331642446be05292e3e1f8a51218827168cdclaireho
2545569331642446be05292e3e1f8a51218827168cdclaireho    if (item->item.script == HB_Script_Hebrew
2555569331642446be05292e3e1f8a51218827168cdclaireho        && (-baseMetrics.y) > baseMetrics.height)
2565569331642446be05292e3e1f8a51218827168cdclaireho        // we need to attach below the baseline, because of the hebrew iud.
2575569331642446be05292e3e1f8a51218827168cdclaireho        baseMetrics.height = -baseMetrics.y;
2585569331642446be05292e3e1f8a51218827168cdclaireho
2595569331642446be05292e3e1f8a51218827168cdclaireho//     qDebug("---> positionCluster: cluster from %d to %d", gfrom, glast);
2605569331642446be05292e3e1f8a51218827168cdclaireho//     qDebug("baseInfo: %f/%f (%f/%f) off=%f/%f", baseInfo.x, baseInfo.y, baseInfo.width, baseInfo.height, baseInfo.xoff, baseInfo.yoff);
2615569331642446be05292e3e1f8a51218827168cdclaireho
2625569331642446be05292e3e1f8a51218827168cdclaireho    HB_Fixed size = item->font->klass->getFontMetric(item->font, HB_FontAscent) / 10;
2635569331642446be05292e3e1f8a51218827168cdclaireho    HB_Fixed offsetBase = HB_FIXED_CONSTANT(1) + (size - HB_FIXED_CONSTANT(4)) / 4;
2645569331642446be05292e3e1f8a51218827168cdclaireho    if (size > HB_FIXED_CONSTANT(4))
2655569331642446be05292e3e1f8a51218827168cdclaireho        offsetBase += HB_FIXED_CONSTANT(4);
2665569331642446be05292e3e1f8a51218827168cdclaireho    else
2675569331642446be05292e3e1f8a51218827168cdclaireho        offsetBase += size;
2685569331642446be05292e3e1f8a51218827168cdclaireho    //qreal offsetBase = (size - 4) / 4 + qMin<qreal>(size, 4) + 1;
2695569331642446be05292e3e1f8a51218827168cdclaireho//     qDebug("offset = %f", offsetBase);
2705569331642446be05292e3e1f8a51218827168cdclaireho
2715569331642446be05292e3e1f8a51218827168cdclaireho    bool rightToLeft = item->item.bidiLevel % 2;
2725569331642446be05292e3e1f8a51218827168cdclaireho
2735569331642446be05292e3e1f8a51218827168cdclaireho    int i;
2745569331642446be05292e3e1f8a51218827168cdclaireho    unsigned char lastCmb = 0;
2755569331642446be05292e3e1f8a51218827168cdclaireho    HB_GlyphMetrics attachmentRect;
2765569331642446be05292e3e1f8a51218827168cdclaireho    memset(&attachmentRect, 0, sizeof(attachmentRect));
2775569331642446be05292e3e1f8a51218827168cdclaireho
2785569331642446be05292e3e1f8a51218827168cdclaireho    for(i = 1; i <= nmarks; i++) {
2795569331642446be05292e3e1f8a51218827168cdclaireho        HB_Glyph mark = glyphs[gfrom+i];
2805569331642446be05292e3e1f8a51218827168cdclaireho        HB_GlyphMetrics markMetrics;
2815569331642446be05292e3e1f8a51218827168cdclaireho        item->font->klass->getGlyphMetrics(item->font, mark, &markMetrics);
2825569331642446be05292e3e1f8a51218827168cdclaireho        HB_FixedPoint p;
2835569331642446be05292e3e1f8a51218827168cdclaireho        p.x = p.y = 0;
2845569331642446be05292e3e1f8a51218827168cdclaireho//          qDebug("markInfo: %f/%f (%f/%f) off=%f/%f", markInfo.x, markInfo.y, markInfo.width, markInfo.height, markInfo.xoff, markInfo.yoff);
2855569331642446be05292e3e1f8a51218827168cdclaireho
2865569331642446be05292e3e1f8a51218827168cdclaireho        HB_Fixed offset = offsetBase;
2875569331642446be05292e3e1f8a51218827168cdclaireho        unsigned char cmb = attributes[gfrom+i].combiningClass;
2885569331642446be05292e3e1f8a51218827168cdclaireho
2895569331642446be05292e3e1f8a51218827168cdclaireho        // ### maybe the whole position determination should move down to heuristicSetGlyphAttributes. Would save some
2905569331642446be05292e3e1f8a51218827168cdclaireho        // bits  in the glyphAttributes structure.
2915569331642446be05292e3e1f8a51218827168cdclaireho        if (cmb < 200) {
2925569331642446be05292e3e1f8a51218827168cdclaireho            // fixed position classes. We approximate by mapping to one of the others.
2935569331642446be05292e3e1f8a51218827168cdclaireho            // currently I added only the ones for arabic, hebrew, lao and thai.
2945569331642446be05292e3e1f8a51218827168cdclaireho
2955569331642446be05292e3e1f8a51218827168cdclaireho            // for Lao and Thai marks with class 0, see below (heuristicSetGlyphAttributes)
2965569331642446be05292e3e1f8a51218827168cdclaireho
2975569331642446be05292e3e1f8a51218827168cdclaireho            // add a bit more offset to arabic, a bit hacky
2985569331642446be05292e3e1f8a51218827168cdclaireho            if (cmb >= 27 && cmb <= 36 && offset < 3)
2995569331642446be05292e3e1f8a51218827168cdclaireho                offset +=1;
3005569331642446be05292e3e1f8a51218827168cdclaireho            // below
3015569331642446be05292e3e1f8a51218827168cdclaireho            if ((cmb >= 10 && cmb <= 18) ||
3025569331642446be05292e3e1f8a51218827168cdclaireho                 cmb == 20 || cmb == 22 ||
3035569331642446be05292e3e1f8a51218827168cdclaireho                 cmb == 29 || cmb == 32)
3045569331642446be05292e3e1f8a51218827168cdclaireho                cmb = HB_Combining_Below;
3055569331642446be05292e3e1f8a51218827168cdclaireho            // above
3065569331642446be05292e3e1f8a51218827168cdclaireho            else if (cmb == 23 || cmb == 27 || cmb == 28 ||
3075569331642446be05292e3e1f8a51218827168cdclaireho                      cmb == 30 || cmb == 31 || (cmb >= 33 && cmb <= 36))
3085569331642446be05292e3e1f8a51218827168cdclaireho                cmb = HB_Combining_Above;
3095569331642446be05292e3e1f8a51218827168cdclaireho            //below-right
3105569331642446be05292e3e1f8a51218827168cdclaireho            else if (cmb == 9 || cmb == 103 || cmb == 118)
3115569331642446be05292e3e1f8a51218827168cdclaireho                cmb = HB_Combining_BelowRight;
3125569331642446be05292e3e1f8a51218827168cdclaireho            // above-right
3135569331642446be05292e3e1f8a51218827168cdclaireho            else if (cmb == 24 || cmb == 107 || cmb == 122)
3145569331642446be05292e3e1f8a51218827168cdclaireho                cmb = HB_Combining_AboveRight;
3155569331642446be05292e3e1f8a51218827168cdclaireho            else if (cmb == 25)
3165569331642446be05292e3e1f8a51218827168cdclaireho                cmb = HB_Combining_AboveLeft;
3175569331642446be05292e3e1f8a51218827168cdclaireho            // fixed:
3185569331642446be05292e3e1f8a51218827168cdclaireho            //  19 21
3195569331642446be05292e3e1f8a51218827168cdclaireho
3205569331642446be05292e3e1f8a51218827168cdclaireho        }
3215569331642446be05292e3e1f8a51218827168cdclaireho
3225569331642446be05292e3e1f8a51218827168cdclaireho        // combining marks of different class don't interact. Reset the rectangle.
3235569331642446be05292e3e1f8a51218827168cdclaireho        if (cmb != lastCmb) {
3245569331642446be05292e3e1f8a51218827168cdclaireho            //qDebug("resetting rect");
3255569331642446be05292e3e1f8a51218827168cdclaireho            attachmentRect = baseMetrics;
3265569331642446be05292e3e1f8a51218827168cdclaireho        }
3275569331642446be05292e3e1f8a51218827168cdclaireho
3285569331642446be05292e3e1f8a51218827168cdclaireho        switch(cmb) {
3295569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_DoubleBelow:
3305569331642446be05292e3e1f8a51218827168cdclaireho                // ### wrong in rtl context!
3315569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_BelowLeft:
3325569331642446be05292e3e1f8a51218827168cdclaireho            p.y += offset;
3335569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_BelowLeftAttached:
3345569331642446be05292e3e1f8a51218827168cdclaireho            p.x += attachmentRect.x - markMetrics.x;
3355569331642446be05292e3e1f8a51218827168cdclaireho            p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
3365569331642446be05292e3e1f8a51218827168cdclaireho            break;
3375569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_Below:
3385569331642446be05292e3e1f8a51218827168cdclaireho            p.y += offset;
3395569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_BelowAttached:
3405569331642446be05292e3e1f8a51218827168cdclaireho            p.x += attachmentRect.x - markMetrics.x;
3415569331642446be05292e3e1f8a51218827168cdclaireho            p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
3425569331642446be05292e3e1f8a51218827168cdclaireho
3435569331642446be05292e3e1f8a51218827168cdclaireho            p.x += (attachmentRect.width - markMetrics.width) / 2;
3445569331642446be05292e3e1f8a51218827168cdclaireho            break;
3455569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_BelowRight:
3465569331642446be05292e3e1f8a51218827168cdclaireho            p.y += offset;
3475569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_BelowRightAttached:
3485569331642446be05292e3e1f8a51218827168cdclaireho            p.x += attachmentRect.x + attachmentRect.width - markMetrics.width - markMetrics.x;
3495569331642446be05292e3e1f8a51218827168cdclaireho            p.y += attachmentRect.y + attachmentRect.height - markMetrics.y;
3505569331642446be05292e3e1f8a51218827168cdclaireho            break;
3515569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_Left:
3525569331642446be05292e3e1f8a51218827168cdclaireho            p.x -= offset;
3535569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_LeftAttached:
3545569331642446be05292e3e1f8a51218827168cdclaireho            break;
3555569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_Right:
3565569331642446be05292e3e1f8a51218827168cdclaireho            p.x += offset;
3575569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_RightAttached:
3585569331642446be05292e3e1f8a51218827168cdclaireho            break;
3595569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_DoubleAbove:
3605569331642446be05292e3e1f8a51218827168cdclaireho            // ### wrong in RTL context!
3615569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_AboveLeft:
3625569331642446be05292e3e1f8a51218827168cdclaireho            p.y -= offset;
3635569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_AboveLeftAttached:
3645569331642446be05292e3e1f8a51218827168cdclaireho            p.x += attachmentRect.x - markMetrics.x;
3655569331642446be05292e3e1f8a51218827168cdclaireho            p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
3665569331642446be05292e3e1f8a51218827168cdclaireho            break;
3675569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_Above:
3685569331642446be05292e3e1f8a51218827168cdclaireho            p.y -= offset;
3695569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_AboveAttached:
3705569331642446be05292e3e1f8a51218827168cdclaireho            p.x += attachmentRect.x - markMetrics.x;
3715569331642446be05292e3e1f8a51218827168cdclaireho            p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
3725569331642446be05292e3e1f8a51218827168cdclaireho
3735569331642446be05292e3e1f8a51218827168cdclaireho            p.x += (attachmentRect.width - markMetrics.width) / 2;
3745569331642446be05292e3e1f8a51218827168cdclaireho            break;
3755569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_AboveRight:
3765569331642446be05292e3e1f8a51218827168cdclaireho            p.y -= offset;
3775569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_AboveRightAttached:
3785569331642446be05292e3e1f8a51218827168cdclaireho            p.x += attachmentRect.x + attachmentRect.width - markMetrics.x - markMetrics.width;
3795569331642446be05292e3e1f8a51218827168cdclaireho            p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
3805569331642446be05292e3e1f8a51218827168cdclaireho            break;
3815569331642446be05292e3e1f8a51218827168cdclaireho
3825569331642446be05292e3e1f8a51218827168cdclaireho        case HB_Combining_IotaSubscript:
3835569331642446be05292e3e1f8a51218827168cdclaireho            default:
3845569331642446be05292e3e1f8a51218827168cdclaireho                break;
3855569331642446be05292e3e1f8a51218827168cdclaireho        }
3865569331642446be05292e3e1f8a51218827168cdclaireho//          qDebug("char=%x combiningClass = %d offset=%f/%f", mark, cmb, p.x(), p.y());
3875569331642446be05292e3e1f8a51218827168cdclaireho        markMetrics.x += p.x;
3885569331642446be05292e3e1f8a51218827168cdclaireho        markMetrics.y += p.y;
3895569331642446be05292e3e1f8a51218827168cdclaireho
3905569331642446be05292e3e1f8a51218827168cdclaireho        HB_GlyphMetrics unitedAttachmentRect = attachmentRect;
3915569331642446be05292e3e1f8a51218827168cdclaireho        unitedAttachmentRect.x = HB_MIN(attachmentRect.x, markMetrics.x);
3925569331642446be05292e3e1f8a51218827168cdclaireho        unitedAttachmentRect.y = HB_MIN(attachmentRect.y, markMetrics.y);
3935569331642446be05292e3e1f8a51218827168cdclaireho        unitedAttachmentRect.width = HB_MAX(attachmentRect.x + attachmentRect.width, markMetrics.x + markMetrics.width) - unitedAttachmentRect.x;
3945569331642446be05292e3e1f8a51218827168cdclaireho        unitedAttachmentRect.height = HB_MAX(attachmentRect.y + attachmentRect.height, markMetrics.y + markMetrics.height) - unitedAttachmentRect.y;
3955569331642446be05292e3e1f8a51218827168cdclaireho        attachmentRect = unitedAttachmentRect;
3965569331642446be05292e3e1f8a51218827168cdclaireho
3975569331642446be05292e3e1f8a51218827168cdclaireho        lastCmb = cmb;
3985569331642446be05292e3e1f8a51218827168cdclaireho        if (rightToLeft) {
3995569331642446be05292e3e1f8a51218827168cdclaireho            item->offsets[gfrom+i].x = p.x;
4005569331642446be05292e3e1f8a51218827168cdclaireho            item->offsets[gfrom+i].y = p.y;
4015569331642446be05292e3e1f8a51218827168cdclaireho        } else {
4025569331642446be05292e3e1f8a51218827168cdclaireho            item->offsets[gfrom+i].x = p.x - baseMetrics.xOffset;
4035569331642446be05292e3e1f8a51218827168cdclaireho            item->offsets[gfrom+i].y = p.y - baseMetrics.yOffset;
4045569331642446be05292e3e1f8a51218827168cdclaireho        }
4055569331642446be05292e3e1f8a51218827168cdclaireho        item->advances[gfrom+i] = 0;
4065569331642446be05292e3e1f8a51218827168cdclaireho    }
4075569331642446be05292e3e1f8a51218827168cdclaireho}
4085569331642446be05292e3e1f8a51218827168cdclaireho
4095569331642446be05292e3e1f8a51218827168cdclairehovoid HB_HeuristicPosition(HB_ShaperItem *item)
4105569331642446be05292e3e1f8a51218827168cdclaireho{
4115569331642446be05292e3e1f8a51218827168cdclaireho    HB_GetGlyphAdvances(item);
4125569331642446be05292e3e1f8a51218827168cdclaireho    HB_GlyphAttributes *attributes = item->attributes;
4135569331642446be05292e3e1f8a51218827168cdclaireho
4145569331642446be05292e3e1f8a51218827168cdclaireho    int cEnd = -1;
4155569331642446be05292e3e1f8a51218827168cdclaireho    int i = item->num_glyphs;
4165569331642446be05292e3e1f8a51218827168cdclaireho    while (i--) {
4175569331642446be05292e3e1f8a51218827168cdclaireho        if (cEnd == -1 && attributes[i].mark) {
4185569331642446be05292e3e1f8a51218827168cdclaireho            cEnd = i;
4195569331642446be05292e3e1f8a51218827168cdclaireho        } else if (cEnd != -1 && !attributes[i].mark) {
4205569331642446be05292e3e1f8a51218827168cdclaireho            positionCluster(item, i, cEnd);
4215569331642446be05292e3e1f8a51218827168cdclaireho            cEnd = -1;
4225569331642446be05292e3e1f8a51218827168cdclaireho        }
4235569331642446be05292e3e1f8a51218827168cdclaireho    }
4245569331642446be05292e3e1f8a51218827168cdclaireho}
4255569331642446be05292e3e1f8a51218827168cdclaireho
4265569331642446be05292e3e1f8a51218827168cdclaireho// set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs
4275569331642446be05292e3e1f8a51218827168cdclaireho// and no reordering.
4285569331642446be05292e3e1f8a51218827168cdclaireho// also computes logClusters heuristically
4295569331642446be05292e3e1f8a51218827168cdclairehovoid HB_HeuristicSetGlyphAttributes(HB_ShaperItem *item)
4305569331642446be05292e3e1f8a51218827168cdclaireho{
4315569331642446be05292e3e1f8a51218827168cdclaireho    const HB_UChar16 *uc = item->string + item->item.pos;
4325569331642446be05292e3e1f8a51218827168cdclaireho    hb_uint32 length = item->item.length;
4335569331642446be05292e3e1f8a51218827168cdclaireho
4345569331642446be05292e3e1f8a51218827168cdclaireho    // ### zeroWidth and justification are missing here!!!!!
4355569331642446be05292e3e1f8a51218827168cdclaireho
4365569331642446be05292e3e1f8a51218827168cdclaireho    // BEGIN android-changed
4375569331642446be05292e3e1f8a51218827168cdclaireho    // We apply the same fix for Chrome to Android.
4385569331642446be05292e3e1f8a51218827168cdclaireho    // Chrome team will talk with upsteam about it.
4395569331642446be05292e3e1f8a51218827168cdclaireho    assert(length <= item->num_glyphs);
4405569331642446be05292e3e1f8a51218827168cdclaireho    // END android-changed
4415569331642446be05292e3e1f8a51218827168cdclaireho
4425569331642446be05292e3e1f8a51218827168cdclaireho//     qDebug("QScriptEngine::heuristicSetGlyphAttributes, num_glyphs=%d", item->num_glyphs);
4435569331642446be05292e3e1f8a51218827168cdclaireho    HB_GlyphAttributes *attributes = item->attributes;
4445569331642446be05292e3e1f8a51218827168cdclaireho    unsigned short *logClusters = item->log_clusters;
4455569331642446be05292e3e1f8a51218827168cdclaireho
4465569331642446be05292e3e1f8a51218827168cdclaireho    hb_uint32 glyph_pos = 0;
4475569331642446be05292e3e1f8a51218827168cdclaireho    hb_uint32 i;
4485569331642446be05292e3e1f8a51218827168cdclaireho    for (i = 0; i < length; i++) {
4495569331642446be05292e3e1f8a51218827168cdclaireho        if (HB_IsHighSurrogate(uc[i]) && i < length - 1
4505569331642446be05292e3e1f8a51218827168cdclaireho            && HB_IsLowSurrogate(uc[i + 1])) {
4515569331642446be05292e3e1f8a51218827168cdclaireho            logClusters[i] = glyph_pos;
4525569331642446be05292e3e1f8a51218827168cdclaireho            logClusters[++i] = glyph_pos;
4535569331642446be05292e3e1f8a51218827168cdclaireho        } else {
4545569331642446be05292e3e1f8a51218827168cdclaireho            logClusters[i] = glyph_pos;
4555569331642446be05292e3e1f8a51218827168cdclaireho        }
4565569331642446be05292e3e1f8a51218827168cdclaireho        ++glyph_pos;
4575569331642446be05292e3e1f8a51218827168cdclaireho    }
4585569331642446be05292e3e1f8a51218827168cdclaireho
4595569331642446be05292e3e1f8a51218827168cdclaireho    // BEGIN android-removed
4605569331642446be05292e3e1f8a51218827168cdclaireho    // We apply the same fix for Chrome to Android.
4615569331642446be05292e3e1f8a51218827168cdclaireho    // Chrome team will talk with upsteam about it
4625569331642446be05292e3e1f8a51218827168cdclaireho    //
4635569331642446be05292e3e1f8a51218827168cdclaireho    // assert(glyph_pos == item->num_glyphs);
4645569331642446be05292e3e1f8a51218827168cdclaireho    //
4655569331642446be05292e3e1f8a51218827168cdclaireho    // END android-removed
4665569331642446be05292e3e1f8a51218827168cdclaireho
4675569331642446be05292e3e1f8a51218827168cdclaireho    // first char in a run is never (treated as) a mark
4685569331642446be05292e3e1f8a51218827168cdclaireho    int cStart = 0;
4695569331642446be05292e3e1f8a51218827168cdclaireho    const bool symbolFont = item->face->isSymbolFont;
4705569331642446be05292e3e1f8a51218827168cdclaireho    attributes[0].mark = false;
4715569331642446be05292e3e1f8a51218827168cdclaireho    attributes[0].clusterStart = true;
4725569331642446be05292e3e1f8a51218827168cdclaireho    attributes[0].dontPrint = (!symbolFont && uc[0] == 0x00ad) || HB_IsControlChar(uc[0]);
4735569331642446be05292e3e1f8a51218827168cdclaireho
4745569331642446be05292e3e1f8a51218827168cdclaireho    int pos = 0;
4755569331642446be05292e3e1f8a51218827168cdclaireho    HB_CharCategory lastCat;
4765569331642446be05292e3e1f8a51218827168cdclaireho    int dummy;
4775569331642446be05292e3e1f8a51218827168cdclaireho    HB_GetUnicodeCharProperties(uc[0], &lastCat, &dummy);
4785569331642446be05292e3e1f8a51218827168cdclaireho    for (i = 1; i < length; ++i) {
4795569331642446be05292e3e1f8a51218827168cdclaireho        if (logClusters[i] == pos)
4805569331642446be05292e3e1f8a51218827168cdclaireho            // same glyph
4815569331642446be05292e3e1f8a51218827168cdclaireho            continue;
4825569331642446be05292e3e1f8a51218827168cdclaireho        ++pos;
4835569331642446be05292e3e1f8a51218827168cdclaireho        while (pos < logClusters[i]) {
4845569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos] = attributes[pos-1];
4855569331642446be05292e3e1f8a51218827168cdclaireho            ++pos;
4865569331642446be05292e3e1f8a51218827168cdclaireho        }
4875569331642446be05292e3e1f8a51218827168cdclaireho        // hide soft-hyphens by default
4885569331642446be05292e3e1f8a51218827168cdclaireho        if ((!symbolFont && uc[i] == 0x00ad) || HB_IsControlChar(uc[i]))
4895569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos].dontPrint = true;
4905569331642446be05292e3e1f8a51218827168cdclaireho        HB_CharCategory cat;
4915569331642446be05292e3e1f8a51218827168cdclaireho        int cmb;
4925569331642446be05292e3e1f8a51218827168cdclaireho        HB_GetUnicodeCharProperties(uc[i], &cat, &cmb);
4935569331642446be05292e3e1f8a51218827168cdclaireho        if (cat != HB_Mark_NonSpacing) {
4945569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos].mark = false;
4955569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos].clusterStart = true;
4965569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos].combiningClass = 0;
4975569331642446be05292e3e1f8a51218827168cdclaireho            cStart = logClusters[i];
4985569331642446be05292e3e1f8a51218827168cdclaireho        } else {
4995569331642446be05292e3e1f8a51218827168cdclaireho            if (cmb == 0) {
5005569331642446be05292e3e1f8a51218827168cdclaireho                // Fix 0 combining classes
5015569331642446be05292e3e1f8a51218827168cdclaireho                if ((uc[pos] & 0xff00) == 0x0e00) {
5025569331642446be05292e3e1f8a51218827168cdclaireho                    // thai or lao
5035569331642446be05292e3e1f8a51218827168cdclaireho                    if (uc[pos] == 0xe31 ||
5045569331642446be05292e3e1f8a51218827168cdclaireho                         uc[pos] == 0xe34 ||
5055569331642446be05292e3e1f8a51218827168cdclaireho                         uc[pos] == 0xe35 ||
5065569331642446be05292e3e1f8a51218827168cdclaireho                         uc[pos] == 0xe36 ||
5075569331642446be05292e3e1f8a51218827168cdclaireho                         uc[pos] == 0xe37 ||
5085569331642446be05292e3e1f8a51218827168cdclaireho                         uc[pos] == 0xe47 ||
5095569331642446be05292e3e1f8a51218827168cdclaireho                         uc[pos] == 0xe4c ||
5105569331642446be05292e3e1f8a51218827168cdclaireho                         uc[pos] == 0xe4d ||
5115569331642446be05292e3e1f8a51218827168cdclaireho                         uc[pos] == 0xe4e) {
5125569331642446be05292e3e1f8a51218827168cdclaireho                        cmb = HB_Combining_AboveRight;
5135569331642446be05292e3e1f8a51218827168cdclaireho                    } else if (uc[pos] == 0xeb1 ||
5145569331642446be05292e3e1f8a51218827168cdclaireho                                uc[pos] == 0xeb4 ||
5155569331642446be05292e3e1f8a51218827168cdclaireho                                uc[pos] == 0xeb5 ||
5165569331642446be05292e3e1f8a51218827168cdclaireho                                uc[pos] == 0xeb6 ||
5175569331642446be05292e3e1f8a51218827168cdclaireho                                uc[pos] == 0xeb7 ||
5185569331642446be05292e3e1f8a51218827168cdclaireho                                uc[pos] == 0xebb ||
5195569331642446be05292e3e1f8a51218827168cdclaireho                                uc[pos] == 0xecc ||
5205569331642446be05292e3e1f8a51218827168cdclaireho                                uc[pos] == 0xecd) {
5215569331642446be05292e3e1f8a51218827168cdclaireho                        cmb = HB_Combining_Above;
5225569331642446be05292e3e1f8a51218827168cdclaireho                    } else if (uc[pos] == 0xebc) {
5235569331642446be05292e3e1f8a51218827168cdclaireho                        cmb = HB_Combining_Below;
5245569331642446be05292e3e1f8a51218827168cdclaireho                    }
5255569331642446be05292e3e1f8a51218827168cdclaireho                }
5265569331642446be05292e3e1f8a51218827168cdclaireho            }
5275569331642446be05292e3e1f8a51218827168cdclaireho
5285569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos].mark = true;
5295569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos].clusterStart = false;
5305569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos].combiningClass = cmb;
5315569331642446be05292e3e1f8a51218827168cdclaireho            logClusters[i] = cStart;
5325569331642446be05292e3e1f8a51218827168cdclaireho        }
5335569331642446be05292e3e1f8a51218827168cdclaireho        // one gets an inter character justification point if the current char is not a non spacing mark.
5345569331642446be05292e3e1f8a51218827168cdclaireho        // as then the current char belongs to the last one and one gets a space justification point
5355569331642446be05292e3e1f8a51218827168cdclaireho        // after the space char.
5365569331642446be05292e3e1f8a51218827168cdclaireho        if (lastCat == HB_Separator_Space)
5375569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos-1].justification = HB_Space;
5385569331642446be05292e3e1f8a51218827168cdclaireho        else if (cat != HB_Mark_NonSpacing)
5395569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos-1].justification = HB_Character;
5405569331642446be05292e3e1f8a51218827168cdclaireho        else
5415569331642446be05292e3e1f8a51218827168cdclaireho            attributes[pos-1].justification = HB_NoJustification;
5425569331642446be05292e3e1f8a51218827168cdclaireho
5435569331642446be05292e3e1f8a51218827168cdclaireho        lastCat = cat;
5445569331642446be05292e3e1f8a51218827168cdclaireho    }
5455569331642446be05292e3e1f8a51218827168cdclaireho    pos = logClusters[length-1];
5465569331642446be05292e3e1f8a51218827168cdclaireho    if (lastCat == HB_Separator_Space)
5475569331642446be05292e3e1f8a51218827168cdclaireho        attributes[pos].justification = HB_Space;
5485569331642446be05292e3e1f8a51218827168cdclaireho    else
5495569331642446be05292e3e1f8a51218827168cdclaireho        attributes[pos].justification = HB_Character;
5505569331642446be05292e3e1f8a51218827168cdclaireho}
5515569331642446be05292e3e1f8a51218827168cdclaireho
5525569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE
5535569331642446be05292e3e1f8a51218827168cdclairehostatic const HB_OpenTypeFeature basic_features[] = {
5545569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
5555569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('l', 'i', 'g', 'a'), CcmpProperty },
5565569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('c', 'l', 'i', 'g'), CcmpProperty },
5575569331642446be05292e3e1f8a51218827168cdclaireho    {0, 0}
5585569331642446be05292e3e1f8a51218827168cdclaireho};
5595569331642446be05292e3e1f8a51218827168cdclaireho#endif
5605569331642446be05292e3e1f8a51218827168cdclaireho
5615569331642446be05292e3e1f8a51218827168cdclairehoHB_Bool HB_ConvertStringToGlyphIndices(HB_ShaperItem *shaper_item)
5625569331642446be05292e3e1f8a51218827168cdclaireho{
5635569331642446be05292e3e1f8a51218827168cdclaireho    if (shaper_item->glyphIndicesPresent) {
5645569331642446be05292e3e1f8a51218827168cdclaireho        shaper_item->num_glyphs = shaper_item->initialGlyphCount;
5655569331642446be05292e3e1f8a51218827168cdclaireho        shaper_item->glyphIndicesPresent = false;
5665569331642446be05292e3e1f8a51218827168cdclaireho        return true;
5675569331642446be05292e3e1f8a51218827168cdclaireho    }
5685569331642446be05292e3e1f8a51218827168cdclaireho    return shaper_item->font->klass
5695569331642446be05292e3e1f8a51218827168cdclaireho           ->convertStringToGlyphIndices(shaper_item->font,
5705569331642446be05292e3e1f8a51218827168cdclaireho                                         shaper_item->string + shaper_item->item.pos, shaper_item->item.length,
5715569331642446be05292e3e1f8a51218827168cdclaireho                                         shaper_item->glyphs, &shaper_item->num_glyphs,
5725569331642446be05292e3e1f8a51218827168cdclaireho                                         shaper_item->item.bidiLevel % 2);
5735569331642446be05292e3e1f8a51218827168cdclaireho}
5745569331642446be05292e3e1f8a51218827168cdclaireho
5755569331642446be05292e3e1f8a51218827168cdclairehoHB_Bool HB_BasicShape(HB_ShaperItem *shaper_item)
5765569331642446be05292e3e1f8a51218827168cdclaireho{
5775569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE
5785569331642446be05292e3e1f8a51218827168cdclaireho    const int availableGlyphs = shaper_item->num_glyphs;
5795569331642446be05292e3e1f8a51218827168cdclaireho#endif
5805569331642446be05292e3e1f8a51218827168cdclaireho
5815569331642446be05292e3e1f8a51218827168cdclaireho    if (!HB_ConvertStringToGlyphIndices(shaper_item))
5825569331642446be05292e3e1f8a51218827168cdclaireho        return false;
5835569331642446be05292e3e1f8a51218827168cdclaireho
5845569331642446be05292e3e1f8a51218827168cdclaireho    HB_HeuristicSetGlyphAttributes(shaper_item);
5855569331642446be05292e3e1f8a51218827168cdclaireho
5865569331642446be05292e3e1f8a51218827168cdclaireho#ifndef NO_OPENTYPE
5875569331642446be05292e3e1f8a51218827168cdclaireho    if (HB_SelectScript(shaper_item, basic_features)) {
5885569331642446be05292e3e1f8a51218827168cdclaireho        HB_OpenTypeShape(shaper_item, /*properties*/0);
5895569331642446be05292e3e1f8a51218827168cdclaireho        return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/true);
5905569331642446be05292e3e1f8a51218827168cdclaireho    }
5915569331642446be05292e3e1f8a51218827168cdclaireho#endif
5925569331642446be05292e3e1f8a51218827168cdclaireho
5935569331642446be05292e3e1f8a51218827168cdclaireho    HB_HeuristicPosition(shaper_item);
5945569331642446be05292e3e1f8a51218827168cdclaireho    return true;
5955569331642446be05292e3e1f8a51218827168cdclaireho}
5965569331642446be05292e3e1f8a51218827168cdclaireho
5975569331642446be05292e3e1f8a51218827168cdclairehoconst HB_ScriptEngine HB_ScriptEngines[] = {
5985569331642446be05292e3e1f8a51218827168cdclaireho    // Common
5995569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, 0},
6005569331642446be05292e3e1f8a51218827168cdclaireho    // Greek
6015569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, 0},
6025569331642446be05292e3e1f8a51218827168cdclaireho    // Cyrillic
6035569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, 0},
6045569331642446be05292e3e1f8a51218827168cdclaireho    // Armenian
6055569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, 0},
6065569331642446be05292e3e1f8a51218827168cdclaireho    // Hebrew
6075569331642446be05292e3e1f8a51218827168cdclaireho    { HB_HebrewShape, 0 },
6085569331642446be05292e3e1f8a51218827168cdclaireho    // Arabic
6095569331642446be05292e3e1f8a51218827168cdclaireho    { HB_ArabicShape, 0},
6105569331642446be05292e3e1f8a51218827168cdclaireho    // Syriac
6115569331642446be05292e3e1f8a51218827168cdclaireho    { HB_ArabicShape, 0},
6125569331642446be05292e3e1f8a51218827168cdclaireho    // Thaana
6135569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, 0 },
6145569331642446be05292e3e1f8a51218827168cdclaireho    // Devanagari
6155569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6165569331642446be05292e3e1f8a51218827168cdclaireho    // Bengali
6175569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6185569331642446be05292e3e1f8a51218827168cdclaireho    // Gurmukhi
6195569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6205569331642446be05292e3e1f8a51218827168cdclaireho    // Gujarati
6215569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6225569331642446be05292e3e1f8a51218827168cdclaireho    // Oriya
6235569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6245569331642446be05292e3e1f8a51218827168cdclaireho    // Tamil
6255569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6265569331642446be05292e3e1f8a51218827168cdclaireho    // Telugu
6275569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6285569331642446be05292e3e1f8a51218827168cdclaireho    // Kannada
6295569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6305569331642446be05292e3e1f8a51218827168cdclaireho    // Malayalam
6315569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6325569331642446be05292e3e1f8a51218827168cdclaireho    // Sinhala
6335569331642446be05292e3e1f8a51218827168cdclaireho    { HB_IndicShape, HB_IndicAttributes },
6345569331642446be05292e3e1f8a51218827168cdclaireho    // Thai
6355569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, HB_ThaiAttributes },
6365569331642446be05292e3e1f8a51218827168cdclaireho    // Lao
6375569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, 0 },
6385569331642446be05292e3e1f8a51218827168cdclaireho    // Tibetan
6395569331642446be05292e3e1f8a51218827168cdclaireho    { HB_TibetanShape, HB_TibetanAttributes },
6405569331642446be05292e3e1f8a51218827168cdclaireho    // Myanmar
6415569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MyanmarShape, HB_MyanmarAttributes },
6425569331642446be05292e3e1f8a51218827168cdclaireho    // Georgian
6435569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, 0 },
6445569331642446be05292e3e1f8a51218827168cdclaireho    // Hangul
6455569331642446be05292e3e1f8a51218827168cdclaireho    { HB_HangulShape, 0 },
6465569331642446be05292e3e1f8a51218827168cdclaireho    // Ogham
6475569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, 0 },
6485569331642446be05292e3e1f8a51218827168cdclaireho    // Runic
6495569331642446be05292e3e1f8a51218827168cdclaireho    { HB_BasicShape, 0 },
6505569331642446be05292e3e1f8a51218827168cdclaireho    // Khmer
6515569331642446be05292e3e1f8a51218827168cdclaireho    { HB_KhmerShape, HB_KhmerAttributes },
6525569331642446be05292e3e1f8a51218827168cdclaireho    // N'Ko
6535569331642446be05292e3e1f8a51218827168cdclaireho    { HB_ArabicShape, 0}
6545569331642446be05292e3e1f8a51218827168cdclaireho};
6555569331642446be05292e3e1f8a51218827168cdclaireho
6565569331642446be05292e3e1f8a51218827168cdclairehovoid HB_GetCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength,
6575569331642446be05292e3e1f8a51218827168cdclaireho                          const HB_ScriptItem *items, hb_uint32 numItems,
6585569331642446be05292e3e1f8a51218827168cdclaireho                          HB_CharAttributes *attributes)
6595569331642446be05292e3e1f8a51218827168cdclaireho{
6605569331642446be05292e3e1f8a51218827168cdclaireho    calcLineBreaks(string, stringLength, attributes);
6615569331642446be05292e3e1f8a51218827168cdclaireho
6625569331642446be05292e3e1f8a51218827168cdclaireho    for (hb_uint32 i = 0; i < numItems; ++i) {
6635569331642446be05292e3e1f8a51218827168cdclaireho        HB_Script script = items[i].script;
6645569331642446be05292e3e1f8a51218827168cdclaireho        if (script == HB_Script_Inherited)
6655569331642446be05292e3e1f8a51218827168cdclaireho            script = HB_Script_Common;
6665569331642446be05292e3e1f8a51218827168cdclaireho        HB_AttributeFunction attributeFunction = HB_ScriptEngines[script].charAttributes;
6675569331642446be05292e3e1f8a51218827168cdclaireho        if (!attributeFunction)
6685569331642446be05292e3e1f8a51218827168cdclaireho            continue;
6695569331642446be05292e3e1f8a51218827168cdclaireho        attributeFunction(script, string, items[i].pos, items[i].length, attributes);
6705569331642446be05292e3e1f8a51218827168cdclaireho    }
6715569331642446be05292e3e1f8a51218827168cdclaireho}
6725569331642446be05292e3e1f8a51218827168cdclaireho
6735569331642446be05292e3e1f8a51218827168cdclaireho
6745569331642446be05292e3e1f8a51218827168cdclairehoenum BreakRule { NoBreak = 0, Break = 1, Middle = 2 };
6755569331642446be05292e3e1f8a51218827168cdclaireho
6765569331642446be05292e3e1f8a51218827168cdclairehostatic const hb_uint8 wordbreakTable[HB_Word_ExtendNumLet + 1][HB_Word_ExtendNumLet + 1] = {
6775569331642446be05292e3e1f8a51218827168cdclaireho//        Other    Format   Katakana ALetter  MidLetter MidNum  Numeric  ExtendNumLet
6785569331642446be05292e3e1f8a51218827168cdclaireho    {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // Other
6795569331642446be05292e3e1f8a51218827168cdclaireho    {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // Format
6805569331642446be05292e3e1f8a51218827168cdclaireho    {   Break,   Break, NoBreak,   Break,   Break,   Break,   Break, NoBreak }, // Katakana
6815569331642446be05292e3e1f8a51218827168cdclaireho    {   Break,   Break,   Break, NoBreak,  Middle,   Break, NoBreak, NoBreak }, // ALetter
6825569331642446be05292e3e1f8a51218827168cdclaireho    {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // MidLetter
6835569331642446be05292e3e1f8a51218827168cdclaireho    {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // MidNum
6845569331642446be05292e3e1f8a51218827168cdclaireho    {   Break,   Break,   Break, NoBreak,   Break,  Middle, NoBreak, NoBreak }, // Numeric
6855569331642446be05292e3e1f8a51218827168cdclaireho    {   Break,   Break, NoBreak, NoBreak,   Break,   Break, NoBreak, NoBreak }, // ExtendNumLet
6865569331642446be05292e3e1f8a51218827168cdclaireho};
6875569331642446be05292e3e1f8a51218827168cdclaireho
6885569331642446be05292e3e1f8a51218827168cdclairehovoid HB_GetWordBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
6895569331642446be05292e3e1f8a51218827168cdclaireho                          const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/,
6905569331642446be05292e3e1f8a51218827168cdclaireho                          HB_CharAttributes *attributes)
6915569331642446be05292e3e1f8a51218827168cdclaireho{
6925569331642446be05292e3e1f8a51218827168cdclaireho    if (stringLength == 0)
6935569331642446be05292e3e1f8a51218827168cdclaireho        return;
6945569331642446be05292e3e1f8a51218827168cdclaireho    unsigned int brk = HB_GetWordClass(string[0]);
6955569331642446be05292e3e1f8a51218827168cdclaireho    attributes[0].wordBoundary = true;
6965569331642446be05292e3e1f8a51218827168cdclaireho    for (hb_uint32 i = 1; i < stringLength; ++i) {
6975569331642446be05292e3e1f8a51218827168cdclaireho        if (!attributes[i].charStop) {
6985569331642446be05292e3e1f8a51218827168cdclaireho            attributes[i].wordBoundary = false;
6995569331642446be05292e3e1f8a51218827168cdclaireho            continue;
7005569331642446be05292e3e1f8a51218827168cdclaireho        }
7015569331642446be05292e3e1f8a51218827168cdclaireho        hb_uint32 nbrk = HB_GetWordClass(string[i]);
7025569331642446be05292e3e1f8a51218827168cdclaireho        if (nbrk == HB_Word_Format) {
7035569331642446be05292e3e1f8a51218827168cdclaireho            attributes[i].wordBoundary = (HB_GetSentenceClass(string[i-1]) == HB_Sentence_Sep);
7045569331642446be05292e3e1f8a51218827168cdclaireho            continue;
7055569331642446be05292e3e1f8a51218827168cdclaireho        }
7065569331642446be05292e3e1f8a51218827168cdclaireho        BreakRule rule = (BreakRule)wordbreakTable[brk][nbrk];
7075569331642446be05292e3e1f8a51218827168cdclaireho        if (rule == Middle) {
7085569331642446be05292e3e1f8a51218827168cdclaireho            rule = Break;
7095569331642446be05292e3e1f8a51218827168cdclaireho            hb_uint32 lookahead = i + 1;
7105569331642446be05292e3e1f8a51218827168cdclaireho            while (lookahead < stringLength) {
7115569331642446be05292e3e1f8a51218827168cdclaireho                hb_uint32 testbrk = HB_GetWordClass(string[lookahead]);
7125569331642446be05292e3e1f8a51218827168cdclaireho                if (testbrk == HB_Word_Format && HB_GetSentenceClass(string[lookahead]) != HB_Sentence_Sep) {
7135569331642446be05292e3e1f8a51218827168cdclaireho                    ++lookahead;
7145569331642446be05292e3e1f8a51218827168cdclaireho                    continue;
7155569331642446be05292e3e1f8a51218827168cdclaireho                }
7165569331642446be05292e3e1f8a51218827168cdclaireho                if (testbrk == brk) {
7175569331642446be05292e3e1f8a51218827168cdclaireho                    rule = NoBreak;
7185569331642446be05292e3e1f8a51218827168cdclaireho                    while (i < lookahead)
7195569331642446be05292e3e1f8a51218827168cdclaireho                        attributes[i++].wordBoundary = false;
7205569331642446be05292e3e1f8a51218827168cdclaireho                    nbrk = testbrk;
7215569331642446be05292e3e1f8a51218827168cdclaireho                }
7225569331642446be05292e3e1f8a51218827168cdclaireho                break;
7235569331642446be05292e3e1f8a51218827168cdclaireho            }
7245569331642446be05292e3e1f8a51218827168cdclaireho        }
7255569331642446be05292e3e1f8a51218827168cdclaireho        attributes[i].wordBoundary = (rule == Break);
7265569331642446be05292e3e1f8a51218827168cdclaireho        brk = nbrk;
7275569331642446be05292e3e1f8a51218827168cdclaireho    }
7285569331642446be05292e3e1f8a51218827168cdclaireho}
7295569331642446be05292e3e1f8a51218827168cdclaireho
7305569331642446be05292e3e1f8a51218827168cdclaireho
7315569331642446be05292e3e1f8a51218827168cdclairehoenum SentenceBreakStates {
7325569331642446be05292e3e1f8a51218827168cdclaireho    SB_Initial,
7335569331642446be05292e3e1f8a51218827168cdclaireho    SB_Upper,
7345569331642446be05292e3e1f8a51218827168cdclaireho    SB_UpATerm,
7355569331642446be05292e3e1f8a51218827168cdclaireho    SB_ATerm,
7365569331642446be05292e3e1f8a51218827168cdclaireho    SB_ATermC,
7375569331642446be05292e3e1f8a51218827168cdclaireho    SB_ACS,
7385569331642446be05292e3e1f8a51218827168cdclaireho    SB_STerm,
7395569331642446be05292e3e1f8a51218827168cdclaireho    SB_STermC,
7405569331642446be05292e3e1f8a51218827168cdclaireho    SB_SCS,
7415569331642446be05292e3e1f8a51218827168cdclaireho    SB_BAfter,
7425569331642446be05292e3e1f8a51218827168cdclaireho    SB_Break,
7435569331642446be05292e3e1f8a51218827168cdclaireho    SB_Look
7445569331642446be05292e3e1f8a51218827168cdclaireho};
7455569331642446be05292e3e1f8a51218827168cdclaireho
7465569331642446be05292e3e1f8a51218827168cdclairehostatic const hb_uint8 sentenceBreakTable[HB_Sentence_Close + 1][HB_Sentence_Close + 1] = {
7475569331642446be05292e3e1f8a51218827168cdclaireho//        Other       Sep         Format      Sp          Lower       Upper       OLetter     Numeric     ATerm       STerm       Close
7485569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Initial, SB_BAfter , SB_Initial, SB_Initial, SB_Initial, SB_Upper  , SB_Initial, SB_Initial, SB_ATerm  , SB_STerm  , SB_Initial }, // SB_Initial,
7495569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Initial, SB_BAfter , SB_Upper  , SB_Initial, SB_Initial, SB_Upper  , SB_Initial, SB_Initial, SB_UpATerm, SB_STerm  , SB_Initial }, // SB_Upper
7505569331642446be05292e3e1f8a51218827168cdclaireho
7515569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Look   , SB_BAfter , SB_UpATerm, SB_ACS    , SB_Initial, SB_Upper  , SB_Break  , SB_Initial, SB_ATerm  , SB_STerm  , SB_ATermC  }, // SB_UpATerm
7525569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Look   , SB_BAfter , SB_ATerm  , SB_ACS    , SB_Initial, SB_Break  , SB_Break  , SB_Initial, SB_ATerm  , SB_STerm  , SB_ATermC  }, // SB_ATerm
7535569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Look   , SB_BAfter , SB_ATermC , SB_ACS    , SB_Initial, SB_Break  , SB_Break  , SB_Look   , SB_ATerm  , SB_STerm  , SB_ATermC  }, // SB_ATermC,
7545569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Look   , SB_BAfter , SB_ACS    , SB_ACS    , SB_Initial, SB_Break  , SB_Break  , SB_Look   , SB_ATerm  , SB_STerm  , SB_Look    }, // SB_ACS,
7555569331642446be05292e3e1f8a51218827168cdclaireho
7565569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Break  , SB_BAfter , SB_STerm  , SB_SCS    , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_ATerm  , SB_STerm  , SB_STermC  }, // SB_STerm,
7575569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Break  , SB_BAfter , SB_STermC , SB_SCS    , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_ATerm  , SB_STerm  , SB_STermC  }, // SB_STermC,
7585569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Break  , SB_BAfter , SB_SCS    , SB_SCS    , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_ATerm  , SB_STerm  , SB_Break   }, // SB_SCS,
7595569331642446be05292e3e1f8a51218827168cdclaireho      { SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break   }, // SB_BAfter,
7605569331642446be05292e3e1f8a51218827168cdclaireho};
7615569331642446be05292e3e1f8a51218827168cdclaireho
7625569331642446be05292e3e1f8a51218827168cdclairehovoid HB_GetSentenceBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
7635569331642446be05292e3e1f8a51218827168cdclaireho                              const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/,
7645569331642446be05292e3e1f8a51218827168cdclaireho                              HB_CharAttributes *attributes)
7655569331642446be05292e3e1f8a51218827168cdclaireho{
7665569331642446be05292e3e1f8a51218827168cdclaireho    if (stringLength == 0)
7675569331642446be05292e3e1f8a51218827168cdclaireho        return;
7685569331642446be05292e3e1f8a51218827168cdclaireho    hb_uint32 brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[0])];
7695569331642446be05292e3e1f8a51218827168cdclaireho    attributes[0].sentenceBoundary = true;
7705569331642446be05292e3e1f8a51218827168cdclaireho    for (hb_uint32 i = 1; i < stringLength; ++i) {
7715569331642446be05292e3e1f8a51218827168cdclaireho        if (!attributes[i].charStop) {
7725569331642446be05292e3e1f8a51218827168cdclaireho            attributes[i].sentenceBoundary = false;
7735569331642446be05292e3e1f8a51218827168cdclaireho            continue;
7745569331642446be05292e3e1f8a51218827168cdclaireho        }
7755569331642446be05292e3e1f8a51218827168cdclaireho        brk = sentenceBreakTable[brk][HB_GetSentenceClass(string[i])];
7765569331642446be05292e3e1f8a51218827168cdclaireho        if (brk == SB_Look) {
7775569331642446be05292e3e1f8a51218827168cdclaireho            brk = SB_Break;
7785569331642446be05292e3e1f8a51218827168cdclaireho            hb_uint32 lookahead = i + 1;
7795569331642446be05292e3e1f8a51218827168cdclaireho            while (lookahead < stringLength) {
7805569331642446be05292e3e1f8a51218827168cdclaireho                hb_uint32 sbrk = HB_GetSentenceClass(string[lookahead]);
7815569331642446be05292e3e1f8a51218827168cdclaireho                if (sbrk != HB_Sentence_Other && sbrk != HB_Sentence_Numeric && sbrk != HB_Sentence_Close) {
7825569331642446be05292e3e1f8a51218827168cdclaireho                    break;
7835569331642446be05292e3e1f8a51218827168cdclaireho                } else if (sbrk == HB_Sentence_Lower) {
7845569331642446be05292e3e1f8a51218827168cdclaireho                    brk = SB_Initial;
7855569331642446be05292e3e1f8a51218827168cdclaireho                    break;
7865569331642446be05292e3e1f8a51218827168cdclaireho                }
7875569331642446be05292e3e1f8a51218827168cdclaireho                ++lookahead;
7885569331642446be05292e3e1f8a51218827168cdclaireho            }
7895569331642446be05292e3e1f8a51218827168cdclaireho            if (brk == SB_Initial) {
7905569331642446be05292e3e1f8a51218827168cdclaireho                while (i < lookahead)
7915569331642446be05292e3e1f8a51218827168cdclaireho                    attributes[i++].sentenceBoundary = false;
7925569331642446be05292e3e1f8a51218827168cdclaireho            }
7935569331642446be05292e3e1f8a51218827168cdclaireho        }
7945569331642446be05292e3e1f8a51218827168cdclaireho        if (brk == SB_Break) {
7955569331642446be05292e3e1f8a51218827168cdclaireho            attributes[i].sentenceBoundary = true;
7965569331642446be05292e3e1f8a51218827168cdclaireho            brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[i])];
7975569331642446be05292e3e1f8a51218827168cdclaireho        } else {
7985569331642446be05292e3e1f8a51218827168cdclaireho            attributes[i].sentenceBoundary = false;
7995569331642446be05292e3e1f8a51218827168cdclaireho        }
8005569331642446be05292e3e1f8a51218827168cdclaireho    }
8015569331642446be05292e3e1f8a51218827168cdclaireho}
8025569331642446be05292e3e1f8a51218827168cdclaireho
8035569331642446be05292e3e1f8a51218827168cdclaireho
8045569331642446be05292e3e1f8a51218827168cdclairehostatic inline char *tag_to_string(HB_UInt tag)
8055569331642446be05292e3e1f8a51218827168cdclaireho{
8065569331642446be05292e3e1f8a51218827168cdclaireho    static char string[5];
8075569331642446be05292e3e1f8a51218827168cdclaireho    string[0] = (tag >> 24)&0xff;
8085569331642446be05292e3e1f8a51218827168cdclaireho    string[1] = (tag >> 16)&0xff;
8095569331642446be05292e3e1f8a51218827168cdclaireho    string[2] = (tag >> 8)&0xff;
8105569331642446be05292e3e1f8a51218827168cdclaireho    string[3] = tag&0xff;
8115569331642446be05292e3e1f8a51218827168cdclaireho    string[4] = 0;
8125569331642446be05292e3e1f8a51218827168cdclaireho    return string;
8135569331642446be05292e3e1f8a51218827168cdclaireho}
8145569331642446be05292e3e1f8a51218827168cdclaireho
8155569331642446be05292e3e1f8a51218827168cdclaireho#ifdef OT_DEBUG
8165569331642446be05292e3e1f8a51218827168cdclairehostatic void dump_string(HB_Buffer buffer)
8175569331642446be05292e3e1f8a51218827168cdclaireho{
8185569331642446be05292e3e1f8a51218827168cdclaireho    for (uint i = 0; i < buffer->in_length; ++i) {
8195569331642446be05292e3e1f8a51218827168cdclaireho        qDebug("    %x: cluster=%d", buffer->in_string[i].gindex, buffer->in_string[i].cluster);
8205569331642446be05292e3e1f8a51218827168cdclaireho    }
8215569331642446be05292e3e1f8a51218827168cdclaireho}
8225569331642446be05292e3e1f8a51218827168cdclaireho#define DEBUG printf
8235569331642446be05292e3e1f8a51218827168cdclaireho#else
8245569331642446be05292e3e1f8a51218827168cdclaireho#define DEBUG if (1) ; else printf
8255569331642446be05292e3e1f8a51218827168cdclaireho#endif
8265569331642446be05292e3e1f8a51218827168cdclaireho
8275569331642446be05292e3e1f8a51218827168cdclaireho#define DefaultLangSys 0xffff
8285569331642446be05292e3e1f8a51218827168cdclaireho#define DefaultScript HB_MAKE_TAG('D', 'F', 'L', 'T')
8295569331642446be05292e3e1f8a51218827168cdclaireho
8305569331642446be05292e3e1f8a51218827168cdclairehoenum {
8315569331642446be05292e3e1f8a51218827168cdclaireho    RequiresGsub = 1,
8325569331642446be05292e3e1f8a51218827168cdclaireho    RequiresGpos = 2
8335569331642446be05292e3e1f8a51218827168cdclaireho};
8345569331642446be05292e3e1f8a51218827168cdclaireho
8355569331642446be05292e3e1f8a51218827168cdclairehostruct OTScripts {
8365569331642446be05292e3e1f8a51218827168cdclaireho    unsigned int tag;
8375569331642446be05292e3e1f8a51218827168cdclaireho    int flags;
8385569331642446be05292e3e1f8a51218827168cdclaireho};
8395569331642446be05292e3e1f8a51218827168cdclairehostatic const OTScripts ot_scripts [] = {
8405569331642446be05292e3e1f8a51218827168cdclaireho    // Common
8415569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('l', 'a', 't', 'n'), 0 },
8425569331642446be05292e3e1f8a51218827168cdclaireho    // Greek
8435569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('g', 'r', 'e', 'k'), 0 },
8445569331642446be05292e3e1f8a51218827168cdclaireho    // Cyrillic
8455569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('c', 'y', 'r', 'l'), 0 },
8465569331642446be05292e3e1f8a51218827168cdclaireho    // Armenian
8475569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('a', 'r', 'm', 'n'), 0 },
8485569331642446be05292e3e1f8a51218827168cdclaireho    // Hebrew
8495569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('h', 'e', 'b', 'r'), 1 },
8505569331642446be05292e3e1f8a51218827168cdclaireho    // Arabic
8515569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('a', 'r', 'a', 'b'), 1 },
8525569331642446be05292e3e1f8a51218827168cdclaireho    // Syriac
8535569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('s', 'y', 'r', 'c'), 1 },
8545569331642446be05292e3e1f8a51218827168cdclaireho    // Thaana
8555569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('t', 'h', 'a', 'a'), 1 },
8565569331642446be05292e3e1f8a51218827168cdclaireho    // Devanagari
8575569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('d', 'e', 'v', 'a'), 1 },
8585569331642446be05292e3e1f8a51218827168cdclaireho    // Bengali
8595569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('b', 'e', 'n', 'g'), 1 },
8605569331642446be05292e3e1f8a51218827168cdclaireho    // Gurmukhi
8615569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('g', 'u', 'r', 'u'), 1 },
8625569331642446be05292e3e1f8a51218827168cdclaireho    // Gujarati
8635569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('g', 'u', 'j', 'r'), 1 },
8645569331642446be05292e3e1f8a51218827168cdclaireho    // Oriya
8655569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('o', 'r', 'y', 'a'), 1 },
8665569331642446be05292e3e1f8a51218827168cdclaireho    // Tamil
8675569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('t', 'a', 'm', 'l'), 1 },
8685569331642446be05292e3e1f8a51218827168cdclaireho    // Telugu
8695569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('t', 'e', 'l', 'u'), 1 },
8705569331642446be05292e3e1f8a51218827168cdclaireho    // Kannada
8715569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('k', 'n', 'd', 'a'), 1 },
8725569331642446be05292e3e1f8a51218827168cdclaireho    // Malayalam
8735569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('m', 'l', 'y', 'm'), 1 },
8745569331642446be05292e3e1f8a51218827168cdclaireho    // Sinhala
8755569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('s', 'i', 'n', 'h'), 1 },
8765569331642446be05292e3e1f8a51218827168cdclaireho    // Thai
8775569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('t', 'h', 'a', 'i'), 1 },
8785569331642446be05292e3e1f8a51218827168cdclaireho    // Lao
8795569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('l', 'a', 'o', ' '), 1 },
8805569331642446be05292e3e1f8a51218827168cdclaireho    // Tibetan
8815569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('t', 'i', 'b', 't'), 1 },
8825569331642446be05292e3e1f8a51218827168cdclaireho    // Myanmar
8835569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('m', 'y', 'm', 'r'), 1 },
8845569331642446be05292e3e1f8a51218827168cdclaireho    // Georgian
8855569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('g', 'e', 'o', 'r'), 0 },
8865569331642446be05292e3e1f8a51218827168cdclaireho    // Hangul
8875569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('h', 'a', 'n', 'g'), 1 },
8885569331642446be05292e3e1f8a51218827168cdclaireho    // Ogham
8895569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('o', 'g', 'a', 'm'), 0 },
8905569331642446be05292e3e1f8a51218827168cdclaireho    // Runic
8915569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('r', 'u', 'n', 'r'), 0 },
8925569331642446be05292e3e1f8a51218827168cdclaireho    // Khmer
8935569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('k', 'h', 'm', 'r'), 1 },
8945569331642446be05292e3e1f8a51218827168cdclaireho    // N'Ko
8955569331642446be05292e3e1f8a51218827168cdclaireho    { HB_MAKE_TAG('n', 'k', 'o', ' '), 1 }
8965569331642446be05292e3e1f8a51218827168cdclaireho};
8975569331642446be05292e3e1f8a51218827168cdclairehoenum { NumOTScripts = sizeof(ot_scripts)/sizeof(OTScripts) };
8985569331642446be05292e3e1f8a51218827168cdclaireho
8995569331642446be05292e3e1f8a51218827168cdclairehostatic HB_Bool checkScript(HB_Face face, int script)
9005569331642446be05292e3e1f8a51218827168cdclaireho{
9015569331642446be05292e3e1f8a51218827168cdclaireho    assert(script < HB_ScriptCount);
9025569331642446be05292e3e1f8a51218827168cdclaireho
9035569331642446be05292e3e1f8a51218827168cdclaireho    if (!face->gsub && !face->gpos)
9045569331642446be05292e3e1f8a51218827168cdclaireho        return false;
9055569331642446be05292e3e1f8a51218827168cdclaireho
9065569331642446be05292e3e1f8a51218827168cdclaireho    unsigned int tag = ot_scripts[script].tag;
9075569331642446be05292e3e1f8a51218827168cdclaireho    int requirements = ot_scripts[script].flags;
9085569331642446be05292e3e1f8a51218827168cdclaireho
9095569331642446be05292e3e1f8a51218827168cdclaireho    if (requirements & RequiresGsub) {
9105569331642446be05292e3e1f8a51218827168cdclaireho        if (!face->gsub)
9115569331642446be05292e3e1f8a51218827168cdclaireho            return false;
9125569331642446be05292e3e1f8a51218827168cdclaireho
9135569331642446be05292e3e1f8a51218827168cdclaireho        HB_UShort script_index;
9145569331642446be05292e3e1f8a51218827168cdclaireho        HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
9155569331642446be05292e3e1f8a51218827168cdclaireho        if (error) {
9165569331642446be05292e3e1f8a51218827168cdclaireho            DEBUG("could not select script %d in GSub table: %d", (int)script, error);
9175569331642446be05292e3e1f8a51218827168cdclaireho            error = HB_GSUB_Select_Script(face->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
9185569331642446be05292e3e1f8a51218827168cdclaireho            if (error)
9195569331642446be05292e3e1f8a51218827168cdclaireho                return false;
9205569331642446be05292e3e1f8a51218827168cdclaireho        }
9215569331642446be05292e3e1f8a51218827168cdclaireho    }
9225569331642446be05292e3e1f8a51218827168cdclaireho
9235569331642446be05292e3e1f8a51218827168cdclaireho    if (requirements & RequiresGpos) {
9245569331642446be05292e3e1f8a51218827168cdclaireho        if (!face->gpos)
9255569331642446be05292e3e1f8a51218827168cdclaireho            return false;
9265569331642446be05292e3e1f8a51218827168cdclaireho
9275569331642446be05292e3e1f8a51218827168cdclaireho        HB_UShort script_index;
9285569331642446be05292e3e1f8a51218827168cdclaireho        HB_Error error = HB_GPOS_Select_Script(face->gpos, script, &script_index);
9295569331642446be05292e3e1f8a51218827168cdclaireho        if (error) {
9305569331642446be05292e3e1f8a51218827168cdclaireho            DEBUG("could not select script in gpos table: %d", error);
9315569331642446be05292e3e1f8a51218827168cdclaireho            error = HB_GPOS_Select_Script(face->gpos, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
9325569331642446be05292e3e1f8a51218827168cdclaireho            if (error)
9335569331642446be05292e3e1f8a51218827168cdclaireho                return false;
9345569331642446be05292e3e1f8a51218827168cdclaireho        }
9355569331642446be05292e3e1f8a51218827168cdclaireho
9365569331642446be05292e3e1f8a51218827168cdclaireho    }
9375569331642446be05292e3e1f8a51218827168cdclaireho    return true;
9385569331642446be05292e3e1f8a51218827168cdclaireho}
9395569331642446be05292e3e1f8a51218827168cdclaireho
9405569331642446be05292e3e1f8a51218827168cdclairehostatic HB_Stream getTableStream(void *font, HB_GetFontTableFunc tableFunc, HB_Tag tag)
9415569331642446be05292e3e1f8a51218827168cdclaireho{
9425569331642446be05292e3e1f8a51218827168cdclaireho    HB_Error error;
9435569331642446be05292e3e1f8a51218827168cdclaireho    HB_UInt length = 0;
9445569331642446be05292e3e1f8a51218827168cdclaireho    HB_Stream stream = 0;
9455569331642446be05292e3e1f8a51218827168cdclaireho
9465569331642446be05292e3e1f8a51218827168cdclaireho    if (!font)
9475569331642446be05292e3e1f8a51218827168cdclaireho        return 0;
9485569331642446be05292e3e1f8a51218827168cdclaireho
9495569331642446be05292e3e1f8a51218827168cdclaireho    error = tableFunc(font, tag, 0, &length);
9505569331642446be05292e3e1f8a51218827168cdclaireho    if (error)
9515569331642446be05292e3e1f8a51218827168cdclaireho        return 0;
9525569331642446be05292e3e1f8a51218827168cdclaireho    stream = (HB_Stream)malloc(sizeof(HB_StreamRec));
9535569331642446be05292e3e1f8a51218827168cdclaireho    if (!stream)
9545569331642446be05292e3e1f8a51218827168cdclaireho        return 0;
9555569331642446be05292e3e1f8a51218827168cdclaireho    stream->base = (HB_Byte*)malloc(length);
9565569331642446be05292e3e1f8a51218827168cdclaireho    if (!stream->base) {
9575569331642446be05292e3e1f8a51218827168cdclaireho        free(stream);
9585569331642446be05292e3e1f8a51218827168cdclaireho        return 0;
9595569331642446be05292e3e1f8a51218827168cdclaireho    }
9605569331642446be05292e3e1f8a51218827168cdclaireho    error = tableFunc(font, tag, stream->base, &length);
9615569331642446be05292e3e1f8a51218827168cdclaireho    if (error) {
9625569331642446be05292e3e1f8a51218827168cdclaireho        _hb_close_stream(stream);
9635569331642446be05292e3e1f8a51218827168cdclaireho        return 0;
9645569331642446be05292e3e1f8a51218827168cdclaireho    }
9655569331642446be05292e3e1f8a51218827168cdclaireho    stream->size = length;
9665569331642446be05292e3e1f8a51218827168cdclaireho    stream->pos = 0;
9675569331642446be05292e3e1f8a51218827168cdclaireho    stream->cursor = NULL;
9685569331642446be05292e3e1f8a51218827168cdclaireho    return stream;
9695569331642446be05292e3e1f8a51218827168cdclaireho}
9705569331642446be05292e3e1f8a51218827168cdclaireho
9715569331642446be05292e3e1f8a51218827168cdclairehoHB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc)
9725569331642446be05292e3e1f8a51218827168cdclaireho{
9735569331642446be05292e3e1f8a51218827168cdclaireho    HB_Face face = (HB_Face )malloc(sizeof(HB_FaceRec));
9745569331642446be05292e3e1f8a51218827168cdclaireho    if (!face)
9755569331642446be05292e3e1f8a51218827168cdclaireho        return 0;
9765569331642446be05292e3e1f8a51218827168cdclaireho
9775569331642446be05292e3e1f8a51218827168cdclaireho    face->isSymbolFont = false;
9785569331642446be05292e3e1f8a51218827168cdclaireho    face->gdef = 0;
9795569331642446be05292e3e1f8a51218827168cdclaireho    face->gpos = 0;
9805569331642446be05292e3e1f8a51218827168cdclaireho    face->gsub = 0;
9815569331642446be05292e3e1f8a51218827168cdclaireho    face->current_script = HB_ScriptCount;
9825569331642446be05292e3e1f8a51218827168cdclaireho    face->current_flags = HB_ShaperFlag_Default;
9835569331642446be05292e3e1f8a51218827168cdclaireho    face->has_opentype_kerning = false;
9845569331642446be05292e3e1f8a51218827168cdclaireho    face->tmpAttributes = 0;
9855569331642446be05292e3e1f8a51218827168cdclaireho    face->tmpLogClusters = 0;
9865569331642446be05292e3e1f8a51218827168cdclaireho    face->glyphs_substituted = false;
9875569331642446be05292e3e1f8a51218827168cdclaireho    face->buffer = 0;
9885569331642446be05292e3e1f8a51218827168cdclaireho
9895569331642446be05292e3e1f8a51218827168cdclaireho    HB_Error error;
9905569331642446be05292e3e1f8a51218827168cdclaireho    HB_Stream stream;
9915569331642446be05292e3e1f8a51218827168cdclaireho    HB_Stream gdefStream;
9925569331642446be05292e3e1f8a51218827168cdclaireho
9935569331642446be05292e3e1f8a51218827168cdclaireho    gdefStream = getTableStream(font, tableFunc, TTAG_GDEF);
9945569331642446be05292e3e1f8a51218827168cdclaireho    if (!gdefStream || (error = HB_Load_GDEF_Table(gdefStream, &face->gdef))) {
9955569331642446be05292e3e1f8a51218827168cdclaireho        //DEBUG("error loading gdef table: %d", error);
9965569331642446be05292e3e1f8a51218827168cdclaireho        face->gdef = 0;
9975569331642446be05292e3e1f8a51218827168cdclaireho    }
9985569331642446be05292e3e1f8a51218827168cdclaireho
9995569331642446be05292e3e1f8a51218827168cdclaireho    //DEBUG() << "trying to load gsub table";
10005569331642446be05292e3e1f8a51218827168cdclaireho    stream = getTableStream(font, tableFunc, TTAG_GSUB);
10015569331642446be05292e3e1f8a51218827168cdclaireho    if (!stream || (error = HB_Load_GSUB_Table(stream, &face->gsub, face->gdef, gdefStream))) {
10025569331642446be05292e3e1f8a51218827168cdclaireho        face->gsub = 0;
10035569331642446be05292e3e1f8a51218827168cdclaireho        if (error != HB_Err_Not_Covered) {
10045569331642446be05292e3e1f8a51218827168cdclaireho            //DEBUG("error loading gsub table: %d", error);
10055569331642446be05292e3e1f8a51218827168cdclaireho        } else {
10065569331642446be05292e3e1f8a51218827168cdclaireho            //DEBUG("face doesn't have a gsub table");
10075569331642446be05292e3e1f8a51218827168cdclaireho        }
10085569331642446be05292e3e1f8a51218827168cdclaireho    }
10095569331642446be05292e3e1f8a51218827168cdclaireho    _hb_close_stream(stream);
10105569331642446be05292e3e1f8a51218827168cdclaireho
10115569331642446be05292e3e1f8a51218827168cdclaireho    stream = getTableStream(font, tableFunc, TTAG_GPOS);
10125569331642446be05292e3e1f8a51218827168cdclaireho    if (!stream || (error = HB_Load_GPOS_Table(stream, &face->gpos, face->gdef, gdefStream))) {
10135569331642446be05292e3e1f8a51218827168cdclaireho        face->gpos = 0;
10145569331642446be05292e3e1f8a51218827168cdclaireho        DEBUG("error loading gpos table: %d", error);
10155569331642446be05292e3e1f8a51218827168cdclaireho    }
10165569331642446be05292e3e1f8a51218827168cdclaireho    _hb_close_stream(stream);
10175569331642446be05292e3e1f8a51218827168cdclaireho
10185569331642446be05292e3e1f8a51218827168cdclaireho    _hb_close_stream(gdefStream);
10195569331642446be05292e3e1f8a51218827168cdclaireho
10205569331642446be05292e3e1f8a51218827168cdclaireho    for (unsigned int i = 0; i < HB_ScriptCount; ++i)
10215569331642446be05292e3e1f8a51218827168cdclaireho        face->supported_scripts[i] = checkScript(face, i);
10225569331642446be05292e3e1f8a51218827168cdclaireho
10235569331642446be05292e3e1f8a51218827168cdclaireho    if (hb_buffer_new(&face->buffer) != HB_Err_Ok) {
10245569331642446be05292e3e1f8a51218827168cdclaireho        HB_FreeFace(face);
10255569331642446be05292e3e1f8a51218827168cdclaireho        return 0;
10265569331642446be05292e3e1f8a51218827168cdclaireho    }
10275569331642446be05292e3e1f8a51218827168cdclaireho
10285569331642446be05292e3e1f8a51218827168cdclaireho    return face;
10295569331642446be05292e3e1f8a51218827168cdclaireho}
10305569331642446be05292e3e1f8a51218827168cdclaireho
10315569331642446be05292e3e1f8a51218827168cdclairehovoid HB_FreeFace(HB_Face face)
10325569331642446be05292e3e1f8a51218827168cdclaireho{
10335569331642446be05292e3e1f8a51218827168cdclaireho    if (!face)
10345569331642446be05292e3e1f8a51218827168cdclaireho        return;
10355569331642446be05292e3e1f8a51218827168cdclaireho    if (face->gpos)
10365569331642446be05292e3e1f8a51218827168cdclaireho        HB_Done_GPOS_Table(face->gpos);
10375569331642446be05292e3e1f8a51218827168cdclaireho    if (face->gsub)
10385569331642446be05292e3e1f8a51218827168cdclaireho        HB_Done_GSUB_Table(face->gsub);
10395569331642446be05292e3e1f8a51218827168cdclaireho    if (face->gdef)
10405569331642446be05292e3e1f8a51218827168cdclaireho        HB_Done_GDEF_Table(face->gdef);
10415569331642446be05292e3e1f8a51218827168cdclaireho    if (face->buffer)
10425569331642446be05292e3e1f8a51218827168cdclaireho        hb_buffer_free(face->buffer);
10435569331642446be05292e3e1f8a51218827168cdclaireho    if (face->tmpAttributes)
10445569331642446be05292e3e1f8a51218827168cdclaireho        free(face->tmpAttributes);
10455569331642446be05292e3e1f8a51218827168cdclaireho    if (face->tmpLogClusters)
10465569331642446be05292e3e1f8a51218827168cdclaireho        free(face->tmpLogClusters);
10475569331642446be05292e3e1f8a51218827168cdclaireho    free(face);
10485569331642446be05292e3e1f8a51218827168cdclaireho}
10495569331642446be05292e3e1f8a51218827168cdclaireho
10505569331642446be05292e3e1f8a51218827168cdclairehoHB_Bool HB_SelectScript(HB_ShaperItem *shaper_item, const HB_OpenTypeFeature *features)
10515569331642446be05292e3e1f8a51218827168cdclaireho{
10525569331642446be05292e3e1f8a51218827168cdclaireho    HB_Script script = shaper_item->item.script;
10535569331642446be05292e3e1f8a51218827168cdclaireho
10545569331642446be05292e3e1f8a51218827168cdclaireho    if (!shaper_item->face->supported_scripts[script])
10555569331642446be05292e3e1f8a51218827168cdclaireho        return false;
10565569331642446be05292e3e1f8a51218827168cdclaireho
10575569331642446be05292e3e1f8a51218827168cdclaireho    HB_Face face = shaper_item->face;
10585569331642446be05292e3e1f8a51218827168cdclaireho    if (face->current_script == script && face->current_flags == shaper_item->shaperFlags)
10595569331642446be05292e3e1f8a51218827168cdclaireho        return true;
10605569331642446be05292e3e1f8a51218827168cdclaireho
10615569331642446be05292e3e1f8a51218827168cdclaireho    face->current_script = script;
10625569331642446be05292e3e1f8a51218827168cdclaireho    face->current_flags = shaper_item->shaperFlags;
10635569331642446be05292e3e1f8a51218827168cdclaireho
10645569331642446be05292e3e1f8a51218827168cdclaireho    assert(script < HB_ScriptCount);
10655569331642446be05292e3e1f8a51218827168cdclaireho    // find script in our list of supported scripts.
10665569331642446be05292e3e1f8a51218827168cdclaireho    unsigned int tag = ot_scripts[script].tag;
10675569331642446be05292e3e1f8a51218827168cdclaireho
10685569331642446be05292e3e1f8a51218827168cdclaireho    if (face->gsub && features) {
10695569331642446be05292e3e1f8a51218827168cdclaireho#ifdef OT_DEBUG
10705569331642446be05292e3e1f8a51218827168cdclaireho        {
10715569331642446be05292e3e1f8a51218827168cdclaireho            HB_FeatureList featurelist = face->gsub->FeatureList;
10725569331642446be05292e3e1f8a51218827168cdclaireho            int numfeatures = featurelist.FeatureCount;
10735569331642446be05292e3e1f8a51218827168cdclaireho            DEBUG("gsub table has %d features", numfeatures);
10745569331642446be05292e3e1f8a51218827168cdclaireho            for (int i = 0; i < numfeatures; i++) {
10755569331642446be05292e3e1f8a51218827168cdclaireho                HB_FeatureRecord *r = featurelist.FeatureRecord + i;
10765569331642446be05292e3e1f8a51218827168cdclaireho                DEBUG("   feature '%s'", tag_to_string(r->FeatureTag));
10775569331642446be05292e3e1f8a51218827168cdclaireho            }
10785569331642446be05292e3e1f8a51218827168cdclaireho        }
10795569331642446be05292e3e1f8a51218827168cdclaireho#endif
10805569331642446be05292e3e1f8a51218827168cdclaireho        HB_GSUB_Clear_Features(face->gsub);
10815569331642446be05292e3e1f8a51218827168cdclaireho        HB_UShort script_index;
10825569331642446be05292e3e1f8a51218827168cdclaireho        HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
10835569331642446be05292e3e1f8a51218827168cdclaireho        if (!error) {
10845569331642446be05292e3e1f8a51218827168cdclaireho            DEBUG("script %s has script index %d", tag_to_string(script), script_index);
10855569331642446be05292e3e1f8a51218827168cdclaireho            while (features->tag) {
10865569331642446be05292e3e1f8a51218827168cdclaireho                HB_UShort feature_index;
10875569331642446be05292e3e1f8a51218827168cdclaireho                error = HB_GSUB_Select_Feature(face->gsub, features->tag, script_index, 0xffff, &feature_index);
10885569331642446be05292e3e1f8a51218827168cdclaireho                if (!error) {
10895569331642446be05292e3e1f8a51218827168cdclaireho                    DEBUG("  adding feature %s", tag_to_string(features->tag));
10905569331642446be05292e3e1f8a51218827168cdclaireho                    HB_GSUB_Add_Feature(face->gsub, feature_index, features->property);
10915569331642446be05292e3e1f8a51218827168cdclaireho                }
10925569331642446be05292e3e1f8a51218827168cdclaireho                ++features;
10935569331642446be05292e3e1f8a51218827168cdclaireho            }
10945569331642446be05292e3e1f8a51218827168cdclaireho        }
10955569331642446be05292e3e1f8a51218827168cdclaireho    }
10965569331642446be05292e3e1f8a51218827168cdclaireho
10975569331642446be05292e3e1f8a51218827168cdclaireho    // reset
10985569331642446be05292e3e1f8a51218827168cdclaireho    face->has_opentype_kerning = false;
10995569331642446be05292e3e1f8a51218827168cdclaireho
11005569331642446be05292e3e1f8a51218827168cdclaireho    if (face->gpos) {
11015569331642446be05292e3e1f8a51218827168cdclaireho        HB_GPOS_Clear_Features(face->gpos);
11025569331642446be05292e3e1f8a51218827168cdclaireho        HB_UShort script_index;
11035569331642446be05292e3e1f8a51218827168cdclaireho        HB_Error error = HB_GPOS_Select_Script(face->gpos, tag, &script_index);
11045569331642446be05292e3e1f8a51218827168cdclaireho        if (!error) {
11055569331642446be05292e3e1f8a51218827168cdclaireho#ifdef OT_DEBUG
11065569331642446be05292e3e1f8a51218827168cdclaireho            {
11075569331642446be05292e3e1f8a51218827168cdclaireho                HB_FeatureList featurelist = face->gpos->FeatureList;
11085569331642446be05292e3e1f8a51218827168cdclaireho                int numfeatures = featurelist.FeatureCount;
11095569331642446be05292e3e1f8a51218827168cdclaireho                DEBUG("gpos table has %d features", numfeatures);
11105569331642446be05292e3e1f8a51218827168cdclaireho                for(int i = 0; i < numfeatures; i++) {
11115569331642446be05292e3e1f8a51218827168cdclaireho                    HB_FeatureRecord *r = featurelist.FeatureRecord + i;
11125569331642446be05292e3e1f8a51218827168cdclaireho                    HB_UShort feature_index;
11135569331642446be05292e3e1f8a51218827168cdclaireho                    HB_GPOS_Select_Feature(face->gpos, r->FeatureTag, script_index, 0xffff, &feature_index);
11145569331642446be05292e3e1f8a51218827168cdclaireho                    DEBUG("   feature '%s'", tag_to_string(r->FeatureTag));
11155569331642446be05292e3e1f8a51218827168cdclaireho                }
11165569331642446be05292e3e1f8a51218827168cdclaireho            }
11175569331642446be05292e3e1f8a51218827168cdclaireho#endif
11185569331642446be05292e3e1f8a51218827168cdclaireho            HB_UInt *feature_tag_list_buffer;
11195569331642446be05292e3e1f8a51218827168cdclaireho            error = HB_GPOS_Query_Features(face->gpos, script_index, 0xffff, &feature_tag_list_buffer);
11205569331642446be05292e3e1f8a51218827168cdclaireho            if (!error) {
11215569331642446be05292e3e1f8a51218827168cdclaireho                HB_UInt *feature_tag_list = feature_tag_list_buffer;
11225569331642446be05292e3e1f8a51218827168cdclaireho                while (*feature_tag_list) {
11235569331642446be05292e3e1f8a51218827168cdclaireho                    HB_UShort feature_index;
11245569331642446be05292e3e1f8a51218827168cdclaireho                    if (*feature_tag_list == HB_MAKE_TAG('k', 'e', 'r', 'n')) {
11255569331642446be05292e3e1f8a51218827168cdclaireho                        if (face->current_flags & HB_ShaperFlag_NoKerning) {
11265569331642446be05292e3e1f8a51218827168cdclaireho                            ++feature_tag_list;
11275569331642446be05292e3e1f8a51218827168cdclaireho                            continue;
11285569331642446be05292e3e1f8a51218827168cdclaireho                        }
11295569331642446be05292e3e1f8a51218827168cdclaireho                        face->has_opentype_kerning = true;
11305569331642446be05292e3e1f8a51218827168cdclaireho                    }
11315569331642446be05292e3e1f8a51218827168cdclaireho                    error = HB_GPOS_Select_Feature(face->gpos, *feature_tag_list, script_index, 0xffff, &feature_index);
11325569331642446be05292e3e1f8a51218827168cdclaireho                    if (!error)
11335569331642446be05292e3e1f8a51218827168cdclaireho                        HB_GPOS_Add_Feature(face->gpos, feature_index, PositioningProperties);
11345569331642446be05292e3e1f8a51218827168cdclaireho                    ++feature_tag_list;
11355569331642446be05292e3e1f8a51218827168cdclaireho                }
11365569331642446be05292e3e1f8a51218827168cdclaireho                FREE(feature_tag_list_buffer);
11375569331642446be05292e3e1f8a51218827168cdclaireho            }
11385569331642446be05292e3e1f8a51218827168cdclaireho        }
11395569331642446be05292e3e1f8a51218827168cdclaireho    }
11405569331642446be05292e3e1f8a51218827168cdclaireho
11415569331642446be05292e3e1f8a51218827168cdclaireho    return true;
11425569331642446be05292e3e1f8a51218827168cdclaireho}
11435569331642446be05292e3e1f8a51218827168cdclaireho
11445569331642446be05292e3e1f8a51218827168cdclairehoHB_Bool HB_OpenTypeShape(HB_ShaperItem *item, const hb_uint32 *properties)
11455569331642446be05292e3e1f8a51218827168cdclaireho{
11465569331642446be05292e3e1f8a51218827168cdclaireho    HB_GlyphAttributes *tmpAttributes;
11475569331642446be05292e3e1f8a51218827168cdclaireho    unsigned int *tmpLogClusters;
11485569331642446be05292e3e1f8a51218827168cdclaireho
11495569331642446be05292e3e1f8a51218827168cdclaireho    HB_Face face = item->face;
11505569331642446be05292e3e1f8a51218827168cdclaireho
11515569331642446be05292e3e1f8a51218827168cdclaireho    face->length = item->num_glyphs;
11525569331642446be05292e3e1f8a51218827168cdclaireho
11535569331642446be05292e3e1f8a51218827168cdclaireho    hb_buffer_clear(face->buffer);
11545569331642446be05292e3e1f8a51218827168cdclaireho
11555569331642446be05292e3e1f8a51218827168cdclaireho    tmpAttributes = (HB_GlyphAttributes *) realloc(face->tmpAttributes, face->length*sizeof(HB_GlyphAttributes));
11565569331642446be05292e3e1f8a51218827168cdclaireho    if (!tmpAttributes)
11575569331642446be05292e3e1f8a51218827168cdclaireho        return false;
11585569331642446be05292e3e1f8a51218827168cdclaireho    face->tmpAttributes = tmpAttributes;
11595569331642446be05292e3e1f8a51218827168cdclaireho
11605569331642446be05292e3e1f8a51218827168cdclaireho    tmpLogClusters = (unsigned int *) realloc(face->tmpLogClusters, face->length*sizeof(unsigned int));
11615569331642446be05292e3e1f8a51218827168cdclaireho    if (!tmpLogClusters)
11625569331642446be05292e3e1f8a51218827168cdclaireho        return false;
11635569331642446be05292e3e1f8a51218827168cdclaireho    face->tmpLogClusters = tmpLogClusters;
11645569331642446be05292e3e1f8a51218827168cdclaireho
11655569331642446be05292e3e1f8a51218827168cdclaireho    for (int i = 0; i < face->length; ++i) {
11665569331642446be05292e3e1f8a51218827168cdclaireho        hb_buffer_add_glyph(face->buffer, item->glyphs[i], properties ? properties[i] : 0, i);
11675569331642446be05292e3e1f8a51218827168cdclaireho        face->tmpAttributes[i] = item->attributes[i];
11685569331642446be05292e3e1f8a51218827168cdclaireho        face->tmpLogClusters[i] = item->log_clusters[i];
11695569331642446be05292e3e1f8a51218827168cdclaireho    }
11705569331642446be05292e3e1f8a51218827168cdclaireho
11715569331642446be05292e3e1f8a51218827168cdclaireho#ifdef OT_DEBUG
11725569331642446be05292e3e1f8a51218827168cdclaireho    DEBUG("-----------------------------------------");
11735569331642446be05292e3e1f8a51218827168cdclaireho//     DEBUG("log clusters before shaping:");
11745569331642446be05292e3e1f8a51218827168cdclaireho//     for (int j = 0; j < length; j++)
11755569331642446be05292e3e1f8a51218827168cdclaireho//         DEBUG("    log[%d] = %d", j, item->log_clusters[j]);
11765569331642446be05292e3e1f8a51218827168cdclaireho    DEBUG("original glyphs: %p", item->glyphs);
11775569331642446be05292e3e1f8a51218827168cdclaireho    for (int i = 0; i < length; ++i)
11785569331642446be05292e3e1f8a51218827168cdclaireho        DEBUG("   glyph=%4x", hb_buffer->in_string[i].gindex);
11795569331642446be05292e3e1f8a51218827168cdclaireho//     dump_string(hb_buffer);
11805569331642446be05292e3e1f8a51218827168cdclaireho#endif
11815569331642446be05292e3e1f8a51218827168cdclaireho
11825569331642446be05292e3e1f8a51218827168cdclaireho    face->glyphs_substituted = false;
11835569331642446be05292e3e1f8a51218827168cdclaireho    if (face->gsub) {
11845569331642446be05292e3e1f8a51218827168cdclaireho        unsigned int error = HB_GSUB_Apply_String(face->gsub, face->buffer);
11855569331642446be05292e3e1f8a51218827168cdclaireho        if (error && error != HB_Err_Not_Covered)
11865569331642446be05292e3e1f8a51218827168cdclaireho            return false;
11875569331642446be05292e3e1f8a51218827168cdclaireho        face->glyphs_substituted = (error != HB_Err_Not_Covered);
11885569331642446be05292e3e1f8a51218827168cdclaireho    }
11895569331642446be05292e3e1f8a51218827168cdclaireho
11905569331642446be05292e3e1f8a51218827168cdclaireho#ifdef OT_DEBUG
11915569331642446be05292e3e1f8a51218827168cdclaireho//     DEBUG("log clusters before shaping:");
11925569331642446be05292e3e1f8a51218827168cdclaireho//     for (int j = 0; j < length; j++)
11935569331642446be05292e3e1f8a51218827168cdclaireho//         DEBUG("    log[%d] = %d", j, item->log_clusters[j]);
11945569331642446be05292e3e1f8a51218827168cdclaireho    DEBUG("shaped glyphs:");
11955569331642446be05292e3e1f8a51218827168cdclaireho    for (int i = 0; i < length; ++i)
11965569331642446be05292e3e1f8a51218827168cdclaireho        DEBUG("   glyph=%4x", hb_buffer->in_string[i].gindex);
11975569331642446be05292e3e1f8a51218827168cdclaireho    DEBUG("-----------------------------------------");
11985569331642446be05292e3e1f8a51218827168cdclaireho//     dump_string(hb_buffer);
11995569331642446be05292e3e1f8a51218827168cdclaireho#endif
12005569331642446be05292e3e1f8a51218827168cdclaireho
12015569331642446be05292e3e1f8a51218827168cdclaireho    return true;
12025569331642446be05292e3e1f8a51218827168cdclaireho}
12035569331642446be05292e3e1f8a51218827168cdclaireho
12045569331642446be05292e3e1f8a51218827168cdclaireho/* See comments near the definition of HB_ShaperFlag_ForceMarksToZeroWidth for a description
12055569331642446be05292e3e1f8a51218827168cdclaireho   of why this function exists. */
12065569331642446be05292e3e1f8a51218827168cdclairehovoid HB_FixupZeroWidth(HB_ShaperItem *item)
12075569331642446be05292e3e1f8a51218827168cdclaireho{
12085569331642446be05292e3e1f8a51218827168cdclaireho    HB_UShort property;
12095569331642446be05292e3e1f8a51218827168cdclaireho
12105569331642446be05292e3e1f8a51218827168cdclaireho    if (!item->face->gdef)
12115569331642446be05292e3e1f8a51218827168cdclaireho        return;
12125569331642446be05292e3e1f8a51218827168cdclaireho
12135569331642446be05292e3e1f8a51218827168cdclaireho    for (unsigned int i = 0; i < item->num_glyphs; ++i) {
12145569331642446be05292e3e1f8a51218827168cdclaireho        /* If the glyph is a mark, force its advance to zero. */
12155569331642446be05292e3e1f8a51218827168cdclaireho        if (HB_GDEF_Get_Glyph_Property (item->face->gdef, item->glyphs[i], &property) == HB_Err_Ok &&
12165569331642446be05292e3e1f8a51218827168cdclaireho            property == HB_GDEF_MARK) {
12175569331642446be05292e3e1f8a51218827168cdclaireho            item->advances[i] = 0;
12185569331642446be05292e3e1f8a51218827168cdclaireho        }
12195569331642446be05292e3e1f8a51218827168cdclaireho    }
12205569331642446be05292e3e1f8a51218827168cdclaireho}
12215569331642446be05292e3e1f8a51218827168cdclaireho
12225569331642446be05292e3e1f8a51218827168cdclairehoHB_Bool HB_OpenTypePosition(HB_ShaperItem *item, int availableGlyphs, HB_Bool doLogClusters)
12235569331642446be05292e3e1f8a51218827168cdclaireho{
12245569331642446be05292e3e1f8a51218827168cdclaireho    HB_Face face = item->face;
12255569331642446be05292e3e1f8a51218827168cdclaireho
12265569331642446be05292e3e1f8a51218827168cdclaireho    bool glyphs_positioned = false;
12275569331642446be05292e3e1f8a51218827168cdclaireho    if (face->gpos) {
12285569331642446be05292e3e1f8a51218827168cdclaireho        if (face->buffer->positions)
12295569331642446be05292e3e1f8a51218827168cdclaireho            memset(face->buffer->positions, 0, face->buffer->in_length*sizeof(HB_PositionRec));
12305569331642446be05292e3e1f8a51218827168cdclaireho        // #### check that passing "false,false" is correct
12315569331642446be05292e3e1f8a51218827168cdclaireho        glyphs_positioned = HB_GPOS_Apply_String(item->font, face->gpos, face->current_flags, face->buffer, false, false) != HB_Err_Not_Covered;
12325569331642446be05292e3e1f8a51218827168cdclaireho    }
12335569331642446be05292e3e1f8a51218827168cdclaireho
12345569331642446be05292e3e1f8a51218827168cdclaireho    if (!face->glyphs_substituted && !glyphs_positioned) {
12355569331642446be05292e3e1f8a51218827168cdclaireho        HB_GetGlyphAdvances(item);
12365569331642446be05292e3e1f8a51218827168cdclaireho        if (item->face->current_flags & HB_ShaperFlag_ForceMarksToZeroWidth)
12375569331642446be05292e3e1f8a51218827168cdclaireho            HB_FixupZeroWidth(item);
12385569331642446be05292e3e1f8a51218827168cdclaireho        return true; // nothing to do for us
12395569331642446be05292e3e1f8a51218827168cdclaireho    }
12405569331642446be05292e3e1f8a51218827168cdclaireho
12415569331642446be05292e3e1f8a51218827168cdclaireho    // make sure we have enough space to write everything back
12425569331642446be05292e3e1f8a51218827168cdclaireho    if (availableGlyphs < (int)face->buffer->in_length) {
12435569331642446be05292e3e1f8a51218827168cdclaireho        item->num_glyphs = face->buffer->in_length;
12445569331642446be05292e3e1f8a51218827168cdclaireho        return false;
12455569331642446be05292e3e1f8a51218827168cdclaireho    }
12465569331642446be05292e3e1f8a51218827168cdclaireho
12475569331642446be05292e3e1f8a51218827168cdclaireho    HB_Glyph *glyphs = item->glyphs;
12485569331642446be05292e3e1f8a51218827168cdclaireho    HB_GlyphAttributes *attributes = item->attributes;
12495569331642446be05292e3e1f8a51218827168cdclaireho
12505569331642446be05292e3e1f8a51218827168cdclaireho    for (unsigned int i = 0; i < face->buffer->in_length; ++i) {
12515569331642446be05292e3e1f8a51218827168cdclaireho        glyphs[i] = face->buffer->in_string[i].gindex;
12525569331642446be05292e3e1f8a51218827168cdclaireho        attributes[i] = face->tmpAttributes[face->buffer->in_string[i].cluster];
12535569331642446be05292e3e1f8a51218827168cdclaireho        if (i && face->buffer->in_string[i].cluster == face->buffer->in_string[i-1].cluster)
12545569331642446be05292e3e1f8a51218827168cdclaireho            attributes[i].clusterStart = false;
12555569331642446be05292e3e1f8a51218827168cdclaireho    }
12565569331642446be05292e3e1f8a51218827168cdclaireho    item->num_glyphs = face->buffer->in_length;
12575569331642446be05292e3e1f8a51218827168cdclaireho
12585569331642446be05292e3e1f8a51218827168cdclaireho    if (doLogClusters && face->glyphs_substituted) {
12595569331642446be05292e3e1f8a51218827168cdclaireho        // we can't do this for indic, as we pass the stuf in syllables and it's easier to do it in the shaper.
12605569331642446be05292e3e1f8a51218827168cdclaireho        unsigned short *logClusters = item->log_clusters;
12615569331642446be05292e3e1f8a51218827168cdclaireho        int clusterStart = 0;
12625569331642446be05292e3e1f8a51218827168cdclaireho        int oldCi = 0;
12635569331642446be05292e3e1f8a51218827168cdclaireho        // #### the reconstruction of the logclusters currently does not work if the original string
12645569331642446be05292e3e1f8a51218827168cdclaireho        // contains surrogate pairs
12655569331642446be05292e3e1f8a51218827168cdclaireho        for (unsigned int i = 0; i < face->buffer->in_length; ++i) {
12665569331642446be05292e3e1f8a51218827168cdclaireho            int ci = face->buffer->in_string[i].cluster;
12675569331642446be05292e3e1f8a51218827168cdclaireho            //         DEBUG("   ci[%d] = %d mark=%d, cmb=%d, cs=%d",
12685569331642446be05292e3e1f8a51218827168cdclaireho            //                i, ci, glyphAttributes[i].mark, glyphAttributes[i].combiningClass, glyphAttributes[i].clusterStart);
12695569331642446be05292e3e1f8a51218827168cdclaireho            if (!attributes[i].mark && attributes[i].clusterStart && ci != oldCi) {
12705569331642446be05292e3e1f8a51218827168cdclaireho                for (int j = oldCi; j < ci; j++)
12715569331642446be05292e3e1f8a51218827168cdclaireho                    logClusters[j] = clusterStart;
12725569331642446be05292e3e1f8a51218827168cdclaireho                clusterStart = i;
12735569331642446be05292e3e1f8a51218827168cdclaireho                oldCi = ci;
12745569331642446be05292e3e1f8a51218827168cdclaireho            }
12755569331642446be05292e3e1f8a51218827168cdclaireho        }
12765569331642446be05292e3e1f8a51218827168cdclaireho        for (int j = oldCi; j < face->length; j++)
12775569331642446be05292e3e1f8a51218827168cdclaireho            logClusters[j] = clusterStart;
12785569331642446be05292e3e1f8a51218827168cdclaireho    }
12795569331642446be05292e3e1f8a51218827168cdclaireho
12805569331642446be05292e3e1f8a51218827168cdclaireho    // calulate the advances for the shaped glyphs
12815569331642446be05292e3e1f8a51218827168cdclaireho//     DEBUG("unpositioned: ");
12825569331642446be05292e3e1f8a51218827168cdclaireho
12835569331642446be05292e3e1f8a51218827168cdclaireho    // positioning code:
12845569331642446be05292e3e1f8a51218827168cdclaireho    if (glyphs_positioned) {
12855569331642446be05292e3e1f8a51218827168cdclaireho        HB_GetGlyphAdvances(item);
12865569331642446be05292e3e1f8a51218827168cdclaireho        HB_Position positions = face->buffer->positions;
12875569331642446be05292e3e1f8a51218827168cdclaireho        HB_Fixed *advances = item->advances;
12885569331642446be05292e3e1f8a51218827168cdclaireho
12895569331642446be05292e3e1f8a51218827168cdclaireho//         DEBUG("positioned glyphs:");
12905569331642446be05292e3e1f8a51218827168cdclaireho        for (unsigned int i = 0; i < face->buffer->in_length; i++) {
12915569331642446be05292e3e1f8a51218827168cdclaireho//             DEBUG("    %d:\t orig advance: (%d/%d)\tadv=(%d/%d)\tpos=(%d/%d)\tback=%d\tnew_advance=%d", i,
12925569331642446be05292e3e1f8a51218827168cdclaireho//                    glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(),
12935569331642446be05292e3e1f8a51218827168cdclaireho//                    (int)(positions[i].x_advance >> 6), (int)(positions[i].y_advance >> 6),
12945569331642446be05292e3e1f8a51218827168cdclaireho//                    (int)(positions[i].x_pos >> 6), (int)(positions[i].y_pos >> 6),
12955569331642446be05292e3e1f8a51218827168cdclaireho//                    positions[i].back, positions[i].new_advance);
12965569331642446be05292e3e1f8a51218827168cdclaireho
12975569331642446be05292e3e1f8a51218827168cdclaireho            HB_Fixed adjustment = (item->item.bidiLevel % 2) ? -positions[i].x_advance : positions[i].x_advance;
12985569331642446be05292e3e1f8a51218827168cdclaireho
12995569331642446be05292e3e1f8a51218827168cdclaireho            if (!(face->current_flags & HB_ShaperFlag_UseDesignMetrics))
13005569331642446be05292e3e1f8a51218827168cdclaireho                adjustment = HB_FIXED_ROUND(adjustment);
13015569331642446be05292e3e1f8a51218827168cdclaireho
13025569331642446be05292e3e1f8a51218827168cdclaireho            if (positions[i].new_advance) {
13035569331642446be05292e3e1f8a51218827168cdclaireho                advances[i] = adjustment;
13045569331642446be05292e3e1f8a51218827168cdclaireho            } else {
13055569331642446be05292e3e1f8a51218827168cdclaireho                advances[i] += adjustment;
13065569331642446be05292e3e1f8a51218827168cdclaireho            }
13075569331642446be05292e3e1f8a51218827168cdclaireho
13085569331642446be05292e3e1f8a51218827168cdclaireho            int back = 0;
13095569331642446be05292e3e1f8a51218827168cdclaireho            HB_FixedPoint *offsets = item->offsets;
13105569331642446be05292e3e1f8a51218827168cdclaireho            offsets[i].x = positions[i].x_pos;
13115569331642446be05292e3e1f8a51218827168cdclaireho            offsets[i].y = positions[i].y_pos;
13125569331642446be05292e3e1f8a51218827168cdclaireho            while (positions[i - back].back) {
13135569331642446be05292e3e1f8a51218827168cdclaireho                back += positions[i - back].back;
13145569331642446be05292e3e1f8a51218827168cdclaireho                offsets[i].x += positions[i - back].x_pos;
13155569331642446be05292e3e1f8a51218827168cdclaireho                offsets[i].y += positions[i - back].y_pos;
13165569331642446be05292e3e1f8a51218827168cdclaireho            }
13175569331642446be05292e3e1f8a51218827168cdclaireho            offsets[i].y = -offsets[i].y;
13185569331642446be05292e3e1f8a51218827168cdclaireho
13195569331642446be05292e3e1f8a51218827168cdclaireho            if (item->item.bidiLevel % 2) {
13205569331642446be05292e3e1f8a51218827168cdclaireho                // ### may need to go back multiple glyphs like in ltr
13215569331642446be05292e3e1f8a51218827168cdclaireho                back = positions[i].back;
13225569331642446be05292e3e1f8a51218827168cdclaireho                while (back--)
13235569331642446be05292e3e1f8a51218827168cdclaireho                    offsets[i].x -= advances[i-back];
13245569331642446be05292e3e1f8a51218827168cdclaireho            } else {
13255569331642446be05292e3e1f8a51218827168cdclaireho                back = 0;
13265569331642446be05292e3e1f8a51218827168cdclaireho                while (positions[i - back].back) {
13275569331642446be05292e3e1f8a51218827168cdclaireho                    back += positions[i - back].back;
13285569331642446be05292e3e1f8a51218827168cdclaireho                    offsets[i].x -= advances[i-back];
13295569331642446be05292e3e1f8a51218827168cdclaireho                }
13305569331642446be05292e3e1f8a51218827168cdclaireho            }
13315569331642446be05292e3e1f8a51218827168cdclaireho//             DEBUG("   ->\tadv=%d\tpos=(%d/%d)",
13325569331642446be05292e3e1f8a51218827168cdclaireho//                    glyphs[i].advance.x.toInt(), glyphs[i].offset.x.toInt(), glyphs[i].offset.y.toInt());
13335569331642446be05292e3e1f8a51218827168cdclaireho        }
13345569331642446be05292e3e1f8a51218827168cdclaireho        item->kerning_applied = face->has_opentype_kerning;
13355569331642446be05292e3e1f8a51218827168cdclaireho    } else {
13365569331642446be05292e3e1f8a51218827168cdclaireho        HB_HeuristicPosition(item);
13375569331642446be05292e3e1f8a51218827168cdclaireho    }
13385569331642446be05292e3e1f8a51218827168cdclaireho
13395569331642446be05292e3e1f8a51218827168cdclaireho#ifdef OT_DEBUG
13405569331642446be05292e3e1f8a51218827168cdclaireho    if (doLogClusters) {
13415569331642446be05292e3e1f8a51218827168cdclaireho        DEBUG("log clusters after shaping:");
13425569331642446be05292e3e1f8a51218827168cdclaireho        for (int j = 0; j < length; j++)
13435569331642446be05292e3e1f8a51218827168cdclaireho            DEBUG("    log[%d] = %d", j, item->log_clusters[j]);
13445569331642446be05292e3e1f8a51218827168cdclaireho    }
13455569331642446be05292e3e1f8a51218827168cdclaireho    DEBUG("final glyphs:");
13465569331642446be05292e3e1f8a51218827168cdclaireho    for (int i = 0; i < (int)hb_buffer->in_length; ++i)
13475569331642446be05292e3e1f8a51218827168cdclaireho        DEBUG("   glyph=%4x char_index=%d mark: %d cmp: %d, clusterStart: %d advance=%d/%d offset=%d/%d",
13485569331642446be05292e3e1f8a51218827168cdclaireho               glyphs[i].glyph, hb_buffer->in_string[i].cluster, glyphs[i].attributes.mark,
13495569331642446be05292e3e1f8a51218827168cdclaireho               glyphs[i].attributes.combiningClass, glyphs[i].attributes.clusterStart,
13505569331642446be05292e3e1f8a51218827168cdclaireho               glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(),
13515569331642446be05292e3e1f8a51218827168cdclaireho               glyphs[i].offset.x.toInt(), glyphs[i].offset.y.toInt());
13525569331642446be05292e3e1f8a51218827168cdclaireho    DEBUG("-----------------------------------------");
13535569331642446be05292e3e1f8a51218827168cdclaireho#endif
13545569331642446be05292e3e1f8a51218827168cdclaireho    return true;
13555569331642446be05292e3e1f8a51218827168cdclaireho}
13565569331642446be05292e3e1f8a51218827168cdclaireho
13575569331642446be05292e3e1f8a51218827168cdclairehoHB_Bool HB_ShapeItem(HB_ShaperItem *shaper_item)
13585569331642446be05292e3e1f8a51218827168cdclaireho{
13595569331642446be05292e3e1f8a51218827168cdclaireho    HB_Bool result = false;
13605569331642446be05292e3e1f8a51218827168cdclaireho    if (shaper_item->num_glyphs < shaper_item->item.length) {
13615569331642446be05292e3e1f8a51218827168cdclaireho        shaper_item->num_glyphs = shaper_item->item.length;
13625569331642446be05292e3e1f8a51218827168cdclaireho        return false;
13635569331642446be05292e3e1f8a51218827168cdclaireho    }
13645569331642446be05292e3e1f8a51218827168cdclaireho    assert(shaper_item->item.script < HB_ScriptCount);
13655569331642446be05292e3e1f8a51218827168cdclaireho    result = HB_ScriptEngines[shaper_item->item.script].shape(shaper_item);
13665569331642446be05292e3e1f8a51218827168cdclaireho    shaper_item->glyphIndicesPresent = false;
13675569331642446be05292e3e1f8a51218827168cdclaireho    return result;
13685569331642446be05292e3e1f8a51218827168cdclaireho}
13695569331642446be05292e3e1f8a51218827168cdclaireho
1370