Cache accessibility plugins.

Profiling shows that the cost of QAcccessible::
queryAccessibleInterface is dominated by plugin loading.
(json parsing etc.)

Cache QAccessiblePlugin per class. Also cache the fact
that no plugin is found for a certain class. This speeds
up the average queryAccessibleInterface call by a factor
of 10X

Change-Id: Iab6d052dec499a2203d1dcc4672a8a543b279239
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@digia.com>
This commit is contained in:
Morten Johan Sorvig 2012-12-13 14:54:47 +01:00 committed by The Qt Project
parent 3f374afaae
commit 818c544d6b

View File

@ -51,6 +51,7 @@
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qmetaobject.h> #include <QtCore/qmetaobject.h>
#include <QtCore/qhash.h>
#include <private/qfactoryloader_p.h> #include <private/qfactoryloader_p.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -430,6 +431,8 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
#endif #endif
Q_GLOBAL_STATIC(QList<QAccessible::InterfaceFactory>, qAccessibleFactories) Q_GLOBAL_STATIC(QList<QAccessible::InterfaceFactory>, qAccessibleFactories)
typedef QHash<QString, QAccessiblePlugin*> QAccessiblePluginsHash;
Q_GLOBAL_STATIC(QAccessiblePluginsHash, qAccessiblePlugins);
QAccessible::UpdateHandler QAccessible::updateHandler = 0; QAccessible::UpdateHandler QAccessible::updateHandler = 0;
QAccessible::RootObjectHandler QAccessible::rootObjectHandler = 0; QAccessible::RootObjectHandler QAccessible::rootObjectHandler = 0;
@ -580,9 +583,13 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object)
if (!object) if (!object)
return 0; return 0;
// Create a QAccessibleInterface for the object class. Start by the most
// derived class and walk up the class hierarchy.
const QMetaObject *mo = object->metaObject(); const QMetaObject *mo = object->metaObject();
while (mo) { while (mo) {
const QString cn = QLatin1String(mo->className()); const QString cn = QLatin1String(mo->className());
// Check if the class has a InterfaceFactory installed.
for (int i = qAccessibleFactories()->count(); i > 0; --i) { for (int i = qAccessibleFactories()->count(); i > 0; --i) {
InterfaceFactory factory = qAccessibleFactories()->at(i - 1); InterfaceFactory factory = qAccessibleFactories()->at(i - 1);
if (QAccessibleInterface *iface = factory(cn, object)) if (QAccessibleInterface *iface = factory(cn, object))
@ -590,8 +597,21 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object)
} }
#ifndef QT_NO_ACCESSIBILITY #ifndef QT_NO_ACCESSIBILITY
#ifndef QT_NO_LIBRARY #ifndef QT_NO_LIBRARY
if (QAccessibleInterface * iface = qLoadPlugin1<QAccessibleInterface, QAccessiblePlugin>(loader(), cn, object)) // Find a QAccessiblePlugin (factory) for the class name. If there's
return iface; // no entry in the cache try to create it using the plugin loader.
if (!qAccessiblePlugins()->contains(cn)) {
QAccessiblePlugin *factory = 0; // 0 means "no plugin found". This is cached as well.
const int index = loader()->indexOf(cn);
if (index != -1)
factory = qobject_cast<QAccessiblePlugin *>(loader()->instance(index));
qAccessiblePlugins()->insert(cn, factory);
}
// At this point the cache should contain a valid factory pointer or 0:
Q_ASSERT(qAccessiblePlugins()->contains(cn));
QAccessiblePlugin *factory = qAccessiblePlugins()->value(cn);
if (factory)
return factory->create(cn, object);
#endif #endif
#endif #endif
mo = mo->superClass(); mo = mo->superClass();