summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp12
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h3
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h6
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp28
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h1
-rw-r--r--src/gui/image/image.pri15
-rw-r--r--src/gui/image/qnativeimagehandleprovider_p.h69
-rw-r--r--src/gui/image/qpixmap.cpp2
-rw-r--r--src/gui/image/qpixmap_raster.cpp3
-rw-r--r--src/gui/image/qpixmap_s60.cpp31
-rw-r--r--src/gui/image/qpixmapdata_p.h4
-rw-r--r--src/gui/image/qvolatileimage.cpp318
-rw-r--r--src/gui/image/qvolatileimage_p.h101
-rw-r--r--src/gui/image/qvolatileimagedata.cpp113
-rw-r--r--src/gui/image/qvolatileimagedata_p.h97
-rw-r--r--src/gui/image/qvolatileimagedata_symbian.cpp474
-rw-r--r--src/gui/inputmethod/qcoefepinputcontext_p.h11
-rw-r--r--src/gui/inputmethod/qcoefepinputcontext_s60.cpp251
-rw-r--r--src/gui/kernel/qapplication_p.h2
-rw-r--r--src/gui/kernel/qapplication_s60.cpp124
-rw-r--r--src/gui/kernel/qclipboard_win.cpp15
-rw-r--r--src/gui/kernel/qdesktopwidget_s60.cpp164
-rw-r--r--src/gui/kernel/qt_s60_p.h89
-rw-r--r--src/gui/kernel/qwidget.cpp10
-rw-r--r--src/gui/kernel/qwidget_p.h6
-rw-r--r--src/gui/kernel/qwidget_s60.cpp57
-rw-r--r--src/gui/math3d/qvector2d.cpp5
-rw-r--r--src/gui/math3d/qvector3d.cpp5
-rw-r--r--src/gui/math3d/qvector4d.cpp5
-rw-r--r--src/gui/painting/qbackingstore.cpp5
-rw-r--r--src/gui/painting/qgraphicssystem.cpp5
-rw-r--r--src/gui/painting/qgraphicssystem_p.h2
-rw-r--r--src/gui/painting/qgraphicssystem_runtime.cpp5
-rw-r--r--src/gui/painting/qpaintengine_s60.cpp21
-rw-r--r--src/gui/painting/qpainterpath.cpp8
-rw-r--r--src/gui/painting/qwindowsurface_s60.cpp28
-rw-r--r--src/gui/styles/qs60style.cpp58
-rw-r--r--src/gui/styles/qs60style_p.h12
-rw-r--r--src/gui/styles/qs60style_s60.cpp62
-rw-r--r--src/gui/styles/qs60style_simulated.cpp2
-rw-r--r--src/gui/text/qfontengine_mac.mm15
-rw-r--r--src/gui/text/qtextcontrol.cpp19
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp2
-rw-r--r--src/gui/text/qtextengine_mac.cpp5
-rw-r--r--src/gui/text/qtextlayout.cpp47
-rw-r--r--src/gui/text/qtextobject.cpp2
-rw-r--r--src/gui/widgets/qlinecontrol.cpp8
47 files changed, 2130 insertions, 197 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 265029b..a36a276 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -417,6 +417,11 @@
click focus to items underneath when being clicked on. This flag
allows you create a non-focusable item that can be clicked on without
changing the focus. \endomit
+
+ \omitvalue ItemStopsFocusHandling \omit Same as
+ ItemStopsClickFocusPropagation, but also suppresses focus-out. This flag
+ allows you to completely take over focus handling.
+ This flag was introduced in Qt 4.7.
*/
/*!
@@ -5579,8 +5584,10 @@ void QGraphicsItemPrivate::setSubFocus(QGraphicsItem *rootItem, QGraphicsItem *s
parent->d_ptr->subFocusItemChange();
} while (!parent->isPanel() && (parent = parent->d_ptr->parent) && (visible || !parent->d_ptr->visible));
- if (scene && !scene->isActive())
+ if (scene && !scene->isActive()) {
+ scene->d_func()->passiveFocusItem = subFocusItem;
scene->d_func()->lastFocusItem = subFocusItem;
+ }
}
/*!
@@ -11551,6 +11558,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
case QGraphicsItem::ItemStopsClickFocusPropagation:
str = "ItemStopsClickFocusPropagation";
break;
+ case QGraphicsItem::ItemStopsFocusHandling:
+ str = "ItemStopsFocusHandling";
+ break;
}
debug << str;
return debug;
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index e59a7c9..67c9cd3 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -107,7 +107,8 @@ public:
ItemIsPanel = 0x4000,
ItemIsFocusScope = 0x8000, // internal
ItemSendsScenePositionChanges = 0x10000,
- ItemStopsClickFocusPropagation = 0x20000
+ ItemStopsClickFocusPropagation = 0x20000,
+ ItemStopsFocusHandling = 0x40000
// NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag.
};
Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag)
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 5c82116..90ff43f 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -559,7 +559,7 @@ public:
quint32 dirtyChildrenBoundingRect : 1;
// Packed 32 bits
- quint32 flags : 18;
+ quint32 flags : 19;
quint32 paintedViewBoundingRectsNeedRepaint : 1;
quint32 dirtySceneTransform : 1;
quint32 geometryChanged : 1;
@@ -573,9 +573,9 @@ public:
quint32 sceneTransformTranslateOnly : 1;
quint32 notifyBoundingRectChanged : 1;
quint32 notifyInvalidated : 1;
- quint32 mouseSetsFocus : 1;
// New 32 bits
+ quint32 mouseSetsFocus : 1;
quint32 explicitActivate : 1;
quint32 wantsActive : 1;
quint32 holesInSiblingIndex : 1;
@@ -586,7 +586,7 @@ public:
quint32 mayHaveChildWithGraphicsEffect : 1;
quint32 isDeclarativeItem : 1;
quint32 sendParentChangeNotification : 1;
- quint32 padding : 22;
+ quint32 padding : 21;
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index f997fc2..85a4e16 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -306,6 +306,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
rectAdjust(2),
focusItem(0),
lastFocusItem(0),
+ passiveFocusItem(0),
tabFocusFirst(0),
activePanel(0),
lastActivePanel(0),
@@ -630,6 +631,8 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
focusItem = 0;
if (item == lastFocusItem)
lastFocusItem = 0;
+ if (item == passiveFocusItem)
+ passiveFocusItem = 0;
if (item == activePanel) {
// ### deactivate...
activePanel = 0;
@@ -1317,8 +1320,10 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
// Set focus on the topmost enabled item that can take focus.
bool setFocus = false;
+
foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
- if (item->isBlockedByModalPanel()) {
+ if (item->isBlockedByModalPanel()
+ || (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling)) {
// Make sure we don't clear focus.
setFocus = true;
break;
@@ -1331,10 +1336,10 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
break;
}
}
- if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
- break;
if (item->isPanel())
break;
+ if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
+ break;
}
// Check for scene modality.
@@ -2980,7 +2985,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *item)
QGraphicsItem *QGraphicsScene::focusItem() const
{
Q_D(const QGraphicsScene);
- return isActive() ? d->focusItem : d->lastFocusItem;
+ return isActive() ? d->focusItem : d->passiveFocusItem;
}
/*!
@@ -3054,6 +3059,7 @@ void QGraphicsScene::clearFocus()
Q_D(QGraphicsScene);
if (d->hasFocus) {
d->hasFocus = false;
+ d->passiveFocusItem = d->focusItem;
setFocusItem(0, Qt::OtherFocusReason);
}
}
@@ -3756,9 +3762,9 @@ void QGraphicsScene::focusInEvent(QFocusEvent *focusEvent)
focusEvent->ignore();
break;
default:
- if (d->lastFocusItem) {
+ if (d->passiveFocusItem) {
// Set focus on the last focus item
- setFocusItem(d->lastFocusItem, focusEvent->reason());
+ setFocusItem(d->passiveFocusItem, focusEvent->reason());
}
break;
}
@@ -3777,6 +3783,7 @@ void QGraphicsScene::focusOutEvent(QFocusEvent *focusEvent)
{
Q_D(QGraphicsScene);
d->hasFocus = false;
+ d->passiveFocusItem = d->focusItem;
setFocusItem(0, focusEvent->reason());
// Remove all popups when the scene loses focus.
@@ -5925,6 +5932,7 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve
// Set focus on the topmost enabled item that can take focus.
bool setFocus = false;
+
foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
@@ -5938,6 +5946,11 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve
break;
if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
break;
+ if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) {
+ // Make sure we don't clear focus.
+ setFocus = true;
+ break;
+ }
}
// If nobody could take focus, clear it.
@@ -5970,7 +5983,8 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve
}
if (item && item->isPanel())
break;
- if (item && (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation))
+ if (item && (item->d_ptr->flags
+ & (QGraphicsItem::ItemStopsClickFocusPropagation | QGraphicsItem::ItemStopsFocusHandling)))
break;
}
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index 815c70b..2b47105 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -150,6 +150,7 @@ public:
quint32 rectAdjust;
QGraphicsItem *focusItem;
QGraphicsItem *lastFocusItem;
+ QGraphicsItem *passiveFocusItem;
QGraphicsWidget *tabFocusFirst;
QGraphicsItem *activePanel;
QGraphicsItem *lastActivePanel;
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index f89706c..00dccbe 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -28,7 +28,10 @@ HEADERS += \
image/qpixmapdata_p.h \
image/qpixmapdatafactory_p.h \
image/qpixmapfilter_p.h \
- image/qimagepixmapcleanuphooks_p.h
+ image/qimagepixmapcleanuphooks_p.h \
+ image/qvolatileimage_p.h \
+ image/qvolatileimagedata_p.h \
+ image/qnativeimagehandleprovider_p.h
SOURCES += \
image/qbitmap.cpp \
@@ -51,7 +54,8 @@ SOURCES += \
image/qmovie.cpp \
image/qpixmap_raster.cpp \
image/qnativeimage.cpp \
- image/qimagepixmapcleanuphooks.cpp
+ image/qimagepixmapcleanuphooks.cpp \
+ image/qvolatileimage.cpp
win32 {
SOURCES += image/qpixmap_win.cpp
@@ -72,6 +76,13 @@ else:symbian {
SOURCES += image/qpixmap_s60.cpp
}
+!symbian|contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2) {
+ SOURCES += image/qvolatileimagedata.cpp
+}
+else {
+ SOURCES += image/qvolatileimagedata_symbian.cpp
+}
+
# Built-in image format support
HEADERS += \
image/qbmphandler_p.h \
diff --git a/src/gui/image/qnativeimagehandleprovider_p.h b/src/gui/image/qnativeimagehandleprovider_p.h
new file mode 100644
index 0000000..4e6ed38
--- /dev/null
+++ b/src/gui/image/qnativeimagehandleprovider_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNATIVEIMAGEHANDLEPROVIDER_P_H
+#define QNATIVEIMAGEHANDLEPROVIDER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNativeImageHandleProvider
+{
+public:
+ virtual void get(void **handle, QString *type) = 0;
+ virtual void release(void *handle, const QString &type) = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNATIVEIMAGEHANDLEPROVIDER_P_H
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index 0aefafb..1a83318 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -1997,7 +1997,7 @@ void QPixmap::detach()
}
if (data->is_cached && data->ref == 1)
- QImagePixmapCleanupHooks::executePixmapDataModificationHooks(pd);
+ QImagePixmapCleanupHooks::executePixmapDataModificationHooks(data.data());
#if defined(Q_WS_MAC)
QMacPixmapData *macData = id == QPixmapData::MacClass ? static_cast<QMacPixmapData*>(pd) : 0;
diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp
index 368600f..5e0ffa8 100644
--- a/src/gui/image/qpixmap_raster.cpp
+++ b/src/gui/image/qpixmap_raster.cpp
@@ -380,6 +380,9 @@ int QRasterPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
void QRasterPixmapData::createPixmapForImage(QImage &sourceImage, Qt::ImageConversionFlags flags, bool inPlace)
{
QImage::Format format;
+ if (flags & Qt::NoFormatConversion)
+ format = sourceImage.format();
+ else
#ifdef Q_WS_QWS
if (pixelType() == BitmapType) {
format = QImage::Format_Mono;
diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp
index ca5f133..32d8dd7 100644
--- a/src/gui/image/qpixmap_s60.cpp
+++ b/src/gui/image/qpixmap_s60.cpp
@@ -374,6 +374,8 @@ CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const
To be sure that QPixmap does not modify your original instance, you should
make a copy of your \c CFbsBitmap before calling this function.
If the CFbsBitmap is not valid this function will return a null QPixmap.
+ For performance reasons it is recommended to use a \a bitmap with a display
+ mode of EColor16MAP or EColor16MU whenever possible.
\warning This function is only available on Symbian OS.
@@ -599,6 +601,9 @@ bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect)
return res;
}
+Q_GUI_EXPORT int qt_defaultDpiX();
+Q_GUI_EXPORT int qt_defaultDpiY();
+
int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
{
if (!cfbsBitmap)
@@ -609,28 +614,18 @@ int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
return cfbsBitmap->SizeInPixels().iWidth;
case QPaintDevice::PdmHeight:
return cfbsBitmap->SizeInPixels().iHeight;
- case QPaintDevice::PdmWidthMM: {
- TInt twips = cfbsBitmap->SizeInTwips().iWidth;
- return (int)(twips * (25.4/KTwipsPerInch));
- }
- case QPaintDevice::PdmHeightMM: {
- TInt twips = cfbsBitmap->SizeInTwips().iHeight;
- return (int)(twips * (25.4/KTwipsPerInch));
- }
+ case QPaintDevice::PdmWidthMM:
+ return qRound(cfbsBitmap->SizeInPixels().iWidth * 25.4 / qt_defaultDpiX());
+ case QPaintDevice::PdmHeightMM:
+ return qRound(cfbsBitmap->SizeInPixels().iHeight * 25.4 / qt_defaultDpiY());
case QPaintDevice::PdmNumColors:
return TDisplayModeUtils::NumDisplayModeColors(cfbsBitmap->DisplayMode());
case QPaintDevice::PdmDpiX:
- case QPaintDevice::PdmPhysicalDpiX: {
- TReal inches = cfbsBitmap->SizeInTwips().iWidth / (TReal)KTwipsPerInch;
- TInt pixels = cfbsBitmap->SizeInPixels().iWidth;
- return pixels / inches;
- }
+ case QPaintDevice::PdmPhysicalDpiX:
+ return qt_defaultDpiX();
case QPaintDevice::PdmDpiY:
- case QPaintDevice::PdmPhysicalDpiY: {
- TReal inches = cfbsBitmap->SizeInTwips().iHeight / (TReal)KTwipsPerInch;
- TInt pixels = cfbsBitmap->SizeInPixels().iHeight;
- return pixels / inches;
- }
+ case QPaintDevice::PdmPhysicalDpiY:
+ return qt_defaultDpiY();
case QPaintDevice::PdmDepth:
return TDisplayModeUtils::NumDisplayModeBitsPerPixel(cfbsBitmap->DisplayMode());
default:
diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h
index 7699344..0d0d417 100644
--- a/src/gui/image/qpixmapdata_p.h
+++ b/src/gui/image/qpixmapdata_p.h
@@ -71,7 +71,9 @@ public:
#if defined(Q_OS_SYMBIAN)
enum NativeType {
FbsBitmap,
- SgImage
+ SgImage,
+ VolatileImage,
+ NativeImageHandleProvider
};
#endif
enum ClassId { RasterClass, X11Class, MacClass, DirectFBClass,
diff --git a/src/gui/image/qvolatileimage.cpp b/src/gui/image/qvolatileimage.cpp
new file mode 100644
index 0000000..098e9a1
--- /dev/null
+++ b/src/gui/image/qvolatileimage.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvolatileimage_p.h"
+#include "qvolatileimagedata_p.h"
+#include <QtGui/private/qpaintengine_raster_p.h>
+#include <QtGui/private/qpixmapdata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVolatileImagePaintEnginePrivate : public QRasterPaintEnginePrivate
+{
+public:
+ QVolatileImagePaintEnginePrivate() { }
+ QVolatileImage *img;
+};
+
+class QVolatileImagePaintEngine : public QRasterPaintEngine
+{
+ Q_DECLARE_PRIVATE(QVolatileImagePaintEngine)
+
+public:
+ QVolatileImagePaintEngine(QPaintDevice *device, QVolatileImage *img);
+ bool begin(QPaintDevice *device);
+ bool end();
+ void drawPixmap(const QPointF &p, const QPixmap &pm);
+ void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
+};
+
+QVolatileImage::QVolatileImage()
+ : d(new QVolatileImageData)
+{
+}
+
+QVolatileImage::QVolatileImage(int w, int h, QImage::Format format)
+ : d(new QVolatileImageData(w, h, format))
+{
+}
+
+QVolatileImage::QVolatileImage(const QImage &sourceImage)
+ : d(new QVolatileImageData(sourceImage))
+{
+}
+
+QVolatileImage::QVolatileImage(void *nativeImage, void *nativeMask)
+ : d(new QVolatileImageData(nativeImage, nativeMask))
+{
+}
+
+// Need non-inline, non-autogenerated copy ctor, dtor, op= to keep the
+// fwd declared QSharedData working.
+
+QVolatileImage::QVolatileImage(const QVolatileImage &other)
+ : d(other.d)
+{
+}
+
+QVolatileImage::~QVolatileImage()
+{
+}
+
+QVolatileImage &QVolatileImage::operator=(const QVolatileImage &rhs)
+{
+ d = rhs.d;
+ return *this;
+}
+
+bool QVolatileImage::isNull() const
+{
+ return d->image.isNull();
+}
+
+QImage::Format QVolatileImage::format() const
+{
+ return d->image.format();
+}
+
+int QVolatileImage::width() const
+{
+ return d->image.width();
+}
+
+int QVolatileImage::height() const
+{
+ return d->image.height();
+}
+
+int QVolatileImage::bytesPerLine() const
+{
+ return d->image.bytesPerLine();
+}
+
+int QVolatileImage::byteCount() const
+{
+ return d->image.byteCount();
+}
+
+int QVolatileImage::depth() const
+{
+ return d->image.depth();
+}
+
+bool QVolatileImage::hasAlphaChannel() const
+{
+ return d->image.hasAlphaChannel();
+}
+
+void QVolatileImage::beginDataAccess() const
+{
+ d->beginDataAccess();
+}
+
+void QVolatileImage::endDataAccess(bool readOnly) const
+{
+ d->endDataAccess(readOnly);
+}
+
+/*!
+ Access to pixel data via bits() or constBits() should be guarded by
+ begin/endDataAccess().
+ */
+uchar *QVolatileImage::bits()
+{
+ return d->image.bits();
+}
+
+const uchar *QVolatileImage::constBits() const
+{
+ return d->image.constBits();
+}
+
+bool QVolatileImage::ensureFormat(QImage::Format format)
+{
+ return d->ensureFormat(format);
+}
+
+/*!
+ This will always perform a copy of the pixel data.
+ */
+QImage QVolatileImage::toImage() const
+{
+ d->beginDataAccess();
+ QImage newImage = d->image.copy(); // no sharing allowed
+ d->endDataAccess(true);
+ return newImage;
+}
+
+/*!
+ Returns a reference to the image that is potentially using some native
+ buffer internally. Access to the image's pixel data should be guarded by
+ begin/endDataAccess(). Use it when there is a need for QImage APIs not provided
+ by this class. The returned QImage must never be shared or assigned to.
+ */
+QImage &QVolatileImage::imageRef() // non-const, in order to cause a detach
+{
+ d->ensureImage();
+ return d->image;
+}
+
+void *QVolatileImage::duplicateNativeImage() const
+{
+ return d->duplicateNativeImage();
+}
+
+void QVolatileImage::setAlphaChannel(const QPixmap &alphaChannel)
+{
+ ensureFormat(QImage::Format_ARGB32_Premultiplied);
+ beginDataAccess();
+ imageRef().setAlphaChannel(alphaChannel.toImage());
+ endDataAccess();
+ d->ensureImage();
+}
+
+void QVolatileImage::fill(uint pixelValue)
+{
+ beginDataAccess();
+ imageRef().fill(pixelValue);
+ endDataAccess();
+ d->ensureImage();
+}
+
+void QVolatileImage::copyFrom(QVolatileImage *source, const QRect &rect)
+{
+ if (source->isNull()) {
+ return;
+ }
+ QRect r = rect;
+ if (rect.isNull()) {
+ r = QRect(0, 0, source->width(), source->height());
+ }
+ source->beginDataAccess();
+ QImage &srcImgRef(source->imageRef());
+ int srcbpl = srcImgRef.bytesPerLine();
+ int srcbpp = srcImgRef.depth() / 8;
+ const uchar *sptr = srcImgRef.constBits() + r.y() * srcbpl;
+ beginDataAccess();
+ QImage &dstImgRef(imageRef());
+ int dstbpl = dstImgRef.bytesPerLine();
+ uchar *dptr = dstImgRef.bits();
+ for (int y = 0; y < r.height(); ++y) {
+ qMemCopy(dptr, sptr + r.x() * srcbpp, r.width() * srcbpp);
+ sptr += srcbpl;
+ dptr += dstbpl;
+ }
+ endDataAccess();
+ source->endDataAccess(true);
+}
+
+/*!
+ To be called from the PixmapData's paintEngine().
+ */
+QPaintEngine *QVolatileImage::paintEngine()
+{
+ if (!d->pengine) {
+ d->pengine = new QVolatileImagePaintEngine(&imageRef(), this);
+ }
+ return d->pengine;
+}
+
+QVolatileImagePaintEngine::QVolatileImagePaintEngine(QPaintDevice *device,
+ QVolatileImage *img)
+ : QRasterPaintEngine(*(new QVolatileImagePaintEnginePrivate), device)
+{
+ Q_D(QVolatileImagePaintEngine);
+ d->img = img;
+}
+
+bool QVolatileImagePaintEngine::begin(QPaintDevice *device)
+{
+ Q_D(QVolatileImagePaintEngine);
+ d->img->beginDataAccess();
+ return QRasterPaintEngine::begin(device);
+}
+
+bool QVolatileImagePaintEngine::end()
+{
+ Q_D(QVolatileImagePaintEngine);
+ bool ret = QRasterPaintEngine::end();
+ d->img->endDataAccess();
+ return ret;
+}
+
+// For non-RasterClass pixmaps drawPixmap() would call toImage() which is slow in
+// our case. Therefore drawPixmap() is rerouted to drawImage().
+
+void QVolatileImagePaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm)
+{
+#ifdef Q_OS_SYMBIAN
+ void *nativeData = pm.pixmapData()->toNativeType(QPixmapData::VolatileImage);
+ if (nativeData) {
+ QVolatileImage *img = static_cast<QVolatileImage *>(nativeData);
+ img->beginDataAccess();
+ QRasterPaintEngine::drawImage(p, img->imageRef());
+ img->endDataAccess(true);
+ } else {
+ QRasterPaintEngine::drawPixmap(p, pm);
+ }
+#else
+ QRasterPaintEngine::drawPixmap(p, pm);
+#endif
+}
+
+void QVolatileImagePaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
+{
+#ifdef Q_OS_SYMBIAN
+ void *nativeData = pm.pixmapData()->toNativeType(QPixmapData::VolatileImage);
+ if (nativeData) {
+ QVolatileImage *img = static_cast<QVolatileImage *>(nativeData);
+ img->beginDataAccess();
+ QRasterPaintEngine::drawImage(r, img->imageRef(), sr);
+ img->endDataAccess(true);
+ } else {
+ QRasterPaintEngine::drawPixmap(r, pm, sr);
+ }
+#else
+ QRasterPaintEngine::drawPixmap(r, pm, sr);
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qvolatileimage_p.h b/src/gui/image/qvolatileimage_p.h
new file mode 100644
index 0000000..fc5d6b1
--- /dev/null
+++ b/src/gui/image/qvolatileimage_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVOLATILEIMAGE_P_H
+#define QVOLATILEIMAGE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qimage.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVolatileImageData;
+
+class Q_GUI_EXPORT QVolatileImage
+{
+public:
+ QVolatileImage();
+ QVolatileImage(int w, int h, QImage::Format format);
+ explicit QVolatileImage(const QImage &sourceImage);
+ explicit QVolatileImage(void *nativeImage, void *nativeMask = 0);
+ QVolatileImage(const QVolatileImage &other);
+ ~QVolatileImage();
+ QVolatileImage &operator=(const QVolatileImage &rhs);
+
+ bool isNull() const;
+ QImage::Format format() const;
+ int width() const;
+ int height() const;
+ int bytesPerLine() const;
+ int byteCount() const;
+ int depth() const;
+ bool hasAlphaChannel() const;
+ void beginDataAccess() const;
+ void endDataAccess(bool readOnly = false) const;
+ uchar *bits();
+ const uchar *constBits() const;
+ bool ensureFormat(QImage::Format format);
+ QImage toImage() const;
+ QImage &imageRef();
+ QPaintEngine *paintEngine();
+ void setAlphaChannel(const QPixmap &alphaChannel);
+ void fill(uint pixelValue);
+ void *duplicateNativeImage() const;
+ void copyFrom(QVolatileImage *source, const QRect &rect);
+
+private:
+ QSharedDataPointer<QVolatileImageData> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QVOLATILEIMAGE_P_H
diff --git a/src/gui/image/qvolatileimagedata.cpp b/src/gui/image/qvolatileimagedata.cpp
new file mode 100644
index 0000000..51b5995
--- /dev/null
+++ b/src/gui/image/qvolatileimagedata.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvolatileimagedata_p.h"
+#include <QtGui/qpaintengine.h>
+
+QT_BEGIN_NAMESPACE
+
+QVolatileImageData::QVolatileImageData()
+ : pengine(0)
+{
+}
+
+QVolatileImageData::QVolatileImageData(int w, int h, QImage::Format format)
+ : pengine(0)
+{
+ image = QImage(w, h, format);
+}
+
+QVolatileImageData::QVolatileImageData(const QImage &sourceImage)
+ : pengine(0)
+{
+ image = sourceImage;
+}
+
+QVolatileImageData::QVolatileImageData(void *, void *)
+ : pengine(0)
+{
+ // Not supported.
+}
+
+QVolatileImageData::QVolatileImageData(const QVolatileImageData &other)
+{
+ image = other.image;
+ // The detach is not mandatory here but we do it nonetheless in order to
+ // keep the behavior consistent with other platforms.
+ image.detach();
+ pengine = 0;
+}
+
+QVolatileImageData::~QVolatileImageData()
+{
+ delete pengine;
+}
+
+void QVolatileImageData::beginDataAccess() const
+{
+ // nothing to do here
+}
+
+void QVolatileImageData::endDataAccess(bool readOnly) const
+{
+ Q_UNUSED(readOnly);
+ // nothing to do here
+}
+
+bool QVolatileImageData::ensureFormat(QImage::Format format)
+{
+ if (image.format() != format) {
+ image = image.convertToFormat(format);
+ }
+ return true;
+}
+
+void *QVolatileImageData::duplicateNativeImage() const
+{
+ return 0;
+}
+
+void QVolatileImageData::ensureImage()
+{
+ // nothing to do here
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qvolatileimagedata_p.h b/src/gui/image/qvolatileimagedata_p.h
new file mode 100644
index 0000000..dab1685
--- /dev/null
+++ b/src/gui/image/qvolatileimagedata_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVOLATILEIMAGEDATA_P_H
+#define QVOLATILEIMAGEDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qimage.h>
+#include <QtCore/qshareddata.h>
+
+#ifdef Q_OS_SYMBIAN
+class CFbsBitmap;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QVolatileImageData : public QSharedData
+{
+public:
+ QVolatileImageData();
+ QVolatileImageData(int w, int h, QImage::Format format);
+ QVolatileImageData(const QImage &sourceImage);
+ QVolatileImageData(void *nativeImage, void *nativeMask);
+ QVolatileImageData(const QVolatileImageData &other);
+ ~QVolatileImageData();
+
+ void beginDataAccess() const;
+ void endDataAccess(bool readOnly = false) const;
+ bool ensureFormat(QImage::Format format);
+ void *duplicateNativeImage() const;
+ void ensureImage();
+
+#ifdef Q_OS_SYMBIAN
+ void updateImage();
+ void initWithBitmap(CFbsBitmap *source);
+ void applyMask(CFbsBitmap *mask);
+ void ensureBitmap();
+ void release();
+ QVolatileImageData *next;
+ QVolatileImageData *prev;
+ CFbsBitmap *bitmap;
+#endif
+ QImage image;
+ QPaintEngine *pengine;
+};
+
+QT_END_NAMESPACE
+
+#endif // QVOLATILEIMAGEDATA_P_H
diff --git a/src/gui/image/qvolatileimagedata_symbian.cpp b/src/gui/image/qvolatileimagedata_symbian.cpp
new file mode 100644
index 0000000..6e2909b
--- /dev/null
+++ b/src/gui/image/qvolatileimagedata_symbian.cpp
@@ -0,0 +1,474 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvolatileimagedata_p.h"
+#include <fbs.h>
+#include <QtGui/private/qt_s60_p.h>
+#include <QtGui/qpaintengine.h>
+#include <QtGui/private/qimage_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static CFbsBitmap *rasterizeBitmap(CFbsBitmap *bitmap, TDisplayMode newMode)
+{
+ if (!bitmap) {
+ return 0;
+ }
+ QScopedPointer<CFbsBitmap> newBitmap(new CFbsBitmap);
+ if (newBitmap->Create(bitmap->SizeInPixels(), newMode) != KErrNone) {
+ qWarning("QVolatileImage: Failed to create new bitmap");
+ return 0;
+ }
+ CFbsBitmapDevice *bitmapDevice = 0;
+ CFbsBitGc *bitmapGc = 0;
+ QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(newBitmap.data()));
+ QScopedPointer<CFbsBitmapDevice> bitmapDevicePtr(bitmapDevice);
+ QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL());
+ bitmapGc->Activate(bitmapDevice);
+ bitmapGc->BitBlt(TPoint(), bitmap);
+ delete bitmapGc;
+ return newBitmap.take();
+}
+
+static inline TDisplayMode format2TDisplayMode(QImage::Format format)
+{
+ TDisplayMode mode;
+ switch (format) {
+ case QImage::Format_MonoLSB:
+ mode = EGray2;
+ break;
+ case QImage::Format_Indexed8:
+ mode = EColor256;
+ break;
+ case QImage::Format_RGB444:
+ mode = EColor4K;
+ break;
+ case QImage::Format_RGB16:
+ mode = EColor64K;
+ break;
+ case QImage::Format_RGB888:
+ mode = EColor16M;
+ break;
+ case QImage::Format_RGB32:
+ mode = EColor16MU;
+ break;
+ case QImage::Format_ARGB32:
+ mode = EColor16MA;
+ break;
+ case QImage::Format_ARGB32_Premultiplied:
+ mode = Q_SYMBIAN_ECOLOR16MAP;
+ break;
+ default:
+ mode = ENone;
+ break;
+ }
+ return mode;
+}
+
+static CFbsBitmap *imageToBitmap(const QImage &image)
+{
+ if (image.isNull()) {
+ return 0;
+ }
+ CFbsBitmap *bitmap = new CFbsBitmap;
+ if (bitmap->Create(TSize(image.width(), image.height()),
+ format2TDisplayMode(image.format())) == KErrNone) {
+ bitmap->BeginDataAccess();
+ uchar *dptr = reinterpret_cast<uchar *>(bitmap->DataAddress());
+ int bmpLineLen = bitmap->DataStride();
+ int imgLineLen = image.bytesPerLine();
+ if (bmpLineLen == imgLineLen) {
+ qMemCopy(dptr, image.constBits(), image.byteCount());
+ } else {
+ int len = qMin(bmpLineLen, imgLineLen);
+ const uchar *sptr = image.constBits();
+ for (int y = 0; y < image.height(); ++y) {
+ qMemCopy(dptr, sptr, len);
+ dptr += bmpLineLen;
+ sptr += imgLineLen;
+ }
+ }
+ bitmap->EndDataAccess();
+ } else {
+ qWarning("QVolatileImage: Failed to create source bitmap");
+ delete bitmap;
+ bitmap = 0;
+ }
+ return bitmap;
+}
+
+static CFbsBitmap *copyData(const QVolatileImageData &source)
+{
+ source.beginDataAccess();
+ CFbsBitmap *bmp = imageToBitmap(source.image);
+ source.endDataAccess();
+ return bmp;
+}
+
+static CFbsBitmap *convertData(const QVolatileImageData &source, QImage::Format newFormat)
+{
+ source.beginDataAccess();
+ QImage img = source.image.convertToFormat(newFormat);
+ CFbsBitmap *bmp = imageToBitmap(img);
+ source.endDataAccess();
+ return bmp;
+}
+
+static CFbsBitmap *duplicateBitmap(const CFbsBitmap &sourceBitmap)
+{
+ CFbsBitmap *bitmap = new CFbsBitmap;
+ if (bitmap->Duplicate(sourceBitmap.Handle()) != KErrNone) {
+ qWarning("QVolatileImage: Failed to duplicate source bitmap");
+ delete bitmap;
+ bitmap = 0;
+ }
+ return bitmap;
+}
+
+static CFbsBitmap *createBitmap(int w, int h, QImage::Format format)
+{
+ CFbsBitmap *bitmap = new CFbsBitmap;
+ if (bitmap->Create(TSize(w, h), format2TDisplayMode(format)) != KErrNone) {
+ qWarning("QVolatileImage: Failed to create source bitmap %d,%d (%d)", w, h, format);
+ delete bitmap;
+ bitmap = 0;
+ }
+ return bitmap;
+}
+
+static inline bool bitmapNeedsCopy(CFbsBitmap *bitmap)
+{
+ bool needsCopy = bitmap->IsCompressedInRAM();
+#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE
+ needsCopy |= (bitmap->ExtendedBitmapType() != KNullUid);
+#endif
+ return needsCopy;
+}
+
+static bool cleanup_function_registered = false;
+static QVolatileImageData *firstImageData = 0;
+
+static void cleanup()
+{
+ if (RFbsSession::GetSession()) {
+ QVolatileImageData *imageData = firstImageData;
+ while (imageData) {
+ imageData->release();
+ imageData = imageData->next;
+ }
+ }
+}
+
+static void ensureCleanup()
+{
+ // Destroy all underlying bitmaps in a post routine to prevent panics.
+ // This is a must because CFbsBitmap destructor needs the fbs session,
+ // that was used to create the bitmap, to be open still.
+ if (!cleanup_function_registered) {
+ qAddPostRoutine(cleanup);
+ cleanup_function_registered = true;
+ }
+}
+
+static void registerImageData(QVolatileImageData *imageData)
+{
+ ensureCleanup();
+ imageData->next = firstImageData;
+ if (firstImageData) {
+ firstImageData->prev = imageData;
+ }
+ firstImageData = imageData;
+}
+
+static void unregisterImageData(QVolatileImageData *imageData)
+{
+ if (imageData->prev) {
+ imageData->prev->next = imageData->next;
+ } else {
+ firstImageData = imageData->next;
+ }
+ if (imageData->next) {
+ imageData->next->prev = imageData->prev;
+ }
+}
+
+QVolatileImageData::QVolatileImageData()
+ : next(0), prev(0), bitmap(0), pengine(0)
+{
+ registerImageData(this);
+}
+
+QVolatileImageData::QVolatileImageData(int w, int h, QImage::Format format)
+ : next(0), prev(0), bitmap(0), pengine(0)
+{
+ registerImageData(this);
+ bitmap = createBitmap(w, h, format);
+ updateImage();
+}
+
+QVolatileImageData::QVolatileImageData(const QImage &sourceImage)
+ : next(0), prev(0), bitmap(0), pengine(0)
+{
+ registerImageData(this);
+ image = sourceImage;
+ // The following is not mandatory, but we do it here to have a bitmap
+ // created always in order to reduce local heap usage.
+ ensureBitmap();
+}
+
+QVolatileImageData::QVolatileImageData(void *nativeImage, void *nativeMask)
+ : next(0), prev(0), bitmap(0), pengine(0)
+{
+ registerImageData(this);
+ if (nativeImage) {
+ CFbsBitmap *source = static_cast<CFbsBitmap *>(nativeImage);
+ CFbsBitmap *mask = static_cast<CFbsBitmap *>(nativeMask);
+ initWithBitmap(source);
+ if (mask) {
+ applyMask(mask);
+ }
+ }
+}
+
+QVolatileImageData::QVolatileImageData(const QVolatileImageData &other)
+{
+ bitmap = 0;
+ pengine = 0;
+ next = prev = 0;
+ registerImageData(this);
+ if (!other.image.isNull()) {
+ bitmap = copyData(other);
+ updateImage();
+ }
+}
+
+QVolatileImageData::~QVolatileImageData()
+{
+ release();
+ unregisterImageData(this);
+}
+
+void QVolatileImageData::release()
+{
+ delete bitmap;
+ bitmap = 0;
+ delete pengine;
+ pengine = 0;
+}
+
+void QVolatileImageData::beginDataAccess() const
+{
+ if (bitmap) {
+ bitmap->BeginDataAccess();
+ }
+}
+
+void QVolatileImageData::endDataAccess(bool readOnly) const
+{
+ if (bitmap) {
+ bitmap->EndDataAccess(readOnly);
+ }
+}
+
+bool QVolatileImageData::ensureFormat(QImage::Format format)
+{
+ if (image.isNull()) {
+ return false;
+ }
+ if (image.format() != format) {
+ CFbsBitmap *newBitmap = convertData(*this, format);
+ if (newBitmap && newBitmap != bitmap) {
+ delete bitmap;
+ bitmap = newBitmap;
+ updateImage();
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+void *QVolatileImageData::duplicateNativeImage() const
+{
+ const_cast<QVolatileImageData *>(this)->ensureBitmap();
+ if (bitmap) {
+ if (bitmap->DisplayMode() == EColor16M) {
+ // slow path: needs rgb swapping
+ beginDataAccess();
+ QImage tmp = image.rgbSwapped();
+ endDataAccess(true);
+ return imageToBitmap(tmp);
+ } else if (bitmap->DisplayMode() == EGray2) {
+ // slow path: needs inverting pixels
+ beginDataAccess();
+ QImage tmp = image.copy();
+ endDataAccess(true);
+ tmp.invertPixels();
+ return imageToBitmap(tmp);
+ } else {
+ // fast path: just duplicate the bitmap
+ return duplicateBitmap(*bitmap);
+ }
+ }
+ return 0;
+}
+
+void QVolatileImageData::updateImage()
+{
+ if (bitmap) {
+ TSize size = bitmap->SizeInPixels();
+ beginDataAccess();
+ // Use existing buffer, no copy. The data address never changes so it
+ // is enough to do this whenever we have a new CFbsBitmap. N.B. never
+ // use const uchar* here, that would create a read-only image data which
+ // would make a copy in detach() even when refcount is 1.
+ image = QImage(reinterpret_cast<uchar *>(bitmap->DataAddress()),
+ size.iWidth, size.iHeight, bitmap->DataStride(),
+ qt_TDisplayMode2Format(bitmap->DisplayMode()));
+ endDataAccess(true);
+ } else {
+ image = QImage();
+ }
+}
+
+void QVolatileImageData::initWithBitmap(CFbsBitmap *source)
+{
+ bool needsCopy = bitmapNeedsCopy(source);
+ if (source->DisplayMode() == EColor16M) {
+ // EColor16M is BGR
+ CFbsBitmap *unswappedBmp = source;
+ if (needsCopy) {
+ unswappedBmp = rasterizeBitmap(source, source->DisplayMode());
+ }
+ unswappedBmp->BeginDataAccess();
+ TSize sourceSize = unswappedBmp->SizeInPixels();
+ QImage img((uchar *) unswappedBmp->DataAddress(),
+ sourceSize.iWidth, sourceSize.iHeight, unswappedBmp->DataStride(),
+ qt_TDisplayMode2Format(unswappedBmp->DisplayMode()));
+ img = img.rgbSwapped();
+ unswappedBmp->EndDataAccess(true);
+ bitmap = imageToBitmap(img);
+ if (needsCopy) {
+ delete unswappedBmp;
+ }
+ } else if (needsCopy) {
+ // Rasterize extended and compressed bitmaps.
+ bitmap = rasterizeBitmap(source, EColor16MAP);
+ } else if (source->DisplayMode() == EGray2) {
+ // The pixels will be inverted, must make a copy.
+ bitmap = rasterizeBitmap(source, source->DisplayMode());
+ } else {
+ // Efficient path: no pixel data copying. Just duplicate. This of course
+ // means the original bitmap's data may get modified, but that's fine
+ // and is in accordance with the QPixmap::fromSymbianCFbsBitmap() docs.
+ bitmap = duplicateBitmap(*source);
+ }
+ updateImage();
+ if (bitmap && bitmap->DisplayMode() == EGray2) {
+ // Symbian thinks set pixels are white/transparent, Qt thinks they are
+ // foreground/solid. Invert mono bitmaps so that masks work correctly.
+ beginDataAccess();
+ image.invertPixels();
+ endDataAccess();
+ }
+}
+
+void QVolatileImageData::applyMask(CFbsBitmap *mask)
+{
+ ensureFormat(QImage::Format_ARGB32_Premultiplied);
+ bool destroyMask = false;
+ if (bitmapNeedsCopy(mask)) {
+ mask = rasterizeBitmap(mask, EColor16MU);
+ if (!mask) {
+ return;
+ }
+ destroyMask = true;
+ }
+ mask->BeginDataAccess();
+ TSize maskSize = mask->SizeInPixels();
+ QImage maskImg((const uchar *) mask->DataAddress(), maskSize.iWidth, maskSize.iHeight,
+ mask->DataStride(), qt_TDisplayMode2Format(mask->DisplayMode()));
+ if (mask->DisplayMode() == EGray2) {
+ maskImg = maskImg.copy();
+ maskImg.invertPixels();
+ }
+ beginDataAccess();
+ image.setAlphaChannel(maskImg);
+ endDataAccess();
+ mask->EndDataAccess(true);
+ ensureImage();
+ if (destroyMask) {
+ delete mask;
+ }
+}
+
+void QVolatileImageData::ensureImage()
+{
+ if (bitmap && !image.isNull()) {
+ QImageData *imaged = image.data_ptr();
+ if (imaged->ref != 1 || imaged->ro_data) {
+ // This is bad, the imagedata got shared somehow. Detach, in order to
+ // have the next check fail and thus have 'image' recreated.
+ beginDataAccess();
+ image.detach();
+ endDataAccess(true);
+ }
+ }
+ if (bitmap && image.constBits() != reinterpret_cast<const uchar *>(bitmap->DataAddress())) {
+ // Should not ever get here. If we do it means that either 'image' has
+ // been replaced with a copy (e.g. because some QImage API assigned a
+ // new, regular QImage to *this) or the bitmap's data address changed
+ // unexpectedly.
+ qWarning("QVolatileImageData: Ptr mismatch");
+ // Recover by recreating the image so that it uses the bitmap as its buffer.
+ updateImage();
+ }
+}
+
+void QVolatileImageData::ensureBitmap()
+{
+ if (!bitmap && !image.isNull()) {
+ bitmap = imageToBitmap(image);
+ updateImage();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/inputmethod/qcoefepinputcontext_p.h b/src/gui/inputmethod/qcoefepinputcontext_p.h
index 8c8ffd4..de3577f 100644
--- a/src/gui/inputmethod/qcoefepinputcontext_p.h
+++ b/src/gui/inputmethod/qcoefepinputcontext_p.h
@@ -93,6 +93,9 @@ public:
TCoeInputCapabilities inputCapabilities();
+ void resetSplitViewWidget(bool keepInputWidget = false);
+ void ensureFocusWidgetVisible(QWidget *widget);
+
protected:
void timerEvent(QTimerEvent *timerEvent);
@@ -104,9 +107,11 @@ private:
void queueInputCapabilitiesChanged();
bool needsInputPanel();
void commitTemporaryPreeditString();
+ bool isWidgetVisible(QWidget *widget, int offset = 0);
private Q_SLOTS:
void ensureInputCapabilitiesChanged();
+ void translateInputWidget();
// From MCoeFepAwareTextEditor
public:
@@ -155,9 +160,15 @@ private:
QBasicTimer m_tempPreeditStringTimeout;
bool m_hasTempPreeditString;
+ int m_splitViewResizeBy;
+ Qt::WindowStates m_splitViewPreviousWindowStates;
+ QRectF m_transformation;
+
friend class tst_QInputContext;
};
+Q_GUI_EXPORT void qt_s60_setPartialScreenInputMode(bool enable);
+
QT_END_NAMESPACE
#endif // QT_NO_IM
diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp
index 1bef64d..9d8dd41 100644
--- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp
+++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp
@@ -48,6 +48,8 @@
#include <qgraphicsscene.h>
#include <qgraphicswidget.h>
#include <qsymbianevent.h>
+#include <qlayout.h>
+#include <qdesktopwidget.h>
#include <private/qcore_symbian_p.h>
#include <fepitfr.h>
@@ -67,8 +69,16 @@
// that support text selection.
#define QT_EAknEditorFlagSelectionVisible 0x100000
+// EAknEditorFlagEnablePartialScreen is only valid from Sym^3 onwards.
+#define QT_EAknEditorFlagEnablePartialScreen 0x200000
+
QT_BEGIN_NAMESPACE
+Q_GUI_EXPORT void qt_s60_setPartialScreenInputMode(bool enable)
+{
+ S60->partial_keyboard = enable;
+}
+
QCoeFepInputContext::QCoeFepInputContext(QObject *parent)
: QInputContext(parent),
m_fepState(q_check_ptr(new CAknEdwinState)), // CBase derived object needs check on new
@@ -80,13 +90,19 @@ QCoeFepInputContext::QCoeFepInputContext(QObject *parent)
m_inlinePosition(0),
m_formatRetriever(0),
m_pointerHandler(0),
- m_hasTempPreeditString(false)
+ m_hasTempPreeditString(false),
+ m_splitViewResizeBy(0),
+ m_splitViewPreviousWindowStates(Qt::WindowNoState)
{
m_fepState->SetObjectProvider(this);
- if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0)
- m_fepState->SetFlags(EAknEditorFlagDefault | QT_EAknEditorFlagSelectionVisible);
- else
- m_fepState->SetFlags(EAknEditorFlagDefault);
+ int defaultFlags = EAknEditorFlagDefault;
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) {
+ if (S60->partial_keyboard) {
+ defaultFlags |= QT_EAknEditorFlagEnablePartialScreen;
+ }
+ defaultFlags |= QT_EAknEditorFlagSelectionVisible;
+ }
+ m_fepState->SetFlags(defaultFlags);
m_fepState->SetDefaultInputMode( EAknEditorTextInputMode );
m_fepState->SetPermittedInputModes( EAknEditorAllInputModes );
m_fepState->SetDefaultCase( EAknEditorTextCase );
@@ -210,6 +226,21 @@ bool QCoeFepInputContext::filterEvent(const QEvent *event)
return false;
switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ // Alphanumeric keypad doesn't like it when we click and text is still getting displayed
+ // It ignores the mouse event, so we need to commit and send a selection event (which will get triggered
+ // after the commit)
+ if (!m_preeditString.isEmpty()) {
+ commitCurrentString(false);
+
+ int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
+
+ QList<QInputMethodEvent::Attribute> selectAttributes;
+ selectAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos, 0, QVariant());
+ QInputMethodEvent selectEvent(QLatin1String(""), selectAttributes);
+ sendEvent(selectEvent);
+ }
+ break;
case QEvent::KeyPress:
commitTemporaryPreeditString();
// fall through intended
@@ -343,6 +374,165 @@ TCoeInputCapabilities QCoeFepInputContext::inputCapabilities()
return TCoeInputCapabilities(m_textCapabilities, this, 0);
}
+void QCoeFepInputContext::resetSplitViewWidget(bool keepInputWidget)
+{
+ QGraphicsView *gv = qobject_cast<QGraphicsView*>(S60->splitViewLastWidget);
+
+ if (!gv) {
+ return;
+ }
+
+ QSymbianControl *symControl = static_cast<QSymbianControl*>(gv->effectiveWinId());
+ symControl->CancelLongTapTimer();
+
+ const bool alwaysResize = (gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff);
+ QWidget *windowToMove = gv->window();
+
+ bool userResize = gv->testAttribute(Qt::WA_Resized);
+
+ windowToMove->setUpdatesEnabled(false);
+
+ if (!alwaysResize) {
+ if (gv->scene()) {
+ if (gv->scene()->focusItem())
+ disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget()));
+ QGraphicsItem *rootItem;
+ foreach (QGraphicsItem *item, gv->scene()->items()) {
+ if (!item->parentItem()) {
+ rootItem = item;
+ break;
+ }
+ }
+ if (rootItem)
+ rootItem->resetTransform();
+ }
+ } else {
+ if (m_splitViewResizeBy)
+ gv->resize(gv->rect().width(), m_splitViewResizeBy);
+ }
+ // Resizing might have led to widget losing its original windowstate.
+ // Restore previous window state.
+
+ if (m_splitViewPreviousWindowStates != windowToMove->windowState())
+ windowToMove->setWindowState(m_splitViewPreviousWindowStates);
+
+ windowToMove->setUpdatesEnabled(true);
+
+ gv->setAttribute(Qt::WA_Resized, userResize); //not a user resize
+
+ m_splitViewResizeBy = 0;
+ if (!keepInputWidget) {
+ m_splitViewPreviousWindowStates = Qt::WindowNoState;
+ S60->splitViewLastWidget = 0;
+ }
+}
+
+// Checks if a given widget is visible in the splitview rect. The offset
+// parameter can be used to validate if moving widget upwards or downwards
+// by the offset would make a difference for the visibility.
+
+bool QCoeFepInputContext::isWidgetVisible(QWidget *widget, int offset)
+{
+ bool visible = false;
+ if (widget) {
+ QRect splitViewRect = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+ QWidget *window = QApplication::activeWindow();
+ QGraphicsView *gv = qobject_cast<QGraphicsView*>(widget);
+ if (gv && window) {
+ if (QGraphicsScene *scene = gv->scene()) {
+ if (QGraphicsItem *focusItem = scene->focusItem()) {
+ QPoint cursorPos = window->mapToGlobal(focusItem->cursor().pos());
+ cursorPos.setY(cursorPos.y() + offset);
+ if (splitViewRect.contains(cursorPos)) {
+ visible = true;
+ }
+ }
+ }
+ }
+ }
+ return visible;
+}
+
+// Ensure that the input widget is visible in the splitview rect.
+
+void QCoeFepInputContext::ensureFocusWidgetVisible(QWidget *widget)
+{
+ // Native side opening and closing its virtual keyboard when it changes the keyboard layout,
+ // has an adverse impact on long tap timer. Cancel the timer when splitview opens to avoid this.
+ QSymbianControl *symControl = static_cast<QSymbianControl*>(widget->effectiveWinId());
+ symControl->CancelLongTapTimer();
+
+ // Graphicsviews that have vertical scrollbars should always be resized to the splitview area.
+ // Graphicsviews without scrollbars should be translated.
+
+ QGraphicsView *gv = qobject_cast<QGraphicsView*>(widget);
+ if (!gv)
+ return;
+
+ const bool alwaysResize = (gv && gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff);
+ const bool moveWithinVisibleArea = (S60->splitViewLastWidget != 0);
+
+ QWidget *windowToMove = gv ? gv : symControl->widget();
+ if (!windowToMove->isWindow())
+ windowToMove = windowToMove->window();
+ if (!windowToMove) {
+ return;
+ }
+
+ // When opening the keyboard (not moving within the splitview area), save the original
+ // window state. In some cases, ensuring input widget visibility might lead to window
+ // states getting changed.
+
+ if (!moveWithinVisibleArea) {
+ S60->splitViewLastWidget = widget;
+ m_splitViewPreviousWindowStates = windowToMove->windowState();
+ }
+
+ int windowTop = widget->window()->pos().y();
+
+ const bool userResize = widget->testAttribute(Qt::WA_Resized);
+
+ QRect splitViewRect = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+
+
+ // When resizing a window widget, it will lose its maximized window state.
+ // Native applications hide statuspane in splitview state, so lets move to
+ // fullscreen mode. This makes available area slightly bigger, which helps usability
+ // and greatly reduces event passing in orientation switch cases,
+ // as the statuspane size is not changing.
+
+ if (!(windowToMove->windowState() & Qt::WindowFullScreen)) {
+ windowToMove->setWindowState(
+ (windowToMove->windowState() & ~(Qt::WindowMinimized | Qt::WindowFullScreen)) | Qt::WindowFullScreen);
+ }
+
+ if (alwaysResize) {
+ windowToMove->setUpdatesEnabled(false);
+ if (!moveWithinVisibleArea)
+ m_splitViewResizeBy = widget->height();
+
+ windowTop = widget->geometry().top();
+ widget->resize(widget->width(), splitViewRect.height() - windowTop);
+
+ if (gv->scene()) {
+ const QRectF microFocusRect = gv->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
+ gv->ensureVisible(microFocusRect);
+ }
+ windowToMove->setUpdatesEnabled(true);
+ } else {
+ if (!moveWithinVisibleArea) {
+ // Check if the widget contains cursorPositionChanged signal and connect to it.
+ const char *signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged())).constData();
+ int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal + 1);
+ if (index != -1)
+ connect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget()));
+ }
+ translateInputWidget();
+ }
+
+ widget->setAttribute(Qt::WA_Resized, userResize); //not a user resize
+}
+
static QTextCharFormat qt_TCharFormat2QTextCharFormat(const TCharFormat &cFormat, bool validStyleColor)
{
QTextCharFormat qFormat;
@@ -474,10 +664,12 @@ void QCoeFepInputContext::applyHints(Qt::InputMethodHints hints)
m_fepState->SetPermittedCases(flags);
ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateCaseModeUpdate);
- if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0)
- flags = QT_EAknEditorFlagSelectionVisible;
- else
- flags = 0;
+ flags = 0;
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) {
+ if (S60->partial_keyboard)
+ flags |= QT_EAknEditorFlagEnablePartialScreen;
+ flags |= QT_EAknEditorFlagSelectionVisible;
+ }
if (hints & ImhUppercaseOnly && !(hints & ImhLowercaseOnly)
|| hints & ImhLowercaseOnly && !(hints & ImhUppercaseOnly)) {
flags |= EAknEditorFlagFixedCase;
@@ -604,6 +796,47 @@ void QCoeFepInputContext::ensureInputCapabilitiesChanged()
m_pendingInputCapabilitiesChanged = false;
}
+void QCoeFepInputContext::translateInputWidget()
+{
+ QGraphicsView *gv = qobject_cast<QGraphicsView *>(S60->splitViewLastWidget);
+ QRect splitViewRect = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+
+ QRectF cursor = gv->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
+ QPolygon cursorP = gv->mapFromScene(cursor);
+ QRectF vkbRect = QRectF(splitViewRect.bottomLeft(), qApp->desktop()->rect().bottomRight());
+ if (cursor.isEmpty() || vkbRect.isEmpty())
+ return;
+
+ // Fetch root item (i.e. graphicsitem with no parent)
+ QGraphicsItem *rootItem;
+ foreach (QGraphicsItem *item, gv->scene()->items()) {
+ if (!item->parentItem()) {
+ rootItem = item;
+ break;
+ }
+ }
+ if (!rootItem)
+ return;
+
+ m_transformation = (rootItem->transform().isTranslating()) ? QRectF(0,0, gv->width(), rootItem->transform().dy()) : QRectF();
+
+ // Do nothing if the cursor is visible in the splitview area.
+ if (splitViewRect.contains(cursorP.boundingRect()))
+ return;
+
+ // New Y position should be ideally at the center of the splitview area.
+ // If that would expose unpainted canvas, limit the tranformation to the visible scene bottom.
+
+ const qreal maxY = gv->sceneRect().bottom() - splitViewRect.bottom() + m_transformation.height();
+ qreal dy = -(qMin(maxY, (cursor.bottom() - vkbRect.top() / 2)));
+
+ // Do not allow transform above screen top.
+ if (m_transformation.height() + dy > 0)
+ return;
+
+ rootItem->setTransform(QTransform::fromTranslate(0, dy), true);
+}
+
void QCoeFepInputContext::StartFepInlineEditL(const TDesC& aInitialInlineText,
TInt aPositionOfInsertionPointInInlineText, TBool aCursorVisibility, const MFormCustomDraw* /*aCustomDraw*/,
MFepInlineTextFormatRetriever& aInlineTextFormatRetriever,
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index 43634ef..3d2c9d6 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -599,6 +599,8 @@ public:
int pressureSupported;
int maxTouchPressure;
QList<QTouchEvent::TouchPoint> appAllTouchPoints;
+
+ bool useTranslucentEGLSurfaces;
#endif
private:
diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp
index fb0c6b8..2b10d63 100644
--- a/src/gui/kernel/qapplication_s60.cpp
+++ b/src/gui/kernel/qapplication_s60.cpp
@@ -96,6 +96,9 @@ QT_BEGIN_NAMESPACE
// Goom Events through Window Server
static const int KGoomMemoryLowEvent = 0x10282DBF;
static const int KGoomMemoryGoodEvent = 0x20026790;
+// Split view open/close events from AVKON
+static const int KSplitViewOpenEvent = 0x2001E2C0;
+static const int KSplitViewCloseEvent = 0x2001E2C1;
#if defined(QT_DEBUG)
static bool appNoGrab = false; // Grabbing enabled
@@ -401,6 +404,7 @@ QSymbianControl::QSymbianControl(QWidget *w)
, m_longTapDetector(0)
, m_ignoreFocusChanged(0)
, m_symbianPopupIsOpen(0)
+ , m_inExternalScreenOverride(false)
{
}
@@ -408,9 +412,11 @@ void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
{
if (!desktop)
{
- if (isWindowOwning || !qwidget->parentWidget())
- CreateWindowL(S60->windowGroup());
- else
+ if (isWindowOwning || !qwidget->parentWidget()
+ || qwidget->parentWidget()->windowType() == Qt::Desktop) {
+ RWindowGroup &wg(S60->windowGroup(qwidget));
+ CreateWindowL(wg);
+ } else {
/**
* TODO: in order to avoid creating windows for all ancestors of
* this widget up to the root window, the parameter passed to
@@ -420,6 +426,7 @@ void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
* is created for a widget between this one and the root window.
*/
CreateWindowL(qwidget->parentWidget()->winId());
+ }
// Necessary in order to be able to track the activation status of
// the control's window
@@ -452,7 +459,7 @@ void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
windowPurpose = ETfxPurposeSplashScreenWindow;
break;
default:
- windowPurpose = (isWindowOwning || !qwidget->parentWidget())
+ windowPurpose = (isWindowOwning || !qwidget->parentWidget() || qwidget->parentWidget()->windowType() == Qt::Desktop)
? ETfxPurposeWindow : ETfxPurposeChildWindow;
break;
}
@@ -983,14 +990,15 @@ TKeyResponse QSymbianControl::handleVirtualMouse(const TKeyEvent& keyEvent,TEven
}
}
//clip to screen size (window server allows a sprite hotspot to be outside the screen)
+ int screenNumber = S60->screenNumberForWidget(qwidget);
if (x < 0)
x = 0;
- else if (x >= S60->screenWidthInPixels)
- x = S60->screenWidthInPixels - 1;
+ else if (x >= S60->screenWidthInPixelsForScreen[screenNumber])
+ x = S60->screenWidthInPixelsForScreen[screenNumber] - 1;
if (y < 0)
y = 0;
- else if (y >= S60->screenHeightInPixels)
- y = S60->screenHeightInPixels - 1;
+ else if (y >= S60->screenHeightInPixelsForScreen[screenNumber])
+ y = S60->screenHeightInPixelsForScreen[screenNumber] - 1;
TPoint epos(x, y);
TPoint cpos = epos - PositionRelativeToScreen();
fakeEvent.iPosition = cpos;
@@ -1124,7 +1132,8 @@ void QSymbianControl::Draw(const TRect& controlRect) const
// Do nothing
break;
case QWExtra::Blit:
- if (qwidget->d_func()->isOpaque)
+ case QWExtra::BlitWriteAlpha:
+ if (qwidget->d_func()->isOpaque || nativePaintMode == QWExtra::BlitWriteAlpha)
gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect);
break;
@@ -1167,6 +1176,18 @@ void QSymbianControl::SizeChanged()
QSize newSize(Size().iWidth, Size().iHeight);
if (oldSize != newSize) {
+ const bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen;
+ const int screenNumber = S60->screenNumberForWidget(qwidget);
+ if (!m_inExternalScreenOverride && isFullscreen && screenNumber > 0) {
+ int screenWidth = S60->screenWidthInPixelsForScreen[screenNumber];
+ int screenHeight = S60->screenHeightInPixelsForScreen[screenNumber];
+ TSize screenSize(screenWidth, screenHeight);
+ if (screenWidth > 0 && screenHeight > 0 && screenSize != Size()) {
+ m_inExternalScreenOverride = true;
+ SetExtent(TPoint(0, 0), screenSize);
+ return;
+ }
+ }
QRect cr = qwidget->geometry();
cr.setSize(newSize);
qwidget->data->crect = cr;
@@ -1189,6 +1210,8 @@ void QSymbianControl::SizeChanged()
}
}
+ m_inExternalScreenOverride = false;
+
// CCoeControl::SetExtent calls SizeChanged, but does not call
// PositionChanged, so we call it here to ensure that the widget's
// position is updated.
@@ -1224,6 +1247,11 @@ void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop)
return;
+#ifdef Q_WS_S60
+ if (S60->splitViewLastWidget)
+ return;
+#endif
+
// Popups never get focused, but still receive the FocusChanged when they are hidden.
if (QApplicationPrivate::popupWidgets != 0
|| (qwidget->windowType() & Qt::Popup) == Qt::Popup)
@@ -1302,9 +1330,56 @@ void QSymbianControl::handleClientAreaChange()
}
}
+bool QSymbianControl::isSplitViewWidget(QWidget *widget) {
+ bool returnValue = true;
+ //Ignore events sent to non-active windows, not visible widgets and not parents of input widget.
+ if (!qwidget->isActiveWindow()
+ || !qwidget->isVisible()
+ || !qwidget->isAncestorOf(widget)) {
+
+ returnValue = false;
+ }
+ return returnValue;
+}
+
void QSymbianControl::HandleResourceChange(int resourceType)
{
switch (resourceType) {
+ case KSplitViewCloseEvent: //intentional fall-through
+ case KSplitViewOpenEvent: {
+#if !defined(QT_NO_IM) && defined(Q_WS_S60)
+
+ //Fetch widget getting the text input
+ QWidget *widget = QWidget::keyboardGrabber();
+ if (!widget) {
+ if (QApplicationPrivate::popupWidgets) {
+ widget = QApplication::activePopupWidget()->focusWidget();
+ if (!widget) {
+ widget = QApplication::activePopupWidget();
+ }
+ } else {
+ widget = QApplicationPrivate::focus_widget;
+ if (!widget) {
+ widget = qwidget;
+ }
+ }
+ }
+ if (widget) {
+ QCoeFepInputContext *ic = qobject_cast<QCoeFepInputContext *>(widget->inputContext());
+ if (!ic) {
+ ic = qobject_cast<QCoeFepInputContext *>(qApp->inputContext());
+ }
+ if (ic && isSplitViewWidget(widget)) {
+ if (resourceType == KSplitViewCloseEvent) {
+ ic->resetSplitViewWidget();
+ } else {
+ ic->ensureFocusWidgetVisible(widget);
+ }
+ }
+ }
+#endif // !defined(QT_NO_IM) && defined(Q_WS_S60)
+ }
+ break;
case KInternalStatusPaneChange:
handleClientAreaChange();
if (IsFocused() && IsVisible()) {
@@ -1590,6 +1665,32 @@ void qt_init(QApplicationPrivate * /* priv */, int)
QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit()));
#endif
+#ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = true;
+
+ const TUid KIvePropertyCat = {0x2726beef};
+ enum TIvePropertyChipType {
+ EVCBCM2727B1 = 0x00000000,
+ EVCBCM2763A0 = 0x04000100,
+ EVCBCM2763B0 = 0x04000102,
+ EVCBCM2763C0 = 0x04000103,
+ EVCBCM2763C1 = 0x04000104,
+ EVCBCMUnknown = 0x7fffffff
+ };
+
+ TInt chipType = EVCBCMUnknown;
+ if (RProperty::Get(KIvePropertyCat, 0 /*chip type*/, chipType) == KErrNone) {
+ if (chipType == EVCBCM2727B1) {
+ // We have only 32MB GPU memory. Use raster surfaces
+ // for transparent TLWs.
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+ }
+ } else {
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+ }
+#else
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+#endif
/*
### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
int argc = priv->argc;
@@ -1979,7 +2080,10 @@ int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent
return 1;
}
break;
- case EEventScreenDeviceChanged:
+ case EEventScreenDeviceChanged: // fallthrough
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ case EEventDisplayChanged:
+#endif
if (callSymbianEventFilters(symbianEvent))
return 1;
if (S60)
diff --git a/src/gui/kernel/qclipboard_win.cpp b/src/gui/kernel/qclipboard_win.cpp
index 52b9663..ea41165 100644
--- a/src/gui/kernel/qclipboard_win.cpp
+++ b/src/gui/kernel/qclipboard_win.cpp
@@ -52,6 +52,7 @@
#include "qt_windows.h"
#include "qdnd_p.h"
#include <private/qwidget_p.h>
+#include <private/qsystemlibrary_p.h>
QT_BEGIN_NAMESPACE
@@ -70,6 +71,9 @@ void QtCeFlushClipboard();
#endif
+typedef BOOL (WINAPI *PtrIsHungAppWindow)(HWND);
+
+static PtrIsHungAppWindow ptrIsHungAppWindow = 0;
class QClipboardWatcher : public QInternalMimeData {
public:
@@ -327,9 +331,16 @@ bool QClipboard::event(QEvent *e)
d->releaseIData();
propagate = true;
}
-
if (propagate && d->nextClipboardViewer) {
- SendMessage(d->nextClipboardViewer, m->message, m->wParam, m->lParam);
+ if (ptrIsHungAppWindow == 0) {
+ QSystemLibrary library(QLatin1String("User32"));
+ ptrIsHungAppWindow = (PtrIsHungAppWindow)library.resolve("IsHungAppWindow");
+ }
+ if (ptrIsHungAppWindow && ptrIsHungAppWindow(d->nextClipboardViewer)) {
+ qWarning("%s: Cowardly refusing to send clipboard message to hung application...", Q_FUNC_INFO);
+ } else {
+ SendMessage(d->nextClipboardViewer, m->message, m->wParam, m->lParam);
+ }
}
return true;
diff --git a/src/gui/kernel/qdesktopwidget_s60.cpp b/src/gui/kernel/qdesktopwidget_s60.cpp
index 3653ae2..62a4d40 100644
--- a/src/gui/kernel/qdesktopwidget_s60.cpp
+++ b/src/gui/kernel/qdesktopwidget_s60.cpp
@@ -44,36 +44,67 @@
#include "qwidget_p.h"
#include "qt_s60_p.h"
#include <w32std.h>
-
-#include "hal.h"
-#include "hal_data.h"
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+#include <graphics/displaycontrol.h>
+#endif
QT_BEGIN_NAMESPACE
-class QDesktopWidgetPrivate : public QWidgetPrivate
+extern int qt_symbian_create_desktop_on_screen;
+
+class QSingleDesktopWidget : public QWidget
+{
+public:
+ QSingleDesktopWidget();
+ ~QSingleDesktopWidget();
+};
+
+QSingleDesktopWidget::QSingleDesktopWidget()
+ : QWidget(0, Qt::Desktop)
+{
+}
+
+QSingleDesktopWidget::~QSingleDesktopWidget()
{
+ const QObjectList &childList = children();
+ for (int i = childList.size(); i > 0 ;) {
+ --i;
+ childList.at(i)->setParent(0);
+ }
+}
+class QDesktopWidgetPrivate : public QWidgetPrivate
+{
public:
QDesktopWidgetPrivate();
~QDesktopWidgetPrivate();
-
static void init(QDesktopWidget *that);
static void cleanup();
+ static void init_sys();
static int screenCount;
static int primaryScreen;
static QVector<QRect> *rects;
static QVector<QRect> *workrects;
+ static QVector<QWidget *> *screens;
static int refcount;
+
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ static MDisplayControl *displayControl;
+#endif
};
int QDesktopWidgetPrivate::screenCount = 1;
int QDesktopWidgetPrivate::primaryScreen = 0;
QVector<QRect> *QDesktopWidgetPrivate::rects = 0;
QVector<QRect> *QDesktopWidgetPrivate::workrects = 0;
+QVector<QWidget *> *QDesktopWidgetPrivate::screens = 0;
int QDesktopWidgetPrivate::refcount = 0;
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+MDisplayControl *QDesktopWidgetPrivate::displayControl = 0;
+#endif
QDesktopWidgetPrivate::QDesktopWidgetPrivate()
{
@@ -88,25 +119,55 @@ QDesktopWidgetPrivate::~QDesktopWidgetPrivate()
void QDesktopWidgetPrivate::init(QDesktopWidget *that)
{
- Q_UNUSED(that);
-// int screenCount=0;
-
- // ### TODO: Implement proper multi-display support
- QDesktopWidgetPrivate::screenCount = 1;
-// if (HAL::Get(0, HALData::EDisplayNumberOfScreens, screenCount) == KErrNone)
-// QDesktopWidgetPrivate::screenCount = screenCount;
-// else
-// QDesktopWidgetPrivate::screenCount = 0;
+ // Note that on S^3 devices the screen count retrieved via RWsSession
+ // will always be 2 but the width and height for screen number 1 will
+ // be 0 as long as TV-out is not connected.
+ //
+ // On the other hand a valid size for screen 1 will be reported even
+ // after the cable is disconnected. In order to overcome this, we use
+ // MDisplayControl::NumberOfResolutions() to check if the display is
+ // valid or not.
+
+ screenCount = S60->screenCount();
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ if (displayControl) {
+ if (displayControl->NumberOfResolutions() < 1)
+ screenCount = 1;
+ }
+#endif
+ if (screenCount < 1) {
+ qWarning("No screen available");
+ screenCount = 1;
+ }
rects = new QVector<QRect>();
workrects = new QVector<QRect>();
-
- rects->resize(QDesktopWidgetPrivate::screenCount);
- workrects->resize(QDesktopWidgetPrivate::screenCount);
-
- (*rects)[0].setRect(0, 0, S60->screenWidthInPixels, S60->screenHeightInPixels);
- QRect wr = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
- (*workrects)[0].setRect(wr.x(), wr.y(), wr.width(), wr.height());
+ screens = new QVector<QWidget *>();
+
+ rects->resize(screenCount);
+ workrects->resize(screenCount);
+ screens->resize(screenCount);
+
+ for (int i = 0; i < screenCount; ++i) {
+ // All screens will have a position of (0, 0) as there is no true virtual desktop
+ // or pointer event support for multiple screens on Symbian.
+ QRect r(0, 0,
+ S60->screenWidthInPixelsForScreen[i], S60->screenHeightInPixelsForScreen[i]);
+ // Stop here if empty and ignore this screen.
+ if (r.isEmpty()) {
+ screenCount = i;
+ break;
+ }
+ (*rects)[i] = r;
+ QRect wr;
+ if (i == 0)
+ wr = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+ else
+ wr = rects->at(i);
+ (*workrects)[i].setRect(wr.x(), wr.y(), wr.width(), wr.height());
+ (*screens)[i] = 0;
+ }
+ (*screens)[0] = that;
}
void QDesktopWidgetPrivate::cleanup()
@@ -115,6 +176,29 @@ void QDesktopWidgetPrivate::cleanup()
rects = 0;
delete workrects;
workrects = 0;
+ if (screens) {
+ // First item is the QDesktopWidget so skip it.
+ for (int i = 1; i < screens->count(); ++i)
+ delete screens->at(i);
+ }
+ delete screens;
+ screens = 0;
+}
+
+void QDesktopWidgetPrivate::init_sys()
+{
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ if (S60->screenCount() > 1) {
+ CWsScreenDevice *dev = S60->screenDevice(1);
+ if (dev) {
+ displayControl = static_cast<MDisplayControl *>(
+ dev->GetInterface(MDisplayControl::ETypeId));
+ if (displayControl) {
+ displayControl->EnableDisplayChangeEvents(ETrue);
+ }
+ }
+ }
+#endif
}
@@ -122,6 +206,7 @@ QDesktopWidget::QDesktopWidget()
: QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop)
{
setObjectName(QLatin1String("desktop"));
+ QDesktopWidgetPrivate::init_sys();
QDesktopWidgetPrivate::init(this);
}
@@ -131,7 +216,7 @@ QDesktopWidget::~QDesktopWidget()
bool QDesktopWidget::isVirtualDesktop() const
{
- return true;
+ return false;
}
int QDesktopWidget::primaryScreen() const
@@ -145,9 +230,23 @@ int QDesktopWidget::numScreens() const
return QDesktopWidgetPrivate::screenCount;
}
-QWidget *QDesktopWidget::screen(int /* screen */)
+static inline QWidget *newSingleDesktopWidget(int screen)
{
- return this;
+ qt_symbian_create_desktop_on_screen = screen;
+ QWidget *w = new QSingleDesktopWidget;
+ qt_symbian_create_desktop_on_screen = -1;
+ return w;
+}
+
+QWidget *QDesktopWidget::screen(int screen)
+{
+ Q_D(QDesktopWidget);
+ if (screen < 0 || screen >= d->screenCount)
+ screen = d->primaryScreen;
+ if (!d->screens->at(screen)
+ || d->screens->at(screen)->windowType() != Qt::Desktop)
+ (*d->screens)[screen] = newSingleDesktopWidget(screen);
+ return (*d->screens)[screen];
}
const QRect QDesktopWidget::availableGeometry(int screen) const
@@ -168,14 +267,19 @@ const QRect QDesktopWidget::screenGeometry(int screen) const
return d->rects->at(screen);
}
-int QDesktopWidget::screenNumber(const QWidget * /* widget */) const
+int QDesktopWidget::screenNumber(const QWidget *widget) const
{
- return QDesktopWidgetPrivate::primaryScreen;
+ Q_D(const QDesktopWidget);
+ return widget
+ ? S60->screenNumberForWidget(widget)
+ : d->primaryScreen;
}
-int QDesktopWidget::screenNumber(const QPoint & /* point */) const
+int QDesktopWidget::screenNumber(const QPoint &point) const
{
- return QDesktopWidgetPrivate::primaryScreen;
+ Q_UNUSED(point);
+ Q_D(const QDesktopWidget);
+ return d->primaryScreen;
}
void QDesktopWidget::resizeEvent(QResizeEvent *)
@@ -203,6 +307,10 @@ void QDesktopWidget::resizeEvent(QResizeEvent *)
if (oldrect != newrect)
emit workAreaResized(j);
}
+
+ if (oldscreencount != d->screenCount) {
+ emit screenCountChanged(d->screenCount);
+ }
}
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h
index 40697bf..3bb27c3 100644
--- a/src/gui/kernel/qt_s60_p.h
+++ b/src/gui/kernel/qt_s60_p.h
@@ -64,6 +64,7 @@
#include "qapplication.h"
#include "qelapsedtimer.h"
#include "QtCore/qthreadstorage.h"
+#include "qwidget_p.h"
#include <w32std.h>
#include <coecntrl.h>
#include <eikenv.h>
@@ -84,6 +85,8 @@ QT_BEGIN_NAMESPACE
// system events seems to start with 0x10
const TInt KInternalStatusPaneChange = 0x50000000;
+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)
@@ -142,7 +145,10 @@ public:
int avkonComponentsSupportTransparency : 1;
int menuBeingConstructed : 1;
int orientationSet : 1;
+ int partial_keyboard : 1;
QApplication::QS60MainApplicationFactory s60ApplicationFactory; // typedef'ed pointer type
+ QPointer<QWidget> splitViewLastWidget;
+
static CEikButtonGroupContainer *cba;
enum ScanCodeState {
@@ -154,8 +160,14 @@ public:
static inline void updateScreenSize();
inline RWsSession& wsSession();
+ static inline int screenCount();
static inline RWindowGroup& windowGroup();
+ static inline RWindowGroup& windowGroup(const QWidget *widget);
+ static inline RWindowGroup& windowGroup(int screenNumber);
inline CWsScreenDevice* screenDevice();
+ inline CWsScreenDevice* screenDevice(const QWidget *widget);
+ inline CWsScreenDevice* screenDevice(int screenNumber);
+ static inline int screenNumberForWidget(const QWidget *widget);
static inline CCoeAppUi* appUi();
static inline CEikMenuBar* menuBar();
#ifdef Q_WS_S60
@@ -172,6 +184,11 @@ public:
#ifdef Q_OS_SYMBIAN
TTrapHandler *s60InstalledTrapHandler;
#endif
+
+ int screenWidthInPixelsForScreen[qt_symbian_max_screens];
+ int screenHeightInPixelsForScreen[qt_symbian_max_screens];
+ int screenWidthInTwipsForScreen[qt_symbian_max_screens];
+ int screenHeightInTwipsForScreen[qt_symbian_max_screens];
};
Q_AUTOTEST_EXPORT QS60Data* qGlobalS60Data();
@@ -252,6 +269,7 @@ private:
#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
void translateAdvancedPointerEvent(const TAdvancedPointerEvent *event);
#endif
+ bool isSplitViewWidget(QWidget *widget);
public:
void handleClientAreaChange();
@@ -270,6 +288,8 @@ private:
// Fader object used to fade everything except this menu and the CBA.
TAknPopupFader popupFader;
#endif
+
+ bool m_inExternalScreenOverride : 1;
};
inline QS60Data::QS60Data()
@@ -297,6 +317,7 @@ inline QS60Data::QS60Data()
avkonComponentsSupportTransparency(0),
menuBeingConstructed(0),
orientationSet(0),
+ partial_keyboard(0),
s60ApplicationFactory(0)
#ifdef Q_OS_SYMBIAN
,s60InstalledTrapHandler(0)
@@ -320,6 +341,17 @@ inline void QS60Data::updateScreenSize()
S60->defaultDpiY = S60->screenHeightInPixels / inches;
inches = S60->screenWidthInTwips / (TReal)KTwipsPerInch;
S60->defaultDpiX = S60->screenWidthInPixels / inches;
+
+ int screens = S60->screenCount();
+ for (int i = 0; i < screens; ++i) {
+ CWsScreenDevice *dev = S60->screenDevice(i);
+ mode = dev->CurrentScreenMode();
+ dev->GetScreenModeSizeAndRotation(mode, params);
+ S60->screenWidthInPixelsForScreen[i] = params.iPixelSize.iWidth;
+ S60->screenHeightInPixelsForScreen[i] = params.iPixelSize.iHeight;
+ S60->screenWidthInTwipsForScreen[i] = params.iTwipsSize.iWidth;
+ S60->screenHeightInTwipsForScreen[i] = params.iTwipsSize.iHeight;
+ }
}
inline RWsSession& QS60Data::wsSession()
@@ -330,11 +362,38 @@ inline RWsSession& QS60Data::wsSession()
return tls.localData()->wsSession;
}
+inline int QS60Data::screenCount()
+{
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ CCoeEnv *env = CCoeEnv::Static();
+ if (env) {
+ return qMin(env->WsSession().NumberOfScreens(), qt_symbian_max_screens);
+ }
+#endif
+ return 1;
+}
+
inline RWindowGroup& QS60Data::windowGroup()
{
return CCoeEnv::Static()->RootWin();
}
+inline RWindowGroup& QS60Data::windowGroup(const QWidget *widget)
+{
+ return windowGroup(screenNumberForWidget(widget));
+}
+
+inline RWindowGroup& QS60Data::windowGroup(int screenNumber)
+{
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ RWindowGroup *wg = CCoeEnv::Static()->RootWin(screenNumber);
+ return wg ? *wg : windowGroup();
+#else
+ Q_UNUSED(screenNumber);
+ return windowGroup();
+#endif
+}
+
inline CWsScreenDevice* QS60Data::screenDevice()
{
if(!tls.hasLocalData()) {
@@ -343,6 +402,36 @@ inline CWsScreenDevice* QS60Data::screenDevice()
return tls.localData()->screenDevice;
}
+inline CWsScreenDevice* QS60Data::screenDevice(const QWidget *widget)
+{
+ return screenDevice(screenNumberForWidget(widget));
+}
+
+inline CWsScreenDevice* QS60Data::screenDevice(int screenNumber)
+{
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ CCoeEnv *env = CCoeEnv::Static();
+ if (env) {
+ CWsScreenDevice *dev = env->ScreenDevice(screenNumber);
+ return dev ? dev : screenDevice();
+ } else {
+ return screenDevice();
+ }
+#else
+ return screenDevice();
+#endif
+}
+
+inline int QS60Data::screenNumberForWidget(const QWidget *widget)
+{
+ if (!widget)
+ return 0;
+ const QWidget *w = widget;
+ while (w->parentWidget())
+ w = w->parentWidget();
+ return qt_widget_private(const_cast<QWidget *>(w))->symbianScreenNumber;
+}
+
inline CCoeAppUi* QS60Data::appUi()
{
return CCoeEnv::Static()-> AppUi();
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 7065e85..e8d9efd 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -304,6 +304,8 @@ QWidgetPrivate::QWidgetPrivate(int version)
, hasAlienChildren(0)
, window_event(0)
, qd_hd(0)
+#elif defined(Q_OS_SYMBIAN)
+ , symbianScreenNumber(0)
#endif
{
if (!qApp) {
@@ -1284,6 +1286,10 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
// programmer specified desktop widget
xinfo = desktopWidget->d_func()->xinfo;
}
+#elif defined(Q_OS_SYMBIAN)
+ if (desktopWidget) {
+ symbianScreenNumber = qt_widget_private(desktopWidget)->symbianScreenNumber;
+ }
#else
Q_UNUSED(desktopWidget);
#endif
@@ -1320,8 +1326,8 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
//give potential windows a bigger "pre-initial" size; create_sys() will give them a new size later
#ifdef Q_OS_SYMBIAN
if (isGLWidget) {
- // Don't waste GPU mem for unnecessary large egl surface
- data.crect = QRect(0,0,2,2);
+ // Don't waste GPU mem for unnecessary large egl surface until resized by application
+ data.crect = QRect(0,0,1,1);
} else {
data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,360,640);
}
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index 9f6ba6f..13e2349 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -315,6 +315,11 @@ struct QWExtra {
*/
ZeroFill,
+ /**
+ * Blit backing store, propagating alpha channel into the framebuffer.
+ */
+ BlitWriteAlpha,
+
Default = Blit
};
@@ -877,6 +882,7 @@ public:
#elif defined(Q_OS_SYMBIAN) // <--------------------------------------------------------- SYMBIAN
static QWidget *mouseGrabber;
static QWidget *keyboardGrabber;
+ int symbianScreenNumber; // only valid for desktop widget and top-levels
void s60UpdateIsOpaque();
void reparentChildren();
void registerTouchWindow();
diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp
index af9ae47..b65ae4d 100644
--- a/src/gui/kernel/qwidget_s60.cpp
+++ b/src/gui/kernel/qwidget_s60.cpp
@@ -84,6 +84,8 @@ QWidget *QWidgetPrivate::mouseGrabber = 0;
QWidget *QWidgetPrivate::keyboardGrabber = 0;
CEikButtonGroupContainer *QS60Data::cba = 0;
+int qt_symbian_create_desktop_on_screen = -1;
+
static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b)
{
if ( a.count() != b.count())
@@ -349,12 +351,18 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de
int sh = clientRect.Height();
if (desktop) {
- TSize screenSize = S60->screenDevice()->SizeInPixels();
+ symbianScreenNumber = qMax(qt_symbian_create_desktop_on_screen, 0);
+ TSize screenSize = S60->screenDevice(symbianScreenNumber)->SizeInPixels();
data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight);
q->setAttribute(Qt::WA_DontShowOnScreen);
} else if (topLevel && !q->testAttribute(Qt::WA_Resized)){
int width = sw;
int height = sh;
+ if (symbianScreenNumber > 0) {
+ TSize screenSize = S60->screenDevice(symbianScreenNumber)->SizeInPixels();
+ width = screenSize.iWidth;
+ height = screenSize.iHeight;
+ }
if (extra) {
width = qMax(qMin(width, extra->maxw), extra->minw);
height = qMax(qMin(height, extra->maxh), extra->minh);
@@ -640,7 +648,7 @@ void QWidgetPrivate::raise_sys()
// If toplevel widget, raise app to foreground
if (q->isWindow())
- S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), 0);
+ S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup(q).Identifier(), 0);
}
}
@@ -652,7 +660,7 @@ void QWidgetPrivate::lower_sys()
if (q->internalWinId()) {
// If toplevel widget, lower app to background
if (q->isWindow())
- S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), -1);
+ S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup(q).Identifier(), -1);
else
q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1);
}
@@ -722,6 +730,11 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
{
Q_Q(QWidget);
+ if (parent && parent->windowType() == Qt::Desktop) {
+ symbianScreenNumber = qt_widget_private(parent)->symbianScreenNumber;
+ parent = 0;
+ }
+
bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
@@ -792,25 +805,33 @@ void QWidgetPrivate::s60UpdateIsOpaque()
{
Q_Q(QWidget);
- if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
+ if (!q->testAttribute(Qt::WA_WState_Created))
return;
+ const bool writeAlpha = extraData()->nativePaintMode == QWExtra::BlitWriteAlpha;
+ if (!q->testAttribute(Qt::WA_TranslucentBackground) && !writeAlpha)
+ return;
+ const bool requireAlphaChannel = !isOpaque || writeAlpha;
+
createTLExtra();
RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
#ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
- window->SetSurfaceTransparency(!isOpaque);
- extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
-#else
- if (!isOpaque) {
+ if (QApplicationPrivate::instance()->useTranslucentEGLSurfaces) {
+ window->SetSurfaceTransparency(!isOpaque);
+ extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
+ return;
+ }
+#endif
+ if (requireAlphaChannel) {
const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA));
if (window->SetTransparencyAlphaChannel() == KErrNone) {
window->SetBackgroundColor(TRgb(255, 255, 255, 0));
extra->topextra->nativeWindowTransparencyEnabled = 1;
-
- if (extra->topextra->backingStore.data() &&
- QApplicationPrivate::graphics_system_name == QLatin1String("openvg")) {
+ if (extra->topextra->backingStore.data() && (
+ QApplicationPrivate::graphics_system_name == QLatin1String("openvg")
+ || QApplicationPrivate::graphics_system_name == QLatin1String("opengl"))) {
// Semi-transparent EGL surfaces aren't supported. We need to
// recreate backing store to get translucent surface (raster surface).
extra->topextra->backingStore.create(q);
@@ -821,7 +842,6 @@ void QWidgetPrivate::s60UpdateIsOpaque()
window->SetTransparentRegion(TRegionFix<1>());
extra->topextra->nativeWindowTransparencyEnabled = 0;
}
-#endif
}
void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
@@ -1037,7 +1057,7 @@ int QWidget::metric(PaintDeviceMetric m) const
} else if (m == PdmHeight) {
val = data->crect.height();
} else {
- CWsScreenDevice *scr = S60->screenDevice();
+ CWsScreenDevice *scr = S60->screenDevice(this);
switch(m) {
case PdmDpiX:
case PdmPhysicalDpiX:
@@ -1207,7 +1227,16 @@ void QWidget::setWindowState(Qt::WindowStates newstate)
const bool cbaVisibilityHint = windowFlags() & Qt::WindowSoftkeysVisibleHint;
if (newstate & Qt::WindowFullScreen && !cbaVisibilityHint) {
setAttribute(Qt::WA_OutsideWSRange, false);
- window->SetExtentToWholeScreen();
+ if (d->symbianScreenNumber > 0) {
+ int w = S60->screenWidthInPixelsForScreen[d->symbianScreenNumber];
+ int h = S60->screenHeightInPixelsForScreen[d->symbianScreenNumber];
+ if (w <= 0 || h <= 0)
+ window->SetExtentToWholeScreen();
+ else
+ window->SetExtent(TPoint(0, 0), TSize(w, h));
+ } else {
+ window->SetExtentToWholeScreen();
+ }
} else if (newstate & Qt::WindowMaximized || ((newstate & Qt::WindowFullScreen) && cbaVisibilityHint)) {
setAttribute(Qt::WA_OutsideWSRange, false);
TRect maxExtent = qt_QRect2TRect(qApp->desktop()->availableGeometry(this));
diff --git a/src/gui/math3d/qvector2d.cpp b/src/gui/math3d/qvector2d.cpp
index 7f5a937..1fccfc9 100644
--- a/src/gui/math3d/qvector2d.cpp
+++ b/src/gui/math3d/qvector2d.cpp
@@ -60,6 +60,11 @@ QT_BEGIN_NAMESPACE
The QVector2D class can also be used to represent vertices in 2D space.
We therefore do not need to provide a separate vertex class.
+ \bold{Note:} By design values in the QVector2D instance are stored as \c float.
+ This means that on platforms where the \c qreal arguments to QVector2D
+ functions are represented by \c double values, it is possible to
+ lose precision.
+
\sa QVector3D, QVector4D, QQuaternion
*/
diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp
index 2414b5f..7bf0400 100644
--- a/src/gui/math3d/qvector3d.cpp
+++ b/src/gui/math3d/qvector3d.cpp
@@ -63,6 +63,11 @@ QT_BEGIN_NAMESPACE
The QVector3D class can also be used to represent vertices in 3D space.
We therefore do not need to provide a separate vertex class.
+ \bold{Note:} By design values in the QVector3D instance are stored as \c float.
+ This means that on platforms where the \c qreal arguments to QVector3D
+ functions are represented by \c double values, it is possible to
+ lose precision.
+
\sa QVector2D, QVector4D, QQuaternion
*/
diff --git a/src/gui/math3d/qvector4d.cpp b/src/gui/math3d/qvector4d.cpp
index 74dedc4..23befc0 100644
--- a/src/gui/math3d/qvector4d.cpp
+++ b/src/gui/math3d/qvector4d.cpp
@@ -59,6 +59,11 @@ QT_BEGIN_NAMESPACE
The QVector4D class can also be used to represent vertices in 4D space.
We therefore do not need to provide a separate vertex class.
+ \bold{Note:} By design values in the QVector4D instance are stored as \c float.
+ This means that on platforms where the \c qreal arguments to QVector4D
+ functions are represented by \c double values, it is possible to
+ lose precision.
+
\sa QQuaternion, QVector2D, QVector3D
*/
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index 83c58c4..4fcff1d 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -1117,6 +1117,11 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg
return;
}
+ // If there's no partial update support we always need
+ // to do a full repaint before flushing
+ if (!windowSurface->hasPartialUpdateSupport())
+ fullUpdatePending = true;
+
// Nothing to repaint.
if (!isDirty()) {
qt_flush(exposedWidget, exposedRegion, windowSurface, tlw, tlwOffset);
diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp
index 770d947..5112019 100644
--- a/src/gui/painting/qgraphicssystem.cpp
+++ b/src/gui/painting/qgraphicssystem.cpp
@@ -84,4 +84,9 @@ QPixmapData *QGraphicsSystem::createPixmapData(QPixmapData *origin)
return createPixmapData(origin->pixelType());
}
+void QGraphicsSystem::releaseCachedResources()
+{
+ // Do nothing here
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qgraphicssystem_p.h b/src/gui/painting/qgraphicssystem_p.h
index 76e9a8e..80e8959 100644
--- a/src/gui/painting/qgraphicssystem_p.h
+++ b/src/gui/painting/qgraphicssystem_p.h
@@ -72,6 +72,8 @@ public:
//### Remove this & change qpixmap.cpp & qbitmap.cpp once every platform is gaurenteed
// to have a graphics system.
static QPixmapData *createDefaultPixmapData(QPixmapData::PixelType type);
+
+ virtual void releaseCachedResources();
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qgraphicssystem_runtime.cpp b/src/gui/painting/qgraphicssystem_runtime.cpp
index 5841d40..33652ee 100644
--- a/src/gui/painting/qgraphicssystem_runtime.cpp
+++ b/src/gui/painting/qgraphicssystem_runtime.cpp
@@ -394,7 +394,10 @@ void QRuntimeGraphicsSystem::setGraphicsSystem(const QString &name)
if(m_windowSurfaceDestroyPolicy == DestroyAfterFirstFlush)
proxy->m_pendingWindowSurface.reset(proxy->m_windowSurface.take());
- proxy->m_windowSurface.reset(m_graphicsSystem->createWindowSurface(widget));
+ QWindowSurface *newWindowSurface = m_graphicsSystem->createWindowSurface(widget);
+ newWindowSurface->setGeometry(proxy->geometry());
+
+ proxy->m_windowSurface.reset(newWindowSurface);
qt_widget_private(widget)->invalidateBuffer(widget->rect());
}
diff --git a/src/gui/painting/qpaintengine_s60.cpp b/src/gui/painting/qpaintengine_s60.cpp
index 1bc7799..ca303be 100644
--- a/src/gui/painting/qpaintengine_s60.cpp
+++ b/src/gui/painting/qpaintengine_s60.cpp
@@ -41,6 +41,7 @@
#include <private/qpaintengine_s60_p.h>
#include <private/qpixmap_s60_p.h>
#include <private/qt_s60_p.h>
+#include <private/qvolatileimage_p.h>
QT_BEGIN_NAMESPACE
@@ -90,7 +91,15 @@ void QS60PaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm)
QRasterPaintEngine::drawPixmap(p, pm);
srcData->endDataAccess();
} else {
- QRasterPaintEngine::drawPixmap(p, pm);
+ void *nativeData = pm.pixmapData()->toNativeType(QPixmapData::VolatileImage);
+ if (nativeData) {
+ QVolatileImage *img = static_cast<QVolatileImage *>(nativeData);
+ img->beginDataAccess();
+ QRasterPaintEngine::drawImage(p, img->imageRef());
+ img->endDataAccess(true);
+ } else {
+ QRasterPaintEngine::drawPixmap(p, pm);
+ }
}
}
@@ -102,7 +111,15 @@ void QS60PaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRect
QRasterPaintEngine::drawPixmap(r, pm, sr);
srcData->endDataAccess();
} else {
- QRasterPaintEngine::drawPixmap(r, pm, sr);
+ void *nativeData = pm.pixmapData()->toNativeType(QPixmapData::VolatileImage);
+ if (nativeData) {
+ QVolatileImage *img = static_cast<QVolatileImage *>(nativeData);
+ img->beginDataAccess();
+ QRasterPaintEngine::drawImage(r, img->imageRef(), sr);
+ img->endDataAccess(true);
+ } else {
+ QRasterPaintEngine::drawPixmap(r, pm, sr);
+ }
}
}
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index 9ef6955..0948a64 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -1690,7 +1690,7 @@ static void qt_painterpath_isect_line(const QPointF &p1,
}
static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
- int *winding)
+ int *winding, int depth = 0)
{
qreal y = pt.y();
qreal x = pt.x();
@@ -1705,7 +1705,7 @@ static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
// hit lower limit... This is a rough threshold, but its a
// tradeoff between speed and precision.
const qreal lower_bound = qreal(.001);
- if (bounds.width() < lower_bound && bounds.height() < lower_bound) {
+ if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) {
// We make the assumption here that the curve starts to
// approximate a line after while (i.e. that it doesn't
// change direction drastically during its slope)
@@ -1718,8 +1718,8 @@ static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
// split curve and try again...
QBezier first_half, second_half;
bezier.split(&first_half, &second_half);
- qt_painterpath_isect_curve(first_half, pt, winding);
- qt_painterpath_isect_curve(second_half, pt, winding);
+ qt_painterpath_isect_curve(first_half, pt, winding, depth + 1);
+ qt_painterpath_isect_curve(second_half, pt, winding, depth + 1);
}
}
diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp
index 9f371a8..cb53ea0 100644
--- a/src/gui/painting/qwindowsurface_s60.cpp
+++ b/src/gui/painting/qwindowsurface_s60.cpp
@@ -63,7 +63,6 @@ struct QS60WindowSurfacePrivate
TDisplayMode displayMode(bool opaque)
{
-
TDisplayMode mode = S60->screenDevice()->DisplayMode();
if (opaque) {
mode = EColor16MU;
@@ -76,10 +75,18 @@ TDisplayMode displayMode(bool opaque)
return mode;
}
+bool blitWriteAlpha(QWidgetPrivate *widgetPrivate)
+{
+ QWExtra *extra = widgetPrivate->extraData();
+ return extra ? extra->nativePaintMode == QWExtra::BlitWriteAlpha : false;
+}
+
QS60WindowSurface::QS60WindowSurface(QWidget* widget)
: QWindowSurface(widget), d_ptr(new QS60WindowSurfacePrivate)
{
- TDisplayMode mode = displayMode(qt_widget_private(widget)->isOpaque);
+ QWidgetPrivate *widgetPrivate = qt_widget_private(widget);
+ const bool opaque = widgetPrivate->isOpaque && !blitWriteAlpha(widgetPrivate);
+ TDisplayMode mode = displayMode(opaque);
// We create empty CFbsBitmap here -> it will be resized in setGeometry
CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new
qt_symbian_throwIfError( bitmap->Create( TSize(0, 0), mode ) );
@@ -123,7 +130,8 @@ void QS60WindowSurface::beginPaint(const QRegion &rgn)
S60->wsSession().Finish();
#endif
- if (!qt_widget_private(window())->isOpaque) {
+ QWidgetPrivate *windowPrivate = qt_widget_private(window());
+ if (!windowPrivate->isOpaque || blitWriteAlpha(windowPrivate)) {
QS60PixmapData *pixmapData = static_cast<QS60PixmapData *>(d_ptr->device.data_ptr().data());
TDisplayMode mode = displayMode(false);
@@ -132,12 +140,14 @@ void QS60WindowSurface::beginPaint(const QRegion &rgn)
pixmapData->beginDataAccess();
- QPainter p(&pixmapData->image);
- p.setCompositionMode(QPainter::CompositionMode_Source);
- const QVector<QRect> rects = rgn.rects();
- const QColor blank = Qt::transparent;
- for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
- p.fillRect(*it, blank);
+ if (!windowPrivate->isOpaque) {
+ QPainter p(&pixmapData->image);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ const QVector<QRect> rects = rgn.rects();
+ const QColor blank = Qt::transparent;
+ for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
+ p.fillRect(*it, blank);
+ }
}
pixmapData->endDataAccess();
diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp
index 38a4b7c..a9e10a3 100644
--- a/src/gui/styles/qs60style.cpp
+++ b/src/gui/styles/qs60style.cpp
@@ -118,6 +118,7 @@ const short *QS60StylePrivate::m_pmPointer = QS60StylePrivate::data[0];
// theme background texture
QPixmap *QS60StylePrivate::m_background = 0;
+QPixmap *QS60StylePrivate::m_placeHolderTexture = 0;
// theme palette
QPalette *QS60StylePrivate::m_themePalette = 0;
@@ -155,6 +156,10 @@ const double KTabFontMul = 0.72;
QS60StylePrivate::~QS60StylePrivate()
{
clearCaches(); //deletes also background image
+ if (m_placeHolderTexture) {
+ delete m_placeHolderTexture;
+ m_placeHolderTexture = 0;
+ }
deleteThemePalette();
#ifdef Q_WS_S60
removeAnimations();
@@ -505,7 +510,10 @@ void QS60StylePrivate::setBackgroundTexture(QApplication *app) const
{
Q_UNUSED(app)
QPalette applicationPalette = QApplication::palette();
- applicationPalette.setBrush(QPalette::Window, backgroundTexture());
+ // The initial QPalette::Window is just a placeHolder QPixmap to save RAM
+ // if the actual texture is not needed. The real texture is created just before
+ // painting it in qt_s60_fill_background().
+ applicationPalette.setBrush(QPalette::Window, placeHolderTexture());
setThemePalette(&applicationPalette);
}
@@ -630,25 +638,6 @@ QPixmap QS60StylePrivate::cachedFrame(SkinFrameElements frame, const QSize &size
return result;
}
-void QS60StylePrivate::refreshUI()
-{
- QList<QWidget *> widgets = QApplication::allWidgets();
-
- for (int i = 0; i < widgets.size(); ++i) {
- QWidget *widget = widgets.at(i);
- if (widget == 0)
- continue;
-
- if (widget->style()) {
- widget->style()->polish(widget);
- QEvent event(QEvent::StyleChange);
- qApp->sendEvent(widget, &event);
- }
- widget->update();
- widget->updateGeometry();
- }
-}
-
void QS60StylePrivate::setFont(QWidget *widget) const
{
QS60StyleEnums::FontCategories fontCategory = QS60StyleEnums::FC_Undefined;
@@ -678,7 +667,7 @@ void QS60StylePrivate::setFont(QWidget *widget) const
}
}
-void QS60StylePrivate::setThemePalette(QWidget *widget) const
+void QS60StylePrivate::setThemePalette(QWidget *widget)
{
if(!widget)
return;
@@ -719,8 +708,10 @@ void QS60StylePrivate::setThemePalette(QPalette *palette) const
palette->setColor(QPalette::LinkVisited, palette->color(QPalette::Link).darker());
palette->setColor(QPalette::Highlight,
s60Color(QS60StyleEnums::CL_QsnHighlightColors, 2, 0));
- // set background image as a texture brush
- palette->setBrush(QPalette::Window, backgroundTexture());
+ // The initial QPalette::Window is just a placeHolder QPixmap to save RAM
+ // if the actual texture is not needed. The real texture is created just before
+ // painting it in qt_s60_fill_background().
+ palette->setBrush(QPalette::Window, placeHolderTexture());
// set as transparent so that styled full screen theme background is visible
palette->setBrush(QPalette::Base, Qt::transparent);
// set button color based on pixel colors
@@ -761,7 +752,7 @@ void QS60StylePrivate::storeThemePalette(QPalette *palette)
}
// set widget specific palettes
-void QS60StylePrivate::setThemePaletteHash(QPalette *palette) const
+void QS60StylePrivate::setThemePaletteHash(QPalette *palette)
{
if (!palette)
return;
@@ -2643,10 +2634,13 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt,
sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget);
//native items have small empty areas at the beginning and end of menu item
sz.setWidth(sz.width() + 2 * pixelMetric(PM_MenuHMargin) + 2 * QS60StylePrivate::pixelMetric(PM_FrameCornerWidth));
- if (QS60StylePrivate::isTouchSupported())
+ if (QS60StylePrivate::isTouchSupported()) {
//Make itemview easier to use in touch devices
+ sz.setHeight(sz.height() + 2 * pixelMetric(PM_FocusFrameVMargin));
//QCommonStyle does not adjust height with horizontal margin, it only adjusts width
- sz.setHeight(sz.height() + 2 * pixelMetric(PM_FocusFrameVMargin) - 8); //QCommonstyle adds 8 to height that this style handles through PM values
+ if (ct == CT_MenuItem)
+ sz.setHeight(sz.height() - 8); //QCommonstyle adds 8 to height that this style handles through PM values
+ }
break;
#ifndef QT_NO_COMBOBOX
case CT_ComboBox: {
@@ -3545,10 +3539,18 @@ extern QPoint qt_s60_fill_background_offset(const QWidget *targetWidget);
bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush)
{
- const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture());
- if (backgroundTexture.cacheKey() != brush.texture().cacheKey())
+ // Check if the widget's palette matches placeholder or actual background texture.
+ // When accessing backgroundTexture, use parameter value 'true' to avoid creating
+ // the texture, if it is not already created.
+
+ const QPixmap placeHolder(QS60StylePrivate::placeHolderTexture());
+ const QPixmap bg(QS60StylePrivate::backgroundTexture(true));
+ if (placeHolder.cacheKey() != brush.texture().cacheKey()
+ && bg.cacheKey() != brush.texture().cacheKey())
return false;
+ const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture());
+
const QPaintDevice *target = painter->device();
if (target->devType() == QInternal::Widget) {
const QWidget *widget = static_cast<const QWidget *>(target);
diff --git a/src/gui/styles/qs60style_p.h b/src/gui/styles/qs60style_p.h
index 242c451..3628b27 100644
--- a/src/gui/styles/qs60style_p.h
+++ b/src/gui/styles/qs60style_p.h
@@ -554,7 +554,8 @@ public:
static QPixmap frame(SkinFrameElements frame, const QSize &size,
SkinElementFlags flags = KDefaultSkinElementFlags);
- static QPixmap backgroundTexture();
+ static QPixmap backgroundTexture(bool skipCreation = false);
+ static QPixmap placeHolderTexture();
#ifdef Q_WS_S60
void handleDynamicLayoutVariantSwitch();
@@ -592,13 +593,11 @@ private:
static QPixmap cachedFrame(SkinFrameElements frame, const QSize &size,
SkinElementFlags flags = KDefaultSkinElementFlags);
- static void refreshUI();
-
// set S60 font for widget
void setFont(QWidget *widget) const;
- void setThemePalette(QWidget *widget) const;
+ static void setThemePalette(QWidget *widget);
void setThemePalette(QPalette *palette) const;
- void setThemePaletteHash(QPalette *palette) const;
+ static void setThemePaletteHash(QPalette *palette);
static void storeThemePalette(QPalette *palette);
static void deleteThemePalette();
static bool equalToThemePalette(QColor color, QPalette::ColorRole role);
@@ -616,6 +615,9 @@ private:
// Contains background texture.
static QPixmap *m_background;
+ // Placeholder pixmap for the real background texture.
+ static QPixmap *m_placeHolderTexture;
+
const static SkinElementFlags KDefaultSkinElementFlags;
// defined theme palette
static QPalette *m_themePalette;
diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp
index 605872e..c5149a3 100644
--- a/src/gui/styles/qs60style_s60.cpp
+++ b/src/gui/styles/qs60style_s60.cpp
@@ -47,6 +47,7 @@
#include "private/qt_s60_p.h"
#include "private/qpixmap_s60_p.h"
#include "private/qcore_symbian_p.h"
+#include "private/qvolatileimage_p.h"
#include "qapplication.h"
#include "qsettings.h"
@@ -65,7 +66,6 @@
#include <aknnavi.h>
#include <gulicon.h>
#include <AknBitmapAnimation.h>
-
#include <centralrepository.h>
#if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN)
@@ -637,9 +637,23 @@ QPixmap QS60StyleModeSpecifics::fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask
if (error)
return QPixmap();
- QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(icon);
- if (mask)
- pixmap.setAlphaChannel(QPixmap::fromSymbianCFbsBitmap(mask));
+ QPixmap pixmap;
+ QScopedPointer<QPixmapData> pd(QPixmapData::create(0, 0, QPixmapData::PixmapType));
+ if (mask) {
+ // Try the efficient path with less copying and conversion.
+ QVolatileImage img(icon, mask);
+ pd->fromNativeType(&img, QPixmapData::VolatileImage);
+ if (!pd->isNull())
+ pixmap = QPixmap(pd.take());
+ }
+ if (pixmap.isNull()) {
+ // Potentially more expensive path.
+ pd->fromNativeType(icon, QPixmapData::FbsBitmap);
+ pixmap = QPixmap(pd.take());
+ if (mask) {
+ pixmap.setAlphaChannel(QPixmap::fromSymbianCFbsBitmap(mask));
+ }
+ }
if ((flags & QS60StylePrivate::SF_PointEast) ||
(flags & QS60StylePrivate::SF_PointSouth) ||
@@ -795,6 +809,8 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX(
rotatedBy90or270 ? TSize(size.height(), size.width()) : qt_QSize2TSize(size);
MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance();
+ static const TDisplayMode displayMode = S60->supportsPremultipliedAlpha ? Q_SYMBIAN_ECOLOR16MAP : EColor16MA;
+ static const TInt drawParam = S60->supportsPremultipliedAlpha ? KAknsDrawParamDefault : KAknsDrawParamRGBOnly;
QPixmap result;
@@ -833,7 +849,7 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX(
// QS60WindowSurface::unlockBitmapHeap();
CFbsBitmap *background = new (ELeave) CFbsBitmap(); //offscreen
CleanupStack::PushL(background);
- User::LeaveIfError(background->Create(targetSize, EColor16MA));
+ User::LeaveIfError(background->Create(targetSize, displayMode));
CFbsBitmapDevice *dev = CFbsBitmapDevice::NewL(background);
CleanupStack::PushL(dev);
@@ -854,7 +870,7 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX(
*gc,
TPoint(),
targetSize,
- KAknsDrawParamDefault | KAknsDrawParamRGBOnly);
+ drawParam);
if (drawn)
result = fromFbsBitmap(background, NULL, flags, targetSize);
@@ -1375,7 +1391,7 @@ QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, Skin
return result;
}
-QPixmap QS60StylePrivate::backgroundTexture()
+QPixmap QS60StylePrivate::backgroundTexture(bool skipCreation)
{
bool createNewBackground = false;
TRect applicationRect = (static_cast<CEikAppUi*>(S60->appUi())->ApplicationRect());
@@ -1390,14 +1406,40 @@ QPixmap QS60StylePrivate::backgroundTexture()
}
}
- if (createNewBackground) {
+ if (createNewBackground && !skipCreation) {
QPixmap background = part(QS60StyleEnums::SP_QsnBgScreen,
- QSize(applicationRect.Width(), applicationRect.Height()), 0, SkinElementFlags());
+ QSize(applicationRect.Width(), applicationRect.Height()), 0, SkinElementFlags());
m_background = new QPixmap(background);
+
+ // Notify all widgets that palette is updated with the actual background texture.
+ QPalette pal = QApplication::palette();
+ pal.setBrush(QPalette::Window, *m_background);
+ QApplication::setPalette(pal);
+ setThemePaletteHash(&pal);
+ storeThemePalette(&pal);
+ foreach (QWidget *widget, QApplication::allWidgets()){
+ QEvent e(QEvent::PaletteChange);
+ QApplication::sendEvent(widget, &e);
+ setThemePalette(widget);
+ widget->ensurePolished();
+ }
}
+ if (!m_background)
+ return QPixmap();
return *m_background;
}
+// Generates 1*1 white pixmap as a placeholder for real texture.
+// The actual theme texture is drawn in qt_s60_fill_background().
+QPixmap QS60StylePrivate::placeHolderTexture()
+{
+ if (!m_placeHolderTexture) {
+ m_placeHolderTexture = new QPixmap(1,1);
+ m_placeHolderTexture->fill(Qt::white);
+ }
+ return *m_placeHolderTexture;
+}
+
QSize QS60StylePrivate::screenSize()
{
return QSize(S60->screenWidthInPixels, S60->screenHeightInPixels);
@@ -1412,8 +1454,8 @@ QS60Style::QS60Style()
void QS60StylePrivate::handleDynamicLayoutVariantSwitch()
{
clearCaches(QS60StylePrivate::CC_LayoutChange);
+ setBackgroundTexture(qApp);
setActiveLayout();
- refreshUI();
foreach (QWidget *widget, QApplication::allWidgets())
widget->ensurePolished();
}
diff --git a/src/gui/styles/qs60style_simulated.cpp b/src/gui/styles/qs60style_simulated.cpp
index 77e0d0e..7223c6b 100644
--- a/src/gui/styles/qs60style_simulated.cpp
+++ b/src/gui/styles/qs60style_simulated.cpp
@@ -308,7 +308,7 @@ QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size,
return result;
}
-QPixmap QS60StylePrivate::backgroundTexture()
+QPixmap QS60StylePrivate::backgroundTexture(bool /*skipCreation*/)
{
if (!m_background) {
const QSize size = QApplication::desktop()->screen()->size();
diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm
index 1c21f91..42b9402 100644
--- a/src/gui/text/qfontengine_mac.mm
+++ b/src/gui/text/qfontengine_mac.mm
@@ -59,6 +59,8 @@
QT_BEGIN_NAMESPACE
+static float SYNTHETIC_ITALIC_SKEW = tanf(14 * acosf(0) / 90);
+
/*****************************************************************************
QFontEngine debug facilities
*****************************************************************************/
@@ -467,6 +469,9 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
glyph_metrics_t ret;
CGGlyph g = glyph;
CGRect rect = CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, 0, 1);
+ if (synthesisFlags & QFontEngine::SynthesizedItalic) {
+ rect.size.width += rect.size.height * SYNTHETIC_ITALIC_SKEW;
+ }
ret.width = QFixed::fromReal(rect.size.width);
ret.height = QFixed::fromReal(rect.size.height);
ret.x = QFixed::fromReal(rect.origin.x);
@@ -558,7 +563,7 @@ void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextIt
CGAffineTransformConcat(cgMatrix, oldTextMatrix);
if (synthesisFlags & QFontEngine::SynthesizedItalic)
- cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -tanf(14 * acosf(0) / 90), 1, 0, 0));
+ cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
@@ -646,7 +651,7 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position
cgMatrix = CGAffineTransformScale(cgMatrix, 1, -1);
if (synthesisFlags & QFontEngine::SynthesizedItalic)
- cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -tanf(14 * acosf(0) / 90), 1, 0, 0));
+ cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
for (int i = 0; i < nGlyphs; ++i) {
@@ -681,7 +686,7 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, int margin, bool aa)
CGAffineTransformConcat(cgMatrix, oldTextMatrix);
if (synthesisFlags & QFontEngine::SynthesizedItalic)
- cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, tanf(14 * acosf(0) / 90), 1, 0, 0));
+ cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
@@ -1625,7 +1630,7 @@ QImage QFontEngineMac::imageForGlyph(glyph_t glyph, int margin, bool colorful)
CGAffineTransformConcat(cgMatrix, oldTextMatrix);
if (synthesisFlags & QFontEngine::SynthesizedItalic)
- cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, tanf(14 * acosf(0) / 90), 1, 0, 0));
+ cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
@@ -1718,7 +1723,7 @@ void QFontEngineMac::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt
CGAffineTransformConcat(cgMatrix, oldTextMatrix);
if (synthesisFlags & QFontEngine::SynthesizedItalic)
- cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -tanf(14 * acosf(0) / 90), 1, 0, 0));
+ cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp
index b25588d..6babca1 100644
--- a/src/gui/text/qtextcontrol.cpp
+++ b/src/gui/text/qtextcontrol.cpp
@@ -284,7 +284,7 @@ bool QTextControlPrivate::cursorMoveKeyEvent(QKeyEvent *e)
if (cursor.position() != oldCursorPos)
emit q->cursorPositionChanged();
emit q->microFocusChanged();
- } else if (ignoreNavigationEvents && isNavigationEvent) {
+ } else if (ignoreNavigationEvents && isNavigationEvent && oldSelection.anchor() == cursor.anchor()) {
return false;
}
@@ -1607,7 +1607,10 @@ void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, cons
if (!(buttons & Qt::LeftButton))
return;
- if (!((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable)))
+ const bool selectable = interactionFlags & Qt::TextSelectableByMouse;
+ const bool editable = interactionFlags & Qt::TextEditable;
+
+ if (!selectable && !editable)
return;
if (!(mousePressed
@@ -1623,6 +1626,10 @@ void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, cons
startDrag();
return;
}
+
+ if (!selectable)
+ return;
+
const qreal mouseX = qreal(mousePos.x());
int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit);
@@ -1638,7 +1645,7 @@ void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, cons
extendBlockwiseSelection(newCursorPos);
else if (selectedWordOnDoubleClick.hasSelection())
extendWordwiseSelection(newCursorPos, mouseX);
- else if (interactionFlags & Qt::TextSelectableByMouse)
+ else
setCursorPosition(newCursorPos, QTextCursor::KeepAnchor);
if (interactionFlags & Qt::TextEditable) {
@@ -1649,8 +1656,10 @@ void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, cons
emit q->cursorPositionChanged();
_q_updateCurrentCharFormatAndSelection();
#ifndef QT_NO_IM
- if (QInputContext *ic = inputContext()) {
- ic->update();
+ if (contextWidget) {
+ if (QInputContext *ic = inputContext()) {
+ ic->update();
+ }
}
#endif //QT_NO_IM
} else {
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index a1dcb63..5e59341 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -3148,7 +3148,7 @@ QRectF QTextDocumentLayoutPrivate::frameBoundingRectInternal(QTextFrame *frame)
QRectF QTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
{
Q_D(const QTextDocumentLayout);
- if (d->docPrivate->pageSize.isNull())
+ if (d->docPrivate->pageSize.isNull() || !block.isValid())
return QRectF();
d->ensureLayoutedByPosition(block.position() + block.length());
QTextFrame *frame = d->document->frameAt(block.position());
diff --git a/src/gui/text/qtextengine_mac.cpp b/src/gui/text/qtextengine_mac.cpp
index ce42241..c34bdb3 100644
--- a/src/gui/text/qtextengine_mac.cpp
+++ b/src/gui/text/qtextengine_mac.cpp
@@ -604,8 +604,9 @@ void QTextEngine::shapeTextMac(int item) const
bool stringToCMapFailed = false;
if (!fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters, attributes())) {
ensureSpace(num_glyphs);
- stringToCMapFailed = fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters,
- attributes());
+ g = availableGlyphs(&si);
+ stringToCMapFailed = !fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters,
+ attributes());
}
if (!stringToCMapFailed) {
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index a996f59..905f81b 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -1682,6 +1682,7 @@ namespace {
int glyphCount;
int maxGlyphs;
int currentPosition;
+ glyph_t previousGlyph;
QFixed minw;
QFixed softHyphenWidth;
@@ -1709,6 +1710,15 @@ namespace {
return glyphs.glyphs[logClusters[currentPosition - 1]];
}
+ inline void saveCurrentGlyph()
+ {
+ previousGlyph = 0;
+ if (currentPosition > 0 &&
+ logClusters[currentPosition - 1] < glyphs.numGlyphs) {
+ previousGlyph = currentGlyph(); // needed to calculate right bearing later
+ }
+ }
+
inline void adjustRightBearing(glyph_t glyph)
{
qreal rb;
@@ -1723,6 +1733,12 @@ namespace {
adjustRightBearing(currentGlyph());
}
+ inline void adjustPreviousRightBearing()
+ {
+ if (previousGlyph > 0)
+ adjustRightBearing(previousGlyph);
+ }
+
inline void resetRightBearing()
{
rightBearing = QFixed(1); // Any positive number is defined as invalid since only
@@ -1798,22 +1814,7 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
int item = -1;
- int newItem = -1;
- int left = 0;
- int right = eng->layoutData->items.size()-1;
- while(left <= right) {
- int middle = ((right-left)/2)+left;
- if (line.from > eng->layoutData->items[middle].position)
- left = middle+1;
- else if(line.from < eng->layoutData->items[middle].position)
- right = middle-1;
- else {
- newItem = middle;
- break;
- }
- }
- if (newItem == -1)
- newItem = right;
+ int newItem = eng->findItem(line.from);
LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
@@ -1825,6 +1826,7 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.currentPosition = line.from;
int end = 0;
lbh.logClusters = eng->layoutData->logClustersPtr;
+ lbh.previousGlyph = 0;
while (newItem < eng->layoutData->items.size()) {
lbh.resetRightBearing();
@@ -1885,6 +1887,7 @@ void QTextLine::layout_helper(int maxGlyphs)
current, lbh.logClusters, lbh.glyphs);
} else {
lbh.tmpData.length++;
+ lbh.adjustPreviousRightBearing();
}
line += lbh.tmpData;
goto found;
@@ -1915,9 +1918,7 @@ void QTextLine::layout_helper(int maxGlyphs)
} else {
lbh.whiteSpaceOrObject = false;
bool sb_or_ws = false;
- glyph_t previousGlyph = 0;
- if (lbh.currentPosition > 0 && lbh.logClusters[lbh.currentPosition - 1] <lbh.glyphs.numGlyphs)
- previousGlyph = lbh.currentGlyph(); // needed to calculate right bearing later
+ lbh.saveCurrentGlyph();
do {
addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
current, lbh.logClusters, lbh.glyphs);
@@ -1942,7 +1943,7 @@ void QTextLine::layout_helper(int maxGlyphs)
// b) if we are so short of available width that the
// soft hyphen is the first breakable position, then
// we don't want to show it. However we initially
- // have to take the width for it into accoun so that
+ // have to take the width for it into account so that
// the text document layout sees the overflow and
// switch to break-anywhere mode, in which we
// want the soft-hyphen to slip into the next line
@@ -1970,8 +1971,9 @@ void QTextLine::layout_helper(int maxGlyphs)
// we are too wide, fix right bearing
if (rightBearing <= 0)
lbh.rightBearing = rightBearing; // take from cache
- else if (previousGlyph > 0)
- lbh.adjustRightBearing(previousGlyph);
+ else
+ lbh.adjustPreviousRightBearing();
+
if (!breakany) {
line.textWidth += lbh.softHyphenWidth;
}
@@ -1979,6 +1981,7 @@ void QTextLine::layout_helper(int maxGlyphs)
goto found;
}
}
+ lbh.saveCurrentGlyph();
}
if (lbh.currentPosition == end)
newItem = item + 1;
diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp
index e323fd0..94f2fc7 100644
--- a/src/gui/text/qtextobject.cpp
+++ b/src/gui/text/qtextobject.cpp
@@ -1504,7 +1504,7 @@ QTextBlock QTextBlock::next() const
*/
QTextBlock QTextBlock::previous() const
{
- if (!isValid())
+ if (!p)
return QTextBlock();
return QTextBlock(p, p->blockMap().previous(n));
diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp
index d108ad9..5a281ad 100644
--- a/src/gui/widgets/qlinecontrol.cpp
+++ b/src/gui/widgets/qlinecontrol.cpp
@@ -414,13 +414,17 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event)
if (isGettingInput) {
// If any text is being input, remove selected text.
priorState = m_undoState;
+ if (echoMode() == QLineEdit::PasswordEchoOnEdit && !passwordEchoEditing()) {
+ updatePasswordEchoEditing(true);
+ m_selstart = 0;
+ m_selend = m_text.length();
+ }
removeSelectedText();
}
-
int c = m_cursor; // cursor position after insertion of commit string
if (event->replacementStart() <= 0)
- c += event->commitString().length() + qMin(-event->replacementStart(), event->replacementLength());
+ c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength());
m_cursor += event->replacementStart();