void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState,
                                             QQuickTextNode::Decorations decorations, const QColor &textColor,
                                             const QColor &backgroundColor, const QPointF &position)
{
    QRectF searchRect = glyphRun.boundingRect();
    searchRect.translate(position);

    if (qFuzzyIsNull(searchRect.width()) || qFuzzyIsNull(searchRect.height()))
        return;

    decorations |= (glyphRun.underline() ? QQuickTextNode::Underline : QQuickTextNode::NoDecoration);
    decorations |= (glyphRun.overline()  ? QQuickTextNode::Overline  : QQuickTextNode::NoDecoration);
    decorations |= (glyphRun.strikeOut() ? QQuickTextNode::StrikeOut : QQuickTextNode::NoDecoration);
    decorations |= (backgroundColor.isValid() ? QQuickTextNode::Background : QQuickTextNode::NoDecoration);

    qreal ascent = glyphRun.rawFont().ascent();
    insert(binaryTree, BinaryTreeNode(glyphRun,
                                      selectionState,
                                      searchRect,
                                      decorations,
                                      textColor,
                                      backgroundColor,
                                      position,
                                      ascent));
}
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 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 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::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);
}
void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
{
    if (m_material != 0)
        delete m_material;

    QRawFont font = glyphs.rawFont();
    m_material = new QSGTextMaskMaterial(font);
    m_material->setColor(m_color);

    QRectF boundingRect;
    m_material->populate(position, glyphs.glyphIndexes(), glyphs.positions(), geometry(),
                         &boundingRect, &m_baseLine);

    setMaterial(m_material);
    setBoundingRect(boundingRect);

    markDirty(DirtyGeometry);

#ifdef QML_RUNTIME_TESTING
    description = QLatin1String("glyphs");
#endif
}
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  QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
                                            QQuickText::TextStyle style,
                                            const QColor &styleColor)
{
    if (m_currentLine.isValid())
        processCurrentLine();


    for (int i=0; i<m_backgrounds.size(); ++i) {
        const QRectF &rect = m_backgrounds.at(i).first;
        const QColor &color = m_backgrounds.at(i).second;

        parentNode->appendChildNode(new QSGSimpleRectNode(rect, color));
    }

    // First, prepend all selection rectangles to the tree
    for (int i=0; i<m_selectionRects.size(); ++i) {
        const QRectF &rect = m_selectionRects.at(i);

        parentNode->appendChildNode(new QSGSimpleRectNode(rect, m_selectionColor));
    }

    // Finally, add decorations for each node to the tree.
    for (int i=0; i<m_lines.size(); ++i) {
        const TextDecoration &textDecoration = m_lines.at(i);

        QColor color = textDecoration.selectionState == Selected
                ? m_selectedTextColor
                : textDecoration.color;

        parentNode->appendChildNode(new QSGSimpleRectNode(textDecoration.rect, color));
    }

    // Then, go through all the nodes for all lines and combine all QGlyphRuns with a common
    // font, selection state and clip node.
    typedef QPair<QFontEngine *, QPair<QQuickDefaultClipNode *, QPair<QRgb, int> > > KeyType;
    QHash<KeyType, BinaryTreeNode *> map;
    QList<BinaryTreeNode *> nodes;
    for (int i = 0; i < m_processedNodes.size(); ++i) {
        BinaryTreeNode *node = m_processedNodes.data() + i;

        if (node->image.isNull()) {
            QGlyphRun glyphRun = node->glyphRun;
            QRawFont rawFont = glyphRun.rawFont();
            QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont);

            QFontEngine *fontEngine = rawFontD->fontEngine;

            KeyType key(qMakePair(fontEngine,
                                  qMakePair(node->clipNode,
                                            qMakePair(node->color.rgba(), int(node->selectionState)))));

            BinaryTreeNode *otherNode = map.value(key, 0);
            if (otherNode != 0) {
                QGlyphRun &otherGlyphRun = otherNode->glyphRun;

                QVector<quint32> otherGlyphIndexes = otherGlyphRun.glyphIndexes();
                QVector<QPointF> otherGlyphPositions = otherGlyphRun.positions();

                otherGlyphIndexes += glyphRun.glyphIndexes();

                QVector<QPointF> glyphPositions = glyphRun.positions();
                otherGlyphPositions.reserve(otherGlyphPositions.size() + glyphPositions.size());
                for (int j = 0; j < glyphPositions.size(); ++j) {
                    otherGlyphPositions += glyphPositions.at(j) + (node->position - otherNode->position);
                }

                otherGlyphRun.setGlyphIndexes(otherGlyphIndexes);
                otherGlyphRun.setPositions(otherGlyphPositions);

            } else {
                map.insert(key, node);
                nodes.append(node);
            }
        } else {
            parentNode->addImage(node->boundingRect, node->image);
            if (node->selectionState == Selected) {
                QColor color = m_selectionColor;
                color.setAlpha(128);
                parentNode->appendChildNode(new QSGSimpleRectNode(node->boundingRect, color));
            }
        }
    }

    foreach (const BinaryTreeNode *node, nodes) {

        QQuickDefaultClipNode *clipNode = node->clipNode;
        if (clipNode != 0 && clipNode->parent() == 0 )
            parentNode->appendChildNode(clipNode);

        QColor color = node->selectionState == Selected
                ? m_selectedTextColor
                : node->color;

        parentNode->addGlyphs(node->position, node->glyphRun, color, style, styleColor, clipNode);
    }
Exemple #9
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;				
		}
}