Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qsgdistancefieldglyphnode.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
6#include <QtQuick/private/qsgcontext_p.h>
7
9
10Q_LOGGING_CATEGORY(lcSgText, "qt.scenegraph.text")
11
12qint64 QSGDistanceFieldGlyphNode::m_totalAllocation = 0;
13
15 : m_glyphNodeType(RootGlyphNode)
16 , m_context(context)
17 , m_material(nullptr)
18 , m_glyph_cache(nullptr)
19 , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
20 , m_style(QQuickText::Normal)
21 , m_antialiasingMode(GrayAntialiasing)
22 , m_texture(nullptr)
23 , m_renderTypeQuality(-1)
24 , m_dirtyGeometry(false)
25 , m_dirtyMaterial(false)
26{
27 m_geometry.setDrawingMode(QSGGeometry::DrawTriangles);
28 setGeometry(&m_geometry);
29#ifdef QSG_RUNTIME_DESCRIPTION
31#endif
32}
33
35{
36 delete m_material;
37
38 if (m_glyphNodeType == SubGlyphNode)
39 return;
40
41 if (m_glyph_cache) {
42 m_glyph_cache->release(m_glyphs.glyphIndexes());
43 m_glyph_cache->unregisterGlyphNode(this);
44 m_glyph_cache->unregisterOwnerElement(ownerElement());
45 }
46}
47
49{
50 m_color = color;
51 if (m_material != nullptr) {
52 m_material->setColor(color);
54 } else {
55 m_dirtyMaterial = true;
56 }
57}
58
60{
61 if (renderTypeQuality == m_renderTypeQuality)
62 return;
63
64 m_renderTypeQuality = renderTypeQuality;
65}
66
68{
69 if (mode == m_antialiasingMode)
70 return;
71 m_antialiasingMode = mode;
72 m_dirtyMaterial = true;
73}
74
76{
77 QRawFont font = glyphs.rawFont();
78 m_originalPosition = position;
79 m_position = QPointF(position.x(), position.y() - font.ascent());
80 m_glyphs = glyphs;
81
82 m_dirtyGeometry = true;
83 m_dirtyMaterial = true;
85
86 QSGDistanceFieldGlyphCache *oldCache = m_glyph_cache;
87 m_glyph_cache = m_context->distanceFieldGlyphCache(m_glyphs.rawFont(), m_renderTypeQuality);
88
89 if (m_glyphNodeType == SubGlyphNode)
90 return;
91
92 if (m_glyph_cache != oldCache) {
93 Q_ASSERT(ownerElement() != nullptr);
94 if (oldCache) {
95 oldCache->unregisterGlyphNode(this);
97 }
98 m_glyph_cache->registerGlyphNode(this);
99 m_glyph_cache->registerOwnerElement(ownerElement());
100 }
101 m_glyph_cache->populate(glyphs.glyphIndexes());
102
103 const QVector<quint32> glyphIndexes = m_glyphs.glyphIndexes();
104 for (int i = 0; i < glyphIndexes.size(); ++i)
105 m_allGlyphIndexesLookup.insert(glyphIndexes.at(i));
106 qCDebug(lcSgText, "inserting %" PRIdQSIZETYPE " glyphs, %" PRIdQSIZETYPE " unique",
107 glyphIndexes.size(),
108 m_allGlyphIndexesLookup.size());
109#ifdef QSG_RUNTIME_DESCRIPTION
110 qsgnode_set_description(this, QString::number(glyphs.glyphIndexes().count()) + QStringLiteral(" DF glyphs: ") +
111 m_glyphs.rawFont().familyName() + QStringLiteral(" ") + QString::number(m_glyphs.rawFont().pixelSize()));
112#endif
113}
114
116{
117 if (m_style == style)
118 return;
119 m_style = style;
120 m_dirtyMaterial = true;
121}
122
124{
125 if (m_styleColor == color)
126 return;
127 m_styleColor = color;
128 m_dirtyMaterial = true;
129}
130
132{
133 if (m_dirtyMaterial)
134 updateMaterial();
135}
136
138{
139 if (m_dirtyGeometry)
141
142 setFlag(UsePreprocess, false);
143}
144
146{
147 if (m_dirtyGeometry)
148 return;
149
150 for (int i = 0; i < glyphs.size(); ++i) {
151 if (m_allGlyphIndexesLookup.contains(glyphs.at(i))) {
152 m_dirtyGeometry = true;
154 return;
155 }
156 }
157}
158
160{
161 Q_ASSERT(m_glyph_cache);
162
163 // Remove previously created sub glyph nodes
164 // We assume all the children are sub glyph nodes
165 QSGNode *subnode = firstChild();
166 QSGNode *nextNode = nullptr;
167 while (subnode) {
168 nextNode = subnode->nextSibling();
169 delete subnode;
170 subnode = nextNode;
171 }
172
174
176 m_glyphsInOtherTextures.clear();
177
178 const QVector<quint32> indexes = m_glyphs.glyphIndexes();
179 const QVector<QPointF> positions = m_glyphs.positions();
180 qreal fontPixelSize = m_glyphs.rawFont().pixelSize();
181
182 // The template parameters here are assuming that most strings are short, 64
183 // characters or less.
186 const qsizetype maxIndexCount = (std::numeric_limits<quint16>::max() - 1) / 4; // 16383 (see below: 0xFFFF is not allowed)
187 const qsizetype maxVertexCount = maxIndexCount * 4; // 65532
188 const auto likelyGlyphCount = qMin(indexes.size(), maxIndexCount);
189 vp.reserve(likelyGlyphCount * 4);
190 ip.reserve(likelyGlyphCount * 6);
191
192 qreal maxTexMargin = m_glyph_cache->distanceFieldRadius();
193 qreal fontScale = m_glyph_cache->fontScale(fontPixelSize);
194 qreal margin = 2;
195 qreal texMargin = margin / fontScale;
196 if (texMargin > maxTexMargin) {
197 texMargin = maxTexMargin;
198 margin = maxTexMargin * fontScale;
199 }
200
201 for (int i = 0; i < indexes.size(); ++i) {
202 const int glyphIndex = indexes.at(i);
203 QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
204
205 if (c.isNull())
206 continue;
207
208 const QPointF position = positions.at(i);
209
210 const QSGDistanceFieldGlyphCache::Texture *texture = m_glyph_cache->glyphTexture(glyphIndex);
211 if (texture->texture && !m_texture)
212 m_texture = texture;
213
214 // As we use UNSIGNED_SHORT indexing in the geometry, we overload the
215 // "glyphsInOtherTextures" concept as overflow for if there are more
216 // than 65532 vertices to render, which would otherwise exceed the
217 // maximum index size. (leave 0xFFFF unused in order not to clash with
218 // primitive restart) This will cause sub-nodes to be
219 // created to handle any number of glyphs. But only the RootGlyphNode
220 // needs to do this classification; from the perspective of a SubGlyphNode,
221 // it's already done, and m_glyphs contains only pointers to ranges of
222 // indices and positions that the RootGlyphNode is storing.
223 if (m_texture != texture || vp.size() >= maxVertexCount) {
224 if (m_glyphNodeType == RootGlyphNode && texture->texture) {
225 GlyphInfo &glyphInfo = m_glyphsInOtherTextures[texture];
226 glyphInfo.indexes.append(glyphIndex);
227 glyphInfo.positions.append(position);
228 } else if (vp.size() >= maxVertexCount && m_glyphNodeType == SubGlyphNode) {
229 break; // out of this loop over indices, because we won't add any more vertices
230 }
231 continue;
232 }
233
234 QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex, fontPixelSize);
235
236 if (!metrics.isNull() && !c.isNull()) {
237 metrics.width += margin * 2;
238 metrics.height += margin * 2;
239 metrics.baselineX -= margin;
240 metrics.baselineY += margin;
241 c.xMargin -= texMargin;
242 c.yMargin -= texMargin;
243 c.width += texMargin * 2;
244 c.height += texMargin * 2;
245 }
246
247 qreal x = position.x() + metrics.baselineX + m_position.x();
248 qreal y = position.y() - metrics.baselineY + m_position.y();
249
250 m_boundingRect |= QRectF(x, y, metrics.width, metrics.height);
251
252 float cx1 = x;
253 float cx2 = x + metrics.width;
254 float cy1 = y;
255 float cy2 = y + metrics.height;
256
257 float tx1 = c.x + c.xMargin;
258 float tx2 = tx1 + c.width;
259 float ty1 = c.y + c.yMargin;
260 float ty2 = ty1 + c.height;
261
262 if (m_baseLine.isNull())
263 m_baseLine = position;
264
265 int o = vp.size();
266
268 v1.set(cx1, cy1, tx1, ty1);
270 v2.set(cx2, cy1, tx2, ty1);
272 v3.set(cx1, cy2, tx1, ty2);
274 v4.set(cx2, cy2, tx2, ty2);
275 vp.append(v1);
276 vp.append(v2);
277 vp.append(v3);
278 vp.append(v4);
279
280 ip.append(o + 0);
281 ip.append(o + 2);
282 ip.append(o + 3);
283 ip.append(o + 3);
284 ip.append(o + 1);
285 ip.append(o + 0);
286 }
287
288 if (m_glyphNodeType == SubGlyphNode) {
289 Q_ASSERT(m_glyphsInOtherTextures.isEmpty());
290 } else {
291 if (!m_glyphsInOtherTextures.isEmpty())
292 qCDebug(lcSgText, "%" PRIdQSIZETYPE " 'other' textures", m_glyphsInOtherTextures.size());
294 while (ite != m_glyphsInOtherTextures.constEnd()) {
295 QGlyphRun subNodeGlyphRun(m_glyphs);
296 for (int i = 0; i < ite->indexes.size(); i += maxIndexCount) {
297 int len = qMin(maxIndexCount, ite->indexes.size() - i);
298 subNodeGlyphRun.setRawData(ite->indexes.constData() + i, ite->positions.constData() + i, len);
299 qCDebug(lcSgText) << "subNodeGlyphRun has" << len << "positions:"
300 << *(ite->positions.constData() + i) << "->" << *(ite->positions.constData() + i + len - 1);
301
303 subNode->setGlyphNodeType(SubGlyphNode);
304 subNode->setColor(m_color);
305 subNode->setStyle(m_style);
306 subNode->setStyleColor(m_styleColor);
307 subNode->setPreferredAntialiasingMode(m_antialiasingMode);
308 subNode->setGlyphs(m_originalPosition, subNodeGlyphRun);
309 subNode->update();
310 subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered
311 appendChildNode(subNode);
312 }
313 ++ite;
314 }
315 }
316
317 m_totalAllocation += vp.size() * sizeof(QSGGeometry::TexturedPoint2D) + ip.size() * sizeof(quint16);
318 qCDebug(lcSgText) << "allocating for" << vp.size() << "vtx (reserved" << likelyGlyphCount * 4 << "):" << vp.size() * sizeof(QSGGeometry::TexturedPoint2D)
319 << "bytes;" << ip.size() << "idx:" << ip.size() * sizeof(quint16) << "bytes; total bytes so far" << m_totalAllocation;
320 g->allocate(vp.size(), ip.size());
321 memcpy(g->vertexDataAsTexturedPoint2D(), vp.constData(), vp.size() * sizeof(QSGGeometry::TexturedPoint2D));
322 memcpy(g->indexDataAsUShort(), ip.constData(), ip.size() * sizeof(quint16));
323
324 setBoundingRect(m_boundingRect);
326 m_dirtyGeometry = false;
327
328 m_material->setTexture(m_texture);
329}
330
331void QSGDistanceFieldGlyphNode::updateMaterial()
332{
333 delete m_material;
334
335 if (m_style == QQuickText::Normal) {
336 switch (m_antialiasingMode) {
339 break;
342 break;
343 case GrayAntialiasing:
344 default:
345 m_material = new QSGDistanceFieldTextMaterial;
346 break;
347 }
348 } else {
350 if (m_style == QQuickText::Outline) {
352 } else {
354 if (m_style == QQuickText::Raised)
355 sMaterial->setShift(QPointF(0.0, 1.0));
356 else
357 sMaterial->setShift(QPointF(0.0, -1.0));
358 material = sMaterial;
359 }
360 material->setStyleColor(m_styleColor);
361 m_material = material;
362 }
363
364 m_material->setGlyphCache(m_glyph_cache);
365 if (m_glyph_cache)
366 m_material->setFontScale(m_glyph_cache->fontScale(m_glyphs.rawFont().pixelSize()));
367 m_material->setColor(m_color);
368 setMaterial(m_material);
369 m_dirtyMaterial = false;
370}
371
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
The QGlyphRun class provides direct access to the internal glyphs in a font.
Definition qglyphrun.h:20
void setRawData(const quint32 *glyphIndexArray, const QPointF *glyphPositionArray, int size)
Sets the glyph indexes and positions of this QGlyphRun to use the first size elements in the arrays g...
QList< quint32 > glyphIndexes() const
Returns the glyph indexes for this QGlyphRun object.
QRawFont rawFont() const
Returns the font selected for this QGlyphRun object.
QList< QPointF > positions() const
Returns the position of the edge of the baseline for each glyph in this set of glyph indexes.
\inmodule QtCore
Definition qhash.h:1135
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:925
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1209
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1205
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:949
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:926
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
qsizetype count() const noexcept
Definition qlist.h:387
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
bool isNull() const noexcept
Returns true if both the x and y coordinates are set to 0.0 (ignoring the sign); otherwise returns fa...
Definition qpoint.h:328
The QRawFont class provides access to a single physical instance of a font.
Definition qrawfont.h:24
QString familyName() const
Returns the family name of this QRawFont.
Definition qrawfont.cpp:441
qreal pixelSize() const
Returns the pixel size set for this QRawFont.
Definition qrawfont.cpp:402
\inmodule QtCore\reentrant
Definition qrect.h:483
const QSGGeometry * geometry() const
Returns this node's geometry.
Definition qsgnode.h:160
virtual void registerOwnerElement(QQuickItem *ownerElement)
void unregisterGlyphNode(QSGDistanceFieldGlyphConsumer *node)
Metrics glyphMetrics(glyph_t glyph, qreal pixelSize)
qreal fontScale(qreal pixelSize) const
void populate(const QVector< glyph_t > &glyphs)
const Texture * glyphTexture(glyph_t glyph)
void release(const QVector< glyph_t > &glyphs)
TexCoord glyphTexCoord(glyph_t glyph)
virtual void unregisterOwnerElement(QQuickItem *ownerElement)
void registerGlyphNode(QSGDistanceFieldGlyphConsumer *node)
void setStyleColor(const QColor &color) override
void setStyle(QQuickText::TextStyle style) override
void setRenderTypeQuality(int renderTypeQuality) override
void setColor(const QColor &color) override
void setPreferredAntialiasingMode(AntialiasingMode mode) override
void preprocess() override
Override this function to do processing on the node before it is rendered.
void invalidateGlyphs(const QVector< quint32 > &glyphs) override
void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) override
virtual void setColor(const QColor &color)
void setGlyphCache(QSGDistanceFieldGlyphCache *a)
void setTexture(const QSGDistanceFieldGlyphCache::Texture *tex)
QSGMaterial * material() const
Returns the material of the QSGGeometryNode.
Definition qsgnode.h:197
void setMaterial(QSGMaterial *material)
Sets the material of this geometry node to material.
Definition qsgnode.cpp:925
The QSGGeometry class provides low-level storage for graphics primitives in the \l{Qt Quick Scene Gra...
Definition qsggeometry.h:15
QQuickItem * ownerElement() const
virtual void setBoundingRect(const QRectF &bounds)
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
QSGNode * nextSibling() const
Returns the node after this in the parent's list of children.
Definition qsgnode.h:107
@ DirtyMaterial
Definition qsgnode.h:75
@ DirtyGeometry
Definition qsgnode.h:74
@ UsePreprocess
Definition qsgnode.h:52
void appendChildNode(QSGNode *node)
Appends node to this node's list of children.
Definition qsgnode.cpp:396
QSGNode * firstChild() const
Returns the first child of this node.
Definition qsgnode.h:105
void markDirty(DirtyState bits)
Notifies all connected renderers that the node has dirty bits.
Definition qsgnode.cpp:622
void setFlag(Flag, bool=true)
Sets the flag f on this node if enabled is true; otherwise clears the flag.
Definition qsgnode.cpp:584
virtual QSGDistanceFieldGlyphCache * distanceFieldGlyphCache(const QRawFont &font, int renderTypeQuality)
Factory function for scene graph backends of the distance-field glyph cache.
qsizetype size() const
Definition qset.h:50
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
constexpr size_type size() const noexcept
void append(const T &t)
const T * constData() const
void reserve(qsizetype sz)
Combined button and popup list for selecting options.
static void * context
static const QCssKnownValue positions[NumKnownPositionModes - 1]
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLint GLfloat GLfloat GLfloat v2
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLint GLfloat GLfloat v1
GLenum GLuint texture
GLboolean GLboolean g
GLint GLfloat GLfloat GLfloat GLfloat v3
GLint y
const GLubyte * c
GLenum GLsizei len
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
void qsgnode_set_description(QSGNode *node, const QString &description)
Definition qsgnode.cpp:639
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define v1
unsigned short quint16
Definition qtypes.h:43
#define PRIdQSIZETYPE
Definition qtypes.h:77
ptrdiff_t qsizetype
Definition qtypes.h:70
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
The QSGGeometry::TexturedPoint2D struct is a convenience struct for accessing 2D Points with texture ...
Definition qsggeometry.h:85
void set(float nx, float ny, float ntx, float nty)
Sets the position of the vertex to x and y and the texture coordinate to tx and ty.
Definition qsggeometry.h:88