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.cpp232
1 files changed, 153 insertions, 79 deletions
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index e9ff70e00b..f746fe8b1b 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -1,40 +1,32 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL$
+** $QT_BEGIN_LICENSE:LGPL21$
** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -49,7 +41,6 @@
#include <QtGui/qtextobject.h>
#include <QtGui/qtexttable.h>
#include <QtGui/qtextlist.h>
-#include <QtQuick/qsgsimplerectnode.h>
#include <private/qquicktext_p_p.h>
#include <private/qtextdocumentlayout_p.h>
@@ -60,7 +51,7 @@ QT_BEGIN_NAMESPACE
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)
+ const QColor &backgroundColor, const QPointF &position, int rangeStart, int rangeEnd)
{
QRectF searchRect = glyphRun.boundingRect();
searchRect.translate(position);
@@ -75,7 +66,7 @@ void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode
qreal ascent = glyphRun.rawFont().ascent();
insert(binaryTree, BinaryTreeNode(glyphRun, selectionState, searchRect, decorations,
- textColor, backgroundColor, position, ascent));
+ textColor, backgroundColor, position, ascent, rangeStart, rangeEnd));
}
void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const BinaryTreeNode &binaryTreeNode)
@@ -256,12 +247,9 @@ void QQuickTextNodeEngine::processCurrentLine()
// 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) {
- if (node != 0)
- currentRect.setRight(node->boundingRect.left());
currentRect.setY(m_position.y() + m_currentLine.y());
currentRect.setHeight(m_currentLine.height());
- // Draw selection all the way up to the left edge of the unselected item
if (currentSelectionState == Selected)
m_selectionRects.append(currentRect);
@@ -297,8 +285,10 @@ void QQuickTextNodeEngine::processCurrentLine()
}
if (node != 0) {
- node->clipNode = currentClipNode;
- currentClipNodeUsed = true;
+ if (node->selectionState == Selected) {
+ node->clipNode = currentClipNode;
+ currentClipNodeUsed = true;
+ }
decorationRect = node->boundingRect;
@@ -451,17 +441,19 @@ void QQuickTextNodeEngine::addTextObject(const QPointF &position, const QTextCha
}
}
-void QQuickTextNodeEngine::addUnselectedGlyphs(const QGlyphRun &glyphRun)
+void QQuickTextNodeEngine::addUnselectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd)
{
BinaryTreeNode::insert(&m_currentLineTree, glyphRun, Unselected,
- QQuickTextNode::NoDecoration, m_textColor, m_backgroundColor, m_position);
+ QQuickTextNode::NoDecoration, m_textColor, m_backgroundColor, m_position,
+ rangeStart, rangeEnd);
}
-void QQuickTextNodeEngine::addSelectedGlyphs(const QGlyphRun &glyphRun)
+void QQuickTextNodeEngine::addSelectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd)
{
int currentSize = m_currentLineTree.size();
BinaryTreeNode::insert(&m_currentLineTree, glyphRun, Selected,
- QQuickTextNode::NoDecoration, m_textColor, m_backgroundColor, m_position);
+ QQuickTextNode::NoDecoration, m_textColor, m_backgroundColor, m_position,
+ rangeStart, rangeEnd);
m_hasSelection = m_hasSelection || m_currentLineTree.size() > currentSize;
}
@@ -534,17 +526,15 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
QList<QGlyphRun> glyphRuns = line.glyphRuns(rangeStart, rangeLength);
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addUnselectedGlyphs(glyphRun);
+ addUnselectedGlyphs(glyphRun, rangeStart, rangeEnd - 1);
}
} else {
if (rangeStart < selectionStart) {
- QList<QGlyphRun> glyphRuns = line.glyphRuns(rangeStart,
- qMin(selectionStart - rangeStart,
- rangeLength));
-
+ int length = qMin(selectionStart - rangeStart, rangeLength);
+ QList<QGlyphRun> glyphRuns = line.glyphRuns(rangeStart, length);
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addUnselectedGlyphs(glyphRun);
+ addUnselectedGlyphs(glyphRun, rangeStart, rangeStart + length - 1);
}
}
@@ -555,15 +545,18 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addSelectedGlyphs(glyphRun);
+ addSelectedGlyphs(glyphRun, start, start + length - 1);
+ addUnselectedGlyphs(glyphRun, start, start + length - 1);
}
}
if (selectionEnd >= rangeStart && selectionEnd < rangeEnd) {
- QList<QGlyphRun> glyphRuns = line.glyphRuns(selectionEnd + 1, rangeEnd - selectionEnd - 1);
+ int start = selectionEnd + 1;
+ int length = rangeEnd - selectionEnd - 1;
+ QList<QGlyphRun> glyphRuns = line.glyphRuns(start, length);
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addUnselectedGlyphs(glyphRun);
+ addUnselectedGlyphs(glyphRun, start, start + length - 1);
}
}
}
@@ -642,37 +635,12 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
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;
+ QList<BinaryTreeNode *> imageNodes;
for (int i = 0; i < m_processedNodes.size(); ++i) {
BinaryTreeNode *node = m_processedNodes.data() + i;
@@ -705,31 +673,137 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode,
otherGlyphRun.setGlyphIndexes(otherGlyphIndexes);
otherGlyphRun.setPositions(otherGlyphPositions);
+ otherNode->ranges += node->ranges;
+
} 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));
- }
+ imageNodes.append(node);
}
}
- foreach (const BinaryTreeNode *node, nodes) {
+ 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->addRectangleNode(rect, color);
+ }
+ // Add all unselected text first
+ for (int i = 0; i < nodes.size(); ++i) {
+ const BinaryTreeNode *node = nodes.at(i);
+ if (node->selectionState == Unselected)
+ parentNode->addGlyphs(node->position, node->glyphRun, node->color, style, styleColor, 0);
+ }
+
+ for (int i = 0; i < imageNodes.size(); ++i) {
+ const BinaryTreeNode *node = imageNodes.at(i);
+ if (node->selectionState == Unselected)
+ parentNode->addImage(node->boundingRect, node->image);
+ }
+
+ // Then, prepend all selection rectangles to the tree
+ for (int i = 0; i < m_selectionRects.size(); ++i) {
+ const QRectF &rect = m_selectionRects.at(i);
+
+ parentNode->addRectangleNode(rect, m_selectionColor);
+ }
+
+ // 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->addRectangleNode(textDecoration.rect, color);
+ }
+
+ // Finally add the selected text on top of everything
+ for (int i = 0; i < nodes.size(); ++i) {
+ const BinaryTreeNode *node = nodes.at(i);
QQuickDefaultClipNode *clipNode = node->clipNode;
- if (clipNode != 0 && clipNode->parent() == 0 )
+ if (clipNode != 0 && clipNode->parent() == 0)
parentNode->appendChildNode(clipNode);
- QColor color = node->selectionState == Selected
- ? m_selectedTextColor
- : node->color;
+ if (node->selectionState == Selected) {
+ QColor color = m_selectedTextColor;
+ int previousNodeIndex = i - 1;
+ int nextNodeIndex = i + 1;
+ const BinaryTreeNode *previousNode = previousNodeIndex < 0 ? 0 : nodes.at(previousNodeIndex);
+ while (previousNode != 0 && qFuzzyCompare(previousNode->boundingRect.left(), node->boundingRect.left()))
+ previousNode = --previousNodeIndex < 0 ? 0 : nodes.at(previousNodeIndex);
+
+ const BinaryTreeNode *nextNode = nextNodeIndex == nodes.size() ? 0 : nodes.at(nextNodeIndex);
+
+ if (previousNode != 0 && previousNode->selectionState == Unselected)
+ parentNode->addGlyphs(previousNode->position, previousNode->glyphRun, color, style, styleColor, clipNode);
+
+ if (nextNode != 0 && nextNode->selectionState == Unselected)
+ parentNode->addGlyphs(nextNode->position, nextNode->glyphRun, color, style, styleColor, clipNode);
+
+ // If the previous or next node completely overlaps this one, then we have already drawn the glyphs of
+ // this node
+ bool drawCurrent = false;
+ if (previousNode != 0 || nextNode != 0) {
+ for (int i = 0; i < node->ranges.size(); ++i) {
+ const QPair<int, int> &range = node->ranges.at(i);
+
+ int rangeLength = range.second - range.first + 1;
+ if (previousNode != 0) {
+ for (int j = 0; j < previousNode->ranges.size(); ++j) {
+ const QPair<int, int> &otherRange = previousNode->ranges.at(j);
+ if (range.first <= otherRange.second && range.second >= otherRange.first) {
+ int start = qMax(range.first, otherRange.first);
+ int end = qMin(range.second, otherRange.second);
+ rangeLength -= end - start + 1;
+ if (rangeLength == 0)
+ break;
+ }
+ }
+ }
+
+ if (nextNode != 0 && rangeLength > 0) {
+ for (int j = 0; j < nextNode->ranges.size(); ++j) {
+ const QPair<int, int> &otherRange = nextNode->ranges.at(j);
+
+ if (range.first <= otherRange.second && range.second >= otherRange.first) {
+ int start = qMax(range.first, otherRange.first);
+ int end = qMin(range.second, otherRange.second);
+ rangeLength -= end - start + 1;
+ if (rangeLength == 0)
+ break;
+ }
+ }
+ }
- parentNode->addGlyphs(node->position, node->glyphRun, color, style, styleColor, clipNode);
+ if (rangeLength > 0) {
+ drawCurrent = true;
+ break;
+ }
+ }
+ } else {
+ drawCurrent = true;
+ }
+
+ if (drawCurrent)
+ parentNode->addGlyphs(node->position, node->glyphRun, color, style, styleColor, clipNode);
+ }
+ }
+
+ for (int i = 0; i < imageNodes.size(); ++i) {
+ const BinaryTreeNode *node = imageNodes.at(i);
+ if (node->selectionState == Selected) {
+ parentNode->addImage(node->boundingRect, node->image);
+ if (node->selectionState == Selected) {
+ QColor color = m_selectionColor;
+ color.setAlpha(128);
+ parentNode->addRectangleNode(node->boundingRect, color);
+ }
+ }
}
}
@@ -853,7 +927,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
QList<QGlyphRun> glyphRuns = layout.glyphRuns();
for (int i=0; i<glyphRuns.size(); ++i)
- addUnselectedGlyphs(glyphRuns.at(i));
+ addUnselectedGlyphs(glyphRuns.at(i), 0, layout.text().length() - 1);
}
}