📄 qtextlayout.cpp
字号:
QFont f = eng->font(si); gf.fontEngine = f.d->engineForScript(si.analysis.script); gf.f = &f; QTextCharFormat chf; if (eng->hasFormats() || selection) { chf = eng->format(&si); if (selection) chf.merge(selection->format); setPenAndDrawBackground(p, pen, chf, QRectF(x.toReal(), (y - line.ascent).toReal(), gf.width.toReal(), line.height().toReal())); QTextCharFormat::VerticalAlignment valign = chf.verticalAlignment(); if (valign != QTextCharFormat::AlignNormal) { QFixed height = gf.fontEngine->ascent() + gf.fontEngine->descent(); if (valign == QTextCharFormat::AlignSubScript) itemBaseLine += height / 6; else if (valign == QTextCharFormat::AlignSuperScript) itemBaseLine -= height / 2; } } if (f.d->underline) gf.flags |= QTextItem::Underline; if (f.d->overline) gf.flags |= QTextItem::Overline; if (f.d->strikeOut) gf.flags |= QTextItem::StrikeOut; gf.underlineColor = chf.underlineColor(); Q_ASSERT(gf.fontEngine); if (eng->underlinePositions) { // can't have selections in this case drawMenuText(p, x, itemBaseLine, si, gf, eng, start, gs); } else { QPointF pos(x.toReal(), itemBaseLine.toReal()); if (chf.hasProperty(QTextFormat::TextOutline)) { QPainterPath path; path.setFillRule(Qt::WindingFill); if (gf.num_glyphs) gf.fontEngine->addOutlineToPath(pos.x(), pos.y(), gf.glyphs, gf.num_glyphs, &path, gf.flags); if (gf.flags) { const QFontEngine *fe = gf.fontEngine; const qreal lw = fe->lineThickness().toReal(); if (gf.flags & QTextItem::Underline) { qreal offs = fe->underlinePosition().toReal(); path.addRect(pos.x(), pos.y() + offs, gf.width.toReal(), lw); } if (gf.flags & QTextItem::Overline) { qreal offs = fe->ascent().toReal() + 1; path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw); } if (gf.flags & QTextItem::StrikeOut) { qreal offs = fe->ascent().toReal() / 3; path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw); } } p->save(); p->setRenderHint(QPainter::Antialiasing); //Currently QPen with a Qt::NoPen style still returns a default //QBrush which != Qt::NoBrush so we need this specialcase to reset it if (p->pen().style() == Qt::NoPen) p->setBrush(Qt::NoBrush); else p->setBrush(p->pen().brush()); p->setPen(chf.textOutline()); p->drawPath(path); p->restore(); } else { p->drawTextItem(pos, gf); } } if (selection) p->restore(); x += gf.width; } if (selection && outlineRect.isValid()) { QVariant outline = selection->format.property(QTextFormat::OutlinePen); if (outline.type() == QVariant::Pen) { p->setPen(qVariantValue<QPen>(outline)); p->drawRect(outlineRect); } } if (eng->hasFormats()) p->setPen(pen);}/*! \fn int QTextLine::cursorToX(int cursorPos, Edge edge) const \overload*//*! Converts the cursor position \a cursorPos to the corresponding x position inside the line, taking account of the \a edge. If \a cursorPos is not a valid cursor position, the nearest valid cursor position will be used instead, and cpos will be modified to point to this valid cursor position. \sa xToCursor()*/qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const{ if (!eng->layoutData) eng->itemize(); const QScriptLine &line = eng->lines[i]; QFixed x = line.x; x += alignLine(eng, line); if (!i && !eng->layoutData->items.size()) { *cursorPos = 0; return x.toReal(); } int pos = *cursorPos; int itm = eng->findItem(pos); if (pos == line.from + (int)line.length) { // end of line ensure we have the last item on the line itm = eng->findItem(pos-1); } const QScriptItem *si = &eng->layoutData->items[itm]; if (!si->num_glyphs) eng->shape(itm); pos -= si->position; QGlyphLayout *glyphs = eng->glyphs(si); unsigned short *logClusters = eng->logClusters(si); int l = eng->length(itm); if (pos > l) pos = l; if (pos < 0) pos = 0; int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos]; if (edge == Trailing) { // trailing edge is leading edge of next cluster while (glyph_pos < si->num_glyphs && !glyphs[glyph_pos].attributes.clusterStart) glyph_pos++; } bool reverse = eng->layoutData->items[itm].analysis.bidiLevel % 2; int lineEnd = line.from + line.length; // add the items left of the cursor int firstItem = eng->findItem(line.from); int lastItem = eng->findItem(lineEnd - 1); int nItems = lastItem-firstItem+1; 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()); for (int i = 0; i < nItems; ++i) { int item = visualOrder[i]+firstItem; if (item == itm) break; QScriptItem &si = eng->layoutData->items[item]; if (!si.num_glyphs) eng->shape(item); if (si.isTab) { x = eng->nextTab(&si, x); continue; } else if (si.isObject) { x += si.width; continue; } int start = qMax(line.from, si.position); int end = qMin(lineEnd, si.position + eng->length(item)); logClusters = eng->logClusters(&si); int gs = logClusters[start-si.position]; int ge = (end == si.position + eng->length(item)) ? si.num_glyphs-1 : logClusters[end-si.position-1]; QGlyphLayout *glyphs = eng->glyphs(&si); while (gs <= ge) { x += (glyphs[gs].advance.x + QFixed::fromFixed(glyphs[gs].space_18d6)) * !glyphs[gs].attributes.dontPrint; ++gs; } } logClusters = eng->logClusters(si); glyphs = eng->glyphs(si); if (si->isTab) { if(pos == l) x = eng->nextTab(si, x); } else if (si->isObject) { if(pos == l) x += si->width; } else { if (reverse) { int end = qMin(lineEnd, si->position + l) - si->position; int glyph_end = end == l ? si->num_glyphs : logClusters[end]; for (int i = glyph_end - 1; i >= glyph_pos; i--) x += (glyphs[i].advance.x + QFixed::fromFixed(glyphs[i].space_18d6)) * !glyphs[i].attributes.dontPrint; } else { int start = qMax(line.from - si->position, 0); int glyph_start = logClusters[start]; for (int i = glyph_start; i < glyph_pos; i++) x += (glyphs[i].advance.x + QFixed::fromFixed(glyphs[i].space_18d6)) *!glyphs[i].attributes.dontPrint; } } *cursorPos = pos + si->position; return x.toReal();}/*! \fn int QTextLine::xToCursor(qreal x, CursorPosition cpos) const Converts the x-coordinate \a x, to the nearest matching cursor position, depending on the cursor position type, \a cpos. \sa cursorToX()*/int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const{ QFixed x = QFixed::fromReal(_x); const QScriptLine &line = eng->lines[i]; if (!eng->layoutData) eng->itemize(); int line_length = line.length; if (line_length > 0 && eng->layoutData->string.at(line.from + line_length - 1) == QChar::LineSeparator) --line_length; if (!line_length) return line.from; int firstItem = eng->findItem(line.from); int lastItem = eng->findItem(line.from + line_length - 1); int nItems = lastItem-firstItem+1; x -= line.x; x -= alignLine(eng, line);// qDebug("xToCursor: x=%f, cpos=%d", x, cpos); QVarLengthArray<int> visualOrder(nItems); QVarLengthArray<unsigned char> 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()); if (x <= 0) { // left of first item int item = visualOrder[0]+firstItem; QScriptItem &si = eng->layoutData->items[item]; if (!si.num_glyphs) eng->shape(item); int pos = si.position; if (si.analysis.bidiLevel % 2) pos += eng->length(item); pos = qMax(line.from, pos); pos = qMin(line.from + line_length, pos); return pos; } else if (x < line.textWidth || (line.justified && x < line.width)) { // has to be in one of the runs QFixed pos; for (int i = 0; i < nItems; ++i) { int item = visualOrder[i]+firstItem; QScriptItem &si = eng->layoutData->items[item]; if (!si.num_glyphs) eng->shape(item); int item_length = eng->length(item);// qDebug(" item %d, visual %d x_remain=%f", i, item, x); int start = qMax(line.from - si.position, 0); int end = qMin(line.from + line_length - si.position, item_length); unsigned short *logClusters = eng->logClusters(&si); int gs = logClusters[start]; int ge = (end == item_length ? si.num_glyphs : logClusters[end]) - 1; QGlyphLayout *glyphs = eng->glyphs(&si); QFixed item_width = 0; if (si.isTab) { item_width = eng->nextTab(&si, pos) - pos; } else if (si.isObject) { item_width = si.width; } else { int g = gs; while (g <= ge) { item_width += (glyphs[g].advance.x + QFixed::fromFixed(glyphs[g].space_18d6)) * !glyphs[g].attributes.dontPrint; ++g; } }// qDebug(" start=%d, end=%d, gs=%d, ge=%d item_width=%f", start, end, gs, ge, item_width); if (pos + item_width < x) { pos += item_width; continue; }// qDebug(" inside run"); if (si.isTab || si.isObject) { if (cpos == QTextLine::CursorOnCharacter) return si.position; bool left_half = (x - pos) < item_width/2; if (bool(si.analysis.bidiLevel % 2) != left_half) return si.position; return si.position + 1; } int glyph_pos = -1; // has to be inside run if (cpos == QTextLine::CursorOnCharacter) { if (si.analysis.bidiLevel % 2) { pos += item_width; int last_glyph = gs; while (gs <= ge) { if (glyphs[gs].attributes.clusterStart && pos < x) { glyph_pos = last_glyph; break; } pos -= (glyphs[gs].advance.x + QFixed::fromFixed(glyphs[gs].space_18d6)) * !glyphs[gs].attributes.dontPrint; ++gs; } } else { glyph_pos = gs; while (gs <= ge) { if (glyphs[gs].attributes.clusterStart) { if (pos > x) break; glyph_pos = gs; } pos += (glyphs[gs].advance.x + QFixed::fromFixed(glyphs[gs].space_18d6)) * !glyphs[gs].attributes.dontPrint; ++gs; } } } else { QFixed dist = INT_MAX/256; if (si.analysis.bidiLevel % 2) { pos += item_width; while (gs <= ge) { if (glyphs[gs].attributes.clusterStart && qAbs(x-pos) < dist) { glyph_pos = gs; dist = qAbs(x-pos); } pos -= (glyphs[gs].advance.x + QFixed::fromFixed(glyphs[gs].space_18d6)) * !glyphs[gs].attributes.dontPrint; ++gs; } } else { while (gs <= ge) { if (glyphs[gs].attributes.clusterStart && qAbs(x-pos) < dist) { glyph_pos = gs; dist = qAbs(x-pos); } pos += (glyphs[gs].advance.x + QFixed::fromFixed(glyphs[gs].space_18d6)) * !glyphs[gs].attributes.dontPrint; ++gs; } } if (qAbs(x-pos) < dist) return si.position + end; } Q_ASSERT(glyph_pos != -1); int j; for (j = 0; j < eng->length(item); ++j) if (logClusters[j] == glyph_pos) break;// qDebug("at pos %d (in run: %d)", si.position + j, j); return si.position + j; } } // right of last item int item = visualOrder[nItems-1]+firstItem; QScriptItem &si = eng->layoutData->items[item]; if (!si.num_glyphs) eng->shape(item); int pos = si.position; if (!(si.analysis.bidiLevel % 2)) pos += eng->length(item); pos = qMax(line.from, pos); int maxPos = line.from + line_length; // except for the last line we assume that the // character between lines is a space and we want // to position the cursor to the left of that // character. // ###### breaks with japanese for example, fix > 4.1 if (this->i < eng->lines.count() - 1) --maxPos; pos = qMin(pos, maxPos); return pos;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -