Windows/Linux: Cache cursors by mask/pixmap keys and shape.

Task-number: QTBUG-33383

Change-Id: I65a5a0870f50f42c26a4d297331224b3597a36e0
Reviewed-by: Andy Shaw <andy.shaw@digia.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
bb10
Friedemann Kleint 2013-10-01 15:00:55 +02:00 committed by The Qt Project
parent 8388b40108
commit 5ad1e2578b
4 changed files with 111 additions and 27 deletions

View File

@ -45,7 +45,7 @@
#include "qwindowswindow.h"
#include "qwindowsscreen.h"
#include <QtGui/QPixmap>
#include <QtGui/QBitmap>
#include <QtGui/QImage>
#include <QtGui/QBitmap>
#include <QtGui/QGuiApplication>
@ -60,6 +60,30 @@ QT_BEGIN_NAMESPACE
Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap);
/*!
\class QWindowsCursorCacheKey
\brief Cache key for storing values in a QHash with a QCursor as key.
\internal
\ingroup qt-lighthouse-win
*/
QWindowsCursorCacheKey::QWindowsCursorCacheKey(const QCursor &c)
: shape(c.shape()), bitmapCacheKey(0), maskCacheKey(0)
{
if (shape == Qt::BitmapCursor) {
const qint64 pixmapCacheKey = c.pixmap().cacheKey();
if (pixmapCacheKey) {
bitmapCacheKey = pixmapCacheKey;
} else {
Q_ASSERT(c.bitmap());
Q_ASSERT(c.mask());
bitmapCacheKey = c.bitmap()->cacheKey();
maskCacheKey = c.mask()->cacheKey();
}
}
}
/*!
\class QWindowsCursor
\brief Platform cursor implementation
@ -388,9 +412,10 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c)
QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape)
{
StandardCursorCache::iterator it = m_standardCursorCache.find(shape);
if (it == m_standardCursorCache.end())
it = m_standardCursorCache.insert(shape, QWindowsWindowCursor(QCursor(shape)));
const QWindowsCursorCacheKey key(shape);
CursorCache::iterator it = m_cursorCache.find(key);
if (it == m_cursorCache.end())
it = m_cursorCache.insert(key, QWindowsWindowCursor(QCursor(shape)));
return it.value();
}
@ -400,10 +425,10 @@ QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape)
QWindowsWindowCursor QWindowsCursor::pixmapWindowCursor(const QCursor &c)
{
const qint64 cacheKey = c.pixmap().cacheKey();
PixmapCursorCache::iterator it = m_pixmapCursorCache.find(cacheKey);
if (it == m_pixmapCursorCache.end())
it = m_pixmapCursorCache.insert(cacheKey, QWindowsWindowCursor(c));
const QWindowsCursorCacheKey cacheKey(c);
CursorCache::iterator it = m_cursorCache.find(cacheKey);
if (it == m_cursorCache.end())
it = m_cursorCache.insert(cacheKey, QWindowsWindowCursor(c));
return it.value();
}

View File

@ -52,6 +52,27 @@ QT_BEGIN_NAMESPACE
class QWindowsWindowCursorData;
struct QWindowsCursorCacheKey
{
explicit QWindowsCursorCacheKey(const QCursor &c);
explicit QWindowsCursorCacheKey(Qt::CursorShape s) : shape(s), bitmapCacheKey(0), maskCacheKey(0) {}
QWindowsCursorCacheKey() : shape(Qt::CustomCursor), bitmapCacheKey(0), maskCacheKey(0) {}
Qt::CursorShape shape;
qint64 bitmapCacheKey;
qint64 maskCacheKey;
};
inline bool operator==(const QWindowsCursorCacheKey &k1, const QWindowsCursorCacheKey &k2)
{
return k1.shape == k2.shape && k1.bitmapCacheKey == k2.bitmapCacheKey && k1.maskCacheKey == k2.maskCacheKey;
}
inline uint qHash(const QWindowsCursorCacheKey &k, uint seed) Q_DECL_NOTHROW
{
return (uint(k.shape) + uint(k.bitmapCacheKey) + uint(k.maskCacheKey)) ^ seed;
}
class QWindowsWindowCursor
{
public:
@ -86,11 +107,9 @@ public:
QWindowsWindowCursor pixmapWindowCursor(const QCursor &c);
private:
typedef QHash<Qt::CursorShape, QWindowsWindowCursor> StandardCursorCache;
typedef QHash<qint64, QWindowsWindowCursor> PixmapCursorCache;
typedef QHash<QWindowsCursorCacheKey, QWindowsWindowCursor> CursorCache;
StandardCursorCache m_standardCursorCache;
PixmapCursorCache m_pixmapCursorCache;
CursorCache m_cursorCache;
};
QT_END_NAMESPACE

View File

@ -272,6 +272,26 @@ static const char * const cursorNames[] = {
"link"
};
#ifndef QT_NO_CURSOR
QXcbCursorCacheKey::QXcbCursorCacheKey(const QCursor &c)
: shape(c.shape()), bitmapCacheKey(0), maskCacheKey(0)
{
if (shape == Qt::BitmapCursor) {
const qint64 pixmapCacheKey = c.pixmap().cacheKey();
if (pixmapCacheKey) {
bitmapCacheKey = pixmapCacheKey;
} else {
Q_ASSERT(c.bitmap());
Q_ASSERT(c.mask());
bitmapCacheKey = c.bitmap()->cacheKey();
maskCacheKey = c.mask()->cacheKey();
}
}
}
#endif // !QT_NO_CURSOR
QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
: QXcbObject(conn), m_screen(screen), m_gtkCursorThemeInitialized(false)
{
@ -318,9 +338,7 @@ QXcbCursor::~QXcbCursor()
if (!--cursorCount)
xcb_close_font(conn, cursorFont);
foreach (xcb_cursor_t cursor, m_bitmapCursorMap)
xcb_free_cursor(conn, cursor);
foreach (xcb_cursor_t cursor, m_shapeCursorMap)
foreach (xcb_cursor_t cursor, m_cursorHash)
xcb_free_cursor(conn, cursor);
}
@ -336,17 +354,13 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget)
xcb_cursor_t c = XCB_CURSOR_NONE;
if (cursor) {
if (cursor->shape() == Qt::BitmapCursor) {
qint64 id = cursor->pixmap().cacheKey();
if (!m_bitmapCursorMap.contains(id))
m_bitmapCursorMap.insert(id, createBitmapCursor(cursor));
c = m_bitmapCursorMap.value(id);
} else {
int id = cursor->shape();
if (!m_shapeCursorMap.contains(id))
m_shapeCursorMap.insert(id, createFontCursor(cursor->shape()));
c = m_shapeCursorMap.value(id);
const QXcbCursorCacheKey key(*cursor);
CursorHash::iterator it = m_cursorHash.find(key);
if (it == m_cursorHash.end()) {
const Qt::CursorShape shape = cursor->shape();
it = m_cursorHash.insert(key, shape == Qt::BitmapCursor ? createBitmapCursor(cursor) : createFontCursor(shape));
}
c = it.value();
}
w->setCursor(c);

View File

@ -47,6 +47,31 @@
QT_BEGIN_NAMESPACE
#ifndef QT_NO_CURSOR
struct QXcbCursorCacheKey
{
explicit QXcbCursorCacheKey(const QCursor &c);
explicit QXcbCursorCacheKey(Qt::CursorShape s) : shape(s), bitmapCacheKey(0), maskCacheKey(0) {}
QXcbCursorCacheKey() : shape(Qt::CustomCursor), bitmapCacheKey(0), maskCacheKey(0) {}
Qt::CursorShape shape;
qint64 bitmapCacheKey;
qint64 maskCacheKey;
};
inline bool operator==(const QXcbCursorCacheKey &k1, const QXcbCursorCacheKey &k2)
{
return k1.shape == k2.shape && k1.bitmapCacheKey == k2.bitmapCacheKey && k1.maskCacheKey == k2.maskCacheKey;
}
inline uint qHash(const QXcbCursorCacheKey &k, uint seed) Q_DECL_NOTHROW
{
return (uint(k.shape) + uint(k.bitmapCacheKey) + uint(k.maskCacheKey)) ^ seed;
}
#endif // !QT_NO_CURSOR
class QXcbCursor : public QXcbObject, public QPlatformCursor
{
public:
@ -62,6 +87,8 @@ public:
private:
#ifndef QT_NO_CURSOR
typedef QHash<QXcbCursorCacheKey, xcb_cursor_t> CursorHash;
xcb_cursor_t createFontCursor(int cshape);
xcb_cursor_t createBitmapCursor(QCursor *cursor);
xcb_cursor_t createNonStandardCursor(int cshape);
@ -69,8 +96,7 @@ private:
QXcbScreen *m_screen;
#ifndef QT_NO_CURSOR
QMap<int, xcb_cursor_t> m_shapeCursorMap;
QMap<qint64, xcb_cursor_t> m_bitmapCursorMap;
CursorHash m_cursorHash;
#endif
#ifdef XCB_USE_XLIB
static void cursorThemePropertyChanged(QXcbScreen *screen,