aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquicktextnodeengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquicktextnodeengine.cpp')
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp165
1 files changed, 92 insertions, 73 deletions
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index dd666416e8..c486fece40 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquicktextnodeengine_p.h"
@@ -49,7 +13,6 @@
#include <QtGui/qtextlist.h>
#include <private/qquicktext_p.h>
-#include <private/qquicktextdocument_p.h>
#include <private/qtextdocumentlayout_p.h>
#include <private/qtextimagehandler_p.h>
#include <private/qrawfont_p.h>
@@ -58,6 +21,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcSgText)
+
QQuickTextNodeEngine::BinaryTreeNodeKey::BinaryTreeNodeKey(BinaryTreeNode *node)
: fontEngine(QRawFontPrivate::get(node->glyphRun.rawFont())->fontEngine)
, clipNode(node->clipNode)
@@ -71,7 +36,7 @@ QQuickTextNodeEngine::BinaryTreeNode::BinaryTreeNode(const QGlyphRun &g,
const QRectF &brect,
const Decorations &decs,
const QColor &c,
- const QColor &bc,
+ const QColor &bc, const QColor &dc,
const QPointF &pos, qreal a)
: glyphRun(g)
, boundingRect(brect)
@@ -80,6 +45,7 @@ QQuickTextNodeEngine::BinaryTreeNode::BinaryTreeNode(const QGlyphRun &g,
, decorations(decs)
, color(c)
, backgroundColor(bc)
+ , decorationColor(dc)
, position(pos)
, ascent(a)
, leftChildIndex(-1)
@@ -92,7 +58,7 @@ QQuickTextNodeEngine::BinaryTreeNode::BinaryTreeNode(const QGlyphRun &g,
void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState,
Decorations decorations, const QColor &textColor,
- const QColor &backgroundColor, const QPointF &position)
+ const QColor &backgroundColor, const QColor &decorationColor, const QPointF &position)
{
QRectF searchRect = glyphRun.boundingRect();
searchRect.translate(position);
@@ -112,6 +78,7 @@ void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode
decorations,
textColor,
backgroundColor,
+ decorationColor,
position,
ascent));
}
@@ -207,10 +174,7 @@ void QQuickTextNodeEngine::addTextDecorations(const QVarLengthArray<TextDecorati
{
QRectF &rect = textDecoration.rect;
- rect.setY(qRound(rect.y()
- + m_currentLine.ascent()
- + (m_currentLine.leadingIncluded() ? m_currentLine.leading() : qreal(0.0f))
- + offset));
+ rect.setY(qRound(rect.y() + m_currentLine.ascent() + offset));
rect.setHeight(thickness);
}
@@ -252,6 +216,7 @@ void QQuickTextNodeEngine::processCurrentLine()
QColor lastColor;
QColor lastBackgroundColor;
+ QColor lastDecorationColor;
QVarLengthArray<TextDecoration> pendingUnderlines;
QVarLengthArray<TextDecoration> pendingOverlines;
@@ -266,11 +231,10 @@ void QQuickTextNodeEngine::processCurrentLine()
Q_ASSERT(sortedIndex < m_currentLineTree.size());
node = m_currentLineTree.data() + sortedIndex;
+ if (i == 0)
+ currentSelectionState = node->selectionState;
}
- if (i == 0)
- currentSelectionState = node->selectionState;
-
// Update decorations
if (currentDecorations != Decoration::NoDecoration) {
decorationRect.setY(m_position.y() + m_currentLine.y());
@@ -280,6 +244,12 @@ void QQuickTextNodeEngine::processCurrentLine()
decorationRect.setRight(node->boundingRect.left());
TextDecoration textDecoration(currentSelectionState, decorationRect, lastColor);
+ if (lastDecorationColor.isValid() &&
+ (currentDecorations.testFlag(Decoration::Underline) ||
+ currentDecorations.testFlag(Decoration::Overline) ||
+ currentDecorations.testFlag(Decoration::StrikeOut)))
+ textDecoration.color = lastDecorationColor;
+
if (currentDecorations & Decoration::Underline)
pendingUnderlines.append(textDecoration);
@@ -398,6 +368,7 @@ void QQuickTextNodeEngine::processCurrentLine()
currentDecorations = node->decorations;
lastColor = node->color;
lastBackgroundColor = node->backgroundColor;
+ lastDecorationColor = node->decorationColor;
m_processedNodes.append(*node);
}
}
@@ -457,15 +428,8 @@ void QQuickTextNodeEngine::addTextObject(const QTextBlock &block, const QPointF
if (format.objectType() == QTextFormat::ImageObject) {
QTextImageFormat imageFormat = format.toImageFormat();
- if (QQuickTextDocumentWithImageResources *imageDoc = qobject_cast<QQuickTextDocumentWithImageResources *>(textDocument)) {
- image = imageDoc->image(imageFormat);
-
- if (image.isNull())
- return;
- } else {
- QTextImageHandler *imageHandler = static_cast<QTextImageHandler *>(handler);
- image = imageHandler->image(textDocument, imageFormat);
- }
+ QTextImageHandler *imageHandler = static_cast<QTextImageHandler *>(handler);
+ image = imageHandler->image(textDocument, imageFormat);
}
if (image.isNull()) {
@@ -511,6 +475,7 @@ void QQuickTextNodeEngine::addUnselectedGlyphs(const QGlyphRun &glyphRun)
Decoration::NoDecoration,
m_textColor,
m_backgroundColor,
+ m_decorationColor,
m_position);
}
@@ -523,6 +488,7 @@ void QQuickTextNodeEngine::addSelectedGlyphs(const QGlyphRun &glyphRun)
Decoration::NoDecoration,
m_textColor,
m_backgroundColor,
+ m_decorationColor,
m_position);
m_hasSelection = m_hasSelection || m_currentLineTree.size() > currentSize;
}
@@ -540,7 +506,7 @@ void QQuickTextNodeEngine::addGlyphsForRanges(const QVarLengthArray<QTextLayout:
if (range.start > currentPosition) {
addGlyphsInRange(currentPosition, range.start - currentPosition,
- QColor(), QColor(), selectionStart, selectionEnd);
+ QColor(), QColor(), QColor(), selectionStart, selectionEnd);
}
int rangeEnd = qMin(range.start + range.length, currentPosition + remainingLength);
QColor rangeColor;
@@ -552,8 +518,12 @@ void QQuickTextNodeEngine::addGlyphsForRanges(const QVarLengthArray<QTextLayout:
? range.format.background().color()
: QColor();
+ QColor rangeDecorationColor = range.format.hasProperty(QTextFormat::TextUnderlineColor)
+ ? range.format.underlineColor()
+ : QColor();
+
addGlyphsInRange(range.start, rangeEnd - range.start,
- rangeColor, rangeBackgroundColor,
+ rangeColor, rangeBackgroundColor, rangeDecorationColor,
selectionStart, selectionEnd);
currentPosition = range.start + range.length;
@@ -565,14 +535,14 @@ void QQuickTextNodeEngine::addGlyphsForRanges(const QVarLengthArray<QTextLayout:
}
if (remainingLength > 0) {
- addGlyphsInRange(currentPosition, remainingLength, QColor(), QColor(),
+ addGlyphsInRange(currentPosition, remainingLength, QColor(), QColor(), QColor(),
selectionStart, selectionEnd);
}
}
void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
- const QColor &color, const QColor &backgroundColor,
+ const QColor &color, const QColor &backgroundColor, const QColor &decorationColor,
int selectionStart, int selectionEnd)
{
QColor oldColor;
@@ -587,6 +557,12 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
m_backgroundColor = backgroundColor;
}
+ QColor oldDecorationColor = m_decorationColor;
+ if (decorationColor.isValid()) {
+ oldDecorationColor = m_decorationColor;
+ m_decorationColor = decorationColor;
+ }
+
bool hasSelection = selectionEnd >= 0
&& selectionStart <= selectionEnd;
@@ -630,6 +606,9 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
}
}
+ if (decorationColor.isValid())
+ m_decorationColor = oldDecorationColor;
+
if (backgroundColor.isValid())
m_backgroundColor = oldBackgroundColor;
@@ -681,9 +660,14 @@ void QQuickTextNodeEngine::addFrameDecorations(QTextDocument *document, QTextFra
if (borderStyle == QTextFrameFormat::BorderStyle_None)
return;
- addBorder(boundingRect.adjusted(frameFormat.leftMargin(), frameFormat.topMargin(),
- -frameFormat.rightMargin(), -frameFormat.bottomMargin()),
- borderWidth, borderStyle, borderBrush);
+ const auto collapsed = table->format().borderCollapse();
+
+ if (!collapsed) {
+ addBorder(boundingRect.adjusted(frameFormat.leftMargin(), frameFormat.topMargin(),
+ -frameFormat.rightMargin() - borderWidth,
+ -frameFormat.bottomMargin() - borderWidth),
+ borderWidth, borderStyle, borderBrush);
+ }
if (table != nullptr) {
int rows = table->rows();
int columns = table->columns();
@@ -693,7 +677,7 @@ void QQuickTextNodeEngine::addFrameDecorations(QTextDocument *document, QTextFra
QTextTableCell cell = table->cellAt(row, column);
QRectF cellRect = documentLayout->tableCellBoundingRect(table, cell);
- addBorder(cellRect.adjusted(-borderWidth, -borderWidth, 0, 0), borderWidth,
+ addBorder(cellRect.adjusted(-borderWidth, -borderWidth, collapsed ? -borderWidth : 0, collapsed ? -borderWidth : 0), borderWidth,
borderStyle, borderBrush);
}
}
@@ -714,6 +698,9 @@ void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularN
BinaryTreeNode *node = m_processedNodes.data() + i;
if (node->image.isNull()) {
+ if (node->glyphRun.isEmpty())
+ continue;
+
BinaryTreeNodeKey key(node);
QList<BinaryTreeNode *> &nodes = map[key];
@@ -768,7 +755,7 @@ void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularN
}
}
-void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
+void QQuickTextNodeEngine::addToSceneGraph(QSGInternalTextNode *parentNode,
QQuickText::TextStyle style,
const QColor &styleColor)
{
@@ -813,7 +800,7 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
? m_selectedTextColor
: textDecoration.color;
- parentNode->addRectangleNode(textDecoration.rect, color);
+ parentNode->addDecorationNode(textDecoration.rect, color);
}
// Finally add the selected text on top of everything
@@ -955,11 +942,21 @@ void QQuickTextNodeEngine::mergeFormats(QTextLayout *textLayout, QVarLengthArray
}
-void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QTextBlock &block, const QPointF &position, const QColor &textColor, const QColor &anchorColor, int selectionStart, int selectionEnd)
+/*!
+ \internal
+ Adds the \a block from the \a textDocument at \a position if its
+ \l {QAbstractTextDocumentLayout::blockBoundingRect()}{bounding rect}
+ intersects the \a viewport, or if \c viewport is not valid
+ (i.e. use a default-constructed QRectF to skip the viewport check).
+
+ \sa QQuickItem::clipRect()
+ */
+void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QTextBlock &block, const QPointF &position,
+ const QColor &textColor, const QColor &anchorColor, int selectionStart, int selectionEnd, const QRectF &viewport)
{
Q_ASSERT(textDocument);
#if QT_CONFIG(im)
- int preeditLength = block.isValid() ? block.layout()->preeditAreaText().length() : 0;
+ int preeditLength = block.isValid() ? block.layout()->preeditAreaText().size() : 0;
int preeditPosition = block.isValid() ? block.layout()->preeditAreaPosition() : -1;
#endif
@@ -970,6 +967,11 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
const QTextCharFormat charFormat = block.charFormat();
const QRectF blockBoundingRect = textDocument->documentLayout()->blockBoundingRect(block).translated(position);
+ if (viewport.isValid()) {
+ if (!blockBoundingRect.intersects(viewport))
+ return;
+ qCDebug(lcSgText) << "adding block with length" << block.length() << ':' << blockBoundingRect << "in viewport" << viewport;
+ }
if (charFormat.background().style() != Qt::NoBrush)
m_backgrounds.append(qMakePair(blockBoundingRect, charFormat.background().color()));
@@ -1037,6 +1039,12 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
line.setPosition(QPointF(0, 0));
layout.endLayout();
+ // set the color for the bullets, instead of using the previous QTextBlock's color.
+ if (charFormat.foreground().style() == Qt::NoBrush)
+ setTextColor(textColor);
+ else
+ setTextColor(charFormat.foreground().color());
+
QList<QGlyphRun> glyphRuns = layout.glyphRuns();
for (int i=0; i<glyphRuns.size(); ++i)
addUnselectedGlyphs(glyphRuns.at(i));
@@ -1065,7 +1073,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
else
setPosition(blockBoundingRect.topLeft());
- if (text.contains(QChar::ObjectReplacementCharacter)) {
+ if (text.contains(QChar::ObjectReplacementCharacter) && charFormat.objectType() != QTextFormat::NoObject) {
QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat));
if (!frame || frame->frameFormat().position() == QTextFrameFormat::InFlow) {
int blockRelativePosition = textPos - block.position();
@@ -1076,14 +1084,14 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
}
QQuickTextNodeEngine::SelectionState selectionState =
- (selectionStart < textPos + text.length()
+ (selectionStart < textPos + text.size()
&& selectionEnd >= textPos)
? QQuickTextNodeEngine::Selected
: QQuickTextNodeEngine::Unselected;
addTextObject(block, QPointF(), charFormat, selectionState, textDocument, textPos);
}
- textPos += text.length();
+ textPos += text.size();
} else {
if (charFormat.foreground().style() != Qt::NoBrush)
setTextColor(charFormat.foreground().color());
@@ -1100,7 +1108,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
fragmentEnd += preeditLength;
}
#endif
- if (charFormat.background().style() != Qt::NoBrush) {
+ if (charFormat.background().style() != Qt::NoBrush || charFormat.hasProperty(QTextFormat::TextUnderlineColor)) {
QTextLayout::FormatRange additionalFormat;
additionalFormat.start = textPos - block.position();
additionalFormat.length = fragmentEnd - textPos;
@@ -1130,6 +1138,17 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
}
#endif
+ // Add block decorations (so far only horizontal rules)
+ if (block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)) {
+ auto ruleLength = qvariant_cast<QTextLength>(block.blockFormat().property(QTextFormat::BlockTrailingHorizontalRulerWidth));
+ QRectF ruleRect(0, 0, ruleLength.value(blockBoundingRect.width()), 1);
+ ruleRect.moveCenter(blockBoundingRect.center());
+ const QColor ruleColor = block.blockFormat().hasProperty(QTextFormat::BackgroundBrush)
+ ? qvariant_cast<QBrush>(block.blockFormat().property(QTextFormat::BackgroundBrush)).color()
+ : m_textColor;
+ m_lines.append(TextDecoration(QQuickTextNodeEngine::Unselected, ruleRect, ruleColor));
+ }
+
setCurrentLine(QTextLine()); // Reset current line because the text layout changed
m_hasContents = true;
}