| Index: third_party/harfbuzz/src/harfbuzz-shaper.cpp | 
| diff --git a/third_party/harfbuzz/src/harfbuzz-shaper.cpp b/third_party/harfbuzz/src/harfbuzz-shaper.cpp | 
| deleted file mode 100644 | 
| index f1606e6a79813f5214248f76da56f2050b08d60b..0000000000000000000000000000000000000000 | 
| --- a/third_party/harfbuzz/src/harfbuzz-shaper.cpp | 
| +++ /dev/null | 
| @@ -1,1357 +0,0 @@ | 
| -/* | 
| - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) | 
| - * | 
| - * This is part of HarfBuzz, an OpenType Layout engine library. | 
| - * | 
| - * Permission is hereby granted, without written agreement and without | 
| - * license or royalty fees, to use, copy, modify, and distribute this | 
| - * software and its documentation for any purpose, provided that the | 
| - * above copyright notice and the following two paragraphs appear in | 
| - * all copies of this software. | 
| - * | 
| - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 
| - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | 
| - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | 
| - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | 
| - * DAMAGE. | 
| - * | 
| - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | 
| - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 
| - * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS | 
| - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | 
| - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 
| - */ | 
| - | 
| -#include "harfbuzz-shaper.h" | 
| -#include "harfbuzz-shaper-private.h" | 
| - | 
| -#include "harfbuzz-stream-private.h" | 
| -#include <assert.h> | 
| -#include <stdio.h> | 
| - | 
| -#define HB_MIN(a, b) ((a) < (b) ? (a) : (b)) | 
| -#define HB_MAX(a, b) ((a) > (b) ? (a) : (b)) | 
| - | 
| -// ----------------------------------------------------------------------------------------------------- | 
| -// | 
| -// The line break algorithm. See http://www.unicode.org/reports/tr14/tr14-13.html | 
| -// | 
| -// ----------------------------------------------------------------------------------------------------- | 
| - | 
| -/* The Unicode algorithm does in our opinion allow line breaks at some | 
| -   places they shouldn't be allowed. The following changes were thus | 
| -   made in comparison to the Unicode reference: | 
| - | 
| -   EX->AL from DB to IB | 
| -   SY->AL from DB to IB | 
| -   SY->PO from DB to IB | 
| -   SY->PR from DB to IB | 
| -   SY->OP from DB to IB | 
| -   AL->PR from DB to IB | 
| -   AL->PO from DB to IB | 
| -   PR->PR from DB to IB | 
| -   PO->PO from DB to IB | 
| -   PR->PO from DB to IB | 
| -   PO->PR from DB to IB | 
| -   HY->PO from DB to IB | 
| -   HY->PR from DB to IB | 
| -   HY->OP from DB to IB | 
| -   NU->EX from PB to IB | 
| -   EX->PO from DB to IB | 
| -*/ | 
| - | 
| -// The following line break classes are not treated by the table: | 
| -//  AI, BK, CB, CR, LF, NL, SA, SG, SP, XX | 
| - | 
| -enum break_class { | 
| -    // the first 4 values have to agree with the enum in QCharAttributes | 
| -    ProhibitedBreak,            // PB in table | 
| -    DirectBreak,                // DB in table | 
| -    IndirectBreak,              // IB in table | 
| -    CombiningIndirectBreak,     // CI in table | 
| -    CombiningProhibitedBreak    // CP in table | 
| -}; | 
| -#define DB DirectBreak | 
| -#define IB IndirectBreak | 
| -#define CI CombiningIndirectBreak | 
| -#define CP CombiningProhibitedBreak | 
| -#define PB ProhibitedBreak | 
| - | 
| -static const hb_uint8 breakTable[HB_LineBreak_JT+1][HB_LineBreak_JT+1] = | 
| -{ | 
| -/*          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 */ | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 }, | 
| -/* 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 } | 
| -}; | 
| -#undef DB | 
| -#undef IB | 
| -#undef CI | 
| -#undef CP | 
| -#undef PB | 
| - | 
| -static const hb_uint8 graphemeTable[HB_Grapheme_LVT + 1][HB_Grapheme_LVT + 1] = | 
| -{ | 
| -//      Other, CR,    LF,    Control,Extend,L,    V,     T,     LV,    LVT | 
| -    { true , true , true , true , true , true , true , true , true , true  }, // Other, | 
| -    { true , true , true , true , true , true , true , true , true , true  }, // CR, | 
| -    { true , false, true , true , true , true , true , true , true , true  }, // LF, | 
| -    { true , true , true , true , true , true , true , true , true , true  }, // Control, | 
| -    { false, true , true , true , false, false, false, false, false, false }, // Extend, | 
| -    { true , true , true , true , true , false, true , true , true , true  }, // L, | 
| -    { true , true , true , true , true , false, false, true , false, true  }, // V, | 
| -    { true , true , true , true , true , true , false, false, false, false }, // T, | 
| -    { true , true , true , true , true , false, true , true , true , true  }, // LV, | 
| -    { true , true , true , true , true , false, true , true , true , true  }, // LVT | 
| -}; | 
| - | 
| -static void calcLineBreaks(const HB_UChar16 *uc, hb_uint32 len, HB_CharAttributes *charAttributes) | 
| -{ | 
| -    if (!len) | 
| -        return; | 
| - | 
| -    // ##### can this fail if the first char is a surrogate? | 
| -    HB_LineBreakClass cls; | 
| -    HB_GraphemeClass grapheme; | 
| -    HB_GetGraphemeAndLineBreakClass(*uc, &grapheme, &cls); | 
| -    // handle case where input starts with an LF | 
| -    if (cls == HB_LineBreak_LF) | 
| -        cls = HB_LineBreak_BK; | 
| - | 
| -    charAttributes[0].whiteSpace = (cls == HB_LineBreak_SP || cls == HB_LineBreak_BK); | 
| -    charAttributes[0].charStop = true; | 
| - | 
| -    int lcls = cls; | 
| -    for (hb_uint32 i = 1; i < len; ++i) { | 
| -        charAttributes[i].whiteSpace = false; | 
| -        charAttributes[i].charStop = true; | 
| - | 
| -        HB_UChar32 code = uc[i]; | 
| -        HB_GraphemeClass ngrapheme; | 
| -        HB_LineBreakClass ncls; | 
| -        HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls); | 
| -        charAttributes[i].charStop = graphemeTable[ngrapheme][grapheme]; | 
| -        // handle surrogates | 
| -        if (ncls == HB_LineBreak_SG) { | 
| -            if (HB_IsHighSurrogate(uc[i]) && i < len - 1 && HB_IsLowSurrogate(uc[i+1])) { | 
| -                continue; | 
| -            } else if (HB_IsLowSurrogate(uc[i]) && HB_IsHighSurrogate(uc[i-1])) { | 
| -                code = HB_SurrogateToUcs4(uc[i-1], uc[i]); | 
| -                HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls); | 
| -                charAttributes[i].charStop = false; | 
| -            } else { | 
| -                ncls = HB_LineBreak_AL; | 
| -            } | 
| -        } | 
| - | 
| -        // set white space and char stop flag | 
| -        if (ncls >= HB_LineBreak_SP) | 
| -            charAttributes[i].whiteSpace = true; | 
| - | 
| -        HB_LineBreakType lineBreakType = HB_NoBreak; | 
| -        if (cls >= HB_LineBreak_LF) { | 
| -            lineBreakType = HB_ForcedBreak; | 
| -        } else if(cls == HB_LineBreak_CR) { | 
| -            lineBreakType = (ncls == HB_LineBreak_LF) ? HB_NoBreak : HB_ForcedBreak; | 
| -        } | 
| - | 
| -        if (ncls == HB_LineBreak_SP) | 
| -            goto next_no_cls_update; | 
| -        if (ncls >= HB_LineBreak_CR) | 
| -            goto next; | 
| - | 
| -        // two complex chars (thai or lao), thai_attributes might override, but here we do a best guess | 
| -	if (cls == HB_LineBreak_SA && ncls == HB_LineBreak_SA) { | 
| -            lineBreakType = HB_Break; | 
| -            goto next; | 
| -        } | 
| - | 
| -        { | 
| -            int tcls = ncls; | 
| -            if (tcls >= HB_LineBreak_SA) | 
| -                tcls = HB_LineBreak_ID; | 
| -            if (cls >= HB_LineBreak_SA) | 
| -                cls = HB_LineBreak_ID; | 
| - | 
| -            int brk = breakTable[cls][tcls]; | 
| -            switch (brk) { | 
| -            case DirectBreak: | 
| -                lineBreakType = HB_Break; | 
| -                if (uc[i-1] == 0xad) // soft hyphen | 
| -                    lineBreakType = HB_SoftHyphen; | 
| -                break; | 
| -            case IndirectBreak: | 
| -                lineBreakType = (lcls == HB_LineBreak_SP) ? HB_Break : HB_NoBreak; | 
| -                break; | 
| -            case CombiningIndirectBreak: | 
| -                lineBreakType = HB_NoBreak; | 
| -                if (lcls == HB_LineBreak_SP){ | 
| -                    if (i > 1) | 
| -                        charAttributes[i-2].lineBreakType = HB_Break; | 
| -                } else { | 
| -                    goto next_no_cls_update; | 
| -                } | 
| -                break; | 
| -            case CombiningProhibitedBreak: | 
| -                lineBreakType = HB_NoBreak; | 
| -                if (lcls != HB_LineBreak_SP) | 
| -                    goto next_no_cls_update; | 
| -            case ProhibitedBreak: | 
| -            default: | 
| -                break; | 
| -            } | 
| -        } | 
| -    next: | 
| -        cls = ncls; | 
| -    next_no_cls_update: | 
| -        lcls = ncls; | 
| -        grapheme = ngrapheme; | 
| -        charAttributes[i-1].lineBreakType = lineBreakType; | 
| -    } | 
| -    charAttributes[len-1].lineBreakType = HB_ForcedBreak; | 
| -} | 
| - | 
| -// -------------------------------------------------------------------------------------------------------------------------------------------- | 
| -// | 
| -// Basic processing | 
| -// | 
| -// -------------------------------------------------------------------------------------------------------------------------------------------- | 
| - | 
| -static inline void positionCluster(HB_ShaperItem *item, int gfrom,  int glast) | 
| -{ | 
| -    int nmarks = glast - gfrom; | 
| -    assert(nmarks > 0); | 
| - | 
| -    HB_Glyph *glyphs = item->glyphs; | 
| -    HB_GlyphAttributes *attributes = item->attributes; | 
| - | 
| -    HB_GlyphMetrics baseMetrics; | 
| -    item->font->klass->getGlyphMetrics(item->font, glyphs[gfrom], &baseMetrics); | 
| - | 
| -    if (item->item.script == HB_Script_Hebrew | 
| -        && (-baseMetrics.y) > baseMetrics.height) | 
| -        // we need to attach below the baseline, because of the hebrew iud. | 
| -        baseMetrics.height = -baseMetrics.y; | 
| - | 
| -//     qDebug("---> positionCluster: cluster from %d to %d", gfrom, glast); | 
| -//     qDebug("baseInfo: %f/%f (%f/%f) off=%f/%f", baseInfo.x, baseInfo.y, baseInfo.width, baseInfo.height, baseInfo.xoff, baseInfo.yoff); | 
| - | 
| -    HB_Fixed size = item->font->klass->getFontMetric(item->font, HB_FontAscent) / 10; | 
| -    HB_Fixed offsetBase = HB_FIXED_CONSTANT(1) + (size - HB_FIXED_CONSTANT(4)) / 4; | 
| -    if (size > HB_FIXED_CONSTANT(4)) | 
| -        offsetBase += HB_FIXED_CONSTANT(4); | 
| -    else | 
| -        offsetBase += size; | 
| -    //qreal offsetBase = (size - 4) / 4 + qMin<qreal>(size, 4) + 1; | 
| -//     qDebug("offset = %f", offsetBase); | 
| - | 
| -    bool rightToLeft = item->item.bidiLevel % 2; | 
| - | 
| -    int i; | 
| -    unsigned char lastCmb = 0; | 
| -    HB_GlyphMetrics attachmentRect; | 
| -    memset(&attachmentRect, 0, sizeof(attachmentRect)); | 
| - | 
| -    for(i = 1; i <= nmarks; i++) { | 
| -        HB_Glyph mark = glyphs[gfrom+i]; | 
| -        HB_GlyphMetrics markMetrics; | 
| -        item->font->klass->getGlyphMetrics(item->font, mark, &markMetrics); | 
| -        HB_FixedPoint p; | 
| -        p.x = p.y = 0; | 
| -//          qDebug("markInfo: %f/%f (%f/%f) off=%f/%f", markInfo.x, markInfo.y, markInfo.width, markInfo.height, markInfo.xoff, markInfo.yoff); | 
| - | 
| -        HB_Fixed offset = offsetBase; | 
| -        unsigned char cmb = attributes[gfrom+i].combiningClass; | 
| - | 
| -        // ### maybe the whole position determination should move down to heuristicSetGlyphAttributes. Would save some | 
| -        // bits  in the glyphAttributes structure. | 
| -        if (cmb < 200) { | 
| -            // fixed position classes. We approximate by mapping to one of the others. | 
| -            // currently I added only the ones for arabic, hebrew, lao and thai. | 
| - | 
| -            // for Lao and Thai marks with class 0, see below (heuristicSetGlyphAttributes) | 
| - | 
| -            // add a bit more offset to arabic, a bit hacky | 
| -            if (cmb >= 27 && cmb <= 36 && offset < 3) | 
| -                offset +=1; | 
| -            // below | 
| -            if ((cmb >= 10 && cmb <= 18) || | 
| -                 cmb == 20 || cmb == 22 || | 
| -                 cmb == 29 || cmb == 32) | 
| -                cmb = HB_Combining_Below; | 
| -            // above | 
| -            else if (cmb == 23 || cmb == 27 || cmb == 28 || | 
| -                      cmb == 30 || cmb == 31 || (cmb >= 33 && cmb <= 36)) | 
| -                cmb = HB_Combining_Above; | 
| -            //below-right | 
| -            else if (cmb == 9 || cmb == 103 || cmb == 118) | 
| -                cmb = HB_Combining_BelowRight; | 
| -            // above-right | 
| -            else if (cmb == 24 || cmb == 107 || cmb == 122) | 
| -                cmb = HB_Combining_AboveRight; | 
| -            else if (cmb == 25) | 
| -                cmb = HB_Combining_AboveLeft; | 
| -            // fixed: | 
| -            //  19 21 | 
| - | 
| -        } | 
| - | 
| -        // combining marks of different class don't interact. Reset the rectangle. | 
| -        if (cmb != lastCmb) { | 
| -            //qDebug("resetting rect"); | 
| -            attachmentRect = baseMetrics; | 
| -        } | 
| - | 
| -        switch(cmb) { | 
| -        case HB_Combining_DoubleBelow: | 
| -                // ### wrong in rtl context! | 
| -        case HB_Combining_BelowLeft: | 
| -            p.y += offset; | 
| -        case HB_Combining_BelowLeftAttached: | 
| -            p.x += attachmentRect.x - markMetrics.x; | 
| -            p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y; | 
| -            break; | 
| -        case HB_Combining_Below: | 
| -            p.y += offset; | 
| -        case HB_Combining_BelowAttached: | 
| -            p.x += attachmentRect.x - markMetrics.x; | 
| -            p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y; | 
| - | 
| -            p.x += (attachmentRect.width - markMetrics.width) / 2; | 
| -            break; | 
| -        case HB_Combining_BelowRight: | 
| -            p.y += offset; | 
| -        case HB_Combining_BelowRightAttached: | 
| -            p.x += attachmentRect.x + attachmentRect.width - markMetrics.width - markMetrics.x; | 
| -            p.y += attachmentRect.y + attachmentRect.height - markMetrics.y; | 
| -            break; | 
| -        case HB_Combining_Left: | 
| -            p.x -= offset; | 
| -        case HB_Combining_LeftAttached: | 
| -            break; | 
| -        case HB_Combining_Right: | 
| -            p.x += offset; | 
| -        case HB_Combining_RightAttached: | 
| -            break; | 
| -        case HB_Combining_DoubleAbove: | 
| -            // ### wrong in RTL context! | 
| -        case HB_Combining_AboveLeft: | 
| -            p.y -= offset; | 
| -        case HB_Combining_AboveLeftAttached: | 
| -            p.x += attachmentRect.x - markMetrics.x; | 
| -            p.y += attachmentRect.y - markMetrics.y - markMetrics.height; | 
| -            break; | 
| -        case HB_Combining_Above: | 
| -            p.y -= offset; | 
| -        case HB_Combining_AboveAttached: | 
| -            p.x += attachmentRect.x - markMetrics.x; | 
| -            p.y += attachmentRect.y - markMetrics.y - markMetrics.height; | 
| - | 
| -            p.x += (attachmentRect.width - markMetrics.width) / 2; | 
| -            break; | 
| -        case HB_Combining_AboveRight: | 
| -            p.y -= offset; | 
| -        case HB_Combining_AboveRightAttached: | 
| -            p.x += attachmentRect.x + attachmentRect.width - markMetrics.x - markMetrics.width; | 
| -            p.y += attachmentRect.y - markMetrics.y - markMetrics.height; | 
| -            break; | 
| - | 
| -        case HB_Combining_IotaSubscript: | 
| -            default: | 
| -                break; | 
| -        } | 
| -//          qDebug("char=%x combiningClass = %d offset=%f/%f", mark, cmb, p.x(), p.y()); | 
| -        markMetrics.x += p.x; | 
| -        markMetrics.y += p.y; | 
| - | 
| -        HB_GlyphMetrics unitedAttachmentRect = attachmentRect; | 
| -        unitedAttachmentRect.x = HB_MIN(attachmentRect.x, markMetrics.x); | 
| -        unitedAttachmentRect.y = HB_MIN(attachmentRect.y, markMetrics.y); | 
| -        unitedAttachmentRect.width = HB_MAX(attachmentRect.x + attachmentRect.width, markMetrics.x + markMetrics.width) - unitedAttachmentRect.x; | 
| -        unitedAttachmentRect.height = HB_MAX(attachmentRect.y + attachmentRect.height, markMetrics.y + markMetrics.height) - unitedAttachmentRect.y; | 
| -        attachmentRect = unitedAttachmentRect; | 
| - | 
| -        lastCmb = cmb; | 
| -        if (rightToLeft) { | 
| -            item->offsets[gfrom+i].x = p.x; | 
| -            item->offsets[gfrom+i].y = p.y; | 
| -        } else { | 
| -            item->offsets[gfrom+i].x = p.x - baseMetrics.xOffset; | 
| -            item->offsets[gfrom+i].y = p.y - baseMetrics.yOffset; | 
| -        } | 
| -        item->advances[gfrom+i] = 0; | 
| -    } | 
| -} | 
| - | 
| -void HB_HeuristicPosition(HB_ShaperItem *item) | 
| -{ | 
| -    HB_GetGlyphAdvances(item); | 
| -    HB_GlyphAttributes *attributes = item->attributes; | 
| - | 
| -    int cEnd = -1; | 
| -    int i = item->num_glyphs; | 
| -    while (i--) { | 
| -        if (cEnd == -1 && attributes[i].mark) { | 
| -            cEnd = i; | 
| -        } else if (cEnd != -1 && !attributes[i].mark) { | 
| -            positionCluster(item, i, cEnd); | 
| -            cEnd = -1; | 
| -        } | 
| -    } | 
| -} | 
| - | 
| -// set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs | 
| -// and no reordering. | 
| -// also computes logClusters heuristically | 
| -void HB_HeuristicSetGlyphAttributes(HB_ShaperItem *item) | 
| -{ | 
| -    const HB_UChar16 *uc = item->string + item->item.pos; | 
| -    hb_uint32 length = item->item.length; | 
| - | 
| -    // ### zeroWidth and justification are missing here!!!!! | 
| - | 
| -    assert(length <= item->num_glyphs); | 
| - | 
| -//     qDebug("QScriptEngine::heuristicSetGlyphAttributes, num_glyphs=%d", item->num_glyphs); | 
| -    HB_GlyphAttributes *attributes = item->attributes; | 
| -    unsigned short *logClusters = item->log_clusters; | 
| - | 
| -    hb_uint32 glyph_pos = 0; | 
| -    hb_uint32 i; | 
| -    for (i = 0; i < length; i++) { | 
| -        if (HB_IsHighSurrogate(uc[i]) && i < length - 1 | 
| -            && HB_IsLowSurrogate(uc[i + 1])) { | 
| -            logClusters[i] = glyph_pos; | 
| -            logClusters[++i] = glyph_pos; | 
| -        } else { | 
| -            logClusters[i] = glyph_pos; | 
| -        } | 
| -        ++glyph_pos; | 
| -    } | 
| - | 
| -    // first char in a run is never (treated as) a mark | 
| -    int cStart = 0; | 
| -    const bool symbolFont = item->face->isSymbolFont; | 
| -    attributes[0].mark = false; | 
| -    attributes[0].clusterStart = true; | 
| -    attributes[0].dontPrint = (!symbolFont && uc[0] == 0x00ad) || HB_IsControlChar(uc[0]); | 
| - | 
| -    int pos = 0; | 
| -    HB_CharCategory lastCat; | 
| -    int dummy; | 
| -    HB_GetUnicodeCharProperties(uc[0], &lastCat, &dummy); | 
| -    for (i = 1; i < length; ++i) { | 
| -        if (logClusters[i] == pos) | 
| -            // same glyph | 
| -            continue; | 
| -        ++pos; | 
| -        while (pos < logClusters[i]) { | 
| -            attributes[pos] = attributes[pos-1]; | 
| -            ++pos; | 
| -        } | 
| -        // hide soft-hyphens by default | 
| -        if ((!symbolFont && uc[i] == 0x00ad) || HB_IsControlChar(uc[i])) | 
| -            attributes[pos].dontPrint = true; | 
| -        HB_CharCategory cat; | 
| -        int cmb; | 
| -        HB_GetUnicodeCharProperties(uc[i], &cat, &cmb); | 
| -        if (cat != HB_Mark_NonSpacing) { | 
| -            attributes[pos].mark = false; | 
| -            attributes[pos].clusterStart = true; | 
| -            attributes[pos].combiningClass = 0; | 
| -            cStart = logClusters[i]; | 
| -        } else { | 
| -            if (cmb == 0) { | 
| -                // Fix 0 combining classes | 
| -                if ((uc[pos] & 0xff00) == 0x0e00) { | 
| -                    // thai or lao | 
| -                    if (uc[pos] == 0xe31 || | 
| -                         uc[pos] == 0xe34 || | 
| -                         uc[pos] == 0xe35 || | 
| -                         uc[pos] == 0xe36 || | 
| -                         uc[pos] == 0xe37 || | 
| -                         uc[pos] == 0xe47 || | 
| -                         uc[pos] == 0xe4c || | 
| -                         uc[pos] == 0xe4d || | 
| -                         uc[pos] == 0xe4e) { | 
| -                        cmb = HB_Combining_AboveRight; | 
| -                    } else if (uc[pos] == 0xeb1 || | 
| -                                uc[pos] == 0xeb4 || | 
| -                                uc[pos] == 0xeb5 || | 
| -                                uc[pos] == 0xeb6 || | 
| -                                uc[pos] == 0xeb7 || | 
| -                                uc[pos] == 0xebb || | 
| -                                uc[pos] == 0xecc || | 
| -                                uc[pos] == 0xecd) { | 
| -                        cmb = HB_Combining_Above; | 
| -                    } else if (uc[pos] == 0xebc) { | 
| -                        cmb = HB_Combining_Below; | 
| -                    } | 
| -                } | 
| -            } | 
| - | 
| -            attributes[pos].mark = true; | 
| -            attributes[pos].clusterStart = false; | 
| -            attributes[pos].combiningClass = cmb; | 
| -            logClusters[i] = cStart; | 
| -        } | 
| -        // one gets an inter character justification point if the current char is not a non spacing mark. | 
| -        // as then the current char belongs to the last one and one gets a space justification point | 
| -        // after the space char. | 
| -        if (lastCat == HB_Separator_Space) | 
| -            attributes[pos-1].justification = HB_Space; | 
| -        else if (cat != HB_Mark_NonSpacing) | 
| -            attributes[pos-1].justification = HB_Character; | 
| -        else | 
| -            attributes[pos-1].justification = HB_NoJustification; | 
| - | 
| -        lastCat = cat; | 
| -    } | 
| -    pos = logClusters[length-1]; | 
| -    if (lastCat == HB_Separator_Space) | 
| -        attributes[pos].justification = HB_Space; | 
| -    else | 
| -        attributes[pos].justification = HB_Character; | 
| -} | 
| - | 
| -#ifndef NO_OPENTYPE | 
| -static const HB_OpenTypeFeature basic_features[] = { | 
| -    { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, | 
| -    { HB_MAKE_TAG('l', 'i', 'g', 'a'), CcmpProperty }, | 
| -    { HB_MAKE_TAG('c', 'l', 'i', 'g'), CcmpProperty }, | 
| -    {0, 0} | 
| -}; | 
| -#endif | 
| - | 
| -HB_Bool HB_ConvertStringToGlyphIndices(HB_ShaperItem *shaper_item) | 
| -{ | 
| -    if (shaper_item->glyphIndicesPresent) { | 
| -        shaper_item->num_glyphs = shaper_item->initialGlyphCount; | 
| -        shaper_item->glyphIndicesPresent = false; | 
| -        return true; | 
| -    } | 
| -    return shaper_item->font->klass | 
| -           ->convertStringToGlyphIndices(shaper_item->font, | 
| -                                         shaper_item->string + shaper_item->item.pos, shaper_item->item.length, | 
| -                                         shaper_item->glyphs, &shaper_item->num_glyphs, | 
| -                                         shaper_item->item.bidiLevel % 2); | 
| -} | 
| - | 
| -HB_Bool HB_BasicShape(HB_ShaperItem *shaper_item) | 
| -{ | 
| -#ifndef NO_OPENTYPE | 
| -    const int availableGlyphs = shaper_item->num_glyphs; | 
| -#endif | 
| - | 
| -    if (!HB_ConvertStringToGlyphIndices(shaper_item)) | 
| -        return false; | 
| - | 
| -    HB_HeuristicSetGlyphAttributes(shaper_item); | 
| - | 
| -#ifndef NO_OPENTYPE | 
| -    if (HB_SelectScript(shaper_item, basic_features)) { | 
| -        HB_OpenTypeShape(shaper_item, /*properties*/0); | 
| -        return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/true); | 
| -    } | 
| -#endif | 
| - | 
| -    HB_HeuristicPosition(shaper_item); | 
| -    return true; | 
| -} | 
| - | 
| -const HB_ScriptEngine HB_ScriptEngines[] = { | 
| -    // Common | 
| -    { HB_BasicShape, 0}, | 
| -    // Greek | 
| -    { HB_BasicShape, 0}, | 
| -    // Cyrillic | 
| -    { HB_BasicShape, 0}, | 
| -    // Armenian | 
| -    { HB_BasicShape, 0}, | 
| -    // Hebrew | 
| -    { HB_HebrewShape, 0 }, | 
| -    // Arabic | 
| -    { HB_ArabicShape, 0}, | 
| -    // Syriac | 
| -    { HB_ArabicShape, 0}, | 
| -    // Thaana | 
| -    { HB_BasicShape, 0 }, | 
| -    // Devanagari | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Bengali | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Gurmukhi | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Gujarati | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Oriya | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Tamil | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Telugu | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Kannada | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Malayalam | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Sinhala | 
| -    { HB_IndicShape, HB_IndicAttributes }, | 
| -    // Thai | 
| -    { HB_BasicShape, HB_ThaiAttributes }, | 
| -    // Lao | 
| -    { HB_BasicShape, 0 }, | 
| -    // Tibetan | 
| -    { HB_TibetanShape, HB_TibetanAttributes }, | 
| -    // Myanmar | 
| -    { HB_MyanmarShape, HB_MyanmarAttributes }, | 
| -    // Georgian | 
| -    { HB_BasicShape, 0 }, | 
| -    // Hangul | 
| -    { HB_HangulShape, 0 }, | 
| -    // Ogham | 
| -    { HB_BasicShape, 0 }, | 
| -    // Runic | 
| -    { HB_BasicShape, 0 }, | 
| -    // Khmer | 
| -    { HB_KhmerShape, HB_KhmerAttributes }, | 
| -    // N'Ko | 
| -    { HB_ArabicShape, 0} | 
| -}; | 
| - | 
| -void HB_GetCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength, | 
| -                          const HB_ScriptItem *items, hb_uint32 numItems, | 
| -                          HB_CharAttributes *attributes) | 
| -{ | 
| -    calcLineBreaks(string, stringLength, attributes); | 
| - | 
| -    for (hb_uint32 i = 0; i < numItems; ++i) { | 
| -        HB_Script script = items[i].script; | 
| -        if (script == HB_Script_Inherited) | 
| -            script = HB_Script_Common; | 
| -        HB_AttributeFunction attributeFunction = HB_ScriptEngines[script].charAttributes; | 
| -        if (!attributeFunction) | 
| -            continue; | 
| -        attributeFunction(script, string, items[i].pos, items[i].length, attributes); | 
| -    } | 
| -} | 
| - | 
| - | 
| -enum BreakRule { NoBreak = 0, Break = 1, Middle = 2 }; | 
| - | 
| -static const hb_uint8 wordbreakTable[HB_Word_ExtendNumLet + 1][HB_Word_ExtendNumLet + 1] = { | 
| -//        Other    Format   Katakana ALetter  MidLetter MidNum  Numeric  ExtendNumLet | 
| -    {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // Other | 
| -    {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // Format | 
| -    {   Break,   Break, NoBreak,   Break,   Break,   Break,   Break, NoBreak }, // Katakana | 
| -    {   Break,   Break,   Break, NoBreak,  Middle,   Break, NoBreak, NoBreak }, // ALetter | 
| -    {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // MidLetter | 
| -    {   Break,   Break,   Break,   Break,   Break,   Break,   Break,   Break }, // MidNum | 
| -    {   Break,   Break,   Break, NoBreak,   Break,  Middle, NoBreak, NoBreak }, // Numeric | 
| -    {   Break,   Break, NoBreak, NoBreak,   Break,   Break, NoBreak, NoBreak }, // ExtendNumLet | 
| -}; | 
| - | 
| -void HB_GetWordBoundaries(const HB_UChar16 *string, hb_uint32 stringLength, | 
| -                          const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/, | 
| -                          HB_CharAttributes *attributes) | 
| -{ | 
| -    if (stringLength == 0) | 
| -        return; | 
| -    unsigned int brk = HB_GetWordClass(string[0]); | 
| -    attributes[0].wordBoundary = true; | 
| -    for (hb_uint32 i = 1; i < stringLength; ++i) { | 
| -        if (!attributes[i].charStop) { | 
| -            attributes[i].wordBoundary = false; | 
| -            continue; | 
| -        } | 
| -        hb_uint32 nbrk = HB_GetWordClass(string[i]); | 
| -        if (nbrk == HB_Word_Format) { | 
| -            attributes[i].wordBoundary = (HB_GetSentenceClass(string[i-1]) == HB_Sentence_Sep); | 
| -            continue; | 
| -        } | 
| -        BreakRule rule = (BreakRule)wordbreakTable[brk][nbrk]; | 
| -        if (rule == Middle) { | 
| -            rule = Break; | 
| -            hb_uint32 lookahead = i + 1; | 
| -            while (lookahead < stringLength) { | 
| -                hb_uint32 testbrk = HB_GetWordClass(string[lookahead]); | 
| -                if (testbrk == HB_Word_Format && HB_GetSentenceClass(string[lookahead]) != HB_Sentence_Sep) { | 
| -                    ++lookahead; | 
| -                    continue; | 
| -                } | 
| -                if (testbrk == brk) { | 
| -                    rule = NoBreak; | 
| -                    while (i < lookahead) | 
| -                        attributes[i++].wordBoundary = false; | 
| -                    nbrk = testbrk; | 
| -                } | 
| -                break; | 
| -            } | 
| -        } | 
| -        attributes[i].wordBoundary = (rule == Break); | 
| -        brk = nbrk; | 
| -    } | 
| -} | 
| - | 
| - | 
| -enum SentenceBreakStates { | 
| -    SB_Initial, | 
| -    SB_Upper, | 
| -    SB_UpATerm, | 
| -    SB_ATerm, | 
| -    SB_ATermC, | 
| -    SB_ACS, | 
| -    SB_STerm, | 
| -    SB_STermC, | 
| -    SB_SCS, | 
| -    SB_BAfter, | 
| -    SB_Break, | 
| -    SB_Look | 
| -}; | 
| - | 
| -static const hb_uint8 sentenceBreakTable[HB_Sentence_Close + 1][HB_Sentence_Close + 1] = { | 
| -//        Other       Sep         Format      Sp          Lower       Upper       OLetter     Numeric     ATerm       STerm       Close | 
| -      { SB_Initial, SB_BAfter , SB_Initial, SB_Initial, SB_Initial, SB_Upper  , SB_Initial, SB_Initial, SB_ATerm  , SB_STerm  , SB_Initial }, // SB_Initial, | 
| -      { SB_Initial, SB_BAfter , SB_Upper  , SB_Initial, SB_Initial, SB_Upper  , SB_Initial, SB_Initial, SB_UpATerm, SB_STerm  , SB_Initial }, // SB_Upper | 
| - | 
| -      { SB_Look   , SB_BAfter , SB_UpATerm, SB_ACS    , SB_Initial, SB_Upper  , SB_Break  , SB_Initial, SB_ATerm  , SB_STerm  , SB_ATermC  }, // SB_UpATerm | 
| -      { SB_Look   , SB_BAfter , SB_ATerm  , SB_ACS    , SB_Initial, SB_Break  , SB_Break  , SB_Initial, SB_ATerm  , SB_STerm  , SB_ATermC  }, // SB_ATerm | 
| -      { SB_Look   , SB_BAfter , SB_ATermC , SB_ACS    , SB_Initial, SB_Break  , SB_Break  , SB_Look   , SB_ATerm  , SB_STerm  , SB_ATermC  }, // SB_ATermC, | 
| -      { SB_Look   , SB_BAfter , SB_ACS    , SB_ACS    , SB_Initial, SB_Break  , SB_Break  , SB_Look   , SB_ATerm  , SB_STerm  , SB_Look    }, // SB_ACS, | 
| - | 
| -      { SB_Break  , SB_BAfter , SB_STerm  , SB_SCS    , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_ATerm  , SB_STerm  , SB_STermC  }, // SB_STerm, | 
| -      { SB_Break  , SB_BAfter , SB_STermC , SB_SCS    , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_ATerm  , SB_STerm  , SB_STermC  }, // SB_STermC, | 
| -      { SB_Break  , SB_BAfter , SB_SCS    , SB_SCS    , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_ATerm  , SB_STerm  , SB_Break   }, // SB_SCS, | 
| -      { SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break  , SB_Break   }, // SB_BAfter, | 
| -}; | 
| - | 
| -void HB_GetSentenceBoundaries(const HB_UChar16 *string, hb_uint32 stringLength, | 
| -                              const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/, | 
| -                              HB_CharAttributes *attributes) | 
| -{ | 
| -    if (stringLength == 0) | 
| -        return; | 
| -    hb_uint32 brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[0])]; | 
| -    attributes[0].sentenceBoundary = true; | 
| -    for (hb_uint32 i = 1; i < stringLength; ++i) { | 
| -        if (!attributes[i].charStop) { | 
| -            attributes[i].sentenceBoundary = false; | 
| -            continue; | 
| -        } | 
| -        brk = sentenceBreakTable[brk][HB_GetSentenceClass(string[i])]; | 
| -        if (brk == SB_Look) { | 
| -            brk = SB_Break; | 
| -            hb_uint32 lookahead = i + 1; | 
| -            while (lookahead < stringLength) { | 
| -                hb_uint32 sbrk = HB_GetSentenceClass(string[lookahead]); | 
| -                if (sbrk != HB_Sentence_Other && sbrk != HB_Sentence_Numeric && sbrk != HB_Sentence_Close) { | 
| -                    break; | 
| -                } else if (sbrk == HB_Sentence_Lower) { | 
| -                    brk = SB_Initial; | 
| -                    break; | 
| -                } | 
| -                ++lookahead; | 
| -            } | 
| -            if (brk == SB_Initial) { | 
| -                while (i < lookahead) | 
| -                    attributes[i++].sentenceBoundary = false; | 
| -            } | 
| -        } | 
| -        if (brk == SB_Break) { | 
| -            attributes[i].sentenceBoundary = true; | 
| -            brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[i])]; | 
| -        } else { | 
| -            attributes[i].sentenceBoundary = false; | 
| -        } | 
| -    } | 
| -} | 
| - | 
| - | 
| -static inline char *tag_to_string(HB_UInt tag) | 
| -{ | 
| -    static char string[5]; | 
| -    string[0] = (tag >> 24)&0xff; | 
| -    string[1] = (tag >> 16)&0xff; | 
| -    string[2] = (tag >> 8)&0xff; | 
| -    string[3] = tag&0xff; | 
| -    string[4] = 0; | 
| -    return string; | 
| -} | 
| - | 
| -#ifdef OT_DEBUG | 
| -static void dump_string(HB_Buffer buffer) | 
| -{ | 
| -    for (uint i = 0; i < buffer->in_length; ++i) { | 
| -        qDebug("    %x: cluster=%d", buffer->in_string[i].gindex, buffer->in_string[i].cluster); | 
| -    } | 
| -} | 
| -#define DEBUG printf | 
| -#else | 
| -#define DEBUG if (1) ; else printf | 
| -#endif | 
| - | 
| -#define DefaultLangSys 0xffff | 
| -#define DefaultScript HB_MAKE_TAG('D', 'F', 'L', 'T') | 
| - | 
| -enum { | 
| -    RequiresGsub = 1, | 
| -    RequiresGpos = 2 | 
| -}; | 
| - | 
| -struct OTScripts { | 
| -    unsigned int tag; | 
| -    int flags; | 
| -}; | 
| -static const OTScripts ot_scripts [] = { | 
| -    // Common | 
| -    { HB_MAKE_TAG('l', 'a', 't', 'n'), 0 }, | 
| -    // Greek | 
| -    { HB_MAKE_TAG('g', 'r', 'e', 'k'), 0 }, | 
| -    // Cyrillic | 
| -    { HB_MAKE_TAG('c', 'y', 'r', 'l'), 0 }, | 
| -    // Armenian | 
| -    { HB_MAKE_TAG('a', 'r', 'm', 'n'), 0 }, | 
| -    // Hebrew | 
| -    { HB_MAKE_TAG('h', 'e', 'b', 'r'), 1 }, | 
| -    // Arabic | 
| -    { HB_MAKE_TAG('a', 'r', 'a', 'b'), 1 }, | 
| -    // Syriac | 
| -    { HB_MAKE_TAG('s', 'y', 'r', 'c'), 1 }, | 
| -    // Thaana | 
| -    { HB_MAKE_TAG('t', 'h', 'a', 'a'), 1 }, | 
| -    // Devanagari | 
| -    { HB_MAKE_TAG('d', 'e', 'v', 'a'), 1 }, | 
| -    // Bengali | 
| -    { HB_MAKE_TAG('b', 'e', 'n', 'g'), 1 }, | 
| -    // Gurmukhi | 
| -    { HB_MAKE_TAG('g', 'u', 'r', 'u'), 1 }, | 
| -    // Gujarati | 
| -    { HB_MAKE_TAG('g', 'u', 'j', 'r'), 1 }, | 
| -    // Oriya | 
| -    { HB_MAKE_TAG('o', 'r', 'y', 'a'), 1 }, | 
| -    // Tamil | 
| -    { HB_MAKE_TAG('t', 'a', 'm', 'l'), 1 }, | 
| -    // Telugu | 
| -    { HB_MAKE_TAG('t', 'e', 'l', 'u'), 1 }, | 
| -    // Kannada | 
| -    { HB_MAKE_TAG('k', 'n', 'd', 'a'), 1 }, | 
| -    // Malayalam | 
| -    { HB_MAKE_TAG('m', 'l', 'y', 'm'), 1 }, | 
| -    // Sinhala | 
| -    { HB_MAKE_TAG('s', 'i', 'n', 'h'), 1 }, | 
| -    // Thai | 
| -    { HB_MAKE_TAG('t', 'h', 'a', 'i'), 1 }, | 
| -    // Lao | 
| -    { HB_MAKE_TAG('l', 'a', 'o', ' '), 1 }, | 
| -    // Tibetan | 
| -    { HB_MAKE_TAG('t', 'i', 'b', 't'), 1 }, | 
| -    // Myanmar | 
| -    { HB_MAKE_TAG('m', 'y', 'm', 'r'), 1 }, | 
| -    // Georgian | 
| -    { HB_MAKE_TAG('g', 'e', 'o', 'r'), 0 }, | 
| -    // Hangul | 
| -    { HB_MAKE_TAG('h', 'a', 'n', 'g'), 1 }, | 
| -    // Ogham | 
| -    { HB_MAKE_TAG('o', 'g', 'a', 'm'), 0 }, | 
| -    // Runic | 
| -    { HB_MAKE_TAG('r', 'u', 'n', 'r'), 0 }, | 
| -    // Khmer | 
| -    { HB_MAKE_TAG('k', 'h', 'm', 'r'), 1 }, | 
| -    // N'Ko | 
| -    { HB_MAKE_TAG('n', 'k', 'o', ' '), 1 } | 
| -}; | 
| -enum { NumOTScripts = sizeof(ot_scripts)/sizeof(OTScripts) }; | 
| - | 
| -static HB_Bool checkScript(HB_Face face, int script) | 
| -{ | 
| -    assert(script < HB_ScriptCount); | 
| - | 
| -    if (!face->gsub && !face->gpos) | 
| -        return false; | 
| - | 
| -    unsigned int tag = ot_scripts[script].tag; | 
| -    int requirements = ot_scripts[script].flags; | 
| - | 
| -    if (requirements & RequiresGsub) { | 
| -        if (!face->gsub) | 
| -            return false; | 
| - | 
| -        HB_UShort script_index; | 
| -        HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index); | 
| -        if (error) { | 
| -            DEBUG("could not select script %d in GSub table: %d", (int)script, error); | 
| -            error = HB_GSUB_Select_Script(face->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index); | 
| -            if (error) | 
| -                return false; | 
| -        } | 
| -    } | 
| - | 
| -    if (requirements & RequiresGpos) { | 
| -        if (!face->gpos) | 
| -            return false; | 
| - | 
| -        HB_UShort script_index; | 
| -        HB_Error error = HB_GPOS_Select_Script(face->gpos, script, &script_index); | 
| -        if (error) { | 
| -            DEBUG("could not select script in gpos table: %d", error); | 
| -            error = HB_GPOS_Select_Script(face->gpos, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index); | 
| -            if (error) | 
| -                return false; | 
| -        } | 
| - | 
| -    } | 
| -    return true; | 
| -} | 
| - | 
| -static HB_Stream getTableStream(void *font, HB_GetFontTableFunc tableFunc, HB_Tag tag) | 
| -{ | 
| -    HB_Error error; | 
| -    HB_UInt length = 0; | 
| -    HB_Stream stream = 0; | 
| - | 
| -    if (!font) | 
| -        return 0; | 
| - | 
| -    error = tableFunc(font, tag, 0, &length); | 
| -    if (error) | 
| -        return 0; | 
| -    stream = (HB_Stream)malloc(sizeof(HB_StreamRec)); | 
| -    if (!stream) | 
| -        return 0; | 
| -    stream->base = (HB_Byte*)malloc(length); | 
| -    if (!stream->base) { | 
| -        free(stream); | 
| -        return 0; | 
| -    } | 
| -    error = tableFunc(font, tag, stream->base, &length); | 
| -    if (error) { | 
| -        _hb_close_stream(stream); | 
| -        return 0; | 
| -    } | 
| -    stream->size = length; | 
| -    stream->pos = 0; | 
| -    stream->cursor = NULL; | 
| -    return stream; | 
| -} | 
| - | 
| -HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc) | 
| -{ | 
| -    HB_Face face = (HB_Face )malloc(sizeof(HB_FaceRec)); | 
| -    if (!face) | 
| -        return 0; | 
| - | 
| -    face->isSymbolFont = false; | 
| -    face->gdef = 0; | 
| -    face->gpos = 0; | 
| -    face->gsub = 0; | 
| -    face->current_script = HB_ScriptCount; | 
| -    face->current_flags = HB_ShaperFlag_Default; | 
| -    face->has_opentype_kerning = false; | 
| -    face->tmpAttributes = 0; | 
| -    face->tmpLogClusters = 0; | 
| -    face->glyphs_substituted = false; | 
| -    face->buffer = 0; | 
| - | 
| -    HB_Error error; | 
| -    HB_Stream stream; | 
| -    HB_Stream gdefStream; | 
| - | 
| -    gdefStream = getTableStream(font, tableFunc, TTAG_GDEF); | 
| -    if (!gdefStream || (error = HB_Load_GDEF_Table(gdefStream, &face->gdef))) { | 
| -        //DEBUG("error loading gdef table: %d", error); | 
| -        face->gdef = 0; | 
| -    } | 
| - | 
| -    //DEBUG() << "trying to load gsub table"; | 
| -    stream = getTableStream(font, tableFunc, TTAG_GSUB); | 
| -    if (!stream || (error = HB_Load_GSUB_Table(stream, &face->gsub, face->gdef, gdefStream))) { | 
| -        face->gsub = 0; | 
| -        if (error != HB_Err_Not_Covered) { | 
| -            //DEBUG("error loading gsub table: %d", error); | 
| -        } else { | 
| -            //DEBUG("face doesn't have a gsub table"); | 
| -        } | 
| -    } | 
| -    _hb_close_stream(stream); | 
| - | 
| -    stream = getTableStream(font, tableFunc, TTAG_GPOS); | 
| -    if (!stream || (error = HB_Load_GPOS_Table(stream, &face->gpos, face->gdef, gdefStream))) { | 
| -        face->gpos = 0; | 
| -        DEBUG("error loading gpos table: %d", error); | 
| -    } | 
| -    _hb_close_stream(stream); | 
| - | 
| -    _hb_close_stream(gdefStream); | 
| - | 
| -    for (unsigned int i = 0; i < HB_ScriptCount; ++i) | 
| -        face->supported_scripts[i] = checkScript(face, i); | 
| - | 
| -    if (hb_buffer_new(&face->buffer) != HB_Err_Ok) { | 
| -        HB_FreeFace(face); | 
| -        return 0; | 
| -    } | 
| - | 
| -    return face; | 
| -} | 
| - | 
| -void HB_FreeFace(HB_Face face) | 
| -{ | 
| -    if (!face) | 
| -        return; | 
| -    if (face->gpos) | 
| -        HB_Done_GPOS_Table(face->gpos); | 
| -    if (face->gsub) | 
| -        HB_Done_GSUB_Table(face->gsub); | 
| -    if (face->gdef) | 
| -        HB_Done_GDEF_Table(face->gdef); | 
| -    if (face->buffer) | 
| -        hb_buffer_free(face->buffer); | 
| -    if (face->tmpAttributes) | 
| -        free(face->tmpAttributes); | 
| -    if (face->tmpLogClusters) | 
| -        free(face->tmpLogClusters); | 
| -    free(face); | 
| -} | 
| - | 
| -HB_Bool HB_SelectScript(HB_ShaperItem *shaper_item, const HB_OpenTypeFeature *features) | 
| -{ | 
| -    HB_Script script = shaper_item->item.script; | 
| - | 
| -    if (!shaper_item->face->supported_scripts[script]) | 
| -        return false; | 
| - | 
| -    HB_Face face = shaper_item->face; | 
| -    if (face->current_script == script && face->current_flags == shaper_item->shaperFlags) | 
| -        return true; | 
| - | 
| -    face->current_script = script; | 
| -    face->current_flags = shaper_item->shaperFlags; | 
| - | 
| -    assert(script < HB_ScriptCount); | 
| -    // find script in our list of supported scripts. | 
| -    unsigned int tag = ot_scripts[script].tag; | 
| - | 
| -    if (face->gsub && features) { | 
| -#ifdef OT_DEBUG | 
| -        { | 
| -            HB_FeatureList featurelist = face->gsub->FeatureList; | 
| -            int numfeatures = featurelist.FeatureCount; | 
| -            DEBUG("gsub table has %d features", numfeatures); | 
| -            for (int i = 0; i < numfeatures; i++) { | 
| -                HB_FeatureRecord *r = featurelist.FeatureRecord + i; | 
| -                DEBUG("   feature '%s'", tag_to_string(r->FeatureTag)); | 
| -            } | 
| -        } | 
| -#endif | 
| -        HB_GSUB_Clear_Features(face->gsub); | 
| -        HB_UShort script_index; | 
| -        HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index); | 
| -        if (!error) { | 
| -            DEBUG("script %s has script index %d", tag_to_string(script), script_index); | 
| -            while (features->tag) { | 
| -                HB_UShort feature_index; | 
| -                error = HB_GSUB_Select_Feature(face->gsub, features->tag, script_index, 0xffff, &feature_index); | 
| -                if (!error) { | 
| -                    DEBUG("  adding feature %s", tag_to_string(features->tag)); | 
| -                    HB_GSUB_Add_Feature(face->gsub, feature_index, features->property); | 
| -                } | 
| -                ++features; | 
| -            } | 
| -        } | 
| -    } | 
| - | 
| -    // reset | 
| -    face->has_opentype_kerning = false; | 
| - | 
| -    if (face->gpos) { | 
| -        HB_GPOS_Clear_Features(face->gpos); | 
| -        HB_UShort script_index; | 
| -        HB_Error error = HB_GPOS_Select_Script(face->gpos, tag, &script_index); | 
| -        if (!error) { | 
| -#ifdef OT_DEBUG | 
| -            { | 
| -                HB_FeatureList featurelist = face->gpos->FeatureList; | 
| -                int numfeatures = featurelist.FeatureCount; | 
| -                DEBUG("gpos table has %d features", numfeatures); | 
| -                for(int i = 0; i < numfeatures; i++) { | 
| -                    HB_FeatureRecord *r = featurelist.FeatureRecord + i; | 
| -                    HB_UShort feature_index; | 
| -                    HB_GPOS_Select_Feature(face->gpos, r->FeatureTag, script_index, 0xffff, &feature_index); | 
| -                    DEBUG("   feature '%s'", tag_to_string(r->FeatureTag)); | 
| -                } | 
| -            } | 
| -#endif | 
| -            HB_UInt *feature_tag_list_buffer; | 
| -            error = HB_GPOS_Query_Features(face->gpos, script_index, 0xffff, &feature_tag_list_buffer); | 
| -            if (!error) { | 
| -                HB_UInt *feature_tag_list = feature_tag_list_buffer; | 
| -                while (*feature_tag_list) { | 
| -                    HB_UShort feature_index; | 
| -                    if (*feature_tag_list == HB_MAKE_TAG('k', 'e', 'r', 'n')) { | 
| -                        if (face->current_flags & HB_ShaperFlag_NoKerning) { | 
| -                            ++feature_tag_list; | 
| -                            continue; | 
| -                        } | 
| -                        face->has_opentype_kerning = true; | 
| -                    } | 
| -                    error = HB_GPOS_Select_Feature(face->gpos, *feature_tag_list, script_index, 0xffff, &feature_index); | 
| -                    if (!error) | 
| -                        HB_GPOS_Add_Feature(face->gpos, feature_index, PositioningProperties); | 
| -                    ++feature_tag_list; | 
| -                } | 
| -                FREE(feature_tag_list_buffer); | 
| -            } | 
| -        } | 
| -    } | 
| - | 
| -    return true; | 
| -} | 
| - | 
| -HB_Bool HB_OpenTypeShape(HB_ShaperItem *item, const hb_uint32 *properties) | 
| -{ | 
| -    HB_GlyphAttributes *tmpAttributes; | 
| -    unsigned int *tmpLogClusters; | 
| - | 
| -    HB_Face face = item->face; | 
| - | 
| -    face->length = item->num_glyphs; | 
| - | 
| -    hb_buffer_clear(face->buffer); | 
| - | 
| -    tmpAttributes = (HB_GlyphAttributes *) realloc(face->tmpAttributes, face->length*sizeof(HB_GlyphAttributes)); | 
| -    if (!tmpAttributes) | 
| -        return false; | 
| -    face->tmpAttributes = tmpAttributes; | 
| - | 
| -    tmpLogClusters = (unsigned int *) realloc(face->tmpLogClusters, face->length*sizeof(unsigned int)); | 
| -    if (!tmpLogClusters) | 
| -        return false; | 
| -    face->tmpLogClusters = tmpLogClusters; | 
| - | 
| -    for (int i = 0; i < face->length; ++i) { | 
| -        hb_buffer_add_glyph(face->buffer, item->glyphs[i], properties ? properties[i] : 0, i); | 
| -        face->tmpAttributes[i] = item->attributes[i]; | 
| -        face->tmpLogClusters[i] = item->log_clusters[i]; | 
| -    } | 
| - | 
| -#ifdef OT_DEBUG | 
| -    DEBUG("-----------------------------------------"); | 
| -//     DEBUG("log clusters before shaping:"); | 
| -//     for (int j = 0; j < length; j++) | 
| -//         DEBUG("    log[%d] = %d", j, item->log_clusters[j]); | 
| -    DEBUG("original glyphs: %p", item->glyphs); | 
| -    for (int i = 0; i < length; ++i) | 
| -        DEBUG("   glyph=%4x", hb_buffer->in_string[i].gindex); | 
| -//     dump_string(hb_buffer); | 
| -#endif | 
| - | 
| -    face->glyphs_substituted = false; | 
| -    if (face->gsub) { | 
| -        unsigned int error = HB_GSUB_Apply_String(face->gsub, face->buffer); | 
| -        if (error && error != HB_Err_Not_Covered) | 
| -            return false; | 
| -        face->glyphs_substituted = (error != HB_Err_Not_Covered); | 
| -    } | 
| - | 
| -#ifdef OT_DEBUG | 
| -//     DEBUG("log clusters before shaping:"); | 
| -//     for (int j = 0; j < length; j++) | 
| -//         DEBUG("    log[%d] = %d", j, item->log_clusters[j]); | 
| -    DEBUG("shaped glyphs:"); | 
| -    for (int i = 0; i < length; ++i) | 
| -        DEBUG("   glyph=%4x", hb_buffer->in_string[i].gindex); | 
| -    DEBUG("-----------------------------------------"); | 
| -//     dump_string(hb_buffer); | 
| -#endif | 
| - | 
| -    return true; | 
| -} | 
| - | 
| -/* See comments near the definition of HB_ShaperFlag_ForceMarksToZeroWidth for a description | 
| -   of why this function exists. */ | 
| -void HB_FixupZeroWidth(HB_ShaperItem *item) | 
| -{ | 
| -    HB_UShort property; | 
| - | 
| -    if (!item->face->gdef) | 
| -        return; | 
| - | 
| -    for (unsigned int i = 0; i < item->num_glyphs; ++i) { | 
| -        /* If the glyph is a mark, force its advance to zero. */ | 
| -        if (HB_GDEF_Get_Glyph_Property (item->face->gdef, item->glyphs[i], &property) == HB_Err_Ok && | 
| -            property == HB_GDEF_MARK) { | 
| -            item->advances[i] = 0; | 
| -        } | 
| -    } | 
| -} | 
| - | 
| -HB_Bool HB_OpenTypePosition(HB_ShaperItem *item, int availableGlyphs, HB_Bool doLogClusters) | 
| -{ | 
| -    HB_Face face = item->face; | 
| - | 
| -    bool glyphs_positioned = false; | 
| -    if (face->gpos) { | 
| -        if (face->buffer->positions) | 
| -            memset(face->buffer->positions, 0, face->buffer->in_length*sizeof(HB_PositionRec)); | 
| -        // #### check that passing "false,false" is correct | 
| -        glyphs_positioned = HB_GPOS_Apply_String(item->font, face->gpos, face->current_flags, face->buffer, false, false) != HB_Err_Not_Covered; | 
| -    } | 
| - | 
| -    if (!face->glyphs_substituted && !glyphs_positioned) { | 
| -        HB_GetGlyphAdvances(item); | 
| -        if (item->face->current_flags & HB_ShaperFlag_ForceMarksToZeroWidth) | 
| -            HB_FixupZeroWidth(item); | 
| -        return true; // nothing to do for us | 
| -    } | 
| - | 
| -    // make sure we have enough space to write everything back | 
| -    if (availableGlyphs < (int)face->buffer->in_length) { | 
| -        item->num_glyphs = face->buffer->in_length; | 
| -        return false; | 
| -    } | 
| - | 
| -    HB_Glyph *glyphs = item->glyphs; | 
| -    HB_GlyphAttributes *attributes = item->attributes; | 
| - | 
| -    for (unsigned int i = 0; i < face->buffer->in_length; ++i) { | 
| -        glyphs[i] = face->buffer->in_string[i].gindex; | 
| -        attributes[i] = face->tmpAttributes[face->buffer->in_string[i].cluster]; | 
| -        if (i && face->buffer->in_string[i].cluster == face->buffer->in_string[i-1].cluster) | 
| -            attributes[i].clusterStart = false; | 
| -    } | 
| -    item->num_glyphs = face->buffer->in_length; | 
| - | 
| -    if (doLogClusters && face->glyphs_substituted) { | 
| -        // we can't do this for indic, as we pass the stuf in syllables and it's easier to do it in the shaper. | 
| -        unsigned short *logClusters = item->log_clusters; | 
| -        int clusterStart = 0; | 
| -        int oldCi = 0; | 
| -        // #### the reconstruction of the logclusters currently does not work if the original string | 
| -        // contains surrogate pairs | 
| -        for (unsigned int i = 0; i < face->buffer->in_length; ++i) { | 
| -            int ci = face->buffer->in_string[i].cluster; | 
| -            //         DEBUG("   ci[%d] = %d mark=%d, cmb=%d, cs=%d", | 
| -            //                i, ci, glyphAttributes[i].mark, glyphAttributes[i].combiningClass, glyphAttributes[i].clusterStart); | 
| -            if (!attributes[i].mark && attributes[i].clusterStart && ci != oldCi) { | 
| -                for (int j = oldCi; j < ci; j++) | 
| -                    logClusters[j] = clusterStart; | 
| -                clusterStart = i; | 
| -                oldCi = ci; | 
| -            } | 
| -        } | 
| -        for (int j = oldCi; j < face->length; j++) | 
| -            logClusters[j] = clusterStart; | 
| -    } | 
| - | 
| -    // calulate the advances for the shaped glyphs | 
| -//     DEBUG("unpositioned: "); | 
| - | 
| -    // positioning code: | 
| -    if (glyphs_positioned) { | 
| -        HB_GetGlyphAdvances(item); | 
| -        HB_Position positions = face->buffer->positions; | 
| -        HB_Fixed *advances = item->advances; | 
| - | 
| -//         DEBUG("positioned glyphs:"); | 
| -        for (unsigned int i = 0; i < face->buffer->in_length; i++) { | 
| -//             DEBUG("    %d:\t orig advance: (%d/%d)\tadv=(%d/%d)\tpos=(%d/%d)\tback=%d\tnew_advance=%d", i, | 
| -//                    glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(), | 
| -//                    (int)(positions[i].x_advance >> 6), (int)(positions[i].y_advance >> 6), | 
| -//                    (int)(positions[i].x_pos >> 6), (int)(positions[i].y_pos >> 6), | 
| -//                    positions[i].back, positions[i].new_advance); | 
| - | 
| -            HB_Fixed adjustment = (item->item.bidiLevel % 2) ? -positions[i].x_advance : positions[i].x_advance; | 
| - | 
| -            if (!(face->current_flags & HB_ShaperFlag_UseDesignMetrics)) | 
| -                adjustment = HB_FIXED_ROUND(adjustment); | 
| - | 
| -            if (positions[i].new_advance) { | 
| -                advances[i] = adjustment; | 
| -            } else { | 
| -                advances[i] += adjustment; | 
| -            } | 
| - | 
| -            int back = 0; | 
| -            HB_FixedPoint *offsets = item->offsets; | 
| -            offsets[i].x = positions[i].x_pos; | 
| -            offsets[i].y = positions[i].y_pos; | 
| -            while (positions[i - back].back) { | 
| -                back += positions[i - back].back; | 
| -                offsets[i].x += positions[i - back].x_pos; | 
| -                offsets[i].y += positions[i - back].y_pos; | 
| -            } | 
| -            offsets[i].y = -offsets[i].y; | 
| - | 
| -            if (item->item.bidiLevel % 2) { | 
| -                // ### may need to go back multiple glyphs like in ltr | 
| -                back = positions[i].back; | 
| -                while (back--) | 
| -                    offsets[i].x -= advances[i-back]; | 
| -            } else { | 
| -                back = 0; | 
| -                while (positions[i - back].back) { | 
| -                    back += positions[i - back].back; | 
| -                    offsets[i].x -= advances[i-back]; | 
| -                } | 
| -            } | 
| -//             DEBUG("   ->\tadv=%d\tpos=(%d/%d)", | 
| -//                    glyphs[i].advance.x.toInt(), glyphs[i].offset.x.toInt(), glyphs[i].offset.y.toInt()); | 
| -        } | 
| -        item->kerning_applied = face->has_opentype_kerning; | 
| -    } else { | 
| -        HB_HeuristicPosition(item); | 
| -    } | 
| - | 
| -#ifdef OT_DEBUG | 
| -    if (doLogClusters) { | 
| -        DEBUG("log clusters after shaping:"); | 
| -        for (int j = 0; j < length; j++) | 
| -            DEBUG("    log[%d] = %d", j, item->log_clusters[j]); | 
| -    } | 
| -    DEBUG("final glyphs:"); | 
| -    for (int i = 0; i < (int)hb_buffer->in_length; ++i) | 
| -        DEBUG("   glyph=%4x char_index=%d mark: %d cmp: %d, clusterStart: %d advance=%d/%d offset=%d/%d", | 
| -               glyphs[i].glyph, hb_buffer->in_string[i].cluster, glyphs[i].attributes.mark, | 
| -               glyphs[i].attributes.combiningClass, glyphs[i].attributes.clusterStart, | 
| -               glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(), | 
| -               glyphs[i].offset.x.toInt(), glyphs[i].offset.y.toInt()); | 
| -    DEBUG("-----------------------------------------"); | 
| -#endif | 
| -    return true; | 
| -} | 
| - | 
| -HB_Bool HB_ShapeItem(HB_ShaperItem *shaper_item) | 
| -{ | 
| -    HB_Bool result = false; | 
| -    if (shaper_item->num_glyphs < shaper_item->item.length) { | 
| -        shaper_item->num_glyphs = shaper_item->item.length; | 
| -        return false; | 
| -    } | 
| -    assert(shaper_item->item.script < HB_ScriptCount); | 
| -    result = HB_ScriptEngines[shaper_item->item.script].shape(shaper_item); | 
| -    shaper_item->glyphIndicesPresent = false; | 
| -    return result; | 
| -} | 
| - | 
|  |