📄 qopentype.cpp
字号:
/****************************************************************************
**
** Copyright (C) 1992-2006 Trolltech AS. 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://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** 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 "qopentype_p.h"
#include "qfontengine_p.h"
#include "qscriptengine_p.h"
#ifndef QT_NO_FREETYPE
// --------------------------------------------------------------------------------------------------------------------
// Open type support
// --------------------------------------------------------------------------------------------------------------------
//#define OT_DEBUG
#ifdef OT_DEBUG
static 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;
}
#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('D', 'F', 'L', 'T'), 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
// ### could not find any OT specs on this
{ 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 },
// Hangul
{ FT_MAKE_TAG('h', 'a', 'n', 'g'), 1 },
// Khmer
{ FT_MAKE_TAG('k', 'h', 'm', 'r'), 1 },
};
QOpenType::QOpenType(QFontEngine *fe, FT_Face _face)
: fontEngine(fe), face(_face), gdef(0), gsub(0), gpos(0), current_script(0)
{
otl_buffer_new(face->memory, &otl_buffer);
tmpAttributes = 0;
tmpLogClusters = 0;
FT_Error error;
if ((error = TT_Load_GDEF_Table(face, &gdef))) {
#ifdef OT_DEBUG
qDebug("error loading gdef table: %d", error);
#endif
gdef = 0;
}
if ((error = TT_Load_GSUB_Table(face, &gsub, gdef))) {
gsub = 0;
#ifdef OT_DEBUG
if (error != FT_Err_Table_Missing) {
qDebug("error loading gsub table: %d", error);
} else {
qDebug("face doesn't have a gsub table");
}
#endif
}
if ((error = TT_Load_GPOS_Table(face, &gpos, gdef))) {
gpos = 0;
#ifdef OT_DEBUG
qDebug("error loading gpos table: %d", error);
#endif
}
for (uint i = 0; i < QUnicodeTables::ScriptCount; ++i)
supported_scripts[i] = checkScript(i);
}
QOpenType::~QOpenType()
{
if (gpos)
TT_Done_GPOS_Table(gpos);
if (gsub)
TT_Done_GSUB_Table(gsub);
if (gdef)
TT_Done_GDEF_Table(gdef);
if (otl_buffer)
otl_buffer_free(otl_buffer);
if (tmpAttributes)
free(tmpAttributes);
if (tmpLogClusters)
free(tmpLogClusters);
}
bool QOpenType::checkScript(unsigned int script)
{
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 = TT_GSUB_Select_Script(gsub, tag, &script_index);
if (error) {
#ifdef OT_DEBUG
qDebug("could not select script %d in GSub table: %d", (int)script, error);
#endif
return false;
}
}
if (requirements & RequiresGpos) {
if (!gpos)
return false;
FT_UShort script_index;
FT_Error error = TT_GPOS_Select_Script(gpos, script, &script_index);
if (error) {
#ifdef OT_DEBUG
qDebug("could not select script in gpos table: %d", error);
#endif
return false;
}
}
return true;
}
void QOpenType::selectScript(unsigned int script, const Features *features)
{
if (current_script == script)
return;
assert(script < QUnicodeTables::ScriptCount);
// find script in our list of supported scripts.
uint tag = ot_scripts[script].tag;
if (gsub && features) {
#ifdef OT_DEBUG
{
TTO_FeatureList featurelist = gsub->FeatureList;
int numfeatures = featurelist.FeatureCount;
qDebug("gsub table has %d features", numfeatures);
for(int i = 0; i < numfeatures; i++) {
TTO_FeatureRecord *r = featurelist.FeatureRecord + i;
qDebug(" feature '%s'", tag_to_string(r->FeatureTag));
}
}
#endif
TT_GSUB_Clear_Features(gsub);
FT_UShort script_index;
FT_Error error = TT_GSUB_Select_Script(gsub, tag, &script_index);
if (!error) {
#ifdef OT_DEBUG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -