📄 qtextengine.cpp
字号:
// The following line break classes are not treated by the table:// AI, BK, CB, CR, LF, NL, SA, SG, SP, XXenum break_class { // the first 4 values have to agree with the enum in QCharAttributes ProhibitedBreak, // PB in table DirectBreak, // DB in table IndirectBreak, // IB in table CombiningIndirectBreak, // CI in table CombiningProhibitedBreak, // CP in table};#define DB DirectBreak#define IB IndirectBreak#define CI CombiningIndirectBreak#define CP CombiningProhibitedBreak#define PB ProhibitedBreakstatic const quint8 breakTable[QUnicodeTables::LineBreak_JT+1][QUnicodeTables::LineBreak_JT+1] ={/* OP CL QU GL NS EX SY IS PR PO NU AL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT *//* OP */ { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, CP, PB, PB, PB, PB, PB, PB },/* CL */ { DB, PB, IB, IB, PB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* QU */ { PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },/* GL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },/* NS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* EX */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* SY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* IS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* PR */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, IB },/* PO */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* NU */ { IB, PB, IB, IB, IB, IB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* AL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* ID */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* IN */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* HY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* BA */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* BB */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },/* B2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, PB, PB, CI, PB, DB, DB, DB, DB, DB },/* ZW */ { DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, PB, DB, DB, DB, DB, DB, DB, DB },/* CM */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },/* WJ */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },/* H2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },/* H3 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB },/* JL */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, DB },/* JV */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },/* JT */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB }};#undef DB#undef IB#undef CI#undef CP#undef PBstatic void calcLineBreaks(const QString &string, QCharAttributes *charAttributes){ int len = string.length(); if (!len) return; const QChar *uc = string.unicode(); // ##### can this fail if the first char is a surrogate? const QUnicodeTables::Properties *prop = QUnicodeTables::properties(uc->unicode()); int cls = prop->line_break_class; // handle case where input starts with an LF if (cls == QUnicodeTables::LineBreak_LF) cls = QUnicodeTables::LineBreak_BK; charAttributes[0].whiteSpace = (cls == QUnicodeTables::LineBreak_SP || cls == QUnicodeTables::LineBreak_BK); charAttributes[0].charStop = true; int lcls = cls; for (int i = 1; i < len; ++i) { charAttributes[i].whiteSpace = false; charAttributes[i].charStop = true; prop = QUnicodeTables::properties(uc[i].unicode()); int ncls = prop->line_break_class; // handle surrogates if (ncls == QUnicodeTables::LineBreak_SG) { if (uc[i].isHighSurrogate() && i < len - 1 && uc[i+1].isLowSurrogate()) { continue; } else if (uc[i].isLowSurrogate() && uc[i-1].isHighSurrogate()) { uint code = QChar::surrogateToUcs4(uc[i-1].unicode(), uc[i].unicode()); prop = QUnicodeTables::properties(code); ncls = prop->line_break_class; charAttributes[i].charStop = false; } else { ncls = QUnicodeTables::LineBreak_AL; } } // set white space and char stop flag if (ncls >= QUnicodeTables::LineBreak_SP) charAttributes[i].whiteSpace = true; if (ncls == QUnicodeTables::LineBreak_CM) charAttributes[i].charStop = false; QCharAttributes::LineBreakType lineBreakType = QCharAttributes::NoBreak; if (cls >= QUnicodeTables::LineBreak_LF) { lineBreakType = QCharAttributes::ForcedBreak; } else if(cls == QUnicodeTables::LineBreak_CR) { lineBreakType = (ncls == QUnicodeTables::LineBreak_LF) ? QCharAttributes::NoBreak : QCharAttributes::ForcedBreak; } if (ncls == QUnicodeTables::LineBreak_SP) goto next_no_cls_update; if (ncls >= QUnicodeTables::LineBreak_CR) goto next; // two complex chars (thai or lao), thai_attributes might override, but here we do a best guess if (cls == QUnicodeTables::LineBreak_SA && ncls == QUnicodeTables::LineBreak_SA) { lineBreakType = QCharAttributes::Break; goto next; } { int tcls = ncls; if (tcls >= QUnicodeTables::LineBreak_SA) tcls = QUnicodeTables::LineBreak_ID; if (cls >= QUnicodeTables::LineBreak_SA) cls = QUnicodeTables::LineBreak_ID; int brk = breakTable[cls][tcls]; switch (brk) { case DirectBreak: lineBreakType = QCharAttributes::Break; if (uc[i-1].unicode() == 0xad) // soft hyphen lineBreakType = QCharAttributes::SoftHyphen; break; case IndirectBreak: lineBreakType = (lcls == QUnicodeTables::LineBreak_SP) ? QCharAttributes::Break : QCharAttributes::NoBreak; break; case CombiningIndirectBreak: lineBreakType = QCharAttributes::NoBreak; if (lcls == QUnicodeTables::LineBreak_SP){ if (i > 1) charAttributes[i-2].lineBreakType = QCharAttributes::Break; } else { goto next_no_cls_update; } break; case CombiningProhibitedBreak: lineBreakType = QCharAttributes::NoBreak; if (lcls != QUnicodeTables::LineBreak_SP) goto next_no_cls_update; case ProhibitedBreak: default: break; } } next: cls = ncls; next_no_cls_update: lcls = ncls; charAttributes[i-1].lineBreakType = lineBreakType; } charAttributes[len-1].lineBreakType = QCharAttributes::ForcedBreak;}#if defined(Q_WS_X11) || defined (Q_WS_QWS)# include "qtextengine_unix.cpp"#elif defined(Q_WS_WIN)# include "qtextengine_win.cpp"#elif defined(Q_WS_MAC)# include "qtextengine_mac.cpp"#endifstatic void init(QTextEngine *e){#ifdef Q_WS_WIN if(!resolvedUsp10) resolveUsp10();#endif e->ignoreBidi = false; e->cacheGlyphs = false; e->forceJustification = false; e->layoutData = 0; e->minWidth = 0; e->maxWidth = 0; e->underlinePositions = 0; e->specialData = 0; e->stackEngine = false;}QTextEngine::QTextEngine(){ init(this);}QTextEngine::QTextEngine(const QString &str, const QFont &f) : fnt(f){ init(this); text = str;}QTextEngine::~QTextEngine(){ if (!stackEngine) delete layoutData; delete specialData;}const QCharAttributes *QTextEngine::attributes() const{ if (layoutData && layoutData->haveCharAttributes) return (QCharAttributes *) layoutData->memory; itemize(); ensureSpace(layoutData->string.length()); calcLineBreaks(layoutData->string, (QCharAttributes *) layoutData->memory); for (int i = 0; i < layoutData->items.size(); i++) { const QScriptItem &si = layoutData->items[i]; int script = si.analysis.script;#ifdef Q_WS_WIN if(hasUsp10) { script = QUnicodeTables::script(layoutData->string.at(si.position)); }#endif if (script == QUnicodeTables::Inherited) script = QUnicodeTables::Common; AttributeFunction attributes = qt_scriptEngines[script].charAttributes; if (!attributes) continue; int from = si.position; int len = length(i); attributes(script, layoutData->string, from, len, (QCharAttributes *) layoutData->memory); } layoutData->haveCharAttributes = true; return (QCharAttributes *) layoutData->memory;}void QTextEngine::shape(int item) const{ if (layoutData->items[item].isObject) { ensureSpace(1); if (block.docHandle()) { QTextFormat format = formats()->format(formatIndex(&layoutData->items[item])); docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)), layoutData->items[item].position + block.position(), format); } } else { shapeText(item); }}void QTextEngine::invalidate(){ freeMemory(); lines.clear(); minWidth = 0; maxWidth = 0; if (specialData) specialData->resolvedFormatIndices.clear();}void QTextEngine::validate() const{ if (layoutData) return; layoutData = new LayoutData(); if (block.docHandle()) layoutData->string = block.text(); else layoutData->string = text; if (specialData && specialData->preeditPosition != -1) layoutData->string.insert(specialData->preeditPosition, specialData->preeditText);}void QTextEngine::itemize() const{ validate(); if (layoutData->items.size()) return; if (layoutData->string.length() == 0) return; bool ignore = ignoreBidi; if (!ignore && option.textDirection() == Qt::LeftToRight) { ignore = true; const QChar *start = layoutData->string.unicode(); const QChar * const end = start + layoutData->string.length(); while (start < end) { if (start->unicode() >= 0x590) { ignore = false; break; } ++start; } } if (!ignore) { layoutData->hasBidi = bidiItemize(const_cast<QTextEngine *>(this), (option.textDirection() == Qt::RightToLeft)); } else { QBidiControl control(false); int start = 0; int stop = layoutData->string.length() - 1; appendItems(const_cast<QTextEngine *>(this), start, stop, control, QChar::DirL); layoutData->hasBidi = false; } addRequiredBoundaries(); resolveAdditionalFormats();}int QTextEngine::findItem(int strPos) const{ itemize(); // ##### use binary search int item; for (item = layoutData->items.size()-1; item > 0; --item) { if (layoutData->items[item].position <= strPos) break; } return item;}QFixed QTextEngine::width(int from, int len) const{ itemize(); QFixed w = 0;// qDebug("QTextEngine::width(from = %d, len = %d), numItems=%d, strleng=%d", from, len, items.size(), string.length()); for (int i = 0; i < layoutData->items.size(); i++) { const QScriptItem *si = layoutData->items.constData() + i; int pos = si->position; int ilen = length(i);// qDebug("item %d: from %d len %d", i, pos, ilen); if (pos >= from + len) break; if (pos + ilen > from) { if (!si->num_glyphs) shape(i); if (si->isObject) { w += si->width; continue; } else if (si->isTab) { w = nextTab(si, w); continue; } QGlyphLayout *glyphs = this->glyphs(si); unsigned short *logClusters = this->logClusters(si);// fprintf(stderr, " logclusters:");// for (int k = 0; k < ilen; k++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -