Revision control

++ // Copyright (C) 2018 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++ #include "distancefieldmodel.h"
++ #include "distancefieldmodelworker.h"
++
++ #include <QThread>
++ #include <QMetaEnum>
++
++ QT_BEGIN_NAMESPACE
++
++ DistanceFieldModel::DistanceFieldModel(QObject *parent)
++ : QAbstractListModel(parent)
++ , m_glyphCount(0)
++ {
++ int index = metaObject()->indexOfEnumerator("UnicodeRange");
++ Q_ASSERT(index >= 0);
++
++ m_rangeEnum = metaObject()->enumerator(index);
++
++ m_workerThread.reset(new QThread);
++
++ m_worker = new DistanceFieldModelWorker;
++ m_worker->moveToThread(m_workerThread.data());
++ connect(m_workerThread.data(), &QThread::finished,
++ m_worker, &QObject::deleteLater);
++
++ connect(m_worker, &DistanceFieldModelWorker::fontLoaded,
++ this, &DistanceFieldModel::startGeneration);
++ connect(m_worker, &DistanceFieldModelWorker::fontLoaded,
++ this, &DistanceFieldModel::reserveSpace);
++ connect(m_worker, &DistanceFieldModelWorker::distanceFieldGenerated,
++ this, &DistanceFieldModel::addDistanceField);
++ connect(m_worker, &DistanceFieldModelWorker::fontGenerated,
++ this, &DistanceFieldModel::stopGeneration);
++ connect(m_worker, &DistanceFieldModelWorker::distanceFieldGenerated,
++ this, &DistanceFieldModel::distanceFieldGenerated);
++ connect(m_worker, &DistanceFieldModelWorker::error,
++ this, &DistanceFieldModel::error);
++
++ m_workerThread->start();
++ }
++
++ DistanceFieldModel::~DistanceFieldModel()
++ {
++ m_workerThread->quit();
++ m_workerThread->wait();
++ }
++
++ QVariant DistanceFieldModel::headerData(int section, Qt::Orientation orientation, int role) const
++ {
++ Q_UNUSED(section);
++ Q_UNUSED(orientation);
++ Q_UNUSED(role);
++ return QVariant();
++ }
++
++ int DistanceFieldModel::rowCount(const QModelIndex &parent) const
++ {
++ if (parent.isValid())
++ return 0;
++ else
++ return m_glyphCount;
++ }
++
++ QVariant DistanceFieldModel::data(const QModelIndex &index, int role) const
++ {
++ static QPixmap defaultImage;
++ if (defaultImage.isNull()) {
++ defaultImage = QPixmap(64, 64);
++ defaultImage.fill(Qt::white);
++ }
++
++ if (!index.isValid())
++ return QVariant();
++
++ if (role == Qt::DecorationRole) {
++ if (index.row() < m_distanceFields.size()) {
++ return QPixmap::fromImage(m_distanceFields.at(index.row()).scaled(64, 64));
++ } else {
++ return defaultImage;
++ }
++
++ }
++
++ return QVariant();
++ }
++
++ void DistanceFieldModel::setFont(const QString &fileName)
++ {
++ QMetaObject::invokeMethod(m_worker,
++ [this, fileName] { m_worker->loadFont(fileName); },
++ Qt::QueuedConnection);
++ }
++
++ void DistanceFieldModel::reserveSpace(quint16 glyphCount,
++ bool doubleResolution,
++ qreal pixelSize)
++ {
++ beginResetModel();
++ m_glyphsPerUnicodeRange.clear();
++ m_distanceFields.clear();
++ m_glyphCount = glyphCount;
++ if (glyphCount > 0)
++ m_distanceFields.reserve(glyphCount);
++ endResetModel();
++
++ m_doubleGlyphResolution = doubleResolution;
++ m_pixelSize = pixelSize;
++
++ QMetaObject::invokeMethod(m_worker,
++ [this] { m_worker->generateOneDistanceField(); },
++ Qt::QueuedConnection);
++ }
++
++ DistanceFieldModel::UnicodeRange DistanceFieldModel::unicodeRangeForUcs4(quint32 ucs4) const
++ {
++ int index = metaObject()->indexOfEnumerator("UnicodeRange");
++ Q_ASSERT(index >= 0);
++
++ QMetaEnum range = metaObject()->enumerator(index);
++ for (int i = 0; i < range.keyCount() - 1; ++i) {
++ int rangeStart = range.value(i);
++ int rangeEnd = range.value(i + 1);
++ if (quint32(rangeStart) <= ucs4 && quint32(rangeEnd) >= ucs4)
++ return UnicodeRange(rangeStart);
++ }
++
++ return Other;
++ }
++
++ QList<DistanceFieldModel::UnicodeRange> DistanceFieldModel::unicodeRanges() const
++ {
++ return m_glyphsPerUnicodeRange.uniqueKeys();
++ }
++
++ QList<glyph_t> DistanceFieldModel::glyphIndexesForUnicodeRange(UnicodeRange range) const
++ {
++ return m_glyphsPerUnicodeRange.values(range);
++ }
++
++ QString DistanceFieldModel::nameForUnicodeRange(UnicodeRange range) const
++ {
++ return QString::fromLatin1(m_rangeEnum.valueToKey(int(range)));
++ }
++
++ void DistanceFieldModel::addDistanceField(const QImage &distanceField,
++ const QPainterPath &path,
++ glyph_t glyphId,
++ quint32 ucs4)
++ {
++ if (glyphId >= quint16(m_distanceFields.size()))
++ m_distanceFields.resize(glyphId + 1);
++ m_distanceFields[glyphId] = distanceField;
++ if (glyphId >= quint16(m_paths.size()))
++ m_paths.resize(glyphId + 1);
++ m_paths[glyphId] = path;
++
++ if (ucs4 != 0) {
++ UnicodeRange range = unicodeRangeForUcs4(ucs4);
++ m_glyphsPerUnicodeRange.insert(range, glyphId);
++ m_glyphsPerUcs4.insert(ucs4, glyphId);
++ }
++
++ emit dataChanged(createIndex(glyphId, 0), createIndex(glyphId, 0));
++
++ QMetaObject::invokeMethod(m_worker,
++ [this] { m_worker->generateOneDistanceField(); },
++ Qt::QueuedConnection);
++ }
++
++ glyph_t DistanceFieldModel::glyphIndexForUcs4(quint32 ucs4) const
++ {
++ return m_glyphsPerUcs4.value(ucs4);
++ }
++
++ QT_END_NAMESPACE