Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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 }
45}
46
48{
49 m_color = color;
50 if (m_material != nullptr) {
51 m_material->setColor(color);
53 } else {
54 m_dirtyMaterial = true;
55 }
56}
57
59{
60 if (renderTypeQuality == m_renderTypeQuality)
61 return;
62
63 m_renderTypeQuality = renderTypeQuality;
64}
65
67{
68 if (mode == m_antialiasingMode)
69 return;
70 m_antialiasingMode = mode;
71 m_dirtyMaterial = true;
72}
73
75{
76 QRawFont font = glyphs.rawFont();
77 m_originalPosition = position;
78 m_position = QPointF(position.x(), position.y() - font.ascent());
79 m_glyphs = glyphs;
80
81 m_dirtyGeometry = true;
82 m_dirtyMaterial = true;
84
85 QSGDistanceFieldGlyphCache *oldCache = m_glyph_cache;
86 m_glyph_cache = m_context->distanceFieldGlyphCache(m_glyphs.rawFont(), m_renderTypeQuality);
87
88 if (m_glyphNodeType == SubGlyphNode)
89 return;
90
91 if (m_glyph_cache != oldCache) {
92 if (oldCache) {
93 oldCache->unregisterGlyphNode(this);
94 }
95 m_glyph_cache->registerGlyphNode(this);
96 }
97 if (m_glyph_cache)
98 m_glyph_cache->populate(glyphs.glyphIndexes());
99
100 const QVector<quint32> glyphIndexes = m_glyphs.glyphIndexes();
101 for (int i = 0; i < glyphIndexes.size(); ++i)
102 m_allGlyphIndexesLookup.insert(glyphIndexes.at(i));
103 qCDebug(lcSgText, "inserting %" PRIdQSIZETYPE " glyphs, %" PRIdQSIZETYPE " unique",
104 glyphIndexes.size(),
105 m_allGlyphIndexesLookup.size());
106#ifdef QSG_RUNTIME_DESCRIPTION
107 qsgnode_set_description(this, QString::number(glyphs.glyphIndexes().count()) + QStringLiteral(" DF glyphs: ") +
108 m_glyphs.rawFont().familyName() + QStringLiteral(" ") + QString::number(m_glyphs.rawFont().pixelSize()));
109#endif
110}
111
113{
114 if (m_style == style)
115 return;
116 m_style = style;
117 m_dirtyMaterial = true;
118}
119
121{
122 if (m_styleColor == color)
123 return;
124 m_styleColor = color;
125 m_dirtyMaterial = true;
126}
127
129{
130 if (m_dirtyMaterial)
131 updateMaterial();
132}
133
135{
136 if (m_dirtyGeometry)
138
139 setFlag(UsePreprocess, false);
140}
141
142void QSGDistanceFieldGlyphNode::invalidateGlyphs(const QVector<quint32> &glyphs)
143{
144 if (m_dirtyGeometry)
145 return;
146
147 for (int i = 0; i < glyphs.size(); ++i) {
148 if (m_allGlyphIndexesLookup.contains(glyphs.at(i))) {
149 m_dirtyGeometry = true;
151 return;
152 }
153 }
154}
155
157{
158 if (!m_glyph_cache)
159 return;
160
161 // Remove previously created sub glyph nodes
162 // We assume all the children are sub glyph nodes
163 QSGNode *subnode = firstChild();
164 QSGNode *nextNode = nullptr;
165 while (subnode) {
166 nextNode = subnode->nextSibling();
167 delete subnode;
168 subnode = nextNode;
169 }
170
172
174 m_glyphsInOtherTextures.clear();
175
176 const QVector<quint32> indexes = m_glyphs.glyphIndexes();
177 const QVector<QPointF> positions = m_glyphs.positions();
178 qreal fontPixelSize = m_glyphs.rawFont().pixelSize();
179
180 // The template parameters here are assuming that most strings are short, 64
181 // characters or less.
182 QVarLengthArray<QSGGeometry::TexturedPoint2D, 256> vp;
183 QVarLengthArray<ushort, 384> ip;
184 const qsizetype maxIndexCount = (std::numeric_limits<quint16>::max() - 1) / 4; // 16383 (see below: 0xFFFF is not allowed)
185 const qsizetype maxVertexCount = maxIndexCount * 4; // 65532
186 const auto likelyGlyphCount = qMin(indexes.size(), maxIndexCount);
187 vp.reserve(likelyGlyphCount * 4);
188 ip.reserve(likelyGlyphCount * 6);
189
190 qreal maxTexMargin = m_glyph_cache->distanceFieldRadius();
191 qreal fontScale = m_glyph_cache->fontScale(fontPixelSize);
192 qreal margin = 2;
193 qreal texMargin = margin / fontScale;
194 if (texMargin > maxTexMargin) {
195 texMargin = maxTexMargin;
196 margin = maxTexMargin * fontScale;
197 }
198
199 for (int i = 0; i < indexes.size(); ++i) {
200 const int glyphIndex = indexes.at(i);
201 QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
202
203 if (c.isNull())
204 continue;
205
206 const QPointF position = positions.at(i);
207
208 const QSGDistanceFieldGlyphCache::Texture *texture = m_glyph_cache->glyphTexture(glyphIndex);
209 if (texture->texture && !m_texture)
210 m_texture = texture;
211
212 // As we use UNSIGNED_SHORT indexing in the geometry, we overload the
213 // "glyphsInOtherTextures" concept as overflow for if there are more
214 // than 65532 vertices to render, which would otherwise exceed the
215 // maximum index size. (leave 0xFFFF unused in order not to clash with
216 // primitive restart) This will cause sub-nodes to be
217 // created to handle any number of glyphs. But only the RootGlyphNode
218 // needs to do this classification; from the perspective of a SubGlyphNode,
219 // it's already done, and m_glyphs contains only pointers to ranges of
220 // indices and positions that the RootGlyphNode is storing.
221 if (m_texture != texture || vp.size() >= maxVertexCount) {
222 if (m_glyphNodeType == RootGlyphNode && texture->texture) {
223 GlyphInfo &glyphInfo = m_glyphsInOtherTextures[texture];
224 glyphInfo.indexes.append(glyphIndex);
225 glyphInfo.positions.append(position);
226 } else if (vp.size() >= maxVertexCount && m_glyphNodeType == SubGlyphNode) {
227 break; // out of this loop over indices, because we won't add any more vertices
228 }
229 continue;
230 }
231
232 QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex, fontPixelSize);
233
234 if (!metrics.isNull() && !c.isNull()) {
235 metrics.width += margin * 2;
236 metrics.height += margin * 2;
237 metrics.baselineX -= margin;
238 metrics.baselineY += margin;
239 c.xMargin -= texMargin;
240 c.yMargin -= texMargin;
241 c.width += texMargin * 2;
242 c.height += texMargin * 2;
243 }
244
245 qreal x = position.x() + metrics.baselineX + m_position.x();
246 qreal y = position.y() - metrics.baselineY + m_position.y();
247
248 m_boundingRect |= QRectF(x, y, metrics.width, metrics.height);
249
250 float cx1 = x;
251 float cx2 = x + metrics.width;
252 float cy1 = y;
253 float cy2 = y + metrics.height;
254
255 float tx1 = c.x + c.xMargin;
256 float tx2 = tx1 + c.width;
257 float ty1 = c.y + c.yMargin;
258 float ty2 = ty1 + c.height;
259
260 if (m_baseLine.isNull())
261 m_baseLine = position;
262
263 int o = vp.size();
264
266 v1.set(cx1, cy1, tx1, ty1);
268 v2.set(cx2, cy1, tx2, ty1);
270 v3.set(cx1, cy2, tx1, ty2);
272 v4.set(cx2, cy2, tx2, ty2);
273 vp.append(v1);
274 vp.append(v2);
275 vp.append(v3);
276 vp.append(v4);
277
278 ip.append(o + 0);
279 ip.append(o + 2);
280 ip.append(o + 3);
281 ip.append(o + 3);
282 ip.append(o + 1);
283 ip.append(o + 0);
284 }
285
286 if (m_glyphNodeType == SubGlyphNode) {
287 Q_ASSERT(m_glyphsInOtherTextures.isEmpty());
288 } else {
289 if (!m_glyphsInOtherTextures.isEmpty())
290 qCDebug(lcSgText, "%" PRIdQSIZETYPE " 'other' textures", m_glyphsInOtherTextures.size());
292 while (ite != m_glyphsInOtherTextures.constEnd()) {
293 QGlyphRun subNodeGlyphRun(m_glyphs);
294 for (int i = 0; i < ite->indexes.size(); i += maxIndexCount) {
295 int len = qMin(maxIndexCount, ite->indexes.size() - i);
296 subNodeGlyphRun.setRawData(ite->indexes.constData() + i, ite->positions.constData() + i, len);
297 qCDebug(lcSgText) << "subNodeGlyphRun has" << len << "positions:"
298 << *(ite->positions.constData() + i) << "->" << *(ite->positions.constData() + i + len - 1);
299
301 subNode->setGlyphNodeType(SubGlyphNode);
302 subNode->setColor(m_color);
303 subNode->setStyle(m_style);
304 subNode->setStyleColor(m_styleColor);
305 subNode->setPreferredAntialiasingMode(m_antialiasingMode);
306 subNode->setGlyphs(m_originalPosition, subNodeGlyphRun);
307 subNode->update();
308 subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered
309 appendChildNode(subNode);
310 }
311 ++ite;
312 }
313 }
314
315 m_totalAllocation += vp.size() * sizeof(QSGGeometry::TexturedPoint2D) + ip.size() * sizeof(quint16);
316 qCDebug(lcSgText) << "allocating for" << vp.size() << "vtx (reserved" << likelyGlyphCount * 4 << "):" << vp.size() * sizeof(QSGGeometry::TexturedPoint2D)
317 << "bytes;" << ip.size() << "idx:" << ip.size() * sizeof(quint16) << "bytes; total bytes so far" << m_totalAllocation;
318 g->allocate(vp.size(), ip.size());
319 memcpy(g->vertexDataAsTexturedPoint2D(), vp.constData(), vp.size() * sizeof(QSGGeometry::TexturedPoint2D));
320 memcpy(g->indexDataAsUShort(), ip.constData(), ip.size() * sizeof(quint16));
321
322 setBoundingRect(m_boundingRect);
324 m_dirtyGeometry = false;
325
326 m_material->setTexture(m_texture);
327}
328
329void QSGDistanceFieldGlyphNode::updateMaterial()
330{
331 delete m_material;
332
333 if (m_style == QQuickText::Normal) {
334 switch (m_antialiasingMode) {
337 break;
340 break;
341 case GrayAntialiasing:
342 default:
343 m_material = new QSGDistanceFieldTextMaterial;
344 break;
345 }
346 } else {
348 if (m_style == QQuickText::Outline) {
350 } else {
352 if (m_style == QQuickText::Raised)
353 sMaterial->setShift(QPointF(0.0, 1.0));
354 else
355 sMaterial->setShift(QPointF(0.0, -1.0));
356 material = sMaterial;
357 }
358 material->setStyleColor(m_styleColor);
359 m_material = material;
360 }
361
362 m_material->setGlyphCache(m_glyph_cache);
363 if (m_glyph_cache)
364 m_material->setFontScale(m_glyph_cache->fontScale(m_glyphs.rawFont().pixelSize()));
365 m_material->setColor(m_color);
366 setMaterial(m_material);
367 m_dirtyMaterial = false;
368}
369
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
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:1145
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:927
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:1219
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:1215
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:951
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:928
qsizetype count() const noexcept
Definition qlist.h:398
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
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:338
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:484
const QSGGeometry * geometry() const
Returns this node's geometry.
Definition qsgnode.h:160
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)
void registerGlyphNode(QSGDistanceFieldGlyphConsumer *node)
QSGDistanceFieldGlyphNode(QSGRenderContext *context)
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:194
void setMaterial(QSGMaterial *material)
Sets the material of this geometry node to material.
Definition qsgnode.cpp:927
The QSGGeometry class provides low-level storage for graphics primitives in the \l{Qt Quick Scene Gra...
Definition qsggeometry.h:15
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:398
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:624
void setFlag(Flag, bool=true)
Sets the flag f on this node if enabled is true; otherwise clears the flag.
Definition qsgnode.cpp:586
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:8084
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
GLuint color
[2]
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:641
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
#define v1
unsigned short quint16
Definition qtypes.h:48
#define PRIdQSIZETYPE
Definition qtypes.h:172
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
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