make packageurlinterceptor as noop as possible

Summary:
minimize file access during url rewrite

we still need it for accessing stuff under code/

Test Plan: plasma still loads, seems to save ~2%

Reviewers: #plasma, davidedmundson

Reviewed By: #plasma, davidedmundson

Subscribers: davidedmundson, ngraham, apol, plasma-devel, #frameworks

Tags: #plasma, #frameworks

Differential Revision: https://phabricator.kde.org/D9124
This commit is contained in:
Marco Martin 2017-12-18 13:00:14 +01:00
parent 2956419c7e
commit c318fde313
9 changed files with 32 additions and 97 deletions

View File

@ -41,7 +41,7 @@ void ConfigModelTest::configSchemeFromPackage()
qmlRegisterType<PlasmaQuick::ConfigCategory>("org.kde.plasma.configuration", 2, 0, "ConfigCategory");
QQmlEngine engine;
QQmlComponent *component = new QQmlComponent(&engine, QUrl::fromLocalFile(applet->package().filePath("configmodel")), this);
QQmlComponent *component = new QQmlComponent(&engine, applet->kPackage().fileUrl("configmodel"), this);
QObject *object = component->create(engine.rootContext());
PlasmaQuick::ConfigModel *configModel = qobject_cast<PlasmaQuick::ConfigModel *>(object);

View File

@ -38,7 +38,7 @@ CustomCorona::CustomCorona(QObject *parent)
qmlRegisterUncreatableType<PlasmaQuick::ContainmentView>("org.kde.plasma.shell", 2, 0, "Desktop", QStringLiteral("It is not possible to create objects of type Desktop"));
m_view = new PlasmaQuick::ContainmentView(this);
m_view->setSource(QUrl::fromLocalFile(package.filePath("views", QStringLiteral("Desktop.qml"))));
m_view->setSource(package.fileUrl("views", QStringLiteral("Desktop.qml")));
m_view->show();
load();

View File

@ -519,7 +519,7 @@ void AppletQuickItem::init()
engine->setProperty(("_plasma_qqc_style_set"), true);
}
d->qmlObject->setSource(QUrl::fromLocalFile(d->applet->kPackage().filePath("mainscript")));
d->qmlObject->setSource(d->applet->kPackage().fileUrl("mainscript"));
if (!engine || !engine->rootContext() || !engine->rootContext()->isValid() || !d->qmlObject->mainComponent() || d->qmlObject->mainComponent()->isError() || d->applet->failedToLaunch()) {
QString reason;
@ -534,7 +534,7 @@ void AppletQuickItem::init()
reason = i18n("Error loading Applet: package inexistent. %1", applet()->launchErrorMessage());
}
d->qmlObject->setSource(QUrl::fromLocalFile(d->coronaPackage.filePath("appleterror")));
d->qmlObject->setSource(d->coronaPackage.fileUrl("appleterror"));
d->qmlObject->completeInitialization();
//even the error message QML may fail
@ -579,20 +579,20 @@ void AppletQuickItem::init()
//default compactRepresentation is a simple icon provided by the shell package
if (!d->compactRepresentation) {
d->compactRepresentation = new QQmlComponent(engine, this);
d->compactRepresentation->loadUrl(QUrl::fromLocalFile(d->coronaPackage.filePath("defaultcompactrepresentation")));
d->compactRepresentation->loadUrl(d->coronaPackage.fileUrl("defaultcompactrepresentation"));
emit compactRepresentationChanged(d->compactRepresentation);
}
//default compactRepresentationExpander is the popup in which fullRepresentation goes
if (!d->compactRepresentationExpander) {
d->compactRepresentationExpander = new QQmlComponent(engine, this);
QString compactExpanderPath = d->containmentPackage.filePath("compactapplet");
QUrl compactExpanderUrl = d->containmentPackage.fileUrl("compactapplet");
if (compactExpanderPath.isEmpty()) {
compactExpanderPath = d->coronaPackage.filePath("compactapplet");
if (compactExpanderUrl.isEmpty()) {
compactExpanderUrl = d->coronaPackage.fileUrl("compactapplet");
}
d->compactRepresentationExpander->loadUrl(QUrl::fromLocalFile(compactExpanderPath));
d->compactRepresentationExpander->loadUrl(compactExpanderUrl);
}
d->compactRepresentationCheck();
@ -674,7 +674,7 @@ QQmlComponent *AppletQuickItem::fullRepresentation()
QObject *AppletQuickItem::testItem()
{
if (!d->testItem) {
const QUrl url = QUrl::fromLocalFile(d->appletPackage.filePath("test"));
const QUrl url(d->appletPackage.fileUrl("test"));
if (url.isEmpty()) {
return nullptr;
}

View File

@ -239,7 +239,7 @@ QVariant ConfigModel::data(const QModelIndex &index, int role) const
if (d->appletInterface && !source.isEmpty() && !(source.startsWith(QLatin1Char('/')) && source.endsWith(QLatin1String("qml")))) {
if(!d->appletInterface.data()->kPackage().isValid())
qWarning() << "wrong applet" << d->appletInterface.data()->pluginMetaData().name();
return QUrl::fromLocalFile(d->appletInterface.data()->kPackage().filePath("ui", source));
return d->appletInterface.data()->kPackage().fileUrl("ui", source);
} else {
return source;
}

View File

@ -133,7 +133,7 @@ void ConfigViewPrivate::init()
q->setResizeMode(QQuickView::SizeViewToRootObject);
//config model local of the applet
QQmlComponent *component = new QQmlComponent(q->engine(), QUrl::fromLocalFile(applet.data()->kPackage().filePath("configmodel")), q);
QQmlComponent *component = new QQmlComponent(q->engine(), applet.data()->kPackage().fileUrl("configmodel"), q);
QObject *object = component->beginCreate(q->engine()->rootContext());
configModel = qobject_cast<ConfigModel *>(object);
@ -298,7 +298,7 @@ ConfigView::~ConfigView()
void ConfigView::init()
{
setSource(QUrl::fromLocalFile(d->corona->kPackage().filePath("appletconfigurationui")));
setSource(d->corona->kPackage().fileUrl("appletconfigurationui"));
}
Plasma::Applet *ConfigView::applet()

View File

@ -24,6 +24,7 @@
#include <QFile>
#include <QFileInfo>
#include <QStandardPaths>
#include <QRegularExpression>
#include <Plasma/PluginLoader>
#include <Plasma/Package>
@ -46,14 +47,8 @@ public:
QStringList allowedPaths;
QQmlEngine *engine;
bool forcePlasmaStyle = false;
//FIXME: those are going to be stuffed here and stay..
// they should probably be removed when the last applet of that type is removed
static QHash<QString, KPackage::Package> s_packages;
};
QHash<QString, KPackage::Package> PackageUrlInterceptorPrivate::s_packages = QHash<QString, KPackage::Package>();
PackageUrlInterceptor::PackageUrlInterceptor(QQmlEngine *engine, const KPackage::Package &p)
: QQmlAbstractUrlInterceptor(),
@ -96,86 +91,26 @@ QUrl PackageUrlInterceptor::intercept(const QUrl &path, QQmlAbstractUrlIntercept
{
//qDebug() << "Intercepted URL:" << path << type;
if (d->forcePlasmaStyle && path.path().contains(QLatin1String("Controls.2/org.kde.desktop/"))) {
return QUrl::fromLocalFile(path.path().replace(QLatin1String("Controls.2/org.kde.desktop/"), QLatin1String("Controls.2/Plasma/")));
}
QString pkgRoot;
KPackage::Package package;
if (d->package.isValid()) {
package = d->package;
} else {
foreach (const QString &base, QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) {
pkgRoot = QFileInfo(base + QStringLiteral("/plasma/plasmoids/")).canonicalFilePath();
if (!pkgRoot.isEmpty() && path.path().startsWith(pkgRoot)) {
const QString pkgName = path.path().midRef(pkgRoot.length() + 1).split(QLatin1Char('/')).first().toString();
auto it = PackageUrlInterceptorPrivate::s_packages.constFind(pkgName);
if (it != PackageUrlInterceptorPrivate::s_packages.constEnd()) {
package = *it;
} else {
package = Plasma::PluginLoader::self()->loadPackage(QStringLiteral("Plasma/Applet")).kPackage();
package.setPath(pkgName);
PackageUrlInterceptorPrivate::s_packages[pkgName] = package;
}
break;
}
}
}
if (!package.isValid()) {
//we assume we never rewritten qml/qmldir files
if (path.path().endsWith(QStringLiteral("qml")) || path.path().endsWith(QStringLiteral("qmldir"))) {
return path;
}
const QString prefix = QString::fromUtf8(prefixForType(type, path.path()));
QRegularExpression match(QStringLiteral("/ui/(.*)"));
if (d->package.isValid() && path.scheme() == QStringLiteral("plasmapackage")) {
//FIXME: this is incorrect but works around a bug in qml in resolution of urls of qmldir files
if (type == QQmlAbstractUrlInterceptor::QmldirFile) {
return QUrl(d->package.filePath(0, path.path()));
} else {
return QUrl::fromLocalFile(d->package.filePath(0, path.path()));
}
}
QString plainPath = path.toString();
if (plainPath.contains(match)) {
QString rewritten = plainPath.replace(match, QStringLiteral("/%1/\\1").arg(prefix));
//TODO: security: permission for remote urls
if (!path.isLocalFile()) {
return path;
}
//if is just a normal string, no qml file was asked, allow it
if (type == QQmlAbstractUrlInterceptor::UrlString) {
return path;
}
//asked a file inside a package: let's rewrite the url!
if (path.path().startsWith(package.path())) {
//qDebug() << "Found URL in package" << path;
//tries to isolate the relative path asked relative to the contentsPrefixPath: like ui/foo.qml
QString relativePath;
foreach (const QString &prefix, package.contentsPrefixPaths()) {
QString root = package.path() + prefix;
if (path.path().startsWith(root)) {
//obtain a string in the form ui/foo/bar/baz.qml
relativePath = path.path().mid(root.length());
break;
}
}
//should never happen
Q_ASSERT(!relativePath.isEmpty());
const int firstSlash = relativePath.indexOf(QLatin1Char('/')) + 1;
const QString filename = firstSlash > 0 ? relativePath.mid(firstSlash) : relativePath;
const QUrl ret = QUrl::fromLocalFile(package.filePath(prefixForType(type, filename), filename));
//qDebug() << "Returning" << ret;
if (ret.path().isEmpty()) {
//search it in a resource or as a file on disk
if (!(rewritten.contains(QStringLiteral("qrc")) &&
QFile::exists(QStringLiteral(":") + QUrl(rewritten).path())) &&
!QFile::exists(QUrl(rewritten).path())) {
return path;
}
return ret;
//forbid to load random absolute paths
qWarning()<<"Warning: all files used by qml by the plasmoid should be in ui/. The file in the path" << rewritten << "was expected at" <<path;
return QUrl(rewritten);
}
return path;
}

View File

@ -66,7 +66,7 @@ public:
case QQmlAbstractUrlInterceptor::QmlFile:
return QByteArray("ui");
case QQmlAbstractUrlInterceptor::JavaScriptFile:
return QByteArray("scripts");
return QByteArray("code");
default:
break;
}
@ -80,8 +80,8 @@ public:
return QByteArray("images");
//FIXME: are those necessary? are they *always* catched by type?
} else if (extension == QStringLiteral("js")) {
return QByteArray("scripts");
} else if (extension == QStringLiteral("qml")) {
return QByteArray("code");
} else if (extension == QStringLiteral("qml") || extension == QStringLiteral("qmldir")) {
return QByteArray("ui");
//everything else, throw it in "data"
} else {

View File

@ -122,7 +122,7 @@ void ContainmentInterface::init()
QVariantHash toolboxProperties;
toolboxProperties[QStringLiteral("parent")] = QVariant::fromValue(this);
QObject *toolBoxObject = qmlObject()->createObjectFromSource(QUrl::fromLocalFile(pkg.filePath("mainscript")), 0, toolboxProperties);
QObject *toolBoxObject = qmlObject()->createObjectFromSource(pkg.fileUrl("mainscript"), 0, toolboxProperties);
if (toolBoxObject && containmentGraphicObject) {
containmentGraphicObject->setProperty("toolBox", QVariant::fromValue(toolBoxObject));
}

View File

@ -147,7 +147,7 @@ void WallpaperInterface::syncWallpaperPackage()
}
m_qmlObject->rootContext()->setContextProperty(QStringLiteral("wallpaper"), this);
m_qmlObject->setSource(QUrl::fromLocalFile(m_pkg.filePath("mainscript")));
m_qmlObject->setSource(m_pkg.fileUrl("mainscript"));
const QString rootPath = m_pkg.metadata().value(QStringLiteral("X-Plasma-RootPath"));
if (!rootPath.isEmpty()) {