📄 qtextengine.cpp
字号:
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; if (!ignoreBidi) { 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); } 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++)// fprintf(stderr, " %d", logClusters[k]);// fprintf(stderr, "\n"); // do the simple thing for now and give the first glyph in a cluster the full width, all other ones 0. int charFrom = from - pos; if (charFrom < 0) charFrom = 0; int glyphStart = logClusters[charFrom]; if (charFrom > 0 && logClusters[charFrom-1] == glyphStart) while (charFrom < ilen && logClusters[charFrom] == glyphStart) charFrom++; if (charFrom < ilen) { glyphStart = logClusters[charFrom]; int charEnd = from + len - 1 - pos; if (charEnd >= ilen) charEnd = ilen-1; int glyphEnd = logClusters[charEnd]; while (charEnd < ilen && logClusters[charEnd] == glyphEnd) charEnd++; glyphEnd = (charEnd == ilen) ? si->num_glyphs : logClusters[charEnd];// qDebug("char: start=%d end=%d / glyph: start = %d, end = %d", charFrom, charEnd, glyphStart, glyphEnd); for (int i = glyphStart; i < glyphEnd; i++) w += glyphs[i].advance.x; } } }// qDebug(" --> w= %d ", w); return w;}glyph_metrics_t QTextEngine::boundingBox(int from, int len) const{ itemize(); glyph_metrics_t gm; for (int i = 0; i < layoutData->items.size(); i++) { const QScriptItem *si = layoutData->items.constData() + i; int pos = si->position; int ilen = length(i); if (pos > from + len) break; if (pos + len > from) { if (!si->num_glyphs) shape(i); unsigned short *logClusters = this->logClusters(si); QGlyphLayout *glyphs = this->glyphs(si); // do the simple thing for now and give the first glyph in a cluster the full width, all other ones 0. int charFrom = from - pos; if (charFrom < 0) charFrom = 0; int glyphStart = logClusters[charFrom]; if (charFrom > 0 && logClusters[charFrom-1] == glyphStart) while (charFrom < ilen && logClusters[charFrom] == glyphStart) charFrom++; if (charFrom < ilen) { glyphStart = logClusters[charFrom]; int charEnd = from + len - 1 - pos; if (charEnd >= ilen) charEnd = ilen-1; int glyphEnd = logClusters[charEnd]; while (charEnd < ilen && logClusters[charEnd] == glyphEnd) charEnd++; glyphEnd = (charEnd == ilen) ? si->num_glyphs : logClusters[charEnd]; if (glyphStart <= glyphEnd ) { QFontEngine *fe = fontEngine(*si); glyph_metrics_t m = fe->boundingBox(glyphs+glyphStart, glyphEnd-glyphStart); gm.x = qMin(gm.x, m.x + gm.xoff); gm.y = qMin(gm.y, m.y + gm.yoff); gm.width = qMax(gm.width, m.width+gm.xoff); gm.height = qMax(gm.height, m.height+gm.yoff); gm.xoff += m.xoff; gm.yoff += m.yoff; } } } } return gm;}QFont QTextEngine::font(const QScriptItem &si) const{ if (!hasFormats()) return fnt; QTextCharFormat f = format(&si); QFont font = f.font(); if (block.docHandle()) { // Make sure we get the right dpi on printers QPaintDevice *pdev = block.docHandle()->layout()->paintDevice(); if (pdev) font = QFont(font, pdev); } else { font = font.resolve(fnt); } if (f.verticalAlignment() != QTextCharFormat::AlignNormal) font.setPointSize((font.pointSize() * 2) / 3); return font;}QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFixed *descent) const{ QFontEngine *engine; QFontEngine *scaledEngine = 0; int script = si.analysis.script;#if defined(Q_WS_WIN) if (hasUsp10) { const SCRIPT_PROPERTIES *script_prop = script_properties[si.analysis.script]; script = scriptForWinLanguage(script_prop->langid); }#endif if (!hasFormats()) { engine = fnt.d->engineForScript(script);#if defined(Q_WS_WIN) if (engine->type() == QFontEngine::Box) engine = fnt.d->engineForScript(QUnicodeTables::Common);#endif } else { QTextCharFormat f = format(&si); QFont font = f.font(); if (block.docHandle()) { // Make sure we get the right dpi on printers QPaintDevice *pdev = block.docHandle()->layout()->paintDevice(); if (pdev) font = QFont(font, pdev); } else { font = font.resolve(fnt); } engine = font.d->engineForScript(script);#if defined(Q_WS_WIN) if (engine->type() == QFontEngine::Box) engine = font.d->engineForScript(QUnicodeTables::Common);#endif if (f.verticalAlignment() != QTextCharFormat::AlignNormal) { font.setPointSize((font.pointSize() * 2) / 3); scaledEngine = font.d->engineForScript(script);#if defined(Q_WS_WIN) if (scaledEngine->type() == QFontEngine::Box) scaledEngine = font.d->engineForScript(QUnicodeTables::Common);#endif } } if (ascent) { *ascent = engine->ascent(); *descent = engine->descent(); } if (scaledEngine) return scaledEngine; return engine;}struct QJustificationPoint { int type; QFixed kashidaWidth; QGlyphLayout *glyph; QFontEngine *fontEngine;};Q_DECLARE_TYPEINFO(QJustificationPoint, Q_PRIMITIVE_TYPE);static void set(QJustificationPoint *point, int type, QGlyphLayout *glyph, QFontEngine *fe){ point->type = type; point->glyph = glyph; point->fontEngine = fe; if (type >= QGlyphLayout::Arabic_Normal) { QChar ch(0x640); // Kashida character QGlyphLayout glyphs[8]; int nglyphs = 7; fe->stringToCMap(&ch, 1, glyphs, &nglyphs, 0); if (glyphs[0].glyph && glyphs[0].advance.x != 0) { point->kashidaWidth = glyphs[0].advance.x; } else { point->type = QGlyphLayout::NoJustification; point->kashidaWidth = 0; } }}void QTextEngine::justify(const QScriptLine &line){// qDebug("justify: line.gridfitted = %d, line.justified=%d", line.gridfitted, line.justified); if (line.gridfitted && line.justified) return; if (!line.gridfitted) { // redo layout in device metrics, then adjust const_cast<QScriptLine &>(line).gridfitted = true; } if ((option.alignment() & Qt::AlignHorizontal_Mask) != Qt::AlignJustify) return; itemize(); if (line.from + (int)line.length == layoutData->string.length() || layoutData->string.at(line.from + line.length - 1) == QChar::LineSeparator) return; // justify line int maxJustify = 0; // don't include trailing white spaces when doing justification int line_length = line.length; const QCharAttributes *a = attributes()+line.from; while (line_length && a[line_length-1].whiteSpace) --line_length; // subtract one char more, as we can't justfy after the last character --line_length; if (!line_length) return; int firstItem = findItem(line.from); int nItems = findItem(line.from + line_length - 1) - firstItem + 1; QVarLengthArray<QJustificationPoint> justificationPoints; int nPoints = 0;// qDebug("justifying from %d len %d, firstItem=%d, nItems=%d", line.from, line_length, firstItem, nItems); QFixed minKashida = 0x100000; // we need to do all shaping before we go into the next loop, as we there // store pointers to the glyph data that could get reallocated by the shaping // process. for (int i = 0; i < nItems; ++i) { QScriptItem &si = layoutData->items[firstItem + i]; if (!si.num_glyphs) shape(firstItem + i); } for (int i = 0; i < nItems; ++i) { QScriptItem &si = layoutData->items[firstItem + i]; int kashida_type = QGlyphLayout::Arabic_Normal; int kashida_pos = -1; int start = qMax(line.from - si.position, 0); int end = qMin(line.from + line_length - (int)si.position, length(firstItem+i)); unsigned short *log_clusters = logClusters(&si); int gs = log_clusters[start]; int ge = (end == length(firstItem+i) ? si.num_glyphs : log_clusters[end]); QGlyphLayout *g = glyphs(&si); for (int i = gs; i < ge; ++i) { g[i].justificationType = QGlyphLayout::JustifyNone; g[i].nKashidas = 0; g[i].space_18d6 = 0; justificationPoints.resize(nPoints+3); int justification = g[i].attributes.justification; switch(justification) { case QGlyphLayout::NoJustification: break; case QGlyphLayout::Space : // fall through
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -