📄 qtextlayout.cpp
字号:
QPointF position = pos + d->position; QFixed clipy = (INT_MIN/256); QFixed clipe = (INT_MAX/256); if (clip.isValid()) { clipy = QFixed::fromReal(clip.y() - position.y()); clipe = clipy + QFixed::fromReal(clip.height()); } for (int i = 0; i < d->lines.size(); i++) { QTextLine l(i, d); const QScriptLine &sl = d->lines[i]; if (sl.y > clipe || (sl.y + sl.height()) < clipy) continue; l.draw(p, position); for (int i = 0; i < selections.size(); ++i) l.draw(p, position, selections.constData()+i); } if (!d->cacheGlyphs) d->freeMemory();}/*! \fn void QTextLayout::drawCursor(QPainter *painter, const QPointF &position, int cursorPosition) const Draws a text cursor with the current pen at the given \a position using the \a painter specified. The corresponding position within the text is specified by \a cursorPosition.*/void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const{ if (!d->layoutData) d->itemize(); QPointF position = pos + d->position; QFixed pos_x = QFixed::fromReal(position.x()); QFixed pos_y = QFixed::fromReal(position.y()); for (int i = 0; i < d->lines.size(); i++) { QTextLine l(i, d); const QScriptLine &sl = d->lines[i]; if ((sl.from <= cursorPosition && sl.from + (int)sl.length > cursorPosition) || (sl.from + (int)sl.length == cursorPosition && cursorPosition == d->layoutData->string.length())) { const qreal x = position.x() + l.cursorToX(cursorPosition); int itm = d->findItem(cursorPosition - 1); QFixed ascent = sl.ascent; QFixed descent = sl.descent; bool rightToLeft = (d->option.textDirection() == Qt::RightToLeft); if (itm >= 0) { const QScriptItem &si = d->layoutData->items.at(itm); if (si.ascent > 0) ascent = si.ascent; if (si.descent > 0) descent = si.descent; rightToLeft = si.analysis.bidiLevel % 2; } qreal y = position.y() + (sl.y + sl.ascent - ascent).toReal(); p->drawLine(QLineF(x, y, x, y + (ascent + descent).toReal())); if (d->layoutData->hasBidi) { const int arrow_extent = 4; int sign = rightToLeft ? -1 : 1; p->drawLine(QLineF(x, y, x + (sign * arrow_extent/2), y + arrow_extent/2)); p->drawLine(QLineF(x, y+arrow_extent, x + (sign * arrow_extent/2), y + arrow_extent/2)); } return; } }}/*! \class QTextLine \brief The QTextLine class represents a line of text inside a QTextLayout. \ingroup text A text line is usually created by QTextLayout::createLine(). After being created, the line can be filled using the setLineWidth() or setNumColumns() functions. A line has a number of attributes including the rectangle it occupies, rect(), its coordinates, x() and y(), its textLength(), width() and naturalTextWidth(), and its ascent() and decent() relative to the text. The position of the cursor in terms of the line is available from cursorToX() and its inverse from xToCursor(). A line can be moved with setPosition().*//*! \enum QTextLine::Edge \value Leading \value Trailing*//*! \enum QTextLine::CursorPosition \value CursorBetweenCharacters \value CursorOnCharacter*//*! \fn QTextLine::QTextLine(int line, QTextEngine *e) \internal Constructs a new text line using the line at position \a line in the text engine \a e.*//*! \fn QTextLine::QTextLine() Creates an invalid line.*//*! \fn bool QTextLine::isValid() const Returns true if this text line is valid; otherwise returns false.*//*! \fn int QTextLine::lineNumber() const Returns the position of the line in the text engine.*//*! Returns the line's bounding rectangle. \sa x() y() textLength() width()*/QRectF QTextLine::rect() const{ const QScriptLine& sl = eng->lines[i]; return QRectF(sl.x.toReal(), sl.y.toReal(), sl.width.toReal(), sl.height().toReal());}/*! Returns the rectangle covered by the line.*/QRectF QTextLine::naturalTextRect() const{ const QScriptLine& sl = eng->lines[i]; QFixed x = sl.x + alignLine(eng, sl); QFixed width = sl.textWidth; if (sl.justified) width = sl.width; return QRectF(x.toReal(), sl.y.toReal(), width.toReal(), sl.height().toReal());}/*! Returns the line's x position. \sa rect() y() textLength() width()*/qreal QTextLine::x() const{ return eng->lines[i].x.toReal();}/*! Returns the line's y position. \sa x() rect() textLength() width()*/qreal QTextLine::y() const{ return eng->lines[i].y.toReal();}/*! Returns the line's width as specified by the layout() function. \sa naturalTextWidth() x() y() textLength() rect()*/qreal QTextLine::width() const{ return eng->lines[i].width.toReal();}/*! Returns the line's ascent. \sa descent() height()*/qreal QTextLine::ascent() const{ return eng->lines[i].ascent.toReal();}/*! Returns the line's descent. \sa ascent() height()*/qreal QTextLine::descent() const{ return eng->lines[i].descent.toReal();}/*! Returns the line's height. This is equal to ascent() + descent() + 1. \sa ascent() descent()*/qreal QTextLine::height() const{ return eng->lines[i].height().toReal();}/*! Returns the width of the line that is occupied by text. This is always \<= to width(), and is the minimum width that could be used by layout() without changing the line break position.*/qreal QTextLine::naturalTextWidth() const{ return eng->lines[i].textWidth.toReal();}/*! Lays out the line with the given \a width. The line is filled from its starting position with as many characters as will fit into the line.*/void QTextLine::setLineWidth(qreal width){ QScriptLine &line = eng->lines[i]; line.width = QFixed::fromReal(width); line.length = 0; line.textWidth = 0; layout_helper(INT_MAX);}/*! Lays out the line. The line is filled from its starting position with as many characters as are specified by \a numColumns.*/void QTextLine::setNumColumns(int numColumns){ QScriptLine &line = eng->lines[i]; line.width = INT_MAX/256; line.length = 0; line.textWidth = 0; layout_helper(numColumns);}enum State { Empty, Characters, WhiteSpace};enum Action { NoAction, AddWhiteSpace, AddTemp, Error};const Action state_table[3][3] = { { Error, Error, Error }, { NoAction, NoAction, AddTemp }, { NoAction, AddWhiteSpace, NoAction },};#if 0#define LB_DEBUG qDebug#else#define LB_DEBUG if (0) qDebug#endifstatic inline bool check_full_otherwise_extend(QScriptLine &line, QScriptLine &tmpData, QScriptLine &spaceData, int glyphCount, int maxGlyphs, QFixed &minw, bool manualWrap, QFixed softHyphenWidth = QFixed()){ LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal()); if (line.length && !manualWrap && (line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth > line.width || glyphCount > maxGlyphs)) return true; minw = qMax(minw, tmpData.textWidth); line += tmpData; line.textWidth += spaceData.textWidth; line.length += spaceData.length; tmpData.textWidth = 0; tmpData.length = 0; spaceData.textWidth = 0; spaceData.length = 0; return false;}void QTextLine::layout_helper(int maxGlyphs){ QScriptLine &line = eng->lines[i]; line.length = 0; line.textWidth = 0; if (!eng->layoutData->items.size()) { line.setDefaultHeight(eng); return; } Q_ASSERT(line.from < eng->layoutData->string.length()); bool breakany = (eng->option.wrapMode() == QTextOption::WrapAnywhere); bool manualWrap = (eng->option.wrapMode() == QTextOption::ManualWrap); // #### binary search! int item = -1; int newItem; for (newItem = eng->layoutData->items.size()-1; newItem > 0; --newItem) { if (eng->layoutData->items[newItem].position <= line.from) break; } QFixed minw = 0; int glyphCount = 0; LB_DEBUG("from: %d: item=%d, total %d width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal()); QScriptLine tmpData; QScriptLine spaceData; State state = Empty; Qt::Alignment alignment = eng->option.alignment(); const QCharAttributes *attributes = eng->attributes(); int pos = line.from; int end = 0; QGlyphLayout *glyphs = 0; unsigned short *logClusters = eng->layoutData->logClustersPtr; while (newItem < eng->layoutData->items.size()) { if (newItem != item) { item = newItem; const QScriptItem ¤t = eng->layoutData->items[item]; if (!current.num_glyphs) { eng->shape(item); attributes = eng->attributes(); logClusters = eng->layoutData->logClustersPtr; } pos = qMax(line.from, current.position); end = current.position + eng->length(item); glyphs = eng->glyphs(¤t); } const QScriptItem ¤t = eng->layoutData->items[item]; State newState = (attributes[pos].whiteSpace || current.isTab) ? WhiteSpace : Characters; Action action = state_table[newState][state]; switch (action) { case NoAction: break; case AddWhiteSpace: break; case Error: Q_ASSERT(false); break; case AddTemp: if (check_full_otherwise_extend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap)) goto found; } state = newState; if (state == Characters || current.isTab) { tmpData.ascent = qMax(tmpData.ascent, current.ascent); tmpData.descent = qMax(tmpData.descent, current.descent); } if (current.isTab && (alignment & Qt::AlignLeft)) { QFixed x = line.x + line.textWidth; QFixed nx = eng->nextTab(¤t, x); spaceData.textWidth += nx - x; spaceData.length++; newItem = item + 1; ++glyphCount; if (check_full_otherwise_extend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap)) goto found; } else if (current.isObject) { QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item])); if (eng->block.docHandle()) eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format); tmpData.length++; // the width of the linesep doesn't count into the textwidth if (eng->layoutData->string.at(current.position) == QChar::LineSeparator) { // if the line consists only of the line separator make sure // we have a sane height if (!line.length && tmpData.length == 1) line.setDefaultHeight(eng); line += tmpData; goto found; } tmpData.textWidth += current.width; newItem = item + 1; ++glyphCount; if (check_full_otherwise_extend(line, tmpData, spaceData, glyphCount, maxGlyphs, minw, manualWrap)) goto found; } else if (!attributes[pos].whiteSpace) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -