📄 qscriptengine.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 "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 const bool symbolFont = item->font->symbol; glyphs[0].attributes.mark = false; glyphs[0].attributes.clusterStart = true; glyphs[0].attributes.dontPrint = (!symbolFont && uc[0].unicode() == 0x00ad) || qIsControlChar(uc[0].unicode()); int pos = 0; int lastCat = QChar::category(uc[0].unicode()); 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 ((!symbolFont && 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 // 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 == 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);}enum { CcmpProperty = 0x1};#ifndef QT_NO_OPENTYPEstatic const QOpenType::Features basic_features[] = { { FT_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty }, { FT_MAKE_TAG('l', 'i', 'g', 'a'), CcmpProperty }, { FT_MAKE_TAG('c', 'l', 'i', 'g'), CcmpProperty }, {0, 0}};#endifstatic bool basic_shape(QShaperItem *item){#if !defined(QT_NO_OPENTYPE) && !defined(Q_WS_QWS) const int availableGlyphs = item->num_glyphs;#endif if (!item->font->stringToCMap(item->string->unicode()+item->from, item->length, item->glyphs, &item->num_glyphs, QFlag(item->flags))) return false; heuristicSetGlyphAttributes(item); // disable open type shaping for simple scripts on embedded, as it's computationally rahter expensive
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -