📄 qtextlayout.cpp
字号:
bool sb_or_ws = false; do { int gp = logClusters[pos]; do { ++pos; ++tmpData.length; } while (pos < end && logClusters[pos] == gp); do { tmpData.textWidth += glyphs[gp].advance.x * !glyphs[gp].attributes.dontPrint; ++gp; } while (gp < current.num_glyphs && !glyphs[gp].attributes.clusterStart); Q_ASSERT((pos == end && gp == current.num_glyphs) || logClusters[pos] == gp); ++glyphCount; if (attributes[pos].whiteSpace || attributes[pos].softBreak) { sb_or_ws = true; break; } else if (breakany && attributes[pos].charStop) { break; } } while (pos < end); minw = qMax(tmpData.textWidth, minw); QFixed softHyphenWidth; if (pos && eng->layoutData->string.at(pos - 1) == 0x00ad) { // if we are splitting up a word because of // a soft hyphen then we ... // // a) have to take the width of the soft hyphen into // account to see if the first syllable(s) /and/ // the soft hyphen fit into the line // // b) if we are so short of available width that the // soft hyphen is the first breakable position, then // we don't want to show it. However we initially // have to take the width for it into accoun so that // the text document layout sees the overflow and // switch to break-anywhere mode, in which we // want the soft-hyphen to slip into the next line // and thus become invisible again. // if (line.length) softHyphenWidth = glyphs[logClusters[pos - 1]].advance.x; else if (breakany) tmpData.textWidth += glyphs[logClusters[pos - 1]].advance.x; } if ((sb_or_ws|breakany) && check_full_otherwise_extend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap, softHyphenWidth)) { if (!breakany) { line.textWidth += softHyphenWidth; } goto found; } if (sb_or_ws) breakany = false; } else { while (pos < end && attributes[pos].whiteSpace) { int gp = logClusters[pos]; do { ++pos; ++spaceData.length; } while (pos < end && logClusters[pos] == gp); do { spaceData.textWidth += glyphs[gp].advance.x * !glyphs[gp].attributes.dontPrint; ++gp; } while (gp < current.num_glyphs && !glyphs[gp].attributes.clusterStart); ++glyphCount; Q_ASSERT((pos == end && gp == current.num_glyphs) || logClusters[pos] == gp); } } if (pos == end) newItem = item + 1; } LB_DEBUG("reached end of line"); check_full_otherwise_extend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap);found: if (line.length == 0) { LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f", tmpData.length, tmpData.textWidth.toReal(), spaceData.length, spaceData.textWidth.toReal()); line += tmpData; } LB_DEBUG("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(), line.descent.toReal(), line.textWidth.toReal(), spaceData.width.toReal()); LB_DEBUG(" : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data()); if (eng->option.wrapMode() == QTextOption::ManualWrap || eng->option.wrapMode() == QTextOption::NoWrap) { eng->minWidth = qMax(eng->minWidth, line.textWidth); eng->maxWidth = qMax(eng->maxWidth, line.textWidth); } else { eng->minWidth = qMax(eng->minWidth, minw); eng->maxWidth += line.textWidth; } if (line.textWidth > 0 && item < eng->layoutData->items.size()) eng->maxWidth += spaceData.textWidth; if (eng->option.flags() & QTextOption::IncludeTrailingSpaces) line.textWidth += spaceData.textWidth; line.length += spaceData.length; line.justified = false; line.gridfitted = false;}/*! Moves the line to position \a pos.*/void QTextLine::setPosition(const QPointF &pos){ eng->lines[i].x = QFixed::fromReal(pos.x()); eng->lines[i].y = QFixed::fromReal(pos.y());}// ### DOC: I have no idea what this means/does.// You create a text layout with a string of text. Once you layouted// it, it contains a number of QTextLines. from() returns the position// inside the text string where this line starts. If you e.g. has a// text of "This is a string", layouted into two lines (the second// starting at the word 'a'), layout.lineAt(0).from() == 0 and// layout.lineAt(1).from() == 8./*! Returns the start of the line from the beginning of the string passed to the QTextLayout.*/int QTextLine::textStart() const{ return eng->lines[i].from;}/*! Returns the length of the text in the line. \sa naturalTextWidth()*/int QTextLine::textLength() const{ return eng->lines[i].length;}static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si, QTextItemInt &gf, QTextEngine *eng, int start, int glyph_start){ int ge = glyph_start + gf.num_glyphs; int gs = glyph_start; int end = start + gf.num_chars; unsigned short *logClusters = eng->logClusters(&si); QGlyphLayout *glyphs = eng->glyphs(&si); QFixed orig_width = gf.width; int *ul = eng->underlinePositions; if (ul) while (*ul != -1 && *ul < start) ++ul; bool rtl = si.analysis.bidiLevel % 2; if (rtl) x += si.width; do { int gtmp = ge; int stmp = end; if (ul && *ul != -1 && *ul < end) { stmp = *ul; gtmp = logClusters[*ul-si.position]; } gf.num_glyphs = gtmp - gs; gf.glyphs = glyphs + gs; gf.num_chars = stmp - start; gf.chars = eng->layoutData->string.unicode() + start; QFixed w = 0; while (gs < gtmp) { w += (glyphs[gs].advance.x + QFixed::fromFixed(glyphs[gs].space_18d6)) * !glyphs[gs].attributes.dontPrint; ++gs; } start = stmp; gf.width = w; if (rtl) x -= w; if (gf.num_chars) p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf); if (!rtl) x += w; if (ul && *ul != -1 && *ul < end) { // draw underline gtmp = (*ul == end-1) ? ge : logClusters[*ul+1-si.position]; ++stmp; gf.num_glyphs = gtmp - gs; gf.glyphs = glyphs + gs; gf.num_chars = stmp - start; gf.chars = eng->layoutData->string.unicode() + start; gf.logClusters = logClusters + start - si.position; w = 0; while (gs < gtmp) { w += (glyphs[gs].advance.x + QFixed::fromFixed(glyphs[gs].space_18d6)) * !glyphs[gs].attributes.dontPrint; ++gs; } ++start; gf.width = w; gf.flags |= QTextItem::Underline; if (rtl) x -= w; p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf); if (!rtl) x += w; gf.flags &= ~QTextItem::Underline; ++gf.chars; ++ul; } } while (gs < ge); gf.width = orig_width;}static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r){ QBrush c = chf.foreground(); if (c.style() == Qt::NoBrush) p->setPen(defaultPen); QBrush bg = chf.background(); if (bg.style() != Qt::NoBrush) p->fillRect(r, bg); if (c.style() != Qt::NoBrush) p->setPen(QPen(c, 0));}/*! \fn void QTextLine::draw(QPainter *painter, const QPointF &position, const QTextLayout::FormatRange *selection) const Draws a line on the given \a painter at the specified \a position. The \a selection is reserved for internal use.*/void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatRange *selection) const{ const QScriptLine &line = eng->lines[i]; if (!line.length) return; QPen pen = p->pen(); int lineEnd = line.from + line.length; int firstItem = eng->findItem(line.from); int lastItem = eng->findItem(lineEnd - 1); int nItems = lastItem-firstItem+1; QFixed x = QFixed::fromReal(pos.x()); QFixed y = QFixed::fromReal(pos.y()); QFixed pos_x = x; QFixed pos_y = y; x += line.x; y += line.y + line.ascent; x += alignLine(eng, line); QVarLengthArray<int> visualOrder(nItems); QVarLengthArray<uchar> levels(nItems); for (int i = 0; i < nItems; ++i) levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); QRectF outlineRect; for (int i = 0; i < nItems; ++i) { int item = visualOrder[i]+firstItem; QScriptItem &si = eng->layoutData->items[item]; int si_len = eng->length(item); if (!si.num_glyphs) eng->shape(item); if (si.isObject || si.isTab) { if (eng->hasFormats() && (!selection || (si.position < selection->start + selection->length && si.position + si_len > selection->start))) { p->save(); QTextCharFormat format = eng->format(&si); if (selection) format.merge(selection->format); QFixed width = si.width; if (si.isTab) { width = eng->nextTab(&si, x - pos_x) - (x - pos_x); } setPenAndDrawBackground(p, pen, format, QRectF(x.toReal(), (y - line.ascent).toReal(), width.toReal(), line.height().toReal())); if (si.isObject && eng->block.docHandle()) { QRectF itemRect(x.toReal(), (y-si.ascent).toReal(), width.toReal(), si.height().toReal()); eng->docLayout()->drawInlineObject(p, itemRect, QTextInlineObject(item, eng), si.position + eng->block.position(), format); if (selection) { QBrush bg = format.background(); if (bg.style() != Qt::NoBrush) { QColor c = bg.color(); c.setAlpha(128); p->fillRect(itemRect, c); } if (selection) outlineRect = outlineRect.unite(itemRect); } } else { // si.isTab QTextItemInt gf; QFont f = eng->font(si); if (f.d->underline) gf.flags |= QTextItem::Underline; if (f.d->overline) gf.flags |= QTextItem::Overline; if (f.d->strikeOut) gf.flags |= QTextItem::StrikeOut; if (gf.flags) { if (si.analysis.bidiLevel %2) gf.flags |= QTextItem::RightToLeft; gf.ascent = si.ascent; gf.descent = si.descent; gf.num_glyphs = 0; gf.chars = 0; gf.num_chars = 0; gf.width = width; gf.fontEngine = f.d->engineForScript(si.analysis.script); gf.f = &f; gf.underlineColor = format.underlineColor(); p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf); } } p->restore(); } if (si.isTab) x = eng->nextTab(&si, x - pos_x) + pos_x; else x += si.width; continue; } unsigned short *logClusters = eng->logClusters(&si); QGlyphLayout *glyphs = eng->glyphs(&si); int start = qMax(line.from, si.position); int gs = logClusters[start-si.position]; int end; int ge; if (lineEnd < si.position + eng->length(item)) { end = lineEnd; ge = logClusters[end-si.position]; } else { end = si.position + si_len; ge = si.num_glyphs; } // show soft-hyphen at line-break if (si.position + si_len >= lineEnd && eng->layoutData->string.at(lineEnd - 1) == 0x00ad) glyphs[ge - 1].attributes.dontPrint = false; QFixed itemBaseLine = y; QTextItemInt gf; if (si.analysis.bidiLevel %2) gf.flags |= QTextItem::RightToLeft; gf.ascent = si.ascent; gf.descent = si.descent; gf.num_glyphs = ge - gs; gf.glyphs = glyphs + gs; gf.chars = eng->layoutData->string.unicode() + start; gf.logClusters = logClusters + start - si.position; gf.num_chars = end - start; gf.width = 0; int g = gs; while (g < ge) { gf.width += (glyphs[g].advance.x + QFixed::fromFixed(glyphs[g].space_18d6)) * !glyphs[g].attributes.dontPrint; ++g; } if (selection) { int from = qMax(start, selection->start) - si.position; int to = qMin(end, selection->start + selection->length) - si.position; if (from >= to) { x += gf.width; continue; } int start_glyph = logClusters[from]; int end_glyph = (to == eng->length(item)) ? si.num_glyphs : logClusters[to]; QFixed soff; QFixed swidth; if (si.analysis.bidiLevel %2) { for (int g = ge - 1; g >= end_glyph; --g) soff += (glyphs[g].advance.x + QFixed::fromFixed(glyphs[g].space_18d6)) * !glyphs[g].attributes.dontPrint; for (int g = end_glyph - 1; g >= start_glyph; --g) swidth += (glyphs[g].advance.x + QFixed::fromFixed(glyphs[g].space_18d6)) * !glyphs[g].attributes.dontPrint; } else { for (int g = gs; g < start_glyph; ++g) soff += (glyphs[g].advance.x + QFixed::fromFixed(glyphs[g].space_18d6)) * !glyphs[g].attributes.dontPrint; for (int g = start_glyph; g < end_glyph; ++g) swidth += (glyphs[g].advance.x + QFixed::fromFixed(glyphs[g].space_18d6)) * !glyphs[g].attributes.dontPrint; } QRectF rect((x + soff).toReal(), (y - line.ascent).toReal(), swidth.toReal(), line.height().toReal()); if (selection) outlineRect = outlineRect.unite(rect); p->save(); p->setClipRect(rect, Qt::IntersectClip); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -