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
DistanceFieldModel(QObject * parent)37 DistanceFieldModel::DistanceFieldModel(QObject *parent)
38 : QAbstractListModel(parent)
39 , m_glyphCount(0)
40 {
41 int index = metaObject()->indexOfEnumerator("UnicodeRange");
42 Q_ASSERT(index >= 0);
43
44 m_rangeEnum = metaObject()->enumerator(index);
45
46 m_workerThread.reset(new QThread);
47
48 m_worker = new DistanceFieldModelWorker;
49 m_worker->moveToThread(m_workerThread.data());
50 connect(m_workerThread.data(), &QThread::finished,
51 m_worker, &QObject::deleteLater);
52
53 connect(m_worker, &DistanceFieldModelWorker::fontLoaded,
54 this, &DistanceFieldModel::startGeneration);
55 connect(m_worker, &DistanceFieldModelWorker::fontLoaded,
56 this, &DistanceFieldModel::reserveSpace);
57 connect(m_worker, &DistanceFieldModelWorker::distanceFieldGenerated,
58 this, &DistanceFieldModel::addDistanceField);
59 connect(m_worker, &DistanceFieldModelWorker::fontGenerated,
60 this, &DistanceFieldModel::stopGeneration);
61 connect(m_worker, &DistanceFieldModelWorker::distanceFieldGenerated,
62 this, &DistanceFieldModel::distanceFieldGenerated);
63 connect(m_worker, &DistanceFieldModelWorker::error,
64 this, &DistanceFieldModel::error);
65
66 m_workerThread->start();
67 }
68
~DistanceFieldModel()69 DistanceFieldModel::~DistanceFieldModel()
70 {
71 m_workerThread->quit();
72 m_workerThread->wait();
73 }
74
headerData(int section,Qt::Orientation orientation,int role) const75 QVariant DistanceFieldModel::headerData(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
rowCount(const QModelIndex & parent) const83 int DistanceFieldModel::rowCount(const QModelIndex &parent) const
84 {
85 if (parent.isValid())
86 return 0;
87 else
88 return m_glyphCount;
89 }
90
data(const QModelIndex & index,int role) const91 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(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(m_distanceFields.at(index.row()).scaled(64, 64));
105 } else {
106 return defaultImage;
107 }
108
109 }
110
111 return QVariant();
112 }
113
setFont(const QString & fileName)114 void DistanceFieldModel::setFont(const QString &fileName)
115 {
116 QMetaObject::invokeMethod(m_worker,
117 [this, fileName] { m_worker->loadFont(fileName); },
118 Qt::QueuedConnection);
119 }
120
reserveSpace(quint16 glyphCount,bool doubleResolution,qreal pixelSize)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(glyphCount);
131 endResetModel();
132
133 m_doubleGlyphResolution = doubleResolution;
134 m_pixelSize = pixelSize;
135
136 QMetaObject::invokeMethod(m_worker,
137 [this] { m_worker->generateOneDistanceField(); },
138 Qt::QueuedConnection);
139 }
140
unicodeRangeForUcs4(quint32 ucs4) const141 DistanceFieldModel::UnicodeRange DistanceFieldModel::unicodeRangeForUcs4(quint32 ucs4) const
142 {
143 int index = metaObject()->indexOfEnumerator("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(i);
149 int rangeEnd = range.value(i + 1);
150 if (quint32(rangeStart) <= ucs4 && quint32(rangeEnd) >= ucs4)
151 return UnicodeRange(rangeStart);
152 }
153
154 return Other;
155 }
156
unicodeRanges() const157 QList<DistanceFieldModel::UnicodeRange> DistanceFieldModel::unicodeRanges() const
158 {
159 return m_glyphsPerUnicodeRange.uniqueKeys();
160 }
161
glyphIndexesForUnicodeRange(UnicodeRange range) const162 QList<glyph_t> DistanceFieldModel::glyphIndexesForUnicodeRange(UnicodeRange range) const
163 {
164 return m_glyphsPerUnicodeRange.values(range);
165 }
166
nameForUnicodeRange(UnicodeRange range) const167 QString DistanceFieldModel::nameForUnicodeRange(UnicodeRange range) const
168 {
169 return QString::fromLatin1(m_rangeEnum.valueToKey(int(range)));
170 }
171
addDistanceField(const QImage & distanceField,const QPainterPath & path,glyph_t glyphId,quint32 ucs4)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(glyphId + 1);
179 m_distanceFields[glyphId] = distanceField;
180 if (glyphId >= quint16(m_paths.size()))
181 m_paths.resize(glyphId + 1);
182 m_paths[glyphId] = path;
183
184 if (ucs4 != 0) {
185 UnicodeRange range = unicodeRangeForUcs4(ucs4);
186 m_glyphsPerUnicodeRange.insert(range, glyphId);
187 m_glyphsPerUcs4.insert(ucs4, glyphId);
188 }
189
190 emit dataChanged(createIndex(glyphId, 0), createIndex(glyphId, 0));
191
192 QMetaObject::invokeMethod(m_worker,
193 [this] { m_worker->generateOneDistanceField(); },
194 Qt::QueuedConnection);
195 }
196
glyphIndexForUcs4(quint32 ucs4) const197 glyph_t DistanceFieldModel::glyphIndexForUcs4(quint32 ucs4) const
198 {
199 return m_glyphsPerUcs4.value(ucs4);
200 }
201
202 QT_END_NAMESPACE
203