Make text rendering working outside the gui thread on Symbian.

It was previously not possible to render text (QPainter::drawText)
in a secondary thread on Symbian, it always resulted in some
kind of panic. This patch corrects it. For S60 5.0 and earlier
the behavior is not changed, threaded text rendering is only
supported on Symbian^3 and newer. This also means
QFontDatabase::supportsThreadedFontRendering() will return
true from now on, but only on Symbian^3 and higher.

Task-number: QTBUG-18516
Reviewed-by: mread
(cherry picked from commit 0c62e02b80570bf8b92eff7acceb9018df61c89e)
This commit is contained in:
Laszlo Agocs 2011-04-26 15:35:51 +02:00 committed by Olivier Goffart
parent af6057918a
commit d4eedda7d2
3 changed files with 48 additions and 11 deletions

View File

@ -2703,6 +2703,9 @@ QS60ThreadLocalData::QS60ThreadLocalData()
QS60ThreadLocalData::~QS60ThreadLocalData()
{
for (int i = 0; i < releaseFuncs.count(); ++i)
releaseFuncs[i]();
releaseFuncs.clear();
if (!usingCONEinstances) {
delete screenDevice;
wsSession.Close();

View File

@ -97,6 +97,10 @@ static const int qt_symbian_max_screens = 4;
//this macro exists because EColor16MAP enum value doesn't exist in Symbian OS 9.2
#define Q_SYMBIAN_ECOLOR16MAP TDisplayMode(13)
class QSymbianTypeFaceExtras;
typedef QHash<QString, const QSymbianTypeFaceExtras *> QSymbianTypeFaceExtrasHash;
typedef void (*QThreadLocalReleaseFunc)();
class Q_AUTOTEST_EXPORT QS60ThreadLocalData
{
public:
@ -105,6 +109,8 @@ public:
bool usingCONEinstances;
RWsSession wsSession;
CWsScreenDevice *screenDevice;
QSymbianTypeFaceExtrasHash fontData;
QVector<QThreadLocalReleaseFunc> releaseFuncs;
};
class QS60Data
@ -175,6 +181,8 @@ public:
inline CWsScreenDevice* screenDevice(const QWidget *widget);
inline CWsScreenDevice* screenDevice(int screenNumber);
static inline int screenNumberForWidget(const QWidget *widget);
inline QSymbianTypeFaceExtrasHash& fontData();
inline void addThreadLocalReleaseFunc(QThreadLocalReleaseFunc func);
static inline CCoeAppUi* appUi();
static inline CEikMenuBar* menuBar();
#ifdef Q_WS_S60
@ -470,6 +478,24 @@ inline int QS60Data::screenNumberForWidget(const QWidget *widget)
return qt_widget_private(const_cast<QWidget *>(w))->symbianScreenNumber;
}
inline QSymbianTypeFaceExtrasHash& QS60Data::fontData()
{
if (!tls.hasLocalData()) {
tls.setLocalData(new QS60ThreadLocalData);
}
return tls.localData()->fontData;
}
inline void QS60Data::addThreadLocalReleaseFunc(QThreadLocalReleaseFunc func)
{
if (!tls.hasLocalData()) {
tls.setLocalData(new QS60ThreadLocalData);
}
QS60ThreadLocalData *data = tls.localData();
if (!data->releaseFuncs.contains(func))
data->releaseFuncs.append(func);
}
inline CCoeAppUi* QS60Data::appUi()
{
return CCoeEnv::Static()-> AppUi();

View File

@ -152,7 +152,6 @@ public:
COpenFontRasterizer *m_rasterizer;
mutable QList<const QSymbianTypeFaceExtras *> m_extras;
mutable QHash<QString, const QSymbianTypeFaceExtras *> m_extrasHash;
mutable QSet<QString> m_applicationFontFamilies;
};
@ -255,8 +254,9 @@ void QSymbianFontDatabaseExtrasImplementation::clear()
static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
if (!dbExtras)
return; // initializeDb() has never been called
QSymbianTypeFaceExtrasHash &extrasHash = S60->fontData();
if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
qDeleteAll(dbExtras->m_extrasHash);
qDeleteAll(extrasHash);
} else {
typedef QList<const QSymbianTypeFaceExtras *>::iterator iterator;
for (iterator p = dbExtras->m_extras.begin(); p != dbExtras->m_extras.end(); ++p) {
@ -265,11 +265,16 @@ void QSymbianFontDatabaseExtrasImplementation::clear()
}
dbExtras->m_extras.clear();
}
dbExtras->m_extrasHash.clear();
extrasHash.clear();
}
void qt_cleanup_symbianFontDatabase()
{
static bool cleanupDone = false;
if (cleanupDone)
return;
cleanupDone = true;
QFontDatabasePrivate *db = privateDb();
if (!db)
return;
@ -320,9 +325,12 @@ COpenFont* OpenFontFromBitmapFont(const CBitmapFont* aBitmapFont)
const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &aTypeface,
bool bold, bool italic) const
{
QSymbianTypeFaceExtrasHash &extrasHash = S60->fontData();
if (extrasHash.isEmpty() && QThread::currentThread() != QApplication::instance()->thread())
S60->addThreadLocalReleaseFunc(clear);
const QString typeface = qt_symbian_fontNameWithAppFontMarker(aTypeface);
const QString searchKey = typeface + QString::number(int(bold)) + QString::number(int(italic));
if (!m_extrasHash.contains(searchKey)) {
if (!extrasHash.contains(searchKey)) {
TFontSpec searchSpec(qt_QString2TPtrC(typeface), 1);
if (bold)
searchSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
@ -336,7 +344,7 @@ const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(c
QScopedPointer<CFont, CFontFromScreenDeviceReleaser> sFont(font);
QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font);
sFont.take();
m_extrasHash.insert(searchKey, extras);
extrasHash.insert(searchKey, extras);
} else {
const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, searchSpec);
Q_ASSERT(err == KErrNone && font);
@ -350,20 +358,20 @@ const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(c
const TOpenFontFaceAttrib* const attrib = openFont->FaceAttrib();
const QString foundKey =
QString((const QChar*)attrib->FullName().Ptr(), attrib->FullName().Length());
if (!m_extrasHash.contains(foundKey)) {
if (!extrasHash.contains(foundKey)) {
QScopedPointer<CFont, CFontFromFontStoreReleaser> sFont(font);
QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font, openFont);
sFont.take();
m_extras.append(extras);
m_extrasHash.insert(searchKey, extras);
m_extrasHash.insert(foundKey, extras);
extrasHash.insert(searchKey, extras);
extrasHash.insert(foundKey, extras);
} else {
m_store->ReleaseFont(font);
m_extrasHash.insert(searchKey, m_extrasHash.value(foundKey));
extrasHash.insert(searchKey, extrasHash.value(foundKey));
}
}
}
return m_extrasHash.value(searchKey);
return extrasHash.value(searchKey);
}
void QSymbianFontDatabaseExtrasImplementation::removeAppFontData(
@ -956,7 +964,7 @@ bool QFontDatabase::removeAllApplicationFonts()
bool QFontDatabase::supportsThreadedFontRendering()
{
return false;
return QSymbianTypeFaceExtras::symbianFontTableApiAvailable();
}
static