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