diff options
Diffstat (limited to 'tqtinterface/qt4/include/private/qt4_harfbuzz/src/harfbuzz-shaper.cpp')
-rw-r--r-- | tqtinterface/qt4/include/private/qt4_harfbuzz/src/harfbuzz-shaper.cpp | 1338 |
1 files changed, 0 insertions, 1338 deletions
diff --git a/tqtinterface/qt4/include/private/qt4_harfbuzz/src/harfbuzz-shaper.cpp b/tqtinterface/qt4/include/private/qt4_harfbuzz/src/harfbuzz-shaper.cpp deleted file mode 100644 index ce4d4ac..0000000 --- a/tqtinterface/qt4/include/private/qt4_harfbuzz/src/harfbuzz-shaper.cpp +++ /dev/null @@ -1,1338 +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; - - { - int tcls = ncls; - // for south east asian chars that require a complex (dictionary analysis), the unicode - // standard recommends to treat them as AL. thai_attributes and other attribute methods that - // do dictionary analysis can override - if (tcls >= HB_LineBreak_SA) - tcls = HB_LineBreak_AL; - if (cls >= HB_LineBreak_SA) - cls = HB_LineBreak_AL; - - 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(item->num_glyphs <= length); - -// 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; - } - assert(glyph_pos == item->num_glyphs); - - // 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_GreekShape, 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_Err_Ok; - HB_Stream stream; - HB_Stream gdefStream; - - gdefStream = getTableStream(font, tableFunc, TTAG_GDEF); - error = HB_Err_Not_Covered; - 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); - error = HB_Err_Not_Covered; - 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); - error = HB_Err_Not_Covered; - 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; -} - -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); - 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; -} - |