diff options
Diffstat (limited to 'src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp')
-rw-r--r-- | src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp | 1111 |
1 files changed, 0 insertions, 1111 deletions
diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp deleted file mode 100644 index 82977db5e7..0000000000 --- a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp +++ /dev/null @@ -1,1111 +0,0 @@ -/* - * Copyright (C) 2015 The Qt Company Ltd - * - * 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)) - -// -------------------------------------------------------------------------------------------------------------------------------------------- -// -// 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); - - // To fix some Thai character heights check for two above glyphs - if (nmarks == 2 && (attributes[gfrom+1].combiningClass == HB_Combining_AboveRight || - attributes[gfrom+1].combiningClass == HB_Combining_AboveLeft || - attributes[gfrom+1].combiningClass == HB_Combining_Above)) - if (attributes[gfrom+2].combiningClass == 23 || - attributes[gfrom+2].combiningClass == 24 || - attributes[gfrom+2].combiningClass == 25 || - attributes[gfrom+2].combiningClass == 27 || - attributes[gfrom+2].combiningClass == 28 || - attributes[gfrom+2].combiningClass == 30 || - attributes[gfrom+2].combiningClass == 31 || - attributes[gfrom+2].combiningClass == 33 || - attributes[gfrom+2].combiningClass == 34 || - attributes[gfrom+2].combiningClass == 35 || - attributes[gfrom+2].combiningClass == 36 || - attributes[gfrom+2].combiningClass == 107 || - attributes[gfrom+2].combiningClass == 122) { - // Two above glyphs, check total height - int markTotalHeight = baseMetrics.height; - HB_GlyphMetrics markMetrics; - item->font->klass->getGlyphMetrics(item->font, glyphs[gfrom+1], &markMetrics); - markTotalHeight += markMetrics.height; - item->font->klass->getGlyphMetrics(item->font, glyphs[gfrom+2], &markMetrics); - markTotalHeight += markMetrics.height; - if ((markTotalHeight + 2 * offsetBase) > (size * 10)) - offsetBase = ((size * 10) - markTotalHeight) / 2; // Use offset that just fits - } - - const bool rightToLeft = (item->item.bidiLevel % 2) != 0; - - 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; - // fall through - 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; - // fall through - 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; - // fall through - 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; - // fall through - case HB_Combining_LeftAttached: - break; - case HB_Combining_Right: - p.x += offset; - // fall through - case HB_Combining_RightAttached: - break; - case HB_Combining_DoubleAbove: - // ### wrong in RTL context! - case HB_Combining_AboveLeft: - p.y -= offset; - // fall through - 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; - // fall through - 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; - // fall through - 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 != 0; - 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'), LigaProperty }, - { HB_MAKE_TAG('c', 'l', 'i', 'g'), CligProperty }, - {0, 0} -}; - -static const HB_OpenTypeFeature disabled_features[] = { - { HB_MAKE_TAG('c', 'p', 'c', 't'), PositioningProperties }, - { HB_MAKE_TAG('h', 'a', 'l', 't'), PositioningProperties }, - // TODO: we need to add certain HB_ShaperFlag for vertical - // writing mode to enable these vertical writing features: - { HB_MAKE_TAG('v', 'a', 'l', 't'), PositioningProperties }, - { HB_MAKE_TAG('v', 'h', 'a', 'l'), PositioningProperties }, - { HB_MAKE_TAG('v', 'k', 'r', 'n'), PositioningProperties }, - { HB_MAKE_TAG('v', 'p', 'a', 'l'), PositioningProperties }, - {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_ThaiShape, 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_GetTailoredCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength, - const HB_ScriptItem *items, hb_uint32 numItems, - HB_CharAttributes *attributes) -{ - if (stringLength == 0) - return; - 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); - } -} - - -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_AllocFace(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; - face->font_for_init = font; - face->get_font_table_func = tableFunc; - - return face; -} - -HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc) -{ - HB_Face face = HB_AllocFace(font, tableFunc); - if (face) - face = HB_LoadFace(face); - return face; -} - -HB_Face HB_LoadFace(HB_Face face) -{ - void *font = face->font_for_init; - if (!font) - return face; - - HB_GetFontTableFunc tableFunc = face->get_font_table_func; - - face->get_font_table_func = 0; - face->font_for_init = 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); -} - -#ifndef NO_OPENTYPE -HB_Bool HB_SelectScript(HB_ShaperItem *shaper_item, const HB_OpenTypeFeature *features) -{ - HB_Script script = shaper_item->item.script; - - HB_Face face = shaper_item->face; - if (face->current_script == script && face->current_flags == shaper_item->shaperFlags) - return shaper_item->face->supported_scripts[script] ? true : false; - - face->current_script = script; - face->current_flags = shaper_item->shaperFlags; - - if (!shaper_item->face->supported_scripts[script]) - return false; - - 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; - bool skip = false; - if (*feature_tag_list == HB_MAKE_TAG('k', 'e', 'r', 'n')) { - if (face->current_flags & HB_ShaperFlag_NoKerning) - skip = true; - else - face->has_opentype_kerning = true; - } - features = disabled_features; - while (features->tag) { - if (*feature_tag_list == features->tag) { - skip = true; - break; - } - ++features; - } - // 'palt' should be turned off by default unless 'kern' is on - if (!face->has_opentype_kerning && - *feature_tag_list == HB_MAKE_TAG('p', 'a', 'l', 't')) - skip = true; - - if (skip) { - ++feature_tag_list; - continue; - } - 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; -} - -static HB_Bool containsSurrogates(HB_ShaperItem *item) -{ - for (hb_uint32 i=item->item.pos; i<item->item.pos+item->item.length; ++i) { - HB_UChar16 ucs = item->string[i]; - if ( HB_IsHighSurrogate(ucs) || HB_IsLowSurrogate(ucs) ) - return true; - } - - return false; -} - -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 && !containsSurrogates(item)) { - 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_HeuristicPosition(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 = 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:\n"); - for (unsigned int j = 0; j < item->item.length; j++) - DEBUG(" log[%d] = %d\n", j, item->log_clusters[j]); - } - DEBUG("final glyphs:\n"); - for (unsigned int i = 0; i < item->num_glyphs; ++i) - DEBUG(" glyph=%4x char_index=%d mark: %d cmp: %d, clusterStart: %d advance=%d offset=%d/%d\n", - glyphs[i], face->buffer->in_string[i].cluster, attributes[i].mark, - attributes[i].combiningClass, attributes[i].clusterStart, - item->advances[i] >> 6, - item->offsets[i].x >> 6, item->offsets[i].y >> 6); - DEBUG("-----------------------------------------\n"); -#endif - return true; -} -#endif // NO_OPENTYPE - -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; -} - |