Beispiel #1
0
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));
}
Beispiel #2
0
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));
}
Beispiel #3
0
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;
      }
Beispiel #4
0
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);
      }
Beispiel #5
0
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;
}
Beispiel #7
0
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));
}
Beispiel #8
0
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);
}
Beispiel #9
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;
    }
}
Beispiel #11
0
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()));
}
Beispiel #12
0
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);
    }
}
Beispiel #15
0
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;				
		}
}
Beispiel #16
0
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));
                        }
                  }
            }
      }
Beispiel #17
0
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);
}
Beispiel #18
0
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;
}