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