1 | // Copyright (C) 2018 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | |
4 | #include "distancefieldmodel.h" |
5 | #include "distancefieldmodelworker.h" |
6 | |
7 | #include <QThread> |
8 | #include <QMetaEnum> |
9 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | DistanceFieldModel::DistanceFieldModel(QObject *parent) |
13 | : QAbstractListModel(parent) |
14 | , m_glyphCount(0) |
15 | { |
16 | int index = metaObject()->indexOfEnumerator(name: "UnicodeRange" ); |
17 | Q_ASSERT(index >= 0); |
18 | |
19 | m_rangeEnum = metaObject()->enumerator(index); |
20 | |
21 | m_workerThread.reset(other: new QThread); |
22 | |
23 | m_worker = new DistanceFieldModelWorker; |
24 | m_worker->moveToThread(thread: m_workerThread.data()); |
25 | connect(sender: m_workerThread.data(), signal: &QThread::finished, |
26 | context: m_worker, slot: &QObject::deleteLater); |
27 | |
28 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::fontLoaded, |
29 | context: this, slot: &DistanceFieldModel::startGeneration); |
30 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::fontLoaded, |
31 | context: this, slot: &DistanceFieldModel::reserveSpace); |
32 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::distanceFieldGenerated, |
33 | context: this, slot: &DistanceFieldModel::addDistanceField); |
34 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::fontGenerated, |
35 | context: this, slot: &DistanceFieldModel::stopGeneration); |
36 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::distanceFieldGenerated, |
37 | context: this, slot: &DistanceFieldModel::distanceFieldGenerated); |
38 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::error, |
39 | context: this, slot: &DistanceFieldModel::error); |
40 | |
41 | m_workerThread->start(); |
42 | } |
43 | |
44 | DistanceFieldModel::~DistanceFieldModel() |
45 | { |
46 | m_workerThread->quit(); |
47 | m_workerThread->wait(); |
48 | } |
49 | |
50 | QVariant DistanceFieldModel::(int section, Qt::Orientation orientation, int role) const |
51 | { |
52 | Q_UNUSED(section); |
53 | Q_UNUSED(orientation); |
54 | Q_UNUSED(role); |
55 | return QVariant(); |
56 | } |
57 | |
58 | int DistanceFieldModel::rowCount(const QModelIndex &parent) const |
59 | { |
60 | if (parent.isValid()) |
61 | return 0; |
62 | else |
63 | return m_glyphCount; |
64 | } |
65 | |
66 | QVariant DistanceFieldModel::data(const QModelIndex &index, int role) const |
67 | { |
68 | static QPixmap defaultImage; |
69 | if (defaultImage.isNull()) { |
70 | defaultImage = QPixmap(64, 64); |
71 | defaultImage.fill(fillColor: Qt::white); |
72 | } |
73 | |
74 | if (!index.isValid()) |
75 | return QVariant(); |
76 | |
77 | if (role == Qt::DecorationRole) { |
78 | if (index.row() < m_distanceFields.size()) { |
79 | return QPixmap::fromImage(image: m_distanceFields.at(i: index.row()).scaled(w: 64, h: 64)); |
80 | } else { |
81 | return defaultImage; |
82 | } |
83 | |
84 | } |
85 | |
86 | return QVariant(); |
87 | } |
88 | |
89 | void DistanceFieldModel::setFont(const QString &fileName) |
90 | { |
91 | QMetaObject::invokeMethod(object: m_worker, |
92 | function: [this, fileName] { m_worker->loadFont(fileName); }, |
93 | type: Qt::QueuedConnection); |
94 | } |
95 | |
96 | void DistanceFieldModel::reserveSpace(quint16 glyphCount, |
97 | bool doubleResolution, |
98 | qreal pixelSize) |
99 | { |
100 | beginResetModel(); |
101 | m_glyphsPerUnicodeRange.clear(); |
102 | m_distanceFields.clear(); |
103 | m_glyphCount = glyphCount; |
104 | if (glyphCount > 0) |
105 | m_distanceFields.reserve(asize: glyphCount); |
106 | endResetModel(); |
107 | |
108 | m_doubleGlyphResolution = doubleResolution; |
109 | m_pixelSize = pixelSize; |
110 | |
111 | QMetaObject::invokeMethod(object: m_worker, |
112 | function: [this] { m_worker->generateOneDistanceField(); }, |
113 | type: Qt::QueuedConnection); |
114 | } |
115 | |
116 | DistanceFieldModel::UnicodeRange DistanceFieldModel::unicodeRangeForUcs4(quint32 ucs4) const |
117 | { |
118 | int index = metaObject()->indexOfEnumerator(name: "UnicodeRange" ); |
119 | Q_ASSERT(index >= 0); |
120 | |
121 | QMetaEnum range = metaObject()->enumerator(index); |
122 | for (int i = 0; i < range.keyCount() - 1; ++i) { |
123 | int rangeStart = range.value(index: i); |
124 | int rangeEnd = range.value(index: i + 1); |
125 | if (quint32(rangeStart) <= ucs4 && quint32(rangeEnd) >= ucs4) |
126 | return UnicodeRange(rangeStart); |
127 | } |
128 | |
129 | return Other; |
130 | } |
131 | |
132 | QList<DistanceFieldModel::UnicodeRange> DistanceFieldModel::unicodeRanges() const |
133 | { |
134 | return m_glyphsPerUnicodeRange.uniqueKeys(); |
135 | } |
136 | |
137 | QList<glyph_t> DistanceFieldModel::glyphIndexesForUnicodeRange(UnicodeRange range) const |
138 | { |
139 | return m_glyphsPerUnicodeRange.values(key: range); |
140 | } |
141 | |
142 | QString DistanceFieldModel::nameForUnicodeRange(UnicodeRange range) const |
143 | { |
144 | return QString::fromLatin1(ba: m_rangeEnum.valueToKey(value: int(range))); |
145 | } |
146 | |
147 | void DistanceFieldModel::addDistanceField(const QImage &distanceField, |
148 | const QPainterPath &path, |
149 | glyph_t glyphId, |
150 | quint32 ucs4) |
151 | { |
152 | if (glyphId >= quint16(m_distanceFields.size())) |
153 | m_distanceFields.resize(size: glyphId + 1); |
154 | m_distanceFields[glyphId] = distanceField; |
155 | if (glyphId >= quint16(m_paths.size())) |
156 | m_paths.resize(size: glyphId + 1); |
157 | m_paths[glyphId] = path; |
158 | |
159 | if (ucs4 != 0) { |
160 | UnicodeRange range = unicodeRangeForUcs4(ucs4); |
161 | m_glyphsPerUnicodeRange.insert(key: range, value: glyphId); |
162 | m_glyphsPerUcs4.insert(key: ucs4, value: glyphId); |
163 | } |
164 | |
165 | emit dataChanged(topLeft: createIndex(arow: glyphId, acolumn: 0), bottomRight: createIndex(arow: glyphId, acolumn: 0)); |
166 | |
167 | QMetaObject::invokeMethod(object: m_worker, |
168 | function: [this] { m_worker->generateOneDistanceField(); }, |
169 | type: Qt::QueuedConnection); |
170 | } |
171 | |
172 | glyph_t DistanceFieldModel::glyphIndexForUcs4(quint32 ucs4) const |
173 | { |
174 | return m_glyphsPerUcs4.value(key: ucs4); |
175 | } |
176 | |
177 | QT_END_NAMESPACE |
178 | |