1
0
Fork 0

Remote-canvas loads fonts from the host.

This commit is contained in:
James Turner 2016-12-20 10:31:38 +00:00
parent 34ca0c15cc
commit 066d81568d
6 changed files with 195 additions and 2 deletions

View file

@ -30,6 +30,8 @@ set(SOURCES
fgcanvaswidget.h
canvastreemodel.cpp
canvastreemodel.h
fgqcanvasfontcache.cpp
fgqcanvasfontcache.h
)
qt5_wrap_ui(uic_sources temporarywidget.ui)

View file

@ -5,11 +5,16 @@
#include "fgcanvaspaintcontext.h"
#include "localprop.h"
#include "fgqcanvasfontcache.h"
FGCanvasText::FGCanvasText(FGCanvasGroup* pr, LocalProp* prop) :
FGCanvasElement(pr, prop),
_metrics(QFont())
{
// this signal fires infrequently enough, it's simpler just to have
// all texts watch it.
connect(FGQCanvasFontCache::instance(), &FGQCanvasFontCache::fontLoaded,
this, &FGCanvasText::onFontLoaded);
}
void FGCanvasText::doPaint(FGCanvasPaintContext *context) const
@ -131,10 +136,25 @@ void FGCanvasText::markFontDirty()
_fontDirty = true;
}
void FGCanvasText::onFontLoaded(QByteArray name)
{
QByteArray fontName = getCascadedStyle("font", QString()).toByteArray();
if (name != fontName) {
return; // not our font
}
markFontDirty();
}
void FGCanvasText::rebuildFont() const
{
QString fontName = getCascadedStyle("font", QString()).toString();
QFont f(fontName);
QByteArray fontName = getCascadedStyle("font", QString()).toByteArray();
bool ok;
QFont f = FGQCanvasFontCache::instance()->fontForName(fontName, &ok);
if (!ok) {
// wait for the correct font
}
f.setPixelSize(getCascadedStyle("character-size", 16).toInt());
_font = f;
_metrics = QFontMetricsF(_font);

View file

@ -24,6 +24,8 @@ private:
void setDrawMode(QVariant var);
void markFontDirty();
void onFontLoaded(QByteArray name);
private:
void rebuildFont() const;
void rebuildAlignment(QVariant var) const;

View file

@ -0,0 +1,122 @@
#include "fgqcanvasfontcache.h"
#include <QNetworkAccessManager>
#include <QStandardPaths>
#include <QDebug>
#include <QUrl>
#include <QNetworkReply>
#include <QFontDatabase>
#include <QFile>
FGQCanvasFontCache::FGQCanvasFontCache(QNetworkAccessManager* nam, QObject *parent)
: QObject(parent)
, m_downloader(nam)
{
}
QFont FGQCanvasFontCache::fontForName(QByteArray name, bool* ok)
{
if (m_cache.contains(name)) {
if (ok) {
*ok = true;
}
return m_cache.value(name); // easy!
}
lookupFile(name);
if (m_cache.contains(name)) {
if (ok) {
*ok = true;
}
return m_cache.value(name);
}
if (ok) {
*ok = false;
}
return QFont(); // default font
}
static FGQCanvasFontCache* s_instance = nullptr;
void FGQCanvasFontCache::initialise(QNetworkAccessManager *nam)
{
Q_ASSERT(s_instance == nullptr);
s_instance = new FGQCanvasFontCache(nam);
}
FGQCanvasFontCache *FGQCanvasFontCache::instance()
{
return s_instance;
}
void FGQCanvasFontCache::onFontDownloadFinished()
{
QByteArray fontPath = sender()->property("font").toByteArray();
qDebug() << "finished download of " << fontPath;
QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
QString absPath = cacheDir.absoluteFilePath(fontPath);
QFileInfo finfo(fontPath);
cacheDir.mkpath(finfo.dir().path());
QFile f(absPath);
if (!f.open(QIODevice::WriteOnly)) {
qWarning() << "failed to open cache file" << f.fileName();
}
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
Q_ASSERT(m_transfers.contains(reply));
f.write(reply->readAll());
f.close();
m_transfers.removeOne(reply);
// call ourselves again now it's cached;
lookupFile(fontPath);
}
void FGQCanvasFontCache::onFontDownloadError(QNetworkReply::NetworkError)
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
qWarning() << "font download failed:" << reply->errorString();
}
void FGQCanvasFontCache::lookupFile(QByteArray name)
{
QString path = QStandardPaths::locate(QStandardPaths::CacheLocation, name);
if (path.isEmpty()) {
QUrl url = QUrl("http://localhost:8080/Fonts/" + name);
Q_FOREACH (QNetworkReply* transfer, m_transfers) {
if (transfer->url() == url) {
return; // transfer already active
}
}
qDebug() << "reqeusting font" << url;
QNetworkReply* reply = m_downloader->get(QNetworkRequest(url));
reply->setProperty("font", name);
connect(reply, &QNetworkReply::finished, this, &FGQCanvasFontCache::onFontDownloadFinished);
// connect(reply, &QNetworkReply::error, this, &FGQCanvasFontCache::onFontDownloadError);
m_transfers.append(reply);
} else {
qDebug() << "found font" << name << "at path" << path;
int fontFamilyId = QFontDatabase::addApplicationFont(path);
QStringList families = QFontDatabase::applicationFontFamilies(fontFamilyId);
qDebug() << "families are:" << families;
// compute a QFont and cache
QFont font(families.front());
m_cache.insert(name, font);
}
}

View file

@ -0,0 +1,39 @@
#ifndef FGQCANVASFONTCACHE_H
#define FGQCANVASFONTCACHE_H
#include <QObject>
#include <QFont>
#include <QDir>
#include <QHash>
#include <QNetworkReply>
class QNetworkAccessManager;
class FGQCanvasFontCache : public QObject
{
Q_OBJECT
public:
explicit FGQCanvasFontCache(QNetworkAccessManager* nam, QObject *parent = 0);
QFont fontForName(QByteArray name, bool* ok = nullptr);
static void initialise(QNetworkAccessManager* nam);
static FGQCanvasFontCache* instance();
signals:
void fontLoaded(QByteArray name);
private slots:
void onFontDownloadFinished();
void onFontDownloadError(QNetworkReply::NetworkError);
private:
QNetworkAccessManager* m_downloader;
QHash<QByteArray, QFont> m_cache;
void lookupFile(QByteArray name);
QList<QNetworkReply*> m_transfers;
};
#endif // FGQCANVASFONTCACHE_H

View file

@ -1,5 +1,9 @@
#include "temporarywidget.h"
#include <QApplication>
#include <QNetworkAccessManager>
#include "fgqcanvasfontcache.h"
int main(int argc, char *argv[])
{
@ -9,6 +13,10 @@ int main(int argc, char *argv[])
a.setOrganizationDomain("flightgear.org");
a.setOrganizationName("FlightGear");
QNetworkAccessManager* downloader = new QNetworkAccessManager;
FGQCanvasFontCache::initialise(downloader);
TemporaryWidget w;
w.show();