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
qsgcurveglyphnode.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 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
9
10#include <private/qsgcurveabstractnode_p.h>
11#include <private/qsgcontext_p.h>
12#include <private/qsgtexturematerial_p.h>
13
14#include <private/qrawfont_p.h>
15#include <QtGui/qcolor.h>
16
17QT_BEGIN_NAMESPACE
18
19QSGCurveGlyphNode::QSGCurveGlyphNode(QSGRenderContext *context)
20 : QSGGlyphNode(QSGTextNode::CurveRendering)
21 , m_context(context)
22 , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
23 , m_dirtyGeometry(false)
24{
25 setFlag(UsePreprocess);
26 setFlag(OwnsMaterial);
27
28 // #### To avoid asserts: we should probably merge this with QSGCurveFillNode
29 setGeometry(&m_geometry);
30 setMaterial(new QSGTextureMaterial);
31}
32
33QSGCurveGlyphNode::~QSGCurveGlyphNode()
34{
35}
36
37void QSGCurveGlyphNode::cleanup()
38{
39 delete m_glyphNode;
40 m_glyphNode = nullptr;
41
42 delete m_styleNode;
43 m_styleNode = nullptr;
44}
45
46void QSGCurveGlyphNode::recycle()
47{
48 Q_ASSERT(m_geometry.vertexCount() == 0);
49 Q_ASSERT(m_geometry.indexCount() == 0);
50
51 QSGGlyphNode::recycle();
52 m_color = Qt::black;
53 m_dirtyGeometry = true;
54 m_fontSize = 0.0f;
55 m_glyphs = QGlyphRun{};
56 m_style = QQuickText::Normal;
57 m_styleColor = QColor{};
58 m_baseLine = QPointF{};
59 m_position = QPointF{};
60
61 cleanup();
62}
63
64void QSGCurveGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
65{
66 Q_UNUSED(mode);
67}
68
69void QSGCurveGlyphNode::setColor(const QColor &color)
70{
71 m_color = color;
72 if (m_glyphNode != nullptr)
73 m_glyphNode->setColor(color);
74}
75
76void QSGCurveGlyphNode::setStyleColor(const QColor &styleColor)
77{
78 m_styleColor = styleColor;
79 if (m_styleNode != nullptr)
80 m_styleNode->setColor(styleColor);
81}
82
83void QSGCurveGlyphNode::setStyle(QQuickText::TextStyle style)
84{
85 if (m_style != style) {
86 m_style = style;
87 m_dirtyGeometry = true;
88 update();
89 }
90}
91
92void QSGCurveGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
93{
94 m_glyphs = glyphs;
95
96 QRawFont font = glyphs.rawFont();
97 m_fontSize = font.pixelSize();
98 m_position = QPointF(position.x(), position.y() - font.ascent());
99
100
101 m_dirtyGeometry = true;
102
103#ifdef QSG_RUNTIME_DESCRIPTION
104 qsgnode_set_description(this, QString::number(glyphs.glyphIndexes().count())
105 + QStringLiteral(" curve glyphs: ")
106 + m_glyphs.rawFont().familyName()
107 + QStringLiteral(" ")
108 + QString::number(m_glyphs.rawFont().pixelSize()));
109#endif
110}
111
112void QSGCurveGlyphNode::update()
113{
114 markDirty(DirtyGeometry);
115}
116
117void QSGCurveGlyphNode::preprocess()
118{
119 if (m_dirtyGeometry)
120 updateGeometry();
121}
122
123void QSGCurveGlyphNode::updateGeometry()
124{
125 cleanup();
126
127 QSGCurveGlyphAtlas *curveGlyphAtlas = m_context->curveGlyphAtlas(m_glyphs.rawFont());
128 curveGlyphAtlas->populate(m_glyphs.glyphIndexes());
129
130 m_glyphNode = new QSGCurveFillNode;
131 m_glyphNode->setColor(m_color);
132
133 QPointF offset;
134
135 float fontScale = float(m_fontSize / curveGlyphAtlas->fontSize());
136 QSGCurveFillNode *raisedSunkenStyleNode = nullptr;
137 QSGCurveStrokeNode *outlineNode = nullptr;
138 if (m_style == QQuickText::Raised || m_style == QQuickText::Sunken) {
139 raisedSunkenStyleNode = new QSGCurveFillNode;
140 raisedSunkenStyleNode ->setColor(m_styleColor);
141
142 offset = m_style == QQuickText::Raised ? QPointF(0.0f, 1.0f) : QPointF(0.0f, -1.0f);
143 m_styleNode = raisedSunkenStyleNode;
144 } else if (m_style == QQuickText::Outline) {
145 outlineNode = new QSGCurveStrokeNode;
146 outlineNode->setColor(m_styleColor);
147 outlineNode->setStrokeWidth(2 / fontScale);
148 outlineNode->setLocalScale(fontScale);
149
150 m_styleNode = outlineNode;
151 }
152
153 const QList<quint32> indexes = m_glyphs.glyphIndexes();
154 const QList<QPointF> positions = m_glyphs.positions();
155 for (qsizetype i = 0; i < indexes.size(); ++i) {
156 if (i == 0)
157 m_baseLine = positions.at(i);
158 curveGlyphAtlas->addGlyph(m_glyphNode,
159 indexes.at(i),
160 m_position + positions.at(i),
161 m_fontSize);
162 if (raisedSunkenStyleNode != nullptr) {
163 curveGlyphAtlas->addGlyph(raisedSunkenStyleNode,
164 indexes.at(i),
165 m_position + positions.at(i) + offset,
166 m_fontSize);
167 }
168 if (outlineNode != nullptr) {
169 // Since the stroke node will scale everything by fontScale internally (the
170 // shader does not support pre-transforming the vertices), we have to also first
171 // do the inverse scale on the glyph position to get the correct position.
172 curveGlyphAtlas->addStroke(outlineNode,
173 indexes.at(i),
174 (m_position + positions.at(i)) / fontScale);
175 }
176 }
177
178 if (m_styleNode != nullptr) {
179 m_styleNode->cookGeometry();
180 appendChildNode(m_styleNode);
181 }
182
183 m_glyphNode->cookGeometry();
184 appendChildNode(m_glyphNode);
185
186 m_dirtyGeometry = false;
187}
188
189QT_END_NAMESPACE