📄 qtextengine.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 "qtextformat.h"#include "qtextformat_p.h"#include "qtextengine_p.h"#include "qabstracttextdocumentlayout.h"#include "qtextlayout.h"#include "qvarlengtharray.h"#include "qscriptengine_p.h"#include "qfont.h"#include "qfont_p.h"#include "qfontengine_p.h"#include "qstring.h"#include <private/qunicodetables_p.h>#include "qtextdocument_p.h"#include <qapplication.h>#include <stdlib.h>// -----------------------------------------------------------------------------------------------------//// The BiDi algorithm//// -----------------------------------------------------------------------------------------------------#define BIDI_DEBUG 0//2#if (BIDI_DEBUG >= 1)#include <iostream>using namespace std;static const char *directions[] = { "DirL", "DirR", "DirEN", "DirES", "DirET", "DirAN", "DirCS", "DirB", "DirS", "DirWS", "DirON", "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN"};#endifstruct QBidiStatus { QBidiStatus() { eor = QChar::DirON; lastStrong = QChar::DirON; last = QChar:: DirON; dir = QChar::DirON; } QChar::Direction eor; QChar::Direction lastStrong; QChar::Direction last; QChar::Direction dir;};// The Unicode standard says this should be 61, setting it to 29 would save quite some space here.enum { MaxBidiLevel = 61 };struct QBidiControl { inline QBidiControl(bool rtl) : cCtx(0), base(rtl), override(false), level(rtl) {} inline void embed(bool rtl, bool o = false) { uchar plus2 = 0; if((level%2 != 0) == rtl ) { level++; plus2 = 2; } level++; if (level <= MaxBidiLevel) { override = o; unsigned char control = (plus2 + (override ? 1 : 0)) << (cCtx % 4)*2; unsigned char mask = ~(0x3 << (cCtx % 4)*2); ctx[cCtx>>2] &= mask; ctx[cCtx>>2] |= control; cCtx++; } } inline bool canPop() const { return cCtx != 0; } inline void pdf() { Q_ASSERT(cCtx); (void) --cCtx; unsigned char control = (ctx[cCtx>>2] >> ((cCtx % 4)*2)) & 0x3; override = control & 0x1; level--; if (control & 0x2) level--; } inline QChar::Direction basicDirection() const { return (base ? QChar::DirR : QChar:: DirL); } inline uchar baseLevel() const { return base; } inline QChar::Direction direction() const { return ((level%2) ? QChar::DirR : QChar:: DirL); } unsigned char ctx[(MaxBidiLevel+3)/4]; unsigned char cCtx : 6; unsigned char base : 1; unsigned char override : 1; unsigned char unused : 2; unsigned char level : 6;};static void qAppendItems(QTextEngine *engine, int &start, int &stop, QBidiControl &control, QChar::Direction dir){ QScriptItemArray &items = engine->layoutData->items; const QChar *text = engine->layoutData->string.unicode(); if (start > stop) { // #### the algorithm is currently not really safe against this. Still needs fixing.// qWarning("QTextEngine: BiDi internal error in qAppendItems()"); return; } int level = control.level; if(dir != QChar::DirON && !control.override) { // add level of run (cases I1 & I2) if(level % 2) { if(dir == QChar::DirL || dir == QChar::DirAN || dir == QChar::DirEN) level++; } else { if(dir == QChar::DirR) level++; else if(dir == QChar::DirAN || dir == QChar::DirEN) level += 2; } }#if (BIDI_DEBUG >= 1) qDebug("new run: dir=%s from %d, to %d level = %d\n", directions[dir], start, stop, level);#endif int script = -1; QScriptItem item; item.position = start; item.analysis.script = script; item.analysis.bidiLevel = level; item.analysis.override = control.override; item.analysis.reserved = 0; for (int i = start; i <= stop; i++) { unsigned short uc = text[i].unicode(); int s = QUnicodeTables::script(text[i]); if (uc == QChar::ObjectReplacementCharacter || uc == QChar::LineSeparator) { item.analysis.bidiLevel = level % 2 ? level-1 : level; item.analysis.script = QUnicodeTables::Common; item.isObject = true; s = -1; } else if (uc == 9) { item.analysis.script = QUnicodeTables::Common; item.isSpace = true; item.isTab = true; item.analysis.bidiLevel = control.baseLevel(); s = -1; } else if (s != script && (s != QUnicodeTables::Inherited || script == -1)) { item.analysis.script = s == QUnicodeTables::Inherited ? QUnicodeTables::Common : s; item.analysis.bidiLevel = level; } else { if (i - start < 32000) continue; start = i; } item.position = i; items.append(item); script = s; item.isSpace = item.isTab = item.isObject = false; } ++stop; start = stop;}typedef void (* fAppendItems)(QTextEngine *, int &start, int &stop, QBidiControl &control, QChar::Direction dir);static fAppendItems appendItems = qAppendItems;// creates the next QScript items.static bool bidiItemize(QTextEngine *engine, bool rightToLeft){#if BIDI_DEBUG >= 2 cout << "bidiItemize: rightToLeft=" << rightToLeft << endl;#endif QBidiControl control(rightToLeft); bool hasBidi = rightToLeft; int sor = 0; int eor = -1; int length = engine->layoutData->string.length(); if (!length) return hasBidi; const ushort *unicode = (const ushort *)engine->layoutData->string.unicode(); int current = 0; QChar::Direction dir = rightToLeft ? QChar::DirR : QChar::DirL; QBidiStatus status; QChar::Direction sdir = QChar::direction(*unicode); if (sdir != QChar::DirL && sdir != QChar::DirR && sdir != QChar::DirEN && sdir != QChar::DirAN) sdir = QChar::DirON; else dir = QChar::DirON; status.eor = sdir; status.lastStrong = rightToLeft ? QChar::DirR : QChar::DirL; status.last = status.lastStrong; status.dir = sdir; while (current <= length) { QChar::Direction dirCurrent; if (current == (int)length) dirCurrent = control.basicDirection(); else dirCurrent = QChar::direction(unicode[current]);#if (BIDI_DEBUG >= 2) cout << "pos=" << current << " dir=" << directions[dir] << " current=" << directions[dirCurrent] << " last=" << directions[status.last] << " eor=" << eor << "/" << directions[status.eor] << " sor=" << sor << " lastStrong=" << directions[status.lastStrong] << " level=" << (int)control.level << " override=" << (bool)control.override << endl;#endif switch(dirCurrent) { // embedding and overrides (X1-X9 in the BiDi specs) case QChar::DirRLE: case QChar::DirRLO: case QChar::DirLRE: case QChar::DirLRO: { bool rtl = (dirCurrent == QChar::DirRLE || dirCurrent == QChar::DirRLO); hasBidi |= rtl; bool override = (dirCurrent == QChar::DirLRO || dirCurrent == QChar::DirRLO); uchar level = control.level+1; if ((level%2 != 0) == rtl) ++level; if(level < MaxBidiLevel) { eor = current-1; appendItems(engine, sor, eor, control, dir); eor = current; control.embed(rtl, override); QChar::Direction edir = (rtl ? QChar::DirR : QChar::DirL); dir = status.eor = edir; status.lastStrong = edir; } break; } case QChar::DirPDF: { if (control.canPop()) { if (dir != control.direction()) { eor = current-1; appendItems(engine, sor, eor, control, dir); dir = control.direction(); } eor = current; appendItems(engine, sor, eor, control, dir); control.pdf(); dir = QChar::DirON; status.eor = QChar::DirON; status.last = control.direction(); if (control.override) dir = control.direction(); else dir = QChar::DirON; status.lastStrong = control.direction(); } break; } // strong types case QChar::DirL: if(dir == QChar::DirON) dir = QChar::DirL; switch(status.last) { case QChar::DirL: eor = current; status.eor = QChar::DirL; break; case QChar::DirR: case QChar::DirAL: case QChar::DirEN: case QChar::DirAN: if (eor >= 0) { appendItems(engine, sor, eor, control, dir); dir = eor < length ? QChar::direction(unicode[eor]) : control.basicDirection(); status.eor = dir; } else { eor = current; status.eor = dir; } break; case QChar::DirES: case QChar::DirET: case QChar::DirCS: case QChar::DirBN: case QChar::DirB: case QChar::DirS: case QChar::DirWS: case QChar::DirON: if(dir != QChar::DirL) { //last stuff takes embedding dir if(control.direction() == QChar::DirR) { if(status.eor != QChar::DirR) { // AN or EN appendItems(engine, sor, eor, control, dir); status.eor = QChar::DirON; dir = QChar::DirR; } eor = current - 1; appendItems(engine, sor, eor, control, dir); dir = eor < length ? QChar::direction(unicode[eor]) : control.basicDirection(); status.eor = dir; } else { if(status.eor != QChar::DirL) { appendItems(engine, sor, eor, control, dir); status.eor = QChar::DirON; dir = QChar::DirL; } else { eor = current; status.eor = QChar::DirL; break; } } } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -