Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsgdefaultglyphnode.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
7
8#include <private/qrawfont_p.h>
9
11
12QSGDefaultGlyphNode::QSGDefaultGlyphNode(QSGRenderContext *context)
13 : QSGGlyphNode(QSGTextNode::NativeRendering)
14 , m_context(context)
15 , m_glyphNodeType(RootGlyphNode)
16 , m_dirtyGeometry(false)
17 , m_recycled(false)
18 , m_preferredAntialiasingMode(DefaultAntialiasing)
19 , m_style(QQuickText::Normal)
20 , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
21{
22 setFlag(UsePreprocess);
23 setFlag(OwnsMaterial);
24 m_geometry.setDrawingMode(QSGGeometry::DrawTriangles);
25 setGeometry(&m_geometry);
26}
27
28QSGDefaultGlyphNode::~QSGDefaultGlyphNode()
29{
30 cleanup();
31}
32
33void QSGDefaultGlyphNode::cleanup()
34{
35 if (m_glyphNodeType == SubGlyphNode)
36 return;
37
38 qDeleteAll(m_nodesToDelete);
39 m_nodesToDelete.clear();
40}
41
42void QSGDefaultGlyphNode::recycle()
43{
44 QSGGlyphNode::recycle();
45
46 cleanup();
47
48 m_glyphs = QGlyphRun{};
49 m_position = QPointF{};
50 m_color = QColor{};
51 m_style = QQuickText::Normal;
52 m_baseLine = QPointF{};
53 m_geometry.allocate(0, 0);
54
55 m_dirtyGeometry = true;
56 m_preferredAntialiasingMode = DefaultAntialiasing;
57 m_recycled = true;
58}
59
60void QSGDefaultGlyphNode::setColor(const QColor &color)
61{
62 m_color = color;
63 if (material() != nullptr && !m_recycled) {
64 static_cast<QSGTextMaskMaterial *>(material())->setColor(color);
65 markDirty(DirtyMaterial);
66 }
67}
68
69void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
70{
71 m_position = position;
72 m_glyphs = glyphs;
73 m_dirtyGeometry = true;
74
75#ifdef QSG_RUNTIME_DESCRIPTION
76 qsgnode_set_description(this, QLatin1String("glyphs"));
77#endif
78}
79
80void QSGDefaultGlyphNode::setStyle(QQuickText::TextStyle style)
81{
82 if (m_style == style)
83 return;
84 m_style = style;
85}
86
87void QSGDefaultGlyphNode::setStyleColor(const QColor &color)
88{
89 if (m_styleColor == color)
90 return;
91 m_styleColor = color;
92}
93
94void QSGDefaultGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
95{
96 m_preferredAntialiasingMode = mode;
97}
98
99void QSGDefaultGlyphNode::update()
100{
101 m_recycled = false;
102
103 QRawFont font = m_glyphs.rawFont();
104 QMargins margins(0, 0, 0, 0);
105
106 const auto *fontEngine = QRawFontPrivate::get(font)->fontEngine;
107 const bool isColorFont = fontEngine->glyphFormat == QFontEngine::Format_ARGB;
108
109 QSGTextMaskMaterial *material = nullptr;
110 if (m_style == QQuickText::Normal || isColorFont) {
111 QFontEngine::GlyphFormat glyphFormat;
112
113 // Don't try to override glyph format of color fonts
114 if (isColorFont) {
115 glyphFormat = QFontEngine::Format_None;
116 } else {
117 switch (m_preferredAntialiasingMode) {
118 case GrayAntialiasing:
119 glyphFormat = QFontEngine::Format_A8;
120 break;
121 case HighQualitySubPixelAntialiasing:
122 case LowQualitySubPixelAntialiasing:
123 glyphFormat = QFontEngine::Format_A32;
124 break;
125 default:
126 glyphFormat = QFontEngine::Format_None;
127 break;
128 }
129 }
130
131 const auto rgbColor = m_color.toRgb();
132 material = new QSGTextMaskMaterial(m_context, QVector4D(rgbColor.redF(), rgbColor.greenF(), rgbColor.blueF(), rgbColor.alphaF()), font, glyphFormat);
133 } else if (m_style == QQuickText::Outline) {
134 QSGOutlinedTextMaterial *m = new QSGOutlinedTextMaterial(m_context, font);
135 m->setStyleColor(m_styleColor);
136 margins = QMargins(1, 1, 1, 1);
137 material = m;
138 } else {
139 QSGStyledTextMaterial *m = new QSGStyledTextMaterial(m_context, font);
140 if (m_style == QQuickText::Sunken) {
141 m->setStyleShift(QVector2D(0, -1));
142 margins.setTop(1);
143 } else if (m_style == QQuickText::Raised) {
144 m->setStyleShift(QVector2D(0, 1));
145 margins.setBottom(1);
146 }
147 m->setStyleColor(m_styleColor);
148 material = m;
149 }
150
151 material->setColor(m_color);
152
153 QRectF boundingRect;
154 material->populate(m_position, m_glyphs.glyphIndexes(), m_glyphs.positions(), geometry(),
155 &boundingRect, &m_baseLine, margins);
156 setBoundingRect(boundingRect);
157
158 setMaterial(material);
159 markDirty(DirtyGeometry);
160}
161
162void QSGDefaultGlyphNode::preprocess()
163{
164 qDeleteAll(m_nodesToDelete);
165 m_nodesToDelete.clear();
166
167 if (m_dirtyGeometry)
168 updateGeometry();
169}
170
171void QSGDefaultGlyphNode::updateGeometry()
172{
173 // Remove previously created sub glyph nodes
174 // We assume all the children are sub glyph nodes
175 QSGNode *subnode = firstChild();
176 while (subnode) {
177 // We can't delete the node now as it might be in the preprocess list
178 // It will be deleted in the next preprocess
179 m_nodesToDelete.append(subnode);
180 subnode = subnode->nextSibling();
181 }
182 removeAllChildNodes();
183
184 GlyphInfo glyphInfo;
185
186 const QList<quint32> indexes = m_glyphs.glyphIndexes();
187 const QList<QPointF> positions = m_glyphs.positions();
188
189 const int maxGlyphs = (USHRT_MAX + 1) / 4; // 16384
190 const int maxVertices = maxGlyphs * 4; // 65536
191 const int maxIndexes = maxGlyphs * 6; // 98304
192
193 for (int i = 0; i < indexes.size(); ++i) {
194 const int glyphIndex = indexes.at(i);
195 const QPointF position = positions.at(i);
196
197 // As we use UNSIGNED_SHORT indexing in the geometry, we overload the
198 // "glyphsInOtherNodes" concept as overflow for if there are more than
199 // 65536 (16384 * 4) vertices to render which would otherwise exceed
200 // the maximum index size. This will cause sub-nodes to be recursively
201 // created to handle any number of glyphs.
202 if (i >= maxGlyphs) {
203 glyphInfo.indexes.append(glyphIndex);
204 glyphInfo.positions.append(position);
205 continue;
206 }
207 }
208
209 if (!glyphInfo.indexes.isEmpty()) {
210 QGlyphRun subNodeGlyphRun(m_glyphs);
211 subNodeGlyphRun.setGlyphIndexes(glyphInfo.indexes);
212 subNodeGlyphRun.setPositions(glyphInfo.positions);
213
214 QSGDefaultGlyphNode *subNode = new QSGDefaultGlyphNode(m_context);
215 subNode->setGlyphNodeType(SubGlyphNode);
216 subNode->setColor(m_color);
217 subNode->setStyle(m_style);
218 subNode->setStyleColor(m_styleColor);
219 subNode->setGlyphs(m_position, subNodeGlyphRun);
220 subNode->update();
221 subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered
222 appendChildNode(subNode);
223
224 QSGGeometry *g = geometry();
225
226 QSGGeometry::TexturedPoint2D *vertexData = g->vertexDataAsTexturedPoint2D();
227 quint16 *indexData = g->indexDataAsUShort();
228
229 QList<QSGGeometry::TexturedPoint2D> tempVertexData(maxVertices);
230 QList<quint16> tempIndexData(maxIndexes);
231
232 for (int i = 0; i < maxGlyphs; i++) {
233 tempVertexData[i * 4 + 0] = vertexData[i * 4 + 0];
234 tempVertexData[i * 4 + 1] = vertexData[i * 4 + 1];
235 tempVertexData[i * 4 + 2] = vertexData[i * 4 + 2];
236 tempVertexData[i * 4 + 3] = vertexData[i * 4 + 3];
237
238 tempIndexData[i * 6 + 0] = indexData[i * 6 + 0];
239 tempIndexData[i * 6 + 1] = indexData[i * 6 + 1];
240 tempIndexData[i * 6 + 2] = indexData[i * 6 + 2];
241 tempIndexData[i * 6 + 3] = indexData[i * 6 + 3];
242 tempIndexData[i * 6 + 4] = indexData[i * 6 + 4];
243 tempIndexData[i * 6 + 5] = indexData[i * 6 + 5];
244 }
245
246 g->allocate(maxVertices, maxIndexes);
247 vertexData = g->vertexDataAsTexturedPoint2D();
248 indexData = g->indexDataAsUShort();
249
250 for (int i = 0; i < maxGlyphs; i++) {
251 vertexData[i * 4 + 0] = tempVertexData[i * 4 + 0];
252 vertexData[i * 4 + 1] = tempVertexData[i * 4 + 1];
253 vertexData[i * 4 + 2] = tempVertexData[i * 4 + 2];
254 vertexData[i * 4 + 3] = tempVertexData[i * 4 + 3];
255
256 indexData[i * 6 + 0] = tempIndexData[i * 6 + 0];
257 indexData[i * 6 + 1] = tempIndexData[i * 6 + 1];
258 indexData[i * 6 + 2] = tempIndexData[i * 6 + 2];
259 indexData[i * 6 + 3] = tempIndexData[i * 6 + 3];
260 indexData[i * 6 + 4] = tempIndexData[i * 6 + 4];
261 indexData[i * 6 + 5] = tempIndexData[i * 6 + 5];
262 }
263 }
264
265 m_dirtyGeometry = false;
266}
267
268QT_END_NAMESPACE
\inmodule QtCore
Definition qmargins.h:27
constexpr void setTop(int top) noexcept
Sets the Top margin to Top.
Definition qmargins.h:148
constexpr void setBottom(int bottom) noexcept
Sets the bottom margin to bottom.
Definition qmargins.h:154
constexpr QMargins(int left, int top, int right, int bottom) noexcept
Constructs margins with the given left, top, right, and bottom.
Definition qmargins.h:126
The QRawFont class provides access to a single physical instance of a font.
Definition qrawfont.h:24
\inmodule QtQuick
void setStyleColor(const QColor &c)
void setColor(const QColor &c)
Combined button and popup list for selecting options.