📄 qopentype.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qdebug.h"#include "qopentype_p.h"#include "qfontengine_ft_p.h"#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)#include "qfontengine_qpf_p.h"#endif#include "qscriptengine_p.h"#ifndef QT_NO_OPENTYPE// --------------------------------------------------------------------------------------------------------------------// Open type support// --------------------------------------------------------------------------------------------------------------------//#define OT_DEBUGstatic inline char *tag_to_string(FT_ULong 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_DEBUGstatic 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 qDebug#else#define DEBUG if (1) ; else qDebug#endif#define DefaultLangSys 0xffff#define DefaultScript FT_MAKE_TAG('D', 'F', 'L', 'T')enum { RequiresGsub = 1, RequiresGpos = 2};struct OTScripts { unsigned int tag; int flags;};static const OTScripts ot_scripts [] = { // Common { FT_MAKE_TAG('l', 'a', 't', 'n'), 0 }, // Greek { FT_MAKE_TAG('g', 'r', 'e', 'k'), 0 }, // Cyrillic { FT_MAKE_TAG('c', 'y', 'r', 'l'), 0 }, // Armenian { FT_MAKE_TAG('a', 'r', 'm', 'n'), 0 }, // Hebrew { FT_MAKE_TAG('h', 'e', 'b', 'r'), 1 }, // Arabic { FT_MAKE_TAG('a', 'r', 'a', 'b'), 1 }, // Syriac { FT_MAKE_TAG('s', 'y', 'r', 'c'), 1 }, // Thaana { FT_MAKE_TAG('t', 'h', 'a', 'a'), 1 }, // Devanagari { FT_MAKE_TAG('d', 'e', 'v', 'a'), 1 }, // Bengali { FT_MAKE_TAG('b', 'e', 'n', 'g'), 1 }, // Gurmukhi { FT_MAKE_TAG('g', 'u', 'r', 'u'), 1 }, // Gujarati { FT_MAKE_TAG('g', 'u', 'j', 'r'), 1 }, // Oriya { FT_MAKE_TAG('o', 'r', 'y', 'a'), 1 }, // Tamil { FT_MAKE_TAG('t', 'a', 'm', 'l'), 1 }, // Telugu { FT_MAKE_TAG('t', 'e', 'l', 'u'), 1 }, // Kannada { FT_MAKE_TAG('k', 'n', 'd', 'a'), 1 }, // Malayalam { FT_MAKE_TAG('m', 'l', 'y', 'm'), 1 }, // Sinhala { FT_MAKE_TAG('s', 'i', 'n', 'h'), 1 }, // Thai { FT_MAKE_TAG('t', 'h', 'a', 'i'), 1 }, // Lao { FT_MAKE_TAG('l', 'a', 'o', ' '), 1 }, // Tibetan { FT_MAKE_TAG('t', 'i', 'b', 't'), 1 }, // Myanmar { FT_MAKE_TAG('m', 'y', 'm', 'r'), 1 }, // Georgian { FT_MAKE_TAG('g', 'e', 'o', 'r'), 0 }, // Hangul { FT_MAKE_TAG('h', 'a', 'n', 'g'), 1 }, // Ogham { FT_MAKE_TAG('o', 'g', 'a', 'm'), 0 }, // Runic { FT_MAKE_TAG('r', 'u', 'n', 'r'), 0 }, // Khmer { FT_MAKE_TAG('k', 'h', 'm', 'r'), 1 }};enum { NumOTScripts = sizeof(ot_scripts)/sizeof(OTScripts) };QOpenType::QOpenType(QFontEngine *fe, FT_Face _face) : fontEngine(fe), face(_face), gdef(0), gsub(0), gpos(0), current_script(0xffffffff) , allocated(0){ Q_ASSERT(NumOTScripts == (int)QUnicodeTables::ScriptCount); hb_buffer_new(face->memory, &hb_buffer); tmpAttributes = 0; tmpLogClusters = 0; kerning_feature_selected = false; glyphs_substituted = false; FT_Error error; if ((error = HB_Load_GDEF_Table(face, &gdef))) { DEBUG("error loading gdef table: %d", error); gdef = 0; } DEBUG() << "trying to load gsub table"; if ((error = HB_Load_GSUB_Table(face, &gsub, gdef))) { gsub = 0; if (error != FT_Err_Table_Missing) { DEBUG("error loading gsub table: %d", error); } else { DEBUG("face doesn't have a gsub table"); } } if ((error = HB_Load_GPOS_Table(face, &gpos, gdef))) { gpos = 0; DEBUG("error loading gpos table: %d", error); } for (uint i = 0; i < QUnicodeTables::ScriptCount; ++i) supported_scripts[i] = checkScript(i);}QOpenType::~QOpenType(){ if (gpos) HB_Done_GPOS_Table(gpos); if (gsub) HB_Done_GSUB_Table(gsub); if (gdef) HB_Done_GDEF_Table(gdef); if (hb_buffer) hb_buffer_free(hb_buffer); if (tmpAttributes) free(tmpAttributes); if (tmpLogClusters) free(tmpLogClusters);}bool QOpenType::checkScript(unsigned int script){ Q_ASSERT(script < QUnicodeTables::ScriptCount); uint tag = ot_scripts[script].tag; int requirements = ot_scripts[script].flags; if (requirements & RequiresGsub) { if (!gsub) return false; FT_UShort script_index; FT_Error error = HB_GSUB_Select_Script(gsub, tag, &script_index); if (error) { DEBUG("could not select script %d in GSub table: %d", (int)script, error); error = HB_GSUB_Select_Script(gsub, FT_MAKE_TAG('D', 'F', 'L', 'T'), &script_index); if (error) return false; } } if (requirements & RequiresGpos) { if (!gpos) return false; FT_UShort script_index; FT_Error error = HB_GPOS_Select_Script(gpos, script, &script_index); if (error) { DEBUG("could not select script in gpos table: %d", error); error = HB_GPOS_Select_Script(gpos, FT_MAKE_TAG('D', 'F', 'L', 'T'), &script_index); if (error) return false; } } return true;}void QOpenType::selectScript(QShaperItem *item, unsigned int script, const Features *features){ if (current_script == script && kerning_feature_selected == item->kerning_enabled) return; has_features = false; Q_ASSERT(script < QUnicodeTables::ScriptCount); // find script in our list of supported scripts. uint tag = ot_scripts[script].tag; if (gsub && features) {#ifdef OT_DEBUG { HB_FeatureList featurelist = 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(gsub); FT_UShort script_index; FT_Error error = HB_GSUB_Select_Script(gsub, tag, &script_index); if (!error) { DEBUG("script %s has script index %d", tag_to_string(script), script_index); while (features->tag) { FT_UShort feature_index; error = HB_GSUB_Select_Feature(gsub, features->tag, script_index, 0xffff, &feature_index); if (!error) { DEBUG(" adding feature %s", tag_to_string(features->tag)); HB_GSUB_Add_Feature(gsub, feature_index, features->property); has_features = true; } ++features; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -