1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2018 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the tools applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include "distancefieldmodel.h" |
30 | #include "distancefieldmodelworker.h" |
31 | |
32 | #include <QThread> |
33 | #include <QMetaEnum> |
34 | |
35 | QT_BEGIN_NAMESPACE |
36 | |
37 | DistanceFieldModel::DistanceFieldModel(QObject *parent) |
38 | : QAbstractListModel(parent) |
39 | , m_glyphCount(0) |
40 | { |
41 | int index = metaObject()->indexOfEnumerator(name: "UnicodeRange" ); |
42 | Q_ASSERT(index >= 0); |
43 | |
44 | m_rangeEnum = metaObject()->enumerator(index); |
45 | |
46 | m_workerThread.reset(other: new QThread); |
47 | |
48 | m_worker = new DistanceFieldModelWorker; |
49 | m_worker->moveToThread(thread: m_workerThread.data()); |
50 | connect(sender: m_workerThread.data(), signal: &QThread::finished, |
51 | receiver: m_worker, slot: &QObject::deleteLater); |
52 | |
53 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::fontLoaded, |
54 | receiver: this, slot: &DistanceFieldModel::startGeneration); |
55 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::fontLoaded, |
56 | receiver: this, slot: &DistanceFieldModel::reserveSpace); |
57 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::distanceFieldGenerated, |
58 | receiver: this, slot: &DistanceFieldModel::addDistanceField); |
59 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::fontGenerated, |
60 | receiver: this, slot: &DistanceFieldModel::stopGeneration); |
61 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::distanceFieldGenerated, |
62 | receiver: this, slot: &DistanceFieldModel::distanceFieldGenerated); |
63 | connect(sender: m_worker, signal: &DistanceFieldModelWorker::error, |
64 | receiver: this, slot: &DistanceFieldModel::error); |
65 | |
66 | m_workerThread->start(); |
67 | } |
68 | |
69 | DistanceFieldModel::~DistanceFieldModel() |
70 | { |
71 | m_workerThread->quit(); |
72 | m_workerThread->wait(); |
73 | } |
74 | |
75 | QVariant DistanceFieldModel::(int section, Qt::Orientation orientation, int role) const |
76 | { |
77 | Q_UNUSED(section); |
78 | Q_UNUSED(orientation); |
79 | Q_UNUSED(role); |
80 | return QVariant(); |
81 | } |
82 | |
83 | int DistanceFieldModel::rowCount(const QModelIndex &parent) const |
84 | { |
85 | if (parent.isValid()) |
86 | return 0; |
87 | else |
88 | return m_glyphCount; |
89 | } |
90 | |
91 | QVariant DistanceFieldModel::data(const QModelIndex &index, int role) const |
92 | { |
93 | static QPixmap defaultImage; |
94 | if (defaultImage.isNull()) { |
95 | defaultImage = QPixmap(64, 64); |
96 | defaultImage.fill(fillColor: Qt::white); |
97 | } |
98 | |
99 | if (!index.isValid()) |
100 | return QVariant(); |
101 | |
102 | if (role == Qt::DecorationRole) { |
103 | if (index.row() < m_distanceFields.size()) { |
104 | return QPixmap::fromImage(image: m_distanceFields.at(i: index.row()).scaled(w: 64, h: 64)); |
105 | } else { |
106 | return defaultImage; |
107 | } |
108 | |
109 | } |
110 | |
111 | return QVariant(); |
112 | } |
113 | |
114 | void DistanceFieldModel::setFont(const QString &fileName) |
115 | { |
116 | QMetaObject::invokeMethod(context: m_worker, |
117 | function: [this, fileName] { m_worker->loadFont(fileName); }, |
118 | type: Qt::QueuedConnection); |
119 | } |
120 | |
121 | void DistanceFieldModel::reserveSpace(quint16 glyphCount, |
122 | bool doubleResolution, |
123 | qreal pixelSize) |
124 | { |
125 | beginResetModel(); |
126 | m_glyphsPerUnicodeRange.clear(); |
127 | m_distanceFields.clear(); |
128 | m_glyphCount = glyphCount; |
129 | if (glyphCount > 0) |
130 | m_distanceFields.reserve(asize: glyphCount); |
131 | endResetModel(); |
132 | |
133 | m_doubleGlyphResolution = doubleResolution; |
134 | m_pixelSize = pixelSize; |
135 | |
136 | QMetaObject::invokeMethod(context: m_worker, |
137 | function: [this] { m_worker->generateOneDistanceField(); }, |
138 | type: Qt::QueuedConnection); |
139 | } |
140 | |
141 | DistanceFieldModel::UnicodeRange DistanceFieldModel::unicodeRangeForUcs4(quint32 ucs4) const |
142 | { |
143 | int index = metaObject()->indexOfEnumerator(name: "UnicodeRange" ); |
144 | Q_ASSERT(index >= 0); |
145 | |
146 | QMetaEnum range = metaObject()->enumerator(index); |
147 | for (int i = 0; i < range.keyCount() - 1; ++i) { |
148 | int rangeStart = range.value(index: i); |
149 | int rangeEnd = range.value(index: i + 1); |
150 | if (quint32(rangeStart) <= ucs4 && quint32(rangeEnd) >= ucs4) |
151 | return UnicodeRange(rangeStart); |
152 | } |
153 | |
154 | return Other; |
155 | } |
156 | |
157 | QList<DistanceFieldModel::UnicodeRange> DistanceFieldModel::unicodeRanges() const |
158 | { |
159 | return m_glyphsPerUnicodeRange.uniqueKeys(); |
160 | } |
161 | |
162 | QList<glyph_t> DistanceFieldModel::glyphIndexesForUnicodeRange(UnicodeRange range) const |
163 | { |
164 | return m_glyphsPerUnicodeRange.values(akey: range); |
165 | } |
166 | |
167 | QString DistanceFieldModel::nameForUnicodeRange(UnicodeRange range) const |
168 | { |
169 | return QString::fromLatin1(str: m_rangeEnum.valueToKey(value: int(range))); |
170 | } |
171 | |
172 | void DistanceFieldModel::addDistanceField(const QImage &distanceField, |
173 | const QPainterPath &path, |
174 | glyph_t glyphId, |
175 | quint32 ucs4) |
176 | { |
177 | if (glyphId >= quint16(m_distanceFields.size())) |
178 | m_distanceFields.resize(asize: glyphId + 1); |
179 | m_distanceFields[glyphId] = distanceField; |
180 | if (glyphId >= quint16(m_paths.size())) |
181 | m_paths.resize(asize: glyphId + 1); |
182 | m_paths[glyphId] = path; |
183 | |
184 | if (ucs4 != 0) { |
185 | UnicodeRange range = unicodeRangeForUcs4(ucs4); |
186 | m_glyphsPerUnicodeRange.insert(akey: range, avalue: glyphId); |
187 | m_glyphsPerUcs4.insert(akey: ucs4, avalue: glyphId); |
188 | } |
189 | |
190 | emit dataChanged(topLeft: createIndex(arow: glyphId, acolumn: 0), bottomRight: createIndex(arow: glyphId, acolumn: 0)); |
191 | |
192 | QMetaObject::invokeMethod(context: m_worker, |
193 | function: [this] { m_worker->generateOneDistanceField(); }, |
194 | type: Qt::QueuedConnection); |
195 | } |
196 | |
197 | glyph_t DistanceFieldModel::glyphIndexForUcs4(quint32 ucs4) const |
198 | { |
199 | return m_glyphsPerUcs4.value(akey: ucs4); |
200 | } |
201 | |
202 | QT_END_NAMESPACE |
203 | |