void tst_QRawFont::textLayout() { QFontDatabase fontDatabase; int id = fontDatabase.addApplicationFont(SRCDIR "testfont.ttf"); QVERIFY(id >= 0); QString familyName = QString::fromLatin1("QtBidiTestFont"); QFont font(familyName); font.setPixelSize(18.0); QCOMPARE(QFontInfo(font).family(), familyName); QTextLayout layout(QLatin1String("Foobar")); layout.setFont(font); layout.beginLayout(); layout.createLine(); layout.endLayout(); QList<QGlyphRun> glyphRuns = layout.glyphRuns(); QCOMPARE(glyphRuns.size(), 1); QGlyphRun glyphs = glyphRuns.at(0); QRawFont rawFont = glyphs.rawFont(); QVERIFY(rawFont.isValid()); QCOMPARE(rawFont.familyName(), familyName); QCOMPARE(rawFont.pixelSize(), 18.0); QVector<quint32> expectedGlyphIndices; expectedGlyphIndices << 44 << 83 << 83 << 70 << 69 << 86; QCOMPARE(glyphs.glyphIndexes(), expectedGlyphIndices); QVERIFY(fontDatabase.removeApplicationFont(id)); }
void tst_QRawFont::fromFont() { QFETCH(QString, fileName); QFETCH(QFont::HintingPreference, hintingPreference); QFETCH(QString, familyName); QFETCH(QFontDatabase::WritingSystem, writingSystem); QFontDatabase fontDatabase; int id = fontDatabase.addApplicationFont(fileName); QVERIFY(id >= 0); QFont font(familyName); font.setHintingPreference(hintingPreference); font.setPixelSize(26.0); QRawFont rawFont = QRawFont::fromFont(font, writingSystem); QVERIFY(rawFont.isValid()); #ifdef Q_WS_QPA QEXPECT_FAIL("", "QTBUG-20976 fails on qpa", Abort); #endif QCOMPARE(rawFont.familyName(), familyName); QCOMPARE(rawFont.pixelSize(), 26.0); QVERIFY(fontDatabase.removeApplicationFont(id)); }
QRawFont fontId2RawFont(int fontId) { static QRawFont* fonts[4]; // cached values Q_ASSERT(fontId >= 0 && fontId < 4); QRawFont* f = fonts[fontId]; if (f == 0) { qreal size = 20.0 * MScore::DPI / PPI; QString name; if (fontId == 0) name = ":/fonts/mscore-20.ttf"; else if (fontId == 2) { name = ":/fonts/FreeSerifMscore.ttf"; size = 8 * MScore::DPI / PPI; } else if (fontId == 3) name = ":/fonts/gonville-20.ttf"; else qFatal("illegal font id %d", fontId); // horizontal hinting is bad as note hooks do not attach to stems // properly at some magnifications f = fonts[fontId] = new QRawFont(name, size, QFont::PreferVerticalHinting); f->setPixelSize(size); } return *f; }
void Sym::genGlyphs(const QFont& font) { QRawFont rfont = QRawFont::fromFont(font); QVector<quint32> idx = rfont.glyphIndexesForString(toString()); QVector<QPointF> adv; adv << QPointF(); glyphs.setGlyphIndexes(idx); glyphs.setPositions(adv); glyphs.setRawFont(rfont); }
void tst_QRawFont::invalidRawFont() { QRawFont font; QVERIFY(!font.isValid()); QCOMPARE(font.pixelSize(), 0.0); QVERIFY(font.familyName().isEmpty()); QCOMPARE(font.style(), QFont::StyleNormal); QCOMPARE(font.weight(), -1); QCOMPARE(font.ascent(), 0.0); QCOMPARE(font.descent(), 0.0); QVERIFY(font.glyphIndexesForString(QLatin1String("Test")).isEmpty()); }
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { QRawFont rawFont = fontData->platformData().rawFont(); QString qstring = QString::fromRawData(reinterpret_cast<const QChar*>(buffer), static_cast<int>(bufferLength)); QVector<quint32> indexes = rawFont.glyphIndexesForString(qstring); bool haveGlyphs = false; for (unsigned i = 0; i < length; ++i) { Glyph glyph = (i < indexes.size()) ? indexes.at(i) : 0; if (!glyph) setGlyphDataForIndex(offset + i, 0, 0); else { haveGlyphs = true; setGlyphDataForIndex(offset + i, glyph, fontData); } } return haveGlyphs; }
void tst_QRawFont::fromFont() { QFETCH(QString, fileName); QFETCH(QFont::HintingPreference, hintingPreference); QFETCH(QString, familyName); QFETCH(QFontDatabase::WritingSystem, writingSystem); QFontDatabase fontDatabase; int id = fontDatabase.addApplicationFont(fileName); QVERIFY(id >= 0); QFont font(familyName); font.setHintingPreference(hintingPreference); font.setPixelSize(26.0); QRawFont rawFont = QRawFont::fromFont(font, writingSystem); QVERIFY(rawFont.isValid()); QCOMPARE(rawFont.familyName(), familyName); QCOMPARE(rawFont.pixelSize(), 26.0); QVERIFY(fontDatabase.removeApplicationFont(id)); }
void tst_QRawFont::rawFontSetPixelSize() { QFETCH(QFont::HintingPreference, hintingPreference); QTextLayout layout("Foobar"); QFont font = layout.font(); font.setHintingPreference(hintingPreference); font.setPixelSize(12); layout.setFont(font); layout.beginLayout(); layout.createLine(); layout.endLayout(); QGlyphRun glyphs = layout.glyphRuns().at(0); QRawFont rawFont = glyphs.rawFont(); QCOMPARE(rawFont.pixelSize(), 12.0); rawFont.setPixelSize(24); QCOMPARE(rawFont.pixelSize(), 24.0); }
QSGGlyphNode *QQuickTextNode::addGlyphs(const QPointF &position, const QGlyphRun &glyphs, const QColor &color, QQuickText::TextStyle style, const QColor &styleColor, QSGNode *parentNode) { QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext(); QRawFont font = glyphs.rawFont(); bool preferNativeGlyphNode = m_useNativeRenderer; if (!preferNativeGlyphNode) { QRawFontPrivate *fontPriv = QRawFontPrivate::get(font); if (fontPriv->fontEngine->hasUnreliableGlyphOutline()) preferNativeGlyphNode = true; else preferNativeGlyphNode = !QFontDatabase().isSmoothlyScalable(font.familyName(), font.styleName()); } QSGGlyphNode *node = sg->sceneGraphContext()->createGlyphNode(sg, preferNativeGlyphNode); node->setOwnerElement(m_ownerElement); node->setGlyphs(position + QPointF(0, glyphs.rawFont().ascent()), glyphs); node->setStyle(style); node->setStyleColor(styleColor); node->setColor(color); node->update(); /* We flag the geometry as static, but we never call markVertexDataDirty or markIndexDataDirty on them. This is because all text nodes are discarded when a change occurs. If we start appending/removing from existing geometry, then we also need to start marking the geometry as dirty. */ node->geometry()->setIndexDataPattern(QSGGeometry::StaticPattern); node->geometry()->setVertexDataPattern(QSGGeometry::StaticPattern); if (parentNode == 0) parentNode = this; parentNode->appendChildNode(node); return node; }
void QSGTextNode::addTextBlock(const QPointF &position, QTextDocument *textDocument, const QTextBlock &block, const QColor &overrideColor, QSGText::TextStyle style, const QColor &styleColor) { if (!block.isValid()) return; QPointF blockPosition = textDocument->documentLayout()->blockBoundingRect(block).topLeft(); QTextBlock::iterator it = block.begin(); while (!it.atEnd()) { QTextFragment fragment = it.fragment(); if (!fragment.text().isEmpty()) { QTextCharFormat charFormat = fragment.charFormat(); QColor color = overrideColor.isValid() ? overrideColor : charFormat.foreground().color(); QList<QGlyphRun> glyphsList = fragment.glyphRuns(); for (int i=0; i<glyphsList.size(); ++i) { QGlyphRun glyphs = glyphsList.at(i); QRawFont font = glyphs.rawFont(); QSGGlyphNode *glyphNode = addGlyphs(position + blockPosition + QPointF(0, font.ascent()), glyphs, color, style, styleColor); int decorations = (glyphs.overline() ? Overline : 0) | (glyphs.strikeOut() ? StrikeOut : 0) | (glyphs.underline() ? Underline : 0); if (decorations) { QPointF baseLine = glyphNode->baseLine(); qreal width = glyphNode->boundingRect().width(); addTextDecorations(Decoration(decorations), baseLine, color, width, font.lineThickness(), font.underlinePosition(), font.ascent()); } } } ++it; } }
void tst_QRawFont::multipleRawFontsFromData() { QFile file(QString::fromLatin1(SRCDIR "testfont.ttf")); QRawFont testFont; if (file.open(QIODevice::ReadOnly)) { testFont.loadFromData(file.readAll(), 11, QFont::PreferDefaultHinting); file.close(); } file.setFileName(QLatin1String(SRCDIR "testfont_bold_italic.ttf")); QRawFont testFontBoldItalic; if (file.open(QIODevice::ReadOnly)) testFontBoldItalic.loadFromData(file.readAll(), 11, QFont::PreferDefaultHinting); QVERIFY(testFont.familyName() != (testFontBoldItalic.familyName()) || testFont.styleName() != (testFontBoldItalic.styleName())); }
QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font) : m_manager(man) , m_pendingGlyphs(64) { Q_ASSERT(font.isValid()); QRawFontPrivate *fontD = QRawFontPrivate::get(font); m_glyphCount = fontD->fontEngine->glyphCount(); m_doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT; m_referenceFont = font; // we set the same pixel size as used by the distance field internally. // this allows us to call pathForGlyph once and reuse the result. m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution) * QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution)); Q_ASSERT(m_referenceFont.isValid()); m_coreProfile = (c->format().profile() == QSurfaceFormat::CoreProfile); }
QString QSGDistanceFieldGlyphCacheManager::fontKey(const QRawFont &font) { QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine; if (!fe->faceId().filename.isEmpty()) { QByteArray keyName = fe->faceId().filename; if (font.style() != QFont::StyleNormal) keyName += QByteArray(" I"); if (font.weight() != QFont::Normal) keyName += ' ' + QByteArray::number(font.weight()); keyName += QByteArray(" DF"); return QString::fromUtf8(keyName); } else { return QString::fromLatin1("%1_%2_%3_%4") .arg(font.familyName()) .arg(font.styleName()) .arg(font.weight()) .arg(font.style()); } }
void QSGTextNode::addTextLayout(const QPointF &position, QTextLayout *textLayout, const QColor &color, QSGText::TextStyle style, const QColor &styleColor) { QList<QGlyphRun> glyphsList(textLayout->glyphRuns()); QSGGlyphNode *prevNode = 0; QFont font = textLayout->font(); qreal underlinePosition, ascent, lineThickness; int decorations = NoDecoration; decorations |= (font.underline() ? Underline : 0); decorations |= (font.overline() ? Overline : 0); decorations |= (font.strikeOut() ? StrikeOut : 0); underlinePosition = ascent = lineThickness = 0; for (int i=0; i<glyphsList.size(); ++i) { QGlyphRun glyphs = glyphsList.at(i); QRawFont rawfont = glyphs.rawFont(); prevNode = addGlyphs(position + QPointF(0, rawfont.ascent()), glyphs, color, style, styleColor); if (decorations) { qreal rawAscent = rawfont.ascent(); if (decorations & Underline) { ascent = qMax(ascent, rawAscent); qreal pos = rawfont.underlinePosition(); if (pos > underlinePosition) { underlinePosition = pos; // take line thickness from the rawfont with maximum underline // position in this case lineThickness = rawfont.lineThickness(); } } else { // otherwise it's strike out or overline, we take line thickness // from the rawfont with maximum ascent if (rawAscent > ascent) { ascent = rawAscent; lineThickness = rawfont.lineThickness(); } } } } if (decorations) { addTextDecorations(Decoration(decorations), position + QPointF(0, ascent), color, textLayout->boundingRect().width(), lineThickness, underlinePosition, ascent); } }
void BoxBuilder::handleGlyphRun_(const QGlyphRun& glyphRun) { QPainter painter_(&pixmap_); painter_.setPen(glyphPen_); painter_.drawGlyphRun(glyphPosition_,glyphRun); QVector<quint32> indices = glyphRun.glyphIndexes(); QVector<QPointF> positions = glyphRun.positions(); if(indices.size() != positions.size()) log_ << "the number of indices and the number of positions are different: " << indices.size() << " and " << positions.size() << std::endl; QVector<QPointF>::Iterator posit = positions.begin(); qreal posx = glyphPosition_.x(), posy = glyphPosition_.y(); for(QVector<quint32>::iterator ixIt = indices.begin();ixIt != indices.end();++ixIt) { QRawFont rawFont = glyphRun.rawFont(); QPainterPath painterPath = rawFont.pathForGlyph(*ixIt); QRectF glyphBoundingRect = painterPath.boundingRect(); QVector<uint> blockTextIndices(blockText_.length()); int blockTextIndicesSize = blockTextIndices.size(); rawFont.glyphIndexesForChars(blockText_.begin(),blockText_.length(),blockTextIndices.begin(),&blockTextIndicesSize); std::map<uint,QChar> glyphIndicesToChars; std::wstring blockTextStdw = blockText_.toStdWString(); // build index for acessing chars in text, since glyphs order may not correspond chars order in text for(int i = 0; i < blockTextIndices.size(); ++i) glyphIndicesToChars[blockTextIndices[i] ] = blockText_.at(i); QChar currentChar = glyphIndicesToChars[*ixIt]; unsigned histValue = 0; if(histogram.find(currentChar) == histogram.end()) histogram[currentChar] = 0; else histValue = ++histogram[currentChar]; maxHistogramValue = std::max(maxHistogramValue,histValue); //std::wcout << "processing \" "<< QString(currentChar).toStdWString() << " \"... " << std::endl; // // //log_ << "glyphBoundingRect = (" << glyphBoundingRect.x() << "," << glyphBoundingRect.y() << // "," << glyphBoundingRect.width() << "," << glyphBoundingRect.height() << ")" << std::endl; QRect screenBoundingRect( posx + posit->x() + glyphBoundingRect.x(), posy + posit->y() + glyphBoundingRect.y(), glyphBoundingRect.width()+1, glyphBoundingRect.height()+1); /* log_ << "screen layout position = (" << posx << "," << posy << ")" << std::endl; log_ << "screen glyph position = (" << posit->x() << "," << posit->y() << ")" << std::endl; log_ << "screenBoundingRect = (" << screenBoundingRect.x() << "," << screenBoundingRect.y() << "," << screenBoundingRect.width() << "," << screenBoundingRect.height() << ")" << std::end*/; QRect imageBoundingRect(QPoint( screenBoundingRect.x(), pixmap_.height()-1 - screenBoundingRect.y() - screenBoundingRect.height()+1), QPoint( screenBoundingRect.x() + screenBoundingRect.width()-1, pixmap_.height() - screenBoundingRect.y()-1) ); //log_ << "imageBoundingRect = (" << imageBoundingRect.x() << "," << imageBoundingRect.y() << // "," << imageBoundingRect.width() << "," << imageBoundingRect.height() << ")" << std::endl; if(glyphBoundingRect.width()&&glyphBoundingRect.height()) boxes_.push_back(box(glyphIndicesToChars[*ixIt],imageBoundingRect)); //painter_.setPen(boxPen_); painter_.setPen(Qt::green); //painter_.drawRect(screenBoundingRect); ++posit; } }
void Rest::draw(QPainter* painter) const { if ( (staff() && staff()->isTabStaff() // in tab staff, do not draw rests is rests are off OR if dur. symbols are on && ( !((StaffTypeTablature*)staff()->staffType())->showRests() || ((StaffTypeTablature*)staff()->staffType())->genDurations()) ) || generated()) return; qreal _spatium = spatium(); painter->setPen(curColor()); if (parent() && measure() && measure()->multiMeasure()) { Measure* m = measure(); int n = m->multiMeasure(); qreal pw = _spatium * .7; QPen pen(painter->pen()); pen.setWidthF(pw); painter->setPen(pen); qreal w = _mmWidth; qreal y = 0.0; qreal x1 = 0.0; qreal x2 = w; pw *= .5; painter->drawLine(QLineF(x1 + pw, y, x2 - pw, y)); // draw vertical lines: pen.setWidthF(_spatium * .2); painter->setPen(pen); painter->drawLine(QLineF(x1, y-_spatium, x1, y+_spatium)); painter->drawLine(QLineF(x2, y-_spatium, x2, y+_spatium)); #ifdef USE_GLYPHS QRawFont rfont = fontId2RawFont(0); rfont.setPixelSize(20.0 * spatium()/(PPI * SPATIUM20)); QGlyphRun glyphs; QVector<quint32> idx = rfont.glyphIndexesForString(QString("%1").arg(n)); glyphs.setGlyphIndexes(idx); QVector<QPointF> adv = rfont.advancesForGlyphIndexes(idx); adv.insert(0, QPointF()); glyphs.setPositions(adv); glyphs.setRawFont(rfont); QRectF r = glyphs.boundingRect(); y = -_spatium * .5; painter->drawGlyphRun(QPointF((x2 - x1) * .5 + x1 - r.width() * .5, y), glyphs); #else QFont font = fontId2font(0); font.setPixelSize(lrint(20.0 * spatium()/(PPI * SPATIUM20))); painter->setFont(font); QFontMetricsF fm(font); // y = -_spatium * .5 - (staff()->height()*.5) - fm.ascent(); y = -_spatium * .5 - fm.ascent(); painter->drawText(QRectF(center(x1, x2), y, .0, .0), Qt::AlignHCenter|Qt::TextDontClip, QString("%1").arg(n)); #endif } else { qreal mag = magS(); symbols[score()->symIdx()][_sym].draw(painter, mag); int dots = durationType().dots(); if (dots) { qreal y = dotline * _spatium * .5; for (int i = 1; i <= dots; ++i) { qreal x = symbols[score()->symIdx()][_sym].width(mag) + point(score()->styleS(ST_dotNoteDistance)) * i; symbols[score()->symIdx()][dotSym].draw(painter, mag, QPointF(x, y)); } } } }
void tst_QRawFont::unsupportedWritingSystem() { QFETCH(QFont::HintingPreference, hintingPreference); QFontDatabase fontDatabase; int id = fontDatabase.addApplicationFont(QLatin1String(SRCDIR "testfont.ttf")); QFont font("QtBidiTestFont"); font.setHintingPreference(hintingPreference); font.setPixelSize(12.0); QRawFont rawFont = QRawFont::fromFont(font, QFontDatabase::Any); QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); QCOMPARE(rawFont.pixelSize(), 12.0); rawFont = QRawFont::fromFont(font, QFontDatabase::Hebrew); QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); QCOMPARE(rawFont.pixelSize(), 12.0); QString arabicText = QFontDatabase::writingSystemSample(QFontDatabase::Arabic); QTextLayout layout; layout.setFont(font); layout.setText(arabicText); layout.beginLayout(); layout.createLine(); layout.endLayout(); QList<QGlyphRun> glyphRuns = layout.glyphRuns(); QCOMPARE(glyphRuns.size(), 1); QGlyphRun glyphs = glyphRuns.at(0); QRawFont layoutFont = glyphs.rawFont(); QVERIFY(layoutFont.familyName() != QString::fromLatin1("QtBidiTestFont")); QCOMPARE(layoutFont.pixelSize(), 12.0); rawFont = QRawFont::fromFont(font, QFontDatabase::Arabic); QCOMPARE(rawFont.familyName(), layoutFont.familyName()); QCOMPARE(rawFont.pixelSize(), 12.0); fontDatabase.removeApplicationFont(id); }
void tst_QRawFont::detach() { QFETCH(QFont::HintingPreference, hintingPreference); { QString rawFontFamilyName; qreal rawFontPixelSize; qreal rawFontAscent; qreal rawFontDescent; int rawFontTableSize; QRawFont outerRawFont; { QRawFont rawFont(QString::fromLatin1(SRCDIR "testfont.ttf"), 11, hintingPreference); QVERIFY(rawFont.isValid()); rawFontFamilyName = rawFont.familyName(); rawFontPixelSize = rawFont.pixelSize(); rawFontAscent = rawFont.ascent(); rawFontDescent = rawFont.descent(); rawFontTableSize = rawFont.fontTable("glyf").size(); QVERIFY(rawFontTableSize > 0); { QRawFont otherRawFont(rawFont); otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), rawFontPixelSize, hintingPreference); QVERIFY(otherRawFont.isValid()); QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); QCOMPARE(otherRawFont.ascent(), rawFontAscent); QCOMPARE(otherRawFont.descent(), rawFontDescent); QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); } { QRawFont otherRawFont = rawFont; otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), rawFontPixelSize, hintingPreference); QVERIFY(otherRawFont.isValid()); QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); QCOMPARE(otherRawFont.ascent(), rawFontAscent); QCOMPARE(otherRawFont.descent(), rawFontDescent); QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); } outerRawFont = rawFont; rawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), rawFontPixelSize, hintingPreference); } QVERIFY(outerRawFont.isValid()); QCOMPARE(outerRawFont.pixelSize(), rawFontPixelSize); QCOMPARE(outerRawFont.familyName(), rawFontFamilyName); QCOMPARE(outerRawFont.hintingPreference(), hintingPreference); QCOMPARE(outerRawFont.ascent(), rawFontAscent); QCOMPARE(outerRawFont.descent(), rawFontDescent); QCOMPARE(outerRawFont.fontTable("glyf").size(), rawFontTableSize); } }
void QQuickTextNodeEngine::processCurrentLine() { // No glyphs, do nothing if (m_currentLineTree.isEmpty()) return; // 1. Go through current line and get correct decoration position for each node based on // neighbouring decorations. Add decoration to global list // 2. Create clip nodes for all selected text. Try to merge as many as possible within // the line. // 3. Add QRects to a list of selection rects. // 4. Add all nodes to a global processed list QVarLengthArray<int> sortedIndexes; // Indexes in tree sorted by x position BinaryTreeNode::inOrder(m_currentLineTree, &sortedIndexes); Q_ASSERT(sortedIndexes.size() == m_currentLineTree.size()); SelectionState currentSelectionState = Unselected; QRectF currentRect; QQuickTextNode::Decorations currentDecorations = QQuickTextNode::NoDecoration; qreal underlineOffset = 0.0; qreal underlineThickness = 0.0; qreal overlineOffset = 0.0; qreal overlineThickness = 0.0; qreal strikeOutOffset = 0.0; qreal strikeOutThickness = 0.0; QRectF decorationRect = currentRect; QColor lastColor; QColor lastBackgroundColor; QVarLengthArray<TextDecoration> pendingUnderlines; QVarLengthArray<TextDecoration> pendingOverlines; QVarLengthArray<TextDecoration> pendingStrikeOuts; if (!sortedIndexes.isEmpty()) { QQuickDefaultClipNode *currentClipNode = m_hasSelection ? new QQuickDefaultClipNode(QRectF()) : 0; bool currentClipNodeUsed = false; for (int i=0; i<=sortedIndexes.size(); ++i) { BinaryTreeNode *node = 0; if (i < sortedIndexes.size()) { int sortedIndex = sortedIndexes.at(i); Q_ASSERT(sortedIndex < m_currentLineTree.size()); node = m_currentLineTree.data() + sortedIndex; } if (i == 0) currentSelectionState = node->selectionState; // Update decorations if (currentDecorations != QQuickTextNode::NoDecoration) { decorationRect.setY(m_position.y() + m_currentLine.y()); decorationRect.setHeight(m_currentLine.height()); if (node != 0) decorationRect.setRight(node->boundingRect.left()); TextDecoration textDecoration(currentSelectionState, decorationRect, lastColor); if (currentDecorations & QQuickTextNode::Underline) pendingUnderlines.append(textDecoration); if (currentDecorations & QQuickTextNode::Overline) pendingOverlines.append(textDecoration); if (currentDecorations & QQuickTextNode::StrikeOut) pendingStrikeOuts.append(textDecoration); if (currentDecorations & QQuickTextNode::Background) m_backgrounds.append(qMakePair(decorationRect, lastBackgroundColor)); } // If we've reached an unselected node from a selected node, we add the // selection rect to the graph, and we add decoration every time the // selection state changes, because that means the text color changes if (node == 0 || node->selectionState != currentSelectionState) { currentRect.setY(m_position.y() + m_currentLine.y()); currentRect.setHeight(m_currentLine.height()); if (currentSelectionState == Selected) m_selectionRects.append(currentRect); if (currentClipNode != 0) { if (!currentClipNodeUsed) { delete currentClipNode; } else { currentClipNode->setIsRectangular(true); currentClipNode->setRect(currentRect); currentClipNode->update(); } } if (node != 0 && m_hasSelection) currentClipNode = new QQuickDefaultClipNode(QRectF()); else currentClipNode = 0; currentClipNodeUsed = false; if (node != 0) { currentSelectionState = node->selectionState; currentRect = node->boundingRect; // Make sure currentRect is valid, otherwise the unite won't work if (currentRect.isNull()) currentRect.setSize(QSizeF(1, 1)); } } else { if (currentRect.isNull()) currentRect = node->boundingRect; else currentRect = currentRect.united(node->boundingRect); } if (node != 0) { if (node->selectionState == Selected) { node->clipNode = currentClipNode; currentClipNodeUsed = true; } decorationRect = node->boundingRect; // If previous item(s) had underline and current does not, then we add the // pending lines to the lists and likewise for overlines and strikeouts if (!pendingUnderlines.isEmpty() && !(node->decorations & QQuickTextNode::Underline)) { addTextDecorations(pendingUnderlines, underlineOffset, underlineThickness); pendingUnderlines.clear(); underlineOffset = 0.0; underlineThickness = 0.0; } // ### Add pending when overlineOffset/thickness changes to minimize number of // nodes if (!pendingOverlines.isEmpty()) { addTextDecorations(pendingOverlines, overlineOffset, overlineThickness); pendingOverlines.clear(); overlineOffset = 0.0; overlineThickness = 0.0; } // ### Add pending when overlineOffset/thickness changes to minimize number of // nodes if (!pendingStrikeOuts.isEmpty()) { addTextDecorations(pendingStrikeOuts, strikeOutOffset, strikeOutThickness); pendingStrikeOuts.clear(); strikeOutOffset = 0.0; strikeOutThickness = 0.0; } // Merge current values with previous. Prefer greatest thickness QRawFont rawFont = node->glyphRun.rawFont(); if (node->decorations & QQuickTextNode::Underline) { if (rawFont.lineThickness() > underlineThickness) { underlineThickness = rawFont.lineThickness(); underlineOffset = rawFont.underlinePosition(); } } if (node->decorations & QQuickTextNode::Overline) { overlineOffset = -rawFont.ascent(); overlineThickness = rawFont.lineThickness(); } if (node->decorations & QQuickTextNode::StrikeOut) { strikeOutThickness = rawFont.lineThickness(); strikeOutOffset = rawFont.ascent() / -3.0; } currentDecorations = node->decorations; lastColor = node->color; lastBackgroundColor = node->backgroundColor; m_processedNodes.append(*node); } } if (!pendingUnderlines.isEmpty()) addTextDecorations(pendingUnderlines, underlineOffset, underlineThickness); if (!pendingOverlines.isEmpty()) addTextDecorations(pendingOverlines, overlineOffset, overlineThickness); if (!pendingStrikeOuts.isEmpty()) addTextDecorations(pendingStrikeOuts, strikeOutOffset, strikeOutThickness); } m_currentLineTree.clear(); m_currentLine = QTextLine(); m_hasSelection = false; }