1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include <QtCore/qlist.h> |
5 | #include <QtCore/qvarlengtharray.h> |
6 | #include <QtGui/qcolor.h> |
7 | #include <QtGui/qglyphrun.h> |
8 | #include <QtGui/qimage.h> |
9 | #include <QtGui/qtextdocument.h> |
10 | #include <QtGui/qtextlayout.h> |
11 | #include "qquickclipnode_p.h" |
12 | #include "qquicktextnode_p.h" |
13 | |
14 | #ifndef QQUICKTEXTNODEENGINE_P_H |
15 | #define QQUICKTEXTNODEENGINE_P_H |
16 | |
17 | // |
18 | // W A R N I N G |
19 | // ------------- |
20 | // |
21 | // This file is not part of the Qt API. It exists purely as an |
22 | // implementation detail. This header file may change from version to |
23 | // version without notice, or even be removed. |
24 | // |
25 | // We mean it. |
26 | // |
27 | |
28 | QT_BEGIN_NAMESPACE |
29 | |
30 | // Engine that takes glyph runs as input, and produces a set of glyph nodes, clip nodes, |
31 | // and rectangle nodes to represent the text, decorations and selection. Will try to minimize |
32 | // number of nodes, and join decorations in neighbouring items |
33 | |
34 | class QQuickTextNodeEngine { |
35 | public: |
36 | enum Decoration { |
37 | NoDecoration = 0x0, |
38 | Underline = 0x1, |
39 | Overline = 0x2, |
40 | StrikeOut = 0x4, |
41 | Background = 0x8 |
42 | }; |
43 | Q_DECLARE_FLAGS(Decorations, Decoration) |
44 | |
45 | enum SelectionState { |
46 | Unselected, |
47 | Selected |
48 | }; |
49 | |
50 | struct BinaryTreeNode { |
51 | |
52 | BinaryTreeNode() |
53 | : selectionState(Unselected), clipNode(0), decorations(Decoration::NoDecoration) |
54 | , ascent(0.0), leftChildIndex(-1), rightChildIndex(-1) |
55 | { |
56 | } |
57 | |
58 | BinaryTreeNode(const QRectF &brect, const QImage &i, SelectionState selState, qreal a) |
59 | : boundingRect(brect), selectionState(selState), clipNode(0), decorations(Decoration::NoDecoration) |
60 | , image(i), ascent(a), leftChildIndex(-1), rightChildIndex(-1) |
61 | { |
62 | } |
63 | |
64 | BinaryTreeNode(const QGlyphRun &g, SelectionState selState, const QRectF &brect, |
65 | const Decorations &decs, const QColor &c, const QColor &bc, const QColor &dc, |
66 | const QPointF &pos, qreal a); |
67 | |
68 | QGlyphRun glyphRun; |
69 | QRectF boundingRect; |
70 | SelectionState selectionState; |
71 | QQuickDefaultClipNode *clipNode; |
72 | Decorations decorations; |
73 | QColor color; |
74 | QColor backgroundColor; |
75 | QColor decorationColor; |
76 | QPointF position; |
77 | QImage image; |
78 | qreal ascent; |
79 | |
80 | int leftChildIndex; |
81 | int rightChildIndex; |
82 | |
83 | QList<QPair<int, int> > ranges; |
84 | |
85 | static void insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QRectF &rect, const QImage &image, qreal ascent, SelectionState selectionState) |
86 | { insert(binaryTree, binaryTreeNode: BinaryTreeNode(rect, image, selectionState, ascent)); } |
87 | |
88 | static void insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState, |
89 | Decorations decorations, const QColor &textColor, const QColor &backgroundColor, const QColor &underlineColor, const QPointF &position); |
90 | static void insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const BinaryTreeNode &binaryTreeNode); |
91 | static void inOrder(const QVarLengthArray<BinaryTreeNode, 16> &binaryTree, QVarLengthArray<int> *sortedIndexes, int currentIndex = 0); |
92 | }; |
93 | |
94 | struct BinaryTreeNodeKey |
95 | { |
96 | BinaryTreeNodeKey(BinaryTreeNode *node); |
97 | |
98 | bool operator==(const BinaryTreeNodeKey &otherKey) const |
99 | { |
100 | return fontEngine == otherKey.fontEngine |
101 | && clipNode == otherKey.clipNode |
102 | && color == otherKey.color |
103 | && selectionState == otherKey.selectionState; |
104 | } |
105 | |
106 | QFontEngine *fontEngine; |
107 | QQuickDefaultClipNode *clipNode; |
108 | QRgb color; |
109 | int selectionState; |
110 | }; |
111 | |
112 | QQuickTextNodeEngine() |
113 | : m_currentTextDirection(Qt::LeftToRight) |
114 | , m_hasSelection(false) |
115 | , m_hasContents(false) |
116 | {} |
117 | |
118 | bool hasContents() const { return m_hasContents; } |
119 | void addTextBlock(QTextDocument *, const QTextBlock &, const QPointF &position, const QColor &textColor, |
120 | const QColor& anchorColor, int selectionStart, int selectionEnd, const QRectF &viewport = QRectF()); |
121 | QTextLine currentLine() const { return m_currentLine; } |
122 | |
123 | void setCurrentLine(const QTextLine ¤tLine) |
124 | { |
125 | if (m_currentLine.isValid()) |
126 | processCurrentLine(); |
127 | |
128 | m_currentLine = currentLine; |
129 | } |
130 | |
131 | void setCurrentTextDirection(Qt::LayoutDirection textDirection) |
132 | { |
133 | m_currentTextDirection = textDirection; |
134 | } |
135 | |
136 | void addBorder(const QRectF &rect, qreal border, QTextFrameFormat::BorderStyle borderStyle, |
137 | const QBrush &borderBrush); |
138 | void addFrameDecorations(QTextDocument *document, QTextFrame *frame); |
139 | void addImage(const QRectF &rect, const QImage &image, qreal ascent, |
140 | SelectionState selectionState, |
141 | QTextFrameFormat::Position layoutPosition); |
142 | int addText(const QTextBlock &block, |
143 | const QTextCharFormat &charFormat, |
144 | const QColor &textColor, |
145 | const QVarLengthArray<QTextLayout::FormatRange> &colorChanges, |
146 | int textPos, int fragmentEnd, |
147 | int selectionStart, int selectionEnd); |
148 | void addTextObject(const QTextBlock &block, const QPointF &position, const QTextCharFormat &format, |
149 | SelectionState selectionState, |
150 | QTextDocument *textDocument, int pos, |
151 | QTextFrameFormat::Position layoutPosition = QTextFrameFormat::InFlow); |
152 | void addSelectedGlyphs(const QGlyphRun &glyphRun); |
153 | void addUnselectedGlyphs(const QGlyphRun &glyphRun); |
154 | void addGlyphsInRange(int rangeStart, int rangeEnd, |
155 | const QColor &color, const QColor &backgroundColor, const QColor &underlineColor, |
156 | int selectionStart, int selectionEnd); |
157 | void addGlyphsForRanges(const QVarLengthArray<QTextLayout::FormatRange> &ranges, |
158 | int start, int end, |
159 | int selectionStart, int selectionEnd); |
160 | |
161 | void mergeProcessedNodes(QList<BinaryTreeNode *> *regularNodes, |
162 | QList<BinaryTreeNode *> *imageNodes); |
163 | void addToSceneGraph(QQuickTextNode *parent, |
164 | QQuickText::TextStyle style = QQuickText::Normal, |
165 | const QColor &styleColor = QColor()); |
166 | |
167 | void setSelectionColor(const QColor &selectionColor) |
168 | { |
169 | m_selectionColor = selectionColor; |
170 | } |
171 | |
172 | void setSelectedTextColor(const QColor &selectedTextColor) |
173 | { |
174 | m_selectedTextColor = selectedTextColor; |
175 | } |
176 | |
177 | void setTextColor(const QColor &textColor) |
178 | { |
179 | m_textColor = textColor; |
180 | } |
181 | |
182 | void setAnchorColor(const QColor &anchorColor) |
183 | { |
184 | m_anchorColor = anchorColor; |
185 | } |
186 | |
187 | void setPosition(const QPointF &position) |
188 | { |
189 | m_position = position; |
190 | } |
191 | |
192 | |
193 | |
194 | |
195 | private: |
196 | struct TextDecoration |
197 | { |
198 | TextDecoration() : selectionState(Unselected) {} |
199 | TextDecoration(const SelectionState &s, |
200 | const QRectF &r, |
201 | const QColor &c) |
202 | : selectionState(s) |
203 | , rect(r) |
204 | , color(c) |
205 | { |
206 | } |
207 | |
208 | SelectionState selectionState; |
209 | QRectF rect; |
210 | QColor color; |
211 | }; |
212 | |
213 | void processCurrentLine(); |
214 | void addTextDecorations(const QVarLengthArray<TextDecoration> &textDecorations, qreal offset, qreal thickness); |
215 | void mergeFormats(QTextLayout *textLayout, QVarLengthArray<QTextLayout::FormatRange> *mergedFormats); |
216 | |
217 | QColor m_selectionColor; |
218 | QColor m_textColor; |
219 | QColor m_backgroundColor; |
220 | QColor m_decorationColor; |
221 | QColor m_selectedTextColor; |
222 | QColor m_anchorColor; |
223 | QPointF m_position; |
224 | |
225 | QTextLine m_currentLine; |
226 | Qt::LayoutDirection m_currentTextDirection; |
227 | |
228 | QList<QPair<QRectF, QColor> > m_backgrounds; |
229 | QList<QRectF> m_selectionRects; |
230 | QVarLengthArray<BinaryTreeNode, 16> m_currentLineTree; |
231 | |
232 | QList<TextDecoration> m_lines; |
233 | QVector<BinaryTreeNode> m_processedNodes; |
234 | |
235 | bool m_hasSelection : 1; |
236 | bool m_hasContents : 1; |
237 | friend class QQuickTextNode; |
238 | |
239 | }; |
240 | |
241 | QT_END_NAMESPACE |
242 | |
243 | #endif // QQUICKTEXTNODEENGINE_P_H |
244 | |