summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/dialogs/qdialog.cpp37
-rw-r--r--src/gui/dialogs/qdialog.h6
-rw-r--r--src/gui/dialogs/qprogressdialog.cpp11
-rw-r--r--src/gui/egl/qegl.cpp44
-rw-r--r--src/gui/egl/qegl_p.h1
-rw-r--r--src/gui/egl/qegl_stub.cpp17
-rw-r--r--src/gui/egl/qeglcontext_p.h1
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp14
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp22
-rw-r--r--src/gui/gui.pro128
-rw-r--r--src/gui/image/image.pri61
-rw-r--r--src/gui/image/qgifhandler.cpp1199
-rw-r--r--src/gui/image/qgifhandler.pri4
-rw-r--r--src/gui/image/qgifhandler_p.h96
-rw-r--r--src/gui/image/qimage.cpp18
-rw-r--r--src/gui/image/qimage_p.h4
-rw-r--r--src/gui/image/qimage_sse2.cpp109
-rw-r--r--src/gui/image/qimagereader.cpp78
-rw-r--r--src/gui/image/qimagewriter.cpp40
-rw-r--r--src/gui/image/qjpeghandler.cpp901
-rw-r--r--src/gui/image/qjpeghandler.pri10
-rw-r--r--src/gui/image/qjpeghandler_p.h76
-rw-r--r--src/gui/image/qmnghandler.cpp497
-rw-r--r--src/gui/image/qmnghandler.pri10
-rw-r--r--src/gui/image/qmnghandler_p.h83
-rw-r--r--src/gui/image/qpicture.cpp52
-rw-r--r--src/gui/image/qpixmapdatafactory.cpp4
-rw-r--r--src/gui/image/qpnghandler.pri10
-rw-r--r--src/gui/image/qtiffhandler.cpp661
-rw-r--r--src/gui/image/qtiffhandler.pri10
-rw-r--r--src/gui/image/qtiffhandler_p.h78
-rw-r--r--src/gui/kernel/kernel.pri11
-rw-r--r--src/gui/kernel/qapplication.cpp7
-rw-r--r--src/gui/kernel/qapplication.h8
-rw-r--r--src/gui/kernel/qapplication_s60.cpp15
-rw-r--r--src/gui/kernel/qapplication_win.cpp7
-rw-r--r--src/gui/kernel/qsoftkeymanager.cpp5
-rw-r--r--src/gui/kernel/qsoftkeymanager_common_p.h2
-rw-r--r--src/gui/kernel/qstandardgestures.cpp63
-rw-r--r--src/gui/kernel/qt_s60_p.h10
-rw-r--r--src/gui/kernel/qwidget.cpp2
-rw-r--r--src/gui/kernel/qwidget_mac.mm8
-rw-r--r--src/gui/kernel/qwidget_s60.cpp3
-rw-r--r--src/gui/kernel/qwidget_win.cpp2
-rw-r--r--src/gui/kernel/qx11embed_x11.cpp1
-rw-r--r--src/gui/painting/painting.pri164
-rw-r--r--src/gui/painting/qdrawhelper.cpp6
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp144
-rw-r--r--src/gui/painting/qdrawhelper_neon_asm.S105
-rw-r--r--src/gui/painting/qdrawhelper_neon_p.h3
-rw-r--r--src/gui/painting/qdrawhelper_p.h2
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp168
-rw-r--r--src/gui/painting/qdrawingprimitive_sse2_p.h222
-rw-r--r--src/gui/painting/qgraphicssystem.cpp4
-rw-r--r--src/gui/painting/qgraphicssystem_runtime.cpp2
-rw-r--r--src/gui/painting/qgraphicssystem_runtime_p.h2
-rw-r--r--src/gui/painting/qmemrotate.cpp51
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp24
-rw-r--r--src/gui/painting/qpainter.cpp9
-rw-r--r--src/gui/s60framework/qs60mainapplication.cpp23
-rw-r--r--src/gui/s60framework/qs60mainapplication.h20
-rw-r--r--src/gui/s60framework/qs60mainappui.cpp131
-rw-r--r--src/gui/s60framework/qs60mainappui.h75
-rw-r--r--src/gui/s60framework/qs60maindocument.cpp22
-rw-r--r--src/gui/s60framework/qs60maindocument.h20
-rw-r--r--src/gui/s60framework/s60framework.pri22
-rw-r--r--src/gui/styles/qs60style.cpp72
-rw-r--r--src/gui/styles/qs60style.h8
-rw-r--r--src/gui/styles/qs60style_stub.cpp131
-rw-r--r--src/gui/styles/qwindowsvistastyle.cpp25
-rw-r--r--src/gui/styles/qwindowsxpstyle.cpp4
-rw-r--r--src/gui/styles/styles.pri4
-rw-r--r--src/gui/text/qfont.cpp9
-rw-r--r--src/gui/text/qfont.h5
-rw-r--r--src/gui/text/qfont_mac.cpp6
-rw-r--r--src/gui/text/qfont_qws.cpp1
-rw-r--r--src/gui/text/qfont_win.cpp5
-rw-r--r--src/gui/text/qfont_x11.cpp9
-rw-r--r--src/gui/text/qfontengine_s60_p.h3
-rw-r--r--src/gui/text/qtextcursor.cpp4
-rw-r--r--src/gui/text/qtextcursor_p.h1
-rw-r--r--src/gui/text/qtextdocument.cpp8
-rw-r--r--src/gui/text/qtextdocument_p.cpp51
-rw-r--r--src/gui/text/qtextdocument_p.h6
-rw-r--r--src/gui/util/qdesktopservices_s60.cpp19
-rw-r--r--src/gui/util/util.pri3
-rw-r--r--src/gui/widgets/qcombobox.cpp5
-rw-r--r--src/gui/widgets/qmenubar_p.h2
88 files changed, 5387 insertions, 639 deletions
diff --git a/src/gui/dialogs/qdialog.cpp b/src/gui/dialogs/qdialog.cpp
index a6bd78a..9e0437c 100644
--- a/src/gui/dialogs/qdialog.cpp
+++ b/src/gui/dialogs/qdialog.cpp
@@ -67,12 +67,12 @@ extern bool qt_wince_is_smartphone(); //is defined in qguifunctions_wce.cpp
#elif defined(Q_OS_SYMBIAN)
# include "qfiledialog.h"
# include "qfontdialog.h"
-# include "qcolordialog.h"
# include "qwizard.h"
+# include "private/qt_s60_p.h"
#endif
#if defined(Q_WS_S60)
-#include "private/qt_s60_p.h"
+#include <AknUtils.h> // AknLayoutUtils
#endif
#ifndef SPI_GETSNAPTODEFBUTTON
@@ -393,7 +393,7 @@ void QDialogPrivate::resetModalitySetByOpen()
resetModalityTo = -1;
}
-#if defined(Q_WS_WINCE) || defined(Q_WS_S60)
+#if defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN)
#ifdef Q_WS_WINCE_WM
void QDialogPrivate::_q_doneAction()
{
@@ -413,7 +413,7 @@ bool QDialog::event(QEvent *e)
accept();
result = true;
}
-#else
+#elif defined(Q_WS_S60)
if ((e->type() == QEvent::StyleChange) || (e->type() == QEvent::Resize )) {
if (!testAttribute(Qt::WA_Moved)) {
Qt::WindowStates state = windowState();
@@ -423,6 +423,7 @@ bool QDialog::event(QEvent *e)
setWindowState(state);
}
}
+ // TODO is Symbian, non-S60 behaviour required?
#endif
return result;
}
@@ -527,14 +528,19 @@ int QDialog::exec()
#endif //QT_NO_MENUBAR
#endif //Q_WS_WINCE_WM
+ bool showSystemDialogFullScreen = false;
#ifdef Q_OS_SYMBIAN
if (qobject_cast<QFileDialog *>(this) || qobject_cast<QFontDialog *>(this) ||
- qobject_cast<QColorDialog *>(this) || qobject_cast<QWizard *>(this))
- showMaximized();
- else
+ qobject_cast<QWizard *>(this)) {
+ showSystemDialogFullScreen = true;
+ }
#endif // Q_OS_SYMBIAN
- show();
+ if (showSystemDialogFullScreen) {
+ setWindowFlags(windowFlags() | Qt::WindowSoftkeysVisibleHint);
+ setWindowState(Qt::WindowFullScreen);
+ }
+ show();
#ifdef Q_WS_MAC
d->mac_nativeDialogModalHelp();
@@ -818,8 +824,8 @@ void QDialog::adjustPosition(QWidget* w)
return;
#endif
-#ifdef Q_WS_S60
- if (s60AdjustedPosition())
+#ifdef Q_OS_SYMBIAN
+ if (symbianAdjustedPosition())
//dialog has already been positioned
return;
#endif
@@ -887,13 +893,12 @@ void QDialog::adjustPosition(QWidget* w)
move(p);
}
-#if defined(Q_WS_S60)
+#if defined(Q_OS_SYMBIAN)
/*! \internal */
-bool QDialog::s60AdjustedPosition()
+bool QDialog::symbianAdjustedPosition()
{
+#if defined(Q_WS_S60)
QPoint p;
- const QSize mainAreaSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size();
- const int statusPaneHeight = (S60->screenHeightInPixels - mainAreaSize.height())>>1;
const bool doS60Positioning = !(isFullScreen()||isMaximized());
if (doS60Positioning) {
// naive way to deduce screen orientation
@@ -937,6 +942,10 @@ bool QDialog::s60AdjustedPosition()
move(p);
}
return doS60Positioning;
+#else
+ // TODO - check positioning requirement for Symbian, non-s60
+ return false;
+#endif
}
#endif
diff --git a/src/gui/dialogs/qdialog.h b/src/gui/dialogs/qdialog.h
index 777256a..b2ba93c 100644
--- a/src/gui/dialogs/qdialog.h
+++ b/src/gui/dialogs/qdialog.h
@@ -107,7 +107,7 @@ public Q_SLOTS:
protected:
QDialog(QDialogPrivate &, QWidget *parent, Qt::WindowFlags f = 0);
-#if defined(Q_WS_WINCE) || defined(Q_WS_S60)
+#if defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN)
bool event(QEvent *e);
#endif
void keyPressEvent(QKeyEvent *);
@@ -123,8 +123,8 @@ private:
Q_DECLARE_PRIVATE(QDialog)
Q_DISABLE_COPY(QDialog)
-#if defined(Q_WS_S60)
- bool s60AdjustedPosition();
+#if defined(Q_OS_SYMBIAN)
+ bool symbianAdjustedPosition();
#endif
diff --git a/src/gui/dialogs/qprogressdialog.cpp b/src/gui/dialogs/qprogressdialog.cpp
index a2d7b23..d64c847 100644
--- a/src/gui/dialogs/qprogressdialog.cpp
+++ b/src/gui/dialogs/qprogressdialog.cpp
@@ -153,6 +153,13 @@ void QProgressDialogPrivate::layout()
const bool centered =
bool(q->style()->styleHint(QStyle::SH_ProgressDialog_CenterCancelButton, 0, q));
+ int additionalSpacing = 0;
+#ifdef Q_OS_SYMBIAN
+ //In Symbian, we need to have wider margins for dialog borders, as the actual border is some pixels
+ //inside the dialog area (to enable transparent borders)
+ additionalSpacing = mlr;
+#endif
+
QSize cs = cancel ? cancel->sizeHint() : QSize(0,0);
QSize bh = bar->sizeHint();
int cspc;
@@ -185,8 +192,8 @@ void QProgressDialogPrivate::layout()
}
if (label)
- label->setGeometry(mlr, 0, q->width()-mlr*2, lh);
- bar->setGeometry(mlr, lh+sp, q->width()-mlr*2, bh.height());
+ label->setGeometry(mlr, additionalSpacing, q->width() - mlr * 2, lh);
+ bar->setGeometry(mlr, lh + sp + additionalSpacing, q->width() - mlr * 2, bh.height());
}
void QProgressDialogPrivate::retranslateStrings()
diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp
index e6ea198..605b1e6 100644
--- a/src/gui/egl/qegl.cpp
+++ b/src/gui/egl/qegl.cpp
@@ -515,6 +515,31 @@ bool QEglContext::swapBuffers(EGLSurface surface)
return ok;
}
+bool QEglContext::swapBuffersRegion2NOK(EGLSurface surface, const QRegion *region) {
+ QVector<QRect> qrects = region->rects();
+ EGLint *gl_rects;
+ uint count;
+ uint i;
+
+ count = qrects.size();
+ QVarLengthArray <EGLint> arr(4 * count);
+ gl_rects = arr.data();
+ for (i = 0; i < count; i++) {
+ QRect qrect = qrects[i];
+
+ gl_rects[4 * i + 0] = qrect.x();
+ gl_rects[4 * i + 1] = qrect.y();
+ gl_rects[4 * i + 2] = qrect.width();
+ gl_rects[4 * i + 3] = qrect.height();
+ }
+
+ bool ok = QEgl::eglSwapBuffersRegion2NOK(QEgl::display(), surface, count, gl_rects);
+
+ if (!ok)
+ qWarning() << "QEglContext::swapBuffersRegion2NOK():" << QEgl::errorString();
+ return ok;
+}
+
int QEglContext::configAttrib(int name) const
{
EGLint value;
@@ -532,6 +557,9 @@ typedef EGLBoolean (EGLAPIENTRY *_eglDestroyImageKHR)(EGLDisplay, EGLImageKHR);
static _eglCreateImageKHR qt_eglCreateImageKHR = 0;
static _eglDestroyImageKHR qt_eglDestroyImageKHR = 0;
+typedef EGLBoolean (EGLAPIENTRY *_eglSwapBuffersRegion2NOK)(EGLDisplay, EGLSurface, EGLint, const EGLint*);
+
+static _eglSwapBuffersRegion2NOK qt_eglSwapBuffersRegion2NOK = 0;
EGLDisplay QEgl::display()
{
@@ -560,6 +588,10 @@ EGLDisplay QEgl::display()
qt_eglDestroyImageKHR = (_eglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR");
}
#endif
+
+ if (QEgl::hasExtension("EGL_NOK_swap_region2")) {
+ qt_eglSwapBuffersRegion2NOK = (_eglSwapBuffersRegion2NOK) eglGetProcAddress("eglSwapBuffersRegion2NOK");
+ }
}
return dpy;
@@ -591,6 +623,18 @@ EGLBoolean QEgl::eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
return 0;
}
+EGLBoolean QEgl::eglSwapBuffersRegion2NOK(EGLDisplay dpy, EGLSurface surface, EGLint count, const EGLint *rects)
+{
+ if (qt_eglSwapBuffersRegion2NOK)
+ return qt_eglSwapBuffersRegion2NOK(dpy, surface, count, rects);
+
+ QEgl::display(); // Initialises function pointers
+ if (qt_eglSwapBuffersRegion2NOK)
+ return qt_eglSwapBuffersRegion2NOK(dpy, surface, count, rects);
+
+ qWarning("QEgl::eglSwapBuffersRegion2NOK() called but EGL_NOK_swap_region2 extension not present");
+ return 0;
+}
#ifndef Q_WS_X11
EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *properties)
diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h
index 4fc1338..c214e88 100644
--- a/src/gui/egl/qegl_p.h
+++ b/src/gui/egl/qegl_p.h
@@ -224,6 +224,7 @@ namespace QEgl {
// Extension functions
Q_GUI_EXPORT EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
Q_GUI_EXPORT EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img);
+ Q_GUI_EXPORT EGLBoolean eglSwapBuffersRegion2NOK(EGLDisplay dpy, EGLSurface surface, EGLint count, const EGLint *rects);
#ifdef Q_WS_X11
Q_GUI_EXPORT VisualID getCompatibleVisualId(EGLConfig config);
diff --git a/src/gui/egl/qegl_stub.cpp b/src/gui/egl/qegl_stub.cpp
index 86a7aab..1adb56c 100644
--- a/src/gui/egl/qegl_stub.cpp
+++ b/src/gui/egl/qegl_stub.cpp
@@ -176,6 +176,14 @@ bool QEglContext::swapBuffers(EGLSurface surface)
return false;
}
+bool QEglContext::swapBuffersRegion2NOK(EGLSurface surface, const QRegion *region)
+{
+ Q_UNUSED(surface)
+ Q_UNUSED(region)
+ NOEGL
+ return false;
+}
+
int QEglContext::configAttrib(int name) const
{
Q_UNUSED(name)
@@ -208,6 +216,15 @@ EGLBoolean QEgl::eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
return 0;
}
+EGLBoolean QEgl::eglSwapBuffersRegion2NOK(EGLDisplay dpy, EGLSurface surface, EGLint count, const EGLint *rects)
+{
+ Q_UNUSED(dpy);
+ Q_UNUSED(surface);
+ Q_UNUSED(count);
+ Q_UNUSED(rects);
+ NOEGL
+ return 0;
+}
#ifndef Q_WS_X11
EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *properties)
diff --git a/src/gui/egl/qeglcontext_p.h b/src/gui/egl/qeglcontext_p.h
index ccde00d..cae8164 100644
--- a/src/gui/egl/qeglcontext_p.h
+++ b/src/gui/egl/qeglcontext_p.h
@@ -84,6 +84,7 @@ public:
bool doneCurrent();
bool lazyDoneCurrent();
bool swapBuffers(EGLSurface surface);
+ bool swapBuffersRegion2NOK(EGLSurface surface, const QRegion *region);
int configAttrib(int name) const;
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 61285d2..848de2c 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -5510,6 +5510,9 @@ void QGraphicsItemPrivate::setSubFocus(QGraphicsItem *rootItem)
// Update focus child chain. Stop at panels, or if this item
// is hidden, stop at the first item with a visible parent.
QGraphicsItem *parent = rootItem ? rootItem : q_ptr;
+ if (parent->panel() != q_ptr->panel())
+ return;
+
do {
// Clear any existing ancestor's subFocusItem.
if (parent != q_ptr && parent->d_ptr->subFocusItem) {
@@ -7317,10 +7320,13 @@ void QGraphicsItem::updateMicroFocus()
{
#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN))
if (QWidget *fw = QApplication::focusWidget()) {
- for (int i = 0 ; i < scene()->views().count() ; ++i)
- if (scene()->views().at(i) == fw)
- if (QInputContext *inputContext = fw->inputContext())
- inputContext->update();
+ if (scene()) {
+ for (int i = 0 ; i < scene()->views().count() ; ++i) {
+ if (scene()->views().at(i) == fw)
+ if (QInputContext *inputContext = fw->inputContext())
+ inputContext->update();
+ }
+ }
#ifndef QT_NO_ACCESSIBILITY
// ##### is this correct
QAccessible::updateAccessibility(fw, 0, QAccessible::StateChanged);
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index d04074a..4bc7f4c 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -885,8 +885,7 @@ void QGraphicsScenePrivate::removePopup(QGraphicsWidget *widget, bool itemIsDyin
ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
}
if (!itemIsDying && widget->isVisible()) {
- widget->hide();
- widget->QGraphicsItem::d_ptr->explicitlyHidden = 0;
+ widget->QGraphicsItem::d_ptr->setVisibleHelper(false, /* explicit = */ false);
}
}
}
@@ -4165,6 +4164,25 @@ void QGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent)
wheelEvent->scenePos(),
wheelEvent->widget());
+#ifdef Q_WS_MAC
+ // On Mac, ignore the event if the first item under the mouse is not the last opened
+ // popup (or one of its descendant)
+ if (!d->popupWidgets.isEmpty() && !wheelCandidates.isEmpty() && wheelCandidates.first() != d->popupWidgets.back() && !d->popupWidgets.back()->isAncestorOf(wheelCandidates.first())) {
+ wheelEvent->accept();
+ return;
+ }
+#else
+ // Find the first popup under the mouse (including the popup's descendants) starting from the last.
+ // Remove all popups after the one found, or all or them if no popup is under the mouse.
+ // Then continue with the event.
+ QList<QGraphicsWidget *>::const_iterator iter = d->popupWidgets.end();
+ while (--iter >= d->popupWidgets.begin() && !wheelCandidates.isEmpty()) {
+ if (wheelCandidates.first() == *iter || (*iter)->isAncestorOf(wheelCandidates.first()))
+ break;
+ d->removePopup(*iter);
+ }
+#endif
+
bool hasSetFocus = false;
foreach (QGraphicsItem *item, wheelCandidates) {
if (!hasSetFocus && item->isEnabled()
diff --git a/src/gui/gui.pro b/src/gui/gui.pro
index 7f1cb78..41f1904 100644
--- a/src/gui/gui.pro
+++ b/src/gui/gui.pro
@@ -72,8 +72,134 @@ symbian {
pu_header = "; Partial upgrade package for testing QtGui changes without reinstalling everything" \
"$${LITERAL_HASH}{\"Qt gui\"}, (0x2001E61C), $${QT_MAJOR_VERSION},$${QT_MINOR_VERSION},$${QT_PATCH_VERSION}, TYPE=PU"
partial_upgrade.pkg_prerules = pu_header vendorinfo
- partial_upgrade.sources = $$QMAKE_LIBDIR_QT/QtGui.dll
+ partial_upgrade.sources = $$QMAKE_LIBDIR_QT/QtGui$${QT_LIBINFIX}.dll
partial_upgrade.path = c:/sys/bin
DEPLOYMENT = partial_upgrade $$DEPLOYMENT
}
+contains(QMAKE_MAC_XARCH, no) {
+ DEFINES += QT_NO_MAC_XARCH
+} else {
+ mmx:DEFINES += QT_HAVE_MMX
+ 3dnow:DEFINES += QT_HAVE_3DNOW
+ sse:DEFINES += QT_HAVE_SSE QT_HAVE_MMXEXT
+ sse2:DEFINES += QT_HAVE_SSE2
+ iwmmxt:DEFINES += QT_HAVE_IWMMXT
+
+ win32-g++*|!win32:!*-icc* {
+ mmx {
+ mmx_compiler.commands = $$QMAKE_CXX -c -Winline
+
+ mac {
+ mmx_compiler.commands += -Xarch_i386 -mmmx
+ mmx_compiler.commands += -Xarch_x86_64 -mmmx
+ } else {
+ mmx_compiler.commands += -mmmx
+ }
+
+ mmx_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
+ mmx_compiler.dependency_type = TYPE_C
+ mmx_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ mmx_compiler.input = MMX_SOURCES
+ mmx_compiler.variable_out = OBJECTS
+ mmx_compiler.name = compiling[mmx] ${QMAKE_FILE_IN}
+ silent:mmx_compiler.commands = @echo compiling[mmx] ${QMAKE_FILE_IN} && $$mmx_compiler.commands
+ QMAKE_EXTRA_COMPILERS += mmx_compiler
+ }
+ 3dnow {
+ mmx3dnow_compiler.commands = $$QMAKE_CXX -c -Winline
+
+ mac {
+ mmx3dnow_compiler.commands += -Xarch_i386 -m3dnow -Xarch_i386 -mmmx
+ mmx3dnow_compiler.commands += -Xarch_x86_64 -m3dnow -Xarch_x86_64 -mmmx
+ } else {
+ mmx3dnow_compiler.commands += -m3dnow -mmmx
+ }
+
+ mmx3dnow_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
+ mmx3dnow_compiler.dependency_type = TYPE_C
+ mmx3dnow_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ mmx3dnow_compiler.input = MMX3DNOW_SOURCES
+ mmx3dnow_compiler.variable_out = OBJECTS
+ mmx3dnow_compiler.name = compiling[mmx3dnow] ${QMAKE_FILE_IN}
+ silent:mmx3dnow_compiler.commands = @echo compiling[mmx3dnow] ${QMAKE_FILE_IN} && $$mmx3dnow_compiler.commands
+ QMAKE_EXTRA_COMPILERS += mmx3dnow_compiler
+ sse {
+ sse3dnow_compiler.commands = $$QMAKE_CXX -c -Winline
+
+ mac {
+ sse3dnow_compiler.commands += -Xarch_i386 -m3dnow -Xarch_i386 -msse
+ sse3dnow_compiler.commands += -Xarch_x86_64 -m3dnow -Xarch_x86_64 -msse
+ } else {
+ sse3dnow_compiler.commands += -m3dnow -msse
+ }
+
+ sse3dnow_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
+ sse3dnow_compiler.dependency_type = TYPE_C
+ sse3dnow_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ sse3dnow_compiler.input = SSE3DNOW_SOURCES
+ sse3dnow_compiler.variable_out = OBJECTS
+ sse3dnow_compiler.name = compiling[sse3dnow] ${QMAKE_FILE_IN}
+ silent:sse3dnow_compiler.commands = @echo compiling[sse3dnow] ${QMAKE_FILE_IN} && $$sse3dnow_compiler.commands
+ QMAKE_EXTRA_COMPILERS += sse3dnow_compiler
+ }
+ }
+ sse {
+ sse_compiler.commands = $$QMAKE_CXX -c -Winline
+
+ mac {
+ sse_compiler.commands += -Xarch_i386 -msse
+ sse_compiler.commands += -Xarch_x86_64 -msse
+ } else {
+ sse_compiler.commands += -msse
+ }
+
+ sse_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
+ sse_compiler.dependency_type = TYPE_C
+ sse_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ sse_compiler.input = SSE_SOURCES
+ sse_compiler.variable_out = OBJECTS
+ sse_compiler.name = compiling[sse] ${QMAKE_FILE_IN}
+ silent:sse_compiler.commands = @echo compiling[sse] ${QMAKE_FILE_IN} && $$sse_compiler.commands
+ QMAKE_EXTRA_COMPILERS += sse_compiler
+ }
+ sse2 {
+ sse2_compiler.commands = $$QMAKE_CXX -c -Winline
+
+ mac {
+ sse2_compiler.commands += -Xarch_i386 -msse2
+ sse2_compiler.commands += -Xarch_x86_64 -msse2
+ } else {
+ sse2_compiler.commands += -msse2
+ }
+
+ sse2_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
+ sse2_compiler.dependency_type = TYPE_C
+ sse2_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ sse2_compiler.input = SSE2_SOURCES
+ sse2_compiler.variable_out = OBJECTS
+ sse2_compiler.name = compiling[sse2] ${QMAKE_FILE_IN}
+ silent:sse2_compiler.commands = @echo compiling[sse2] ${QMAKE_FILE_IN} && $$sse2_compiler.commands
+ QMAKE_EXTRA_COMPILERS += sse2_compiler
+ }
+ iwmmxt {
+ iwmmxt_compiler.commands = $$QMAKE_CXX -c -Winline
+ iwmmxt_compiler.commands += -mcpu=iwmmxt
+ iwmmxt_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
+ iwmmxt_compiler.dependency_type = TYPE_C
+ iwmmxt_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ iwmmxt_compiler.input = IWMMXT_SOURCES
+ iwmmxt_compiler.variable_out = OBJECTS
+ iwmmxt_compiler.name = compiling[iwmmxt] ${QMAKE_FILE_IN}
+ silent:iwmmxt_compiler.commands = @echo compiling[iwmmxt] ${QMAKE_FILE_IN} && $$iwmmxt_compiler.commands
+ QMAKE_EXTRA_COMPILERS += iwmmxt_compiler
+ }
+ } else {
+ mmx: SOURCES += $$MMX_SOURCES
+ 3dnow: SOURCES += $$MMX3DNOW_SOURCES
+ 3dnow:sse: SOURCES += $$SSE3DNOW_SOURCES
+ sse: SOURCES += $$SSE_SOURCES
+ sse2: SOURCES += $$SSE2_SOURCES
+ iwmmxt: SOURCES += $$IWMMXT_SOURCES
+ }
+}
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index c4eac95..3a02d56 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -28,8 +28,7 @@ HEADERS += \
image/qpixmapdata_p.h \
image/qpixmapdatafactory_p.h \
image/qpixmapfilter_p.h \
- image/qimagepixmapcleanuphooks_p.h \
-
+ image/qimagepixmapcleanuphooks_p.h
SOURCES += \
image/qbitmap.cpp \
@@ -52,24 +51,23 @@ SOURCES += \
image/qmovie.cpp \
image/qpixmap_raster.cpp \
image/qnativeimage.cpp \
- image/qimagepixmapcleanuphooks.cpp \
-
+ image/qimagepixmapcleanuphooks.cpp
win32 {
SOURCES += image/qpixmap_win.cpp
}
-embedded {
+else:embedded {
SOURCES += image/qpixmap_qws.cpp
}
-x11 {
+else:x11 {
HEADERS += image/qpixmap_x11_p.h
- SOURCES += image/qpixmap_x11.cpp
+ SOURCES += image/qpixmap_x11.cpp
}
-mac {
+else:mac {
HEADERS += image/qpixmap_mac_p.h
SOURCES += image/qpixmap_mac.cpp
}
-symbian {
+else:symbian {
HEADERS += image/qpixmap_s60_p.h
SOURCES += image/qpixmap_s60.cpp
}
@@ -87,42 +85,13 @@ SOURCES += \
image/qxbmhandler.cpp \
image/qxpmhandler.cpp
-# 3rd party / system PNG support
-!contains(QT_CONFIG, no-png) {
- HEADERS += image/qpnghandler_p.h
- SOURCES += image/qpnghandler.cpp
+!contains(QT_CONFIG, no-png):include($$PWD/qpnghandler.pri)
+else:DEFINES *= QT_NO_IMAGEFORMAT_PNG
- contains(QT_CONFIG, system-png) {
- unix|win32-g++*:LIBS_PRIVATE += -lpng
- win32:!win32-g++*:LIBS += libpng.lib
- } else {
- DEFINES *= QT_USE_BUNDLED_LIBPNG
- !isEqual(QT_ARCH, i386):!isEqual(QT_ARCH, x86_64):DEFINES += PNG_NO_ASSEMBLER_CODE
- INCLUDEPATH += ../3rdparty/libpng
- SOURCES += ../3rdparty/libpng/png.c \
- ../3rdparty/libpng/pngerror.c \
- ../3rdparty/libpng/pngget.c \
- ../3rdparty/libpng/pngmem.c \
- ../3rdparty/libpng/pngpread.c \
- ../3rdparty/libpng/pngread.c \
- ../3rdparty/libpng/pngrio.c \
- ../3rdparty/libpng/pngrtran.c \
- ../3rdparty/libpng/pngrutil.c \
- ../3rdparty/libpng/pngset.c \
- ../3rdparty/libpng/pngtrans.c \
- ../3rdparty/libpng/pngwio.c \
- ../3rdparty/libpng/pngwrite.c \
- ../3rdparty/libpng/pngwtran.c \
- ../3rdparty/libpng/pngwutil.c
+contains(QT_CONFIG, jpeg):include($$PWD/qjpeghandler.pri)
+contains(QT_CONFIG, mng):include($$PWD/qmnghandler.pri)
+contains(QT_CONFIG, tiff):include($$PWD/qtiffhandler.pri)
+contains(QT_CONFIG, gif):include($$PWD/qgifhandler.pri)
- contains(QT_CONFIG, system-zlib) {
- symbian:LIBS_PRIVATE += -llibz
- else:if(unix|win32-g++*):LIBS_PRIVATE += -lz
- else:LIBS += zdll.lib
- } else {
- INCLUDEPATH += ../3rdparty/zlib
- }
- }
-} else {
- DEFINES *= QT_NO_IMAGEFORMAT_PNG
-}
+# SIMD
+SSE2_SOURCES += image/qimage_sse2.cpp
diff --git a/src/gui/image/qgifhandler.cpp b/src/gui/image/qgifhandler.cpp
new file mode 100644
index 0000000..124d27b
--- /dev/null
+++ b/src/gui/image/qgifhandler.cpp
@@ -0,0 +1,1199 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins 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$
+**
+** WARNING:
+** A separate license from Unisys may be required to use the gif
+** reader. See http://www.unisys.com/about__unisys/lzw/
+** for information from Unisys
+**
+****************************************************************************/
+
+#include "qgifhandler_p.h"
+
+#include <qimage.h>
+#include <qiodevice.h>
+#include <qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+#define Q_TRANSPARENT 0x00ffffff
+
+// avoid going through QImage::scanLine() which calls detach
+#define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl)
+
+
+/*
+ Incremental image decoder for GIF image format.
+
+ This subclass of QImageFormat decodes GIF format images,
+ including animated GIFs. Internally in
+*/
+
+class QGIFFormat {
+public:
+ QGIFFormat();
+ ~QGIFFormat();
+
+ int decode(QImage *image, const uchar* buffer, int length,
+ int *nextFrameDelay, int *loopCount);
+ static void scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount);
+
+ bool newFrame;
+ bool partialNewFrame;
+
+private:
+ void fillRect(QImage *image, int x, int y, int w, int h, QRgb col);
+ inline QRgb color(uchar index) const;
+
+ // GIF specific stuff
+ QRgb* globalcmap;
+ QRgb* localcmap;
+ QImage backingstore;
+ unsigned char hold[16];
+ bool gif89;
+ int count;
+ int ccount;
+ int expectcount;
+ enum State {
+ Header,
+ LogicalScreenDescriptor,
+ GlobalColorMap,
+ LocalColorMap,
+ Introducer,
+ ImageDescriptor,
+ TableImageLZWSize,
+ ImageDataBlockSize,
+ ImageDataBlock,
+ ExtensionLabel,
+ GraphicControlExtension,
+ ApplicationExtension,
+ NetscapeExtensionBlockSize,
+ NetscapeExtensionBlock,
+ SkipBlockSize,
+ SkipBlock,
+ Done,
+ Error
+ } state;
+ int gncols;
+ int lncols;
+ int ncols;
+ int lzwsize;
+ bool lcmap;
+ int swidth, sheight;
+ int width, height;
+ int left, top, right, bottom;
+ enum Disposal { NoDisposal, DoNotChange, RestoreBackground, RestoreImage };
+ Disposal disposal;
+ bool disposed;
+ int trans_index;
+ bool gcmap;
+ int bgcol;
+ int interlace;
+ int accum;
+ int bitcount;
+
+ enum { max_lzw_bits=12 }; // (poor-compiler's static const int)
+
+ int code_size, clear_code, end_code, max_code_size, max_code;
+ int firstcode, oldcode, incode;
+ short* table[2];
+ short* stack;
+ short *sp;
+ bool needfirst;
+ int x, y;
+ int frame;
+ bool out_of_bounds;
+ bool digress;
+ void nextY(unsigned char *bits, int bpl);
+ void disposePrevious(QImage *image);
+};
+
+/*!
+ Constructs a QGIFFormat.
+*/
+QGIFFormat::QGIFFormat()
+{
+ globalcmap = 0;
+ localcmap = 0;
+ lncols = 0;
+ gncols = 0;
+ disposal = NoDisposal;
+ out_of_bounds = false;
+ disposed = true;
+ frame = -1;
+ state = Header;
+ count = 0;
+ lcmap = false;
+ newFrame = false;
+ partialNewFrame = false;
+ table[0] = 0;
+ table[1] = 0;
+ stack = 0;
+}
+
+/*!
+ Destroys a QGIFFormat.
+*/
+QGIFFormat::~QGIFFormat()
+{
+ if (globalcmap) delete[] globalcmap;
+ if (localcmap) delete[] localcmap;
+ delete [] stack;
+}
+
+void QGIFFormat::disposePrevious(QImage *image)
+{
+ if (out_of_bounds) {
+ // flush anything that survived
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ }
+
+ // Handle disposal of previous image before processing next one
+
+ if (disposed) return;
+
+ int l = qMin(swidth-1,left);
+ int r = qMin(swidth-1,right);
+ int t = qMin(sheight-1,top);
+ int b = qMin(sheight-1,bottom);
+
+ switch (disposal) {
+ case NoDisposal:
+ break;
+ case DoNotChange:
+ break;
+ case RestoreBackground:
+ if (trans_index>=0) {
+ // Easy: we use the transparent color
+ fillRect(image, l, t, r-l+1, b-t+1, Q_TRANSPARENT);
+ } else if (bgcol>=0) {
+ // Easy: we use the bgcol given
+ fillRect(image, l, t, r-l+1, b-t+1, color(bgcol));
+ } else {
+ // Impossible: We don't know of a bgcol - use pixel 0
+ QRgb *bits = (QRgb*)image->bits();
+ fillRect(image, l, t, r-l+1, b-t+1, bits[0]);
+ }
+ // ### Changed: QRect(l, t, r-l+1, b-t+1)
+ break;
+ case RestoreImage: {
+ if (frame >= 0) {
+ for (int ln=t; ln<=b; ln++) {
+ memcpy(image->scanLine(ln)+l,
+ backingstore.scanLine(ln-t),
+ (r-l+1)*sizeof(QRgb));
+ }
+ // ### Changed: QRect(l, t, r-l+1, b-t+1)
+ }
+ }
+ }
+ disposal = NoDisposal; // Until an extension says otherwise.
+
+ disposed = true;
+}
+
+/*!
+ This function decodes some data into image changes.
+
+ Returns the number of bytes consumed.
+*/
+int QGIFFormat::decode(QImage *image, const uchar *buffer, int length,
+ int *nextFrameDelay, int *loopCount)
+{
+ // We are required to state that
+ // "The Graphics Interchange Format(c) is the Copyright property of
+ // CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ // CompuServe Incorporated."
+
+ if (!stack) {
+ stack = new short[(1 << max_lzw_bits) * 4];
+ table[0] = &stack[(1 << max_lzw_bits) * 2];
+ table[1] = &stack[(1 << max_lzw_bits) * 3];
+ }
+
+ image->detach();
+ int bpl = image->bytesPerLine();
+ unsigned char *bits = image->bits();
+
+#define LM(l, m) (((m)<<8)|l)
+ digress = false;
+ const int initial = length;
+ while (!digress && length) {
+ length--;
+ unsigned char ch=*buffer++;
+ switch (state) {
+ case Header:
+ hold[count++]=ch;
+ if (count==6) {
+ // Header
+ gif89=(hold[3]!='8' || hold[4]!='7');
+ state=LogicalScreenDescriptor;
+ count=0;
+ }
+ break;
+ case LogicalScreenDescriptor:
+ hold[count++]=ch;
+ if (count==7) {
+ // Logical Screen Descriptor
+ swidth=LM(hold[0], hold[1]);
+ sheight=LM(hold[2], hold[3]);
+ gcmap=!!(hold[4]&0x80);
+ //UNUSED: bpchan=(((hold[4]&0x70)>>3)+1);
+ //UNUSED: gcmsortflag=!!(hold[4]&0x08);
+ gncols=2<<(hold[4]&0x7);
+ bgcol=(gcmap) ? hold[5] : -1;
+ //aspect=hold[6] ? double(hold[6]+15)/64.0 : 1.0;
+
+ trans_index = -1;
+ count=0;
+ ncols=gncols;
+ if (gcmap) {
+ ccount=0;
+ state=GlobalColorMap;
+ globalcmap = new QRgb[gncols+1]; // +1 for trans_index
+ globalcmap[gncols] = Q_TRANSPARENT;
+ } else {
+ state=Introducer;
+ }
+ }
+ break;
+ case GlobalColorMap: case LocalColorMap:
+ hold[count++]=ch;
+ if (count==3) {
+ QRgb rgb = qRgb(hold[0], hold[1], hold[2]);
+ if (state == LocalColorMap) {
+ if (ccount < lncols)
+ localcmap[ccount] = rgb;
+ } else {
+ globalcmap[ccount] = rgb;
+ }
+ if (++ccount >= ncols) {
+ if (state == LocalColorMap)
+ state=TableImageLZWSize;
+ else
+ state=Introducer;
+ }
+ count=0;
+ }
+ break;
+ case Introducer:
+ hold[count++]=ch;
+ switch (ch) {
+ case ',':
+ state=ImageDescriptor;
+ break;
+ case '!':
+ state=ExtensionLabel;
+ break;
+ case ';':
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ state=Done;
+ break;
+ default:
+ digress=true;
+ // Unexpected Introducer - ignore block
+ state=Error;
+ }
+ break;
+ case ImageDescriptor:
+ hold[count++]=ch;
+ if (count==10) {
+ int newleft=LM(hold[1], hold[2]);
+ int newtop=LM(hold[3], hold[4]);
+ int newwidth=LM(hold[5], hold[6]);
+ int newheight=LM(hold[7], hold[8]);
+
+ // disbelieve ridiculous logical screen sizes,
+ // unless the image frames are also large.
+ if (swidth/10 > qMax(newwidth,200))
+ swidth = -1;
+ if (sheight/10 > qMax(newheight,200))
+ sheight = -1;
+
+ if (swidth <= 0)
+ swidth = newleft + newwidth;
+ if (sheight <= 0)
+ sheight = newtop + newheight;
+
+ QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32;
+ if (image->isNull()) {
+ (*image) = QImage(swidth, sheight, format);
+ bpl = image->bytesPerLine();
+ bits = image->bits();
+ memset(bits, 0, image->byteCount());
+ }
+
+ disposePrevious(image);
+ disposed = false;
+
+ left = newleft;
+ top = newtop;
+ width = newwidth;
+ height = newheight;
+
+ right=qMax(0, qMin(left+width, swidth)-1);
+ bottom=qMax(0, qMin(top+height, sheight)-1);
+ lcmap=!!(hold[9]&0x80);
+ interlace=!!(hold[9]&0x40);
+ //bool lcmsortflag=!!(hold[9]&0x20);
+ lncols=lcmap ? (2<<(hold[9]&0x7)) : 0;
+ if (lncols) {
+ if (localcmap)
+ delete [] localcmap;
+ localcmap = new QRgb[lncols+1];
+ localcmap[lncols] = Q_TRANSPARENT;
+ ncols = lncols;
+ } else {
+ ncols = gncols;
+ }
+ frame++;
+ if (frame == 0) {
+ if (left || top || width<swidth || height<sheight) {
+ // Not full-size image - erase with bg or transparent
+ if (trans_index >= 0) {
+ fillRect(image, 0, 0, swidth, sheight, color(trans_index));
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ } else if (bgcol>=0) {
+ fillRect(image, 0, 0, swidth, sheight, color(bgcol));
+ // ### Changed: QRect(0, 0, swidth, sheight)
+ }
+ }
+ }
+
+ if (disposal == RestoreImage) {
+ int l = qMin(swidth-1,left);
+ int r = qMin(swidth-1,right);
+ int t = qMin(sheight-1,top);
+ int b = qMin(sheight-1,bottom);
+ int w = r-l+1;
+ int h = b-t+1;
+
+ if (backingstore.width() < w
+ || backingstore.height() < h) {
+ // We just use the backing store as a byte array
+ backingstore = QImage(qMax(backingstore.width(), w),
+ qMax(backingstore.height(), h),
+ QImage::Format_RGB32);
+ memset(bits, 0, image->byteCount());
+ }
+ const int dest_bpl = backingstore.bytesPerLine();
+ unsigned char *dest_data = backingstore.bits();
+ for (int ln=0; ln<h; ln++) {
+ memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln),
+ FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb));
+ }
+ }
+
+ count=0;
+ if (lcmap) {
+ ccount=0;
+ state=LocalColorMap;
+ } else {
+ state=TableImageLZWSize;
+ }
+ x = left;
+ y = top;
+ accum = 0;
+ bitcount = 0;
+ sp = stack;
+ firstcode = oldcode = 0;
+ needfirst = true;
+ out_of_bounds = left>=swidth || y>=sheight;
+ }
+ break;
+ case TableImageLZWSize: {
+ lzwsize=ch;
+ if (lzwsize > max_lzw_bits) {
+ state=Error;
+ } else {
+ code_size=lzwsize+1;
+ clear_code=1<<lzwsize;
+ end_code=clear_code+1;
+ max_code_size=2*clear_code;
+ max_code=clear_code+2;
+ int i;
+ for (i=0; i<clear_code; i++) {
+ table[0][i]=0;
+ table[1][i]=i;
+ }
+ state=ImageDataBlockSize;
+ }
+ count=0;
+ break;
+ } case ImageDataBlockSize:
+ expectcount=ch;
+ if (expectcount) {
+ state=ImageDataBlock;
+ } else {
+ state=Introducer;
+ digress = true;
+ newFrame = true;
+ }
+ break;
+ case ImageDataBlock:
+ count++;
+ accum|=(ch<<bitcount);
+ bitcount+=8;
+ while (bitcount>=code_size && state==ImageDataBlock) {
+ int code=accum&((1<<code_size)-1);
+ bitcount-=code_size;
+ accum>>=code_size;
+
+ if (code==clear_code) {
+ if (!needfirst) {
+ code_size=lzwsize+1;
+ max_code_size=2*clear_code;
+ max_code=clear_code+2;
+ }
+ needfirst=true;
+ } else if (code==end_code) {
+ bitcount = -32768;
+ // Left the block end arrive
+ } else {
+ if (needfirst) {
+ firstcode=oldcode=code;
+ if (!out_of_bounds && image->height() > y && firstcode!=trans_index)
+ ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode);
+ x++;
+ if (x>=swidth) out_of_bounds = true;
+ needfirst=false;
+ if (x>=left+width) {
+ x=left;
+ out_of_bounds = left>=swidth || y>=sheight;
+ nextY(bits, bpl);
+ }
+ } else {
+ incode=code;
+ if (code>=max_code) {
+ *sp++=firstcode;
+ code=oldcode;
+ }
+ while (code>=clear_code+2) {
+ *sp++=table[1][code];
+ if (code==table[0][code]) {
+ state=Error;
+ break;
+ }
+ if (sp-stack>=(1<<(max_lzw_bits))*2) {
+ state=Error;
+ break;
+ }
+ code=table[0][code];
+ }
+ *sp++=firstcode=table[1][code];
+ code=max_code;
+ if (code<(1<<max_lzw_bits)) {
+ table[0][code]=oldcode;
+ table[1][code]=firstcode;
+ max_code++;
+ if ((max_code>=max_code_size)
+ && (max_code_size<(1<<max_lzw_bits)))
+ {
+ max_code_size*=2;
+ code_size++;
+ }
+ }
+ oldcode=incode;
+ const int h = image->height();
+ const QRgb *map = lcmap ? localcmap : globalcmap;
+ QRgb *line = 0;
+ if (!out_of_bounds && h > y)
+ line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
+ while (sp>stack) {
+ const uchar index = *(--sp);
+ if (!out_of_bounds && h > y && index!=trans_index) {
+ if (index > ncols)
+ line[x] = Q_TRANSPARENT;
+ else
+ line[x] = map ? map[index] : 0;
+ }
+ x++;
+ if (x>=swidth) out_of_bounds = true;
+ if (x>=left+width) {
+ x=left;
+ out_of_bounds = left>=swidth || y>=sheight;
+ nextY(bits, bpl);
+ if (!out_of_bounds && h > y)
+ line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y);
+ }
+ }
+ }
+ }
+ }
+ partialNewFrame = true;
+ if (count==expectcount) {
+ count=0;
+ state=ImageDataBlockSize;
+ }
+ break;
+ case ExtensionLabel:
+ switch (ch) {
+ case 0xf9:
+ state=GraphicControlExtension;
+ break;
+ case 0xff:
+ state=ApplicationExtension;
+ break;
+#if 0
+ case 0xfe:
+ state=CommentExtension;
+ break;
+ case 0x01:
+ break;
+#endif
+ default:
+ state=SkipBlockSize;
+ }
+ count=0;
+ break;
+ case ApplicationExtension:
+ if (count<11) hold[count]=ch;
+ count++;
+ if (count==hold[0]+1) {
+ if (qstrncmp((char*)(hold+1), "NETSCAPE", 8)==0) {
+ // Looping extension
+ state=NetscapeExtensionBlockSize;
+ } else {
+ state=SkipBlockSize;
+ }
+ count=0;
+ }
+ break;
+ case NetscapeExtensionBlockSize:
+ expectcount=ch;
+ count=0;
+ if (expectcount) state=NetscapeExtensionBlock;
+ else state=Introducer;
+ break;
+ case NetscapeExtensionBlock:
+ if (count<3) hold[count]=ch;
+ count++;
+ if (count==expectcount) {
+ *loopCount = hold[1]+hold[2]*256;
+ state=SkipBlockSize; // Ignore further blocks
+ }
+ break;
+ case GraphicControlExtension:
+ if (count<5) hold[count]=ch;
+ count++;
+ if (count==hold[0]+1) {
+ disposePrevious(image);
+ disposal=Disposal((hold[1]>>2)&0x7);
+ //UNUSED: waitforuser=!!((hold[1]>>1)&0x1);
+ int delay=count>3 ? LM(hold[2], hold[3]) : 1;
+ // IE and mozilla use a minimum delay of 10. With the minimum delay of 10
+ // we are compatible to them and avoid huge loads on the app and xserver.
+ *nextFrameDelay = (delay < 2 ? 10 : delay) * 10;
+
+ bool havetrans=hold[1]&0x1;
+ trans_index = havetrans ? hold[4] : -1;
+
+ count=0;
+ state=SkipBlockSize;
+ }
+ break;
+ case SkipBlockSize:
+ expectcount=ch;
+ count=0;
+ if (expectcount) state=SkipBlock;
+ else state=Introducer;
+ break;
+ case SkipBlock:
+ count++;
+ if (count==expectcount) state=SkipBlockSize;
+ break;
+ case Done:
+ digress=true;
+ /* Netscape ignores the junk, so we do too.
+ length++; // Unget
+ state=Error; // More calls to this is an error
+ */
+ break;
+ case Error:
+ return -1; // Called again after done.
+ }
+ }
+ return initial-length;
+}
+
+/*!
+ Scans through the data stream defined by \a device and returns the image
+ sizes found in the stream in the \a imageSizes vector.
+*/
+void QGIFFormat::scan(QIODevice *device, QVector<QSize> *imageSizes, int *loopCount)
+{
+ if (!device)
+ return;
+
+ qint64 oldPos = device->pos();
+ if (!device->seek(0))
+ return;
+
+ int colorCount = 0;
+ int localColorCount = 0;
+ int globalColorCount = 0;
+ int colorReadCount = 0;
+ bool localColormap = false;
+ bool globalColormap = false;
+ int count = 0;
+ int blockSize = 0;
+ int imageWidth = 0;
+ int imageHeight = 0;
+ bool done = false;
+ uchar hold[16];
+ State state = Header;
+
+ const int readBufferSize = 40960; // 40k read buffer
+ QByteArray readBuffer(device->read(readBufferSize));
+
+ if (readBuffer.isEmpty()) {
+ device->seek(oldPos);
+ return;
+ }
+
+ // This is a specialized version of the state machine from decode(),
+ // which doesn't do any image decoding or mallocing, and has an
+ // optimized way of skipping SkipBlocks, ImageDataBlocks and
+ // Global/LocalColorMaps.
+
+ while (!readBuffer.isEmpty()) {
+ int length = readBuffer.size();
+ const uchar *buffer = (const uchar *) readBuffer.constData();
+ while (!done && length) {
+ length--;
+ uchar ch = *buffer++;
+ switch (state) {
+ case Header:
+ hold[count++] = ch;
+ if (count == 6) {
+ state = LogicalScreenDescriptor;
+ count = 0;
+ }
+ break;
+ case LogicalScreenDescriptor:
+ hold[count++] = ch;
+ if (count == 7) {
+ imageWidth = LM(hold[0], hold[1]);
+ imageHeight = LM(hold[2], hold[3]);
+ globalColormap = !!(hold[4] & 0x80);
+ globalColorCount = 2 << (hold[4] & 0x7);
+ count = 0;
+ colorCount = globalColorCount;
+ if (globalColormap) {
+ int colorTableSize = 3 * globalColorCount;
+ if (length >= colorTableSize) {
+ // skip the global color table in one go
+ length -= colorTableSize;
+ buffer += colorTableSize;
+ state = Introducer;
+ } else {
+ colorReadCount = 0;
+ state = GlobalColorMap;
+ }
+ } else {
+ state=Introducer;
+ }
+ }
+ break;
+ case GlobalColorMap:
+ case LocalColorMap:
+ hold[count++] = ch;
+ if (count == 3) {
+ if (++colorReadCount >= colorCount) {
+ if (state == LocalColorMap)
+ state = TableImageLZWSize;
+ else
+ state = Introducer;
+ }
+ count = 0;
+ }
+ break;
+ case Introducer:
+ hold[count++] = ch;
+ switch (ch) {
+ case 0x2c:
+ state = ImageDescriptor;
+ break;
+ case 0x21:
+ state = ExtensionLabel;
+ break;
+ case 0x3b:
+ state = Done;
+ break;
+ default:
+ done = true;
+ state = Error;
+ }
+ break;
+ case ImageDescriptor:
+ hold[count++] = ch;
+ if (count == 10) {
+ int newLeft = LM(hold[1], hold[2]);
+ int newTop = LM(hold[3], hold[4]);
+ int newWidth = LM(hold[5], hold[6]);
+ int newHeight = LM(hold[7], hold[8]);
+
+ if (imageWidth/10 > qMax(newWidth,200))
+ imageWidth = -1;
+ if (imageHeight/10 > qMax(newHeight,200))
+ imageHeight = -1;
+
+ if (imageWidth <= 0)
+ imageWidth = newLeft + newWidth;
+ if (imageHeight <= 0)
+ imageHeight = newTop + newHeight;
+
+ *imageSizes << QSize(imageWidth, imageHeight);
+
+ localColormap = !!(hold[9] & 0x80);
+ localColorCount = localColormap ? (2 << (hold[9] & 0x7)) : 0;
+ if (localColorCount)
+ colorCount = localColorCount;
+ else
+ colorCount = globalColorCount;
+
+ count = 0;
+ if (localColormap) {
+ int colorTableSize = 3 * localColorCount;
+ if (length >= colorTableSize) {
+ // skip the local color table in one go
+ length -= colorTableSize;
+ buffer += colorTableSize;
+ state = TableImageLZWSize;
+ } else {
+ colorReadCount = 0;
+ state = LocalColorMap;
+ }
+ } else {
+ state = TableImageLZWSize;
+ }
+ }
+ break;
+ case TableImageLZWSize:
+ if (ch > max_lzw_bits)
+ state = Error;
+ else
+ state = ImageDataBlockSize;
+ count = 0;
+ break;
+ case ImageDataBlockSize:
+ blockSize = ch;
+ if (blockSize) {
+ if (length >= blockSize) {
+ // we can skip the block in one go
+ length -= blockSize;
+ buffer += blockSize;
+ count = 0;
+ } else {
+ state = ImageDataBlock;
+ }
+ } else {
+ state = Introducer;
+ }
+ break;
+ case ImageDataBlock:
+ ++count;
+ if (count == blockSize) {
+ count = 0;
+ state = ImageDataBlockSize;
+ }
+ break;
+ case ExtensionLabel:
+ switch (ch) {
+ case 0xf9:
+ state = GraphicControlExtension;
+ break;
+ case 0xff:
+ state = ApplicationExtension;
+ break;
+ default:
+ state = SkipBlockSize;
+ }
+ count = 0;
+ break;
+ case ApplicationExtension:
+ if (count < 11)
+ hold[count] = ch;
+ ++count;
+ if (count == hold[0] + 1) {
+ if (qstrncmp((char*)(hold+1), "NETSCAPE", 8) == 0)
+ state=NetscapeExtensionBlockSize;
+ else
+ state=SkipBlockSize;
+ count = 0;
+ }
+ break;
+ case GraphicControlExtension:
+ if (count < 5)
+ hold[count] = ch;
+ ++count;
+ if (count == hold[0] + 1) {
+ count = 0;
+ state = SkipBlockSize;
+ }
+ break;
+ case NetscapeExtensionBlockSize:
+ blockSize = ch;
+ count = 0;
+ if (blockSize)
+ state = NetscapeExtensionBlock;
+ else
+ state = Introducer;
+ break;
+ case NetscapeExtensionBlock:
+ if (count < 3)
+ hold[count] = ch;
+ count++;
+ if (count == blockSize) {
+ *loopCount = LM(hold[1], hold[2]);
+ state = SkipBlockSize;
+ }
+ break;
+ case SkipBlockSize:
+ blockSize = ch;
+ count = 0;
+ if (blockSize) {
+ if (length >= blockSize) {
+ // we can skip the block in one go
+ length -= blockSize;
+ buffer += blockSize;
+ } else {
+ state = SkipBlock;
+ }
+ } else {
+ state = Introducer;
+ }
+ break;
+ case SkipBlock:
+ ++count;
+ if (count == blockSize)
+ state = SkipBlockSize;
+ break;
+ case Done:
+ done = true;
+ break;
+ case Error:
+ device->seek(oldPos);
+ return;
+ }
+ }
+ readBuffer = device->read(readBufferSize);
+ }
+ device->seek(oldPos);
+ return;
+}
+
+void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb color)
+{
+ if (w>0) {
+ for (int j=0; j<h; j++) {
+ QRgb *line = (QRgb*)image->scanLine(j+row);
+ for (int i=0; i<w; i++)
+ *(line+col+i) = color;
+ }
+ }
+}
+
+void QGIFFormat::nextY(unsigned char *bits, int bpl)
+{
+ int my;
+ switch (interlace) {
+ case 0: // Non-interlaced
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, 1);
+ // }
+ y++;
+ break;
+ case 1: {
+ int i;
+ my = qMin(7, bottom-y);
+ // Don't dup with transparency
+ if (trans_index < 0) {
+ for (i=1; i<=my; i++) {
+ memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
+ (right-left+1)*sizeof(QRgb));
+ }
+ }
+
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, my + 1);
+ // }
+// if (!out_of_bounds)
+// qDebug("consumer->changed(QRect(%d, %d, %d, %d))", left, y, right-left+1, my+1);
+ y+=8;
+ if (y>bottom) {
+ interlace++; y=top+4;
+ if (y > bottom) { // for really broken GIFs with bottom < 5
+ interlace=2;
+ y = top + 2;
+ if (y > bottom) { // for really broken GIF with bottom < 3
+ interlace = 0;
+ y = top + 1;
+ }
+ }
+ }
+ } break;
+ case 2: {
+ int i;
+ my = qMin(3, bottom-y);
+ // Don't dup with transparency
+ if (trans_index < 0) {
+ for (i=1; i<=my; i++) {
+ memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
+ (right-left+1)*sizeof(QRgb));
+ }
+ }
+
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, my + 1);
+ // }
+ y+=8;
+ if (y>bottom) {
+ interlace++; y=top+2;
+ // handle broken GIF with bottom < 3
+ if (y > bottom) {
+ interlace = 3;
+ y = top + 1;
+ }
+ }
+ } break;
+ case 3: {
+ int i;
+ my = qMin(1, bottom-y);
+ // Don't dup with transparency
+ if (trans_index < 0) {
+ for (i=1; i<=my; i++) {
+ memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb),
+ (right-left+1)*sizeof(QRgb));
+ }
+ }
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, my + 1);
+ // }
+ y+=4;
+ if (y>bottom) { interlace++; y=top+1; }
+ } break;
+ case 4:
+ // if (!out_of_bounds) {
+ // ### Changed: QRect(left, y, right - left + 1, 1);
+ // }
+ y+=2;
+ }
+
+ // Consume bogus extra lines
+ if (y >= sheight) out_of_bounds=true; //y=bottom;
+}
+
+inline QRgb QGIFFormat::color(uchar index) const
+{
+ if (index == trans_index || index > ncols)
+ return Q_TRANSPARENT;
+
+ QRgb *map = lcmap ? localcmap : globalcmap;
+ return map ? map[index] : 0;
+}
+
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+
+QGifHandler::QGifHandler()
+{
+ gifFormat = new QGIFFormat;
+ nextDelay = 100;
+ loopCnt = 1;
+ frameNumber = -1;
+ scanIsCached = false;
+}
+
+QGifHandler::~QGifHandler()
+{
+ delete gifFormat;
+}
+
+// Does partial decode if necessary, just to see if an image is coming
+
+bool QGifHandler::imageIsComing() const
+{
+ const int GifChunkSize = 4096;
+
+ while (!gifFormat->partialNewFrame) {
+ if (buffer.isEmpty()) {
+ buffer += device()->read(GifChunkSize);
+ if (buffer.isEmpty())
+ break;
+ }
+
+ int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
+ &nextDelay, &loopCnt);
+ if (decoded == -1)
+ break;
+ buffer.remove(0, decoded);
+ }
+ return gifFormat->partialNewFrame;
+}
+
+bool QGifHandler::canRead() const
+{
+ if (canRead(device()) || imageIsComing()) {
+ setFormat("gif");
+ return true;
+ }
+
+ return false;
+}
+
+bool QGifHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QGifHandler::canRead() called with no device");
+ return false;
+ }
+
+ char head[6];
+ if (device->peek(head, sizeof(head)) == sizeof(head))
+ return qstrncmp(head, "GIF87a", 6) == 0
+ || qstrncmp(head, "GIF89a", 6) == 0;
+ return false;
+}
+
+bool QGifHandler::read(QImage *image)
+{
+ const int GifChunkSize = 4096;
+
+ while (!gifFormat->newFrame) {
+ if (buffer.isEmpty()) {
+ buffer += device()->read(GifChunkSize);
+ if (buffer.isEmpty())
+ break;
+ }
+
+ int decoded = gifFormat->decode(&lastImage, (const uchar *)buffer.constData(), buffer.size(),
+ &nextDelay, &loopCnt);
+ if (decoded == -1)
+ break;
+ buffer.remove(0, decoded);
+ }
+ if (gifFormat->newFrame || (gifFormat->partialNewFrame && device()->atEnd())) {
+ *image = lastImage;
+ ++frameNumber;
+ gifFormat->newFrame = false;
+ gifFormat->partialNewFrame = false;
+ return true;
+ }
+
+ return false;
+}
+
+bool QGifHandler::write(const QImage &image)
+{
+ Q_UNUSED(image);
+ return false;
+}
+
+bool QGifHandler::supportsOption(ImageOption option) const
+{
+ if (!device() || device()->isSequential())
+ return option == Animation;
+ else
+ return option == Size
+ || option == Animation;
+}
+
+QVariant QGifHandler::option(ImageOption option) const
+{
+ if (option == Size) {
+ if (!scanIsCached) {
+ QGIFFormat::scan(device(), &imageSizes, &loopCnt);
+ scanIsCached = true;
+ }
+ // before the first frame is read, or we have an empty data stream
+ if (frameNumber == -1)
+ return (imageSizes.count() > 0) ? QVariant(imageSizes.at(0)) : QVariant();
+ // after the last frame has been read, the next size is undefined
+ if (frameNumber >= imageSizes.count() - 1)
+ return QVariant();
+ // and the last case: the size of the next frame
+ return imageSizes.at(frameNumber + 1);
+ } else if (option == Animation) {
+ return true;
+ }
+ return QVariant();
+}
+
+void QGifHandler::setOption(ImageOption option, const QVariant &value)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(value);
+}
+
+int QGifHandler::nextImageDelay() const
+{
+ return nextDelay;
+}
+
+int QGifHandler::imageCount() const
+{
+ if (!scanIsCached) {
+ QGIFFormat::scan(device(), &imageSizes, &loopCnt);
+ scanIsCached = true;
+ }
+ return imageSizes.count();
+}
+
+int QGifHandler::loopCount() const
+{
+ if (!scanIsCached) {
+ QGIFFormat::scan(device(), &imageSizes, &loopCnt);
+ scanIsCached = true;
+ }
+ return loopCnt-1; // In GIF, loop count is iteration count, so subtract one
+}
+
+int QGifHandler::currentImageNumber() const
+{
+ return frameNumber;
+}
+
+QByteArray QGifHandler::name() const
+{
+ return "gif";
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qgifhandler.pri b/src/gui/image/qgifhandler.pri
new file mode 100644
index 0000000..6eb0751
--- /dev/null
+++ b/src/gui/image/qgifhandler.pri
@@ -0,0 +1,4 @@
+# common to plugin and built-in forms
+INCLUDEPATH *= $$PWD
+HEADERS += $$PWD/qgifhandler_p.h
+SOURCES += $$PWD/qgifhandler.cpp
diff --git a/src/gui/image/qgifhandler_p.h b/src/gui/image/qgifhandler_p.h
new file mode 100644
index 0000000..b2a9725
--- /dev/null
+++ b/src/gui/image/qgifhandler_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins 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$
+**
+** WARNING:
+** A separate license from Unisys may be required to use the gif
+** reader. See http://www.unisys.com/about__unisys/lzw/
+** for information from Unisys
+**
+****************************************************************************/
+
+#ifndef QGIFHANDLER_P_H
+#define QGIFHANDLER_P_H
+
+#include <QtGui/qimageiohandler.h>
+#include <QtGui/qimage.h>
+#include <QtCore/qbytearray.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGIFFormat;
+class QGifHandler : public QImageIOHandler
+{
+public:
+ QGifHandler();
+ ~QGifHandler();
+
+ bool canRead() const;
+ bool read(QImage *image);
+ bool write(const QImage &image);
+
+ QByteArray name() const;
+
+ static bool canRead(QIODevice *device);
+
+ QVariant option(ImageOption option) const;
+ void setOption(ImageOption option, const QVariant &value);
+ bool supportsOption(ImageOption option) const;
+
+ int imageCount() const;
+ int loopCount() const;
+ int nextImageDelay() const;
+ int currentImageNumber() const;
+
+private:
+ bool imageIsComing() const;
+ QGIFFormat *gifFormat;
+ QString fileName;
+ mutable QByteArray buffer;
+ mutable QImage lastImage;
+
+ mutable int nextDelay;
+ mutable int loopCnt;
+ int frameNumber;
+ mutable QVector<QSize> imageSizes;
+ mutable bool scanIsCached;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGIFHANDLER_P_H
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 79f266d..e5930ac 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -58,6 +58,7 @@
#include <private/qmemrotate_p.h>
#include <private/qpixmapdata_p.h>
#include <private/qimagescale_p.h>
+#include <private/qsimd_p.h>
#include <qhash.h>
@@ -209,7 +210,7 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format, int nu
break;
}
- const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 8)
+ const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 4)
// sanity check for potential overflows
if (INT_MAX/depth < width
@@ -3630,7 +3631,7 @@ static const Image_Converter converter_map[QImage::NImageFormats][QImage::NImage
} // Format_ARGB4444_Premultiplied
};
-static const InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] =
+static InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] =
{
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -3727,6 +3728,19 @@ static const InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats
} // Format_ARGB4444_Premultiplied
};
+void qInitImageConversions()
+{
+ const uint features = qDetectCPUFeatures();
+ Q_UNUSED(features);
+
+#ifdef QT_HAVE_SSE2
+ if (features & SSE2) {
+ extern bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags);
+ inplace_converter_map[QImage::Format_ARGB32][QImage::Format_ARGB32_Premultiplied] = convert_ARGB_to_ARGB_PM_inplace_sse2;
+ }
+#endif
+}
+
/*!
Returns a copy of the image in the given \a format.
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index f1a0c47..c687448 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -63,6 +63,8 @@
QT_BEGIN_NAMESPACE
+class QImageWriter;
+
struct Q_GUI_EXPORT QImageData { // internal image data
QImageData();
~QImageData();
@@ -108,6 +110,8 @@ struct Q_GUI_EXPORT QImageData { // internal image data
QPaintEngine *paintEngine;
};
+void qInitImageConversions();
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/image/qimage_sse2.cpp b/src/gui/image/qimage_sse2.cpp
new file mode 100644
index 0000000..82d49a6
--- /dev/null
+++ b/src/gui/image/qimage_sse2.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "qimage.h"
+#include <private/qimage_p.h>
+#include <private/qsimd_p.h>
+#include <private/qdrawhelper_p.h>
+#include <private/qdrawingprimitive_sse2_p.h>
+
+#ifdef QT_HAVE_SSE2
+
+QT_BEGIN_NAMESPACE
+
+bool convert_ARGB_to_ARGB_PM_inplace_sse2(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_ARGB32);
+
+ // extra pixels on each line
+ const int spare = data->width & 3;
+ // width in pixels of the pad at the end of each line
+ const int pad = (data->bytes_per_line >> 2) - data->width;
+ const int iter = data->width >> 2;
+ int height = data->height;
+
+ const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+ const __m128i nullVector = _mm_setzero_si128();
+ const __m128i half = _mm_set1_epi16(0x80);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+
+ __m128i *d = reinterpret_cast<__m128i*>(data->data);
+ while (height--) {
+ const __m128i *end = d + iter;
+
+ for (; d != end; ++d) {
+ const __m128i srcVector = _mm_loadu_si128(d);
+ const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask);
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) {
+ // opaque, data is unchanged
+ } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) == 0xffff) {
+ // fully transparent
+ _mm_storeu_si128(d, nullVector);
+ } else {
+ __m128i alphaChannel = _mm_srli_epi32(srcVector, 24);
+ alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16));
+
+ __m128i result;
+ BYTE_MUL_SSE2(result, srcVector, alphaChannel, colorMask, half);
+ result = _mm_or_si128(_mm_andnot_si128(alphaMask, result), srcVectorAlpha);
+ _mm_storeu_si128(d, result);
+ }
+ }
+
+ QRgb *p = reinterpret_cast<QRgb*>(d);
+ QRgb *pe = p+spare;
+ for (; p != pe; ++p) {
+ if (*p < 0x00ffffff)
+ *p = 0;
+ else if (*p < 0xff000000)
+ *p = PREMUL(*p);
+ }
+
+ d = reinterpret_cast<__m128i*>(p+pad);
+ }
+
+ data->format = QImage::Format_ARGB32_Premultiplied;
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_HAVE_SSE2
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 93d5cd3..ec56af2 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -141,6 +141,18 @@
#ifndef QT_NO_IMAGEFORMAT_PNG
#include <private/qpnghandler_p.h>
#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+#include <private/qjpeghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+#include <private/qmnghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+#include <private/qtiffhandler_p.h>
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+#include <private/qgifhandler_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -153,6 +165,18 @@ enum _qt_BuiltInFormatType {
#ifndef QT_NO_IMAGEFORMAT_PNG
_qt_PngFormat,
#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ _qt_JpgFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ _qt_MngFormat,
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ _qt_TifFormat,
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ _qt_GifFormat,
+#endif
_qt_BmpFormat,
#ifndef QT_NO_IMAGEFORMAT_PPM
_qt_PpmFormat,
@@ -179,6 +203,18 @@ static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = {
#ifndef QT_NO_IMAGEFORMAT_PNG
{_qt_PngFormat, "png"},
#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ {_qt_JpgFormat, "jpg"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ {_qt_MngFormat, "mng"},
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ {_qt_TifFormat, "tif"},
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ {_qt_GifFormat, "gif"},
+#endif
{_qt_BmpFormat, "bmp"},
#ifndef QT_NO_IMAGEFORMAT_PPM
{_qt_PpmFormat, "ppm"},
@@ -301,9 +337,25 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
if (!handler && !testFormat.isEmpty()) {
if (false) {
#ifndef QT_NO_IMAGEFORMAT_PNG
- } else if (testFormat == "png") {
+ } else if (testFormat == "png") {
handler = new QPngHandler;
#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ } else if (testFormat == "jpg" || testFormat == "jpeg") {
+ handler = new QJpegHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ } else if (testFormat == "mng") {
+ handler = new QMngHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ } else if (testFormat == "tif" || testFormat == "tiff") {
+ handler = new QTiffHandler;
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ } else if (testFormat == "gif") {
+ handler = new QGifHandler;
+#endif
#ifndef QT_NO_IMAGEFORMAT_BMP
} else if (testFormat == "bmp") {
handler = new QBmpHandler;
@@ -380,6 +432,30 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
handler = new QPngHandler;
break;
#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ case _qt_JpgFormat:
+ if (QJpegHandler::canRead(device))
+ handler = new QJpegHandler;
+ break;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ case _qt_MngFormat:
+ if (QMngHandler::canRead(device))
+ handler = new QMngHandler;
+ break;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ case _qt_TifFormat:
+ if (QTiffHandler::canRead(device))
+ handler = new QTiffHandler;
+ break;
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ case _qt_GifFormat:
+ if (QGifHandler::canRead(device))
+ handler = new QGifHandler;
+ break;
+#endif
#ifndef QT_NO_IMAGEFORMAT_BMP
case _qt_BmpFormat:
if (QBmpHandler::canRead(device))
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
index 552729f..b995914 100644
--- a/src/gui/image/qimagewriter.cpp
+++ b/src/gui/image/qimagewriter.cpp
@@ -114,6 +114,18 @@
#ifndef QT_NO_IMAGEFORMAT_PNG
#include <private/qpnghandler_p.h>
#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+#include <private/qjpeghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+#include <private/qmnghandler_p.h>
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+#include <private/qtiffhandler_p.h>
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+#include <private/qgifhandler_p.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -170,6 +182,22 @@ static QImageIOHandler *createWriteHandlerHelper(QIODevice *device,
} else if (testFormat == "png") {
handler = new QPngHandler;
#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ } else if (testFormat == "jpg" || testFormat == "jpeg") {
+ handler = new QJpegHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ } else if (testFormat == "mng") {
+ handler = new QMngHandler;
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ } else if (testFormat == "tif" || testFormat == "tiff") {
+ handler = new QTiffHandler;
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ } else if (testFormat == "gif") {
+ handler = new QGifHandler;
+#endif
#ifndef QT_NO_IMAGEFORMAT_BMP
} else if (testFormat == "bmp") {
handler = new QBmpHandler;
@@ -669,6 +697,18 @@ QList<QByteArray> QImageWriter::supportedImageFormats()
#ifndef QT_NO_IMAGEFORMAT_PNG
formats << "png";
#endif
+#ifndef QT_NO_IMAGEFORMAT_JPEG
+ formats << "jpg" << "jpeg";
+#endif
+#ifndef QT_NO_IMAGEFORMAT_MNG
+ formats << "mng";
+#endif
+#ifndef QT_NO_IMAGEFORMAT_TIFF
+ formats << "tif" << "tiff";
+#endif
+#ifdef QT_BUILTIN_GIF_READER
+ formats << "gif";
+#endif
#ifndef QT_NO_LIBRARY
QFactoryLoader *l = loader();
diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp
new file mode 100644
index 0000000..972dd65
--- /dev/null
+++ b/src/gui/image/qjpeghandler.cpp
@@ -0,0 +1,901 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins 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 "qjpeghandler_p.h"
+
+#include <qimage.h>
+#include <qvariant.h>
+#include <qvector.h>
+#include <qbuffer.h>
+
+#include <stdio.h> // jpeglib needs this to be pre-included
+#include <setjmp.h>
+
+#ifdef FAR
+#undef FAR
+#endif
+
+// including jpeglib.h seems to be a little messy
+extern "C" {
+// mingw includes rpcndr.h but does not define boolean
+#if defined(Q_OS_WIN) && defined(Q_CC_GNU)
+# if defined(__RPCNDR_H__) && !defined(boolean)
+ typedef unsigned char boolean;
+# define HAVE_BOOLEAN
+# endif
+#endif
+
+#define XMD_H // shut JPEGlib up
+#if defined(Q_OS_UNIXWARE)
+# define HAVE_BOOLEAN // libjpeg under Unixware seems to need this
+#endif
+#include <jpeglib.h>
+#ifdef const
+# undef const // remove crazy C hackery in jconfig.h
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+struct my_error_mgr : public jpeg_error_mgr {
+ jmp_buf setjmp_buffer;
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static void my_error_exit (j_common_ptr cinfo)
+{
+ my_error_mgr* myerr = (my_error_mgr*) cinfo->err;
+ char buffer[JMSG_LENGTH_MAX];
+ (*cinfo->err->format_message)(cinfo, buffer);
+ qWarning("%s", buffer);
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+
+static const int max_buf = 4096;
+
+struct my_jpeg_source_mgr : public jpeg_source_mgr {
+ // Nothing dynamic - cannot rely on destruction over longjump
+ QIODevice *device;
+ JOCTET buffer[max_buf];
+ const QBuffer *memDevice;
+
+public:
+ my_jpeg_source_mgr(QIODevice *device);
+};
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static void qt_init_source(j_decompress_ptr)
+{
+}
+
+static boolean qt_fill_input_buffer(j_decompress_ptr cinfo)
+{
+ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
+ if (src->memDevice) {
+ src->next_input_byte = (const JOCTET *)(src->memDevice->data().constData() + src->memDevice->pos());
+ src->bytes_in_buffer = (size_t)(src->memDevice->data().size() - src->memDevice->pos());
+ return true;
+ }
+ src->next_input_byte = src->buffer;
+ int num_read = src->device->read((char*)src->buffer, max_buf);
+ if (num_read <= 0) {
+ // Insert a fake EOI marker - as per jpeglib recommendation
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ src->bytes_in_buffer = 2;
+ } else {
+ src->bytes_in_buffer = num_read;
+ }
+#if defined(Q_OS_UNIXWARE)
+ return B_TRUE;
+#else
+ return true;
+#endif
+}
+
+static void qt_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
+
+ // `dumb' implementation from jpeglib
+
+ /* Just a dumb implementation for now. Could use fseek() except
+ * it doesn't work on pipes. Not clear that being smart is worth
+ * any trouble anyway --- large skips are infrequent.
+ */
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->bytes_in_buffer) { // Should not happen in case of memDevice
+ num_bytes -= (long) src->bytes_in_buffer;
+ (void) qt_fill_input_buffer(cinfo);
+ /* note we assume that qt_fill_input_buffer will never return false,
+ * so suspension need not be handled.
+ */
+ }
+ src->next_input_byte += (size_t) num_bytes;
+ src->bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+static void qt_term_source(j_decompress_ptr cinfo)
+{
+ my_jpeg_source_mgr* src = (my_jpeg_source_mgr*)cinfo->src;
+ if (!src->device->isSequential())
+ {
+ // read() isn't used for memDevice, so seek past everything that was used
+ if (src->memDevice)
+ src->device->seek(src->device->pos() + (src->memDevice->data().size() - src->memDevice->pos() - src->bytes_in_buffer));
+ else
+ src->device->seek(src->device->pos() - src->bytes_in_buffer);
+ }
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+inline my_jpeg_source_mgr::my_jpeg_source_mgr(QIODevice *device)
+{
+ jpeg_source_mgr::init_source = qt_init_source;
+ jpeg_source_mgr::fill_input_buffer = qt_fill_input_buffer;
+ jpeg_source_mgr::skip_input_data = qt_skip_input_data;
+ jpeg_source_mgr::resync_to_restart = jpeg_resync_to_restart;
+ jpeg_source_mgr::term_source = qt_term_source;
+ this->device = device;
+ memDevice = qobject_cast<QBuffer *>(device);
+ bytes_in_buffer = 0;
+ next_input_byte = buffer;
+}
+
+
+inline static bool read_jpeg_size(int &w, int &h, j_decompress_ptr cinfo)
+{
+ (void) jpeg_calc_output_dimensions(cinfo);
+
+ w = cinfo->output_width;
+ h = cinfo->output_height;
+ return true;
+}
+
+#define HIGH_QUALITY_THRESHOLD 50
+
+inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cinfo)
+{
+
+ bool result = true;
+ switch (cinfo->output_components) {
+ case 1:
+ format = QImage::Format_Indexed8;
+ break;
+ case 3:
+ case 4:
+ format = QImage::Format_RGB32;
+ break;
+ default:
+ result = false;
+ break;
+ }
+ cinfo->output_scanline = cinfo->output_height;
+ return result;
+}
+
+static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
+ const QSize& size)
+{
+ QImage::Format format;
+ switch (info->output_components) {
+ case 1:
+ format = QImage::Format_Indexed8;
+ break;
+ case 3:
+ case 4:
+ format = QImage::Format_RGB32;
+ break;
+ default:
+ return false; // unsupported format
+ }
+
+ if (dest->size() != size || dest->format() != format) {
+ *dest = QImage(size, format);
+
+ if (format == QImage::Format_Indexed8) {
+ dest->setColorCount(256);
+ for (int i = 0; i < 256; i++)
+ dest->setColor(i, qRgb(i,i,i));
+ }
+ }
+
+ return !dest->isNull();
+}
+
+static bool read_jpeg_image(QImage *outImage,
+ QSize scaledSize, QRect scaledClipRect,
+ QRect clipRect, int inQuality, j_decompress_ptr info, struct my_error_mgr* err )
+{
+ if (!setjmp(err->setjmp_buffer)) {
+ // -1 means default quality.
+ int quality = inQuality;
+ if (quality < 0)
+ quality = 75;
+
+ // If possible, merge the scaledClipRect into either scaledSize
+ // or clipRect to avoid doing a separate scaled clipping pass.
+ // Best results are achieved by clipping before scaling, not after.
+ if (!scaledClipRect.isEmpty()) {
+ if (scaledSize.isEmpty() && clipRect.isEmpty()) {
+ // No clipping or scaling before final clip.
+ clipRect = scaledClipRect;
+ scaledClipRect = QRect();
+ } else if (scaledSize.isEmpty()) {
+ // Clipping, but no scaling: combine the clip regions.
+ scaledClipRect.translate(clipRect.topLeft());
+ clipRect = scaledClipRect.intersected(clipRect);
+ scaledClipRect = QRect();
+ } else if (clipRect.isEmpty()) {
+ // No clipping, but scaling: if we can map back to an
+ // integer pixel boundary, then clip before scaling.
+ if ((info->image_width % scaledSize.width()) == 0 &&
+ (info->image_height % scaledSize.height()) == 0) {
+ int x = scaledClipRect.x() * info->image_width /
+ scaledSize.width();
+ int y = scaledClipRect.y() * info->image_height /
+ scaledSize.height();
+ int width = (scaledClipRect.right() + 1) *
+ info->image_width / scaledSize.width() - x;
+ int height = (scaledClipRect.bottom() + 1) *
+ info->image_height / scaledSize.height() - y;
+ clipRect = QRect(x, y, width, height);
+ scaledSize = scaledClipRect.size();
+ scaledClipRect = QRect();
+ }
+ } else {
+ // Clipping and scaling: too difficult to figure out,
+ // and not a likely use case, so do it the long way.
+ }
+ }
+
+ // Determine the scale factor to pass to libjpeg for quick downscaling.
+ if (!scaledSize.isEmpty()) {
+ if (clipRect.isEmpty()) {
+ info->scale_denom =
+ qMin(info->image_width / scaledSize.width(),
+ info->image_height / scaledSize.height());
+ } else {
+ info->scale_denom =
+ qMin(clipRect.width() / scaledSize.width(),
+ clipRect.height() / scaledSize.height());
+ }
+ if (info->scale_denom < 2) {
+ info->scale_denom = 1;
+ } else if (info->scale_denom < 4) {
+ info->scale_denom = 2;
+ } else if (info->scale_denom < 8) {
+ info->scale_denom = 4;
+ } else {
+ info->scale_denom = 8;
+ }
+ info->scale_num = 1;
+ if (!clipRect.isEmpty()) {
+ // Correct the scale factor so that we clip accurately.
+ // It is recommended that the clip rectangle be aligned
+ // on an 8-pixel boundary for best performance.
+ while (info->scale_denom > 1 &&
+ ((clipRect.x() % info->scale_denom) != 0 ||
+ (clipRect.y() % info->scale_denom) != 0 ||
+ (clipRect.width() % info->scale_denom) != 0 ||
+ (clipRect.height() % info->scale_denom) != 0)) {
+ info->scale_denom /= 2;
+ }
+ }
+ }
+
+ // If high quality not required, use fast decompression
+ if( quality < HIGH_QUALITY_THRESHOLD ) {
+ info->dct_method = JDCT_IFAST;
+ info->do_fancy_upsampling = FALSE;
+ }
+
+ (void) jpeg_calc_output_dimensions(info);
+
+ // Determine the clip region to extract.
+ QRect imageRect(0, 0, info->output_width, info->output_height);
+ QRect clip;
+ if (clipRect.isEmpty()) {
+ clip = imageRect;
+ } else if (info->scale_denom == info->scale_num) {
+ clip = clipRect.intersected(imageRect);
+ } else {
+ // The scale factor was corrected above to ensure that
+ // we don't miss pixels when we scale the clip rectangle.
+ clip = QRect(clipRect.x() / int(info->scale_denom),
+ clipRect.y() / int(info->scale_denom),
+ clipRect.width() / int(info->scale_denom),
+ clipRect.height() / int(info->scale_denom));
+ clip = clip.intersected(imageRect);
+ }
+
+ // Allocate memory for the clipped QImage.
+ if (!ensureValidImage(outImage, info, clip.size()))
+ longjmp(err->setjmp_buffer, 1);
+
+ // Avoid memcpy() overhead if grayscale with no clipping.
+ bool quickGray = (info->output_components == 1 &&
+ clip == imageRect);
+ if (!quickGray) {
+ // Ask the jpeg library to allocate a temporary row.
+ // The library will automatically delete it for us later.
+ // The libjpeg docs say we should do this before calling
+ // jpeg_start_decompress(). We can't use "new" here
+ // because we are inside the setjmp() block and an error
+ // in the jpeg input stream would cause a memory leak.
+ JSAMPARRAY rows = (info->mem->alloc_sarray)
+ ((j_common_ptr)info, JPOOL_IMAGE,
+ info->output_width * info->output_components, 1);
+
+ (void) jpeg_start_decompress(info);
+
+ while (info->output_scanline < info->output_height) {
+ int y = int(info->output_scanline) - clip.y();
+ if (y >= clip.height())
+ break; // We've read the entire clip region, so abort.
+
+ (void) jpeg_read_scanlines(info, rows, 1);
+
+ if (y < 0)
+ continue; // Haven't reached the starting line yet.
+
+ if (info->output_components == 3) {
+ // Expand 24->32 bpp.
+ uchar *in = rows[0] + clip.x() * 3;
+ QRgb *out = (QRgb*)outImage->scanLine(y);
+ for (int i = 0; i < clip.width(); ++i) {
+ *out++ = qRgb(in[0], in[1], in[2]);
+ in += 3;
+ }
+ } else if (info->out_color_space == JCS_CMYK) {
+ // Convert CMYK->RGB.
+ uchar *in = rows[0] + clip.x() * 4;
+ QRgb *out = (QRgb*)outImage->scanLine(y);
+ for (int i = 0; i < clip.width(); ++i) {
+ int k = in[3];
+ *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
+ k * in[2] / 255);
+ in += 4;
+ }
+ } else if (info->output_components == 1) {
+ // Grayscale.
+ memcpy(outImage->scanLine(y),
+ rows[0] + clip.x(), clip.width());
+ }
+ }
+ } else {
+ // Load unclipped grayscale data directly into the QImage.
+ (void) jpeg_start_decompress(info);
+ while (info->output_scanline < info->output_height) {
+ uchar *row = outImage->scanLine(info->output_scanline);
+ (void) jpeg_read_scanlines(info, &row, 1);
+ }
+ }
+
+ if (info->output_scanline == info->output_height)
+ (void) jpeg_finish_decompress(info);
+
+ if (info->density_unit == 1) {
+ outImage->setDotsPerMeterX(int(100. * info->X_density / 2.54));
+ outImage->setDotsPerMeterY(int(100. * info->Y_density / 2.54));
+ } else if (info->density_unit == 2) {
+ outImage->setDotsPerMeterX(int(100. * info->X_density));
+ outImage->setDotsPerMeterY(int(100. * info->Y_density));
+ }
+
+ if (scaledSize.isValid() && scaledSize != clip.size()) {
+ *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, quality >= HIGH_QUALITY_THRESHOLD ? Qt::SmoothTransformation : Qt::FastTransformation);
+ }
+
+ if (!scaledClipRect.isEmpty())
+ *outImage = outImage->copy(scaledClipRect);
+ return !outImage->isNull();
+ }
+ else
+ return false;
+}
+
+struct my_jpeg_destination_mgr : public jpeg_destination_mgr {
+ // Nothing dynamic - cannot rely on destruction over longjump
+ QIODevice *device;
+ JOCTET buffer[max_buf];
+
+public:
+ my_jpeg_destination_mgr(QIODevice *);
+};
+
+
+#if defined(Q_C_CALLBACKS)
+extern "C" {
+#endif
+
+static void qt_init_destination(j_compress_ptr)
+{
+}
+
+static boolean qt_empty_output_buffer(j_compress_ptr cinfo)
+{
+ my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
+
+ int written = dest->device->write((char*)dest->buffer, max_buf);
+ if (written == -1)
+ (*cinfo->err->error_exit)((j_common_ptr)cinfo);
+
+ dest->next_output_byte = dest->buffer;
+ dest->free_in_buffer = max_buf;
+
+#if defined(Q_OS_UNIXWARE)
+ return B_TRUE;
+#else
+ return true;
+#endif
+}
+
+static void qt_term_destination(j_compress_ptr cinfo)
+{
+ my_jpeg_destination_mgr* dest = (my_jpeg_destination_mgr*)cinfo->dest;
+ qint64 n = max_buf - dest->free_in_buffer;
+
+ qint64 written = dest->device->write((char*)dest->buffer, n);
+ if (written == -1)
+ (*cinfo->err->error_exit)((j_common_ptr)cinfo);
+}
+
+#if defined(Q_C_CALLBACKS)
+}
+#endif
+
+inline my_jpeg_destination_mgr::my_jpeg_destination_mgr(QIODevice *device)
+{
+ jpeg_destination_mgr::init_destination = qt_init_destination;
+ jpeg_destination_mgr::empty_output_buffer = qt_empty_output_buffer;
+ jpeg_destination_mgr::term_destination = qt_term_destination;
+ this->device = device;
+ next_output_byte = buffer;
+ free_in_buffer = max_buf;
+}
+
+static bool can_write_format(QImage::Format fmt)
+{
+ switch (fmt) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ case QImage::Format_RGB888:
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool write_jpeg_image(const QImage &sourceImage, QIODevice *device, int sourceQuality)
+{
+ bool success = false;
+ const QImage image = can_write_format(sourceImage.format()) ?
+ sourceImage : sourceImage.convertToFormat(QImage::Format_RGB888);
+ const QVector<QRgb> cmap = image.colorTable();
+
+ struct jpeg_compress_struct cinfo;
+ JSAMPROW row_pointer[1];
+ row_pointer[0] = 0;
+
+ struct my_jpeg_destination_mgr *iod_dest = new my_jpeg_destination_mgr(device);
+ struct my_error_mgr jerr;
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jerr.error_exit = my_error_exit;
+
+ if (!setjmp(jerr.setjmp_buffer)) {
+ // WARNING:
+ // this if loop is inside a setjmp/longjmp branch
+ // do not create C++ temporaries here because the destructor may never be called
+ // if you allocate memory, make sure that you can free it (row_pointer[0])
+ jpeg_create_compress(&cinfo);
+
+ cinfo.dest = iod_dest;
+
+ cinfo.image_width = image.width();
+ cinfo.image_height = image.height();
+
+ bool gray=false;
+ switch (image.format()) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ gray = true;
+ for (int i = image.colorCount(); gray && i--;) {
+ gray = gray & (qRed(cmap[i]) == qGreen(cmap[i]) &&
+ qRed(cmap[i]) == qBlue(cmap[i]));
+ }
+ cinfo.input_components = gray ? 1 : 3;
+ cinfo.in_color_space = gray ? JCS_GRAYSCALE : JCS_RGB;
+ break;
+ default:
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+ }
+
+ jpeg_set_defaults(&cinfo);
+
+ qreal diffInch = qAbs(image.dotsPerMeterX()*2.54/100. - qRound(image.dotsPerMeterX()*2.54/100.))
+ + qAbs(image.dotsPerMeterY()*2.54/100. - qRound(image.dotsPerMeterY()*2.54/100.));
+ qreal diffCm = (qAbs(image.dotsPerMeterX()/100. - qRound(image.dotsPerMeterX()/100.))
+ + qAbs(image.dotsPerMeterY()/100. - qRound(image.dotsPerMeterY()/100.)))*2.54;
+ if (diffInch < diffCm) {
+ cinfo.density_unit = 1; // dots/inch
+ cinfo.X_density = qRound(image.dotsPerMeterX()*2.54/100.);
+ cinfo.Y_density = qRound(image.dotsPerMeterY()*2.54/100.);
+ } else {
+ cinfo.density_unit = 2; // dots/cm
+ cinfo.X_density = (image.dotsPerMeterX()+50) / 100;
+ cinfo.Y_density = (image.dotsPerMeterY()+50) / 100;
+ }
+
+
+ int quality = sourceQuality >= 0 ? qMin(sourceQuality,100) : 75;
+#if defined(Q_OS_UNIXWARE)
+ jpeg_set_quality(&cinfo, quality, B_TRUE /* limit to baseline-JPEG values */);
+ jpeg_start_compress(&cinfo, B_TRUE);
+#else
+ jpeg_set_quality(&cinfo, quality, true /* limit to baseline-JPEG values */);
+ jpeg_start_compress(&cinfo, true);
+#endif
+
+ row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
+ int w = cinfo.image_width;
+ while (cinfo.next_scanline < cinfo.image_height) {
+ uchar *row = row_pointer[0];
+ switch (image.format()) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ if (gray) {
+ const uchar* data = image.scanLine(cinfo.next_scanline);
+ if (image.format() == QImage::Format_MonoLSB) {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
+ row[i] = qRed(cmap[bit]);
+ }
+ } else {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
+ row[i] = qRed(cmap[bit]);
+ }
+ }
+ } else {
+ const uchar* data = image.scanLine(cinfo.next_scanline);
+ if (image.format() == QImage::Format_MonoLSB) {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (i & 7)));
+ *row++ = qRed(cmap[bit]);
+ *row++ = qGreen(cmap[bit]);
+ *row++ = qBlue(cmap[bit]);
+ }
+ } else {
+ for (int i=0; i<w; i++) {
+ bool bit = !!(*(data + (i >> 3)) & (1 << (7 -(i & 7))));
+ *row++ = qRed(cmap[bit]);
+ *row++ = qGreen(cmap[bit]);
+ *row++ = qBlue(cmap[bit]);
+ }
+ }
+ }
+ break;
+ case QImage::Format_Indexed8:
+ if (gray) {
+ const uchar* pix = image.scanLine(cinfo.next_scanline);
+ for (int i=0; i<w; i++) {
+ *row = qRed(cmap[*pix]);
+ ++row; ++pix;
+ }
+ } else {
+ const uchar* pix = image.scanLine(cinfo.next_scanline);
+ for (int i=0; i<w; i++) {
+ *row++ = qRed(cmap[*pix]);
+ *row++ = qGreen(cmap[*pix]);
+ *row++ = qBlue(cmap[*pix]);
+ ++pix;
+ }
+ }
+ break;
+ case QImage::Format_RGB888:
+ memcpy(row, image.scanLine(cinfo.next_scanline), w * 3);
+ break;
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied: {
+ QRgb* rgb = (QRgb*)image.scanLine(cinfo.next_scanline);
+ for (int i=0; i<w; i++) {
+ *row++ = qRed(*rgb);
+ *row++ = qGreen(*rgb);
+ *row++ = qBlue(*rgb);
+ ++rgb;
+ }
+ break;
+ }
+ default:
+ qWarning("QJpegHandler: unable to write image of format %i",
+ image.format());
+ break;
+ }
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ success = true;
+ } else {
+ jpeg_destroy_compress(&cinfo);
+ success = false;
+ }
+
+ delete iod_dest;
+ delete [] row_pointer[0];
+ return success;
+}
+
+class QJpegHandlerPrivate
+{
+public:
+ enum State {
+ Ready,
+ ReadHeader,
+ Error
+ };
+
+ QJpegHandlerPrivate(QJpegHandler *qq)
+ : quality(75), iod_src(0), state(Ready), q(qq)
+ {}
+
+ ~QJpegHandlerPrivate()
+ {
+ if(iod_src)
+ {
+ jpeg_destroy_decompress(&info);
+ delete iod_src;
+ iod_src = 0;
+ }
+ }
+
+ bool readJpegHeader(QIODevice*);
+ bool read(QImage *image);
+
+ int quality;
+ QVariant size;
+ QImage::Format format;
+ QSize scaledSize;
+ QRect scaledClipRect;
+ QRect clipRect;
+ struct jpeg_decompress_struct info;
+ struct my_jpeg_source_mgr * iod_src;
+ struct my_error_mgr err;
+
+ State state;
+
+ QJpegHandler *q;
+};
+
+/*!
+ \internal
+*/
+bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
+{
+ if(state == Ready)
+ {
+ state = Error;
+ iod_src = new my_jpeg_source_mgr(device);
+
+ jpeg_create_decompress(&info);
+ info.src = iod_src;
+ info.err = jpeg_std_error(&err);
+ err.error_exit = my_error_exit;
+
+ if (!setjmp(err.setjmp_buffer)) {
+ #if defined(Q_OS_UNIXWARE)
+ (void) jpeg_read_header(&info, B_TRUE);
+ #else
+ (void) jpeg_read_header(&info, true);
+ #endif
+
+ int width = 0;
+ int height = 0;
+ read_jpeg_size(width, height, &info);
+ size = QSize(width, height);
+
+ format = QImage::Format_Invalid;
+ read_jpeg_format(format, &info);
+ state = ReadHeader;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if(state == Error)
+ return false;
+ return true;
+}
+
+bool QJpegHandlerPrivate::read(QImage *image)
+{
+ if(state == Ready)
+ readJpegHeader(q->device());
+
+ if(state == ReadHeader)
+ {
+ bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, &info, &err);
+ state = success ? Ready : Error;
+ return success;
+ }
+
+ return false;
+
+}
+
+QJpegHandler::QJpegHandler()
+ : d(new QJpegHandlerPrivate(this))
+{
+}
+
+QJpegHandler::~QJpegHandler()
+{
+ delete d;
+}
+
+bool QJpegHandler::canRead() const
+{
+ if(d->state == QJpegHandlerPrivate::Ready && !canRead(device()))
+ return false;
+
+ if (d->state != QJpegHandlerPrivate::Error) {
+ setFormat("jpeg");
+ return true;
+ }
+
+ return false;
+}
+
+bool QJpegHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QJpegHandler::canRead() called with no device");
+ return false;
+ }
+
+ char buffer[2];
+ if (device->peek(buffer, 2) != 2)
+ return false;
+ return uchar(buffer[0]) == 0xff && uchar(buffer[1]) == 0xd8;
+}
+
+bool QJpegHandler::read(QImage *image)
+{
+ if (!canRead())
+ return false;
+ return d->read(image);
+}
+
+bool QJpegHandler::write(const QImage &image)
+{
+ return write_jpeg_image(image, device(), d->quality);
+}
+
+bool QJpegHandler::supportsOption(ImageOption option) const
+{
+ return option == Quality
+ || option == ScaledSize
+ || option == ScaledClipRect
+ || option == ClipRect
+ || option == Size
+ || option == ImageFormat;
+}
+
+QVariant QJpegHandler::option(ImageOption option) const
+{
+ switch(option) {
+ case Quality:
+ return d->quality;
+ case ScaledSize:
+ return d->scaledSize;
+ case ScaledClipRect:
+ return d->scaledClipRect;
+ case ClipRect:
+ return d->clipRect;
+ case Size:
+ d->readJpegHeader(device());
+ return d->size;
+ case ImageFormat:
+ d->readJpegHeader(device());
+ return d->format;
+ default:
+ return QVariant();
+ }
+}
+
+void QJpegHandler::setOption(ImageOption option, const QVariant &value)
+{
+ switch(option) {
+ case Quality:
+ d->quality = value.toInt();
+ break;
+ case ScaledSize:
+ d->scaledSize = value.toSize();
+ break;
+ case ScaledClipRect:
+ d->scaledClipRect = value.toRect();
+ break;
+ case ClipRect:
+ d->clipRect = value.toRect();
+ break;
+ default:
+ break;
+ }
+}
+
+QByteArray QJpegHandler::name() const
+{
+ return "jpeg";
+}
+
+
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qjpeghandler.pri b/src/gui/image/qjpeghandler.pri
new file mode 100644
index 0000000..3cb35c9
--- /dev/null
+++ b/src/gui/image/qjpeghandler.pri
@@ -0,0 +1,10 @@
+# common to plugin and built-in forms
+INCLUDEPATH *= $$PWD
+HEADERS += $$PWD/qjpeghandler_p.h
+SOURCES += $$PWD/qjpeghandler.cpp
+contains(QT_CONFIG, system-jpeg) {
+ if(unix|win32-g++*): LIBS += -ljpeg
+ else:win32: LIBS += libjpeg.lib
+} else {
+ include($$PWD/../../3rdparty/libjpeg.pri)
+}
diff --git a/src/gui/image/qjpeghandler_p.h b/src/gui/image/qjpeghandler_p.h
new file mode 100644
index 0000000..5320a5e
--- /dev/null
+++ b/src/gui/image/qjpeghandler_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins 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 QJPEGHANDLER_P_H
+#define QJPEGHANDLER_P_H
+
+#include <QtGui/qimageiohandler.h>
+#include <QtCore/QSize>
+#include <QtCore/QRect>
+
+QT_BEGIN_NAMESPACE
+
+class QJpegHandlerPrivate;
+class QJpegHandler : public QImageIOHandler
+{
+public:
+ QJpegHandler();
+ ~QJpegHandler();
+
+ bool canRead() const;
+ bool read(QImage *image);
+ bool write(const QImage &image);
+
+ QByteArray name() const;
+
+ static bool canRead(QIODevice *device);
+
+ QVariant option(ImageOption option) const;
+ void setOption(ImageOption option, const QVariant &value);
+ bool supportsOption(ImageOption option) const;
+
+private:
+ QJpegHandlerPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QJPEGHANDLER_P_H
diff --git a/src/gui/image/qmnghandler.cpp b/src/gui/image/qmnghandler.cpp
new file mode 100644
index 0000000..cf53af0
--- /dev/null
+++ b/src/gui/image/qmnghandler.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins 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 "qmnghandler_p.h"
+
+#include "qimage.h"
+#include "qvariant.h"
+#include "qcolor.h"
+
+#define MNG_USE_SO
+#include <libmng.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMngHandlerPrivate
+{
+ Q_DECLARE_PUBLIC(QMngHandler)
+ public:
+ bool haveReadNone;
+ bool haveReadAll;
+ mng_handle hMNG;
+ QImage image;
+ int elapsed;
+ int nextDelay;
+ int iterCount;
+ int frameIndex;
+ int nextIndex;
+ int frameCount;
+ mng_uint32 iStyle;
+ mng_bool readData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead);
+ mng_bool writeData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten);
+ mng_bool processHeader(mng_uint32 iWidth, mng_uint32 iHeight);
+ QMngHandlerPrivate(QMngHandler *q_ptr);
+ ~QMngHandlerPrivate();
+ bool getNextImage(QImage *result);
+ bool writeImage(const QImage &image);
+ int currentImageNumber() const;
+ int imageCount() const;
+ bool jumpToImage(int imageNumber);
+ bool jumpToNextImage();
+ int nextImageDelay() const;
+ bool setBackgroundColor(const QColor &color);
+ QColor backgroundColor() const;
+ QMngHandler *q_ptr;
+};
+
+static mng_bool myerror(mng_handle /*hMNG*/,
+ mng_int32 iErrorcode,
+ mng_int8 /*iSeverity*/,
+ mng_chunkid iChunkname,
+ mng_uint32 /*iChunkseq*/,
+ mng_int32 iExtra1,
+ mng_int32 iExtra2,
+ mng_pchar zErrortext)
+{
+ qWarning("MNG error %d: %s; chunk %c%c%c%c; subcode %d:%d",
+ iErrorcode,zErrortext,
+ (iChunkname>>24)&0xff,
+ (iChunkname>>16)&0xff,
+ (iChunkname>>8)&0xff,
+ (iChunkname>>0)&0xff,
+ iExtra1,iExtra2);
+ return TRUE;
+}
+
+static mng_ptr myalloc(mng_size_t iSize)
+{
+#if defined(Q_OS_WINCE)
+ mng_ptr ptr = malloc(iSize);
+ memset(ptr, 0, iSize);
+ return ptr;
+#else
+ return (mng_ptr)calloc(1, iSize);
+#endif
+}
+
+static void myfree(mng_ptr pPtr, mng_size_t /*iSize*/)
+{
+ free(pPtr);
+}
+
+static mng_bool myopenstream(mng_handle)
+{
+ return MNG_TRUE;
+}
+
+static mng_bool myclosestream(mng_handle hMNG)
+{
+ QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
+ pMydata->haveReadAll = true;
+ return MNG_TRUE;
+}
+
+static mng_bool myreaddata(mng_handle hMNG,
+ mng_ptr pBuf,
+ mng_uint32 iSize,
+ mng_uint32p pRead)
+{
+ QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
+ return pMydata->readData(pBuf, iSize, pRead);
+}
+
+static mng_bool mywritedata(mng_handle hMNG,
+ mng_ptr pBuf,
+ mng_uint32 iSize,
+ mng_uint32p pWritten)
+{
+ QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
+ return pMydata->writeData(pBuf, iSize, pWritten);
+}
+
+static mng_bool myprocessheader(mng_handle hMNG,
+ mng_uint32 iWidth,
+ mng_uint32 iHeight)
+{
+ QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
+ return pMydata->processHeader(iWidth, iHeight);
+}
+
+static mng_ptr mygetcanvasline(mng_handle hMNG,
+ mng_uint32 iLinenr)
+{
+ QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
+ return (mng_ptr)pMydata->image.scanLine(iLinenr);
+}
+
+static mng_bool myrefresh(mng_handle /*hMNG*/,
+ mng_uint32 /*iX*/,
+ mng_uint32 /*iY*/,
+ mng_uint32 /*iWidth*/,
+ mng_uint32 /*iHeight*/)
+{
+ return MNG_TRUE;
+}
+
+static mng_uint32 mygettickcount(mng_handle hMNG)
+{
+ QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
+ return pMydata->elapsed++;
+}
+
+static mng_bool mysettimer(mng_handle hMNG,
+ mng_uint32 iMsecs)
+{
+ QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
+ pMydata->elapsed += iMsecs;
+ pMydata->nextDelay = iMsecs;
+ return MNG_TRUE;
+}
+
+static mng_bool myprocessterm(mng_handle hMNG,
+ mng_uint8 iTermaction,
+ mng_uint8 /*iIteraction*/,
+ mng_uint32 /*iDelay*/,
+ mng_uint32 iItermax)
+{
+ QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
+ if (iTermaction == 3)
+ pMydata->iterCount = iItermax;
+ return MNG_TRUE;
+}
+
+static mng_bool mytrace(mng_handle,
+ mng_int32 iFuncnr,
+ mng_int32 iFuncseq,
+ mng_pchar zFuncname)
+{
+ qDebug("mng trace: iFuncnr: %d iFuncseq: %d zFuncname: %s", iFuncnr, iFuncseq, zFuncname);
+ return MNG_TRUE;
+}
+
+QMngHandlerPrivate::QMngHandlerPrivate(QMngHandler *q_ptr)
+ : haveReadNone(true), haveReadAll(false), elapsed(0), nextDelay(0), iterCount(1),
+ frameIndex(-1), nextIndex(0), frameCount(0), q_ptr(q_ptr)
+{
+ iStyle = (QSysInfo::ByteOrder == QSysInfo::LittleEndian) ? MNG_CANVAS_BGRA8 : MNG_CANVAS_ARGB8;
+ // Initialize libmng
+ hMNG = mng_initialize((mng_ptr)this, myalloc, myfree, mytrace);
+ if (hMNG) {
+ // Set callback functions
+ mng_setcb_errorproc(hMNG, myerror);
+ mng_setcb_openstream(hMNG, myopenstream);
+ mng_setcb_closestream(hMNG, myclosestream);
+ mng_setcb_readdata(hMNG, myreaddata);
+ mng_setcb_writedata(hMNG, mywritedata);
+ mng_setcb_processheader(hMNG, myprocessheader);
+ mng_setcb_getcanvasline(hMNG, mygetcanvasline);
+ mng_setcb_refresh(hMNG, myrefresh);
+ mng_setcb_gettickcount(hMNG, mygettickcount);
+ mng_setcb_settimer(hMNG, mysettimer);
+ mng_setcb_processterm(hMNG, myprocessterm);
+ mng_set_doprogressive(hMNG, MNG_FALSE);
+ mng_set_suspensionmode(hMNG, MNG_TRUE);
+ }
+}
+
+QMngHandlerPrivate::~QMngHandlerPrivate()
+{
+ mng_cleanup(&hMNG);
+}
+
+mng_bool QMngHandlerPrivate::readData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead)
+{
+ Q_Q(QMngHandler);
+ *pRead = q->device()->read((char *)pBuf, iSize);
+ return (*pRead > 0) ? MNG_TRUE : MNG_FALSE;
+}
+
+mng_bool QMngHandlerPrivate::writeData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten)
+{
+ Q_Q(QMngHandler);
+ *pWritten = q->device()->write((char *)pBuf, iSize);
+ return MNG_TRUE;
+}
+
+mng_bool QMngHandlerPrivate::processHeader(mng_uint32 iWidth, mng_uint32 iHeight)
+{
+ if (mng_set_canvasstyle(hMNG, iStyle) != MNG_NOERROR)
+ return MNG_FALSE;
+ image = QImage(iWidth, iHeight, QImage::Format_ARGB32);
+ image.fill(0);
+ return MNG_TRUE;
+}
+
+bool QMngHandlerPrivate::getNextImage(QImage *result)
+{
+ mng_retcode ret;
+ if (haveReadNone) {
+ haveReadNone = false;
+ ret = mng_readdisplay(hMNG);
+ } else {
+ ret = mng_display_resume(hMNG);
+ }
+ if ((MNG_NOERROR == ret) || (MNG_NEEDTIMERWAIT == ret)) {
+ *result = image;
+ frameIndex = nextIndex++;
+ if (haveReadAll && (frameCount == 0))
+ frameCount = nextIndex;
+ return true;
+ }
+ return false;
+}
+
+bool QMngHandlerPrivate::writeImage(const QImage &image)
+{
+ mng_reset(hMNG);
+ if (mng_create(hMNG) != MNG_NOERROR)
+ return false;
+
+ this->image = image.convertToFormat(QImage::Format_ARGB32);
+ int w = image.width();
+ int h = image.height();
+
+ if (
+ // width, height, ticks, layercount, framecount, playtime, simplicity
+ (mng_putchunk_mhdr(hMNG, w, h, 1000, 0, 0, 0, 7) == MNG_NOERROR) &&
+ // termination_action, action_after_iterations, delay, iteration_max
+ (mng_putchunk_term(hMNG, 3, 0, 1, 0x7FFFFFFF) == MNG_NOERROR) &&
+ // width, height, bitdepth, colortype, compression, filter, interlace
+ (mng_putchunk_ihdr(hMNG, w, h, 8, 6, 0, 0, 0) == MNG_NOERROR) &&
+ // width, height, colortype, bitdepth, compression, filter, interlace, canvasstyle, getcanvasline
+ (mng_putimgdata_ihdr(hMNG, w, h, 6, 8, 0, 0, 0, iStyle, mygetcanvasline) == MNG_NOERROR) &&
+ (mng_putchunk_iend(hMNG) == MNG_NOERROR) &&
+ (mng_putchunk_mend(hMNG) == MNG_NOERROR) &&
+ (mng_write(hMNG) == MNG_NOERROR)
+ )
+ return true;
+ return false;
+}
+
+int QMngHandlerPrivate::currentImageNumber() const
+{
+// return mng_get_currentframe(hMNG) % imageCount(); not implemented, apparently
+ return frameIndex;
+}
+
+int QMngHandlerPrivate::imageCount() const
+{
+// return mng_get_totalframes(hMNG); not implemented, apparently
+ if (haveReadAll)
+ return frameCount;
+ return 0; // Don't know
+}
+
+bool QMngHandlerPrivate::jumpToImage(int imageNumber)
+{
+ if (imageNumber == nextIndex)
+ return true;
+
+ if ((imageNumber == 0) && haveReadAll && (nextIndex == frameCount)) {
+ // Loop!
+ nextIndex = 0;
+ return true;
+ }
+ if (mng_display_freeze(hMNG) == MNG_NOERROR) {
+ if (mng_display_goframe(hMNG, imageNumber) == MNG_NOERROR) {
+ nextIndex = imageNumber;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QMngHandlerPrivate::jumpToNextImage()
+{
+ return jumpToImage((currentImageNumber()+1) % imageCount());
+}
+
+int QMngHandlerPrivate::nextImageDelay() const
+{
+ return nextDelay;
+}
+
+bool QMngHandlerPrivate::setBackgroundColor(const QColor &color)
+{
+ mng_uint16 iRed = (mng_uint16)(color.red() << 8);
+ mng_uint16 iBlue = (mng_uint16)(color.blue() << 8);
+ mng_uint16 iGreen = (mng_uint16)(color.green() << 8);
+ return (mng_set_bgcolor(hMNG, iRed, iBlue, iGreen) == MNG_NOERROR);
+}
+
+QColor QMngHandlerPrivate::backgroundColor() const
+{
+ mng_uint16 iRed;
+ mng_uint16 iBlue;
+ mng_uint16 iGreen;
+ if (mng_get_bgcolor(hMNG, &iRed, &iBlue, &iGreen) == MNG_NOERROR)
+ return QColor((iRed >> 8) & 0xFF, (iGreen >> 8) & 0xFF, (iBlue >> 8) & 0xFF);
+ return QColor();
+}
+
+QMngHandler::QMngHandler()
+ : d_ptr(new QMngHandlerPrivate(this))
+{
+}
+
+QMngHandler::~QMngHandler()
+{
+}
+
+/*! \reimp */
+bool QMngHandler::canRead() const
+{
+ Q_D(const QMngHandler);
+ if ((!d->haveReadNone
+ && (!d->haveReadAll || (d->haveReadAll && (d->nextIndex < d->frameCount))))
+ || canRead(device()))
+ {
+ setFormat("mng");
+ return true;
+ }
+ return false;
+}
+
+/*! \internal */
+bool QMngHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QMngHandler::canRead() called with no device");
+ return false;
+ }
+
+ return device->peek(8) == "\x8A\x4D\x4E\x47\x0D\x0A\x1A\x0A";
+}
+
+/*! \reimp */
+QByteArray QMngHandler::name() const
+{
+ return "mng";
+}
+
+/*! \reimp */
+bool QMngHandler::read(QImage *image)
+{
+ Q_D(QMngHandler);
+ return canRead() ? d->getNextImage(image) : false;
+}
+
+/*! \reimp */
+bool QMngHandler::write(const QImage &image)
+{
+ Q_D(QMngHandler);
+ return d->writeImage(image);
+}
+
+/*! \reimp */
+int QMngHandler::currentImageNumber() const
+{
+ Q_D(const QMngHandler);
+ return d->currentImageNumber();
+}
+
+/*! \reimp */
+int QMngHandler::imageCount() const
+{
+ Q_D(const QMngHandler);
+ return d->imageCount();
+}
+
+/*! \reimp */
+bool QMngHandler::jumpToImage(int imageNumber)
+{
+ Q_D(QMngHandler);
+ return d->jumpToImage(imageNumber);
+}
+
+/*! \reimp */
+bool QMngHandler::jumpToNextImage()
+{
+ Q_D(QMngHandler);
+ return d->jumpToNextImage();
+}
+
+/*! \reimp */
+int QMngHandler::loopCount() const
+{
+ Q_D(const QMngHandler);
+ if (d->iterCount == 0x7FFFFFFF)
+ return -1; // infinite loop
+ return d->iterCount-1;
+}
+
+/*! \reimp */
+int QMngHandler::nextImageDelay() const
+{
+ Q_D(const QMngHandler);
+ return d->nextImageDelay();
+}
+
+/*! \reimp */
+QVariant QMngHandler::option(ImageOption option) const
+{
+ Q_D(const QMngHandler);
+ if (option == QImageIOHandler::Animation)
+ return true;
+ else if (option == QImageIOHandler::BackgroundColor)
+ return d->backgroundColor();
+ return QVariant();
+}
+
+/*! \reimp */
+void QMngHandler::setOption(ImageOption option, const QVariant & value)
+{
+ Q_D(QMngHandler);
+ if (option == QImageIOHandler::BackgroundColor)
+ d->setBackgroundColor(qVariantValue<QColor>(value));
+}
+
+/*! \reimp */
+bool QMngHandler::supportsOption(ImageOption option) const
+{
+ if (option == QImageIOHandler::Animation)
+ return true;
+ else if (option == QImageIOHandler::BackgroundColor)
+ return true;
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qmnghandler.pri b/src/gui/image/qmnghandler.pri
new file mode 100644
index 0000000..ffb98de
--- /dev/null
+++ b/src/gui/image/qmnghandler.pri
@@ -0,0 +1,10 @@
+# common to plugin and built-in forms
+INCLUDEPATH *= $$PWD
+HEADERS += $$PWD/qmnghandler_p.h
+SOURCES += $$PWD/qmnghandler.cpp
+contains(QT_CONFIG, system-mng) {
+ if(unix|win32-g++*):LIBS += -lmng
+ else:win32: LIBS += libmng.lib
+} else {
+ include($$PWD/../../3rdparty/libmng.pri)
+}
diff --git a/src/gui/image/qmnghandler_p.h b/src/gui/image/qmnghandler_p.h
new file mode 100644
index 0000000..c39d0a6
--- /dev/null
+++ b/src/gui/image/qmnghandler_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins 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 QMNGHANDLER_P_H
+#define QMNGHANDLER_P_H
+
+#include <QtCore/qscopedpointer.h>
+#include <QtGui/qimageiohandler.h>
+
+QT_BEGIN_NAMESPACE
+
+class QImage;
+class QByteArray;
+class QIODevice;
+class QVariant;
+class QMngHandlerPrivate;
+
+class QMngHandler : public QImageIOHandler
+{
+ public:
+ QMngHandler();
+ ~QMngHandler();
+ virtual bool canRead() const;
+ virtual QByteArray name() const;
+ virtual bool read(QImage *image);
+ virtual bool write(const QImage &image);
+ virtual int currentImageNumber() const;
+ virtual int imageCount() const;
+ virtual bool jumpToImage(int imageNumber);
+ virtual bool jumpToNextImage();
+ virtual int loopCount() const;
+ virtual int nextImageDelay() const;
+ static bool canRead(QIODevice *device);
+ virtual QVariant option(ImageOption option) const;
+ virtual void setOption(ImageOption option, const QVariant & value);
+ virtual bool supportsOption(ImageOption option) const;
+
+ private:
+ Q_DECLARE_PRIVATE(QMngHandler)
+ QScopedPointer<QMngHandlerPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMNGHANDLER_P_H
diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp
index 20a1dce..48d2de3 100644
--- a/src/gui/image/qpicture.cpp
+++ b/src/gui/image/qpicture.cpp
@@ -440,6 +440,36 @@ bool QPicture::play(QPainter *painter)
return true; // no end-command
}
+
+//
+// QFakeDevice is used to create fonts with a custom DPI
+//
+class QFakeDevice : public QPaintDevice
+{
+public:
+ QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); }
+ void setDpiX(int dpi) { dpi_x = dpi; }
+ void setDpiY(int dpi) { dpi_y = dpi; }
+ QPaintEngine *paintEngine() const { return 0; }
+ int metric(PaintDeviceMetric m) const
+ {
+ switch(m) {
+ case PdmPhysicalDpiX:
+ case PdmDpiX:
+ return dpi_x;
+ case PdmPhysicalDpiY:
+ case PdmDpiY:
+ return dpi_y;
+ default:
+ return QPaintDevice::metric(m);
+ }
+ }
+
+private:
+ int dpi_x;
+ int dpi_y;
+};
+
/*!
\internal
Iterates over the internal picture data and draws the picture using
@@ -649,16 +679,13 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
if (d->formatMajor >= 9) {
s >> dbl;
- QFont fnt(font, painter->device());
-
- // Fonts that specify a pixel size should not be scaled - QPicture already
- // have a matrix set to compensate for the DPI differences between the
- // default Qt DPI and the actual target device DPI, and we have to take that
- // into consideration in the case where the font has a pixel size set.
-
- qreal scale = fnt.pointSize() == -1 ? 1 : painter->device()->logicalDpiY() / (dbl*qt_defaultDpiY());
- painter->save();
- painter->scale(1/scale, 1/scale);
+ QFont fnt(font);
+ if (dbl != 1.0) {
+ QFakeDevice fake;
+ fake.setDpiX(qRound(dbl*qt_defaultDpiX()));
+ fake.setDpiY(qRound(dbl*qt_defaultDpiY()));
+ fnt = QFont(font, &fake);
+ }
qreal justificationWidth;
s >> justificationWidth;
@@ -667,16 +694,15 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
QSizeF size(1, 1);
if (justificationWidth > 0) {
- size.setWidth(justificationWidth*scale);
+ size.setWidth(justificationWidth);
flags |= Qt::TextJustificationForced;
flags |= Qt::AlignJustify;
}
QFontMetrics fm(fnt);
- QPointF pt(p.x()*scale, p.y()*scale - fm.ascent());
+ QPointF pt(p.x(), p.y() - fm.ascent());
qt_format_text(fnt, QRectF(pt, size), flags, /*opt*/0,
str, /*brect=*/0, /*tabstops=*/0, /*...*/0, /*tabarraylen=*/0, painter);
- painter->restore();
} else {
qt_format_text(font, QRectF(p, QSizeF(1, 1)), Qt::TextSingleLine | Qt::TextDontClip, /*opt*/0,
str, /*brect=*/0, /*tabstops=*/0, /*...*/0, /*tabarraylen=*/0, painter);
diff --git a/src/gui/image/qpixmapdatafactory.cpp b/src/gui/image/qpixmapdatafactory.cpp
index 8014660..7498a7c 100644
--- a/src/gui/image/qpixmapdatafactory.cpp
+++ b/src/gui/image/qpixmapdatafactory.cpp
@@ -53,7 +53,7 @@
#ifdef Q_WS_MAC
# include <private/qpixmap_mac_p.h>
#endif
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
# include <private/qpixmap_s60_p.h>
#endif
@@ -82,7 +82,7 @@ QPixmapData* QSimplePixmapDataFactory::create(QPixmapData::PixelType type)
return new QRasterPixmapData(type);
#elif defined(Q_WS_MAC)
return new QMacPixmapData(type);
-#elif defined(Q_WS_S60)
+#elif defined(Q_OS_SYMBIAN)
return new QS60PixmapData(type);
#else
#error QSimplePixmapDataFactory::create() not implemented
diff --git a/src/gui/image/qpnghandler.pri b/src/gui/image/qpnghandler.pri
new file mode 100644
index 0000000..bedf23f
--- /dev/null
+++ b/src/gui/image/qpnghandler.pri
@@ -0,0 +1,10 @@
+INCLUDEPATH *= $$PWD
+HEADERS += $$PWD/qpnghandler_p.h
+SOURCES += $$PWD/qpnghandler.cpp
+contains(QT_CONFIG, system-png) {
+ if(unix|win32-g++*): LIBS_PRIVATE += -lpng
+ else:win32: LIBS += libpng.lib
+
+} else {
+ include($$PWD/../../3rdparty/libpng.pri)
+}
diff --git a/src/gui/image/qtiffhandler.cpp b/src/gui/image/qtiffhandler.cpp
new file mode 100644
index 0000000..de4f680
--- /dev/null
+++ b/src/gui/image/qtiffhandler.cpp
@@ -0,0 +1,661 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins 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 "qtiffhandler_p.h"
+#include <qvariant.h>
+#include <qdebug.h>
+#include <qimage.h>
+#include <qglobal.h>
+extern "C" {
+#include "tiffio.h"
+}
+
+QT_BEGIN_NAMESPACE
+
+tsize_t qtiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ QIODevice* device = static_cast<QTiffHandler*>(fd)->device();
+ return device->isReadable() ? device->read(static_cast<char *>(buf), size) : -1;
+}
+
+tsize_t qtiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return static_cast<QTiffHandler*>(fd)->device()->write(static_cast<char *>(buf), size);
+}
+
+toff_t qtiffSeekProc(thandle_t fd, toff_t off, int whence)
+{
+ QIODevice *device = static_cast<QTiffHandler*>(fd)->device();
+ switch (whence) {
+ case SEEK_SET:
+ device->seek(off);
+ break;
+ case SEEK_CUR:
+ device->seek(device->pos() + off);
+ break;
+ case SEEK_END:
+ device->seek(device->size() + off);
+ break;
+ }
+
+ return device->pos();
+}
+
+int qtiffCloseProc(thandle_t /*fd*/)
+{
+ return 0;
+}
+
+toff_t qtiffSizeProc(thandle_t fd)
+{
+ return static_cast<QTiffHandler*>(fd)->device()->size();
+}
+
+int qtiffMapProc(thandle_t /*fd*/, tdata_t* /*pbase*/, toff_t* /*psize*/)
+{
+ return 0;
+}
+
+void qtiffUnmapProc(thandle_t /*fd*/, tdata_t /*base*/, toff_t /*size*/)
+{
+}
+
+// for 32 bits images
+inline void rotate_right_mirror_horizontal(QImage *const image)// rotate right->mirrored horizontal
+{
+ const int height = image->height();
+ const int width = image->width();
+ QImage generated(/* width = */ height, /* height = */ width, image->format());
+ const uint32 *originalPixel = reinterpret_cast<const uint32*>(image->bits());
+ uint32 *const generatedPixels = reinterpret_cast<uint32*>(generated.bits());
+ for (int row=0; row < height; ++row) {
+ for (int col=0; col < width; ++col) {
+ int idx = col * height + row;
+ generatedPixels[idx] = *originalPixel;
+ ++originalPixel;
+ }
+ }
+ *image = generated;
+}
+
+inline void rotate_right_mirror_vertical(QImage *const image) // rotate right->mirrored vertical
+{
+ const int height = image->height();
+ const int width = image->width();
+ QImage generated(/* width = */ height, /* height = */ width, image->format());
+ const int lastCol = width - 1;
+ const int lastRow = height - 1;
+ const uint32 *pixel = reinterpret_cast<const uint32*>(image->bits());
+ uint32 *const generatedBits = reinterpret_cast<uint32*>(generated.bits());
+ for (int row=0; row < height; ++row) {
+ for (int col=0; col < width; ++col) {
+ int idx = (lastCol - col) * height + (lastRow - row);
+ generatedBits[idx] = *pixel;
+ ++pixel;
+ }
+ }
+ *image = generated;
+}
+
+QTiffHandler::QTiffHandler() : QImageIOHandler()
+{
+ compression = NoCompression;
+}
+
+bool QTiffHandler::canRead() const
+{
+ if (canRead(device())) {
+ setFormat("tiff");
+ return true;
+ }
+ return false;
+}
+
+bool QTiffHandler::canRead(QIODevice *device)
+{
+ if (!device) {
+ qWarning("QTiffHandler::canRead() called with no device");
+ return false;
+ }
+
+ // current implementation uses TIFFClientOpen which needs to be
+ // able to seek, so sequential devices are not supported
+ QByteArray header = device->peek(4);
+ return header == QByteArray::fromRawData("\x49\x49\x2A\x00", 4)
+ || header == QByteArray::fromRawData("\x4D\x4D\x00\x2A", 4);
+}
+
+bool QTiffHandler::read(QImage *image)
+{
+ if (!canRead())
+ return false;
+
+ TIFF *const tiff = TIFFClientOpen("foo",
+ "r",
+ this,
+ qtiffReadProc,
+ qtiffWriteProc,
+ qtiffSeekProc,
+ qtiffCloseProc,
+ qtiffSizeProc,
+ qtiffMapProc,
+ qtiffUnmapProc);
+
+ if (!tiff) {
+ return false;
+ }
+ uint32 width;
+ uint32 height;
+ uint16 photometric;
+ if (!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width)
+ || !TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height)
+ || !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric)) {
+ TIFFClose(tiff);
+ return false;
+ }
+
+ // BitsPerSample defaults to 1 according to the TIFF spec.
+ uint16 bitPerSample;
+ if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample))
+ bitPerSample = 1;
+
+ bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE;
+ if (grayscale && bitPerSample == 1) {
+ if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono)
+ *image = QImage(width, height, QImage::Format_Mono);
+ QVector<QRgb> colortable(2);
+ if (photometric == PHOTOMETRIC_MINISBLACK) {
+ colortable[0] = 0xff000000;
+ colortable[1] = 0xffffffff;
+ } else {
+ colortable[0] = 0xffffffff;
+ colortable[1] = 0xff000000;
+ }
+ image->setColorTable(colortable);
+
+ if (!image->isNull()) {
+ for (uint32 y=0; y<height; ++y) {
+ if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
+ TIFFClose(tiff);
+ return false;
+ }
+ }
+ }
+ } else {
+ if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8) {
+ if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8)
+ *image = QImage(width, height, QImage::Format_Indexed8);
+ if (!image->isNull()) {
+ const uint16 tableSize = 256;
+ QVector<QRgb> qtColorTable(tableSize);
+ if (grayscale) {
+ for (int i = 0; i<tableSize; ++i) {
+ const int c = (photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i);
+ qtColorTable[i] = qRgb(c, c, c);
+ }
+ } else {
+ // create the color table
+ uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
+ uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
+ uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
+ if (!redTable || !greenTable || !blueTable) {
+ TIFFClose(tiff);
+ return false;
+ }
+ if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
+ TIFFClose(tiff);
+ return false;
+ }
+
+ for (int i = 0; i<tableSize ;++i) {
+ const int red = redTable[i] / 257;
+ const int green = greenTable[i] / 257;
+ const int blue = blueTable[i] / 257;
+ qtColorTable[i] = qRgb(red, green, blue);
+ }
+ }
+
+ image->setColorTable(qtColorTable);
+ for (uint32 y=0; y<height; ++y) {
+ if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
+ TIFFClose(tiff);
+ return false;
+ }
+ }
+
+ // free redTable, greenTable and greenTable done by libtiff
+ }
+ } else {
+ if (image->size() != QSize(width, height) || image->format() != QImage::Format_ARGB32)
+ *image = QImage(width, height, QImage::Format_ARGB32);
+ if (!image->isNull()) {
+ const int stopOnError = 1;
+ if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), ORIENTATION_TOPLEFT, stopOnError)) {
+ for (uint32 y=0; y<height; ++y)
+ convert32BitOrder(image->scanLine(y), width);
+ } else {
+ TIFFClose(tiff);
+ return false;
+ }
+ }
+ }
+ }
+
+ if (image->isNull()) {
+ TIFFClose(tiff);
+ return false;
+ }
+
+ float resX = 0;
+ float resY = 0;
+ uint16 resUnit = RESUNIT_NONE;
+ if (TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit)
+ && TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &resX)
+ && TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &resY)) {
+
+ switch(resUnit) {
+ case RESUNIT_CENTIMETER:
+ image->setDotsPerMeterX(qRound(resX * 100));
+ image->setDotsPerMeterY(qRound(resY * 100));
+ break;
+ case RESUNIT_INCH:
+ image->setDotsPerMeterX(qRound(resX * (100 / 2.54)));
+ image->setDotsPerMeterY(qRound(resY * (100 / 2.54)));
+ break;
+ default:
+ // do nothing as defaults have already
+ // been set within the QImage class
+ break;
+ }
+ }
+
+ // rotate the image if the orientation is defined in the file
+ uint16 orientationTag;
+ if (TIFFGetField(tiff, TIFFTAG_ORIENTATION, &orientationTag)) {
+ if (image->format() == QImage::Format_ARGB32) {
+ // TIFFReadRGBAImageOriented() flip the image but does not rotate them
+ switch (orientationTag) {
+ case 5:
+ rotate_right_mirror_horizontal(image);
+ break;
+ case 6:
+ rotate_right_mirror_vertical(image);
+ break;
+ case 7:
+ rotate_right_mirror_horizontal(image);
+ break;
+ case 8:
+ rotate_right_mirror_vertical(image);
+ break;
+ }
+ } else {
+ switch (orientationTag) {
+ case 1: // default orientation
+ break;
+ case 2: // mirror horizontal
+ *image = image->mirrored(true, false);
+ break;
+ case 3: // mirror both
+ *image = image->mirrored(true, true);
+ break;
+ case 4: // mirror vertical
+ *image = image->mirrored(false, true);
+ break;
+ case 5: // rotate right mirror horizontal
+ {
+ QMatrix transformation;
+ transformation.rotate(90);
+ *image = image->transformed(transformation);
+ *image = image->mirrored(true, false);
+ break;
+ }
+ case 6: // rotate right
+ {
+ QMatrix transformation;
+ transformation.rotate(90);
+ *image = image->transformed(transformation);
+ break;
+ }
+ case 7: // rotate right, mirror vertical
+ {
+ QMatrix transformation;
+ transformation.rotate(90);
+ *image = image->transformed(transformation);
+ *image = image->mirrored(false, true);
+ break;
+ }
+ case 8: // rotate left
+ {
+ QMatrix transformation;
+ transformation.rotate(270);
+ *image = image->transformed(transformation);
+ break;
+ }
+ }
+ }
+ }
+
+
+ TIFFClose(tiff);
+ return true;
+}
+
+static bool checkGrayscale(const QVector<QRgb> &colorTable)
+{
+ if (colorTable.size() != 256)
+ return false;
+
+ const bool increasing = (colorTable.at(0) == 0xff000000);
+ for (int i = 0; i < 256; ++i) {
+ if ((increasing && colorTable.at(i) != qRgb(i, i, i))
+ || (!increasing && colorTable.at(i) != qRgb(255 - i, 255 - i, 255 - i)))
+ return false;
+ }
+ return true;
+}
+
+bool QTiffHandler::write(const QImage &image)
+{
+ if (!device()->isWritable())
+ return false;
+
+ TIFF *const tiff = TIFFClientOpen("foo",
+ "w",
+ this,
+ qtiffReadProc,
+ qtiffWriteProc,
+ qtiffSeekProc,
+ qtiffCloseProc,
+ qtiffSizeProc,
+ qtiffMapProc,
+ qtiffUnmapProc);
+ if (!tiff)
+ return false;
+
+ const int width = image.width();
+ const int height = image.height();
+
+ if (!TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width)
+ || !TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height)
+ || !TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
+ TIFFClose(tiff);
+ return false;
+ }
+
+ // set the resolution
+ bool resolutionSet = false;
+ const int dotPerMeterX = image.dotsPerMeterX();
+ const int dotPerMeterY = image.dotsPerMeterY();
+ if ((dotPerMeterX % 100) == 0
+ && (dotPerMeterY % 100) == 0) {
+ resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER)
+ && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, dotPerMeterX/100.0)
+ && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, dotPerMeterY/100.0);
+ } else {
+ resolutionSet = TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)
+ && TIFFSetField(tiff, TIFFTAG_XRESOLUTION, static_cast<float>(image.logicalDpiX()))
+ && TIFFSetField(tiff, TIFFTAG_YRESOLUTION, static_cast<float>(image.logicalDpiY()));
+ }
+ if (!resolutionSet) {
+ TIFFClose(tiff);
+ return false;
+ }
+
+ // configure image depth
+ const QImage::Format format = image.format();
+ if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) {
+ uint16 photometric = PHOTOMETRIC_MINISBLACK;
+ if (image.colorTable().at(0) == 0xffffffff)
+ photometric = PHOTOMETRIC_MINISWHITE;
+ if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
+ || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE)
+ || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 1)) {
+ TIFFClose(tiff);
+ return false;
+ }
+
+ // try to do the conversion in chunks no greater than 16 MB
+ int chunks = (width * height / (1024 * 1024 * 16)) + 1;
+ int chunkHeight = qMax(height / chunks, 1);
+
+ int y = 0;
+ while (y < height) {
+ QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_Mono);
+
+ int chunkStart = y;
+ int chunkEnd = y + chunk.height();
+ while (y < chunkEnd) {
+ if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) {
+ TIFFClose(tiff);
+ return false;
+ }
+ ++y;
+ }
+ }
+ TIFFClose(tiff);
+ } else if (format == QImage::Format_Indexed8) {
+ const QVector<QRgb> colorTable = image.colorTable();
+ bool isGrayscale = checkGrayscale(colorTable);
+ if (isGrayscale) {
+ uint16 photometric = PHOTOMETRIC_MINISBLACK;
+ if (image.colorTable().at(0) == 0xffffffff)
+ photometric = PHOTOMETRIC_MINISWHITE;
+ if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
+ || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
+ || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
+ TIFFClose(tiff);
+ return false;
+ }
+ } else {
+ if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE)
+ || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
+ || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
+ TIFFClose(tiff);
+ return false;
+ }
+ //// write the color table
+ // allocate the color tables
+ uint16 *redTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
+ uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
+ uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
+ if (!redTable || !greenTable || !blueTable) {
+ TIFFClose(tiff);
+ return false;
+ }
+
+ // set the color table
+ const int tableSize = colorTable.size();
+ Q_ASSERT(tableSize <= 256);
+ for (int i = 0; i<tableSize; ++i) {
+ const QRgb color = colorTable.at(i);
+ redTable[i] = qRed(color) * 257;
+ greenTable[i] = qGreen(color) * 257;
+ blueTable[i] = qBlue(color) * 257;
+ }
+
+ const bool setColorTableSuccess = TIFFSetField(tiff, TIFFTAG_COLORMAP, redTable, greenTable, blueTable);
+
+ qFree(redTable);
+ qFree(greenTable);
+ qFree(blueTable);
+
+ if (!setColorTableSuccess) {
+ TIFFClose(tiff);
+ return false;
+ }
+ }
+
+ //// write the data
+ // try to do the conversion in chunks no greater than 16 MB
+ int chunks = (width * height/ (1024 * 1024 * 16)) + 1;
+ int chunkHeight = qMax(height / chunks, 1);
+
+ int y = 0;
+ while (y < height) {
+ QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y));
+
+ int chunkStart = y;
+ int chunkEnd = y + chunk.height();
+ while (y < chunkEnd) {
+ if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) {
+ TIFFClose(tiff);
+ return false;
+ }
+ ++y;
+ }
+ }
+ TIFFClose(tiff);
+
+ } else {
+ if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
+ || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)
+ || !TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 4)
+ || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
+ TIFFClose(tiff);
+ return false;
+ }
+ // try to do the ARGB32 conversion in chunks no greater than 16 MB
+ int chunks = (width * height * 4 / (1024 * 1024 * 16)) + 1;
+ int chunkHeight = qMax(height / chunks, 1);
+
+ int y = 0;
+ while (y < height) {
+ QImage chunk = image.copy(0, y, width, qMin(chunkHeight, height - y)).convertToFormat(QImage::Format_ARGB32);
+
+ int chunkStart = y;
+ int chunkEnd = y + chunk.height();
+ while (y < chunkEnd) {
+ if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)
+ convert32BitOrder(chunk.scanLine(y - chunkStart), width);
+ else
+ convert32BitOrderBigEndian(chunk.scanLine(y - chunkStart), width);
+
+ if (TIFFWriteScanline(tiff, reinterpret_cast<uint32 *>(chunk.scanLine(y - chunkStart)), y) != 1) {
+ TIFFClose(tiff);
+ return false;
+ }
+ ++y;
+ }
+ }
+ TIFFClose(tiff);
+ }
+
+ return true;
+}
+
+QByteArray QTiffHandler::name() const
+{
+ return "tiff";
+}
+
+QVariant QTiffHandler::option(ImageOption option) const
+{
+ if (option == Size && canRead()) {
+ QSize imageSize;
+ qint64 pos = device()->pos();
+ TIFF *tiff = TIFFClientOpen("foo",
+ "r",
+ const_cast<QTiffHandler*>(this),
+ qtiffReadProc,
+ qtiffWriteProc,
+ qtiffSeekProc,
+ qtiffCloseProc,
+ qtiffSizeProc,
+ qtiffMapProc,
+ qtiffUnmapProc);
+
+ if (tiff) {
+ uint32 width = 0;
+ uint32 height = 0;
+ TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &height);
+ imageSize = QSize(width, height);
+ }
+ device()->seek(pos);
+ if (imageSize.isValid())
+ return imageSize;
+ } else if (option == CompressionRatio) {
+ return compression;
+ } else if (option == ImageFormat) {
+ return QImage::Format_ARGB32;
+ }
+ return QVariant();
+}
+
+void QTiffHandler::setOption(ImageOption option, const QVariant &value)
+{
+ if (option == CompressionRatio && value.type() == QVariant::Int)
+ compression = value.toInt();
+}
+
+bool QTiffHandler::supportsOption(ImageOption option) const
+{
+ return option == CompressionRatio
+ || option == Size
+ || option == ImageFormat;
+}
+
+void QTiffHandler::convert32BitOrder(void *buffer, int width)
+{
+ uint32 *target = reinterpret_cast<uint32 *>(buffer);
+ for (int32 x=0; x<width; ++x) {
+ uint32 p = target[x];
+ // convert between ARGB and ABGR
+ target[x] = (p & 0xff000000)
+ | ((p & 0x00ff0000) >> 16)
+ | (p & 0x0000ff00)
+ | ((p & 0x000000ff) << 16);
+ }
+}
+
+void QTiffHandler::convert32BitOrderBigEndian(void *buffer, int width)
+{
+ uint32 *target = reinterpret_cast<uint32 *>(buffer);
+ for (int32 x=0; x<width; ++x) {
+ uint32 p = target[x];
+ target[x] = (p & 0xff000000) >> 24
+ | (p & 0x00ff0000) << 8
+ | (p & 0x0000ff00) << 8
+ | (p & 0x000000ff) << 8;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/image/qtiffhandler.pri b/src/gui/image/qtiffhandler.pri
new file mode 100644
index 0000000..e1cc3ee
--- /dev/null
+++ b/src/gui/image/qtiffhandler.pri
@@ -0,0 +1,10 @@
+# common to plugin and built-in forms
+INCLUDEPATH *= $$PWD
+HEADERS += $$PWD/qtiffhandler_p.h
+SOURCES += $$PWD/qtiffhandler.cpp
+contains(QT_CONFIG, system-tiff) {
+ if(unix|win32-g++*):LIBS += -ltiff
+ else:win32: LIBS += libtiff.lib
+} else {
+ include($$PWD/../../3rdparty/libtiff.pri)
+}
diff --git a/src/gui/image/qtiffhandler_p.h b/src/gui/image/qtiffhandler_p.h
new file mode 100644
index 0000000..da7d7ed
--- /dev/null
+++ b/src/gui/image/qtiffhandler_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins 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 QTIFFHANDLER_P_H
+#define QTIFFHANDLER_P_H
+
+#include <QtGui/qimageiohandler.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTiffHandler : public QImageIOHandler
+{
+public:
+ QTiffHandler();
+
+ bool canRead() const;
+ bool read(QImage *image);
+ bool write(const QImage &image);
+
+ QByteArray name() const;
+
+ static bool canRead(QIODevice *device);
+
+ QVariant option(ImageOption option) const;
+ void setOption(ImageOption option, const QVariant &value);
+ bool supportsOption(ImageOption option) const;
+
+ enum Compression {
+ NoCompression = 0,
+ LzwCompression = 1
+ };
+private:
+ void convert32BitOrder(void *buffer, int width);
+ void convert32BitOrderBigEndian(void *buffer, int width);
+ int compression;
+};
+
+QT_END_NAMESPACE
+
+#endif // QTIFFHANDLER_P_H
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 6fd45ad..f9c84c1 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -120,18 +120,21 @@ symbian {
kernel/qkeymapper_s60.cpp\
kernel/qclipboard_s60.cpp\
kernel/qdnd_s60.cpp \
- kernel/qsound_s60.cpp \
- kernel/qsoftkeymanager_s60.cpp
+ kernel/qsound_s60.cpp
HEADERS += \
kernel/qt_s60_p.h \
- kernel/qeventdispatcher_s60_p.h \
- kernel/qsoftkeymanager_s60_p.h
+ kernel/qeventdispatcher_s60_p.h
LIBS += -lbafl -lestor
INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE
INCLUDEPATH += ../3rdparty/s60
+
+ contains(QT_CONFIG, s60) {
+ SOURCES += kernel/qsoftkeymanager_s60.cpp
+ HEADERS += kernel/qsoftkeymanager_s60_p.h
+ }
}
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 1680ef4..94211fd 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -81,7 +81,7 @@
#include <private/qt_x11_p.h>
#endif
-#if defined(Q_WS_X11) || defined(Q_WS_S60)
+#if defined(Q_WS_X11) || defined(Q_OS_SYMBIAN)
#include "qinputcontextfactory.h"
#endif
@@ -902,6 +902,7 @@ QApplication::QApplication(Display *dpy, int &argc, char **argv,
#endif // Q_WS_X11
extern void qInitDrawhelperAsm();
+extern void qInitImageConversions();
extern int qRegisterGuiVariant();
extern int qUnregisterGuiVariant();
#ifndef QT_NO_STATEMACHINE
@@ -959,6 +960,8 @@ void QApplicationPrivate::initialize()
// Set up which span functions should be used in raster engine...
qInitDrawhelperAsm();
+ // and QImage conversion functions
+ qInitImageConversions();
#ifndef QT_NO_WHEELEVENT
QApplicationPrivate::wheel_scroll_lines = 3;
@@ -2771,7 +2774,7 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) {
qt_win_set_cursor(cursorWidget, true);
#elif defined(Q_WS_X11)
qt_x11_enforce_cursor(cursorWidget, true);
-#elif defined(Q_WS_S60)
+#elif defined(Q_OS_SYMBIAN)
qt_symbian_set_cursor(cursorWidget, true);
#endif
}
diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h
index cb1d063..d31d9e5 100644
--- a/src/gui/kernel/qapplication.h
+++ b/src/gui/kernel/qapplication.h
@@ -61,7 +61,7 @@
QT_BEGIN_HEADER
-#if defined(Q_WS_S60)
+#if defined(Q_OS_SYMBIAN)
class CApaApplication;
#endif
@@ -118,7 +118,7 @@ class Q_GUI_EXPORT QApplication : public QCoreApplication
public:
enum Type { Tty, GuiClient, GuiServer };
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
typedef CApaApplication * (*QS60MainApplicationFactory)();
#endif
@@ -130,7 +130,7 @@ public:
QApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0, int = QT_VERSION);
QApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0, int = QT_VERSION);
#endif
-#if defined(Q_WS_S60)
+#if defined(Q_OS_SYMBIAN)
QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int = QT_VERSION);
#endif
#endif
@@ -366,7 +366,7 @@ public:
QApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0);
QApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
#endif
-#if defined(Q_WS_S60) || defined(qdoc)
+#if defined(Q_OS_SYMBIAN) || defined(qdoc)
QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv);
#endif
#endif
diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp
index a7c7310..0d65811 100644
--- a/src/gui/kernel/qapplication_s60.cpp
+++ b/src/gui/kernel/qapplication_s60.cpp
@@ -69,14 +69,17 @@
#include "apgwgnam.h" // For CApaWindowGroupName
#include <mdaaudiotoneplayer.h> // For CMdaAudioToneUtility
+#if defined(Q_OS_SYMBIAN)
+# include <private/qs60mainapplication_p.h>
+# include <centralrepository.h>
+# include "qs60mainappui.h"
+# include "qinputcontext.h"
+#endif
+
#if defined(Q_WS_S60)
# if !defined(QT_NO_IM)
-# include "qinputcontext.h"
# include <private/qcoefepinputcontext_p.h>
# endif
-# include <private/qs60mainapplication_p.h>
-# include <centralrepository.h>
-# include "qs60mainappui.h"
#endif
#include "private/qstylesheetstyle_p.h"
@@ -894,7 +897,7 @@ TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent)
if (qic && qic->filterEvent(keyEvent))
return EKeyWasConsumed;
}
-#endif // !defined(QT_NO_IM) && defined(Q_WS_S60)
+#endif // !defined(QT_NO_IM) && defined(Q_OS_SYMBIAN)
if (widget && qt_sendSpontaneousEvent(widget, keyEvent))
if (keyEvent->isAccepted())
@@ -1974,10 +1977,10 @@ int QApplicationPrivate::symbianHandleCommand(const QSymbianEvent *symbianEvent)
ret = 1;
break;
default:
+#ifdef Q_WS_S60
bool handled = QSoftKeyManager::handleCommand(command);
if (handled)
ret = 1;
-#ifdef Q_WS_S60
else
ret = QMenuBarPrivate::symbianCommands(command);
#endif
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp
index ef719ca..9e8a128 100644
--- a/src/gui/kernel/qapplication_win.cpp
+++ b/src/gui/kernel/qapplication_win.cpp
@@ -4086,7 +4086,12 @@ void QApplicationPrivate::initializeMultitouch_sys()
{
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
static const int QT_SM_DIGITIZER = 94;
- QApplicationPrivate::HasTouchSupport = GetSystemMetrics(QT_SM_DIGITIZER);
+ int value = GetSystemMetrics(QT_SM_DIGITIZER);
+ static const int QT_NID_INTEGRATED_TOUCH = 0x01;
+ static const int QT_NID_EXTERNAL_TOUCH = 0x02;
+ static const int QT_NID_MULTI_INPUT = 0x40;
+ QApplicationPrivate::HasTouchSupport =
+ value & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH | QT_NID_MULTI_INPUT);
}
QLibrary library(QLatin1String("user32"));
diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp
index 04e4685..54e6317 100644
--- a/src/gui/kernel/qsoftkeymanager.cpp
+++ b/src/gui/kernel/qsoftkeymanager.cpp
@@ -162,6 +162,7 @@ void QSoftKeyManager::sendKeyEvent()
void QSoftKeyManager::updateSoftKeys()
{
+ QSoftKeyManager::instance()->d_func()->pendingUpdate = true;
QEvent *event = new QEvent(QEvent::UpdateSoftKeys);
QApplication::postEvent(QSoftKeyManager::instance(), event);
}
@@ -250,6 +251,7 @@ bool QSoftKeyManager::handleUpdateSoftKeys()
}
d->updateSoftKeys_sys();
+ d->pendingUpdate = false;
return true;
}
@@ -275,6 +277,9 @@ bool QSoftKeyManager::event(QEvent *e)
#ifdef Q_WS_S60
bool QSoftKeyManager::handleCommand(int command)
{
+ if (QSoftKeyManager::instance()->d_func()->pendingUpdate)
+ (void)QSoftKeyManager::instance()->handleUpdateSoftKeys();
+
return static_cast<QSoftKeyManagerPrivateS60*>(QSoftKeyManager::instance()->d_func())->handleCommand(command);
}
#endif
diff --git a/src/gui/kernel/qsoftkeymanager_common_p.h b/src/gui/kernel/qsoftkeymanager_common_p.h
index 04ddf7d..1b364d4 100644
--- a/src/gui/kernel/qsoftkeymanager_common_p.h
+++ b/src/gui/kernel/qsoftkeymanager_common_p.h
@@ -71,7 +71,7 @@ protected:
QHash<QAction*, Qt::Key> keyedActions;
QMultiHash<int, QAction*> requestedSoftKeyActions;
QWidget *initialSoftKeySource;
-
+ bool pendingUpdate;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp
index 8a3e89e..62d8a53 100644
--- a/src/gui/kernel/qstandardgestures.cpp
+++ b/src/gui/kernel/qstandardgestures.cpp
@@ -45,6 +45,7 @@
#include "qevent.h"
#include "qwidget.h"
#include "qabstractscrollarea.h"
+#include <qgraphicssceneevent.h>
#include "qdebug.h"
#ifndef QT_NO_GESTURES
@@ -509,49 +510,65 @@ QTapAndHoldGestureRecognizer::recognize(QGesture *state, QObject *object,
if (object == state && event->type() == QEvent::Timer) {
q->killTimer(d->timerId);
d->timerId = 0;
- return QGestureRecognizer::Ignore | QGestureRecognizer::ConsumeEventHint;
+ return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint;
}
const QTouchEvent *ev = static_cast<const QTouchEvent *>(event);
-
- QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture;
+ const QMouseEvent *me = static_cast<const QMouseEvent *>(event);
+ const QGraphicsSceneMouseEvent *gsme = static_cast<const QGraphicsSceneMouseEvent *>(event);
enum { TimerInterval = 2000 };
enum { TapRadius = 40 };
switch (event->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ d->position = gsme->screenPos();
+ q->setHotSpot(d->position);
+ if (d->timerId)
+ q->killTimer(d->timerId);
+ d->timerId = q->startTimer(TimerInterval);
+ return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
+ case QEvent::MouseButtonPress:
+ d->position = me->globalPos();
+ q->setHotSpot(d->position);
+ if (d->timerId)
+ q->killTimer(d->timerId);
+ d->timerId = q->startTimer(TimerInterval);
+ return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
case QEvent::TouchBegin:
- d->position = ev->touchPoints().at(0).pos();
+ d->position = ev->touchPoints().at(0).startScreenPos();
+ q->setHotSpot(d->position);
if (d->timerId)
q->killTimer(d->timerId);
d->timerId = q->startTimer(TimerInterval);
- q->setHotSpot(ev->touchPoints().at(0).startScreenPos());
- result = QGestureRecognizer::TriggerGesture;
- break;
+ return QGestureRecognizer::MayBeGesture; // we don't show a sign of life until the timeout
+ case QEvent::GraphicsSceneMouseRelease:
+ case QEvent::MouseButtonRelease:
case QEvent::TouchEnd:
- if (d->timerId)
- result = QGestureRecognizer::CancelGesture;
- else
- result = QGestureRecognizer::FinishGesture;
- break;
+ return QGestureRecognizer::CancelGesture; // get out of the MayBeGesture state
case QEvent::TouchUpdate:
- if (q->state() != Qt::NoGesture && ev->touchPoints().size() == 1) {
+ if (d->timerId && ev->touchPoints().size() == 1) {
QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
QPoint delta = p.pos().toPoint() - p.startPos().toPoint();
if (delta.manhattanLength() <= TapRadius)
- result = QGestureRecognizer::TriggerGesture;
+ return QGestureRecognizer::MayBeGesture;
}
- break;
- case QEvent::MouseButtonPress:
- case QEvent::MouseMove:
- case QEvent::MouseButtonRelease:
- result = QGestureRecognizer::Ignore;
- break;
+ return QGestureRecognizer::CancelGesture;
+ case QEvent::MouseMove: {
+ QPoint delta = me->globalPos() - d->position.toPoint();
+ if (d->timerId && delta.manhattanLength() <= TapRadius)
+ return QGestureRecognizer::MayBeGesture;
+ return QGestureRecognizer::CancelGesture;
+ }
+ case QEvent::GraphicsSceneMouseMove: {
+ QPoint delta = gsme->screenPos() - d->position.toPoint();
+ if (d->timerId && delta.manhattanLength() <= TapRadius)
+ return QGestureRecognizer::MayBeGesture;
+ return QGestureRecognizer::CancelGesture;
+ }
default:
- result = QGestureRecognizer::Ignore;
- break;
+ return QGestureRecognizer::Ignore;
}
- return result;
}
void QTapAndHoldGestureRecognizer::reset(QGesture *state)
diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h
index 204e38c..d8ef67d 100644
--- a/src/gui/kernel/qt_s60_p.h
+++ b/src/gui/kernel/qt_s60_p.h
@@ -155,7 +155,9 @@ public:
static inline CAknTitlePane* titlePane();
static inline CAknContextPane* contextPane();
static inline CEikButtonGroupContainer* buttonGroupContainer();
+#endif
+#ifdef Q_OS_SYMBIAN
TTrapHandler *s60InstalledTrapHandler;
#endif
};
@@ -208,7 +210,7 @@ protected: // from MAknFadedComponent
TInt CountFadedComponents() {return 1;}
CCoeControl* FadedComponent(TInt /*aIndex*/) {return this;}
#else
- #warning No fallback implementation for QSymbianControl::FadeBehindPopup
+ // #warning No fallback implementation for QSymbianControl::FadeBehindPopup
void FadeBehindPopup(bool /*fade*/){ }
#endif
@@ -277,9 +279,9 @@ inline QS60Data::QS60Data()
avkonComponentsSupportTransparency(0),
menuBeingConstructed(0),
memoryLimitForHwRendering(0),
- s60ApplicationFactory(0),
-#ifdef Q_WS_S60
- s60InstalledTrapHandler(0)
+ s60ApplicationFactory(0)
+#ifdef Q_OS_SYMBIAN
+ ,s60InstalledTrapHandler(0)
#endif
{
}
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index dd568cd..233df15 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -10695,7 +10695,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
break;
case Qt::WA_AcceptTouchEvents:
-#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60)
+#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN)
if (on)
d->registerTouchWindow();
#endif
diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm
index a9bb691..e57ec77 100644
--- a/src/gui/kernel/qwidget_mac.mm
+++ b/src/gui/kernel/qwidget_mac.mm
@@ -2861,9 +2861,11 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
}
if (wasWindow) {
oldToolbar = [oldWindow toolbar];
- [oldToolbar retain];
- oldToolbarVisible = [oldToolbar isVisible];
- [oldWindow setToolbar:nil];
+ if (oldToolbar) {
+ [oldToolbar retain];
+ oldToolbarVisible = [oldToolbar isVisible];
+ [oldWindow setToolbar:nil];
+ }
}
#endif
}
diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp
index 3f351d9..2818d88 100644
--- a/src/gui/kernel/qwidget_s60.cpp
+++ b/src/gui/kernel/qwidget_s60.cpp
@@ -54,6 +54,7 @@
#ifdef Q_WS_S60
#include <aknappui.h>
+#include <eikbtgpc.h>
#endif
// This is necessary in order to be able to perform delayed invokation on slots
@@ -1082,12 +1083,14 @@ void QWidget::setWindowState(Qt::WindowStates newstate)
Qt::WindowStates oldstate = windowState();
const TBool isFullscreen = newstate & Qt::WindowFullScreen;
+#ifdef Q_WS_S60
const TBool cbaRequested = windowFlags() & Qt::WindowSoftkeysVisibleHint;
const TBool cbaVisible = CEikButtonGroupContainer::Current() ? true : false;
const TBool softkeyVisibilityChange = isFullscreen && (cbaRequested != cbaVisible);
if (oldstate == newstate && !softkeyVisibilityChange)
return;
+#endif // Q_WS_S60
if (isWindow()) {
createWinId();
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index 9c65aa0..0f05c6b 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -1167,7 +1167,7 @@ void QWidgetPrivate::show_sys()
// This is to resolve the problem where popups are opened from the
// system tray and not being implicitly activated
if (q->windowType() == Qt::Popup &&
- (!q->parentWidget() || !q->parentWidget()->isActiveWindow()))
+ !q->parentWidget() && !qApp->activeWindow())
q->activateWindow();
}
diff --git a/src/gui/kernel/qx11embed_x11.cpp b/src/gui/kernel/qx11embed_x11.cpp
index b527e72..9f1b1f8 100644
--- a/src/gui/kernel/qx11embed_x11.cpp
+++ b/src/gui/kernel/qx11embed_x11.cpp
@@ -1070,6 +1070,7 @@ QX11EmbedContainer::QX11EmbedContainer(QWidget *parent)
d->focusProxy = new QWidget(this);
d->focusProxy->setAttribute(Qt::WA_NativeWindow);
d->focusProxy->setAttribute(Qt::WA_DontCreateNativeAncestors);
+ d->focusProxy->createWinId();
d->focusProxy->setGeometry(-1, -1, 1, 1);
// We need events from the window (activation status) and
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index a5cfb84..4023f65 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -202,154 +202,17 @@ x11|embedded {
DEFINES += QT_NO_CUPS QT_NO_LPR
}
-contains(QMAKE_MAC_XARCH, no) {
- DEFINES += QT_NO_MAC_XARCH
-} else:if(mmx|3dnow|sse|sse2|iwmmxt) {
+if(mmx|3dnow|sse|sse2|iwmmxt) {
HEADERS += painting/qdrawhelper_x86_p.h \
painting/qdrawhelper_mmx_p.h \
- painting/qdrawhelper_sse_p.h
- mmx {
- DEFINES += QT_HAVE_MMX
- MMX_SOURCES += painting/qdrawhelper_mmx.cpp
- }
- 3dnow {
- DEFINES += QT_HAVE_3DNOW
- MMX3DNOW_SOURCES += painting/qdrawhelper_mmx3dnow.cpp
- sse {
- SSE3DNOW_SOURCES += painting/qdrawhelper_sse3dnow.cpp
- }
- }
- sse {
- DEFINES += QT_HAVE_SSE
- SSE_SOURCES += painting/qdrawhelper_sse.cpp
-
- DEFINES += QT_HAVE_MMXEXT
- }
- sse2 {
- DEFINES += QT_HAVE_SSE2
- SSE2_SOURCES += painting/qdrawhelper_sse2.cpp
- }
- iwmmxt {
- DEFINES += QT_HAVE_IWMMXT
- IWMMXT_SOURCES += painting/qdrawhelper_iwmmxt.cpp
- }
-
- win32-g++*|!win32:!*-icc* {
- mmx {
- mmx_compiler.commands = $$QMAKE_CXX -c -Winline
-
- mac {
- mmx_compiler.commands += -Xarch_i386 -mmmx
- mmx_compiler.commands += -Xarch_x86_64 -mmmx
- } else {
- mmx_compiler.commands += -mmmx
- }
-
- mmx_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
- mmx_compiler.dependency_type = TYPE_C
- mmx_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
- mmx_compiler.input = MMX_SOURCES
- mmx_compiler.variable_out = OBJECTS
- mmx_compiler.name = compiling[mmx] ${QMAKE_FILE_IN}
- silent:mmx_compiler.commands = @echo compiling[mmx] ${QMAKE_FILE_IN} && $$mmx_compiler.commands
- QMAKE_EXTRA_COMPILERS += mmx_compiler
- }
- 3dnow {
- mmx3dnow_compiler.commands = $$QMAKE_CXX -c -Winline
-
- mac {
- mmx3dnow_compiler.commands += -Xarch_i386 -m3dnow -Xarch_i386 -mmmx
- mmx3dnow_compiler.commands += -Xarch_x86_64 -m3dnow -Xarch_x86_64 -mmmx
- } else {
- mmx3dnow_compiler.commands += -m3dnow -mmmx
- }
-
- mmx3dnow_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
- mmx3dnow_compiler.dependency_type = TYPE_C
- mmx3dnow_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
- mmx3dnow_compiler.input = MMX3DNOW_SOURCES
- mmx3dnow_compiler.variable_out = OBJECTS
- mmx3dnow_compiler.name = compiling[mmx3dnow] ${QMAKE_FILE_IN}
- silent:mmx3dnow_compiler.commands = @echo compiling[mmx3dnow] ${QMAKE_FILE_IN} && $$mmx3dnow_compiler.commands
- QMAKE_EXTRA_COMPILERS += mmx3dnow_compiler
- sse {
- sse3dnow_compiler.commands = $$QMAKE_CXX -c -Winline
-
- mac {
- sse3dnow_compiler.commands += -Xarch_i386 -m3dnow -Xarch_i386 -msse
- sse3dnow_compiler.commands += -Xarch_x86_64 -m3dnow -Xarch_x86_64 -msse
- } else {
- sse3dnow_compiler.commands += -m3dnow -msse
- }
-
- sse3dnow_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
- sse3dnow_compiler.dependency_type = TYPE_C
- sse3dnow_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
- sse3dnow_compiler.input = SSE3DNOW_SOURCES
- sse3dnow_compiler.variable_out = OBJECTS
- sse3dnow_compiler.name = compiling[sse3dnow] ${QMAKE_FILE_IN}
- silent:sse3dnow_compiler.commands = @echo compiling[sse3dnow] ${QMAKE_FILE_IN} && $$sse3dnow_compiler.commands
- QMAKE_EXTRA_COMPILERS += sse3dnow_compiler
- }
- }
- sse {
- sse_compiler.commands = $$QMAKE_CXX -c -Winline
-
- mac {
- sse_compiler.commands += -Xarch_i386 -msse
- sse_compiler.commands += -Xarch_x86_64 -msse
- } else {
- sse_compiler.commands += -msse
- }
-
- sse_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
- sse_compiler.dependency_type = TYPE_C
- sse_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
- sse_compiler.input = SSE_SOURCES
- sse_compiler.variable_out = OBJECTS
- sse_compiler.name = compiling[sse] ${QMAKE_FILE_IN}
- silent:sse_compiler.commands = @echo compiling[sse] ${QMAKE_FILE_IN} && $$sse_compiler.commands
- QMAKE_EXTRA_COMPILERS += sse_compiler
- }
- sse2 {
- sse2_compiler.commands = $$QMAKE_CXX -c -Winline
-
- mac {
- sse2_compiler.commands += -Xarch_i386 -msse2
- sse2_compiler.commands += -Xarch_x86_64 -msse2
- } else {
- sse2_compiler.commands += -msse2
- }
-
- sse2_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
- sse2_compiler.dependency_type = TYPE_C
- sse2_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
- sse2_compiler.input = SSE2_SOURCES
- sse2_compiler.variable_out = OBJECTS
- sse2_compiler.name = compiling[sse2] ${QMAKE_FILE_IN}
- silent:sse2_compiler.commands = @echo compiling[sse2] ${QMAKE_FILE_IN} && $$sse2_compiler.commands
- QMAKE_EXTRA_COMPILERS += sse2_compiler
- }
- iwmmxt {
- iwmmxt_compiler.commands = $$QMAKE_CXX -c -Winline
- iwmmxt_compiler.commands += -mcpu=iwmmxt
- iwmmxt_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
- iwmmxt_compiler.dependency_type = TYPE_C
- iwmmxt_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
- iwmmxt_compiler.input = IWMMXT_SOURCES
- iwmmxt_compiler.variable_out = OBJECTS
- iwmmxt_compiler.name = compiling[iwmmxt] ${QMAKE_FILE_IN}
- silent:iwmmxt_compiler.commands = @echo compiling[iwmmxt] ${QMAKE_FILE_IN} && $$iwmmxt_compiler.commands
- QMAKE_EXTRA_COMPILERS += iwmmxt_compiler
- }
- } else {
- mmx: SOURCES += $$MMX_SOURCES
- 3dnow: SOURCES += $$MMX3DNOW_SOURCES
- 3dnow:sse: SOURCES += $$SSE3DNOW_SOURCES
- sse: SOURCES += $$SSE_SOURCES
- sse2: SOURCES += $$SSE2_SOURCES
- iwmmxt: SOURCES += $$IWMMXT_SOURCES
- }
+ painting/qdrawhelper_sse_p.h \
+ painting/qdrawingprimitive_sse2_p.h
+ MMX_SOURCES += painting/qdrawhelper_mmx.cpp
+ MMX3DNOW_SOURCES += painting/qdrawhelper_mmx3dnow.cpp
+ SSE3DNOW_SOURCES += painting/qdrawhelper_sse3dnow.cpp
+ SSE_SOURCES += painting/qdrawhelper_sse.cpp
+ SSE2_SOURCES += painting/qdrawhelper_sse2.cpp
+ IWMMXT_SOURCES += painting/qdrawhelper_iwmmxt.cpp
}
x11 {
@@ -402,11 +265,4 @@ neon:*-g++* {
QMAKE_EXTRA_COMPILERS += neon_compiler
}
-contains(QT_CONFIG, zlib) {
- INCLUDEPATH += ../3rdparty/zlib
-} else:!contains(QT_CONFIG, no-zlib) {
- symbian:LIBS_PRIVATE += -llibz
- else:if(unix|win32-g++*):LIBS_PRIVATE += -lz
- else:LIBS += zdll.lib
-}
-
+include($$PWD/../../3rdparty/zlib_dependency.pri)
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 5727b3c..ca9556b 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -5014,7 +5014,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *
length -= copy_image_width;
copy_image_width *= 2;
}
- qt_memconvert(dest, src, length);
+ if (length > 0)
+ qt_memconvert(dest, src, length);
} else {
while (length) {
int l = qMin(image_width - sx, length);
@@ -7901,6 +7902,9 @@ void qInitDrawhelperAsm()
functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon;
destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
+
+ qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
+ qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
}
#endif
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index 3ce90d2..03fe075 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -622,6 +622,150 @@ void QT_FASTCALL comp_func_solid_SourceOver_neon(uint *destPixels, int length, u
}
}
+static const int tileSize = 32;
+
+extern "C" void qt_rotate90_16_neon(quint16 *dst, const quint16 *src, int sstride, int dstride, int count);
+
+void qt_memrotate90_16_neon(const uchar *srcPixels, int w, int h, int sstride, uchar *destPixels, int dstride)
+{
+ const ushort *src = (const ushort *)srcPixels;
+ ushort *dest = (ushort *)destPixels;
+
+ sstride /= sizeof(ushort);
+ dstride /= sizeof(ushort);
+
+ const int pack = sizeof(quint32) / sizeof(ushort);
+ const int unaligned =
+ qMin(uint((quintptr(dest) & (sizeof(quint32)-1)) / sizeof(ushort)), uint(h));
+ const int restX = w % tileSize;
+ const int restY = (h - unaligned) % tileSize;
+ const int unoptimizedY = restY % pack;
+ const int numTilesX = w / tileSize + (restX > 0);
+ const int numTilesY = (h - unaligned) / tileSize + (restY >= pack);
+
+ for (int tx = 0; tx < numTilesX; ++tx) {
+ const int startx = w - tx * tileSize - 1;
+ const int stopx = qMax(startx - tileSize, 0);
+
+ if (unaligned) {
+ for (int x = startx; x >= stopx; --x) {
+ ushort *d = dest + (w - x - 1) * dstride;
+ for (int y = 0; y < unaligned; ++y) {
+ *d++ = src[y * sstride + x];
+ }
+ }
+ }
+
+ for (int ty = 0; ty < numTilesY; ++ty) {
+ const int starty = ty * tileSize + unaligned;
+ const int stopy = qMin(starty + tileSize, h - unoptimizedY);
+
+ int x = startx;
+ // qt_rotate90_16_neon writes to eight rows, four pixels at a time
+ for (; x >= stopx + 7; x -= 8) {
+ ushort *d = dest + (w - x - 1) * dstride + starty;
+ const ushort *s = &src[starty * sstride + x - 7];
+ qt_rotate90_16_neon(d, s, sstride * 2, dstride * 2, stopy - starty);
+ }
+
+ for (; x >= stopx; --x) {
+ quint32 *d = reinterpret_cast<quint32*>(dest + (w - x - 1) * dstride + starty);
+ for (int y = starty; y < stopy; y += pack) {
+ quint32 c = src[y * sstride + x];
+ for (int i = 1; i < pack; ++i) {
+ const int shift = (sizeof(int) * 8 / pack * i);
+ const ushort color = src[(y + i) * sstride + x];
+ c |= color << shift;
+ }
+ *d++ = c;
+ }
+ }
+ }
+
+ if (unoptimizedY) {
+ const int starty = h - unoptimizedY;
+ for (int x = startx; x >= stopx; --x) {
+ ushort *d = dest + (w - x - 1) * dstride + starty;
+ for (int y = starty; y < h; ++y) {
+ *d++ = src[y * sstride + x];
+ }
+ }
+ }
+ }
+}
+
+extern "C" void qt_rotate270_16_neon(quint16 *dst, const quint16 *src, int sstride, int dstride, int count);
+
+void qt_memrotate270_16_neon(const uchar *srcPixels, int w, int h,
+ int sstride,
+ uchar *destPixels, int dstride)
+{
+ const ushort *src = (const ushort *)srcPixels;
+ ushort *dest = (ushort *)destPixels;
+
+ sstride /= sizeof(ushort);
+ dstride /= sizeof(ushort);
+
+ const int pack = sizeof(quint32) / sizeof(ushort);
+ const int unaligned =
+ qMin(uint((long(dest) & (sizeof(quint32)-1)) / sizeof(ushort)), uint(h));
+ const int restX = w % tileSize;
+ const int restY = (h - unaligned) % tileSize;
+ const int unoptimizedY = restY % pack;
+ const int numTilesX = w / tileSize + (restX > 0);
+ const int numTilesY = (h - unaligned) / tileSize + (restY >= pack);
+
+ for (int tx = 0; tx < numTilesX; ++tx) {
+ const int startx = tx * tileSize;
+ const int stopx = qMin(startx + tileSize, w);
+
+ if (unaligned) {
+ for (int x = startx; x < stopx; ++x) {
+ ushort *d = dest + x * dstride;
+ for (int y = h - 1; y >= h - unaligned; --y) {
+ *d++ = src[y * sstride + x];
+ }
+ }
+ }
+
+ for (int ty = 0; ty < numTilesY; ++ty) {
+ const int starty = h - 1 - unaligned - ty * tileSize;
+ const int stopy = qMax(starty - tileSize, unoptimizedY);
+
+ int x = startx;
+ // qt_rotate90_16_neon writes to eight rows, four pixels at a time
+ for (; x < stopx - 7; x += 8) {
+ ushort *d = dest + x * dstride + h - 1 - starty;
+ const ushort *s = &src[starty * sstride + x];
+ qt_rotate90_16_neon(d + 7 * dstride, s, -sstride * 2, -dstride * 2, starty - stopy);
+ }
+
+ for (; x < stopx; ++x) {
+ quint32 *d = reinterpret_cast<quint32*>(dest + x * dstride
+ + h - 1 - starty);
+ for (int y = starty; y > stopy; y -= pack) {
+ quint32 c = src[y * sstride + x];
+ for (int i = 1; i < pack; ++i) {
+ const int shift = (sizeof(int) * 8 / pack * i);
+ const ushort color = src[(y - i) * sstride + x];
+ c |= color << shift;
+ }
+ *d++ = c;
+ }
+ }
+ }
+ if (unoptimizedY) {
+ const int starty = unoptimizedY - 1;
+ for (int x = startx; x < stopx; ++x) {
+ ushort *d = dest + x * dstride + h - 1 - starty;
+ for (int y = starty; y >= 0; --y) {
+ *d++ = src[y * sstride + x];
+ }
+ }
+ }
+ }
+}
+
QT_END_NAMESPACE
#endif // QT_HAVE_NEON
diff --git a/src/gui/painting/qdrawhelper_neon_asm.S b/src/gui/painting/qdrawhelper_neon_asm.S
index 9992817..d9cdc36 100644
--- a/src/gui/painting/qdrawhelper_neon_asm.S
+++ b/src/gui/painting/qdrawhelper_neon_asm.S
@@ -190,3 +190,108 @@ blend_8_pixels_rgb16_on_rgb16_neon:
bx lr
.endfunc
+
+/* void qt_rotate90_16_neon(quint16 *dst, const quint16 *src, int sstride, int dstride, int count) */
+ .func qt_rotate90_16_neon
+ .global qt_rotate90_16_neon
+ /* For ELF format also set function visibility to hidden */
+#ifdef __ELF__
+ .hidden qt_rotate90_16_neon
+ .type qt_rotate90_16_neon, %function
+#endif
+qt_rotate90_16_neon:
+ push { r4-r11, lr }
+ ldr r5, [sp, #(9*4)]
+
+ /* The preloads are the key to getting good performance */
+ pld [r1]
+
+ mov r4, r5, asr #2
+ add r6, r0, r3
+ add r7, r6, r3
+
+ add r8, r7, r3
+ add r9, r8, r3
+
+ pld [r1, r2]
+
+ add r10, r9, r3
+ add r11, r10, r3
+
+ add r3, r3, r11
+ and r5, r5, #3
+
+ pld [r1, r2, lsl #1]
+
+ cmp r4, #0
+ beq .rotate90_16_tail
+
+.rotate90_16_loop:
+ vld1.16 { q8 }, [r1], r2
+
+ pld [r1, r2, lsl #1]
+
+ vld1.16 { q9 }, [r1], r2
+ vld1.16 { q10 }, [r1], r2
+ vld1.16 { q11 }, [r1], r2
+
+ pld [r1]
+
+ /* Could have used four quad-word zips instead,
+ but those take three cycles as opposed to one. */
+ vzip.16 d16, d20
+ vzip.16 d17, d21
+
+ vzip.16 d18, d22
+
+ pld [r1, r2]
+
+ vzip.16 d19, d23
+
+ vzip.16 d16, d18
+ vzip.16 d17, d19
+
+ pld [r1, r2, lsl #1]
+
+ vzip.16 d20, d22
+ vzip.16 d21, d23
+
+ vst1.16 { d23 }, [r0]!
+ vst1.16 { d21 }, [r6]!
+ vst1.16 { d19 }, [r7]!
+ vst1.16 { d17 }, [r8]!
+ vst1.16 { d22 }, [r9]!
+ vst1.16 { d20 }, [r10]!
+ vst1.16 { d18 }, [r11]!
+ vst1.16 { d16 }, [r3]!
+
+ sub r4, r4, #1
+ cmp r4, #0
+ bne .rotate90_16_loop
+ b .rotate90_16_tail
+
+.rotate90_16_tail_loop:
+ sub r5, r5, #2
+
+ vld1.16 { q8 }, [r1], r2
+ vld1.16 { q9 }, [r1], r2
+
+ vzip.16 d16, d18
+ vzip.16 d17, d19
+
+ vst1.32 { d19[1] }, [r0]!
+ vst1.32 { d19[0] }, [r6]!
+ vst1.32 { d17[1] }, [r7]!
+ vst1.32 { d17[0] }, [r8]!
+ vst1.32 { d18[1] }, [r9]!
+ vst1.32 { d18[0] }, [r10]!
+ vst1.32 { d16[1] }, [r11]!
+ vst1.32 { d16[0] }, [r3]!
+
+.rotate90_16_tail:
+ cmp r5, #0
+ bgt .rotate90_16_tail_loop
+
+ pop { r4-r11, pc }
+
+ .endfunc
diff --git a/src/gui/painting/qdrawhelper_neon_p.h b/src/gui/painting/qdrawhelper_neon_p.h
index c054a1e..cd2dbfc 100644
--- a/src/gui/painting/qdrawhelper_neon_p.h
+++ b/src/gui/painting/qdrawhelper_neon_p.h
@@ -120,6 +120,9 @@ void qt_transform_image_rgb16_on_rgb16_neon(uchar *destPixels, int dbpl,
const QTransform &targetRectTransform,
int const_alpha);
+void qt_memrotate90_16_neon(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl);
+void qt_memrotate270_16_neon(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl);
+
uint * QT_FASTCALL qt_destFetchRGB16_neon(uint *buffer,
QRasterBuffer *rasterBuffer,
int x, int y, int length);
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index acf765c..97c78bb 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -152,6 +152,7 @@ typedef void (*SrcOverTransformFunc)(uchar *destPixels, int dbpl,
const QTransform &targetRectTransform,
int const_alpha);
+typedef void (*MemRotateFunc)(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl);
struct DrawHelper {
ProcessSpans blendColor;
@@ -165,6 +166,7 @@ struct DrawHelper {
extern SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats];
extern SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats];
extern SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats];
+extern MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3];
extern DrawHelper qDrawHelper[QImage::NImageFormats];
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index 6cd8688..346e177 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -43,176 +43,12 @@
#ifdef QT_HAVE_SSE2
+#include <private/qsimd_p.h>
+#include <private/qdrawingprimitive_sse2_p.h>
#include <private/qpaintengine_raster_p.h>
-#ifdef QT_LINUXBASE
-// this is an evil hack - the posix_memalign declaration in LSB
-// is wrong - see http://bugs.linuxbase.org/show_bug.cgi?id=2431
-# define posix_memalign _lsb_hack_posix_memalign
-# include <emmintrin.h>
-# undef posix_memalign
-#else
-# include <emmintrin.h>
-#endif
-
QT_BEGIN_NAMESPACE
-/*
- * Multiply the components of pixelVector by alphaChannel
- * Each 32bits components of alphaChannel must be in the form 0x00AA00AA
- * colorMask must have 0x00ff00ff on each 32 bits component
- * half must have the value 128 (0x80) for each 32 bits compnent
- */
-#define BYTE_MUL_SSE2(result, pixelVector, alphaChannel, colorMask, half) \
-{ \
- /* 1. separate the colors in 2 vectors so each color is on 16 bits \
- (in order to be multiplied by the alpha \
- each 32 bit of dstVectorAG are in the form 0x00AA00GG \
- each 32 bit of dstVectorRB are in the form 0x00RR00BB */\
- __m128i pixelVectorAG = _mm_srli_epi16(pixelVector, 8); \
- __m128i pixelVectorRB = _mm_and_si128(pixelVector, colorMask); \
- \
- /* 2. multiply the vectors by the alpha channel */\
- pixelVectorAG = _mm_mullo_epi16(pixelVectorAG, alphaChannel); \
- pixelVectorRB = _mm_mullo_epi16(pixelVectorRB, alphaChannel); \
- \
- /* 3. devide by 255, that's the tricky part. \
- we do it like for BYTE_MUL(), with bit shift: X/255 ~= (X + X/256 + rounding)/256 */ \
- /** so first (X + X/256 + rounding) */\
- pixelVectorRB = _mm_add_epi16(pixelVectorRB, _mm_srli_epi16(pixelVectorRB, 8)); \
- pixelVectorRB = _mm_add_epi16(pixelVectorRB, half); \
- pixelVectorAG = _mm_add_epi16(pixelVectorAG, _mm_srli_epi16(pixelVectorAG, 8)); \
- pixelVectorAG = _mm_add_epi16(pixelVectorAG, half); \
- \
- /** second devide by 256 */\
- pixelVectorRB = _mm_srli_epi16(pixelVectorRB, 8); \
- /** for AG, we could >> 8 to divide followed by << 8 to put the \
- bytes in the correct position. By masking instead, we execute \
- only one instruction */\
- pixelVectorAG = _mm_andnot_si128(colorMask, pixelVectorAG); \
- \
- /* 4. combine the 2 pairs of colors */ \
- result = _mm_or_si128(pixelVectorAG, pixelVectorRB); \
-}
-
-/*
- * Each 32bits components of alphaChannel must be in the form 0x00AA00AA
- * oneMinusAlphaChannel must be 255 - alpha for each 32 bits component
- * colorMask must have 0x00ff00ff on each 32 bits component
- * half must have the value 128 (0x80) for each 32 bits compnent
- */
-#define INTERPOLATE_PIXEL_255_SSE2(result, srcVector, dstVector, alphaChannel, oneMinusAlphaChannel, colorMask, half) { \
- /* interpolate AG */\
- __m128i srcVectorAG = _mm_srli_epi16(srcVector, 8); \
- __m128i dstVectorAG = _mm_srli_epi16(dstVector, 8); \
- __m128i srcVectorAGalpha = _mm_mullo_epi16(srcVectorAG, alphaChannel); \
- __m128i dstVectorAGoneMinusAlphalpha = _mm_mullo_epi16(dstVectorAG, oneMinusAlphaChannel); \
- __m128i finalAG = _mm_add_epi16(srcVectorAGalpha, dstVectorAGoneMinusAlphalpha); \
- finalAG = _mm_add_epi16(finalAG, _mm_srli_epi16(finalAG, 8)); \
- finalAG = _mm_add_epi16(finalAG, half); \
- finalAG = _mm_andnot_si128(colorMask, finalAG); \
- \
- /* interpolate RB */\
- __m128i srcVectorRB = _mm_and_si128(srcVector, colorMask); \
- __m128i dstVectorRB = _mm_and_si128(dstVector, colorMask); \
- __m128i srcVectorRBalpha = _mm_mullo_epi16(srcVectorRB, alphaChannel); \
- __m128i dstVectorRBoneMinusAlphalpha = _mm_mullo_epi16(dstVectorRB, oneMinusAlphaChannel); \
- __m128i finalRB = _mm_add_epi16(srcVectorRBalpha, dstVectorRBoneMinusAlphalpha); \
- finalRB = _mm_add_epi16(finalRB, _mm_srli_epi16(finalRB, 8)); \
- finalRB = _mm_add_epi16(finalRB, half); \
- finalRB = _mm_srli_epi16(finalRB, 8); \
- \
- /* combine */\
- result = _mm_or_si128(finalAG, finalRB); \
-}
-
-// Basically blend src over dst with the const alpha defined as constAlphaVector.
-// nullVector, half, one, colorMask are constant accross the whole image/texture, and should be defined as:
-//const __m128i nullVector = _mm_set1_epi32(0);
-//const __m128i half = _mm_set1_epi16(0x80);
-//const __m128i one = _mm_set1_epi16(0xff);
-//const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
-//const __m128i alphaMask = _mm_set1_epi32(0xff000000);
-//
-// The computation being done is:
-// result = s + d * (1-alpha)
-// with shortcuts if fully opaque or fully transparent.
-#define BLEND_SOURCE_OVER_ARGB32_SSE2(dst, src, length, nullVector, half, one, colorMask, alphaMask) { \
- int x = 0; \
- for (; x < length-3; x += 4) { \
- const __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]); \
- const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask); \
- if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) { \
- /* all opaque */ \
- _mm_storeu_si128((__m128i *)&dst[x], srcVector); \
- } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) { \
- /* not fully transparent */ \
- /* extract the alpha channel on 2 x 16 bits */ \
- /* so we have room for the multiplication */ \
- /* each 32 bits will be in the form 0x00AA00AA */ \
- /* with A being the 1 - alpha */ \
- __m128i alphaChannel = _mm_srli_epi32(srcVector, 24); \
- alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16)); \
- alphaChannel = _mm_sub_epi16(one, alphaChannel); \
- \
- const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]); \
- __m128i destMultipliedByOneMinusAlpha; \
- BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
- \
- /* result = s + d * (1-alpha) */\
- const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
- _mm_storeu_si128((__m128i *)&dst[x], result); \
- } \
- } \
- for (; x < length; ++x) { \
- uint s = src[x]; \
- if (s >= 0xff000000) \
- dst[x] = s; \
- else if (s != 0) \
- dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); \
- } \
-}
-
-// Basically blend src over dst with the const alpha defined as constAlphaVector.
-// nullVector, half, one, colorMask are constant accross the whole image/texture, and should be defined as:
-//const __m128i nullVector = _mm_set1_epi32(0);
-//const __m128i half = _mm_set1_epi16(0x80);
-//const __m128i one = _mm_set1_epi16(0xff);
-//const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
-//
-// The computation being done is:
-// dest = (s + d * sia) * ca + d * cia
-// = s * ca + d * (sia * ca + cia)
-// = s * ca + d * (1 - sa*ca)
-#define BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_SSE2(dst, src, length, nullVector, half, one, colorMask, constAlphaVector) \
-{ \
- int x = 0; \
- for (; x < length-3; x += 4) { \
- __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]); \
- if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVector, nullVector)) != 0xffff) { \
- BYTE_MUL_SSE2(srcVector, srcVector, constAlphaVector, colorMask, half); \
-\
- __m128i alphaChannel = _mm_srli_epi32(srcVector, 24); \
- alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16)); \
- alphaChannel = _mm_sub_epi16(one, alphaChannel); \
- \
- const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]); \
- __m128i destMultipliedByOneMinusAlpha; \
- BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
- \
- const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
- _mm_storeu_si128((__m128i *)&dst[x], result); \
- } \
- } \
- for (; x < length; ++x) { \
- quint32 s = src[x]; \
- if (s != 0) { \
- s = BYTE_MUL(s, const_alpha); \
- dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); \
- } \
- } \
-}
-
void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
const uchar *srcPixels, int sbpl,
int w, int h,
diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h
new file mode 100644
index 0000000..3c96946
--- /dev/null
+++ b/src/gui/painting/qdrawingprimitive_sse2_p.h
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 QDRAWINGPRIMITIVE_SSE2_P_H
+#define QDRAWINGPRIMITIVE_SSE2_P_H
+
+#include <private/qsimd_p.h>
+
+#ifdef QT_HAVE_SSE2
+
+//
+// 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.
+//
+
+QT_BEGIN_NAMESPACE
+
+/*
+ * Multiply the components of pixelVector by alphaChannel
+ * Each 32bits components of alphaChannel must be in the form 0x00AA00AA
+ * colorMask must have 0x00ff00ff on each 32 bits component
+ * half must have the value 128 (0x80) for each 32 bits compnent
+ */
+#define BYTE_MUL_SSE2(result, pixelVector, alphaChannel, colorMask, half) \
+{ \
+ /* 1. separate the colors in 2 vectors so each color is on 16 bits \
+ (in order to be multiplied by the alpha \
+ each 32 bit of dstVectorAG are in the form 0x00AA00GG \
+ each 32 bit of dstVectorRB are in the form 0x00RR00BB */\
+ __m128i pixelVectorAG = _mm_srli_epi16(pixelVector, 8); \
+ __m128i pixelVectorRB = _mm_and_si128(pixelVector, colorMask); \
+ \
+ /* 2. multiply the vectors by the alpha channel */\
+ pixelVectorAG = _mm_mullo_epi16(pixelVectorAG, alphaChannel); \
+ pixelVectorRB = _mm_mullo_epi16(pixelVectorRB, alphaChannel); \
+ \
+ /* 3. devide by 255, that's the tricky part. \
+ we do it like for BYTE_MUL(), with bit shift: X/255 ~= (X + X/256 + rounding)/256 */ \
+ /** so first (X + X/256 + rounding) */\
+ pixelVectorRB = _mm_add_epi16(pixelVectorRB, _mm_srli_epi16(pixelVectorRB, 8)); \
+ pixelVectorRB = _mm_add_epi16(pixelVectorRB, half); \
+ pixelVectorAG = _mm_add_epi16(pixelVectorAG, _mm_srli_epi16(pixelVectorAG, 8)); \
+ pixelVectorAG = _mm_add_epi16(pixelVectorAG, half); \
+ \
+ /** second devide by 256 */\
+ pixelVectorRB = _mm_srli_epi16(pixelVectorRB, 8); \
+ /** for AG, we could >> 8 to divide followed by << 8 to put the \
+ bytes in the correct position. By masking instead, we execute \
+ only one instruction */\
+ pixelVectorAG = _mm_andnot_si128(colorMask, pixelVectorAG); \
+ \
+ /* 4. combine the 2 pairs of colors */ \
+ result = _mm_or_si128(pixelVectorAG, pixelVectorRB); \
+}
+
+/*
+ * Each 32bits components of alphaChannel must be in the form 0x00AA00AA
+ * oneMinusAlphaChannel must be 255 - alpha for each 32 bits component
+ * colorMask must have 0x00ff00ff on each 32 bits component
+ * half must have the value 128 (0x80) for each 32 bits compnent
+ */
+#define INTERPOLATE_PIXEL_255_SSE2(result, srcVector, dstVector, alphaChannel, oneMinusAlphaChannel, colorMask, half) { \
+ /* interpolate AG */\
+ __m128i srcVectorAG = _mm_srli_epi16(srcVector, 8); \
+ __m128i dstVectorAG = _mm_srli_epi16(dstVector, 8); \
+ __m128i srcVectorAGalpha = _mm_mullo_epi16(srcVectorAG, alphaChannel); \
+ __m128i dstVectorAGoneMinusAlphalpha = _mm_mullo_epi16(dstVectorAG, oneMinusAlphaChannel); \
+ __m128i finalAG = _mm_add_epi16(srcVectorAGalpha, dstVectorAGoneMinusAlphalpha); \
+ finalAG = _mm_add_epi16(finalAG, _mm_srli_epi16(finalAG, 8)); \
+ finalAG = _mm_add_epi16(finalAG, half); \
+ finalAG = _mm_andnot_si128(colorMask, finalAG); \
+ \
+ /* interpolate RB */\
+ __m128i srcVectorRB = _mm_and_si128(srcVector, colorMask); \
+ __m128i dstVectorRB = _mm_and_si128(dstVector, colorMask); \
+ __m128i srcVectorRBalpha = _mm_mullo_epi16(srcVectorRB, alphaChannel); \
+ __m128i dstVectorRBoneMinusAlphalpha = _mm_mullo_epi16(dstVectorRB, oneMinusAlphaChannel); \
+ __m128i finalRB = _mm_add_epi16(srcVectorRBalpha, dstVectorRBoneMinusAlphalpha); \
+ finalRB = _mm_add_epi16(finalRB, _mm_srli_epi16(finalRB, 8)); \
+ finalRB = _mm_add_epi16(finalRB, half); \
+ finalRB = _mm_srli_epi16(finalRB, 8); \
+ \
+ /* combine */\
+ result = _mm_or_si128(finalAG, finalRB); \
+}
+
+// Basically blend src over dst with the const alpha defined as constAlphaVector.
+// nullVector, half, one, colorMask are constant accross the whole image/texture, and should be defined as:
+//const __m128i nullVector = _mm_set1_epi32(0);
+//const __m128i half = _mm_set1_epi16(0x80);
+//const __m128i one = _mm_set1_epi16(0xff);
+//const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+//const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+//
+// The computation being done is:
+// result = s + d * (1-alpha)
+// with shortcuts if fully opaque or fully transparent.
+#define BLEND_SOURCE_OVER_ARGB32_SSE2(dst, src, length, nullVector, half, one, colorMask, alphaMask) { \
+ int x = 0; \
+ for (; x < length-3; x += 4) { \
+ const __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]); \
+ const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask); \
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) { \
+ /* all opaque */ \
+ _mm_storeu_si128((__m128i *)&dst[x], srcVector); \
+ } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) { \
+ /* not fully transparent */ \
+ /* extract the alpha channel on 2 x 16 bits */ \
+ /* so we have room for the multiplication */ \
+ /* each 32 bits will be in the form 0x00AA00AA */ \
+ /* with A being the 1 - alpha */ \
+ __m128i alphaChannel = _mm_srli_epi32(srcVector, 24); \
+ alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16)); \
+ alphaChannel = _mm_sub_epi16(one, alphaChannel); \
+ \
+ const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]); \
+ __m128i destMultipliedByOneMinusAlpha; \
+ BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
+ \
+ /* result = s + d * (1-alpha) */\
+ const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
+ _mm_storeu_si128((__m128i *)&dst[x], result); \
+ } \
+ } \
+ for (; x < length; ++x) { \
+ uint s = src[x]; \
+ if (s >= 0xff000000) \
+ dst[x] = s; \
+ else if (s != 0) \
+ dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); \
+ } \
+}
+
+// Basically blend src over dst with the const alpha defined as constAlphaVector.
+// nullVector, half, one, colorMask are constant accross the whole image/texture, and should be defined as:
+//const __m128i nullVector = _mm_set1_epi32(0);
+//const __m128i half = _mm_set1_epi16(0x80);
+//const __m128i one = _mm_set1_epi16(0xff);
+//const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+//
+// The computation being done is:
+// dest = (s + d * sia) * ca + d * cia
+// = s * ca + d * (sia * ca + cia)
+// = s * ca + d * (1 - sa*ca)
+#define BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_SSE2(dst, src, length, nullVector, half, one, colorMask, constAlphaVector) \
+{ \
+ int x = 0; \
+ for (; x < length-3; x += 4) { \
+ __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]); \
+ if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVector, nullVector)) != 0xffff) { \
+ BYTE_MUL_SSE2(srcVector, srcVector, constAlphaVector, colorMask, half); \
+\
+ __m128i alphaChannel = _mm_srli_epi32(srcVector, 24); \
+ alphaChannel = _mm_or_si128(alphaChannel, _mm_slli_epi32(alphaChannel, 16)); \
+ alphaChannel = _mm_sub_epi16(one, alphaChannel); \
+ \
+ const __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]); \
+ __m128i destMultipliedByOneMinusAlpha; \
+ BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
+ \
+ const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
+ _mm_storeu_si128((__m128i *)&dst[x], result); \
+ } \
+ } \
+ for (; x < length; ++x) { \
+ quint32 s = src[x]; \
+ if (s != 0) { \
+ s = BYTE_MUL(s, const_alpha); \
+ dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); \
+ } \
+ } \
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_HAVE_SSE2
+
+#endif // QDRAWINGPRIMITIVE_SSE2_P_H
diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp
index 69ce47e..f06e309 100644
--- a/src/gui/painting/qgraphicssystem.cpp
+++ b/src/gui/painting/qgraphicssystem.cpp
@@ -50,7 +50,7 @@
#ifdef Q_WS_MAC
# include <private/qpixmap_mac_p.h>
#endif
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
# include <private/qpixmap_s60_p.h>
#endif
@@ -71,7 +71,7 @@ QPixmapData *QGraphicsSystem::createDefaultPixmapData(QPixmapData::PixelType typ
return new QRasterPixmapData(type);
#elif defined(Q_WS_MAC)
return new QMacPixmapData(type);
-#elif defined(Q_WS_S60)
+#elif defined(Q_OS_SYMBIAN)
return new QS60PixmapData(type);
#elif !defined(Q_WS_QWS)
#error QGraphicsSystem::createDefaultPixmapData() not implemented
diff --git a/src/gui/painting/qgraphicssystem_runtime.cpp b/src/gui/painting/qgraphicssystem_runtime.cpp
index 1c3ae10..3438137 100644
--- a/src/gui/painting/qgraphicssystem_runtime.cpp
+++ b/src/gui/painting/qgraphicssystem_runtime.cpp
@@ -418,7 +418,7 @@ void QRuntimeGraphicsSystem::setGraphicsSystem(const QString &name)
QRuntimePixmapData *proxy = m_pixmapDatas.at(i);
QPixmapData *newData = m_graphicsSystem->createPixmapData(proxy->m_data);
// ### TODO Optimize. Openvg and s60raster graphics systems could switch internal ARGB32_PRE QImage buffers.
- newData->fromImage(proxy->m_data->toImage(), Qt::AutoColor | Qt::OrderedAlphaDither);
+ newData->fromImage(proxy->m_data->toImage(), Qt::NoOpaqueDetection);
delete proxy->m_data;
proxy->m_data = newData;
proxy->readBackInfo();
diff --git a/src/gui/painting/qgraphicssystem_runtime_p.h b/src/gui/painting/qgraphicssystem_runtime_p.h
index 101a8e7..7aab89c 100644
--- a/src/gui/painting/qgraphicssystem_runtime_p.h
+++ b/src/gui/painting/qgraphicssystem_runtime_p.h
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
class QRuntimeGraphicsSystem;
-class QRuntimePixmapData : public QPixmapData {
+class Q_GUI_EXPORT QRuntimePixmapData : public QPixmapData {
public:
QRuntimePixmapData(const QRuntimeGraphicsSystem *gs, PixelType type);
~QRuntimePixmapData();
diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp
index c37aa51..6888bb0 100644
--- a/src/gui/painting/qmemrotate.cpp
+++ b/src/gui/painting/qmemrotate.cpp
@@ -594,4 +594,55 @@ void Q_GUI_EXPORT qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHei
qt_memrotate90_template(src, srcWidth, srcHeight, srcStride, reinterpret_cast<qrgb_gl_rgba *>(dest), dstStride);
}
+void qt_memrotate90_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate90((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
+}
+
+void qt_memrotate180_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate180((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
+}
+
+void qt_memrotate270_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate270((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
+}
+
+void qt_memrotate90_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate90((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
+}
+
+void qt_memrotate180_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate180((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
+}
+
+void qt_memrotate270_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate270((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
+}
+
+MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3] =
+// 90, 180, 270
+{
+ { 0, 0, 0 }, // Format_Invalid,
+ { 0, 0, 0 }, // Format_Mono,
+ { 0, 0, 0 }, // Format_MonoLSB,
+ { 0, 0, 0 }, // Format_Indexed8,
+ { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGB32,
+ { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_ARGB32,
+ { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_ARGB32_Premultiplied,
+ { qt_memrotate90_16, qt_memrotate180_16, qt_memrotate270_16 }, // Format_RGB16,
+ { 0, 0, 0 }, // Format_ARGB8565_Premultiplied,
+ { 0, 0, 0 }, // Format_RGB666,
+ { 0, 0, 0 }, // Format_ARGB6666_Premultiplied,
+ { 0, 0, 0 }, // Format_RGB555,
+ { 0, 0, 0 }, // Format_ARGB8555_Premultiplied,
+ { 0, 0, 0 }, // Format_RGB888,
+ { 0, 0, 0 }, // Format_RGB444,
+ { 0, 0, 0 } // Format_ARGB4444_Premultiplied,
+};
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 84b36c7..09a87aa 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -2553,23 +2553,6 @@ namespace {
return NoRotation;
}
- template <typename T> void memRotate(RotationType type, const T *srcBase, int w, int h, int sbpl, T *dstBase, int dbpl)
- {
- switch (type) {
- case Rotation90:
- qt_memrotate90(srcBase, w, h, sbpl, dstBase, dbpl);
- break;
- case Rotation180:
- qt_memrotate180(srcBase, w, h, sbpl, dstBase, dbpl);
- break;
- case Rotation270:
- qt_memrotate270(srcBase, w, h, sbpl, dstBase, dbpl);
- break;
- case NoRotation:
- break;
- }
- }
-
inline bool isPixelAligned(const QRectF &rect) {
return QRectF(rect.toRect()) == rect;
}
@@ -2650,7 +2633,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
{
RotationType rotationType = qRotationType(s->matrix);
- if (rotationType != NoRotation && img.rect().contains(sr.toAlignedRect())) {
+ if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
QRectF transformedTargetRect = s->matrix.mapRect(r);
if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
@@ -2678,10 +2661,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
uint cw = clippedSourceRect.width();
uint ch = clippedSourceRect.height();
- if (d->rasterBuffer->format == QImage::Format_RGB16)
- memRotate(rotationType, (quint16 *)srcBase, cw, ch, sbpl, (quint16 *)dstBase, dbpl);
- else
- memRotate(rotationType, (quint32 *)srcBase, cw, ch, sbpl, (quint32 *)dstBase, dbpl);
+ qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
return;
}
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 2ea6673..9dadbd5 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -8969,6 +8969,15 @@ void QPainter::drawPixmapFragments(const PixmapFragment *fragments, int fragment
if (!d->engine)
return;
+#ifndef QT_NO_DEBUG
+ for (int i = 0; i < fragmentCount; ++i) {
+ QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
+ fragments[i].width, fragments[i].height);
+ if (!(QRectF(pixmap.rect()).contains(sourceRect)))
+ qWarning("QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
+ }
+#endif
+
if (d->engine->isExtended()) {
d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
} else {
diff --git a/src/gui/s60framework/qs60mainapplication.cpp b/src/gui/s60framework/qs60mainapplication.cpp
index 41ac1a8..0f9367e 100644
--- a/src/gui/s60framework/qs60mainapplication.cpp
+++ b/src/gui/s60framework/qs60mainapplication.cpp
@@ -71,17 +71,17 @@ _LIT(KQtWrapperResourceFile, "\\resource\\apps\\s60main" QT_LIBINFIX_UNICODE L".
The QS60MainApplication provides a helper class for use in migrating
from existing S60 based applications to Qt based applications. It is
- used in the exact same way as the \c CAknApplication class from
+ used in the exact same way as the \c CEikApplication class from
Symbian, but internally provides extensions used by Qt.
When modifying old S60 applications that rely on implementing
- functions in \c CAknApplication, the class should be modified to
- inherit from this class instead of \c CAknApplication. Then the
+ functions in \c CEikApplication, the class should be modified to
+ inherit from this class instead of \c CEikApplication. Then the
application can choose to override only certain functions. To make
Qt use the custom application objects, pass a factory function to
\c{QApplication::QApplication(QApplication::QS60MainApplicationFactory, int &, char **)}.
- For more information on \c CAknApplication, please see the S60 documentation.
+ For more information on \c CEikApplication, please see the S60 documentation.
Unlike other Qt classes, QS60MainApplication behaves like an S60 class, and can throw Symbian
leaves.
@@ -136,4 +136,19 @@ TFileName QS60MainApplication::ResourceFileName() const
return KNullDesC();
}
+void QS60MainApplication::PreDocConstructL()
+{
+ QS60MainApplicationBase::PreDocConstructL();
+}
+
+CDictionaryStore *QS60MainApplication::OpenIniFileLC(RFs &aFs) const
+{
+ return QS60MainApplicationBase::OpenIniFileLC(aFs);
+}
+
+void QS60MainApplication::NewAppServerL(CApaAppServer *&aAppServer)
+{
+ QS60MainApplicationBase::NewAppServerL(aAppServer);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/s60framework/qs60mainapplication.h b/src/gui/s60framework/qs60mainapplication.h
index 997f30f..cb22e68 100644
--- a/src/gui/s60framework/qs60mainapplication.h
+++ b/src/gui/s60framework/qs60mainapplication.h
@@ -44,9 +44,15 @@
#include <QtCore/qglobal.h>
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
+#ifdef Q_WS_S60
#include <aknapp.h>
+typedef CAknApplication QS60MainApplicationBase;
+#else
+#include <eikapp.h>
+typedef CEikApplication QS60MainApplicationBase;
+#endif
QT_BEGIN_HEADER
@@ -54,7 +60,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
-class Q_GUI_EXPORT QS60MainApplication : public CAknApplication
+class Q_GUI_EXPORT QS60MainApplication : public QS60MainApplicationBase
{
public:
QS60MainApplication();
@@ -65,6 +71,14 @@ public:
virtual TFileName ResourceFileName() const;
+public:
+
+ virtual void PreDocConstructL();
+
+ virtual CDictionaryStore *OpenIniFileLC(RFs &aFs) const;
+
+ virtual void NewAppServerL(CApaAppServer *&aAppServer);
+
protected:
virtual CApaDocument *CreateDocumentL();
@@ -74,6 +88,6 @@ QT_END_NAMESPACE
QT_END_HEADER
-#endif // Q_WS_S60
+#endif // Q_OS_SYMBIAN
#endif // QS60MAINAPPLICATION_H
diff --git a/src/gui/s60framework/qs60mainappui.cpp b/src/gui/s60framework/qs60mainappui.cpp
index ce13de8..40c2d03 100644
--- a/src/gui/s60framework/qs60mainappui.cpp
+++ b/src/gui/s60framework/qs60mainappui.cpp
@@ -41,20 +41,25 @@
// INCLUDE FILES
#include <exception>
+#include <qglobal.h>
+#ifdef Q_WS_S60
#include <avkon.hrh>
#include <eikmenub.h>
#include <eikmenup.h>
+#include <avkon.rsg>
+#endif
#include <barsread.h>
#include <qconfig.h>
-#if defined(QT_LIBINFIX_UNQUOTED)
+#ifdef Q_WS_S60
+# if defined(QT_LIBINFIX_UNQUOTED)
// Two level macro needed for proper expansion of libinfix
-# define QT_S60MAIN_RSG_2(x) <s60main##x##.rsg>
-# define QT_S60MAIN_RSG(x) QT_S60MAIN_RSG_2(x)
-# include QT_S60MAIN_RSG(QT_LIBINFIX_UNQUOTED)
-#else
-# include <s60main.rsg>
+# define QT_S60MAIN_RSG_2(x) <s60main##x##.rsg>
+# define QT_S60MAIN_RSG(x) QT_S60MAIN_RSG_2(x)
+# include QT_S60MAIN_RSG(QT_LIBINFIX_UNQUOTED)
+# else
+# include <s60main.rsg>
+# endif
#endif
-#include <avkon.rsg>
#include "qs60mainappui.h"
#include <QtGui/qapplication.h>
@@ -115,14 +120,16 @@ void QS60MainAppUi::ConstructL()
// ENoAppResourceFile and ENonStandardResourceFile makes UI to work without
// resource files in most SDKs. S60 3rd FP1 public seems to require resource file
// even these flags are defined
- TInt flags = CAknAppUi::EAknEnableSkin
- | CAknAppUi::ENoScreenFurniture
- | CAknAppUi::ENonStandardResourceFile;
+ TInt flags = CEikAppUi::ENoScreenFurniture
+ | CEikAppUi::ENonStandardResourceFile;
+#ifdef Q_WS_S60
+ flags |= CAknAppUi::EAknEnableSkin;
// After 5th Edition S60, native side supports animated wallpapers.
// However, there is no support for that feature on Qt side, so indicate to
// native UI framework that this application will not support background animations.
if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0)
flags |= KAknDisableAnimationBackground;
+#endif
BaseConstructL(flags);
}
@@ -168,7 +175,7 @@ void QS60MainAppUi::HandleCommandL(TInt command)
*/
void QS60MainAppUi::HandleResourceChangeL(TInt type)
{
- CAknAppUi::HandleResourceChangeL(type);
+ QS60MainAppUiBase::HandleResourceChangeL(type);
if (qApp) {
QSymbianEvent event(QSymbianEvent::ResourceChangeEvent, type);
@@ -185,7 +192,7 @@ void QS60MainAppUi::HandleResourceChangeL(TInt type)
* If you override this function, you should call the base class implementation if you do not
* handle the event.
*/
-void QS60MainAppUi::HandleWsEventL(const TWsEvent& wsEvent, CCoeControl *destination)
+void QS60MainAppUi::HandleWsEventL(const TWsEvent &wsEvent, CCoeControl *destination)
{
int result = 0;
if (qApp) {
@@ -196,7 +203,7 @@ void QS60MainAppUi::HandleWsEventL(const TWsEvent& wsEvent, CCoeControl *destina
}
if (result <= 0)
- CAknAppUi::HandleWsEventL(wsEvent, destination);
+ QS60MainAppUiBase::HandleWsEventL(wsEvent, destination);
}
@@ -236,6 +243,7 @@ void QS60MainAppUi::DynInitMenuBarL(TInt /* resourceId */, CEikMenuBar * /* menu
*/
void QS60MainAppUi::DynInitMenuPaneL(TInt resourceId, CEikMenuPane *menuPane)
{
+#ifdef Q_WS_S60
if (resourceId == R_QT_WRAPPERAPP_MENU) {
if (menuPane->NumberOfItemsInPane() <= 1)
QT_TRYCATCH_LEAVING(qt_symbian_show_toplevel(menuPane));
@@ -245,6 +253,9 @@ void QS60MainAppUi::DynInitMenuPaneL(TInt resourceId, CEikMenuPane *menuPane)
&& resourceId != R_AVKON_MENUPANE_LANGUAGE_DEFAULT) {
QT_TRYCATCH_LEAVING(qt_symbian_show_submenu(menuPane, resourceId));
}
+#else
+ QS60MainAppUiBase::DynInitMenuPaneL(resourceId, menuPane);
+#endif
}
/*!
@@ -255,16 +266,104 @@ void QS60MainAppUi::DynInitMenuPaneL(TInt resourceId, CEikMenuPane *menuPane)
*
* If you override this function, you should call the base class implementation as well.
*/
-void QS60MainAppUi::RestoreMenuL(CCoeControl* menuWindow, TInt resourceId, TMenuType menuType)
+void QS60MainAppUi::RestoreMenuL(CCoeControl *menuWindow, TInt resourceId, TMenuType menuType)
{
+#ifdef Q_WS_S60
if (resourceId >= QT_SYMBIAN_FIRST_MENU_ITEM && resourceId <= QT_SYMBIAN_LAST_MENU_ITEM) {
if (menuType == EMenuPane)
DynInitMenuPaneL(resourceId, (CEikMenuPane*)menuWindow);
else
DynInitMenuBarL(resourceId, (CEikMenuBar*)menuWindow);
- } else {
- CAknAppUi::RestoreMenuL(menuWindow, resourceId, menuType);
+ } else
+#endif
+ {
+ QS60MainAppUiBase::RestoreMenuL(menuWindow, resourceId, menuType);
}
}
+void QS60MainAppUi::Exit()
+{
+ QS60MainAppUiBase::Exit();
+}
+
+void QS60MainAppUi::SetFadedL(TBool aFaded)
+{
+ QS60MainAppUiBase::SetFadedL(aFaded);
+}
+
+TRect QS60MainAppUi::ApplicationRect() const
+{
+ return QS60MainAppUiBase::ApplicationRect();
+}
+
+void QS60MainAppUi::HandleScreenDeviceChangedL()
+{
+ QS60MainAppUiBase::HandleScreenDeviceChangedL();
+}
+
+void QS60MainAppUi::HandleApplicationSpecificEventL(TInt aType, const TWsEvent &aEvent)
+{
+ QS60MainAppUiBase::HandleApplicationSpecificEventL(aType, aEvent);
+}
+
+TTypeUid::Ptr QS60MainAppUi::MopSupplyObject(TTypeUid aId)
+{
+ return QS60MainAppUiBase::MopSupplyObject(aId);
+}
+
+void QS60MainAppUi::ProcessCommandL(TInt aCommand)
+{
+ QS60MainAppUiBase::ProcessCommandL(aCommand);
+}
+
+TErrorHandlerResponse QS60MainAppUi::HandleError (TInt aError, const SExtendedError &aExtErr, TDes &aErrorText, TDes &aContextText)
+{
+ return QS60MainAppUiBase::HandleError(aError, aExtErr, aErrorText, aContextText);
+}
+
+void QS60MainAppUi::HandleViewDeactivation(const TVwsViewId &aViewIdToBeDeactivated, const TVwsViewId &aNewlyActivatedViewId)
+{
+ QS60MainAppUiBase::HandleViewDeactivation(aViewIdToBeDeactivated, aNewlyActivatedViewId);
+}
+
+void QS60MainAppUi::PrepareToExit()
+{
+ QS60MainAppUiBase::PrepareToExit();
+}
+
+void QS60MainAppUi::HandleTouchPaneSizeChange()
+{
+ QS60MainAppUiBase::HandleTouchPaneSizeChange();
+}
+
+void QS60MainAppUi::HandleSystemEventL(const TWsEvent &aEvent)
+{
+ QS60MainAppUiBase::HandleSystemEventL(aEvent);
+}
+
+void QS60MainAppUi::Reserved_MtsmPosition()
+{
+ QS60MainAppUiBase::Reserved_MtsmPosition();
+}
+
+void QS60MainAppUi::Reserved_MtsmObject()
+{
+ QS60MainAppUiBase::Reserved_MtsmObject();
+}
+
+void QS60MainAppUi::HandleForegroundEventL(TBool aForeground)
+{
+ QS60MainAppUiBase::HandleForegroundEventL(aForeground);
+}
+
+#ifndef Q_WS_S60
+
+void QS60StubAknAppUi::HandleViewDeactivation(const TVwsViewId &, const TVwsViewId &) {}
+void QS60StubAknAppUi::HandleTouchPaneSizeChange() {}
+void QS60StubAknAppUi::HandleStatusPaneSizeChange() {}
+void QS60StubAknAppUi::Reserved_MtsmPosition() {}
+void QS60StubAknAppUi::Reserved_MtsmObject() {}
+
+#endif
+
QT_END_NAMESPACE
diff --git a/src/gui/s60framework/qs60mainappui.h b/src/gui/s60framework/qs60mainappui.h
index dcc72d1..796059f 100644
--- a/src/gui/s60framework/qs60mainappui.h
+++ b/src/gui/s60framework/qs60mainappui.h
@@ -44,9 +44,55 @@
#include <QtCore/qglobal.h>
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
+#ifdef Q_WS_S60
#include <aknappui.h>
+typedef CAknAppUi QS60MainAppUiBase;
+#else
+#include <eikappui.h>
+// these stub classes simulate the structure of CAknAppUi, to help binary compatibility between Qt configured with and without S60/Avkon
+class QS60StubAknAppUiBase : public CEikAppUi
+{
+private:
+ int qS60StubAknAppUiBaseSpace[4];
+};
+
+class QS60StubMEikStatusPaneObserver
+{
+public:
+ virtual void HandleStatusPaneSizeChange() = 0;
+};
+
+class QS60StubMAknTouchPaneObserver
+{
+public:
+ virtual void HandleTouchPaneSizeChange() = 0;
+};
+
+class QS60StubAknAppUi : public QS60StubAknAppUiBase, QS60StubMEikStatusPaneObserver,
+ public MCoeViewDeactivationObserver,
+ public QS60StubMAknTouchPaneObserver
+{
+public: // MCoeViewDeactivationObserver
+ virtual void HandleViewDeactivation(const TVwsViewId&, const TVwsViewId &);
+
+public: // from MAknTouchPaneObserver
+ virtual void HandleTouchPaneSizeChange();
+
+protected: // from MEikStatusPaneObserver
+ virtual void HandleStatusPaneSizeChange();
+
+protected: // from CAknAppUi
+ virtual void Reserved_MtsmPosition();
+ virtual void Reserved_MtsmObject();
+
+private:
+ int qS60StubAknAppUiSpace[4];
+};
+
+typedef QS60StubAknAppUi QS60MainAppUiBase;
+#endif
QT_BEGIN_HEADER
@@ -54,7 +100,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
-class Q_GUI_EXPORT QS60MainAppUi : public CAknAppUi
+class Q_GUI_EXPORT QS60MainAppUi : public QS60MainAppUiBase
{
public:
QS60MainAppUi();
@@ -63,7 +109,7 @@ public:
virtual void ConstructL();
- virtual void RestoreMenuL(CCoeControl* menuWindow,TInt resourceId,TMenuType menuType);
+ virtual void RestoreMenuL(CCoeControl *menuWindow,TInt resourceId,TMenuType menuType);
virtual void DynInitMenuBarL(TInt resourceId, CEikMenuBar *menuBar);
virtual void DynInitMenuPaneL(TInt resourceId, CEikMenuPane *menuPane);
@@ -74,13 +120,32 @@ public:
virtual void HandleStatusPaneSizeChange();
protected:
- virtual void HandleWsEventL(const TWsEvent& event, CCoeControl* destination);
+ virtual void HandleWsEventL(const TWsEvent &event, CCoeControl *destination);
+
+public:
+ virtual void Exit();
+ virtual void SetFadedL(TBool aFaded);
+ virtual TRect ApplicationRect() const;
+ virtual void ProcessCommandL(TInt aCommand);
+ virtual TErrorHandlerResponse HandleError (TInt aError, const SExtendedError &aExtErr, TDes &aErrorText, TDes &aContextText);
+ virtual void HandleViewDeactivation(const TVwsViewId &aViewIdToBeDeactivated, const TVwsViewId &aNewlyActivatedViewId);
+ virtual void PrepareToExit();
+ virtual void HandleTouchPaneSizeChange();
+
+protected:
+ virtual void HandleScreenDeviceChangedL();
+ virtual void HandleApplicationSpecificEventL(TInt aType, const TWsEvent &aEvent);
+ virtual TTypeUid::Ptr MopSupplyObject(TTypeUid aId);
+ virtual void HandleSystemEventL(const TWsEvent &aEvent);
+ virtual void Reserved_MtsmPosition();
+ virtual void Reserved_MtsmObject();
+ virtual void HandleForegroundEventL(TBool aForeground);
};
QT_END_NAMESPACE
QT_END_HEADER
-#endif // Q_WS_S60
+#endif // Q_OS_SYMBIAN
#endif // QS60MAINAPPUI_H
diff --git a/src/gui/s60framework/qs60maindocument.cpp b/src/gui/s60framework/qs60maindocument.cpp
index 487e067..ed33a41 100644
--- a/src/gui/s60framework/qs60maindocument.cpp
+++ b/src/gui/s60framework/qs60maindocument.cpp
@@ -57,15 +57,15 @@ QT_BEGIN_NAMESPACE
The QS60MainDocument provides a helper class for use in migrating
from existing S60 based applications to Qt based applications. It is
- used in the exact same way as the \c CAknDocument class from
+ used in the exact same way as the \c CEikDocument class from
Symbian, but internally provides extensions used by Qt.
When modifying old S60 applications that rely on implementing
- functions in \c CAknDocument, the class should be modified to
- inherit from this class instead of \c CAknDocument. Then the
+ functions in \c CEikDocument, the class should be modified to
+ inherit from this class instead of \c CEikDocument. Then the
application can choose to override only certain functions.
- For more information on \c CAknDocument, please see the S60
+ For more information on \c CEikDocument, please see the S60
documentation.
Unlike other Qt classes, QS60MainDocument behaves like an S60 class,
@@ -79,8 +79,8 @@ QT_BEGIN_NAMESPACE
*
* \a mainApplication should contain a pointer to a QS60MainApplication instance.
*/
-QS60MainDocument::QS60MainDocument(CEikApplication& mainApplication)
- : CAknDocument(mainApplication)
+QS60MainDocument::QS60MainDocument(CEikApplication &mainApplication)
+ : QS60MainDocumentBase(mainApplication)
{
// No implementation required
}
@@ -105,4 +105,14 @@ CEikAppUi *QS60MainDocument::CreateAppUiL()
return (static_cast <CEikAppUi*>(new(ELeave)QS60MainAppUi));
}
+CFileStore *QS60MainDocument::OpenFileL(TBool aDoOpen, const TDesC &aFilename, RFs &aFs)
+{
+ return QS60MainDocumentBase::OpenFileL(aDoOpen, aFilename, aFs);
+}
+
+void QS60MainDocument::OpenFileL(CFileStore *&aFileStore, RFile &aFile)
+{
+ QS60MainDocumentBase::OpenFileL(aFileStore, aFile);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/s60framework/qs60maindocument.h b/src/gui/s60framework/qs60maindocument.h
index 553675f..2f0564f 100644
--- a/src/gui/s60framework/qs60maindocument.h
+++ b/src/gui/s60framework/qs60maindocument.h
@@ -44,9 +44,15 @@
#include <QtCore/qglobal.h>
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
-#include <AknDoc.h>
+#ifdef Q_WS_S60
+#include <akndoc.h>
+typedef CAknDocument QS60MainDocumentBase;
+#else
+#include <eikdoc.h>
+typedef CEikDocument QS60MainDocumentBase;
+#endif
class CEikApplication;
@@ -58,7 +64,7 @@ QT_MODULE(Gui)
class QS60MainAppUi;
-class Q_GUI_EXPORT QS60MainDocument : public CAknDocument
+class Q_GUI_EXPORT QS60MainDocument : public QS60MainDocumentBase
{
public:
@@ -69,12 +75,18 @@ public:
public:
virtual CEikAppUi *CreateAppUiL();
+
+public:
+
+ virtual CFileStore *OpenFileL(TBool aDoOpen, const TDesC &aFilename, RFs &aFs);
+
+ virtual void OpenFileL(CFileStore *&aFileStore, RFile &aFile);
};
QT_END_NAMESPACE
QT_END_HEADER
-#endif // Q_WS_S60
+#endif // Q_OS_SYMBIAN
#endif // QS60MAINDOCUMENT_H
diff --git a/src/gui/s60framework/s60framework.pri b/src/gui/s60framework/s60framework.pri
index f9d89dc..edbacc0 100644
--- a/src/gui/s60framework/s60framework.pri
+++ b/src/gui/s60framework/s60framework.pri
@@ -1,16 +1,20 @@
+contains(QT_CONFIG, s60) {
# This block serves the minimalistic resource file for S60 3.1 platforms.
# Note there is no way to ifdef S60 version in mmp file, that is why the resource
# file is always compiled for WINSCW
-minimalAppResource31 = \
- "SOURCEPATH s60framework" \
- "START RESOURCE s60main.rss" \
- "TARGET s60main$${QT_LIBINFIX}" \
- "HEADER" \
- "TARGETPATH /resource/apps" \
- "END"
-MMP_RULES += minimalAppResource31
-SYMBIAN_RESOURCES += s60framework/s60main.rss
+ minimalAppResource31 = \
+ "SOURCEPATH s60framework" \
+ "START RESOURCE s60main.rss" \
+ "TARGET s60main$${QT_LIBINFIX}" \
+ "HEADER" \
+ "TARGETPATH /resource/apps" \
+ "END"
+
+ MMP_RULES += minimalAppResource31
+
+ SYMBIAN_RESOURCES += s60framework/s60main.rss
+}
SOURCES += s60framework/qs60mainapplication.cpp \
s60framework/qs60mainappui.cpp \
diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp
index 45bcc00..e28403b 100644
--- a/src/gui/styles/qs60style.cpp
+++ b/src/gui/styles/qs60style.cpp
@@ -1765,52 +1765,31 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option,
QRect iconRect = subElementRect(SE_ItemViewItemDecoration, &optionMenuItem, widget);
QRect textRect = subElementRect(SE_ItemViewItemText, &optionMenuItem, widget);
- //todo: move the vertical spacing stuff into subElementRect
- const int vSpacing = QS60StylePrivate::pixelMetric(PM_LayoutVerticalSpacing);
QStyleOptionMenuItem optionCheckBox;
//Regardless of checkbox visibility, make room for it, this mirrors native implementation,
//where text and icon placement is static regardless of content of menu item.
- const int hSpacing = QS60StylePrivate::pixelMetric(PM_LayoutHorizontalSpacing);
optionCheckBox.QStyleOptionMenuItem::operator=(*menuItem);
optionCheckBox.rect.setWidth(pixelMetric(PM_IndicatorWidth));
optionCheckBox.rect.setHeight(pixelMetric(PM_IndicatorHeight));
+
+ const int vSpacing = QS60StylePrivate::pixelMetric(PM_LayoutVerticalSpacing);
+ //The vertical spacing is doubled; it needs one spacing to separate checkbox from
+ //highlight and then it needs one to separate it whatever is shown after it (text/icon/both).
+ const int moveByX = optionCheckBox.rect.width() + 2 * vSpacing;
optionCheckBox.rect.moveCenter(QPoint(
- optionCheckBox.rect.center().x(),
+ optionCheckBox.rect.center().x() + moveByX >> 1,
menuItem->rect.center().y()));
- const int moveByX = optionCheckBox.rect.width() + vSpacing +
- pixelMetric(PM_DefaultFrameWidth);
- if (optionMenuItem.direction == Qt::LeftToRight) {
- if (iconRect.isValid()) {
- iconRect.translate(moveByX, 0);
- iconRect.setWidth(iconRect.width() + vSpacing);
- }
- if (textRect.isValid()) {
- textRect.translate(moveByX, 0);
- textRect.setWidth(textRect.width() - moveByX - vSpacing);
- }
- optionCheckBox.rect.translate(vSpacing + pixelMetric(PM_DefaultFrameWidth), hSpacing >> 1);
- } else {
- if (textRect.isValid())
- textRect.setWidth(textRect.width() - moveByX);
- if (iconRect.isValid()) {
- iconRect.setWidth(iconRect.width() + vSpacing);
- iconRect.translate(-optionCheckBox.rect.width() - vSpacing, 0);
- }
+
+ if (optionMenuItem.direction != Qt::LeftToRight)
optionCheckBox.rect.translate(textRect.width() + iconRect.width(), 0);
- }
+
const bool selected = (option->state & State_Selected) && (option->state & State_Enabled);
if (selected) {
- const int spacing = pixelMetric(PM_DefaultFrameWidth) * 2;
- int start; int end;
- if (QApplication::layoutDirection() == Qt::LeftToRight) {
- start = optionMenuItem.rect.left() + spacing;
- end = qMax(textRect.right(), iconRect.right() + spacing);
- } else {
- start = qMax(spacing, qMin(textRect.left(), iconRect.left() - spacing));
- end = optionMenuItem.rect.right() - spacing;
- }
+ const int spacing = ignoreCheckMark ? (vSpacing + QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth)) : 0;
+ const int start = optionMenuItem.rect.left() + spacing;
+ const int end = optionMenuItem.rect.right() - spacing;
//-1 adjustment to avoid highlight being on top of possible separator item
const QRect highlightRect = QRect(
QPoint(start, option->rect.top()),
@@ -3025,20 +3004,38 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con
pixelMetric(PM_SmallIconSize, opt, widget);
ret = menuItem->rect;
+ QRect checkBoxRect = checkable ? menuItem->rect : QRect();
+ if (checkable) {
+ checkBoxRect.setWidth(pixelMetric(PM_IndicatorWidth));
+ checkBoxRect.setHeight(pixelMetric(PM_IndicatorHeight));
+ }
+
+ const int vSpacing = QS60StylePrivate::pixelMetric(PM_LayoutVerticalSpacing);
+ //The vertical spacing is doubled; it needs one spacing to separate checkbox from
+ //highlight and then it needs one to separate it whatever is shown after it (text/icon/both).
+ const int moveByX = checkBoxRect.width() + 2 * vSpacing;
+
if (element == SE_ItemViewItemDecoration) {
if (menuItem->icon.isNull()) {
ret = QRect();
} else {
if (menuItem->direction == Qt::RightToLeft)
- ret.translate(ret.width() - indicatorWidth, 0);
+ ret.translate(ret.width() - indicatorWidth - moveByX, 0);
+ else
+ ret.translate(moveByX, 0);
ret.setWidth(indicatorWidth);
}
} else {
- if (!menuItem->icon.isNull())
+ if (!menuItem->icon.isNull()) {
if (menuItem->direction == Qt::LeftToRight)
ret.adjust(indicatorWidth, 0, 0, 0);
else
ret.adjust(0, 0, -indicatorWidth, 0);
+ }
+ if (menuItem->direction == Qt::LeftToRight)
+ ret.adjust(moveByX, 0, 0, 0);
+ else
+ ret.adjust(0, 0, -moveByX, 0);
// Make room for submenu indicator
if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu){
@@ -3116,6 +3113,11 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con
case SE_CheckBoxFocusRect:
ret = opt->rect;
break;
+ case SE_ProgressBarLabel:
+ case SE_ProgressBarContents:
+ case SE_ProgressBarGroove:
+ ret = opt->rect;
+ break;
default:
ret = QCommonStyle::subElementRect(element, opt, widget);
}
diff --git a/src/gui/styles/qs60style.h b/src/gui/styles/qs60style.h
index c878538..f588d9f 100644
--- a/src/gui/styles/qs60style.h
+++ b/src/gui/styles/qs60style.h
@@ -50,8 +50,6 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
-#if !defined(QT_NO_STYLE_S60)
-
//Public custom pixel metrics values.
//These can be used to fetch custom pixel metric value from outside QS60Style.
enum {
@@ -91,14 +89,14 @@ public:
#endif
bool event(QEvent *e);
-#ifndef Q_WS_S60
+#ifndef Q_OS_SYMBIAN
static QStringList partKeys();
static QStringList colorListKeys();
void setS60Theme(const QHash<QString, QPicture> &parts,
const QHash<QPair<QString , int>, QColor> &colors);
bool loadS60ThemeFromBlob(const QString &blobFile);
bool saveS60ThemeToBlob(const QString &blobFile) const;
-#endif // !Q_WS_S60
+#endif // !Q_OS_SYMBIAN
protected Q_SLOTS:
QIcon standardIconImplementation(
@@ -113,8 +111,6 @@ private:
friend class QApplicationPrivate;
};
-#endif // QT_NO_STYLE_S60
-
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/gui/styles/qs60style_stub.cpp b/src/gui/styles/qs60style_stub.cpp
new file mode 100644
index 0000000..a3a5b9d
--- /dev/null
+++ b/src/gui/styles/qs60style_stub.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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 "qs60style.h"
+#include "qdebug.h"
+
+#if defined(QT_NO_STYLE_S60)
+QT_BEGIN_NAMESPACE
+
+QS60Style::QS60Style()
+{
+ qWarning() << "QS60Style stub created";
+}
+
+QS60Style::~QS60Style()
+{
+}
+
+void QS60Style::drawComplexControl(ComplexControl , const QStyleOptionComplex *, QPainter *, const QWidget *) const
+{
+}
+
+void QS60Style::drawControl(ControlElement , const QStyleOption *, QPainter *, const QWidget *) const
+{
+}
+
+void QS60Style::drawPrimitive(PrimitiveElement , const QStyleOption *, QPainter *, const QWidget *) const
+{
+}
+
+int QS60Style::pixelMetric(PixelMetric , const QStyleOption *, const QWidget *) const
+{
+ return 0;
+}
+
+QSize QS60Style::sizeFromContents(ContentsType , const QStyleOption *, const QSize &, const QWidget *) const
+{
+ return QSize();
+}
+
+int QS60Style::styleHint(StyleHint , const QStyleOption *, const QWidget *, QStyleHintReturn *) const
+{
+ return 0;
+}
+
+QRect QS60Style::subControlRect(ComplexControl , const QStyleOptionComplex *, SubControl , const QWidget *) const
+{
+ return QRect();
+}
+
+QRect QS60Style::subElementRect(SubElement , const QStyleOption *, const QWidget *) const
+{
+ return QRect();
+}
+
+void QS60Style::polish(QWidget *)
+{
+}
+
+void QS60Style::unpolish(QWidget *)
+{
+}
+
+void QS60Style::polish(QApplication *)
+{
+}
+
+void QS60Style::unpolish(QApplication *)
+{
+}
+
+bool QS60Style::event(QEvent *)
+{
+ return false;
+}
+
+QIcon QS60Style::standardIconImplementation(StandardPixmap , const QStyleOption *, const QWidget *) const
+{
+ return QIcon();
+}
+
+void QS60Style::timerEvent(QTimerEvent *)
+{
+}
+
+bool QS60Style::eventFilter(QObject *, QEvent *)
+{
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_STYLE_S60
diff --git a/src/gui/styles/qwindowsvistastyle.cpp b/src/gui/styles/qwindowsvistastyle.cpp
index 67a7b85..8511592 100644
--- a/src/gui/styles/qwindowsvistastyle.cpp
+++ b/src/gui/styles/qwindowsvistastyle.cpp
@@ -1926,30 +1926,7 @@ QSize QWindowsVistaStyle::sizeFromContents(ContentsType type, const QStyleOption
return QWindowsStyle::sizeFromContents(type, option, size, widget);
QSize sz(size);
-
- QSize newSize = QWindowsXPStyle::sizeFromContents(type, option, size, widget);
switch (type) {
- case CT_LineEdit:
- case CT_ComboBox:
- {
- HTHEME theme = pOpenThemeData(0, L"Button");
- MARGINS borderSize;
- if (theme) {
- int result = pGetThemeMargins(theme,
- NULL,
- BP_PUSHBUTTON,
- PBS_NORMAL,
- TMT_CONTENTMARGINS,
- NULL,
- &borderSize);
- if (result == S_OK) {
- sz += QSize(borderSize.cxLeftWidth + borderSize.cxRightWidth - 2,
- borderSize.cyBottomHeight + borderSize.cyTopHeight - 2);
- }
- sz += QSize(23, 0); //arrow button
- }
- }
- return sz;
case CT_MenuItem:
sz = QWindowsXPStyle::sizeFromContents(type, option, size, widget);
int minimumHeight;
@@ -1990,7 +1967,7 @@ QSize QWindowsVistaStyle::sizeFromContents(ContentsType type, const QStyleOption
default:
break;
}
- return newSize;
+ return QWindowsXPStyle::sizeFromContents(type, option, size, widget);
}
/*!
diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp
index efb1224..8743807 100644
--- a/src/gui/styles/qwindowsxpstyle.cpp
+++ b/src/gui/styles/qwindowsxpstyle.cpp
@@ -3678,7 +3678,9 @@ QSize QWindowsXPStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt
sz += QSize(borderSize.cxLeftWidth + borderSize.cxRightWidth - 2,
borderSize.cyBottomHeight + borderSize.cyTopHeight - 2);
}
- sz += QSize(23, 0); //arrow button
+ const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin) + 1);
+ sz += QSize(qMax(pixelMetric(QStyle::PM_ScrollBarExtent, option, widget)
+ + textMargins, 23), 0); //arrow button
}
}
break;
diff --git a/src/gui/styles/styles.pri b/src/gui/styles/styles.pri
index 0a96272..b22a908 100644
--- a/src/gui/styles/styles.pri
+++ b/src/gui/styles/styles.pri
@@ -182,5 +182,9 @@ contains( styles, s60 ):contains(QT_CONFIG, s60) {
RESOURCES += styles/qstyle_s60_simulated.qrc
}
} else {
+ symbian {
+ HEADERS += styles/qs60style.h
+ SOURCES += styles/qs60style_stub.cpp
+ }
DEFINES += QT_NO_STYLE_S60
}
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index c229242..3fe98e1 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -1266,6 +1266,15 @@ QFont::StyleHint QFont::styleHint() const
\value OldEnglish the font matcher prefers decorative fonts.
\value Decorative is a synonym for \c OldEnglish.
+ \value Monospace the font matcher prefers fonts that map to the
+ CSS generic font-family 'monospace'.
+
+ \value Fantasy the font matcher prefers fonts that map to the
+ CSS generic font-family 'fantasy'.
+
+ \value Cursive the font matcher prefers fonts that map to the
+ CSS generic font-family 'cursive'.
+
\value System the font matcher prefers system fonts.
*/
diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h
index 6f62424..2cc41e1 100644
--- a/src/gui/text/qfont.h
+++ b/src/gui/text/qfont.h
@@ -72,7 +72,10 @@ public:
Courier, TypeWriter = Courier,
OldEnglish, Decorative = OldEnglish,
System,
- AnyStyle
+ AnyStyle,
+ Cursive,
+ Monospace,
+ Fantasy
};
enum StyleStrategy {
diff --git a/src/gui/text/qfont_mac.cpp b/src/gui/text/qfont_mac.cpp
index 93985ab..0bc8ca2 100644
--- a/src/gui/text/qfont_mac.cpp
+++ b/src/gui/text/qfont_mac.cpp
@@ -136,8 +136,14 @@ QString QFont::defaultFamily() const
return QString::fromLatin1("Times New Roman");
case QFont::Courier:
return QString::fromLatin1("Courier New");
+ case QFont::Monospace:
+ return QString::fromLatin1("Courier");
case QFont::Decorative:
return QString::fromLatin1("Bookman Old Style");
+ case QFont::Cursive:
+ return QString::fromLatin1("Apple Chancery");
+ case QFont::Fantasy:
+ return QString::fromLatin1("Papyrus");
case QFont::Helvetica:
case QFont::System:
default:
diff --git a/src/gui/text/qfont_qws.cpp b/src/gui/text/qfont_qws.cpp
index 51af1e1..72f8c37 100644
--- a/src/gui/text/qfont_qws.cpp
+++ b/src/gui/text/qfont_qws.cpp
@@ -108,6 +108,7 @@ QString QFont::defaultFamily() const
case QFont::Times:
return QString::fromLatin1("times");
case QFont::Courier:
+ case QFont::Monospace:
return QString::fromLatin1("courier");
case QFont::Decorative:
return QString::fromLatin1("old english");
diff --git a/src/gui/text/qfont_win.cpp b/src/gui/text/qfont_win.cpp
index a9610f7..fa45ae1 100644
--- a/src/gui/text/qfont_win.cpp
+++ b/src/gui/text/qfont_win.cpp
@@ -148,9 +148,14 @@ QString QFont::defaultFamily() const
case QFont::Times:
return QString::fromLatin1("Times New Roman");
case QFont::Courier:
+ case QFont::Monospace:
return QString::fromLatin1("Courier New");
case QFont::Decorative:
return QString::fromLatin1("Bookman Old Style");
+ case QFont::Cursive:
+ return QString::fromLatin1("Comic Sans MS");
+ case QFont::Fantasy:
+ return QString::fromLatin1("Impact");
case QFont::Helvetica:
return QString::fromLatin1("Arial");
case QFont::System:
diff --git a/src/gui/text/qfont_x11.cpp b/src/gui/text/qfont_x11.cpp
index 39127dc..92e2326 100644
--- a/src/gui/text/qfont_x11.cpp
+++ b/src/gui/text/qfont_x11.cpp
@@ -281,6 +281,15 @@ QString QFont::defaultFamily() const
case QFont::Courier:
return QString::fromLatin1("Courier");
+ case QFont::Monospace:
+ return QString::fromLatin1("Courier New");
+
+ case QFont::Cursive:
+ return QString::fromLatin1("Comic Sans MS");
+
+ case QFont::Fantasy:
+ return QString::fromLatin1("Impact");
+
case QFont::Decorative:
return QString::fromLatin1("Old English");
diff --git a/src/gui/text/qfontengine_s60_p.h b/src/gui/text/qfontengine_s60_p.h
index beeb4cc..d65f13b 100644
--- a/src/gui/text/qfontengine_s60_p.h
+++ b/src/gui/text/qfontengine_s60_p.h
@@ -54,7 +54,7 @@
//
#include "qconfig.h"
-#include "qfontengine_p.h"
+#include <private/qfontengine_p.h>
#include "qsize.h"
#include <openfont.h>
@@ -134,6 +134,7 @@ public:
private:
friend class QFontPrivate;
+ friend class QSymbianVGFontGlyphCache;
QFixed glyphAdvance(HB_Glyph glyph) const;
CFont *fontWithSize(qreal size) const;
diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp
index a9caa6b..daa40a1 100644
--- a/src/gui/text/qtextcursor.cpp
+++ b/src/gui/text/qtextcursor.cpp
@@ -64,7 +64,8 @@ enum {
QTextCursorPrivate::QTextCursorPrivate(QTextDocumentPrivate *p)
: priv(p), x(0), position(0), anchor(0), adjusted_anchor(0),
- currentCharFormat(-1), visualNavigation(false), keepPositionOnInsert(false)
+ currentCharFormat(-1), visualNavigation(false), keepPositionOnInsert(false),
+ changed(false)
{
priv->addCursor(this);
}
@@ -80,6 +81,7 @@ QTextCursorPrivate::QTextCursorPrivate(const QTextCursorPrivate &rhs)
currentCharFormat = rhs.currentCharFormat;
visualNavigation = rhs.visualNavigation;
keepPositionOnInsert = rhs.keepPositionOnInsert;
+ changed = rhs.changed;
priv->addCursor(this);
}
diff --git a/src/gui/text/qtextcursor_p.h b/src/gui/text/qtextcursor_p.h
index 4e36b95..4b3262f 100644
--- a/src/gui/text/qtextcursor_p.h
+++ b/src/gui/text/qtextcursor_p.h
@@ -114,6 +114,7 @@ public:
int currentCharFormat;
uint visualNavigation : 1;
uint keepPositionOnInsert : 1;
+ uint changed : 1;
};
QT_END_NAMESPACE
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index e0386f1..195dc28 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -583,11 +583,11 @@ void QTextDocument::setDefaultTextOption(const QTextOption &option)
void QTextDocument::markContentsDirty(int from, int length)
{
Q_D(QTextDocument);
- if (!d->inContentsChange)
- d->beginEditBlock();
d->documentChange(from, length);
- if (!d->inContentsChange)
- d->endEditBlock();
+ if (!d->inContentsChange) {
+ d->lout->documentChanged(d->docChangeFrom, d->docChangeOldLength, d->docChangeLength);
+ d->docChangeFrom = -1;
+ }
}
/*!
diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp
index f3cd481..7b3f985 100644
--- a/src/gui/text/qtextdocument_p.cpp
+++ b/src/gui/text/qtextdocument_p.cpp
@@ -205,6 +205,7 @@ QTextDocumentPrivate::QTextDocumentPrivate()
undoEnabled = true;
inContentsChange = false;
+ blockCursorAdjustment = false;
defaultTextOption.setTabStop(80); // same as in qtextengine.cpp
defaultTextOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
@@ -234,17 +235,17 @@ void QTextDocumentPrivate::init()
void QTextDocumentPrivate::clear()
{
Q_Q(QTextDocument);
- for (int i = 0; i < cursors.count(); ++i) {
- cursors.at(i)->setPosition(0);
- cursors.at(i)->currentCharFormat = -1;
- cursors.at(i)->anchor = 0;
- cursors.at(i)->adjusted_anchor = 0;
+
+ foreach (QTextCursorPrivate *curs, cursors) {
+ curs->setPosition(0);
+ curs->currentCharFormat = -1;
+ curs->anchor = 0;
+ curs->adjusted_anchor = 0;
}
QList<QTextCursorPrivate *>oldCursors = cursors;
QT_TRY{
cursors.clear();
- changedCursors.clear();
QMap<int, QTextObject *>::Iterator objectIt = objects.begin();
while (objectIt != objects.end()) {
@@ -287,8 +288,8 @@ void QTextDocumentPrivate::clear()
QTextDocumentPrivate::~QTextDocumentPrivate()
{
- for (int i = 0; i < cursors.count(); ++i)
- cursors.at(i)->priv = 0;
+ foreach (QTextCursorPrivate *curs, cursors)
+ curs->priv = 0;
cursors.clear();
undoState = 0;
undoEnabled = true;
@@ -669,7 +670,14 @@ void QTextDocumentPrivate::remove(int pos, int length, QTextUndoCommand::Operati
{
if (length == 0)
return;
+ blockCursorAdjustment = true;
move(pos, -1, length, op);
+ blockCursorAdjustment = false;
+ foreach (QTextCursorPrivate *curs, cursors) {
+ if (curs->adjustPosition(pos, -length, op) == QTextCursorPrivate::CursorMoved) {
+ curs->changed = true;
+ }
+ }
}
void QTextDocumentPrivate::setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode)
@@ -1221,10 +1229,15 @@ void QTextDocumentPrivate::finishEdit()
}
}
- while (!changedCursors.isEmpty()) {
- QTextCursorPrivate *curs = changedCursors.takeFirst();
- emit q->cursorPositionChanged(QTextCursor(curs));
+ QList<QTextCursor> changedCursors;
+ foreach (QTextCursorPrivate *curs, cursors) {
+ if (curs->changed) {
+ curs->changed = false;
+ changedCursors.append(QTextCursor(curs));
+ }
}
+ foreach (const QTextCursor &cursor, changedCursors)
+ emit q->cursorPositionChanged(cursor);
contentsChanged();
@@ -1266,11 +1279,13 @@ void QTextDocumentPrivate::adjustDocumentChangesAndCursors(int from, int addedOr
if (!editBlock)
++revision;
- for (int i = 0; i < cursors.size(); ++i) {
- QTextCursorPrivate *curs = cursors.at(i);
- if (curs->adjustPosition(from, addedOrRemoved, op) == QTextCursorPrivate::CursorMoved) {
- if (!changedCursors.contains(curs))
- changedCursors.append(curs);
+ if (blockCursorAdjustment) {
+ ; // postpone, will be called again from QTextDocumentPrivate::remove()
+ } else {
+ foreach (QTextCursorPrivate *curs, cursors) {
+ if (curs->adjustPosition(from, addedOrRemoved, op) == QTextCursorPrivate::CursorMoved) {
+ curs->changed = true;
+ }
}
}
@@ -1693,8 +1708,8 @@ bool QTextDocumentPrivate::ensureMaximumBlockCount()
void QTextDocumentPrivate::aboutToRemoveCell(int from, int to)
{
Q_ASSERT(from <= to);
- for (int i = 0; i < cursors.size(); ++i)
- cursors.at(i)->aboutToRemoveCell(from, to);
+ foreach (QTextCursorPrivate *curs, cursors)
+ curs->aboutToRemoveCell(from, to);
}
QT_END_NAMESPACE
diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h
index d1bd698..b46d01c 100644
--- a/src/gui/text/qtextdocument_p.h
+++ b/src/gui/text/qtextdocument_p.h
@@ -277,7 +277,7 @@ public:
void documentChange(int from, int length);
inline void addCursor(QTextCursorPrivate *c) { cursors.append(c); }
- inline void removeCursor(QTextCursorPrivate *c) { cursors.removeAll(c); changedCursors.removeAll(c); }
+ inline void removeCursor(QTextCursorPrivate *c) { cursors.removeAll(c); }
QTextFrame *frameAt(int pos) const;
QTextFrame *rootFrame() const;
@@ -329,8 +329,7 @@ private:
BlockMap blocks;
int initialBlockCharFormatIndex;
- QList<QTextCursorPrivate*> cursors;
- QList<QTextCursorPrivate*> changedCursors;
+ QList<QTextCursorPrivate *> cursors;
QMap<int, QTextObject *> objects;
QMap<QUrl, QVariant> resources;
QMap<QUrl, QVariant> cachedResources;
@@ -346,6 +345,7 @@ public:
int maximumBlockCount;
uint needsEnsureMaximumBlockCount : 1;
uint inContentsChange : 1;
+ uint blockCursorAdjustment : 1;
QSizeF pageSize;
QString title;
QString url;
diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp
index a415180..24f6ccf 100644
--- a/src/gui/util/qdesktopservices_s60.cpp
+++ b/src/gui/util/qdesktopservices_s60.cpp
@@ -39,9 +39,6 @@
**
****************************************************************************/
-// This flag changes the implementation to use S60 CDcoumentHandler
-// instead of apparch when opening the files
-#define USE_DOCUMENTHANDLER
#include <qcoreapplication.h>
#include <qdir.h>
@@ -56,10 +53,16 @@
#include <rsendas.h> // RSendAs
#include <rsendasmessage.h> // RSendAsMessage
+#ifdef Q_WS_S60
+// This flag changes the implementation to use S60 CDcoumentHandler
+// instead of apparch when opening the files
+#define USE_DOCUMENTHANDLER
+#endif
+
// copied from miutset.h, so we don't get a dependency into the app layer
const TUid KUidMsgTypeSMTP = {0x10001028}; // 268439592
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
# include <pathinfo.h> // PathInfo
# ifdef USE_DOCUMENTHANDLER
# include <DocumentHandler.h> // CDocumentHandler
@@ -264,7 +267,7 @@ static TDriveUnit writableExeDrive()
static TPtrC writableDataRoot()
{
TDriveUnit drive = exeDrive();
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
switch(drive.operator TInt()){
case EDriveC:
return PathInfo::PhoneMemoryRootPath();
@@ -391,19 +394,19 @@ QString QDesktopServices::storageLocation(StandardLocation type)
break;
case MusicLocation:
path.Append(writableDataRoot());
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
path.Append(PathInfo::SoundsPath());
#endif
break;
case MoviesLocation:
path.Append(writableDataRoot());
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
path.Append(PathInfo::VideosPath());
#endif
break;
case PicturesLocation:
path.Append(writableDataRoot());
-#ifdef Q_WS_S60
+#ifdef Q_OS_SYMBIAN
path.Append(PathInfo::ImagesPath());
#endif
break;
diff --git a/src/gui/util/util.pri b/src/gui/util/util.pri
index be8db93..bea520e 100644
--- a/src/gui/util/util.pri
+++ b/src/gui/util/util.pri
@@ -43,9 +43,8 @@ embedded {
}
symbian {
- LIBS += -lsendas2 -letext -lapmime
+ LIBS += -lsendas2 -letext -lapmime -lplatformenv
contains(QT_CONFIG, s60) {
- LIBS += -lplatformenv
contains(CONFIG, is_using_gnupoc) {
LIBS += -lcommonui
} else {
diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp
index 1504066..dcc328f 100644
--- a/src/gui/widgets/qcombobox.cpp
+++ b/src/gui/widgets/qcombobox.cpp
@@ -704,6 +704,11 @@ void QComboBoxPrivateContainer::hideEvent(QHideEvent *)
{
emit resetButton();
combo->update();
+ // QGraphicsScenePrivate::removePopup closes the combo box popup, it hides it non-explicitly.
+ // Hiding/showing the QComboBox after this will unexpectedly show the popup as well.
+ // Re-hiding the popup container makes sure it is explicitly hidden.
+ if (QGraphicsProxyWidget *proxy = graphicsProxyWidget())
+ proxy->hide();
}
void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e)
diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h
index 82070fe..fc6701c 100644
--- a/src/gui/widgets/qmenubar_p.h
+++ b/src/gui/widgets/qmenubar_p.h
@@ -269,10 +269,10 @@ public:
} *symbian_menubar;
static int symbianCommands(int command);
+#endif
#ifdef QT_SOFTKEYS_ENABLED
QAction *menuBarAction;
#endif
-#endif
};
#endif