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 "qsgdefaultglyphnode_p.h"
5#include "qsgdefaultglyphnode_p_p.h"
6
7#include <private/qrawfont_p.h>
8
9QT_BEGIN_NAMESPACE
10
11QSGDefaultGlyphNode::QSGDefaultGlyphNode(QSGRenderContext *context)
12 : m_context(context)
13 , m_glyphNodeType(RootGlyphNode)
14 , m_dirtyGeometry(false)
15 , m_preferredAntialiasingMode(DefaultAntialiasing)
16{
17 setFlag(UsePreprocess);
18}
19
20QSGDefaultGlyphNode::~QSGDefaultGlyphNode()
21{
22 if (m_glyphNodeType == SubGlyphNode)
23 return;
24
25 qDeleteAll(c: m_nodesToDelete);
26 m_nodesToDelete.clear();
27}
28
29void QSGDefaultGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
30{
31 m_preferredAntialiasingMode = mode;
32}
33
34void QSGDefaultGlyphNode::setMaterialColor(const QColor &color)
35{
36 static_cast<QSGTextMaskMaterial *>(m_material)->setColor(color);
37}
38
39void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
40{
41 QSGBasicGlyphNode::setGlyphs(position, glyphs);
42 m_dirtyGeometry = true;
43}
44
45void QSGDefaultGlyphNode::update()
46{
47 QRawFont font = m_glyphs.rawFont();
48 QMargins margins(0, 0, 0, 0);
49
50 const auto *fontEngine = QRawFontPrivate::get(font)->fontEngine;
51 const bool isColorFont = fontEngine->glyphFormat == QFontEngine::Format_ARGB;
52
53 if (m_style == QQuickText::Normal || isColorFont) {
54 QFontEngine::GlyphFormat glyphFormat;
55
56 // Don't try to override glyph format of color fonts
57 if (isColorFont) {
58 glyphFormat = QFontEngine::Format_None;
59 } else {
60 switch (m_preferredAntialiasingMode) {
61 case GrayAntialiasing:
62 glyphFormat = QFontEngine::Format_A8;
63 break;
64 case HighQualitySubPixelAntialiasing:
65 case LowQualitySubPixelAntialiasing:
66 glyphFormat = QFontEngine::Format_A32;
67 break;
68 default:
69 glyphFormat = QFontEngine::Format_None;
70 break;
71 }
72 }
73
74 const auto rgbColor = m_color.toRgb();
75 m_material = new QSGTextMaskMaterial(m_context, QVector4D(rgbColor.redF(), rgbColor.greenF(), rgbColor.blueF(), rgbColor.alphaF()), font, glyphFormat);
76 } else if (m_style == QQuickText::Outline) {
77 QSGOutlinedTextMaterial *material = new QSGOutlinedTextMaterial(m_context, font);
78 material->setStyleColor(m_styleColor);
79 m_material = material;
80 margins = QMargins(1, 1, 1, 1);
81 } else {
82 QSGStyledTextMaterial *material = new QSGStyledTextMaterial(m_context, font);
83 if (m_style == QQuickText::Sunken) {
84 material->setStyleShift(QVector2D(0, -1));
85 margins.setTop(1);
86 } else if (m_style == QQuickText::Raised) {
87 material->setStyleShift(QVector2D(0, 1));
88 margins.setBottom(1);
89 }
90 material->setStyleColor(m_styleColor);
91 m_material = material;
92 }
93
94 QSGTextMaskMaterial *textMaskMaterial = static_cast<QSGTextMaskMaterial *>(m_material);
95 textMaskMaterial->setColor(m_color);
96
97 QRectF boundingRect;
98 textMaskMaterial->populate(position: m_position, glyphIndexes: m_glyphs.glyphIndexes(), glyphPositions: m_glyphs.positions(), geometry: geometry(),
99 boundingRect: &boundingRect, baseLine: &m_baseLine, margins);
100 setBoundingRect(boundingRect);
101
102 setMaterial(m_material);
103 markDirty(bits: DirtyGeometry);
104}
105
106void QSGDefaultGlyphNode::preprocess()
107{
108 qDeleteAll(c: m_nodesToDelete);
109 m_nodesToDelete.clear();
110
111 if (m_dirtyGeometry)
112 updateGeometry();
113}
114
115void QSGDefaultGlyphNode::updateGeometry()
116{
117 // Remove previously created sub glyph nodes
118 // We assume all the children are sub glyph nodes
119 QSGNode *subnode = firstChild();
120 while (subnode) {
121 // We can't delete the node now as it might be in the preprocess list
122 // It will be deleted in the next preprocess
123 m_nodesToDelete.append(t: subnode);
124 subnode = subnode->nextSibling();
125 }
126 removeAllChildNodes();
127
128 GlyphInfo glyphInfo;
129
130 const QVector<quint32> indexes = m_glyphs.glyphIndexes();
131 const QVector<QPointF> positions = m_glyphs.positions();
132
133 const int maxGlyphs = (USHRT_MAX + 1) / 4; // 16384
134 const int maxVertices = maxGlyphs * 4; // 65536
135 const int maxIndexes = maxGlyphs * 6; // 98304
136
137 for (int i = 0; i < indexes.size(); ++i) {
138 const int glyphIndex = indexes.at(i);
139 const QPointF position = positions.at(i);
140
141 // As we use UNSIGNED_SHORT indexing in the geometry, we overload the
142 // "glyphsInOtherNodes" concept as overflow for if there are more than
143 // 65536 (16384 * 4) vertices to render which would otherwise exceed
144 // the maximum index size. This will cause sub-nodes to be recursively
145 // created to handle any number of glyphs.
146 if (i >= maxGlyphs) {
147 glyphInfo.indexes.append(t: glyphIndex);
148 glyphInfo.positions.append(t: position);
149 continue;
150 }
151 }
152
153 if (!glyphInfo.indexes.isEmpty()) {
154 QGlyphRun subNodeGlyphRun(m_glyphs);
155 subNodeGlyphRun.setGlyphIndexes(glyphInfo.indexes);
156 subNodeGlyphRun.setPositions(glyphInfo.positions);
157
158 QSGDefaultGlyphNode *subNode = new QSGDefaultGlyphNode(m_context);
159 subNode->setGlyphNodeType(SubGlyphNode);
160 subNode->setColor(m_color);
161 subNode->setStyle(m_style);
162 subNode->setStyleColor(m_styleColor);
163 subNode->setGlyphs(position: m_position, glyphs: subNodeGlyphRun);
164 subNode->update();
165 subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered
166 appendChildNode(node: subNode);
167
168 QSGGeometry *g = geometry();
169
170 QSGGeometry::TexturedPoint2D *vertexData = g->vertexDataAsTexturedPoint2D();
171 quint16 *indexData = g->indexDataAsUShort();
172
173 QVector<QSGGeometry::TexturedPoint2D> tempVertexData(maxVertices);
174 QVector<quint16> tempIndexData(maxIndexes);
175
176 for (int i = 0; i < maxGlyphs; i++) {
177 tempVertexData[i * 4 + 0] = vertexData[i * 4 + 0];
178 tempVertexData[i * 4 + 1] = vertexData[i * 4 + 1];
179 tempVertexData[i * 4 + 2] = vertexData[i * 4 + 2];
180 tempVertexData[i * 4 + 3] = vertexData[i * 4 + 3];
181
182 tempIndexData[i * 6 + 0] = indexData[i * 6 + 0];
183 tempIndexData[i * 6 + 1] = indexData[i * 6 + 1];
184 tempIndexData[i * 6 + 2] = indexData[i * 6 + 2];
185 tempIndexData[i * 6 + 3] = indexData[i * 6 + 3];
186 tempIndexData[i * 6 + 4] = indexData[i * 6 + 4];
187 tempIndexData[i * 6 + 5] = indexData[i * 6 + 5];
188 }
189
190 g->allocate(vertexCount: maxVertices, indexCount: maxIndexes);
191 vertexData = g->vertexDataAsTexturedPoint2D();
192 indexData = g->indexDataAsUShort();
193
194 for (int i = 0; i < maxGlyphs; i++) {
195 vertexData[i * 4 + 0] = tempVertexData[i * 4 + 0];
196 vertexData[i * 4 + 1] = tempVertexData[i * 4 + 1];
197 vertexData[i * 4 + 2] = tempVertexData[i * 4 + 2];
198 vertexData[i * 4 + 3] = tempVertexData[i * 4 + 3];
199
200 indexData[i * 6 + 0] = tempIndexData[i * 6 + 0];
201 indexData[i * 6 + 1] = tempIndexData[i * 6 + 1];
202 indexData[i * 6 + 2] = tempIndexData[i * 6 + 2];
203 indexData[i * 6 + 3] = tempIndexData[i * 6 + 3];
204 indexData[i * 6 + 4] = tempIndexData[i * 6 + 4];
205 indexData[i * 6 + 5] = tempIndexData[i * 6 + 5];
206 }
207 }
208
209 m_dirtyGeometry = false;
210}
211
212QT_END_NAMESPACE
213

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/quick/scenegraph/qsgdefaultglyphnode.cpp