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
qsgrhiinternaltextnode.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
6
7#include <private/qquadpath_p.h>
8#include <private/qsgcurvefillnode_p.h>
9#include <private/qsgcurvestrokenode_p.h>
10#include <private/qsgcurveprocessor_p.h>
11
12#include <QtCore/qmath.h>
13
15
16QSGRhiInternalTextNode::QSGRhiInternalTextNode(QSGRenderContext *renderContext)
17 : QSGInternalTextNode(renderContext)
18{
19}
20
21// Dash pattern arrays {dash, gap, ...} in units of pen width.
22static constexpr qreal dashPattern[] = { 4, 2 };
23static constexpr qreal dotPattern[] = { 1, 2 };
24static constexpr qreal dashDotPattern[] = { 4, 2, 1, 2 };
25static constexpr qreal dashDotDotPattern[] = { 4, 2, 1, 2, 1, 2 };
26
27// Returns the dash pattern for a given underline style.
28static QSpan<const qreal> dashPatternForStyle(QTextCharFormat::UnderlineStyle style)
29{
30 switch (style) {
31 case QTextCharFormat::DashUnderline:
32 return dashPattern;
33 case QTextCharFormat::DotLine:
34 return dotPattern;
35 case QTextCharFormat::DashDotLine:
36 return dashDotPattern;
37 case QTextCharFormat::DashDotDotLine:
38 return dashDotDotPattern;
39 default:
40 return {};
41 }
42}
43
44// Builds a QQuadPath of dashed line segments along y = cy, from x0 to x1.
45static QQuadPath buildDashedPath(qreal x0, qreal x1, qreal cy, QSpan<const qreal> pattern,
46 qreal penWidth)
47{
48 Q_ASSERT(!pattern.isEmpty());
49
50 QQuadPath path;
51 qreal x = x0;
52 int idx = 0;
53 bool drawing = true; // pattern starts with a dash (drawn segment)
54
55 while (x < x1) {
56 // Round segment length to nearest pixel to avoid uneven dot sizes
57 const qreal rawLen = pattern[idx % pattern.size()] * penWidth;
58 const qreal segLen = qMax(qreal(1), qreal(qRound(rawLen)));
59 const qreal segEnd = qMin(x + segLen, x1);
60
61 if (drawing && segEnd > x) {
62 path.moveTo(QVector2D(qRound(x), cy));
63 path.lineTo(QVector2D(qRound(segEnd), cy));
64 }
65
66 x += segLen;
67 drawing = !drawing;
68 ++idx;
69 }
70
71 return path;
72}
73
74static constexpr qreal goldenRatio = 1.6180339887498949;
75
76// Builds a QQuadPath of a wavy line along y = cy, from x0 to x1.
77// Uses quadratic Bezier curves, adapted from generateWavyPixmap() in QPainter.
78static QQuadPath buildWavyPath(qreal x0, qreal x1, qreal cy, qreal penWidth)
79{
80 const qreal radius = qMax(qreal(1), penWidth);
81 const qreal halfPeriod = qMax(qreal(2), radius * goldenRatio);
82
83 QQuadPath path;
84 path.moveTo(QVector2D(x0, cy));
85
86 qreal x = x0;
87 qreal dir = 1.0; // alternates between +1 and -1
88
89 while (x < x1) {
90 const qreal nextX = qMin(x + halfPeriod, x1);
91 const qreal fraction = (nextX - x) / halfPeriod;
92 const qreal peakY = cy + dir * radius * fraction;
93 const qreal ctrlX = (x + nextX) / 2.0;
94
95 path.quadTo(QVector2D(ctrlX, peakY), QVector2D(nextX, cy));
96
97 x = nextX;
98 dir = -dir;
99 }
100
101 return path;
102}
103
104// Helper: creates a QSGCurveStrokeNode from a QQuadPath and appends it.
105static void strokePathToNode(QSGNode *parent, const QQuadPath &path, const QColor &color,
106 qreal penWidth)
107{
108 QSGCurveStrokeNode *node = new QSGCurveStrokeNode;
109 node->setColor(color);
110 node->setStrokeWidth(penWidth);
111
112 QSGCurveProcessor::processStroke(
113 path, 2, penWidth, false, Qt::MiterJoin, Qt::FlatCap,
114 [&node](const std::array<QVector2D, 3> &s, const std::array<QVector2D, 3> &p,
115 const std::array<QVector2D, 3> &n, const std::array<float, 3> &ex,
116 QSGCurveStrokeNode::TriangleFlags /*f*/) {
117 node->appendTriangle(s, std::array<QVector2D, 2>{ p.at(0), p.at(2) }, n, ex);
118 });
119 node->cookGeometry();
120 parent->appendChildNode(node);
121}
122
123void QSGRhiInternalTextNode::addDecorationNode(const QRectF &rect, const QColor &color,
124 QTextCharFormat::UnderlineStyle style)
125{
126 if (rect.width() <= 0)
127 return;
128
129 const qreal penWidth = rect.height();
130 const QPointF c = rect.center();
131
132 if (style == QTextCharFormat::WaveUnderline) {
133 QQuadPath path = buildWavyPath(rect.left(), rect.right(), c.y(), penWidth);
134 // Limit pen width so the wave doesn't get too fat
135 const qreal radius = qMax(qreal(1), penWidth);
136 const qreal maxPenWidth = 0.8 * radius;
137 strokePathToNode(this, path, color, qMin(penWidth, maxPenWidth));
138 return;
139 }
140
141 if (style != QTextCharFormat::SingleUnderline) {
142 // Dashed styles
143 QSpan<const qreal> pattern = dashPatternForStyle(style);
144 if (!pattern.isEmpty()) {
145 QQuadPath path = buildDashedPath(rect.left(), rect.right(), c.y(), pattern, penWidth);
146 strokePathToNode(this, path, color, penWidth);
147 return;
148 }
149 }
150
151 // SingleUnderline: solid line
152 QQuadPath path;
153 path.moveTo(QVector2D(rect.left(), c.y()));
154 path.lineTo(QVector2D(rect.right(), c.y()));
155 strokePathToNode(this, path, color, penWidth);
156}
157
158QT_END_NAMESPACE
\inmodule QtQuick
Combined button and popup list for selecting options.
static constexpr qreal dashDotDotPattern[]
static QQuadPath buildDashedPath(qreal x0, qreal x1, qreal cy, QSpan< const qreal > pattern, qreal penWidth)
static constexpr qreal dashPattern[]
static constexpr qreal dotPattern[]
static constexpr qreal goldenRatio
static void strokePathToNode(QSGNode *parent, const QQuadPath &path, const QColor &color, qreal penWidth)
static QQuadPath buildWavyPath(qreal x0, qreal x1, qreal cy, qreal penWidth)
static QSpan< const qreal > dashPatternForStyle(QTextCharFormat::UnderlineStyle style)
static constexpr qreal dashDotPattern[]