📄 qscriptengine.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 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://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 "qscriptengine_p.h"#include "qdebug.h"#include "qstring.h"#include "qrect.h"#include "qfont.h"#include <private/qunicodetables_p.h>#include "qtextengine_p.h"#include "qfontengine_p.h"#include <stdlib.h>#include <qvarlengtharray.h>#ifndef QT_NO_OPENTYPE#include "qopentype_p.h"#endif#undef None#undef Pre#undef Above#undef Below// --------------------------------------------------------------------------------------------------------------------------------------------//// Basic processing//// --------------------------------------------------------------------------------------------------------------------------------------------static inline void positionCluster(QShaperItem *item, int gfrom, int glast){ int nmarks = glast - gfrom; if (nmarks <= 0) { qWarning("Qt: No marks to position in positionCluster()"); return; } QGlyphLayout *glyphs = item->glyphs; QFontEngine *f = item->font; glyph_metrics_t baseInfo = f->boundingBox(glyphs[gfrom].glyph); if (item->script == QUnicodeTables::Hebrew) // we need to attach below the baseline, because of the hebrew iud. baseInfo.height = qMax(baseInfo.height, -baseInfo.y); QRectF baseRect(baseInfo.x.toReal(), baseInfo.y.toReal(), baseInfo.width.toReal(), baseInfo.height.toReal());// 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); qreal size = (f->ascent()/10).toReal(); qreal offsetBase = (size - 4) / 4 + qMin<qreal>(size, 4) + 1;// qDebug("offset = %f", offsetBase); bool rightToLeft = item->flags & QTextEngine::RightToLeft; int i; unsigned char lastCmb = 0; QRectF attachmentRect; for(i = 1; i <= nmarks; i++) { glyph_t mark = glyphs[gfrom+i].glyph; QPointF p; glyph_metrics_t markInfo = f->boundingBox(mark); QRectF markRect(markInfo.x.toReal(), markInfo.y.toReal(), markInfo.width.toReal(), markInfo.height.toReal());// qDebug("markInfo: %f/%f (%f/%f) off=%f/%f", markInfo.x, markInfo.y, markInfo.width, markInfo.height, markInfo.xoff, markInfo.yoff); qreal offset = offsetBase; unsigned char cmb = glyphs[gfrom+i].attributes.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 = QChar::Combining_Below; // above else if (cmb == 23 || cmb == 27 || cmb == 28 || cmb == 30 || cmb == 31 || (cmb >= 33 && cmb <= 36)) cmb = QChar::Combining_Above; //below-right else if (cmb == 9 || cmb == 103 || cmb == 118) cmb = QChar::Combining_BelowRight; // above-right else if (cmb == 24 || cmb == 107 || cmb == 122) cmb = QChar::Combining_AboveRight; else if (cmb == 25) cmb = QChar::Combining_AboveLeft; // fixed: // 19 21 } // combining marks of different class don't interact. Reset the rectangle. if (cmb != lastCmb) { //qDebug("resetting rect"); attachmentRect = baseRect; } switch(cmb) { case QChar::Combining_DoubleBelow: // ### wrong in rtl context! case QChar::Combining_BelowLeft: p += QPointF(0, offset); case QChar::Combining_BelowLeftAttached: p += attachmentRect.bottomLeft() - markRect.topLeft(); break; case QChar::Combining_Below: p += QPointF(0, offset); case QChar::Combining_BelowAttached: p += attachmentRect.bottomLeft() - markRect.topLeft(); p += QPointF((attachmentRect.width() - markRect.width())/2 , 0); break; case QChar::Combining_BelowRight: p += QPointF(0, offset); case QChar::Combining_BelowRightAttached: p += attachmentRect.bottomRight() - markRect.topRight(); break; case QChar::Combining_Left: p += QPointF(-offset, 0); case QChar::Combining_LeftAttached: break; case QChar::Combining_Right: p += QPointF(offset, 0); case QChar::Combining_RightAttached: break; case QChar::Combining_DoubleAbove: // ### wrong in RTL context! case QChar::Combining_AboveLeft: p += QPointF(0, -offset); case QChar::Combining_AboveLeftAttached: p += attachmentRect.topLeft() - markRect.bottomLeft(); break; case QChar::Combining_Above: p += QPointF(0, -offset); case QChar::Combining_AboveAttached: p += attachmentRect.topLeft() - markRect.bottomLeft(); p += QPointF((attachmentRect.width() - markRect.width())/2 , 0); break; case QChar::Combining_AboveRight: p += QPointF(0, -offset); case QChar::Combining_AboveRightAttached: p += attachmentRect.topRight() - markRect.bottomRight(); break; case QChar::Combining_IotaSubscript: default: break; }// qDebug("char=%x combiningClass = %d offset=%f/%f", mark, cmb, p.x(), p.y()); markRect.translate(p.x(), p.y()); attachmentRect |= markRect; lastCmb = cmb; if (rightToLeft) { glyphs[gfrom+i].offset.x = QFixed::fromReal(p.x()); glyphs[gfrom+i].offset.y = QFixed::fromReal(p.y()); } else { glyphs[gfrom+i].offset.x = QFixed::fromReal(p.x()) - baseInfo.xoff; glyphs[gfrom+i].offset.y = QFixed::fromReal(p.y()) - baseInfo.yoff; } glyphs[gfrom+i].advance = QFixedPoint(); }}void qt_heuristicPosition(QShaperItem *item){ QGlyphLayout *glyphs = item->glyphs; int cEnd = -1; int i = item->num_glyphs; while (i--) { if (cEnd == -1 && glyphs[i].attributes.mark) { cEnd = i; } else if (cEnd != -1 && !glyphs[i].attributes.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 heuristicallystatic void heuristicSetGlyphAttributes(QShaperItem *item, const QChar *uc, int length){ // ### zeroWidth and justification are missing here!!!!! Q_ASSERT(item->num_glyphs <= length);// qDebug("QScriptEngine::heuristicSetGlyphAttributes, num_glyphs=%d", item->num_glyphs); QGlyphLayout *glyphs = item->glyphs; unsigned short *logClusters = item->log_clusters; // the mac font engine does the setup already in stringToCMap#ifndef Q_WS_MAC int glyph_pos = 0; for (int i = 0; i < length; i++) { if (uc[i].unicode() >= 0xd800 && uc[i].unicode() < 0xdc00 && i < length-1 && uc[i+1].unicode() >= 0xdc00 && uc[i+1].unicode() < 0xe000) { logClusters[i] = glyph_pos; logClusters[++i] = glyph_pos; } else { logClusters[i] = glyph_pos; } ++glyph_pos; } Q_ASSERT(glyph_pos == item->num_glyphs);#endif // first char in a run is never (treated as) a mark#if !defined(Q_WS_MAC) int cStart = 0;#endif glyphs[0].attributes.mark = false; glyphs[0].attributes.clusterStart = true; glyphs[0].attributes.dontPrint = (uc[0].unicode() == 0x00ad || qIsControlChar(uc[0].unicode())); int pos = 0; int lastCat = ::category(uc[0]); for (int i = 1; i < length; ++i) { if (logClusters[i] == pos) // same glyph continue; ++pos; while (pos < logClusters[i]) { // the mac engine already has attributes setup properly#if !defined(Q_WS_MAC) glyphs[pos].attributes = glyphs[pos-1].attributes;#endif ++pos; } // hide soft-hyphens by default if (uc[i].unicode() == 0x00ad || qIsControlChar(uc[i].unicode())) glyphs[pos].attributes.dontPrint = true; const QUnicodeTables::Properties *prop = QUnicodeTables::properties(uc[i].unicode()); int cat = prop->category;#if !defined(Q_WS_MAC) if (cat != QChar::Mark_NonSpacing) { glyphs[pos].attributes.mark = false; glyphs[pos].attributes.clusterStart = true; glyphs[pos].attributes.combiningClass = 0; cStart = logClusters[i]; } else { int cmb = prop->combiningClass; if (cmb == 0) { // Fix 0 combining classes if ((uc[pos].unicode() & 0xff00) == 0x0e00) { // thai or lao unsigned char col = uc[pos].cell(); if (col == 0x31 || col == 0x34 || col == 0x35 || col == 0x36 || col == 0x37 || col == 0x47 || col == 0x4c || col == 0x4d || col == 0x4e) { cmb = QChar::Combining_AboveRight; } else if (col == 0xb1 || col == 0xb4 || col == 0xb5 || col == 0xb6 || col == 0xb7 || col == 0xbb || col == 0xcc || col == 0xcd) { cmb = QChar::Combining_Above; } else if (col == 0xbc) { cmb = QChar::Combining_Below; } } } glyphs[pos].attributes.mark = true; glyphs[pos].attributes.clusterStart = false; glyphs[pos].attributes.combiningClass = cmb; logClusters[i] = cStart; glyphs[pos].advance = QFixedPoint(); }#endif if (lastCat == QChar::Separator_Space) glyphs[pos-1].attributes.justification = QGlyphLayout::Space; else if (cat != QChar::Mark_NonSpacing) glyphs[pos-1].attributes.justification = QGlyphLayout::Character; else glyphs[pos-1].attributes.justification = QGlyphLayout::NoJustification; lastCat = cat; } pos = logClusters[length-1]; if (lastCat == QChar::Separator_Space) glyphs[pos].attributes.justification = QGlyphLayout::Space; else glyphs[pos].attributes.justification = QGlyphLayout::Character;}static void heuristicSetGlyphAttributes(QShaperItem *item){ heuristicSetGlyphAttributes(item, item->string->unicode() + item->from, item->length);}#if !defined(Q_WS_MAC)static bool basic_shape(QShaperItem *item){ if (!item->font->stringToCMap(item->string->unicode()+item->from, item->length, item->glyphs, &item->num_glyphs, QFlag(item->flags))) return false; heuristicSetGlyphAttributes(item); qt_heuristicPosition(item); return true;}#endif// --------------------------------------------------------------------------------------------------------------------------------------------//// Middle eastern languages//// --------------------------------------------------------------------------------------------------------------------------------------------// Uniscribe also defines dlig for Hebrew, but we leave this out for now, as it's mostly// ligatures one does not want in modern Hebrew (as lam-alef ligatures).enum { CcmpProperty = 0x1};#ifndef QT_NO_OPENTYPEstatic const QOpenType::Features hebrew_features[] = { { FT_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, {0, 0}};#endif#ifndef Q_WS_MAC/* Hebrew shaping. In the non opentype case we try to use the presentation forms specified for Hebrew. Especially for the ligatures with Dagesh this gives much better results than we could achieve manually.*/static bool hebrew_shape(QShaperItem *item){ Q_ASSERT(item->script == QUnicodeTables::Hebrew);#ifndef QT_NO_OPENTYPE QOpenType *openType = item->font->openType(); if (openType && openType->supportsScript(item->script)) { openType->selectScript(item->script, hebrew_features);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -