aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgcurveglyphnode.cpp
blob: c5252083d3aec722cb237e400e252395f57ddbfd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "qsgcurveglyphnode_p.h"
#include "qsgcurveglyphatlas_p.h"
#include "qsgcurvefillnode_p.h"
#include "qsgcurvestrokenode_p.h"

#include <private/qsgcurveabstractnode_p.h>
#include <private/qsgcontext_p.h>
#include <private/qsgtexturematerial_p.h>

#include <private/qrawfont_p.h>
#include <QtGui/qcolor.h>

QT_BEGIN_NAMESPACE

QSGCurveGlyphNode::QSGCurveGlyphNode(QSGRenderContext *context)
    : m_context(context)
    , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
    , m_dirtyGeometry(false)
{
    setFlag(UsePreprocess);
    setFlag(OwnsMaterial);

    // #### To avoid asserts: we should probably merge this with QSGCurveFillNode
    setGeometry(&m_geometry);
    setMaterial(new QSGTextureMaterial);
}

QSGCurveGlyphNode::~QSGCurveGlyphNode()
{
}

void QSGCurveGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
{
    Q_UNUSED(mode);
}

void QSGCurveGlyphNode::setColor(const QColor &color)
{
    m_color = color;
    if (m_glyphNode != nullptr)
        m_glyphNode->setColor(color);
}

void QSGCurveGlyphNode::setStyleColor(const QColor &styleColor)
{
    m_styleColor = styleColor;
    if (m_styleNode != nullptr)
        m_styleNode->setColor(styleColor);
}

void QSGCurveGlyphNode::setStyle(QQuickText::TextStyle style)
{
    if (m_style != style) {
        m_style = style;
        m_dirtyGeometry = true;
        update();
    }
}

void QSGCurveGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
{
    m_glyphs = glyphs;

    QRawFont font = glyphs.rawFont();
    m_fontSize = font.pixelSize();
    m_position = QPointF(position.x(), position.y() - font.ascent());


    m_dirtyGeometry = true;

#ifdef QSG_RUNTIME_DESCRIPTION
    qsgnode_set_description(this, QString::number(glyphs.glyphIndexes().count())
                                      + QStringLiteral(" curve glyphs: ")
                                      + m_glyphs.rawFont().familyName()
                                      + QStringLiteral(" ")
                                      + QString::number(m_glyphs.rawFont().pixelSize()));
#endif
}

void QSGCurveGlyphNode::update()
{
    markDirty(DirtyGeometry);
}

void QSGCurveGlyphNode::preprocess()
{
    if (m_dirtyGeometry)
        updateGeometry();
}

void QSGCurveGlyphNode::updateGeometry()
{
    delete m_glyphNode;
    m_glyphNode = nullptr;

    delete m_styleNode;
    m_styleNode = nullptr;

    QSGCurveGlyphAtlas *curveGlyphAtlas = m_context->curveGlyphAtlas(m_glyphs.rawFont());
    curveGlyphAtlas->populate(m_glyphs.glyphIndexes());

    m_glyphNode = new QSGCurveFillNode;
    m_glyphNode->setColor(m_color);

    QPointF offset;

    float fontScale = float(m_fontSize / curveGlyphAtlas->fontSize());
    QSGCurveFillNode *raisedSunkenStyleNode = nullptr;
    QSGCurveStrokeNode *outlineNode = nullptr;
    if (m_style == QQuickText::Raised || m_style == QQuickText::Sunken) {
        raisedSunkenStyleNode = new QSGCurveFillNode;
        raisedSunkenStyleNode ->setColor(m_styleColor);

        offset = m_style == QQuickText::Raised ? QPointF(0.0f, 1.0f) : QPointF(0.0f, -1.0f);
        m_styleNode = raisedSunkenStyleNode;
    } else if (m_style == QQuickText::Outline) {
        outlineNode = new QSGCurveStrokeNode;
        outlineNode->setColor(m_styleColor);
        outlineNode->setStrokeWidth(2 / fontScale);
        outlineNode->setLocalScale(fontScale);

        m_styleNode = outlineNode;
    }

    const QVector<quint32> indexes = m_glyphs.glyphIndexes();
    const QVector<QPointF> positions = m_glyphs.positions();
    for (qsizetype i = 0; i < indexes.size(); ++i) {
        if (i == 0)
            m_baseLine = positions.at(i);
        curveGlyphAtlas->addGlyph(m_glyphNode,
                                 indexes.at(i),
                                 m_position + positions.at(i),
                                 m_fontSize);
        if (raisedSunkenStyleNode != nullptr) {
            curveGlyphAtlas->addGlyph(raisedSunkenStyleNode,
                                      indexes.at(i),
                                      m_position + positions.at(i) + offset,
                                      m_fontSize);
        }
        if (outlineNode != nullptr) {
            // Since the stroke node will scale everything by fontScale internally (the
            // shader does not support pre-transforming the vertices), we have to also first
            // do the inverse scale on the glyph position to get the correct position.
            curveGlyphAtlas->addStroke(outlineNode,
                                       indexes.at(i),
                                       (m_position + positions.at(i)) / fontScale);
        }
    }

    if (m_styleNode != nullptr) {
        m_styleNode->cookGeometry();
        appendChildNode(m_styleNode);
    }

    m_glyphNode->cookGeometry();
    appendChildNode(m_glyphNode);

    m_dirtyGeometry = false;
}

QT_END_NAMESPACE