Replace QTextDocumentResourceProvider with a std::function
376e3bd8ec
added the new class for Qt 6.1,
but during header review we concluded that using a class introduces
complexity wrt instance ownership and API design that can be avoided by
using a std::function instead.
The functionality is tied to QTextDocument, so the type definition and
the default provider API is added there.
Since std::function is not trivially copyable, the atomicity of the
previous implementation is not maintained, and concurrent modifications
of and access to the global default provider from multiple threads is
not allowed. The relevant use case can be supported by implementing a
resource provider that is thread safe.
Task-number: QTBUG-90211
Fixes: QTBUG-92208
Pick-to: 6.1
Change-Id: I39215c5e51c7bd27f1dd29e1d9d908aecf754fb7
Reviewed-by: Kai Koehne <kai.koehne@qt.io>
This commit is contained in:
parent
b050d4867f
commit
ccf1a1a953
@ -242,7 +242,6 @@ qt_internal_add_module(Gui
|
||||
text/qtextobject.cpp text/qtextobject.h text/qtextobject_p.h
|
||||
text/qtextoption.cpp text/qtextoption.h
|
||||
text/qtexttable.cpp text/qtexttable.h text/qtexttable_p.h
|
||||
text/qtextdocumentresourceprovider.cpp text/qtextdocumentresourceprovider.h
|
||||
util/qabstractlayoutstyleinfo.cpp util/qabstractlayoutstyleinfo_p.h
|
||||
util/qastchandler.cpp util/qastchandler_p.h
|
||||
util/qdesktopservices.cpp util/qdesktopservices.h
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "qtextdocumentfragment_p.h"
|
||||
#include "qtexttable.h"
|
||||
#include "qtextlist.h"
|
||||
#include "qtextdocumentresourceprovider.h"
|
||||
#include <qdebug.h>
|
||||
#if QT_CONFIG(regularexpression)
|
||||
#include <qregularexpression.h>
|
||||
@ -81,6 +80,9 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n);
|
||||
|
||||
namespace {
|
||||
QTextDocument::ResourceProvider qt_defaultResourceProvider;
|
||||
};
|
||||
|
||||
/*!
|
||||
Returns \c true if the string \a text is likely to be rich text;
|
||||
@ -2080,7 +2082,11 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
|
||||
the resource. loadResource should then use addResource to add the
|
||||
resource to the cache.
|
||||
|
||||
\sa QTextDocument::ResourceType
|
||||
If loadResource does not load the resource, then the resourceProvider and
|
||||
lastly the defaultResourceProvider will be called, if set. Note that the
|
||||
result from the provider will not be added automatically to the cache.
|
||||
|
||||
\sa QTextDocument::ResourceType, resourceProvider()
|
||||
*/
|
||||
QVariant QTextDocument::resource(int type, const QUrl &name) const
|
||||
{
|
||||
@ -2093,9 +2099,9 @@ QVariant QTextDocument::resource(int type, const QUrl &name) const
|
||||
r = const_cast<QTextDocument *>(this)->loadResource(type, url);
|
||||
if (!r.isValid()) {
|
||||
if (d->resourceProvider)
|
||||
r = d->resourceProvider->resource(url);
|
||||
else if (auto defaultProvider = QTextDocumentResourceProvider::defaultProvider())
|
||||
r = defaultProvider->resource(url);
|
||||
r = d->resourceProvider(url);
|
||||
else if (auto defaultProvider = defaultResourceProvider())
|
||||
r = defaultProvider(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2131,26 +2137,62 @@ void QTextDocument::addResource(int type, const QUrl &name, const QVariant &reso
|
||||
\since 6.1
|
||||
|
||||
Returns the resource provider for this text document.
|
||||
|
||||
\sa setResourceProvider(), defaultResourceProvider(), loadResource()
|
||||
*/
|
||||
QTextDocumentResourceProvider *QTextDocument::resourceProvider() const
|
||||
QTextDocument::ResourceProvider QTextDocument::resourceProvider() const
|
||||
{
|
||||
Q_D(const QTextDocument);
|
||||
return d->resourceProvider;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.1
|
||||
\typealias QTextDocument::ResourceProvider
|
||||
|
||||
Type alias for std::function\<QVariant(const QUrl&)\>.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 6.1
|
||||
|
||||
Sets the \a provider of resources for the text document.
|
||||
Sets the provider of resources for the text document to \a provider.
|
||||
|
||||
\note The text document \e{does not} take ownership of the \a provider.
|
||||
\sa resourceProvider(), loadResource()
|
||||
*/
|
||||
void QTextDocument::setResourceProvider(QTextDocumentResourceProvider *provider)
|
||||
void QTextDocument::setResourceProvider(const ResourceProvider &provider)
|
||||
{
|
||||
Q_D(QTextDocument);
|
||||
d->resourceProvider = provider;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.1
|
||||
|
||||
Sets the default resource provider to \a provider.
|
||||
|
||||
The default provider will be used by all QTextDocuments that don't have an
|
||||
explicit provider set.
|
||||
|
||||
\sa setResourceProvider(), loadResource()
|
||||
*/
|
||||
void QTextDocument::setDefaultResourceProvider(const ResourceProvider &provider)
|
||||
{
|
||||
qt_defaultResourceProvider = provider;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 6.1
|
||||
|
||||
Returns the default resource provider.
|
||||
|
||||
\sa resourceProvider(), loadResource()
|
||||
*/
|
||||
QTextDocument::ResourceProvider QTextDocument::defaultResourceProvider()
|
||||
{
|
||||
return qt_defaultResourceProvider;
|
||||
}
|
||||
|
||||
/*!
|
||||
Loads data of the specified \a type from the resource with the
|
||||
given \a name.
|
||||
@ -2168,7 +2210,7 @@ void QTextDocument::setResourceProvider(QTextDocumentResourceProvider *provider)
|
||||
or a QTextDocument itself then the default implementation tries
|
||||
to retrieve the data from the parent.
|
||||
|
||||
\sa QTextDocumentResourceProvider
|
||||
\sa QTextDocument::ResourceProvider
|
||||
*/
|
||||
QVariant QTextDocument::loadResource(int type, const QUrl &name)
|
||||
{
|
||||
|
@ -68,8 +68,6 @@ class QVariant;
|
||||
class QRectF;
|
||||
class QTextOption;
|
||||
class QTextCursor;
|
||||
class QTextDocumentResourceProvider;
|
||||
|
||||
|
||||
namespace Qt
|
||||
{
|
||||
@ -240,8 +238,13 @@ public:
|
||||
QVariant resource(int type, const QUrl &name) const;
|
||||
void addResource(int type, const QUrl &name, const QVariant &resource);
|
||||
|
||||
QTextDocumentResourceProvider *resourceProvider() const;
|
||||
void setResourceProvider(QTextDocumentResourceProvider *provider);
|
||||
using ResourceProvider = std::function<QVariant(const QUrl&)>;
|
||||
|
||||
QTextDocument::ResourceProvider resourceProvider() const;
|
||||
void setResourceProvider(const ResourceProvider &provider);
|
||||
|
||||
static QTextDocument::ResourceProvider defaultResourceProvider();
|
||||
static void setDefaultResourceProvider(const ResourceProvider &provider);
|
||||
|
||||
QList<QTextFormat> allFormats() const;
|
||||
|
||||
|
@ -52,7 +52,6 @@
|
||||
#include "qtextdocumentlayout_p.h"
|
||||
#include "qtexttable.h"
|
||||
#include "qtextengine_p.h"
|
||||
#include "qtextdocumentresourceprovider.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -366,7 +366,7 @@ private:
|
||||
QMap<int, QTextObject *> objects;
|
||||
QMap<QUrl, QVariant> resources;
|
||||
QMap<QUrl, QVariant> cachedResources;
|
||||
QTextDocumentResourceProvider *resourceProvider;
|
||||
QTextDocument::ResourceProvider resourceProvider;
|
||||
QString defaultStyleSheet;
|
||||
|
||||
int lastBlockCount;
|
||||
|
@ -1,100 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 Alexander Volkov <avolkov@astralinux.ru>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtextdocumentresourceprovider.h"
|
||||
|
||||
#include <QtCore/qatomic.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
\class QTextDocumentResourceProvider
|
||||
\inmodule QtGui
|
||||
\since 6.1
|
||||
\brief The QTextDocumentResourceProvider is the base class of resource providers for QTextDocument.
|
||||
|
||||
Override resource() in a subclass, and set a subclass instance on a text document via
|
||||
QTextDocument::setResourceProvider, or on a label via QLabel::setResourceProvider. This
|
||||
allows customizing how resources are loaded in rich text documents without having to subclass
|
||||
QTextDocument or QLabel, respectively.
|
||||
|
||||
\note An implementation should be thread-safe if it can be accessed from different threads,
|
||||
e.g. when the default resource provider lives in the main thread and a QTextDocument lives
|
||||
outside the main thread.
|
||||
*/
|
||||
|
||||
static QAtomicPointer<QTextDocumentResourceProvider> qt_provider;
|
||||
|
||||
/*!
|
||||
Destroys the resource provider.
|
||||
*/
|
||||
QTextDocumentResourceProvider::~QTextDocumentResourceProvider()
|
||||
{
|
||||
qt_provider.testAndSetRelease(this, nullptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn virtual QVariant QTextDocumentResourceProvider::resource(const QUrl &url) = 0;
|
||||
|
||||
Returns data specified by the \a url.
|
||||
|
||||
\sa QTextDocument::loadResource
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns the default resource provider.
|
||||
|
||||
\sa QTextDocument::loadResource
|
||||
*/
|
||||
QTextDocumentResourceProvider *QTextDocumentResourceProvider::defaultProvider()
|
||||
{
|
||||
return qt_provider.loadAcquire();
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the default resource provider to \a provider.
|
||||
|
||||
\sa QTextDocument::loadResource
|
||||
*/
|
||||
void QTextDocumentResourceProvider::setDefaultProvider(QTextDocumentResourceProvider *provider)
|
||||
{
|
||||
qt_provider.storeRelease(provider);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -1,63 +0,0 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 Alexander Volkov <avolkov@astralinux.ru>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QTEXTDOCUMENTRESOURCEPROVIDER_H
|
||||
#define QTEXTDOCUMENTRESOURCEPROVIDER_H
|
||||
|
||||
#include <QtGui/qtguiglobal.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
class Q_GUI_EXPORT QTextDocumentResourceProvider
|
||||
{
|
||||
Q_DISABLE_COPY(QTextDocumentResourceProvider)
|
||||
public:
|
||||
QTextDocumentResourceProvider() = default;
|
||||
virtual ~QTextDocumentResourceProvider();
|
||||
virtual QVariant resource(const QUrl &url) = 0;
|
||||
|
||||
static QTextDocumentResourceProvider *defaultProvider();
|
||||
static void setDefaultProvider(QTextDocumentResourceProvider *provider);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QTEXTDOCUMENTRESOURCEPROVIDER_H
|
@ -1429,7 +1429,7 @@ void QLabel::setTextFormat(Qt::TextFormat format)
|
||||
|
||||
Returns the resource provider for rich text of this label.
|
||||
*/
|
||||
QTextDocumentResourceProvider *QLabel::resourceProvider() const
|
||||
QTextDocument::ResourceProvider QLabel::resourceProvider() const
|
||||
{
|
||||
Q_D(const QLabel);
|
||||
return d->control ? d->control->document()->resourceProvider() : d->resourceProvider;
|
||||
@ -1442,7 +1442,7 @@ QTextDocumentResourceProvider *QLabel::resourceProvider() const
|
||||
|
||||
\note The label \e{does not} take ownership of the \a provider.
|
||||
*/
|
||||
void QLabel::setResourceProvider(QTextDocumentResourceProvider *provider)
|
||||
void QLabel::setResourceProvider(const QTextDocument::ResourceProvider &provider)
|
||||
{
|
||||
Q_D(QLabel);
|
||||
d->resourceProvider = provider;
|
||||
|
@ -43,13 +43,13 @@
|
||||
#include <QtWidgets/qtwidgetsglobal.h>
|
||||
#include <QtWidgets/qframe.h>
|
||||
#include <QtGui/qpicture.h>
|
||||
#include <QtGui/qtextdocument.h>
|
||||
|
||||
QT_REQUIRE_CONFIG(label);
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
class QTextDocumentResourceProvider;
|
||||
class QLabelPrivate;
|
||||
|
||||
class Q_WIDGETS_EXPORT QLabel : public QFrame
|
||||
@ -93,8 +93,8 @@ public:
|
||||
Qt::TextFormat textFormat() const;
|
||||
void setTextFormat(Qt::TextFormat);
|
||||
|
||||
QTextDocumentResourceProvider *resourceProvider() const;
|
||||
void setResourceProvider(QTextDocumentResourceProvider *provider);
|
||||
QTextDocument::ResourceProvider resourceProvider() const;
|
||||
void setResourceProvider(const QTextDocument::ResourceProvider &provider);
|
||||
|
||||
Qt::Alignment alignment() const;
|
||||
void setAlignment(Qt::Alignment);
|
||||
|
@ -154,7 +154,7 @@ public:
|
||||
#endif
|
||||
uint openExternalLinks : 1;
|
||||
// <-- space for more bit field values here
|
||||
QTextDocumentResourceProvider *resourceProvider;
|
||||
QTextDocument::ResourceProvider resourceProvider;
|
||||
|
||||
friend class QMessageBoxPrivate;
|
||||
};
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include <qimage.h>
|
||||
#include <qtextlayout.h>
|
||||
#include <QDomDocument>
|
||||
#include <qtextdocumentresourceprovider.h>
|
||||
#include "common.h"
|
||||
|
||||
// #define DEBUG_WRITE_OUTPUT
|
||||
@ -3596,27 +3595,40 @@ void tst_QTextDocument::clearUndoRedoStacks()
|
||||
QVERIFY(!doc.isUndoAvailable());
|
||||
}
|
||||
|
||||
class UrlResourceProvider : public QTextDocumentResourceProvider
|
||||
{
|
||||
public:
|
||||
QVariant resource(const QUrl &url) override
|
||||
{
|
||||
resourseUrl = url;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QUrl resourseUrl;
|
||||
};
|
||||
|
||||
void tst_QTextDocument::resourceProvider()
|
||||
{
|
||||
|
||||
int providerCalled = 0;
|
||||
QUrl providerUrl;
|
||||
auto provider = [&](const QUrl &url){
|
||||
providerUrl = url;
|
||||
++providerCalled;
|
||||
return QVariant(42);
|
||||
};
|
||||
const QUrl url("test://img");
|
||||
const QString html = QLatin1String("<img src='%1'/>").arg(url.toString());
|
||||
|
||||
QTextDocument doc;
|
||||
UrlResourceProvider resourceProvider;
|
||||
doc.setResourceProvider(&resourceProvider);
|
||||
QUrl url("test://img");
|
||||
doc.setHtml(QStringLiteral("<img src='%1'/>").arg(url.toString()));
|
||||
doc.resource(QTextDocument::UserResource, url);
|
||||
QCOMPARE(url, resourceProvider.resourseUrl);
|
||||
QVERIFY(!doc.resourceProvider());
|
||||
doc.setResourceProvider(provider);
|
||||
QVERIFY(doc.resourceProvider());
|
||||
|
||||
doc.setHtml(html);
|
||||
const QVariant res = doc.resource(QTextDocument::UserResource, url);
|
||||
QVERIFY(res.isValid());
|
||||
QCOMPARE(providerUrl, url);
|
||||
QCOMPARE(providerCalled, 1);
|
||||
|
||||
QVERIFY(!QTextDocument::defaultResourceProvider());
|
||||
QTextDocument::setDefaultResourceProvider(provider);
|
||||
QVERIFY(QTextDocument::defaultResourceProvider());
|
||||
|
||||
QTextDocument doc2;
|
||||
QVERIFY(!doc2.resourceProvider());
|
||||
doc2.setHtml(html);
|
||||
QVariant res2 = doc2.resource(QTextDocument::UserResource, url);
|
||||
QCOMPARE(res2, res);
|
||||
QCOMPARE(providerCalled, 2);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QTextDocument)
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include <qmessagebox.h>
|
||||
#include <qfontmetrics.h>
|
||||
#include <qmath.h>
|
||||
#include <qtextdocumentresourceprovider.h>
|
||||
#include <private/qlabel_p.h>
|
||||
|
||||
class Widget : public QWidget
|
||||
@ -599,27 +598,22 @@ void tst_QLabel::taskQTBUG_48157_dprMovie()
|
||||
QCOMPARE(label.sizeHint(), movie.currentPixmap().size() / movie.currentPixmap().devicePixelRatio());
|
||||
}
|
||||
|
||||
class UrlResourceProvider : public QTextDocumentResourceProvider
|
||||
{
|
||||
public:
|
||||
QVariant resource(const QUrl &url) override
|
||||
{
|
||||
resourseUrl = url;
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QUrl resourseUrl;
|
||||
};
|
||||
|
||||
void tst_QLabel::resourceProvider()
|
||||
{
|
||||
QLabel label;
|
||||
UrlResourceProvider resourceProvider;
|
||||
label.setResourceProvider(&resourceProvider);
|
||||
QUrl url("test://img");
|
||||
int providerCalled = 0;
|
||||
QUrl providerUrl;
|
||||
label.setResourceProvider([&](const QUrl &url){
|
||||
providerUrl = url;
|
||||
++providerCalled;
|
||||
return QVariant();
|
||||
});
|
||||
|
||||
const QUrl url("test://img");
|
||||
label.setText(QStringLiteral("<img src='%1'/>").arg(url.toString()));
|
||||
label.show();
|
||||
QCOMPARE(url, resourceProvider.resourseUrl);
|
||||
QCOMPARE(providerUrl, url);
|
||||
QVERIFY(providerCalled > 0);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QLabel)
|
||||
|
Loading…
Reference in New Issue
Block a user