diff options
author | Rohan McGovern <rohan.mcgovern@nokia.com> | 2011-05-15 23:09:31 (GMT) |
---|---|---|
committer | Rohan McGovern <rohan.mcgovern@nokia.com> | 2011-05-15 23:09:31 (GMT) |
commit | 5aa1cbcdacd19b2e526e358eddac1b7d55a994b5 (patch) | |
tree | 4aba78405e3d98081662fcb934f673acd1b79d42 /src/gui | |
parent | 8592bcc80b7ec245b485fa54f8bd41c4484e93e0 (diff) | |
parent | 7e4a9187bb11b794e45d95d2e9fae026d6b0d07d (diff) | |
download | Qt-5aa1cbcdacd19b2e526e358eddac1b7d55a994b5.zip Qt-5aa1cbcdacd19b2e526e358eddac1b7d55a994b5.tar.gz Qt-5aa1cbcdacd19b2e526e358eddac1b7d55a994b5.tar.bz2 |
Merge remote branch 'origin/4.8' into qa-review-master
Conflicts:
tests/auto/qaccessibility/tst_qaccessibility.cpp
tests/auto/qsslsocket/tst_qsslsocket.cpp
Diffstat (limited to 'src/gui')
245 files changed, 7407 insertions, 2369 deletions
diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index c714173..1e9e55e 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -83,6 +83,42 @@ public: MenuCommand = 0x0018, + // Values from IAccessible2 + ActionChanged = 0x0101, + ActiveDescendantChanged, + AttributeChanged, + DocumentContentChanged, + DocumentLoadComplete, + DocumentLoadStopped, + DocumentReload, + HyperlinkEndIndexChanged, + HyperlinkNumberOfAnchorsChanged, + HyperlinkSelectedLinkChanged, + HypertextLinkActivated, + HypertextLinkSelected, + HyperlinkStartIndexChanged, + HypertextChanged, + HypertextNLinksChanged, + ObjectAttributeChanged, + PageChanged, + SectionChanged, + TableCaptionChanged, + TableColumnDescriptionChanged, + TableColumnHeaderChanged, + TableModelChanged, + TableRowDescriptionChanged, + TableRowHeaderChanged, + TableSummaryChanged, + TextAttributeChanged, + TextCaretMoved, + // TextChanged, deprecated, use TextUpdated + TextColumnChanged = TextCaretMoved + 2, + TextInserted, + TextRemoved, + TextUpdated, + TextSelectionChanged, + VisibleDataChanged, + ObjectCreated = 0x8000, ObjectDestroyed = 0x8001, ObjectShow = 0x8002, diff --git a/src/gui/accessible/qaccessibleobject.cpp b/src/gui/accessible/qaccessibleobject.cpp index 1d2d1da..0cb2c08 100644 --- a/src/gui/accessible/qaccessibleobject.cpp +++ b/src/gui/accessible/qaccessibleobject.cpp @@ -322,9 +322,7 @@ QString QAccessibleApplication::text(Text t, int) const { switch (t) { case Name: - if (QApplication::activeWindow()) - return QApplication::activeWindow()->windowTitle(); - break; + return QApplication::applicationName(); case Description: return QApplication::applicationFilePath(); default: diff --git a/src/gui/dialogs/qabstractprintdialog.cpp b/src/gui/dialogs/qabstractprintdialog.cpp index 3317018..ef46697 100644 --- a/src/gui/dialogs/qabstractprintdialog.cpp +++ b/src/gui/dialogs/qabstractprintdialog.cpp @@ -381,19 +381,11 @@ void QAbstractPrintDialogPrivate::setPrinter(QPrinter *newPrinter) If the dialog is accepted by the user, the QPrinter object is correctly configured for printing. - \raw HTML - <table align="center"> - <tr><td> - \endraw - \inlineimage plastique-printdialog.png - \raw HTML - </td><td> - \endraw - \inlineimage plastique-printdialog-properties.png - \raw HTML - </td></tr> - </table> - \endraw + \table + \row + \o \inlineimage plastique-printdialog.png + \o \inlineimage plastique-printdialog-properties.png + \endtable The printer dialog (shown above in Plastique style) enables access to common printing properties. On X11 platforms that use the CUPS printing system, the diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm index ee9b19a..9daf595 100644 --- a/src/gui/dialogs/qcolordialog_mac.mm +++ b/src/gui/dialogs/qcolordialog_mac.mm @@ -343,6 +343,7 @@ QT_USE_NAMESPACE mDialogIsExecuting = true; bool modalEnded = false; while (!modalEnded) { +#ifndef QT_NO_EXCEPTIONS @try { [NSApp runModalForWindow:mColorPanel]; modalEnded = true; @@ -351,6 +352,10 @@ QT_USE_NAMESPACE // clicking on 'SelectedMenuItemColor' from the 'Developer' // palette (tab three). } +#else + [NSApp runModalForWindow:mColorPanel]; + modalEnded = true; +#endif } QAbstractEventDispatcher::instance()->interrupt(); diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index cb8eb6a..ff4410d 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -1977,13 +1977,14 @@ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) co const bool hideHidden = !(filters & QDir::Hidden); const bool hideSystem = !(filters & QDir::System); const bool hideSymlinks = (filters & QDir::NoSymLinks); - const bool hideDotAndDotDot = (filters & QDir::NoDotAndDotDot); + const bool hideDot = (filters & QDir::NoDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot) + const bool hideDotDot = (filters & QDir::NoDotDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot) // Note that we match the behavior of entryList and not QFileInfo on this and this // incompatibility won't be fixed until Qt 5 at least - bool isDotOrDot = ( (node->fileName == QLatin1String(".") - || node->fileName == QLatin1String(".."))); - if ( (hideHidden && (!isDotOrDot && node->isHidden())) + bool isDot = (node->fileName == QLatin1String(".")); + bool isDotDot = (node->fileName == QLatin1String("..")); + if ( (hideHidden && !(isDot || isDotDot) && node->isHidden()) || (hideSystem && node->isSystem()) || (hideDirs && node->isDir()) || (hideFiles && node->isFile()) @@ -1991,7 +1992,8 @@ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) co || (hideReadable && node->isReadable()) || (hideWritable && node->isWritable()) || (hideExecutable && node->isExecutable()) - || (hideDotAndDotDot && isDotOrDot)) + || (hideDot && isDot) + || (hideDotDot && isDotDot)) return false; return nameFilterDisables || passNameFilters(node); diff --git a/src/gui/dialogs/qmessagebox.cpp b/src/gui/dialogs/qmessagebox.cpp index 09bb56c..d6dbcf6 100644 --- a/src/gui/dialogs/qmessagebox.cpp +++ b/src/gui/dialogs/qmessagebox.cpp @@ -1536,10 +1536,12 @@ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, /*! \since 4.2 - Opens an information message box with the specified \a title and - \a text. The standard \a buttons are added to the message box. \a - defaultButton specifies the button used when \key Enter is - pressed. \a defaultButton must refer to a button that was given in \a buttons. + Opens an information message box with the given \a title and + \a text in front of the specified \a parent widget. + + The standard \a buttons are added to the message box. + \a defaultButton specifies the button used when \key Enter is pressed. + \a defaultButton must refer to a button that was given in \a buttons. If \a defaultButton is QMessageBox::NoButton, QMessageBox chooses a suitable default automatically. @@ -1547,9 +1549,13 @@ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, \key Esc was pressed instead, the \l{Default and Escape Keys} {escape button} is returned. - The message box is an \l{Qt::ApplicationModal} {application modal} + The message box is an \l{Qt::ApplicationModal}{application modal} dialog box. + \warning Do not delete \a parent during the execution of the dialog. + If you want to do this, you should create the dialog + yourself using one of the QMessageBox constructors. + \sa question(), warning(), critical() */ QMessageBox::StandardButton QMessageBox::information(QWidget *parent, const QString &title, @@ -1564,8 +1570,10 @@ QMessageBox::StandardButton QMessageBox::information(QWidget *parent, const QStr /*! \since 4.2 - Opens a question message box with the specified \a title and \a - text. The standard \a buttons are added to the message box. \a + Opens a question message box with the given \a title and \a + text in front of the specified \a parent widget. + + The standard \a buttons are added to the message box. \a defaultButton specifies the button used when \key Enter is pressed. \a defaultButton must refer to a button that was given in \a buttons. If \a defaultButton is QMessageBox::NoButton, QMessageBox @@ -1578,6 +1586,10 @@ QMessageBox::StandardButton QMessageBox::information(QWidget *parent, const QStr The message box is an \l{Qt::ApplicationModal} {application modal} dialog box. + \warning Do not delete \a parent during the execution of the dialog. + If you want to do this, you should create the dialog + yourself using one of the QMessageBox constructors. + \sa information(), warning(), critical() */ QMessageBox::StandardButton QMessageBox::question(QWidget *parent, const QString &title, @@ -1590,8 +1602,10 @@ QMessageBox::StandardButton QMessageBox::question(QWidget *parent, const QString /*! \since 4.2 - Opens a warning message box with the specified \a title and \a - text. The standard \a buttons are added to the message box. \a + Opens a warning message box with the given \a title and \a + text in front of the specified \a parent widget. + + The standard \a buttons are added to the message box. \a defaultButton specifies the button used when \key Enter is pressed. \a defaultButton must refer to a button that was given in \a buttons. If \a defaultButton is QMessageBox::NoButton, QMessageBox @@ -1604,6 +1618,10 @@ QMessageBox::StandardButton QMessageBox::question(QWidget *parent, const QString The message box is an \l{Qt::ApplicationModal} {application modal} dialog box. + \warning Do not delete \a parent during the execution of the dialog. + If you want to do this, you should create the dialog + yourself using one of the QMessageBox constructors. + \sa question(), information(), critical() */ QMessageBox::StandardButton QMessageBox::warning(QWidget *parent, const QString &title, @@ -1616,8 +1634,10 @@ QMessageBox::StandardButton QMessageBox::warning(QWidget *parent, const QString /*! \since 4.2 - Opens a critical message box with the specified \a title and \a - text. The standard \a buttons are added to the message box. \a + Opens a critical message box with the given \a title and \a + text in front of the specified \a parent widget. + + The standard \a buttons are added to the message box. \a defaultButton specifies the button used when \key Enter is pressed. \a defaultButton must refer to a button that was given in \a buttons. If \a defaultButton is QMessageBox::NoButton, QMessageBox @@ -1630,9 +1650,9 @@ QMessageBox::StandardButton QMessageBox::warning(QWidget *parent, const QString The message box is an \l{Qt::ApplicationModal} {application modal} dialog box. - \warning Do not delete \a parent during the execution of the dialog. - If you want to do this, you should create the dialog - yourself using one of the QMessageBox constructors. + \warning Do not delete \a parent during the execution of the dialog. + If you want to do this, you should create the dialog + yourself using one of the QMessageBox constructors. \sa question(), warning(), information() */ diff --git a/src/gui/egl/qegl_symbian.cpp b/src/gui/egl/qegl_symbian.cpp index 6533d11..fabf9d1 100644 --- a/src/gui/egl/qegl_symbian.cpp +++ b/src/gui/egl/qegl_symbian.cpp @@ -42,6 +42,7 @@ #include <QtGui/qpaintdevice.h> #include <QtGui/qpixmap.h> #include <QtGui/qwidget.h> +#include <QtGui/private/qapplication_p.h> #include "qegl_p.h" #include "qeglcontext_p.h" @@ -73,10 +74,14 @@ void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) return; int devType = dev->devType(); - if (devType == QInternal::Image) + if (devType == QInternal::Image) { setPixelFormat(static_cast<QImage *>(dev)->format()); - else - setPixelFormat(QImage::Format_RGB32); + } else { + QImage::Format format = QImage::Format_RGB32; + if (QApplicationPrivate::instance() && QApplicationPrivate::instance()->useTranslucentEGLSurfaces) + format = QImage::Format_ARGB32_Premultiplied; + setPixelFormat(format); + } } diff --git a/src/gui/egl/qegl_x11.cpp b/src/gui/egl/qegl_x11.cpp index fb9ee9d..bf79ec7 100644 --- a/src/gui/egl/qegl_x11.cpp +++ b/src/gui/egl/qegl_x11.cpp @@ -330,10 +330,8 @@ void qt_set_winid_on_widget(QWidget* w, Qt::HANDLE id) // NOTE: The X11 version of createSurface will re-create the native drawable if it's visual doesn't // match the one for the passed in EGLConfig -EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEglProperties *unusedProperties) +EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEglProperties *properties) { - Q_UNUSED(unusedProperties); - int devType = device->devType(); if (devType == QInternal::Pbuffer) { @@ -417,7 +415,12 @@ EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig config, const QEg // At this point, the widget's window should be created and have the correct visual. Now we // just need to create the EGL surface for it: - EGLSurface surf = eglCreateWindowSurface(QEgl::display(), config, (EGLNativeWindowType)widget->winId(), 0); + const int *props; + if (properties) + props = properties->properties(); + else + props = 0; + EGLSurface surf = eglCreateWindowSurface(QEgl::display(), config, (EGLNativeWindowType)widget->winId(), props); if (surf == EGL_NO_SURFACE) qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); return surf; diff --git a/src/gui/embedded/qlock.cpp b/src/gui/embedded/qlock.cpp index b169a9b..d429b93 100644 --- a/src/gui/embedded/qlock.cpp +++ b/src/gui/embedded/qlock.cpp @@ -82,38 +82,27 @@ QT_END_NAMESPACE #else // QT_NO_QWS_MULTIPROCESS +#if defined(Q_OS_DARWIN) +# define Q_NO_SEMAPHORE +#endif + #include "qwssignalhandler_p.h" #include <unistd.h> #include <sys/types.h> -#if defined(Q_OS_DARWIN) -# define Q_NO_SEMAPHORE -# include <sys/stat.h> -# include <sys/file.h> -#else // Q_OS_DARWIN -# include <sys/sem.h> -# if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) && !defined(QT_LINUXBASE)) \ - || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD) \ - || defined(Q_OS_BSDI) - /* union semun is defined by including <sys/sem.h> */ -# else -/* according to X/OPEN we have to define it ourselves */ -union semun { - int val; /* value for SETVAL */ - struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ - unsigned short *array; /* array for GETALL, SETALL */ -}; -# endif -#endif // Q_OS_DARWIN #include <sys/ipc.h> +#if defined(Q_NO_SEMAPHORE) +# include <sys/stat.h> +# include <sys/file.h> +#else +# include <sys/sem.h> +#endif #include <string.h> #include <errno.h> #include <qdebug.h> -#include <signal.h> #include <private/qcore_unix_p.h> // overrides QT_OPEN - QT_BEGIN_NAMESPACE #define MAX_LOCKS 200 // maximum simultaneous read locks @@ -177,7 +166,7 @@ QLock::QLock(const QString &filename, char id, bool create) data->id = semget(semkey,0,0); data->owned = create; if (create) { - semun arg; arg.val = 0; + qt_semun arg; arg.val = 0; if (data->id != -1) semctl(data->id,0,IPC_RMID,arg); data->id = semget(semkey,1,IPC_CREAT|0600); diff --git a/src/gui/embedded/qscreen_qws.cpp b/src/gui/embedded/qscreen_qws.cpp index e207ed1..90561fd 100644 --- a/src/gui/embedded/qscreen_qws.cpp +++ b/src/gui/embedded/qscreen_qws.cpp @@ -64,7 +64,6 @@ QT_BEGIN_NAMESPACE // #define QT_USE_MEMCPY_DUFF #ifndef QT_NO_QWS_CURSOR -bool qt_sw_cursor=false; Q_GUI_EXPORT QScreenCursor * qt_screencursor = 0; #endif Q_GUI_EXPORT QScreen * qt_screen = 0; @@ -119,8 +118,6 @@ ClearCacheFunc QScreen::clearCacheFunc = 0; Returns a pointer to the application's unique screen cursor. */ -extern bool qws_sw_cursor; - /*! Constructs a screen cursor */ diff --git a/src/gui/embedded/qscreen_qws.h b/src/gui/embedded/qscreen_qws.h index 17ffbbb..85c775e 100644 --- a/src/gui/embedded/qscreen_qws.h +++ b/src/gui/embedded/qscreen_qws.h @@ -130,7 +130,7 @@ const int SourcePixmap=1; class QScreenCursor; extern QScreenCursor *qt_screencursor; -extern bool qt_sw_cursor; +extern bool qws_sw_cursor; class Q_GUI_EXPORT QScreenCursor { @@ -145,7 +145,7 @@ public: bool supportsAlphaCursor() const { return supportsAlpha; } - static bool enabled() { return qt_sw_cursor; } + static bool enabled() { return qws_sw_cursor; } QRect boundingRect() const { return QRect(pos - hotspot, size); } QImage image() const { return cursor; } diff --git a/src/gui/embedded/qvfbhdr.h b/src/gui/embedded/qvfbhdr.h index 31704b3..84f82ac 100644 --- a/src/gui/embedded/qvfbhdr.h +++ b/src/gui/embedded/qvfbhdr.h @@ -53,36 +53,37 @@ QT_BEGIN_NAMESPACE QT_MODULE(Gui) #ifndef QT_QWS_TEMP_DIR -#define QT_QWS_TEMP_DIR "/tmp" +# define QT_QWS_TEMP_DIR QLatin1String("/tmp") #endif #ifdef QT_PRIVATE_QWS -#define QT_VFB_DATADIR(DISPLAY) QString("%1/qtembedded-%2-%3") \ - .arg(QT_QWS_TEMP_DIR).arg(getuid()).arg(DISPLAY) - +#define QT_VFB_DATADIR(DISPLAY) QString::fromLatin1("%1/qtembedded-%2-%3") \ + .arg(QT_QWS_TEMP_DIR).arg(getuid()).arg(DISPLAY) #define QT_VFB_MOUSE_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/qtvfb_mouse") + .append(QLatin1String("/qtvfb_mouse")) #define QT_VFB_KEYBOARD_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/qtvfb_keyboard") + .append(QLatin1String("/qtvfb_keyboard")) #define QT_VFB_MAP(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/qtvfb_map") + .append(QLatin1String("/qtvfb_map")) #define QT_VFB_SOUND_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/qt_soundserver") + .append(QLatin1String("/qt_soundserver")) #define QTE_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/QtEmbedded") + .append(QLatin1String("/QtEmbedded")) #define QTE_PIPE_QVFB(DISPLAY) QTE_PIPE(DISPLAY) #else -#define QT_VFB_DATADIR(DISPLAY) QString("%1/qtembedded-%2") \ - .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) -#define QT_VFB_MOUSE_PIPE(DISPLAY) QString("/tmp/.qtvfb_mouse-%1").arg(DISPLAY) -#define QT_VFB_KEYBOARD_PIPE(DISPLAY) QString("/tmp/.qtvfb_keyboard-%1").arg(DISPLAY) -#define QT_VFB_MAP(DISPLAY) QString("/tmp/.qtvfb_map-%1").arg(DISPLAY) -#define QT_VFB_SOUND_PIPE(DISPLAY) QString("/tmp/.qt_soundserver-%1").arg(DISPLAY) -#define QTE_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/QtEmbedded-%1") \ - .arg(DISPLAY) -#define QTE_PIPE_QVFB(DISPLAY) QString("/tmp/qtembedded-%1/QtEmbedded-%1") \ - .arg(DISPLAY) +#define QT_VFB_DATADIR(DISPLAY) QString::fromLatin1("%1/qtembedded-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QT_VFB_MOUSE_PIPE(DISPLAY) QString::fromLatin1("%1/.qtvfb_mouse-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QT_VFB_KEYBOARD_PIPE(DISPLAY) QString::fromLatin1("%1/.qtvfb_keyboard-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QT_VFB_MAP(DISPLAY) QString::fromLatin1("%1/.qtvfb_map-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QT_VFB_SOUND_PIPE(DISPLAY) QString::fromLatin1("%1/.qt_soundserver-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QTE_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ + .append(QLatin1String("/QtEmbedded-%1")).arg(DISPLAY) +#define QTE_PIPE_QVFB(DISPLAY) QTE_PIPE(DISPLAY) #endif struct QVFbHeader diff --git a/src/gui/embedded/qwslock.cpp b/src/gui/embedded/qwslock.cpp index 5841841..324d813 100644 --- a/src/gui/embedded/qwslock.cpp +++ b/src/gui/embedded/qwslock.cpp @@ -60,21 +60,14 @@ #endif #include <unistd.h> +#include <private/qcore_unix_p.h> + QT_BEGIN_NAMESPACE #ifdef QT_NO_SEMAPHORE #error QWSLock currently requires semaphores #endif -#ifndef Q_OS_BSD4 -union semun { - int val; - struct semid_ds *buf; - unsigned short *array; - struct seminfo *__buf; -}; -#endif - QWSLock::QWSLock() { semId = semget(IPC_PRIVATE, 3, IPC_CREAT | 0666); @@ -85,7 +78,7 @@ QWSLock::QWSLock() } QWSSignalHandler::instance()->addSemaphore(semId); - semun semval; + qt_semun semval; semval.val = 1; if (semctl(semId, BackingStore, SETVAL, semval) == -1) { diff --git a/src/gui/embedded/qwssignalhandler.cpp b/src/gui/embedded/qwssignalhandler.cpp index 49b7e94..cc18beb 100644 --- a/src/gui/embedded/qwssignalhandler.cpp +++ b/src/gui/embedded/qwssignalhandler.cpp @@ -47,21 +47,13 @@ #ifndef QT_NO_QWS_MULTIPROCESS # include <sys/ipc.h> # include <sys/sem.h> + +# include <private/qcore_unix_p.h> #endif #include <signal.h> QT_BEGIN_NAMESPACE -#ifndef Q_OS_BSD4 -union semun { - int val; - struct semid_ds *buf; - unsigned short *array; - struct seminfo *__buf; -}; -#endif - - class QWSSignalHandlerPrivate : public QWSSignalHandler { public: @@ -106,7 +98,7 @@ void QWSSignalHandler::removeSemaphore(int semno) { const int index = semaphores.lastIndexOf(semno); if (index != -1) { - semun semval; + qt_semun semval; semval.val = 0; semctl(semaphores.at(index), 0, IPC_RMID, semval); semaphores.remove(index); @@ -121,7 +113,7 @@ void QWSSignalHandler::handleSignal(int signum) signal(signum, h->oldHandlers[signum]); #ifndef QT_NO_QWS_MULTIPROCESS - semun semval; + qt_semun semval; semval.val = 0; for (int i = 0; i < h->semaphores.size(); ++i) semctl(h->semaphores.at(i), 0, IPC_RMID, semval); diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.cpp b/src/gui/graphicsview/qgraphicsanchorlayout.cpp index 014b61b..9bb5424 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout.cpp @@ -56,7 +56,7 @@ Items that are anchored are automatically added to the layout, and if items are removed, all their anchors will be automatically removed. - \div {float-left} + \div {class="float-left"} \inlineimage simpleanchorlayout-example.png Using an anchor layout to align simple colored widgets. \enddiv diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 48cbec3..78918cc 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -451,8 +451,8 @@ static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal valu static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> &factor, qreal min, qreal minPref, qreal pref, qreal maxPref, qreal max) { - qreal lower; - qreal upper; + qreal lower = 0; + qreal upper = 0; switch (factor.first) { case QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred: diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 0af36ac..e67fe82 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -421,7 +421,7 @@ \omitvalue ItemStopsFocusHandling \omit Same as ItemStopsClickFocusPropagation, but also suppresses focus-out. This flag allows you to completely take over focus handling. - This flag was introduced in Qt 4.7. + This flag was introduced in Qt 4.7. \endomit */ /*! @@ -579,19 +579,21 @@ QGraphicsItem pointer). The return value is unused; you cannot adjust anything in this notification. - \value ItemSceneChange The item is moved to a new scene. This notification - is also sent when the item is added to its initial scene, and when it is - removed. The value argument is the new scene (i.e., a QGraphicsScene + \value ItemSceneChange The item is moved to a new scene. This notification is + also sent when the item is added to its initial scene, and when it is removed. + The item's scene() is the old scene (or 0 if the item has not been added to a + scene yet). The value argument is the new scene (i.e., a QGraphicsScene pointer), or a null pointer if the item is removed from a scene. Do not - override this change by passing this item to QGraphicsScene::addItem() as - this notification is delivered; instead, you can return the new scene from + override this change by passing this item to QGraphicsScene::addItem() as this + notification is delivered; instead, you can return the new scene from itemChange(). Use this feature with caution; objecting to a scene change can quickly lead to unwanted recursion. - \value ItemSceneHasChanged The item's scene has changed. The value - argument is the new scene (i.e., a pointer to a QGraphicsScene). Do not - call setScene() in itemChange() as this notification is delivered. The - return value is ignored. + \value ItemSceneHasChanged The item's scene has changed. The item's scene() is + the new scene. This notification is also sent when the item is added to its + initial scene, and when it is removed.The value argument is the new scene + (i.e., a pointer to a QGraphicsScene). Do not call setScene() in itemChange() + as this notification is delivered. The return value is ignored. \value ItemCursorChange The item's cursor changes. The value argument is the new cursor (i.e., a QCursor). Do not call setCursor() in itemChange() diff --git a/src/gui/graphicsview/qgraphicslayout.cpp b/src/gui/graphicsview/qgraphicslayout.cpp index 904a3de..a67ae48 100644 --- a/src/gui/graphicsview/qgraphicslayout.cpp +++ b/src/gui/graphicsview/qgraphicslayout.cpp @@ -167,7 +167,7 @@ QGraphicsLayout::QGraphicsLayout(QGraphicsLayoutItem *parent) " neither a QGraphicsWidget nor QGraphicsLayout"); } } - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType); + d_func()->sizePolicy = QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType); setOwnedByLayout(true); } @@ -188,7 +188,7 @@ QGraphicsLayout::QGraphicsLayout(QGraphicsLayoutPrivate &dd, QGraphicsLayoutItem " neither a QGraphicsWidget nor QGraphicsLayout"); } } - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType); + d_func()->sizePolicy = QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType); setOwnedByLayout(true); } @@ -269,12 +269,20 @@ void QGraphicsLayout::activate() return; Q_ASSERT(!parentItem->isLayout()); - setGeometry(parentItem->contentsRect()); // relayout children + if (QGraphicsLayout::instantInvalidatePropagation()) { + QGraphicsWidget *parentWidget = static_cast<QGraphicsWidget*>(parentItem); + if (!parentWidget->parentLayoutItem()) { + // we've reached the topmost widget, resize it + bool wasResized = parentWidget->testAttribute(Qt::WA_Resized); + parentWidget->resize(parentWidget->size()); + parentWidget->setAttribute(Qt::WA_Resized, wasResized); + } - // ### bug, should be parentItem ? - parentLayoutItem()->updateGeometry(); // bubble up; will set activated to false - // ### too many resizes? maybe we should walk up the chain to the - // ### top-level layouted layoutItem and call activate there. + setGeometry(parentItem->contentsRect()); // relayout children + } else { + setGeometry(parentItem->contentsRect()); // relayout children + parentLayoutItem()->updateGeometry(); + } } /*! @@ -300,32 +308,36 @@ bool QGraphicsLayout::isActivated() const */ void QGraphicsLayout::invalidate() { - // only mark layouts as invalid (activated = false) if we can post a LayoutRequest event. - QGraphicsLayoutItem *layoutItem = this; - while (layoutItem && layoutItem->isLayout()) { - // we could call updateGeometry(), but what if that method - // does not call the base implementation? In addition, updateGeometry() - // does more than we need. - layoutItem->d_func()->sizeHintCacheDirty = true; - layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true; - layoutItem = layoutItem->parentLayoutItem(); - } - if (layoutItem) { - layoutItem->d_func()->sizeHintCacheDirty = true; - layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true; - } - - bool postIt = layoutItem ? !layoutItem->isLayout() : false; - if (postIt) { - layoutItem = this; - while (layoutItem && layoutItem->isLayout() - && static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated) { - static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated = false; + if (QGraphicsLayout::instantInvalidatePropagation()) { + updateGeometry(); + } else { + // only mark layouts as invalid (activated = false) if we can post a LayoutRequest event. + QGraphicsLayoutItem *layoutItem = this; + while (layoutItem && layoutItem->isLayout()) { + // we could call updateGeometry(), but what if that method + // does not call the base implementation? In addition, updateGeometry() + // does more than we need. + layoutItem->d_func()->sizeHintCacheDirty = true; + layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true; layoutItem = layoutItem->parentLayoutItem(); } - if (layoutItem && !layoutItem->isLayout()) { - // If a layout has a parent that is not a layout it must be a QGraphicsWidget. - QApplication::postEvent(static_cast<QGraphicsWidget *>(layoutItem), new QEvent(QEvent::LayoutRequest)); + if (layoutItem) { + layoutItem->d_func()->sizeHintCacheDirty = true; + layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true; + } + + bool postIt = layoutItem ? !layoutItem->isLayout() : false; + if (postIt) { + layoutItem = this; + while (layoutItem && layoutItem->isLayout() + && static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated) { + static_cast<QGraphicsLayout*>(layoutItem)->d_func()->activated = false; + layoutItem = layoutItem->parentLayoutItem(); + } + if (layoutItem && !layoutItem->isLayout()) { + // If a layout has a parent that is not a layout it must be a QGraphicsWidget. + QApplication::postEvent(static_cast<QGraphicsWidget *>(layoutItem), new QEvent(QEvent::LayoutRequest)); + } } } } @@ -335,12 +347,27 @@ void QGraphicsLayout::invalidate() */ void QGraphicsLayout::updateGeometry() { - QGraphicsLayoutItem::updateGeometry(); - if (QGraphicsLayoutItem *parentItem = parentLayoutItem()) { - if (parentItem->isLayout()) { + Q_D(QGraphicsLayout); + if (QGraphicsLayout::instantInvalidatePropagation()) { + d->activated = false; + QGraphicsLayoutItem::updateGeometry(); + + QGraphicsLayoutItem *parentItem = parentLayoutItem(); + if (!parentItem) + return; + + if (parentItem->isLayout()) + static_cast<QGraphicsLayout *>(parentItem)->invalidate(); + else parentItem->updateGeometry(); - } else { - invalidate(); + } else { + QGraphicsLayoutItem::updateGeometry(); + if (QGraphicsLayoutItem *parentItem = parentLayoutItem()) { + if (parentItem->isLayout()) { + parentItem->updateGeometry(); + } else { + invalidate(); + } } } } @@ -446,6 +473,50 @@ void QGraphicsLayout::addChildLayoutItem(QGraphicsLayoutItem *layoutItem) d->addChildLayoutItem(layoutItem); } +static bool g_instantInvalidatePropagation = false; + +/*! + \internal + \since 4.8 + \see instantInvalidatePropagation + + Calling this function with \a enable set to true will enable a feature that + makes propagation of invalidation up to ancestor layout items to be done in + one go. It will propagate up the parentLayoutItem() hierarchy until it has + reached the root. If the root item is a QGraphicsWidget, it will *post* a + layout request to it. When the layout request is consumed it will traverse + down the hierarchy of layouts and widgets and activate all layouts that is + invalid (not activated). This is the recommended behaviour. + + If not set it will also propagate up the parentLayoutItem() hierarchy, but + it will stop at the \i first \i widget it encounters, and post a layout + request to the widget. When the layout request is consumed, this might + cause it to continue propagation up to the parentLayoutItem() of the + widget. It will continue in this fashion until it has reached a widget with + no parentLayoutItem(). This strategy might cause drawing artifacts, since + it is not done in one go, and the consumption of layout requests might be + interleaved by consumption of paint events, which might cause significant + flicker. + Note, this is not the recommended behavior, but for compatibility reasons + this is the default behaviour. +*/ +void QGraphicsLayout::setInstantInvalidatePropagation(bool enable) +{ + g_instantInvalidatePropagation = enable; +} + +/*! + \internal + \since 4.8 + \see setInstantInvalidatePropagation + + returns true if the complete widget/layout hierarchy is rearranged in one go. +*/ +bool QGraphicsLayout::instantInvalidatePropagation() +{ + return g_instantInvalidatePropagation; +} + QT_END_NAMESPACE #endif //QT_NO_GRAPHICSVIEW diff --git a/src/gui/graphicsview/qgraphicslayout.h b/src/gui/graphicsview/qgraphicslayout.h index c622fb8..6031174 100644 --- a/src/gui/graphicsview/qgraphicslayout.h +++ b/src/gui/graphicsview/qgraphicslayout.h @@ -76,6 +76,8 @@ public: virtual QGraphicsLayoutItem *itemAt(int i) const = 0; virtual void removeAt(int index) = 0; + static void setInstantInvalidatePropagation(bool enable); + static bool instantInvalidatePropagation(); protected: QGraphicsLayout(QGraphicsLayoutPrivate &, QGraphicsLayoutItem *); void addChildLayoutItem(QGraphicsLayoutItem *layoutItem); diff --git a/src/gui/graphicsview/qgraphicslayout_p.cpp b/src/gui/graphicsview/qgraphicslayout_p.cpp index c325602..f73fb6a 100644 --- a/src/gui/graphicsview/qgraphicslayout_p.cpp +++ b/src/gui/graphicsview/qgraphicslayout_p.cpp @@ -180,8 +180,13 @@ void QGraphicsLayoutPrivate::activateRecursive(QGraphicsLayoutItem *item) { if (item->isLayout()) { QGraphicsLayout *layout = static_cast<QGraphicsLayout *>(item); - if (layout->d_func()->activated) - layout->invalidate(); + if (layout->d_func()->activated) { + if (QGraphicsLayout::instantInvalidatePropagation()) { + return; + } else { + layout->invalidate(); // ### LOOKS SUSPICIOUSLY WRONG!!??? + } + } for (int i = layout->count() - 1; i >= 0; --i) { QGraphicsLayoutItem *childItem = layout->itemAt(i); diff --git a/src/gui/graphicsview/qgraphicslinearlayout.cpp b/src/gui/graphicsview/qgraphicslinearlayout.cpp index 5591638..40f9b1d 100644 --- a/src/gui/graphicsview/qgraphicslinearlayout.cpp +++ b/src/gui/graphicsview/qgraphicslinearlayout.cpp @@ -275,17 +275,13 @@ void QGraphicsLinearLayout::insertItem(int index, QGraphicsLayoutItem *item) qWarning("QGraphicsLinearLayout::insertItem: cannot insert itself"); return; } - Q_ASSERT(item); - - //the order of the following instructions is very important because - //invalidating the layout before adding the child item will make the layout happen - //before we try to paint the item - invalidate(); d->addChildLayoutItem(item); + Q_ASSERT(item); d->fixIndex(&index); d->engine.insertRow(index, d->orientation); new QGridLayoutItem(&d->engine, item, d->gridRow(index), d->gridColumn(index), 1, 1, 0, index); + invalidate(); } /*! diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 7932a73..0713d09 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -4948,6 +4948,19 @@ void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const Q if (painterStateProtection || restorePainterClip) painter->restore(); + + static int drawRect = qgetenv("QT_DRAW_SCENE_ITEM_RECTS").toInt(); + if (drawRect) { + QPen oldPen = painter->pen(); + QBrush oldBrush = painter->brush(); + quintptr ptr = reinterpret_cast<quintptr>(item); + const QColor color = QColor::fromHsv(ptr % 255, 255, 255); + painter->setPen(color); + painter->setBrush(Qt::NoBrush); + painter->drawRect(adjustedItemBoundingRect(item)); + painter->setPen(oldPen); + painter->setBrush(oldBrush); + } } // Draw children in front @@ -5966,9 +5979,6 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve } if (item && item->isPanel()) break; - if (item && (item->d_ptr->flags - & (QGraphicsItem::ItemStopsClickFocusPropagation | QGraphicsItem::ItemStopsFocusHandling))) - break; } touchEvent->setAccepted(eventAccepted); diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp index 92e4a55..4688fa0 100644 --- a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp +++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp @@ -50,14 +50,14 @@ QGraphicsSceneBspTreeIndex index use a BSP(Binary Space Partitioning) implementation to discover items quickly. This implementation is - very efficient for static scene. It has a depth that you can set. + very efficient for static scenes. It has a depth that you can set. The depth directly affects performance and memory usage; the latter growing exponentially with the depth of the tree. With an optimal tree depth, the index can instantly determine the locality of items, even for scenes with thousands or millions of items. This also greatly improves rendering performance. - By default, the value is 0, in which case Qt will guess a reasonable + By default, the depth value is 0, in which case Qt will guess a reasonable default depth based on the size, location and number of items in the scene. If these parameters change frequently, however, you may experience slowdowns as the index retunes the depth internally. You can avoid diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp index 06df788..513c41f 100644 --- a/src/gui/graphicsview/qgraphicstransform.cpp +++ b/src/gui/graphicsview/qgraphicstransform.cpp @@ -92,6 +92,7 @@ #include "qgraphicstransform_p.h" #include <QDebug> #include <QtCore/qmath.h> +#include <QtCore/qnumeric.h> #ifndef QT_NO_GRAPHICSVIEW QT_BEGIN_NAMESPACE @@ -467,6 +468,7 @@ void QGraphicsRotation::setOrigin(const QVector3D &point) item will be rotated counter-clockwise. Normally the rotation angle will be in the range (-360, 360), but you can also provide numbers outside of this range (e.g., a angle of 370 degrees gives the same result as 10 degrees). + Setting the angle to NaN results in no rotation. \sa origin */ @@ -570,7 +572,7 @@ void QGraphicsRotation::applyTo(QMatrix4x4 *matrix) const { Q_D(const QGraphicsRotation); - if (d->angle == 0. || d->axis.isNull()) + if (d->angle == 0. || d->axis.isNull() || qIsNaN(d->angle)) return; matrix->translate(d->origin); diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 0e2750d..488a36a 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2497,7 +2497,7 @@ QVariant QGraphicsView::inputMethodQuery(Qt::InputMethodQuery query) const else if (value.type() == QVariant::PointF) value = mapFromScene(value.toPointF()); else if (value.type() == QVariant::Rect) - value = mapFromScene(value.toRect()).boundingRect(); + value = d->mapRectFromScene(value.toRect()).toRect(); else if (value.type() == QVariant::Point) value = mapFromScene(value.toPoint()); return value; diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 675a5c5..141e305 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -354,8 +354,10 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) newGeom = rect; newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize)) .boundedTo(effectiveSizeHint(Qt::MaximumSize))); - if (newGeom == d->geom) - return; + + if (newGeom == d->geom) { + goto relayoutChildrenAndReturn; + } // setPos triggers ItemPositionChange, which can adjust position wd->inSetGeometry = 1; @@ -363,8 +365,9 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) wd->inSetGeometry = 0; newGeom.moveTopLeft(pos()); - if (newGeom == d->geom) - return; + if (newGeom == d->geom) { + goto relayoutChildrenAndReturn; + } // Update and prepare to change the geometry (remove from index) if the size has changed. if (wd->scene) { @@ -375,35 +378,54 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) } // Update the layout item geometry - bool moved = oldPos != pos(); - if (moved) { - // Send move event. - QGraphicsSceneMoveEvent event; - event.setOldPos(oldPos); - event.setNewPos(pos()); - QApplication::sendEvent(this, &event); - if (wd->inSetPos) { - //set the new pos - d->geom.moveTopLeft(pos()); - emit geometryChanged(); - return; + { + bool moved = oldPos != pos(); + if (moved) { + // Send move event. + QGraphicsSceneMoveEvent event; + event.setOldPos(oldPos); + event.setNewPos(pos()); + QApplication::sendEvent(this, &event); + if (wd->inSetPos) { + //set the new pos + d->geom.moveTopLeft(pos()); + emit geometryChanged(); + goto relayoutChildrenAndReturn; + } + } + QSizeF oldSize = size(); + QGraphicsLayoutItem::setGeometry(newGeom); + // Send resize event + bool resized = newGeom.size() != oldSize; + if (resized) { + QGraphicsSceneResizeEvent re; + re.setOldSize(oldSize); + re.setNewSize(newGeom.size()); + if (oldSize.width() != newGeom.size().width()) + emit widthChanged(); + if (oldSize.height() != newGeom.size().height()) + emit heightChanged(); + QGraphicsLayout *lay = wd->layout; + if (QGraphicsLayout::instantInvalidatePropagation()) { + if (!lay || lay->isActivated()) { + QApplication::sendEvent(this, &re); + } + } else { + QApplication::sendEvent(this, &re); + } } } - QSizeF oldSize = size(); - QGraphicsLayoutItem::setGeometry(newGeom); - // Send resize event - bool resized = newGeom.size() != oldSize; - if (resized) { - QGraphicsSceneResizeEvent re; - re.setOldSize(oldSize); - re.setNewSize(newGeom.size()); - if (oldSize.width() != newGeom.size().width()) - emit widthChanged(); - if (oldSize.height() != newGeom.size().height()) - emit heightChanged(); - QApplication::sendEvent(this, &re); - } + emit geometryChanged(); +relayoutChildrenAndReturn: + if (QGraphicsLayout::instantInvalidatePropagation()) { + if (QGraphicsLayout *lay = wd->layout) { + if (!lay->isActivated()) { + QEvent layoutRequest(QEvent::LayoutRequest); + QApplication::sendEvent(this, &layoutRequest); + } + } + } } /*! @@ -1052,16 +1074,31 @@ void QGraphicsWidget::updateGeometry() QGraphicsLayoutItem *parentItem = parentLayoutItem(); if (parentItem && parentItem->isLayout()) { - parentItem->updateGeometry(); + if (QGraphicsLayout::instantInvalidatePropagation()) { + static_cast<QGraphicsLayout *>(parentItem)->invalidate(); + } else { + parentItem->updateGeometry(); + } } else { if (parentItem) { + // This is for custom layouting QGraphicsWidget *parentWid = parentWidget(); //### if (parentWid->isVisible()) QApplication::postEvent(parentWid, new QEvent(QEvent::LayoutRequest)); + } else { + /** + * If this is the topmost widget, post a LayoutRequest event to the widget. + * When the event is received, it will start flowing all the way down to the leaf + * widgets in one go. This will make a relayout flicker-free. + */ + if (QGraphicsLayout::instantInvalidatePropagation()) + QApplication::postEvent(static_cast<QGraphicsWidget *>(this), new QEvent(QEvent::LayoutRequest)); + } + if (!QGraphicsLayout::instantInvalidatePropagation()) { + bool wasResized = testAttribute(Qt::WA_Resized); + resize(size()); // this will restrict the size + setAttribute(Qt::WA_Resized, wasResized); } - bool wasResized = testAttribute(Qt::WA_Resized); - resize(size()); // this will restrict the size - setAttribute(Qt::WA_Resized, wasResized); } } diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp index 4580055..63d7298 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.cpp +++ b/src/gui/graphicsview/qgraphicswidget_p.cpp @@ -857,8 +857,6 @@ void QGraphicsWidgetPrivate::setWidth(qreal w) if (q->geometry().width() == w) return; - QRectF oldGeom = q->geometry(); - q->setGeometry(QRectF(q->x(), q->y(), w, height())); } @@ -882,8 +880,6 @@ void QGraphicsWidgetPrivate::setHeight(qreal h) if (q->geometry().height() == h) return; - QRectF oldGeom = q->geometry(); - q->setGeometry(QRectF(q->x(), q->y(), width(), h)); } diff --git a/src/gui/gui.pro b/src/gui/gui.pro index fda76a2..8f72fea 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -55,11 +55,9 @@ DEFINES += Q_INTERNAL_QAPP_SRC symbian { TARGET.UID3=0x2001B2DD - symbian-abld|symbian-sbsv2 { - # ro-section in gui can exceed default allocated space, so move rw-section a little further - QMAKE_LFLAGS.ARMCC += --rw-base 0x800000 - QMAKE_LFLAGS.GCCE += -Tdata 0xC00000 - } + # ro-section in gui can exceed default allocated space, so move rw-section a little further + QMAKE_LFLAGS.ARMCC += --rw-base 0x800000 + QMAKE_LFLAGS.GCCE += -Tdata 0x800000 } neon:*-g++* { diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 158f9ab..7182062 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -972,12 +972,15 @@ QString QIcon::themeName() Returns the QIcon corresponding to \a name in the current icon theme. If no such icon is found in the current theme - \a fallback is return instead. + \a fallback is returned instead. - The lastest version of the freedesktop icon specification and naming - spesification can be obtained here: - http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html - http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html + The latest version of the freedesktop icon specification and naming + specification can be obtained here: + + \list + \o \l{http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html} + \o \l{http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html} + \endlist To fetch an icon from the current icon theme: diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index d992dd5..50b372e 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -65,6 +65,7 @@ #include <private/qpaintengine_raster_p.h> #include <private/qimage_p.h> +#include <private/qfont_p.h> QT_BEGIN_NAMESPACE @@ -119,9 +120,6 @@ const QVector<QRgb> *qt_image_colortable(const QImage &image) return &image.d->colortable; } -Q_GUI_EXPORT extern int qt_defaultDpiX(); -Q_GUI_EXPORT extern int qt_defaultDpiY(); - QBasicAtomicInt qimage_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1); QImageData::QImageData() @@ -797,6 +795,8 @@ QImage::QImage() Constructs an image with the given \a width, \a height and \a format. + A \l{isNull()}{null} image will be returned if memory cannot be allocated. + \warning This will create a QImage with uninitialized data. Call fill() to fill the image with an appropriate pixel value before drawing onto it with QPainter. @@ -810,6 +810,8 @@ QImage::QImage(int width, int height, Format format) /*! Constructs an image with the given \a size and \a format. + A \l{isNull()}{null} image is returned if memory cannot be allocated. + \warning This will create a QImage with uninitialized data. Call fill() to fill the image with an appropriate pixel value before drawing onto it with QPainter. diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index ab05bf1..0a0dc35 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -1482,6 +1482,9 @@ QByteArray QImageReader::imageFormat(QIODevice *device) configure script or check the appropriate option in the graphical installer. + Note that the QApplication instance must be created before this function is + called. + \sa setFormat(), QImageWriter::supportedImageFormats(), QImageIOPlugin */ QList<QByteArray> QImageReader::supportedImageFormats() diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index 8a65ac0..504260a 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -679,6 +679,9 @@ bool QImageWriter::supportsOption(QImageIOHandler::ImageOption option) const Reading and writing SVG files is supported through Qt's \l{QtSvg Module}{SVG Module}. + Note that the QApplication instance must be created before this function is + called. + \sa setFormat(), QImageReader::supportedImageFormats(), QImageIOPlugin */ QList<QByteArray> QImageWriter::supportedImageFormats() diff --git a/src/gui/image/qpaintengine_pic.cpp b/src/gui/image/qpaintengine_pic.cpp index a8683b5..6f0979a 100644 --- a/src/gui/image/qpaintengine_pic.cpp +++ b/src/gui/image/qpaintengine_pic.cpp @@ -477,8 +477,6 @@ void QPicturePaintEngine::drawImage(const QRectF &r, const QImage &image, const writeCmdLength(pos, r, false); } -Q_GUI_EXPORT extern int qt_defaultDpi(); - void QPicturePaintEngine::drawTextItem(const QPointF &p , const QTextItem &ti) { Q_D(QPicturePaintEngine); diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp index 053d1fc..3f38c0c 100644 --- a/src/gui/image/qpicture.cpp +++ b/src/gui/image/qpicture.cpp @@ -46,6 +46,7 @@ #include <private/qfactoryloader_p.h> #include <private/qpaintengine_pic_p.h> +#include <private/qfont_p.h> #include "qdatastream.h" #include "qfile.h" @@ -108,8 +109,6 @@ void qt_format_text(const QFont &fnt, const QRectF &_r, const char *qt_mfhdr_tag = "QPIC"; // header tag static const quint16 mfhdr_maj = 11; // major version # static const quint16 mfhdr_min = 0; // minor version # -Q_GUI_EXPORT extern int qt_defaultDpiX(); -Q_GUI_EXPORT extern int qt_defaultDpiY(); /*! Constructs an empty picture. diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 34804e5..c34f6ac 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1224,12 +1224,8 @@ Qt::HANDLE QPixmap::handle() const { #if defined(Q_WS_X11) const QPixmapData *pd = pixmapData(); - if (pd) { - if (pd->classId() == QPixmapData::X11Class) - return static_cast<const QX11PixmapData*>(pd)->handle(); - else - qWarning("QPixmap::handle(): Pixmap is not an X11 class pixmap"); - } + if (pd && pd->classId() == QPixmapData::X11Class) + return static_cast<const QX11PixmapData*>(pd)->handle(); #endif return 0; } diff --git a/src/gui/image/qpixmap_blitter.cpp b/src/gui/image/qpixmap_blitter.cpp index 26d3b87..e2cd745 100644 --- a/src/gui/image/qpixmap_blitter.cpp +++ b/src/gui/image/qpixmap_blitter.cpp @@ -49,6 +49,7 @@ #include <private/qblittable_p.h> #include <private/qdrawhelper_p.h> +#include <private/qfont_p.h> #ifndef QT_NO_BLITTABLE QT_BEGIN_NAMESPACE @@ -104,8 +105,6 @@ void QBlittablePixmapData::resize(int width, int height) h = height; is_null = (w <= 0 || h <= 0); } -Q_GUI_EXPORT extern int qt_defaultDpiX(); -Q_GUI_EXPORT extern int qt_defaultDpiY(); int QBlittablePixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const { diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index a5f42c1..0a4d921 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -41,6 +41,8 @@ #include "qpixmap.h" +#include <private/qfont_p.h> + #include "qpixmap_raster_p.h" #include "qnativeimage_p.h" #include "qimage_p.h" @@ -346,9 +348,6 @@ QPaintEngine* QRasterPixmapData::paintEngine() const return image.paintEngine(); } -Q_GUI_EXPORT extern int qt_defaultDpiX(); -Q_GUI_EXPORT extern int qt_defaultDpiY(); - int QRasterPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const { QImageData *d = image.d; diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index 32d8dd7..c8aa003 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -46,6 +46,7 @@ #include <private/qgraphicssystem_p.h> #include <private/qt_s60_p.h> #include <private/qpaintengine_s60_p.h> +#include <private/qfont_p.h> #include "qpixmap.h" #include "qpixmap_raster_p.h" @@ -601,9 +602,6 @@ bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect) return res; } -Q_GUI_EXPORT int qt_defaultDpiX(); -Q_GUI_EXPORT int qt_defaultDpiY(); - int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const { if (!cfbsBitmap) diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index 41fc6e9..ae772d8 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -91,9 +91,7 @@ QT_BEGIN_NAMESPACE \sa QCache, QPixmap */ -#if defined(Q_OS_SYMBIAN) -static int cache_limit = 1024; // 1048 KB cache limit for symbian -#elif defined(Q_WS_QWS) || defined(Q_WS_WINCE) +#if defined(Q_WS_QWS) || defined(Q_WS_WINCE) static int cache_limit = 2048; // 2048 KB cache limit for embedded #else static int cache_limit = 10240; // 10 MB cache limit for desktop diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 4d5694f..c2a8b00 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -219,6 +219,7 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, float scre png_colorp palette = 0; int num_palette; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); + png_set_interlace_handling(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { // Black & White or 8-bit grayscale @@ -506,8 +507,8 @@ bool Q_INTERNAL_WIN_NO_THROW QPngHandlerPrivate::readPngImage(QImage *outImage) state = ReadingEnd; png_read_end(png_ptr, end_info); - readPngTexts(end_info); #ifndef QT_NO_IMAGE_TEXT + readPngTexts(end_info); for (int i = 0; i < readTexts.size()-1; i+=2) outImage->setText(readTexts.at(i), readTexts.at(i+1)); #endif diff --git a/src/gui/image/qvolatileimage.cpp b/src/gui/image/qvolatileimage.cpp index 098e9a1..f5076e1 100644 --- a/src/gui/image/qvolatileimage.cpp +++ b/src/gui/image/qvolatileimage.cpp @@ -103,6 +103,11 @@ QVolatileImage &QVolatileImage::operator=(const QVolatileImage &rhs) return *this; } +bool QVolatileImage::paintingActive() const +{ + return d->pengine && d->pengine->isActive(); +} + bool QVolatileImage::isNull() const { return d->image.isNull(); diff --git a/src/gui/image/qvolatileimage_p.h b/src/gui/image/qvolatileimage_p.h index fc5d6b1..d835f45 100644 --- a/src/gui/image/qvolatileimage_p.h +++ b/src/gui/image/qvolatileimage_p.h @@ -71,6 +71,7 @@ public: ~QVolatileImage(); QVolatileImage &operator=(const QVolatileImage &rhs); + bool paintingActive() const; bool isNull() const; QImage::Format format() const; int width() const; diff --git a/src/gui/image/qvolatileimagedata.cpp b/src/gui/image/qvolatileimagedata.cpp index 51b5995..d7b964c 100644 --- a/src/gui/image/qvolatileimagedata.cpp +++ b/src/gui/image/qvolatileimagedata.cpp @@ -68,6 +68,7 @@ QVolatileImageData::QVolatileImageData(void *, void *) } QVolatileImageData::QVolatileImageData(const QVolatileImageData &other) + : QSharedData() { image = other.image; // The detach is not mandatory here but we do it nonetheless in order to diff --git a/src/gui/inputmethod/qcoefepinputcontext_p.h b/src/gui/inputmethod/qcoefepinputcontext_p.h index de3577f..57c1e45 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_p.h +++ b/src/gui/inputmethod/qcoefepinputcontext_p.h @@ -168,6 +168,7 @@ private: }; Q_GUI_EXPORT void qt_s60_setPartialScreenInputMode(bool enable); +Q_GUI_EXPORT void qt_s60_setPartialScreenAutomaticTranslation(bool enable); QT_END_NAMESPACE diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index 9d8dd41..a4d53c0 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -77,6 +77,20 @@ QT_BEGIN_NAMESPACE Q_GUI_EXPORT void qt_s60_setPartialScreenInputMode(bool enable) { S60->partial_keyboard = enable; + + QInputContext *ic = 0; + if (QApplication::focusWidget()) { + ic = QApplication::focusWidget()->inputContext(); + } else if (qApp && qApp->inputContext()) { + ic = qApp->inputContext(); + } + if (ic) + ic->update(); +} + +Q_GUI_EXPORT void qt_s60_setPartialScreenAutomaticTranslation(bool enable) +{ + S60->partial_keyboardAutoTranslation = enable; } QCoeFepInputContext::QCoeFepInputContext(QObject *parent) @@ -108,7 +122,7 @@ QCoeFepInputContext::QCoeFepInputContext(QObject *parent) m_fepState->SetDefaultCase( EAknEditorTextCase ); m_fepState->SetPermittedCases( EAknEditorAllCaseModes ); m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); - m_fepState->SetNumericKeymap( EAknEditorStandardNumberModeKeymap ); + m_fepState->SetNumericKeymap(EAknEditorAlphanumericNumberModeKeymap); } QCoeFepInputContext::~QCoeFepInputContext() @@ -231,7 +245,7 @@ bool QCoeFepInputContext::filterEvent(const QEvent *event) // It ignores the mouse event, so we need to commit and send a selection event (which will get triggered // after the commit) if (!m_preeditString.isEmpty()) { - commitCurrentString(false); + commitCurrentString(true); int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt(); @@ -246,9 +260,13 @@ bool QCoeFepInputContext::filterEvent(const QEvent *event) // fall through intended case QEvent::KeyRelease: const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event); + //If proxy exists, always use hints from proxy. + QWidget *proxy = focusWidget()->focusProxy(); + Qt::InputMethodHints currentHints = proxy ? proxy->inputMethodHints() : focusWidget()->inputMethodHints(); + switch (keyEvent->key()) { case Qt::Key_F20: - Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints()); + Q_ASSERT(m_lastImHints == currentHints); if (m_lastImHints & Qt::ImhHiddenText) { // Special case in Symbian. On editors with secret text, F20 is for some reason // considered to be a backspace. @@ -278,7 +296,7 @@ bool QCoeFepInputContext::filterEvent(const QEvent *event) } if (keyEvent->type() == QEvent::KeyPress - && focusWidget()->inputMethodHints() & Qt::ImhHiddenText + && currentHints & Qt::ImhHiddenText && !keyEvent->text().isEmpty()) { // Send some temporary preedit text in order to make text visible for a moment. m_preeditString = keyEvent->text(); @@ -330,6 +348,23 @@ bool QCoeFepInputContext::symbianFilterEvent(QWidget *keyWidget, const QSymbianE // This should also happen for commands. reset(); + if (event->type() == QSymbianEvent::WindowServerEvent + && event->windowServerEvent() + && event->windowServerEvent()->Type() == EEventWindowVisibilityChanged + && S60->splitViewLastWidget) { + + QGraphicsView *gv = qobject_cast<QGraphicsView*>(S60->splitViewLastWidget); + const bool alwaysResize = (gv && gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff); + + if (alwaysResize) { + TUint visibleFlags = event->windowServerEvent()->VisibilityChanged()->iFlags; + if (visibleFlags & TWsVisibilityChangedEvent::EPartiallyVisible) + ensureFocusWidgetVisible(S60->splitViewLastWidget); + if (visibleFlags & TWsVisibilityChangedEvent::ENotVisible) + resetSplitViewWidget(true); + } + } + return false; } @@ -394,9 +429,15 @@ void QCoeFepInputContext::resetSplitViewWidget(bool keepInputWidget) if (!alwaysResize) { if (gv->scene()) { - if (gv->scene()->focusItem()) - disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); - QGraphicsItem *rootItem; + if (gv->scene()->focusItem()) { + // Check if the widget contains cursorPositionChanged signal and disconnect from it. + QByteArray signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged())); + int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal.right(signal.length() - 1)); + if (index != -1) + disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); + } + + QGraphicsItem *rootItem = 0; foreach (QGraphicsItem *item, gv->scene()->items()) { if (!item->parentItem()) { rootItem = item; @@ -484,6 +525,13 @@ void QCoeFepInputContext::ensureFocusWidgetVisible(QWidget *widget) // states getting changed. if (!moveWithinVisibleArea) { + // Check if the widget contains cursorPositionChanged signal and connect to it. + QByteArray signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged())); + if (gv->scene() && gv->scene()->focusItem()) { + int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal.right(signal.length() - 1)); + if (index != -1) + connect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); + } S60->splitViewLastWidget = widget; m_splitViewPreviousWindowStates = windowToMove->windowState(); } @@ -501,35 +549,33 @@ void QCoeFepInputContext::ensureFocusWidgetVisible(QWidget *widget) // and greatly reduces event passing in orientation switch cases, // as the statuspane size is not changing. + if (alwaysResize) + windowToMove->setUpdatesEnabled(false); + if (!(windowToMove->windowState() & Qt::WindowFullScreen)) { windowToMove->setWindowState( (windowToMove->windowState() & ~(Qt::WindowMinimized | Qt::WindowFullScreen)) | Qt::WindowFullScreen); } if (alwaysResize) { - windowToMove->setUpdatesEnabled(false); - if (!moveWithinVisibleArea) + if (!moveWithinVisibleArea) { m_splitViewResizeBy = widget->height(); + windowTop = widget->geometry().top(); + widget->resize(widget->width(), splitViewRect.height() - windowTop); + } - windowTop = widget->geometry().top(); - widget->resize(widget->width(), splitViewRect.height() - windowTop); - - if (gv->scene()) { + if (gv->scene() && S60->partial_keyboardAutoTranslation) { const QRectF microFocusRect = gv->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF(); gv->ensureVisible(microFocusRect); } - windowToMove->setUpdatesEnabled(true); } else { - if (!moveWithinVisibleArea) { - // Check if the widget contains cursorPositionChanged signal and connect to it. - const char *signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged())).constData(); - int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal + 1); - if (index != -1) - connect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); - } - translateInputWidget(); + if (S60->partial_keyboardAutoTranslation) + translateInputWidget(); } + if (alwaysResize) + windowToMove->setUpdatesEnabled(true); + widget->setAttribute(Qt::WA_Resized, userResize); //not a user resize } @@ -552,7 +598,21 @@ void QCoeFepInputContext::updateHints(bool mustUpdateInputCapabilities) { QWidget *w = focusWidget(); if (w) { - Qt::InputMethodHints hints = w->inputMethodHints(); + QWidget *proxy = w->focusProxy(); + Qt::InputMethodHints hints = proxy ? proxy->inputMethodHints() : w->inputMethodHints(); + + // Since splitview support works like an input method hint, yet it is private flag, + // we need to update its state separately. + if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) { + TInt currentFlags = m_fepState->Flags(); + if (S60->partial_keyboard) + currentFlags |= QT_EAknEditorFlagEnablePartialScreen; + else + currentFlags &= ~QT_EAknEditorFlagEnablePartialScreen; + if (currentFlags != m_fepState->Flags()) + m_fepState->SetFlags(currentFlags); + } + if (hints != m_lastImHints) { m_lastImHints = hints; applyHints(hints); @@ -705,6 +765,8 @@ void QCoeFepInputContext::applyHints(Qt::InputMethodHints hints) m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_EMAIL_ADDR_SPECIAL_CHARACTER_TABLE_DIALOG); } else if (needsCharMap) { m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); + } else if ((hints & ImhFormattedNumbersOnly) || (hints & ImhDialableCharactersOnly)) { + m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); } else { m_fepState->SetSpecialCharacterTableResourceId(0); } @@ -808,7 +870,7 @@ void QCoeFepInputContext::translateInputWidget() return; // Fetch root item (i.e. graphicsitem with no parent) - QGraphicsItem *rootItem; + QGraphicsItem *rootItem = 0; foreach (QGraphicsItem *item, gv->scene()->items()) { if (!item->parentItem()) { rootItem = item; diff --git a/src/gui/inputmethod/qinputcontext.cpp b/src/gui/inputmethod/qinputcontext.cpp index 063aefd..f083e51 100644 --- a/src/gui/inputmethod/qinputcontext.cpp +++ b/src/gui/inputmethod/qinputcontext.cpp @@ -355,9 +355,10 @@ void QInputContext::widgetDestroyed(QWidget *widget) in complex input method. In the case, call QInputContext::reset() to ensure proper termination of inputting. - You must not send any QInputMethodEvent except empty InputMethodEnd event using - QInputContext::reset() at reimplemented reset(). It will break - input state consistency. + In a reimplementation of reset(), you must not send any + QInputMethodEvent containing preedit text. You can only commit + string and attributes; otherwise, you risk breaking input state + consistency. */ diff --git a/src/gui/itemviews/itemviews.pri b/src/gui/itemviews/itemviews.pri index bbc1e98..149bfd6 100644 --- a/src/gui/itemviews/itemviews.pri +++ b/src/gui/itemviews/itemviews.pri @@ -4,6 +4,7 @@ HEADERS += \ itemviews/qabstractitemview.h \ itemviews/qabstractitemview_p.h \ itemviews/qheaderview.h \ + itemviews/qidentityproxymodel.h \ itemviews/qlistview.h \ itemviews/qlistview_p.h \ itemviews/qbsptree_p.h \ @@ -44,6 +45,7 @@ HEADERS += \ SOURCES += \ itemviews/qabstractitemview.cpp \ itemviews/qheaderview.cpp \ + itemviews/qidentityproxymodel.cpp \ itemviews/qlistview.cpp \ itemviews/qbsptree.cpp \ itemviews/qtableview.cpp \ diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 291ec6e..d671496 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -194,6 +194,8 @@ void QAbstractItemViewPrivate::checkMouseMove(const QPersistentModelIndex &index } } +#ifndef QT_NO_GESTURES + // stores and restores the selection and current item when flicking void QAbstractItemViewPrivate::_q_scrollerStateChanged() { @@ -225,6 +227,7 @@ void QAbstractItemViewPrivate::_q_scrollerStateChanged() } } +#endif // QT_NO_GESTURES /*! \class QAbstractItemView @@ -1661,7 +1664,9 @@ bool QAbstractItemView::viewportEvent(QEvent *event) break; case QEvent::ScrollPrepare: executeDelayedItemsLayout(); +#ifndef QT_NO_GESTURES connect(QScroller::scroller(d->viewport), SIGNAL(stateChanged(QScroller::State)), this, SLOT(_q_scrollerStateChanged()), Qt::UniqueConnection); +#endif break; default: diff --git a/src/gui/itemviews/qabstractitemview.h b/src/gui/itemviews/qabstractitemview.h index 20cfb87..f11f209 100644 --- a/src/gui/itemviews/qabstractitemview.h +++ b/src/gui/itemviews/qabstractitemview.h @@ -359,7 +359,9 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed()) Q_PRIVATE_SLOT(d_func(), void _q_layoutChanged()) Q_PRIVATE_SLOT(d_func(), void _q_headerDataChanged()) +#ifndef QT_NO_GESTURES Q_PRIVATE_SLOT(d_func(), void _q_scrollerStateChanged()) +#endif friend class QTreeViewPrivate; // needed to compile with MSVC friend class QAccessibleItemRow; diff --git a/src/gui/itemviews/qabstractproxymodel.cpp b/src/gui/itemviews/qabstractproxymodel.cpp index 34ca7df..82b6c8d 100644 --- a/src/gui/itemviews/qabstractproxymodel.cpp +++ b/src/gui/itemviews/qabstractproxymodel.cpp @@ -121,15 +121,12 @@ QAbstractProxyModel::~QAbstractProxyModel() void QAbstractProxyModel::setSourceModel(QAbstractItemModel *sourceModel) { Q_D(QAbstractProxyModel); - if (d->model) { + if (d->model) disconnect(d->model, SIGNAL(destroyed()), this, SLOT(_q_sourceModelDestroyed())); - disconnect(d->model, SIGNAL(modelReset()), this, SLOT(resetInternalData())); - } if (sourceModel) { d->model = sourceModel; connect(d->model, SIGNAL(destroyed()), this, SLOT(_q_sourceModelDestroyed())); - connect(d->model, SIGNAL(modelReset()), this, SLOT(resetInternalData())); } else { d->model = QAbstractItemModelPrivate::staticEmptyModel(); } @@ -383,25 +380,6 @@ Qt::DropActions QAbstractProxyModel::supportedDropActions() const return d->model->supportedDropActions(); } -/* - \since 4.8 - - This slot is called just after the internal data of a model is cleared - while it is being reset. - - This slot is provided the convenience of subclasses of concrete proxy - models, such as subclasses of QSortFilterProxyModel which maintain extra - data. - - \snippet doc/src/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp 10 - - \sa modelAboutToBeReset(), modelReset() -*/ -void QAbstractProxyModel::resetInternalData() -{ - -} - QT_END_NAMESPACE #include "moc_qabstractproxymodel.cpp" diff --git a/src/gui/itemviews/qabstractproxymodel.h b/src/gui/itemviews/qabstractproxymodel.h index 6e485ae..4f3bc18 100644 --- a/src/gui/itemviews/qabstractproxymodel.h +++ b/src/gui/itemviews/qabstractproxymodel.h @@ -95,9 +95,6 @@ public: QStringList mimeTypes() const; Qt::DropActions supportedDropActions() const; -protected Q_SLOTS: - void resetInternalData(); - protected: QAbstractProxyModel(QAbstractProxyModelPrivate &, QObject *parent); diff --git a/src/gui/itemviews/qdatawidgetmapper.cpp b/src/gui/itemviews/qdatawidgetmapper.cpp index 745ef5a..dac4613 100644 --- a/src/gui/itemviews/qdatawidgetmapper.cpp +++ b/src/gui/itemviews/qdatawidgetmapper.cpp @@ -291,7 +291,7 @@ void QDataWidgetMapperPrivate::_q_modelDestroyed() \snippet doc/src/snippets/code/src_gui_itemviews_qdatawidgetmapper.cpp 0 After the call to toFirst(), \c mySpinBox displays the value \c{1}, \c myLineEdit - displays \c {Nokia Corporation and/or its subsidiary(-ies)} and \c myCountryChooser displays \c{Oslo}. The + displays \c{Qt Norway} and \c myCountryChooser displays \c{Oslo}. The navigational functions toFirst(), toNext(), toPrevious(), toLast() and setCurrentIndex() can be used to navigate in the model and update the widgets with contents from the model. diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp index d6d9536..471c199 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -643,8 +643,12 @@ int QHeaderView::sectionSize(int logicalIndex) const } /*! - Returns the section position of the given \a logicalIndex, or -1 if the - section is hidden. + + Returns the section position of the given \a logicalIndex, or -1 + if the section is hidden. The position is measured in pixels from + the first visible item's top-left corner to the top-left corner of + the item with \a logicalIndex. The measurement is along the x-axis + for horizontal headers and along the y-axis for vertical headers. \sa sectionViewportPosition() */ diff --git a/src/gui/itemviews/qidentityproxymodel.cpp b/src/gui/itemviews/qidentityproxymodel.cpp new file mode 100644 index 0000000..60f7d98 --- /dev/null +++ b/src/gui/itemviews/qidentityproxymodel.cpp @@ -0,0 +1,587 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> +** 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 "qidentityproxymodel.h" + +#ifndef QT_NO_IDENTITYPROXYMODEL + +#include "qitemselectionmodel.h" +#include <private/qabstractproxymodel_p.h> + +QT_BEGIN_NAMESPACE + +class QIdentityProxyModelPrivate : public QAbstractProxyModelPrivate +{ + QIdentityProxyModelPrivate() + : ignoreNextLayoutAboutToBeChanged(false), + ignoreNextLayoutChanged(false) + { + + } + + Q_DECLARE_PUBLIC(QIdentityProxyModel) + + bool ignoreNextLayoutAboutToBeChanged; + bool ignoreNextLayoutChanged; + QList<QPersistentModelIndex> layoutChangePersistentIndexes; + QModelIndexList proxyIndexes; + + void _q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end); + void _q_sourceRowsInserted(const QModelIndex &parent, int start, int end); + void _q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceRowsRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + void _q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + + void _q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsInserted(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + void _q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + + void _q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last); + + void _q_sourceLayoutAboutToBeChanged(); + void _q_sourceLayoutChanged(); + void _q_sourceModelAboutToBeReset(); + void _q_sourceModelReset(); + +}; + +/*! + \since 4.8 + \class QIdentityProxyModel + \brief The QIdentityProxyModel class proxies its source model unmodified + + \ingroup model-view + + QIdentityProxyModel can be used to forward the structure of a source model exactly, with no sorting, filtering or other transformation. + This is similar in concept to an identity matrix where A.I = A. + + Because it does no sorting or filtering, this class is most suitable to proxy models which transform the data() of the source model. + For example, a proxy model could be created to define the font used, or the background colour, or the tooltip etc. This removes the + need to implement all data handling in the same class that creates the structure of the model, and can also be used to create + re-usable components. + + This also provides a way to change the data in the case where a source model is supplied by a third party which can not be modified. + + \snippet doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp 0 + + \sa QAbstractProxyModel, {Model/View Programming}, QAbstractItemModel + +*/ + +/*! + Constructs an identity model with the given \a parent. +*/ +QIdentityProxyModel::QIdentityProxyModel(QObject* parent) + : QAbstractProxyModel(*new QIdentityProxyModelPrivate, parent) +{ + +} + +/*! \internal + */ +QIdentityProxyModel::QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent) + : QAbstractProxyModel(dd, parent) +{ + +} + +/*! + Destroys this identity model. +*/ +QIdentityProxyModel::~QIdentityProxyModel() +{ +} + +/*! + \reimp + */ +int QIdentityProxyModel::columnCount(const QModelIndex& parent) const +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(const QIdentityProxyModel); + return d->model->columnCount(mapToSource(parent)); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->dropMimeData(data, action, row, column, mapToSource(parent)); +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::index(int row, int column, const QModelIndex& parent) const +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(const QIdentityProxyModel); + if (!hasIndex(row, column, parent)) + return QModelIndex(); + const QModelIndex sourceParent = mapToSource(parent); + const QModelIndex sourceIndex = d->model->index(row, column, sourceParent); + Q_ASSERT(sourceIndex.isValid()); + return mapFromSource(sourceIndex); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::insertColumns(int column, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->insertColumns(column, count, mapToSource(parent)); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::insertRows(int row, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->insertRows(row, count, mapToSource(parent)); +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::mapFromSource(const QModelIndex& sourceIndex) const +{ + Q_D(const QIdentityProxyModel); + if (!d->model || !sourceIndex.isValid()) + return QModelIndex(); + + Q_ASSERT(sourceIndex.model() == d->model); + return createIndex(sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer()); +} + +/*! + \reimp + */ +QItemSelection QIdentityProxyModel::mapSelectionFromSource(const QItemSelection& selection) const +{ + Q_D(const QIdentityProxyModel); + QItemSelection proxySelection; + + if (!d->model) + return proxySelection; + + QItemSelection::const_iterator it = selection.constBegin(); + const QItemSelection::const_iterator end = selection.constEnd(); + for ( ; it != end; ++it) { + Q_ASSERT(it->model() == d->model); + const QItemSelectionRange range(mapFromSource(it->topLeft()), mapFromSource(it->bottomRight())); + proxySelection.append(range); + } + + return proxySelection; +} + +/*! + \reimp + */ +QItemSelection QIdentityProxyModel::mapSelectionToSource(const QItemSelection& selection) const +{ + Q_D(const QIdentityProxyModel); + QItemSelection sourceSelection; + + if (!d->model) + return sourceSelection; + + QItemSelection::const_iterator it = selection.constBegin(); + const QItemSelection::const_iterator end = selection.constEnd(); + for ( ; it != end; ++it) { + Q_ASSERT(it->model() == this); + const QItemSelectionRange range(mapToSource(it->topLeft()), mapToSource(it->bottomRight())); + sourceSelection.append(range); + } + + return sourceSelection; +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::mapToSource(const QModelIndex& proxyIndex) const +{ + Q_D(const QIdentityProxyModel); + if (!d->model || !proxyIndex.isValid()) + return QModelIndex(); + Q_ASSERT(proxyIndex.model() == this); + return d->model->createIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer()); +} + +/*! + \reimp + */ +QModelIndexList QIdentityProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const +{ + Q_D(const QIdentityProxyModel); + Q_ASSERT(start.isValid() ? start.model() == this : true); + if (!d->model) + return QModelIndexList(); + + const QModelIndexList sourceList = d->model->match(mapToSource(start), role, value, hits, flags); + QModelIndexList::const_iterator it = sourceList.constBegin(); + const QModelIndexList::const_iterator end = sourceList.constEnd(); + QModelIndexList proxyList; + for ( ; it != end; ++it) + proxyList.append(mapFromSource(*it)); + return proxyList; +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::parent(const QModelIndex& child) const +{ + Q_ASSERT(child.isValid() ? child.model() == this : true); + const QModelIndex sourceIndex = mapToSource(child); + const QModelIndex sourceParent = sourceIndex.parent(); + return mapFromSource(sourceParent); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::removeColumns(int column, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->removeColumns(column, count, mapToSource(parent)); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::removeRows(int row, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->removeRows(row, count, mapToSource(parent)); +} + +/*! + \reimp + */ +int QIdentityProxyModel::rowCount(const QModelIndex& parent) const +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(const QIdentityProxyModel); + return d->model->rowCount(mapToSource(parent)); +} + +/*! + \reimp + */ +void QIdentityProxyModel::setSourceModel(QAbstractItemModel* sourceModel) +{ + beginResetModel(); + + if (sourceModel) { + disconnect(sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsAboutToBeInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsAboutToBeRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceColumnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceColumnsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(modelAboutToBeReset()), + this, SLOT(_q_sourceModelAboutToBeReset())); + disconnect(sourceModel, SIGNAL(modelReset()), + this, SLOT(_q_sourceModelReset())); + disconnect(sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(_q_sourceDataChanged(const QModelIndex &, const QModelIndex &))); + disconnect(sourceModel, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), + this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); + disconnect(sourceModel, SIGNAL(layoutAboutToBeChanged()), + this, SLOT(_q_sourceLayoutAboutToBeChanged())); + disconnect(sourceModel, SIGNAL(layoutChanged()), + this, SLOT(_q_sourceLayoutChanged())); + } + + QAbstractProxyModel::setSourceModel(sourceModel); + + if (sourceModel) { + connect(sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsAboutToBeInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceColumnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceColumnsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(modelAboutToBeReset()), + SLOT(_q_sourceModelAboutToBeReset())); + connect(sourceModel, SIGNAL(modelReset()), + SLOT(_q_sourceModelReset())); + connect(sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + SLOT(_q_sourceDataChanged(const QModelIndex &, const QModelIndex &))); + connect(sourceModel, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), + SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); + connect(sourceModel, SIGNAL(layoutAboutToBeChanged()), + SLOT(_q_sourceLayoutAboutToBeChanged())); + connect(sourceModel, SIGNAL(layoutChanged()), + SLOT(_q_sourceLayoutChanged())); + } + + endResetModel(); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginInsertColumns(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginMoveColumns(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginRemoveColumns(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endInsertColumns(); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(sourceParent) + Q_UNUSED(sourceStart) + Q_UNUSED(sourceEnd) + Q_UNUSED(destParent) + Q_UNUSED(dest) + q->endMoveColumns(); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endRemoveColumns(); +} + +void QIdentityProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + Q_ASSERT(topLeft.isValid() ? topLeft.model() == model : true); + Q_ASSERT(bottomRight.isValid() ? bottomRight.model() == model : true); + Q_Q(QIdentityProxyModel); + q->dataChanged(q->mapFromSource(topLeft), q->mapFromSource(bottomRight)); +} + +void QIdentityProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last) +{ + Q_Q(QIdentityProxyModel); + q->headerDataChanged(orientation, first, last); +} + +void QIdentityProxyModelPrivate::_q_sourceLayoutAboutToBeChanged() +{ + if (ignoreNextLayoutAboutToBeChanged) + return; + + Q_Q(QIdentityProxyModel); + + foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) { + proxyIndexes << proxyPersistentIndex; + Q_ASSERT(proxyPersistentIndex.isValid()); + const QPersistentModelIndex srcPersistentIndex = q->mapToSource(proxyPersistentIndex); + Q_ASSERT(srcPersistentIndex.isValid()); + layoutChangePersistentIndexes << srcPersistentIndex; + } + + q->layoutAboutToBeChanged(); +} + +void QIdentityProxyModelPrivate::_q_sourceLayoutChanged() +{ + if (ignoreNextLayoutChanged) + return; + + Q_Q(QIdentityProxyModel); + + for (int i = 0; i < proxyIndexes.size(); ++i) { + q->changePersistentIndex(proxyIndexes.at(i), q->mapFromSource(layoutChangePersistentIndexes.at(i))); + } + + layoutChangePersistentIndexes.clear(); + proxyIndexes.clear(); + + q->layoutChanged(); +} + +void QIdentityProxyModelPrivate::_q_sourceModelAboutToBeReset() +{ + Q_Q(QIdentityProxyModel); + q->beginResetModel(); +} + +void QIdentityProxyModelPrivate::_q_sourceModelReset() +{ + Q_Q(QIdentityProxyModel); + q->endResetModel(); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginInsertRows(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginMoveRows(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginRemoveRows(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endInsertRows(); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(sourceParent) + Q_UNUSED(sourceStart) + Q_UNUSED(sourceEnd) + Q_UNUSED(destParent) + Q_UNUSED(dest) + q->endMoveRows(); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endRemoveRows(); +} + +QT_END_NAMESPACE + +#include "moc_qidentityproxymodel.cpp" + +#endif // QT_NO_IDENTITYPROXYMODEL diff --git a/src/gui/itemviews/qidentityproxymodel.h b/src/gui/itemviews/qidentityproxymodel.h new file mode 100644 index 0000000..4b3176a --- /dev/null +++ b/src/gui/itemviews/qidentityproxymodel.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> +** 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 QIDENTITYPROXYMODEL_H +#define QIDENTITYPROXYMODEL_H + +#include <QtGui/qabstractproxymodel.h> + +#ifndef QT_NO_IDENTITYPROXYMODEL + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QIdentityProxyModelPrivate; + +class Q_GUI_EXPORT QIdentityProxyModel : public QAbstractProxyModel +{ + Q_OBJECT +public: + explicit QIdentityProxyModel(QObject* parent = 0); + ~QIdentityProxyModel(); + + int columnCount(const QModelIndex& parent = QModelIndex()) const; + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; + QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; + QModelIndex mapToSource(const QModelIndex& proxyIndex) const; + QModelIndex parent(const QModelIndex& child) const; + int rowCount(const QModelIndex& parent = QModelIndex()) const; + bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); + + QItemSelection mapSelectionFromSource(const QItemSelection& selection) const; + QItemSelection mapSelectionToSource(const QItemSelection& selection) const; + QModelIndexList match(const QModelIndex& start, int role, const QVariant& value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const; + void setSourceModel(QAbstractItemModel* sourceModel); + + bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()); + bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()); + bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()); + bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()); + +protected: + QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent); + +private: + Q_DECLARE_PRIVATE(QIdentityProxyModel) + Q_DISABLE_COPY(QIdentityProxyModel) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceDataChanged(QModelIndex,QModelIndex)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last)) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutAboutToBeChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_sourceModelAboutToBeReset()) + Q_PRIVATE_SLOT(d_func(), void _q_sourceModelReset()) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_IDENTITYPROXYMODEL + +#endif // QIDENTITYPROXYMODEL_H + diff --git a/src/gui/itemviews/qitemselectionmodel.cpp b/src/gui/itemviews/qitemselectionmodel.cpp index 27a4a40..0b64452 100644 --- a/src/gui/itemviews/qitemselectionmodel.cpp +++ b/src/gui/itemviews/qitemselectionmodel.cpp @@ -1145,11 +1145,8 @@ void QItemSelectionModel::clearSelection() Q_D(QItemSelectionModel); if (d->ranges.count() == 0 && d->currentSelection.count() == 0) return; - QItemSelection selection = d->ranges; - selection.merge(d->currentSelection, d->currentCommand); - d->ranges.clear(); - d->currentSelection.clear(); - emit selectionChanged(QItemSelection(), selection); + + select(QItemSelection(), Clear); } diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index 94e3b76..61a935f 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -1500,7 +1500,9 @@ void QListWidget::setCurrentRow(int row, QItemSelectionModel::SelectionFlags com } /*! - Returns a pointer to the item at the coordinates \a p. + Returns a pointer to the item at the coordinates \a p. The coordinates + are relative to the list widget's \l{QAbstractScrollArea::}{viewport()}. + */ QListWidgetItem *QListWidget::itemAt(const QPoint &p) const { @@ -1514,6 +1516,9 @@ QListWidgetItem *QListWidget::itemAt(const QPoint &p) const \overload Returns a pointer to the item at the coordinates (\a x, \a y). + The coordinates are relative to the list widget's + \l{QAbstractScrollArea::}{viewport()}. + */ diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index eb56f56..f73607b 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -1502,7 +1502,7 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved( \l{Model Subclassing Reference}. \sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming}, - {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example} + {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example}, QIdentityProxyModel */ /*! diff --git a/src/gui/itemviews/qstyleditemdelegate.cpp b/src/gui/itemviews/qstyleditemdelegate.cpp index 33293f7..4989c05 100644 --- a/src/gui/itemviews/qstyleditemdelegate.cpp +++ b/src/gui/itemviews/qstyleditemdelegate.cpp @@ -263,6 +263,11 @@ QStyledItemDelegate::~QStyledItemDelegate() The default implementation uses the QLocale::toString to convert \a value into a QString. + + This function is not called for empty model indices, i.e., indices for which + the model returns an invalid QVariant. + + \sa QAbstractItemModel::data() */ QString QStyledItemDelegate::displayText(const QVariant &value, const QLocale& locale) const { diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index e494ee5..e70f356 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -1104,6 +1104,21 @@ void QTableView::setRootIndex(const QModelIndex &index) /*! \reimp */ +void QTableView::doItemsLayout() +{ + Q_D(QTableView); + QAbstractItemView::doItemsLayout(); + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) + d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value()); + else + d->verticalHeader->setOffset(verticalScrollBar()->value()); + if (!d->verticalHeader->updatesEnabled()) + d->verticalHeader->setUpdatesEnabled(true); +} + +/*! + \reimp +*/ void QTableView::setSelectionModel(QItemSelectionModel *selectionModel) { Q_D(QTableView); @@ -1285,7 +1300,6 @@ void QTableView::paintEvent(QPaintEvent *event) const QPen gridPen = QPen(gridColor, 0, d->gridStyle); const QHeaderView *verticalHeader = d->verticalHeader; const QHeaderView *horizontalHeader = d->horizontalHeader; - const QStyle::State state = option.state; const bool alternate = d->alternatingColors; const bool rightToLeft = isRightToLeft(); @@ -1975,9 +1989,13 @@ QModelIndexList QTableView::selectedIndexes() const previous number of rows is specified by \a oldCount, and the new number of rows is specified by \a newCount. */ -void QTableView::rowCountChanged(int /*oldCount*/, int /*newCount*/ ) +void QTableView::rowCountChanged(int oldCount, int newCount ) { Q_D(QTableView); + //when removing rows, we need to disable updates for the header until the geometries have been + //updated and the offset has been adjusted, or we risk calling paintSection for all the sections + if (newCount < oldCount) + d->verticalHeader->setUpdatesEnabled(false); d->doDelayedItemsLayout(); } diff --git a/src/gui/itemviews/qtableview.h b/src/gui/itemviews/qtableview.h index d4be086..7ab9d08 100644 --- a/src/gui/itemviews/qtableview.h +++ b/src/gui/itemviews/qtableview.h @@ -71,6 +71,7 @@ public: void setModel(QAbstractItemModel *model); void setRootIndex(const QModelIndex &index); void setSelectionModel(QItemSelectionModel *selectionModel); + void doItemsLayout(); QHeaderView *horizontalHeader() const; QHeaderView *verticalHeader() const; diff --git a/src/gui/itemviews/qtreewidget.cpp b/src/gui/itemviews/qtreewidget.cpp index 4db29d6..2ea9a43 100644 --- a/src/gui/itemviews/qtreewidget.cpp +++ b/src/gui/itemviews/qtreewidget.cpp @@ -2830,7 +2830,8 @@ void QTreeWidget::setCurrentItem(QTreeWidgetItem *item, int column, /*! - Returns a pointer to the item at the coordinates \a p. + Returns a pointer to the item at the coordinates \a p. The coordinates + are relative to the tree widget's \l{QAbstractScrollArea::}{viewport()}. \sa visualItemRect() */ @@ -2844,7 +2845,8 @@ QTreeWidgetItem *QTreeWidget::itemAt(const QPoint &p) const \fn QTreeWidgetItem *QTreeWidget::itemAt(int x, int y) const \overload - Returns a pointer to the item at the coordinates (\a x, \a y). + Returns a pointer to the item at the coordinates (\a x, \a y). The coordinates + are relative to the tree widget's \l{QAbstractScrollArea::}{viewport()}. */ /*! diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 32fa3d3..3c57368 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -108,6 +108,8 @@ win32 { } symbian { + exists($${EPOCROOT}epoc32/include/platform/mw/akntranseffect.h): DEFINES += QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H + SOURCES += \ kernel/qapplication_s60.cpp \ kernel/qeventdispatcher_s60.cpp \ @@ -248,7 +250,8 @@ qpa { kernel/qplatformglcontext_qpa.cpp \ kernel/qplatformcursor_qpa.cpp \ kernel/qplatformclipboard_qpa.cpp \ - kernel/qplatformnativeinterface_qpa.cpp + kernel/qplatformnativeinterface_qpa.cpp \ + kernel/qsessionmanager_qpa.cpp contains(QT_CONFIG, glib) { SOURCES += \ diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index e91fe04..4096bf3 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -128,6 +128,10 @@ extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp //#define ALIEN_DEBUG +#if defined(Q_OS_SYMBIAN) +#include "qt_s60_p.h" +#endif + static void initResources() { #if defined(Q_WS_WINCE) @@ -2438,6 +2442,11 @@ bool QApplication::event(QEvent *e) { Q_D(QApplication); if(e->type() == QEvent::Close) { +#if defined(Q_OS_SYMBIAN) + // In order to have proper application-exit effects on Symbian, certain + // native APIs have to be called _before_ closing/destroying the widgets. + bool effectStarted = qt_beginFullScreenEffect(); +#endif QCloseEvent *ce = static_cast<QCloseEvent*>(e); ce->accept(); closeAllWindows(); @@ -2451,8 +2460,14 @@ bool QApplication::event(QEvent *e) break; } } - if(ce->isAccepted()) + if (ce->isAccepted()) { return true; + } else { +#if defined(Q_OS_SYMBIAN) + if (effectStarted) + qt_abortFullScreenEffect(); +#endif + } } else if(e->type() == QEvent::LanguageChange) { #ifndef QT_NO_TRANSLATION setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight); diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index aa62518..fb61d36 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -79,6 +79,8 @@ template <typename T> class QList; class QLocale; #if defined(Q_WS_QWS) class QDecoration; +#elif defined(Q_WS_QPA) +class QPlatformNativeInterface; #endif #if defined(Q_OS_SYMBIAN) class QSymbianEvent; @@ -254,6 +256,10 @@ public: #endif #endif +#if defined(Q_WS_QPA) + static QPlatformNativeInterface *platformNativeInterface(); +#endif + #if defined(Q_WS_WIN) void winFocus(QWidget *, bool); diff --git a/src/gui/kernel/qapplication_qpa.cpp b/src/gui/kernel/qapplication_qpa.cpp index cb5439c..b754cf7 100644 --- a/src/gui/kernel/qapplication_qpa.cpp +++ b/src/gui/kernel/qapplication_qpa.cpp @@ -444,6 +444,12 @@ void QApplication::alert(QWidget *, int) { } +QPlatformNativeInterface *QApplication::platformNativeInterface() +{ + QPlatformIntegration *pi = QApplicationPrivate::platformIntegration(); + return pi->nativeInterface(); +} + static void init_platform(const QString &name, const QString &platformPluginPath) { QApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, platformPluginPath); @@ -514,7 +520,14 @@ void qt_init(QApplicationPrivate *priv, int type) QList<QByteArray> pluginList; QString platformPluginPath = QLatin1String(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH")); - QString platformName = QLatin1String(qgetenv("QT_QPA_PLATFORM")); + QByteArray platformName; +#ifdef QT_QPA_DEFAULT_PLATFORM_NAME + platformName = QT_QPA_DEFAULT_PLATFORM_NAME; +#endif + QByteArray platformNameEnv = qgetenv("QT_QPA_PLATFORM"); + if (!platformNameEnv.isEmpty()) { + platformName = platformNameEnv; + } // Get command line params @@ -533,7 +546,7 @@ void qt_init(QApplicationPrivate *priv, int type) platformPluginPath = QLatin1String(argv[i]); } else if (arg == "-platform") { if (++i < argc) - platformName = QLatin1String(argv[i]); + platformName = argv[i]; } else if (arg == "-plugin") { if (++i < argc) pluginList << argv[i]; @@ -554,7 +567,7 @@ void qt_init(QApplicationPrivate *priv, int type) } #endif - init_platform(platformName, platformPluginPath); + init_platform(QLatin1String(platformName), platformPluginPath); init_plugins(pluginList); QColormap::initialize(); diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 3d642d0..68c1ab5 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -142,6 +142,60 @@ void QS60Data::setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, boo // Ensure that control rectangle is updated static_cast<QSymbianControl *>(QApplication::activeWindow()->winId())->handleClientAreaChange(); } + +bool QS60Data::setRecursiveDecorationsVisibility(QWidget *window, Qt::WindowStates newState) +{ + // Show statusbar: + // Topmost parent: Show unless fullscreen/minimized. + // Child windows: Follow topmost parent, unless fullscreen, in which case do not show statusbar + // Show CBA: + // Topmost parent: Show unless fullscreen/minimized. + // Exception: Show if fullscreen with Qt::WindowSoftkeysVisibleHint. + // Child windows: + // Minimized: Unclear if there is an use case for having focused minimized window at all. + // Always follow topmost parent just to be safe. + // Maximized and normal: follow topmost parent. + // Exception: If topmost parent is not showing CBA, show CBA if any softkey actions are + // defined. + // Fullscreen: Show only if Qt::WindowSoftkeysVisibleHint set. + + Qt::WindowStates comparisonState = newState; + QWidget *parentWindow = window->parentWidget(); + if (parentWindow) { + while (parentWindow->parentWidget()) + parentWindow = parentWindow->parentWidget(); + comparisonState = parentWindow->windowState(); + } else { + parentWindow = window; + } + + bool decorationsVisible = !(comparisonState & (Qt::WindowFullScreen | Qt::WindowMinimized)); + const bool parentIsFullscreen = comparisonState & Qt::WindowFullScreen; + const bool parentCbaVisibilityHint = parentWindow->windowFlags() & Qt::WindowSoftkeysVisibleHint; + bool buttonGroupVisibility = (decorationsVisible || (parentIsFullscreen && parentCbaVisibilityHint)); + + // Do extra checking for child windows + if (window->parentWidget()) { + if (newState & Qt::WindowFullScreen) { + decorationsVisible = false; + if (window->windowFlags() & Qt::WindowSoftkeysVisibleHint) + buttonGroupVisibility = true; + else + buttonGroupVisibility = false; + } else if (!(newState & Qt::WindowMinimized) && !buttonGroupVisibility) { + for (int i = 0; i < window->actions().size(); ++i) { + if (window->actions().at(i)->softKeyRole() != QAction::NoSoftKey) { + buttonGroupVisibility = true; + break; + } + } + } + } + + S60->setStatusPaneAndButtonGroupVisibility(decorationsVisible, buttonGroupVisibility); + + return decorationsVisible; +} #endif void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible) @@ -161,6 +215,12 @@ void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible) widget->repaint(); } } else { + // In certain special scenarios we may get an ENotVisible event + // without a previous EPartiallyVisible. The backingstore must + // still be destroyed, hence the registerWidget() call below. + if (backingStore.data() && widget->internalWinId() + && qt_widget_private(widget)->maybeBackingStore() == backingStore.data()) + backingStore.registerWidget(widget); backingStore.unregisterWidget(widget); // In order to ensure that any resources used by the window surface // are immediately freed, we flush the WSERV command buffer. @@ -405,6 +465,7 @@ QSymbianControl::QSymbianControl(QWidget *w) , m_ignoreFocusChanged(0) , m_symbianPopupIsOpen(0) , m_inExternalScreenOverride(false) + , m_lastStatusPaneVisibility(0) { } @@ -491,11 +552,52 @@ void QSymbianControl::setWidget(QWidget *w) { qwidget = w; } + +QPoint QSymbianControl::translatePointForFixedNativeOrientation(const TPoint &pointerEventPos) const +{ + QPoint pos(pointerEventPos.iX, pointerEventPos.iY); + if (qwidget->d_func()->fixNativeOrientationCalled) { + QSize wsize = qwidget->size(); + TSize size = Size(); + if (size.iWidth == wsize.height() && size.iHeight == wsize.width()) { + qreal x = pos.x(); + qreal y = pos.y(); + pos.setX(size.iHeight - y); + pos.setY(x); + } + } + return pos; +} + +TRect QSymbianControl::translateRectForFixedNativeOrientation(const TRect &controlRect) const +{ + TRect rect = controlRect; + if (qwidget->d_func()->fixNativeOrientationCalled) { + QPoint a = translatePointForFixedNativeOrientation(rect.iTl); + QPoint b = translatePointForFixedNativeOrientation(rect.iBr); + if (a.x() < b.x()) { + rect.iTl.iX = a.x(); + rect.iBr.iX = b.x(); + } else { + rect.iTl.iX = b.x(); + rect.iBr.iX = a.x(); + } + if (a.y() < b.y()) { + rect.iTl.iY = a.y(); + rect.iBr.iY = b.y(); + } else { + rect.iTl.iY = b.y(); + rect.iBr.iY = a.y(); + } + } + return rect; +} + void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ) { QWidget *alienWidget; - QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY); - QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY); + QPoint widgetPos = translatePointForFixedNativeOrientation(aPenEventLocation); + QPoint globalPos = translatePointForFixedNativeOrientation(aPenEventScreenLocation); alienWidget = qwidget->childAt(widgetPos); if (!alienWidget) alienWidget = qwidget; @@ -510,7 +612,7 @@ void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, cons void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event) { QApplicationPrivate *d = QApplicationPrivate::instance(); - QPointF screenPos = qwidget->mapToGlobal(QPoint(event->iPosition.iX, event->iPosition.iY)); + QPointF screenPos = qwidget->mapToGlobal(translatePointForFixedNativeOrientation(event->iPosition)); qreal pressure; if(d->pressureSupported && event->Pressure() > 0) //workaround for misconfigured HAL @@ -611,7 +713,7 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) mapS60MouseEventTypeToQt(&type, &button, &pEvent); Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers); - QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); + QPoint widgetPos = translatePointForFixedNativeOrientation(pEvent.iPosition); TPoint controlScreenPos = PositionRelativeToScreen(); QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; S60->lastCursorPos = globalPos; @@ -1077,6 +1179,9 @@ void QSymbianControl::Draw(const TRect& controlRect) const Q_ASSERT(window); QTLWExtra *topExtra = window->d_func()->maybeTopData(); Q_ASSERT(topExtra); + + TRect wcontrolRect = translateRectForFixedNativeOrientation(controlRect); + if (!topExtra->inExpose) { topExtra->inExpose = true; if (!qwidget->isWindow()) { @@ -1087,7 +1192,7 @@ void QSymbianControl::Draw(const TRect& controlRect) const gc.SetBrushColor(TRgb(0, 0, 0, 0)); gc.Clear(controlRect); } - QRect exposeRect = qt_TRect2QRect(controlRect); + QRect exposeRect = qt_TRect2QRect(wcontrolRect); qwidget->d_func()->syncBackingStore(exposeRect); topExtra->inExpose = false; } @@ -1100,7 +1205,7 @@ void QSymbianControl::Draw(const TRect& controlRect) const const bool sendNativePaintEvents = qwidget->d_func()->extraData()->receiveNativePaintEvents; if (sendNativePaintEvents) { - const QRect r = qt_TRect2QRect(controlRect); + const QRect r = qt_TRect2QRect(wcontrolRect); QMetaObject::invokeMethod(qwidget, "beginNativePaintEvent", Qt::DirectConnection, Q_ARG(QRect, r)); } @@ -1155,7 +1260,7 @@ void QSymbianControl::Draw(const TRect& controlRect) const } if (sendNativePaintEvents) { - const QRect r = qt_TRect2QRect(controlRect); + const QRect r = qt_TRect2QRect(wcontrolRect); // The draw ops aren't actually sent to WSERV until the graphics // context is deactivated, which happens in the function calling // this one. We therefore delay the delivery of endNativePaintEvent, @@ -1168,14 +1273,45 @@ void QSymbianControl::Draw(const TRect& controlRect) const } } +void QSymbianControl::qwidgetResize_helper(const QSize &newSize) +{ + QRect cr = qwidget->geometry(); + QSize oldSize(cr.size()); + cr.setSize(newSize); + qwidget->data->crect = cr; + if (qwidget->isVisible()) { + QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); + bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = true; + QResizeEvent e(newSize, oldSize); + qt_sendSpontaneousEvent(qwidget, &e); + if (!qwidget->testAttribute(Qt::WA_StaticContents)) + qwidget->d_func()->syncBackingStore(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = false; + } else { + if (!qwidget->testAttribute(Qt::WA_PendingResizeEvent)) { + QResizeEvent *e = new QResizeEvent(newSize, oldSize); + QApplication::postEvent(qwidget, e); + } + } +} + void QSymbianControl::SizeChanged() { CCoeControl::SizeChanged(); + // When FixNativeOrientation had been called, the RWindow/CCoeControl size + // and the surface/QWidget size have nothing to do with each other. + if (qwidget->d_func()->fixNativeOrientationCalled) + return; + QSize oldSize = qwidget->size(); QSize newSize(Size().iWidth, Size().iHeight); if (oldSize != newSize) { + // Enforce the proper size for fullscreen widgets on the secondary screen. const bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen; const int screenNumber = S60->screenNumberForWidget(qwidget); if (!m_inExternalScreenOverride && isFullscreen && screenNumber > 0) { @@ -1188,26 +1324,8 @@ void QSymbianControl::SizeChanged() return; } } - QRect cr = qwidget->geometry(); - cr.setSize(newSize); - qwidget->data->crect = cr; - if (qwidget->isVisible()) { - QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); - bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); - if (!slowResize && tlwExtra) - tlwExtra->inTopLevelResize = true; - QResizeEvent e(newSize, oldSize); - qt_sendSpontaneousEvent(qwidget, &e); - if (!qwidget->testAttribute(Qt::WA_StaticContents)) - qwidget->d_func()->syncBackingStore(); - if (!slowResize && tlwExtra) - tlwExtra->inTopLevelResize = false; - } else { - if (!qwidget->testAttribute(Qt::WA_PendingResizeEvent)) { - QResizeEvent *e = new QResizeEvent(newSize, oldSize); - QApplication::postEvent(qwidget, e); - } - } + + qwidgetResize_helper(newSize); } m_inExternalScreenOverride = false; @@ -1242,6 +1360,23 @@ void QSymbianControl::PositionChanged() } } +// Search recursively if there is a child widget that is both visible and focused. +bool QSymbianControl::hasFocusedAndVisibleChild(QWidget *parentWidget) +{ + for (int i = 0; i < parentWidget->children().size(); ++i) { + QObject *object = parentWidget->children().at(i); + if (object && object->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(object); + WId winId = w->internalWinId(); + if (winId && winId->IsFocused() && winId->IsVisible()) + return true; + if (hasFocusedAndVisibleChild(w)) + return true; + } + } + return false; +} + void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */) { if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop) @@ -1271,28 +1406,12 @@ void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */) qwidget->d_func()->setWindowIcon_sys(true); qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle()); #ifdef Q_WS_S60 - // If widget is fullscreen/minimized, hide status pane and button container otherwise show them. - QWidget *const window = qwidget->window(); - if (!window->parentWidget()) { // Only top level native windows have control over cba/status pane - const bool decorationsVisible = !(window->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized)); - const bool statusPaneVisibility = decorationsVisible; - const bool isFullscreen = window->windowState() & Qt::WindowFullScreen; - const bool cbaVisibilityHint = window->windowFlags() & Qt::WindowSoftkeysVisibleHint; - const bool buttonGroupVisibility = (decorationsVisible || (isFullscreen && cbaVisibilityHint)); - S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility); - } + if (qwidget->isWindow()) + S60->setRecursiveDecorationsVisibility(qwidget, qwidget->windowState()); #endif - } else if (QApplication::activeWindow() == qwidget->window()) { - bool focusedControlFound = false; - WId winId = 0; - for (QWidget *w = qwidget->parentWidget(); w && (winId = w->internalWinId()); w = w->parentWidget()) { - if (winId->IsFocused() && winId->IsVisible()) { - focusedControlFound = true; - break; - } else if (w->isWindow()) - break; - } - if (!focusedControlFound) { + } else { + QWidget *parentWindow = qwidget->window(); + if (QApplication::activeWindow() == parentWindow && !hasFocusedAndVisibleChild(parentWindow)) { if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || S60->menuBeingConstructed) { QWidget *fw = QApplication::focusWidget(); if (fw) { @@ -1381,7 +1500,13 @@ void QSymbianControl::HandleResourceChange(int resourceType) } break; case KInternalStatusPaneChange: - handleClientAreaChange(); + // When status pane is not visible, only handle client area change if status pane was + // previously visible, as size changes to hidden status pane should not affect + // client area. + if (S60->statusPane() && (S60->statusPane()->IsVisible() || m_lastStatusPaneVisibility)) { + m_lastStatusPaneVisibility = S60->statusPane()->IsVisible(); + handleClientAreaChange(); + } if (IsFocused() && IsVisible()) { qwidget->d_func()->setWindowIcon_sys(true); qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle()); @@ -1393,10 +1518,16 @@ void QSymbianControl::HandleResourceChange(int resourceType) #ifdef Q_WS_S60 case KEikDynamicLayoutVariantSwitch: { +#ifdef QT_SOFTKEYS_ENABLED + // Update needed just in case softkeys contain icons + QSoftKeyManager::updateSoftKeys(); +#endif handleClientAreaChange(); // Send resize event to trigger desktopwidget workAreaResized signal - QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size()); - QApplication::sendEvent(qt_desktopWidget, &e); + if (qt_desktopWidget) { + QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size()); + QApplication::sendEvent(qt_desktopWidget, &e); + } break; } #endif @@ -1455,6 +1586,55 @@ bool QSymbianControl::isControlActive() return IsActivated() ? true : false; } +void QSymbianControl::ensureFixNativeOrientation() +{ +#if defined(Q_SYMBIAN_SUPPORTS_FIXNATIVEORIENTATION) + if (!qwidget->isWindow() || qwidget->windowType() == Qt::Desktop) + return; + if (S60->screenNumberForWidget(qwidget) > 0) + return; + const bool isFixed = qwidget->d_func()->fixNativeOrientationCalled; + const bool isFixEnabled = qwidget->testAttribute(Qt::WA_SymbianNoSystemRotation); + const bool isFullScreen = qwidget->windowState().testFlag(Qt::WindowFullScreen); + if (isFullScreen && isFixEnabled) { + const bool surfaceBasedGs = + QApplicationPrivate::graphics_system_name == QLatin1String("openvg") + || QApplicationPrivate::graphics_system_name == QLatin1String("opengl"); + if (!surfaceBasedGs) + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); + if (!isFixed && surfaceBasedGs) { + if (Window().FixNativeOrientation() == KErrNone) { + qwidget->d_func()->fixNativeOrientationCalled = true; + // The EGL window surface is now fixed to the native orientation + // of the device, no matter what size we pass when creating it. + // Enforce the same size for the QWidget too. For the underlying + // CCoeControl and RWindow it is up to the system to resize them + // when the standard auto-rotation mechanism is in use, we must not + // change that behavior by forcing any size for those. In practice + // this means that the QWidget and the underlying native control + // dimensions will be out of sync when FixNativeOrientation was + // called and the device is turned to the non-native (typically + // landscape) orientation. The pointer event handling and certain + // functions like Draw() will need to compensate for this. + QSize newSize(S60->nativeScreenWidthInPixels, S60->nativeScreenHeightInPixels); + if (qwidget->size() != newSize) + qwidgetResize_helper(newSize); + } else { + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); + } + } + } else if (isFixed) { + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); + qwidget->d_func()->fixNativeOrientationCalled = false; + qwidget->hide(); + qwidget->d_func()->create_sys(0, false, true); + qwidget->show(); + } +#else + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); +#endif +} + /*! \typedef QApplication::QS60MainApplicationFactory \since 4.6 @@ -1663,9 +1843,7 @@ void qt_init(QApplicationPrivate * /* priv */, int) systemFont.setFamily(systemFont.defaultFamily()); QApplicationPrivate::setSystemFont(systemFont); -#ifdef Q_SYMBIAN_TRANSITION_EFFECTS QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit())); -#endif #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE QApplicationPrivate::instance()->useTranslucentEGLSurfaces = true; @@ -1690,6 +1868,8 @@ void qt_init(QApplicationPrivate * /* priv */, int) } else { QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; } + if (QApplicationPrivate::graphics_system_name == QLatin1String("raster")) + QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; #else QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; #endif @@ -1761,6 +1941,9 @@ void qt_cleanup() S60->setButtonGroupContainer(0); #endif + // Call EndFullScreen() to prevent confusing the system effect state machine. + qt_endFullScreenEffect(); + if (S60->qtOwnsS60Environment) { // Restore the S60 framework trap handler. See qt_init(). User::SetTrapHandler(S60->s60InstalledTrapHandler); @@ -2132,7 +2315,8 @@ int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent } #endif #ifdef QT_SOFTKEYS_ENABLED - QSoftKeyManager::updateSoftKeys(); + if (!CEikonEnv::Static()->EikAppUi()->IsDisplayingMenuOrDialog()) + QSoftKeyManager::updateSoftKeys(); #endif break; case EEventFocusLost: @@ -2505,6 +2689,8 @@ void QApplication::restoreOverrideCursor() void QApplicationPrivate::_q_aboutToQuit() { + qt_beginFullScreenEffect(); + #ifdef Q_SYMBIAN_TRANSITION_EFFECTS // Send the shutdown tfx command S60->wsSession().SendEffectCommand(ETfxCmdAppShutDown); @@ -2530,6 +2716,9 @@ QS60ThreadLocalData::QS60ThreadLocalData() QS60ThreadLocalData::~QS60ThreadLocalData() { + for (int i = 0; i < releaseFuncs.count(); ++i) + releaseFuncs[i](); + releaseFuncs.clear(); if (!usingCONEinstances) { delete screenDevice; wsSession.Close(); diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 5f5da59..63e2319 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -237,6 +237,7 @@ static void resolveAygLibs() # define FE_FONTSMOOTHINGCLEARTYPE 0x0002 #endif +Q_GUI_EXPORT qreal qt_fontsmoothing_gamma; Q_GUI_EXPORT bool qt_cleartype_enabled; Q_GUI_EXPORT bool qt_win_owndc_required; // CS_OWNDC is required if we use the GL graphicssystem as default @@ -653,8 +654,18 @@ static void qt_win_read_cleartype_settings() if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0)) qt_cleartype_enabled = (result == FE_FONTSMOOTHINGCLEARTYPE); #endif -} + int winSmooth; + if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) { + qt_fontsmoothing_gamma = winSmooth / qreal(1000.0); + } else { + qt_fontsmoothing_gamma = 1.0; + } + + // Safeguard ourselves against corrupt registry values... + if (qt_fontsmoothing_gamma > 5 || qt_fontsmoothing_gamma < 1) + qt_fontsmoothing_gamma = qreal(1.4); +} static void qt_set_windows_resources() { @@ -2361,8 +2372,13 @@ extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wPa #ifndef QT_NO_ACCESSIBILITY case WM_GETOBJECT: { + /* On Win64, lParam can be 0x00000000fffffffc or 0xfffffffffffffffc (!), + but MSDN says that lParam should be converted to a DWORD + before its compared against OBJID_CLIENT + */ + const DWORD dwObjId = (DWORD)lParam; // Ignoring all requests while starting up - if (QApplication::startingUp() || QApplication::closingDown() || lParam != (LPARAM)OBJID_CLIENT) { + if (QApplication::startingUp() || QApplication::closingDown() || dwObjId != OBJID_CLIENT) { result = false; break; } @@ -3815,16 +3831,32 @@ bool QETWidget::translateConfigEvent(const MSG &msg) QApplication::sendSpontaneousEvent(this, &e); hideChildren(true); } - } else if (msg.wParam != SIZE_MINIMIZED && isMinimized()) { + } else if (msg.wParam != SIZE_MINIMIZED) { + bool window_state_changed = false; + Qt::WindowStates oldstate = Qt::WindowStates(dataPtr()->window_state); + if (isMinimized()) { #ifndef Q_WS_WINCE - const QString title = windowTitle(); - if (!title.isEmpty()) - d_func()->setWindowTitle_helper(title); + const QString title = windowTitle(); + if (!title.isEmpty()) + d_func()->setWindowTitle_helper(title); #endif - data->window_state &= ~Qt::WindowMinimized; - showChildren(true); - QShowEvent e; - QApplication::sendSpontaneousEvent(this, &e); + data->window_state &= ~Qt::WindowMinimized; + showChildren(true); + QShowEvent e; + QApplication::sendSpontaneousEvent(this, &e); + // Capture SIZE_MAXIMIZED and SIZE_RESTORED without preceding WM_SYSCOMMAND + // (Aero Snap on Win7) + } else if (msg.wParam == SIZE_MAXIMIZED && !isMaximized()) { + data->window_state |= Qt::WindowMaximized; + window_state_changed = true; + } else if (msg.wParam == SIZE_RESTORED && isMaximized()) { + data->window_state &= ~(Qt::WindowMaximized); + window_state_changed = true; + } + if (window_state_changed) { + QWindowStateChangeEvent e(oldstate); + QApplication::sendSpontaneousEvent(this, &e); + } } } if (msg.wParam != SIZE_MINIMIZED && oldSize != newSize) { @@ -3856,7 +3888,7 @@ bool QETWidget::translateConfigEvent(const MSG &msg) QApplication::postEvent(this, e); } } -} else if (msg.message == WM_MOVE) { // move event + } else if (msg.message == WM_MOVE) { // move event int a = (int) (short) LOWORD(msg.lParam); int b = (int) (short) HIWORD(msg.lParam); QPoint oldPos = geometry().topLeft(); diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 589b12e..20542ea 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -1587,6 +1587,9 @@ static void getXDefault(const char *group, const char *key, int *val) int v = strtol(str, &end, 0); if (str != end) *val = v; + // otherwise use fontconfig to convert the string to integer + else + FcNameConstant((FcChar8 *) str, val); } } @@ -2237,6 +2240,7 @@ void qt_init(QApplicationPrivate *priv, int, } getXDefault("Xft", FC_ANTIALIAS, &X11->fc_antialias); #ifdef FC_HINT_STYLE + X11->fc_hint_style = -1; getXDefault("Xft", FC_HINT_STYLE, &X11->fc_hint_style); #endif #if 0 @@ -2277,6 +2281,13 @@ void qt_init(QApplicationPrivate *priv, int, // Attempt to determine the current running X11 Desktop Enviornment // Use dbus if/when we can, but fall back to using windowManagerName() for now +#ifndef QT_NO_XFIXES + if (X11->ptrXFixesSelectSelectionInput) + X11->ptrXFixesSelectSelectionInput(X11->display, QX11Info::appRootWindow(), ATOM(_NET_WM_CM_S0), + XFixesSetSelectionOwnerNotifyMask + | XFixesSelectionWindowDestroyNotifyMask + | XFixesSelectionClientCloseNotifyMask); +#endif // QT_NO_XFIXES X11->compositingManagerRunning = XGetSelectionOwner(X11->display, ATOM(_NET_WM_CM_S0)); X11->desktopEnvironment = DE_UNKNOWN; @@ -3212,6 +3223,8 @@ int QApplication::x11ProcessEvent(XEvent* event) XFixesSelectionNotifyEvent *req = reinterpret_cast<XFixesSelectionNotifyEvent *>(event); X11->time = req->selection_timestamp; + if (req->selection == ATOM(_NET_WM_CM_S0)) + X11->compositingManagerRunning = req->owner; } #endif diff --git a/src/gui/kernel/qclipboard.h b/src/gui/kernel/qclipboard.h index b55bdc6..019917e 100644 --- a/src/gui/kernel/qclipboard.h +++ b/src/gui/kernel/qclipboard.h @@ -112,6 +112,7 @@ protected: friend class QBaseApplication; friend class QDragManager; friend class QMimeSource; + friend class QPlatformClipboard; private: Q_DISABLE_COPY(QClipboard) diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h index 7d41f3d..ee1115b 100644 --- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h +++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h @@ -146,6 +146,20 @@ QT_END_NAMESPACE [NSApp terminate:sender]; } +- (void)setLevel:(NSInteger)windowLevel +{ + // Cocoa will upon activating/deactivating applications level modal + // windows up and down, regardsless of any explicit set window level. + // To ensure that modal stays-on-top dialogs actually stays on top after + // the application is activated (and therefore stacks in front of + // other stays-on-top windows), we need to add this little special-case override: + QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; + if (widget && widget->isModal() && (widget->windowFlags() & Qt::WindowStaysOnTopHint)) + [super setLevel:NSPopUpMenuWindowLevel]; + else + [super setLevel:windowLevel]; +} + - (void)sendEvent:(NSEvent *)event { [self retain]; diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 54e7e3e..b5e5d18 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -254,7 +254,10 @@ static int qCocoaViewCount = 0; qt_mac_retain_graphics_context(context); // We use a different graphics system. - if (QApplicationPrivate::graphicsSystem() != 0) { + // + // Widgets that are set to paint on screen, specifically QGLWidget, + // requires the native engine to execute in order to be drawn. + if (QApplicationPrivate::graphicsSystem() != 0 && !qwidget->testAttribute(Qt::WA_PaintOnScreen)) { // Raster engine. if (QApplicationPrivate::graphics_system_name == QLatin1String("raster")) { @@ -334,12 +337,6 @@ static int qCocoaViewCount = 0; qwidget->update(qwidget->rect()); qwidgetprivate->syncBackingStore(qwidget->rect()); } - - // Since we don't want to use the native engine, we must exit, however - // widgets that are set to paint on screen, specifically QGLWidget, - // requires the following code to execute in order to be drawn. - if (!qwidget->testAttribute(Qt::WA_PaintOnScreen)) - return; } // Native engine. diff --git a/src/gui/kernel/qcursor_x11.cpp b/src/gui/kernel/qcursor_x11.cpp index d0ed98e..0bc7250 100644 --- a/src/gui/kernel/qcursor_x11.cpp +++ b/src/gui/kernel/qcursor_x11.cpp @@ -55,6 +55,9 @@ #endif // QT_NO_XCURSOR #ifndef QT_NO_XFIXES +#ifndef Status +#define Status int +#endif # include <X11/extensions/Xfixes.h> #endif // QT_NO_XFIXES diff --git a/src/gui/kernel/qdesktopwidget_qpa.cpp b/src/gui/kernel/qdesktopwidget_qpa.cpp index cff05f5..6257a8b 100644 --- a/src/gui/kernel/qdesktopwidget_qpa.cpp +++ b/src/gui/kernel/qdesktopwidget_qpa.cpp @@ -51,6 +51,8 @@ QT_USE_NAMESPACE void QDesktopWidgetPrivate::updateScreenList() { + Q_Q(QDesktopWidget); + QList<QPlatformScreen *> screenList = QApplicationPrivate::platformIntegration()->screens(); int targetLength = screenList.length(); int currentLength = screens.length(); @@ -72,19 +74,15 @@ void QDesktopWidgetPrivate::updateScreenList() } QRegion virtualGeometry; - bool doVirtualGeometry = QApplicationPrivate::platformIntegration()->isVirtualDesktop(); // update the geometry of each screen widget for (int i = 0; i < screens.length(); i++) { QRect screenGeometry = screenList.at(i)->geometry(); screens.at(i)->setGeometry(screenGeometry); - if (doVirtualGeometry) - virtualGeometry += screenGeometry; + virtualGeometry += screenGeometry; } - virtualScreen.setGeometry(virtualGeometry.boundingRect()); - Q_Q(QDesktopWidget); - q->setGeometry(virtualScreen.geometry()); + q->setGeometry(virtualGeometry.boundingRect()); } QDesktopWidget::QDesktopWidget() @@ -118,8 +116,6 @@ int QDesktopWidget::numScreens() const QWidget *QDesktopWidget::screen(int screen) { Q_D(QDesktopWidget); - if (QApplicationPrivate::platformIntegration()->isVirtualDesktop()) - return &d->virtualScreen; if (screen < 0 || screen >= d->screens.length()) return d->screens.at(0); return d->screens.at(screen); diff --git a/src/gui/kernel/qdesktopwidget_qpa_p.h b/src/gui/kernel/qdesktopwidget_qpa_p.h index abee8a1..d6ed686 100644 --- a/src/gui/kernel/qdesktopwidget_qpa_p.h +++ b/src/gui/kernel/qdesktopwidget_qpa_p.h @@ -76,7 +76,6 @@ public: void updateScreenList(); QList<QDesktopScreenWidget *> screens; - QDesktopScreenWidget virtualScreen; }; #endif // QDESKTOPWIDGET_QPA_P_H diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index 5359fb3..7aa7dffd 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -566,7 +566,6 @@ void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures, = w->d_func()->gestureContext.find(type); if (it != w->d_func()->gestureContext.end()) { // i.e. 'w' listens to gesture 'type' - Qt::GestureFlags flags = it.value(); if (!(it.value() & Qt::DontStartGestureOnChildren) && w != widget) { // conflicting gesture! (*conflicts)[widget].append(gestures[widget]); diff --git a/src/gui/kernel/qkeymapper_s60.cpp b/src/gui/kernel/qkeymapper_s60.cpp index bcf32a5..08cfae0 100644 --- a/src/gui/kernel/qkeymapper_s60.cpp +++ b/src/gui/kernel/qkeymapper_s60.cpp @@ -69,8 +69,17 @@ void QKeyMapperPrivate::clearMappings() QString QKeyMapperPrivate::translateKeyEvent(int keySym, Qt::KeyboardModifiers /* modifiers */) { - if (keySym >= Qt::Key_Escape) - return QString(); + if (keySym >= Qt::Key_Escape) { + switch (keySym) { + case Qt::Key_Tab: + return QString(QChar('\t')); + case Qt::Key_Return: // fall through + case Qt::Key_Enter: + return QString(QChar('\r')); + default: + return QString(); + } + } // Symbian doesn't actually use modifiers, but gives us the character code directly. diff --git a/src/gui/kernel/qplatformclipboard_qpa.cpp b/src/gui/kernel/qplatformclipboard_qpa.cpp index 957a4df..33d2afc 100644 --- a/src/gui/kernel/qplatformclipboard_qpa.cpp +++ b/src/gui/kernel/qplatformclipboard_qpa.cpp @@ -42,6 +42,8 @@ #ifndef QT_NO_CLIPBOARD +#include <QtGui/private/qapplication_p.h> + QT_BEGIN_NAMESPACE class QClipboardData @@ -100,6 +102,11 @@ bool QPlatformClipboard::supportsMode(QClipboard::Mode mode) const return mode == QClipboard::Clipboard; } +void QPlatformClipboard::emitChanged(QClipboard::Mode mode) +{ + QApplication::clipboard()->emitChanged(mode); +} + QT_END_NAMESPACE #endif //QT_NO_CLIPBOARD diff --git a/src/gui/kernel/qplatformclipboard_qpa.h b/src/gui/kernel/qplatformclipboard_qpa.h index 3381c06..5444a1f 100644 --- a/src/gui/kernel/qplatformclipboard_qpa.h +++ b/src/gui/kernel/qplatformclipboard_qpa.h @@ -62,6 +62,7 @@ public: virtual const QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard ) const; virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); virtual bool supportsMode(QClipboard::Mode mode) const; + void emitChanged(QClipboard::Mode mode); }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformglcontext_qpa.cpp b/src/gui/kernel/qplatformglcontext_qpa.cpp index 86740e8..1810532 100644 --- a/src/gui/kernel/qplatformglcontext_qpa.cpp +++ b/src/gui/kernel/qplatformglcontext_qpa.cpp @@ -125,24 +125,6 @@ QPlatformGLContext::~QPlatformGLContext() } - -/*! - Makes it possible to set the context which can be the default for making new contexts. -*/ -void QPlatformGLContext::setDefaultSharedContext(QPlatformGLContext *sharedContext) -{ - QPlatformGLContextPrivate::staticSharedContext = sharedContext; -} - -/*! - Default shared context is intended to be a globally awailable pointer to a context which can - be used for sharing resources when creating new contexts. Its default value is 0; -*/ -QPlatformGLContext *QPlatformGLContext::defaultSharedContext() -{ - return QPlatformGLContextPrivate::staticSharedContext; -} - /*! Reimplement in subclass to do makeCurrent on native GL context */ diff --git a/src/gui/kernel/qplatformglcontext_qpa.h b/src/gui/kernel/qplatformglcontext_qpa.h index a680c85..28923a9 100644 --- a/src/gui/kernel/qplatformglcontext_qpa.h +++ b/src/gui/kernel/qplatformglcontext_qpa.h @@ -69,13 +69,10 @@ public: virtual QPlatformWindowFormat platformWindowFormat() const = 0; const static QPlatformGLContext *currentContext(); - static QPlatformGLContext *defaultSharedContext(); protected: - - static void setDefaultSharedContext(QPlatformGLContext *sharedContext); - QScopedPointer<QPlatformGLContextPrivate> d_ptr; + private: //hack to make it work with QGLContext::CurrentContext friend class QGLContext; diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp index c45a953..8ff12eb 100644 --- a/src/gui/kernel/qplatformintegration_qpa.cpp +++ b/src/gui/kernel/qplatformintegration_qpa.cpp @@ -69,16 +69,6 @@ QPlatformEventLoopIntegration *QPlatformIntegration::createEventLoopIntegration( } /*! - Returns whether the given platform integration supports OpenGL. - - Default implementation returns false, -*/ -bool QPlatformIntegration::hasOpenGL() const -{ - return false; -} - -/*! Accessor for the platform integrations fontdatabase. Default implementation returns a default QPlatformFontDatabase. @@ -224,6 +214,7 @@ QPlatformNativeInterface * QPlatformIntegration::nativeInterface() const bool QPlatformIntegration::hasCapability(Capability cap) const { + Q_UNUSED(cap); return false; } diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h index 0aacefa..d06272c 100644 --- a/src/gui/kernel/qplatformintegration_qpa.h +++ b/src/gui/kernel/qplatformintegration_qpa.h @@ -67,6 +67,7 @@ class Q_GUI_EXPORT QPlatformIntegration public: enum Capability { ThreadedPixmaps = 1, + OpenGL = 2 }; virtual ~QPlatformIntegration() { } @@ -95,9 +96,6 @@ public: // the gui thread. All of the functions in QWindowSystemInterface are thread safe. virtual QPlatformEventLoopIntegration *createEventLoopIntegration() const; -//jl:XXX should it be hasGLContext and do we need it at all? - virtual bool hasOpenGL() const; - // Access native handles. The window handle is already available from Wid; virtual QPlatformNativeInterface *nativeInterface() const; }; diff --git a/src/gui/kernel/qplatformwindow_qpa.cpp b/src/gui/kernel/qplatformwindow_qpa.cpp index 19bf7a9..f3654b6 100644 --- a/src/gui/kernel/qplatformwindow_qpa.cpp +++ b/src/gui/kernel/qplatformwindow_qpa.cpp @@ -150,7 +150,7 @@ void QPlatformWindow::setParent(const QPlatformWindow *parent) /*! Reimplement to set the window title to \a title */ -void QPlatformWindow::setWindowTitle(const QString &title) {} +void QPlatformWindow::setWindowTitle(const QString &) {} /*! Reimplement to be able to let Qt rais windows to the top of the desktop diff --git a/src/gui/kernel/qplatformwindowformat_qpa.cpp b/src/gui/kernel/qplatformwindowformat_qpa.cpp index ddc6239..c165c85 100644 --- a/src/gui/kernel/qplatformwindowformat_qpa.cpp +++ b/src/gui/kernel/qplatformwindowformat_qpa.cpp @@ -53,7 +53,7 @@ public: , opts(QPlatformWindowFormat::DoubleBuffer | QPlatformWindowFormat::DepthBuffer | QPlatformWindowFormat::Rgba | QPlatformWindowFormat::DirectRendering | QPlatformWindowFormat::StencilBuffer | QPlatformWindowFormat::DeprecatedFunctions - | QPlatformWindowFormat::UseDefaultSharedContext | QPlatformWindowFormat::HasWindowSurface) + | QPlatformWindowFormat::HasWindowSurface) , depthSize(-1) , accumSize(-1) , stencilSize(-1) @@ -525,16 +525,6 @@ void QPlatformWindowFormat::setSampleBuffers(bool enable) setOption(enable ? QPlatformWindowFormat::SampleBuffers : QPlatformWindowFormat::NoSampleBuffers); } -void QPlatformWindowFormat::setUseDefaultSharedContext(bool enable) -{ - if (enable) { - setOption(QPlatformWindowFormat::UseDefaultSharedContext); - d->sharedContext = 0; - } else { - setOption(QPlatformWindowFormat::NoDefaultSharedContext); - } -} - /*! Returns the number of samples per pixel when multisampling is enabled. By default, the highest number of samples that is @@ -613,7 +603,6 @@ QPlatformWindowFormat::WindowApi QPlatformWindowFormat::windowApi() const void QPlatformWindowFormat::setSharedContext(QPlatformGLContext *context) { - setUseDefaultSharedContext(false); d->sharedContext = context; } diff --git a/src/gui/kernel/qplatformwindowformat_qpa.h b/src/gui/kernel/qplatformwindowformat_qpa.h index fa01a8a..ba21ba4 100644 --- a/src/gui/kernel/qplatformwindowformat_qpa.h +++ b/src/gui/kernel/qplatformwindowformat_qpa.h @@ -66,8 +66,7 @@ public: HasOverlay = 0x0100, SampleBuffers = 0x0200, DeprecatedFunctions = 0x0400, - UseDefaultSharedContext = 0x0800, - HasWindowSurface = 0x1000, + HasWindowSurface = 0x0800, SingleBuffer = DoubleBuffer << 16, NoDepthBuffer = DepthBuffer << 16, ColorIndex = Rgba << 16, @@ -79,7 +78,6 @@ public: NoOverlay = HasOverlay << 16, NoSampleBuffers = SampleBuffers << 16, NoDeprecatedFunctions = DeprecatedFunctions << 16, - NoDefaultSharedContext = UseDefaultSharedContext << 16, NoWindowSurface = HasWindowSurface << 16 }; @@ -149,8 +147,6 @@ public: void setStereo(bool enable); bool directRendering() const; void setDirectRendering(bool enable); - bool useDefaultSharedContext() const; - void setUseDefaultSharedContext(bool enable); bool hasWindowSurface() const; void setWindowSurface(bool enable); @@ -231,11 +227,6 @@ inline bool QPlatformWindowFormat::sampleBuffers() const return testOption(QPlatformWindowFormat::SampleBuffers); } -inline bool QPlatformWindowFormat::useDefaultSharedContext() const -{ - return testOption(QPlatformWindowFormat::UseDefaultSharedContext); -} - QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/kernel/qsessionmanager_qpa.cpp b/src/gui/kernel/qsessionmanager_qpa.cpp new file mode 100644 index 0000000..68685b4 --- /dev/null +++ b/src/gui/kernel/qsessionmanager_qpa.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qsessionmanager.h> + +#include <private/qobject_p.h> +#include <qapplication.h> + +#ifndef QT_NO_SESSIONMANAGER + +QT_BEGIN_NAMESPACE + +class QSessionManagerPrivate : public QObjectPrivate +{ +public: + QSessionManagerPrivate(QSessionManager *m, const QString &id, + const QString &key); + + QStringList restartCommand; + QStringList discardCommand; + const QString sessionId; + const QString sessionKey; + QSessionManager::RestartHint restartHint; +}; + +QSessionManagerPrivate::QSessionManagerPrivate(QSessionManager*, + const QString &id, + const QString &key) + : QObjectPrivate(), sessionId(id), sessionKey(key) +{ +} + +QSessionManager::QSessionManager(QApplication *app, QString &id, QString &key) + : QObject(*(new QSessionManagerPrivate(this, id, key)), app) +{ + Q_D(QSessionManager); + d->restartHint = RestartIfRunning; +} + +QSessionManager::~QSessionManager() +{ +} + +QString QSessionManager::sessionId() const +{ + Q_D(const QSessionManager); + return d->sessionId; +} + +QString QSessionManager::sessionKey() const +{ + Q_D(const QSessionManager); + return d->sessionKey; +} + + +bool QSessionManager::allowsInteraction() +{ + return false; +} + +bool QSessionManager::allowsErrorInteraction() +{ + return false; +} + +void QSessionManager::release() +{ +} + +void QSessionManager::cancel() +{ +} + +void QSessionManager::setRestartHint(QSessionManager::RestartHint hint) +{ + Q_D(QSessionManager); + d->restartHint = hint; +} + +QSessionManager::RestartHint QSessionManager::restartHint() const +{ + Q_D(const QSessionManager); + return d->restartHint; +} + +void QSessionManager::setRestartCommand(const QStringList &command) +{ + Q_D(QSessionManager); + d->restartCommand = command; +} + +QStringList QSessionManager::restartCommand() const +{ + Q_D(const QSessionManager); + return d->restartCommand; +} + +void QSessionManager::setDiscardCommand(const QStringList &command) +{ + Q_D(QSessionManager); + d->discardCommand = command; +} + +QStringList QSessionManager::discardCommand() const +{ + Q_D(const QSessionManager); + return d->discardCommand; +} + +void QSessionManager::setManagerProperty(const QString &name, + const QString &value) +{ + Q_UNUSED(name); + Q_UNUSED(value); +} + +void QSessionManager::setManagerProperty(const QString &name, + const QStringList &value) +{ + Q_UNUSED(name); + Q_UNUSED(value); +} + +bool QSessionManager::isPhase2() const +{ + return false; +} + +void QSessionManager::requestPhase2() +{ +} + +QT_END_NAMESPACE + +#endif // QT_NO_SESSIONMANAGER diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp index 1b26933..204efe9 100644 --- a/src/gui/kernel/qsoftkeymanager.cpp +++ b/src/gui/kernel/qsoftkeymanager.cpp @@ -50,6 +50,10 @@ #include "private/qsoftkeymanager_s60_p.h" #endif +#ifdef SYMBIAN_VERSION_SYMBIAN3 +#include "private/qt_s60_p.h" +#endif + #ifndef QT_NO_SOFTKEYMANAGER QT_BEGIN_NAMESPACE @@ -101,6 +105,30 @@ QSoftKeyManager::QSoftKeyManager() : QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *actionWidget) { QAction *action = new QAction(standardSoftKeyText(standardKey), actionWidget); +#ifdef SYMBIAN_VERSION_SYMBIAN3 + int key = 0; + switch (standardKey) { + case OkSoftKey: + key = EAknSoftkeyOk; + break; + case SelectSoftKey: + key = EAknSoftkeySelect; + break; + case DoneSoftKey: + key = EAknSoftkeyDone; + break; + case MenuSoftKey: + key = EAknSoftkeyOptions; + break; + case CancelSoftKey: + key = EAknSoftkeyCancel; + break; + default: + break; + }; + if (key != 0) + QSoftKeyManager::instance()->d_func()->softKeyCommandActions.insert(action, key); +#endif QAction::SoftKeyRole softKeyRole = QAction::NoSoftKey; switch (standardKey) { case MenuSoftKey: // FALL-THROUGH @@ -143,6 +171,9 @@ void QSoftKeyManager::cleanupHash(QObject *obj) Q_D(QSoftKeyManager); QAction *action = qobject_cast<QAction*>(obj); d->keyedActions.remove(action); +#ifdef SYMBIAN_VERSION_SYMBIAN3 + d->softKeyCommandActions.remove(action); +#endif } void QSoftKeyManager::sendKeyEvent() diff --git a/src/gui/kernel/qsoftkeymanager_common_p.h b/src/gui/kernel/qsoftkeymanager_common_p.h index 27d8ee9..02ae697 100644 --- a/src/gui/kernel/qsoftkeymanager_common_p.h +++ b/src/gui/kernel/qsoftkeymanager_common_p.h @@ -72,6 +72,9 @@ protected: QMultiHash<int, QAction*> requestedSoftKeyActions; QWidget *initialSoftKeySource; bool pendingUpdate; +#ifdef SYMBIAN_VERSION_SYMBIAN3 + QHash<QAction*, int> softKeyCommandActions; +#endif }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qsoftkeymanager_s60.cpp b/src/gui/kernel/qsoftkeymanager_s60.cpp index 3496297..d80cf8a 100644 --- a/src/gui/kernel/qsoftkeymanager_s60.cpp +++ b/src/gui/kernel/qsoftkeymanager_s60.cpp @@ -113,12 +113,20 @@ void QSoftKeyManagerPrivateS60::ensureCbaVisibilityAndResponsiviness(CEikButtonG void QSoftKeyManagerPrivateS60::clearSoftkeys(CEikButtonGroupContainer &cba) { +#ifdef SYMBIAN_VERSION_SYMBIAN3 + QT_TRAP_THROWING( + //EAknSoftkeyEmpty is used, because using -1 adds softkeys without actions on Symbian3 + cba.SetCommandL(0, EAknSoftkeyEmpty, KNullDesC); + cba.SetCommandL(2, EAknSoftkeyEmpty, KNullDesC); + ); +#else QT_TRAP_THROWING( //Using -1 instead of EAknSoftkeyEmpty to avoid flickering. cba.SetCommandL(0, -1, KNullDesC); // TODO: Should we clear also middle SK? cba.SetCommandL(2, -1, KNullDesC); ); +#endif realSoftKeyActions.clear(); } @@ -270,12 +278,6 @@ bool QSoftKeyManagerPrivateS60::setSoftkeyImage(CEikButtonGroupContainer *cba, EikSoftkeyImage::SetImage(cba, *myimage, left); // Takes myimage ownership cbaHasImage[position] = true; ret = true; - } else { - // Restore softkey to text based - if (cbaHasImage[position]) { - EikSoftkeyImage::SetLabel(cba, left); - cbaHasImage[position] = false; - } } } return ret; @@ -286,11 +288,20 @@ bool QSoftKeyManagerPrivateS60::setSoftkey(CEikButtonGroupContainer &cba, { QAction *action = highestPrioritySoftkey(role); if (action) { - setSoftkeyImage(&cba, *action, position); + bool hasImage = setSoftkeyImage(&cba, *action, position); QString text = softkeyText(*action); TPtrC nativeText = qt_QString2TPtrC(text); int command = S60_COMMAND_START + position; +#ifdef SYMBIAN_VERSION_SYMBIAN3 + if (softKeyCommandActions.contains(action)) + command = softKeyCommandActions.value(action); +#endif setNativeSoftkey(cba, position, command, nativeText); + if (!hasImage && cbaHasImage[position]) { + EikSoftkeyImage::SetLabel(&cba, (position == LSK_POSITION)); + cbaHasImage[position] = false; + } + const bool dimmed = !action->isEnabled() && !QSoftKeyManager::isForceEnabledInSofkeys(action); cba.DimCommand(command, dimmed); realSoftKeyActions.insert(command, action); @@ -301,7 +312,18 @@ bool QSoftKeyManagerPrivateS60::setSoftkey(CEikButtonGroupContainer &cba, bool QSoftKeyManagerPrivateS60::setLeftSoftkey(CEikButtonGroupContainer &cba) { - return setSoftkey(cba, QAction::PositiveSoftKey, LSK_POSITION); + if (!setSoftkey(cba, QAction::PositiveSoftKey, LSK_POSITION)) { + if (cbaHasImage[LSK_POSITION]) { + // Clear any residual icon if LSK has no action. A real softkey + // is needed for SetLabel command to work, so do a temporary dummy + setNativeSoftkey(cba, LSK_POSITION, EAknSoftkeyExit, KNullDesC); + EikSoftkeyImage::SetLabel(&cba, true); + setNativeSoftkey(cba, LSK_POSITION, EAknSoftkeyEmpty, KNullDesC); + cbaHasImage[LSK_POSITION] = false; + } + return false; + } + return true; } bool QSoftKeyManagerPrivateS60::setMiddleSoftkey(CEikButtonGroupContainer &cba) @@ -320,16 +342,26 @@ bool QSoftKeyManagerPrivateS60::setRightSoftkey(CEikButtonGroupContainer &cba) if (windowType != Qt::Dialog && windowType != Qt::Popup) { QString text(QSoftKeyManager::tr("Exit")); TPtrC nativeText = qt_QString2TPtrC(text); + setNativeSoftkey(cba, RSK_POSITION, EAknSoftkeyExit, nativeText); if (cbaHasImage[RSK_POSITION]) { EikSoftkeyImage::SetLabel(&cba, false); cbaHasImage[RSK_POSITION] = false; } - setNativeSoftkey(cba, RSK_POSITION, EAknSoftkeyExit, nativeText); cba.DimCommand(EAknSoftkeyExit, false); return true; + } else { + if (cbaHasImage[RSK_POSITION]) { + // Clear any residual icon if RSK has no action. A real softkey + // is needed for SetLabel command to work, so do a temporary dummy + setNativeSoftkey(cba, RSK_POSITION, EAknSoftkeyExit, KNullDesC); + EikSoftkeyImage::SetLabel(&cba, false); + setNativeSoftkey(cba, RSK_POSITION, EAknSoftkeyEmpty, KNullDesC); + cbaHasImage[RSK_POSITION] = false; + } + return false; } } - return false; + return true; } void QSoftKeyManagerPrivateS60::setSoftkeys(CEikButtonGroupContainer &cba) diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index 3bb27c3..4640393 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -77,6 +77,10 @@ #include <akncontext.h> // CAknContextPane #include <eikspane.h> // CEikStatusPane #include <AknPopupFader.h> // MAknFadedComponent and TAknPopupFader +#include <gfxtranseffect/gfxtranseffect.h> // BeginFullScreen +#ifdef QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H +#include <akntranseffect.h> // BeginFullScreen +#endif #endif QT_BEGIN_NAMESPACE @@ -85,11 +89,18 @@ QT_BEGIN_NAMESPACE // system events seems to start with 0x10 const TInt KInternalStatusPaneChange = 0x50000000; +// For BeginFullScreen(). +const TUint KQtAppExitFlag = 0x400; + static const int qt_symbian_max_screens = 4; //this macro exists because EColor16MAP enum value doesn't exist in Symbian OS 9.2 #define Q_SYMBIAN_ECOLOR16MAP TDisplayMode(13) +class QSymbianTypeFaceExtras; +typedef QHash<QString, const QSymbianTypeFaceExtras *> QSymbianTypeFaceExtrasHash; +typedef void (*QThreadLocalReleaseFunc)(); + class Q_AUTOTEST_EXPORT QS60ThreadLocalData { public: @@ -98,6 +109,8 @@ public: bool usingCONEinstances; RWsSession wsSession; CWsScreenDevice *screenDevice; + QSymbianTypeFaceExtrasHash fontData; + QVector<QThreadLocalReleaseFunc> releaseFuncs; }; class QS60Data @@ -146,6 +159,7 @@ public: int menuBeingConstructed : 1; int orientationSet : 1; int partial_keyboard : 1; + int partial_keyboardAutoTranslation : 1; QApplication::QS60MainApplicationFactory s60ApplicationFactory; // typedef'ed pointer type QPointer<QWidget> splitViewLastWidget; @@ -168,6 +182,8 @@ public: inline CWsScreenDevice* screenDevice(const QWidget *widget); inline CWsScreenDevice* screenDevice(int screenNumber); static inline int screenNumberForWidget(const QWidget *widget); + inline QSymbianTypeFaceExtrasHash& fontData(); + inline void addThreadLocalReleaseFunc(QThreadLocalReleaseFunc func); static inline CCoeAppUi* appUi(); static inline CEikMenuBar* menuBar(); #ifdef Q_WS_S60 @@ -178,6 +194,7 @@ public: static inline CEikButtonGroupContainer* buttonGroupContainer(); static inline void setButtonGroupContainer(CEikButtonGroupContainer* newCba); static void setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, bool buttonGroupVisible); + static bool setRecursiveDecorationsVisibility(QWidget *window, Qt::WindowStates newState); #endif static void controlVisibilityChanged(CCoeControl *control, bool visible); @@ -189,6 +206,12 @@ public: int screenHeightInPixelsForScreen[qt_symbian_max_screens]; int screenWidthInTwipsForScreen[qt_symbian_max_screens]; int screenHeightInTwipsForScreen[qt_symbian_max_screens]; + + int nativeScreenWidthInPixels; + int nativeScreenHeightInPixels; + + int beginFullScreenCalled : 1; + int endFullScreenCalled : 1; }; Q_AUTOTEST_EXPORT QS60Data* qGlobalS60Data(); @@ -233,6 +256,10 @@ public: bool isControlActive(); + void ensureFixNativeOrientation(); + QPoint translatePointForFixedNativeOrientation(const TPoint &pointerEventPos) const; + TRect translateRectForFixedNativeOrientation(const TRect &controlRect) const; + #ifdef Q_WS_S60 void FadeBehindPopup(bool fade){ popupFader.FadeBehindPopup( this, this, fade); } void HandleStatusPaneSizeChange(); @@ -251,6 +278,9 @@ protected: void PositionChanged(); void FocusChanged(TDrawNow aDrawNow); +protected: + void qwidgetResize_helper(const QSize &newSize); + private: void HandlePointerEvent(const TPointerEvent& aPointerEvent); TKeyResponse OfferKeyEvent(const TKeyEvent& aKeyEvent,TEventCode aType); @@ -270,6 +300,7 @@ private: void translateAdvancedPointerEvent(const TAdvancedPointerEvent *event); #endif bool isSplitViewWidget(QWidget *widget); + bool hasFocusedAndVisibleChild(QWidget *parentWidget); public: void handleClientAreaChange(); @@ -290,6 +321,7 @@ private: #endif bool m_inExternalScreenOverride : 1; + bool m_lastStatusPaneVisibility : 1; }; inline QS60Data::QS60Data() @@ -318,18 +350,23 @@ inline QS60Data::QS60Data() menuBeingConstructed(0), orientationSet(0), partial_keyboard(0), + partial_keyboardAutoTranslation(1), s60ApplicationFactory(0) #ifdef Q_OS_SYMBIAN ,s60InstalledTrapHandler(0) #endif + ,beginFullScreenCalled(0), + endFullScreenCalled(0) { } inline void QS60Data::updateScreenSize() { + CWsScreenDevice *dev = S60->screenDevice(); + int screenModeCount = dev->NumScreenModes(); + int mode = dev->CurrentScreenMode(); TPixelsTwipsAndRotation params; - int mode = S60->screenDevice()->CurrentScreenMode(); - S60->screenDevice()->GetScreenModeSizeAndRotation(mode, params); + dev->GetScreenModeSizeAndRotation(mode, params); S60->screenWidthInPixels = params.iPixelSize.iWidth; S60->screenHeightInPixels = params.iPixelSize.iHeight; S60->screenWidthInTwips = params.iTwipsSize.iWidth; @@ -352,6 +389,18 @@ inline void QS60Data::updateScreenSize() S60->screenWidthInTwipsForScreen[i] = params.iTwipsSize.iWidth; S60->screenHeightInTwipsForScreen[i] = params.iTwipsSize.iHeight; } + + // Look for a screen mode with rotation 0 + // in order to decide what the native orientation is. + for (mode = 0; mode < screenModeCount; ++mode) { + TPixelsAndRotation sizeAndRotation; + dev->GetScreenModeSizeAndRotation(mode, sizeAndRotation); + if (sizeAndRotation.iRotation == CFbsBitGc::EGraphicsOrientationNormal) { + S60->nativeScreenWidthInPixels = sizeAndRotation.iPixelSize.iWidth; + S60->nativeScreenHeightInPixels = sizeAndRotation.iPixelSize.iHeight; + break; + } + } } inline RWsSession& QS60Data::wsSession() @@ -432,6 +481,24 @@ inline int QS60Data::screenNumberForWidget(const QWidget *widget) return qt_widget_private(const_cast<QWidget *>(w))->symbianScreenNumber; } +inline QSymbianTypeFaceExtrasHash& QS60Data::fontData() +{ + if (!tls.hasLocalData()) { + tls.setLocalData(new QS60ThreadLocalData); + } + return tls.localData()->fontData; +} + +inline void QS60Data::addThreadLocalReleaseFunc(QThreadLocalReleaseFunc func) +{ + if (!tls.hasLocalData()) { + tls.setLocalData(new QS60ThreadLocalData); + } + QS60ThreadLocalData *data = tls.localData(); + if (!data->releaseFuncs.contains(func)) + data->releaseFuncs.append(func); +} + inline CCoeAppUi* QS60Data::appUi() { return CCoeEnv::Static()-> AppUi(); @@ -539,6 +606,49 @@ void qt_symbian_set_cursor_visible(bool visible); bool qt_symbian_is_cursor_visible(); #endif +static inline bool qt_beginFullScreenEffect() +{ +#if defined(Q_WS_S60) && defined(QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H) + // Only for post-S^3. On earlier versions the system transition effects + // may not be able to capture the non-Avkon content, leading to confusing + // looking effects, so just skip the whole thing. + if (S60->beginFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) + return false; + S60->beginFullScreenCalled = true; + // For Avkon apps the app-exit effect is triggered from CAknAppUi::PrepareToExit(). + // That is good for Avkon apps, but in case of Qt the RWindows are destroyed earlier. + // Therefore we call BeginFullScreen() ourselves. + GfxTransEffect::BeginFullScreen(AknTransEffect::EApplicationExit, + TRect(0, 0, 0, 0), + AknTransEffect::EParameterType, + AknTransEffect::GfxTransParam(S60->uid, + AknTransEffect::TParameter::EAvkonCheck | KQtAppExitFlag)); + return true; +#else + return false; +#endif +} + +static inline void qt_abortFullScreenEffect() +{ +#if defined(Q_WS_S60) && defined(QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H) + if (!S60->beginFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) + return; + GfxTransEffect::AbortFullScreen(); + S60->beginFullScreenCalled = S60->endFullScreenCalled = false; +#endif +} + +static inline void qt_endFullScreenEffect() +{ +#if defined(Q_WS_S60) && defined(QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H) + if (S60->endFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) + return; + S60->endFullScreenCalled = true; + GfxTransEffect::EndFullScreen(); +#endif +} + QT_END_NAMESPACE #endif // QT_S60_P_H diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 23d063d..80d7b85 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -312,6 +312,7 @@ QWidgetPrivate::QWidgetPrivate(int version) , qd_hd(0) #elif defined(Q_OS_SYMBIAN) , symbianScreenNumber(0) + , fixNativeOrientationCalled(false) #endif { if (!qApp) { @@ -367,9 +368,12 @@ QWindowSurface *QWidgetPrivate::createDefaultWindowSurface() Q_Q(QWidget); QWindowSurface *surface; +#ifndef QT_NO_PROPERTIES if (q->property("_q_DummyWindowSurface").toBool()) { surface = new QDummyWindowSurface(q); - } else { + } else +#endif + { if (QApplicationPrivate::graphicsSystem()) surface = QApplicationPrivate::graphicsSystem()->createWindowSurface(q); else @@ -609,7 +613,6 @@ void QWidget::setAutoFillBackground(bool enabled) \ingroup basicwidgets - The widget is the atom of the user interface: it receives mouse, keyboard and other events from the window system, and paints a representation of itself on the screen. Every widget is rectangular, and they are sorted in a @@ -1585,6 +1588,7 @@ QWidget::~QWidget() // delete layout while we still are a valid widget delete d->layout; + d->layout = 0; // Remove myself from focus list Q_ASSERT(d->focus_next->d_func()->focus_prev == this); @@ -10967,6 +10971,9 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) } QT_TRAP_THROWING(appUi->SetOrientationL(s60orientation)); S60->orientationSet = true; + QSymbianControl *window = static_cast<QSymbianControl *>(internalWinId()); + if (window) + window->ensureFixNativeOrientation(); #endif break; } @@ -11199,6 +11206,7 @@ void QWidget::setAccessibleName(const QString &name) { Q_D(QWidget); d->accessibleName = name; + QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged); } QString QWidget::accessibleName() const @@ -11220,6 +11228,7 @@ void QWidget::setAccessibleDescription(const QString &description) { Q_D(QWidget); d->accessibleDescription = description; + QAccessible::updateAccessibility(this, 0, QAccessible::DescriptionChanged); } QString QWidget::accessibleDescription() const diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 34918e4..354f05b 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -2849,6 +2849,11 @@ void QWidgetPrivate::transferChildren() #ifdef QT_MAC_USE_COCOA void QWidgetPrivate::setSubWindowStacking(bool set) { + // After hitting too many unforeseen bugs trying to put Qt on top of the cocoa child + // window API, we have decided to revert this behaviour as much as we can. We + // therefore now only allow child windows to exist for children of modal dialogs. + static bool use_behaviour_qt473 = !qgetenv("QT_MAC_USE_CHILDWINDOWS").isEmpty(); + // This will set/remove a visual relationship between parent and child on screen. // The reason for doing this is to ensure that a child always stacks infront of // its parent. Unfortunatly is turns out that [NSWindow addChildWindow] has @@ -2877,7 +2882,10 @@ void QWidgetPrivate::setSubWindowStacking(bool set) if (NSWindow *pwin = [qt_mac_nativeview_for(parent) window]) { if (set) { Qt::WindowType ptype = parent->window()->windowType(); - if ([pwin isVisible] && (ptype == Qt::Window || ptype == Qt::Dialog) && ![qwin parentWindow]) { + if ([pwin isVisible] + && (ptype == Qt::Window || ptype == Qt::Dialog) + && ![qwin parentWindow] + && (use_behaviour_qt473 || parent->windowModality() == Qt::ApplicationModal)) { NSInteger level = [qwin level]; [pwin addChildWindow:qwin ordered:NSWindowAbove]; if ([qwin level] < level) @@ -2889,6 +2897,10 @@ void QWidgetPrivate::setSubWindowStacking(bool set) } } + // Only set-up child windows for q if q is modal: + if (set && !use_behaviour_qt473 && q->windowModality() != Qt::ApplicationModal) + return; + QObjectList widgets = q->children(); for (int i=0; i<widgets.size(); ++i) { QWidget *child = qobject_cast<QWidget *>(widgets.at(i)); diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index e5a2c35..919f8bc 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -908,6 +908,7 @@ public: static QWidget *mouseGrabber; static QWidget *keyboardGrabber; int symbianScreenNumber; // only valid for desktop widget and top-levels + bool fixNativeOrientationCalled; void s60UpdateIsOpaque(); void reparentChildren(); void registerTouchWindow(); diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index b031936..5e9584b 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -235,11 +235,22 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) QSize oldSize(q->size()); QRect oldGeom(data.crect); + bool checkExtra = true; + if (q->isWindow() && (data.window_state & (Qt::WindowFullScreen | Qt::WindowMaximized))) { + // Do not allow fullscreen/maximized windows to expand beyond client rect + TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + w = qMin(w, r.Width()); + h = qMin(h, r.Height()); + + if (w == r.Width() && h == r.Height()) + checkExtra = false; + } + // Lose maximized status if deliberate resize if (w != oldSize.width() || h != oldSize.height()) data.window_state &= ~Qt::WindowMaximized; - if (extra) { // any size restrictions? + if (checkExtra && extra) { // any size restrictions? w = qMin(w,extra->maxw); h = qMin(h,extra->maxh); w = qMax(w,extra->minw); @@ -278,6 +289,8 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); topData()->normalGeometry = data.crect; } + QSymbianControl *window = static_cast<QSymbianControl *>(q->internalWinId()); + window->ensureFixNativeOrientation(); } else { data.crect.setRect(x, y, w, h); @@ -840,6 +853,8 @@ void QWidgetPrivate::s60UpdateIsOpaque() // recreate backing store to get translucent surface (raster surface). extra->topextra->backingStore.create(q); extra->topextra->backingStore.registerWidget(q); + // FixNativeOrientation() will not work without an EGL surface. + q->setAttribute(Qt::WA_SymbianNoSystemRotation, false); } } } else if (extra->topextra->nativeWindowTransparencyEnabled) { @@ -1208,17 +1223,10 @@ void QWidget::setWindowState(Qt::WindowStates newstate) } #ifdef Q_WS_S60 - bool decorationsVisible(false); - if (!parentWidget()) { // Only top level native windows have control over cba/status pane - // Hide window decoration when switching to fullscreen / minimized otherwise show decoration. - // The window decoration visibility has to be changed before doing actual window state - // change since in that order the availableGeometry will return directly the right size and - // we will avoid unnecessary redraws - decorationsVisible = !(newstate & (Qt::WindowFullScreen | Qt::WindowMinimized)); - const bool statusPaneVisibility = decorationsVisible; - const bool buttonGroupVisibility = (decorationsVisible || (isFullscreen && cbaRequested)); - S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility); - } + // The window decoration visibility has to be changed before doing actual window state + // change since in that order the availableGeometry will return directly the right size and + // we will avoid unnecessary redraws + bool decorationsVisible = S60->setRecursiveDecorationsVisibility(this, newstate); #endif // Q_WS_S60 // Ensure the initial size is valid, since we store it as normalGeometry below. @@ -1277,6 +1285,12 @@ void QWidget::setWindowState(Qt::WindowStates newstate) if (newstate & Qt::WindowActive) activateWindow(); + if (isWindow()) { + // Now that the new state is set, fix the display memory layout, if needed. + QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId()); + window->ensureFixNativeOrientation(); + } + QWindowStateChangeEvent e(oldstate); QApplication::sendEvent(this, &e); } @@ -1423,7 +1437,8 @@ void QWidget::activateWindow() if (tlw->isVisible()) { window()->createWinId(); QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId()); - id->setFocusSafely(true); + if (!id->IsFocused()) + id->setFocusSafely(true); } } diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index c6753fc..3eec5c7 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -486,8 +486,6 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO bool topLevel = (flags & Qt::Window); bool popup = (type == Qt::Popup); - bool dialog = (type == Qt::Dialog - || type == Qt::Sheet); bool desktop = (type == Qt::Desktop); bool tool = (type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer); @@ -553,7 +551,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO int sh = DisplayHeight(dpy,scr); if (desktop) { // desktop widget - dialog = popup = false; // force these flags off + popup = false; // force these flags off data.crect.setRect(0, 0, sw, sh); } else if (topLevel && !q->testAttribute(Qt::WA_Resized)) { QDesktopWidget *desktopWidget = qApp->desktop(); @@ -954,8 +952,13 @@ static void qt_x11_recreateWidget(QWidget *widget) // recreate their GL context, which in turn causes them to choose // their visual again. Now that WA_TranslucentBackground is set, // QGLContext::chooseVisual will select an ARGB visual. - QEvent e(QEvent::ParentChange); - QApplication::sendEvent(widget, &e); + + // QGLWidget expects a ParentAboutToChange to be sent first + QEvent aboutToChangeEvent(QEvent::ParentAboutToChange); + QApplication::sendEvent(widget, &aboutToChangeEvent); + + QEvent parentChangeEvent(QEvent::ParentChange); + QApplication::sendEvent(widget, &parentChangeEvent); } else { // For regular widgets, reparent them with their parent which // also triggers a recreation of the native window @@ -1333,12 +1336,40 @@ QPoint QWidgetPrivate::mapFromGlobal(const QPoint &pos) const QPoint QWidget::mapToGlobal(const QPoint &pos) const { Q_D(const QWidget); + QPoint offset = data->crect.topLeft(); + const QWidget *w = this; + const QWidget *p = w->parentWidget(); + while (!w->isWindow() && p) { + w = p; + p = p->parentWidget(); + offset += w->data->crect.topLeft(); + } + + const QWidgetPrivate *wd = w->d_func(); + QTLWExtra *tlw = wd->topData(); + if (!tlw->embedded) + return pos + offset; + return d->mapToGlobal(pos); } QPoint QWidget::mapFromGlobal(const QPoint &pos) const { Q_D(const QWidget); + QPoint offset = data->crect.topLeft(); + const QWidget *w = this; + const QWidget *p = w->parentWidget(); + while (!w->isWindow() && p) { + w = p; + p = p->parentWidget(); + offset += w->data->crect.topLeft(); + } + + const QWidgetPrivate *wd = w->d_func(); + QTLWExtra *tlw = wd->topData(); + if (!tlw->embedded) + return pos - offset; + return d->mapFromGlobal(pos); } @@ -1352,9 +1383,15 @@ void QWidgetPrivate::updateSystemBackground() if (brush.style() == Qt::NoBrush || q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_UpdatesDisabled) - || type == Qt::Popup || type == Qt::ToolTip - ) - XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), XNone); + || type == Qt::Popup || type == Qt::ToolTip) { + if (QX11Info::isCompositingManagerRunning() + && q->testAttribute(Qt::WA_TranslucentBackground) + && !(q->parent())) + XSetWindowBackground(X11->display, q->internalWinId(), + QColormap::instance(xinfo.screen()).pixel(Qt::transparent)); + else + XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), XNone); + } else if (brush.style() == Qt::SolidPattern && brush.isOpaque()) XSetWindowBackground(X11->display, q->internalWinId(), QColormap::instance(xinfo.screen()).pixel(brush.color())); diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index e5d8abc..42c1c35 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -588,7 +588,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up return; } - if (!windowSurface->hasPartialUpdateSupport()) { + if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) { fullUpdatePending = true; sendUpdateRequest(tlw, updateImmediately); return; @@ -683,7 +683,7 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd return; } - if (!windowSurface->hasPartialUpdateSupport()) { + if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) { fullUpdatePending = true; sendUpdateRequest(tlw, updateImmediately); return; @@ -1143,9 +1143,9 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg return; } - // If there's no partial update support we always need + // If there's no preserved contents support we always need // to do a full repaint before flushing - if (!windowSurface->hasPartialUpdateSupport()) + if (!windowSurface->hasFeature(QWindowSurface::PreservedContents)) fullUpdatePending = true; // Nothing to repaint. diff --git a/src/gui/painting/qbackingstore_p.h b/src/gui/painting/qbackingstore_p.h index 39bf66c..05f4bfc 100644 --- a/src/gui/painting/qbackingstore_p.h +++ b/src/gui/painting/qbackingstore_p.h @@ -262,8 +262,7 @@ private: } inline bool hasStaticContents() const - { return !staticWidgets.isEmpty() && windowSurface->hasStaticContentsSupport() - && windowSurface->hasPartialUpdateSupport(); } + { return !staticWidgets.isEmpty() && windowSurface->hasFeature(QWindowSurface::StaticContents); } friend QRegion qt_dirtyRegion(QWidget *); friend class QWidgetPrivate; diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index 119cf1c..a2f0edd 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -65,13 +65,6 @@ QT_BEGIN_NAMESPACE #define M_SQRT2 1.41421356237309504880 #endif -#define log2(x) (qLn(x)/qLn(2.)) - -static inline qreal log4(qreal x) -{ - return qreal(0.5) * log2(x); -} - /*! \internal */ @@ -184,7 +177,7 @@ static inline bool findInflections(qreal a, qreal b, qreal c, *t2 = r1; } if (!qFuzzyIsNull(a)) - *tCups = 0.5 * (-b / a); + *tCups = qreal(0.5) * (-b / a); else *tCups = 2; @@ -274,8 +267,8 @@ static ShiftResult good_offset(const QBezier *b1, const QBezier *b2, qreal offse const qreal o2 = offset*offset; const qreal max_dist_line = threshold*offset*offset; const qreal max_dist_normal = threshold*offset; - const qreal spacing = 0.25; - for (qreal i = spacing; i < 0.99; i += spacing) { + const qreal spacing = qreal(0.25); + for (qreal i = spacing; i < qreal(0.99); i += spacing) { QPointF p1 = b1->pointAt(i); QPointF p2 = b2->pointAt(i); qreal d = (p1.x() - p2.x())*(p1.x() - p2.x()) + (p1.y() - p2.y())*(p1.y() - p2.y()); @@ -284,7 +277,7 @@ static ShiftResult good_offset(const QBezier *b1, const QBezier *b2, qreal offse QPointF normalPoint = b1->normalVector(i); qreal l = qAbs(normalPoint.x()) + qAbs(normalPoint.y()); - if (l != 0.) { + if (l != qreal(0.0)) { d = qAbs( normalPoint.x()*(p1.y() - p2.y()) - normalPoint.y()*(p1.x() - p2.x()) ) / l; if (d > max_dist_normal) return Split; @@ -350,7 +343,7 @@ static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qr QPointF normal_sum = prev_normal + next_normal; - qreal r = 1.0 + prev_normal.x() * next_normal.x() + qreal r = qreal(1.0) + prev_normal.x() * next_normal.x() + prev_normal.y() * next_normal.y(); if (qFuzzyIsNull(r)) { @@ -374,7 +367,7 @@ static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qr // This value is used to determine the length of control point vectors // when approximating arc segments as curves. The factor is multiplied // with the radius of the circle. -#define KAPPA 0.5522847498 +#define KAPPA qreal(0.5522847498) static bool addCircle(const QBezier *b, qreal offset, QBezier *o) @@ -417,11 +410,11 @@ static bool addCircle(const QBezier *b, qreal offset, QBezier *o) QPointF circle[3]; circle[0] = QPointF(b->x1, b->y1) + normals[0]*offset; - circle[1] = QPointF(0.5*(b->x1 + b->x4), 0.5*(b->y1 + b->y4)) + normals[1]*offset; + circle[1] = QPointF(qreal(0.5)*(b->x1 + b->x4), qreal(0.5)*(b->y1 + b->y4)) + normals[1]*offset; circle[2] = QPointF(b->x4, b->y4) + normals[2]*offset; for (int i = 0; i < 2; ++i) { - qreal kappa = 2.*KAPPA * sign * offset * angles[i]; + qreal kappa = qreal(2.0) * KAPPA * sign * offset * angles[i]; o->x1 = circle[i].x(); o->y1 = circle[i].y(); @@ -456,8 +449,8 @@ redo: while (b >= beziers) { int stack_segments = b - beziers + 1; if ((stack_segments == 10) || (o - curveSegments == maxSegments - stack_segments)) { - threshold *= 1.5; - if (threshold > 2.) + threshold *= qreal(1.5); + if (threshold > qreal(2.0)) goto give_up; goto redo; } @@ -535,7 +528,7 @@ static inline void splitBezierAt(const QBezier &bez, qreal t, qreal QBezier::length(qreal error) const { - qreal length = 0.0; + qreal length = qreal(0.0); addIfClose(&length, error); @@ -546,8 +539,8 @@ void QBezier::addIfClose(qreal *length, qreal error) const { QBezier left, right; /* bez poly splits */ - qreal len = 0.0; /* arc length */ - qreal chord; /* chord length */ + qreal len = qreal(0.0); /* arc length */ + qreal chord; /* chord length */ len = len + QLineF(QPointF(x1, y1),QPointF(x2, y2)).length(); len = len + QLineF(QPointF(x2, y2),QPointF(x3, y3)).length(); @@ -589,7 +582,7 @@ qreal QBezier::tForY(qreal t0, qreal t1, qreal y) const qreal lt = t0; qreal dt; do { - qreal t = 0.5 * (t0 + t1); + qreal t = qreal(0.5) * (t0 + t1); qreal a, b, c, d; QBezier::coefficients(t, a, b, c, d); @@ -604,7 +597,7 @@ qreal QBezier::tForY(qreal t0, qreal t1, qreal y) const } dt = lt - t; lt = t; - } while (qAbs(dt) > 1e-7); + } while (qAbs(dt) > qreal(1e-7)); return t0; } @@ -661,15 +654,15 @@ int QBezier::stationaryYPoints(qreal &t0, qreal &t1) const qreal QBezier::tAtLength(qreal l) const { qreal len = length(); - qreal t = 1.0; - const qreal error = (qreal)0.01; + qreal t = qreal(1.0); + const qreal error = qreal(0.01); if (l > len || qFuzzyCompare(l, len)) return t; - t *= 0.5; + t *= qreal(0.5); //int iters = 0; //qDebug()<<"LEN is "<<l<<len; - qreal lastBigger = 1.; + qreal lastBigger = qreal(1.0); while (1) { //qDebug()<<"\tt is "<<t; QBezier right = *this; @@ -680,10 +673,10 @@ qreal QBezier::tAtLength(qreal l) const break; if (lLen < l) { - t += (lastBigger - t)*.5; + t += (lastBigger - t) * qreal(0.5); } else { lastBigger = t; - t -= t*.5; + t -= t * qreal(0.5); } //++iters; } diff --git a/src/gui/painting/qblendfunctions_p.h b/src/gui/painting/qblendfunctions_p.h index 8aff912..81f8b70 100644 --- a/src/gui/painting/qblendfunctions_p.h +++ b/src/gui/painting/qblendfunctions_p.h @@ -275,8 +275,8 @@ void qt_transform_image_rasterize(DestT *destPixels, int dbpl, qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y); int dx_l = int(leftSlope * 0x10000); int dx_r = int(rightSlope * 0x10000); - int x_l = int((topLeft.x + (0.5 + fromY - topLeft.y) * leftSlope + 0.5) * 0x10000); - int x_r = int((topRight.x + (0.5 + fromY - topRight.y) * rightSlope + 0.5) * 0x10000); + int x_l = int((topLeft.x + (qreal(0.5) + fromY - topLeft.y) * leftSlope + qreal(0.5)) * 0x10000); + int x_r = int((topRight.x + (qreal(0.5) + fromY - topRight.y) * rightSlope + qreal(0.5)) * 0x10000); int fromX, toX, x1, x2, u, v, i, ii; DestT *line; @@ -471,8 +471,8 @@ void qt_transform_image(DestT *destPixels, int dbpl, int dvdx = int(m21 * 0x10000); int dudy = int(m12 * 0x10000); int dvdy = int(m22 * 0x10000); - int u0 = qCeil((0.5 * m11 + 0.5 * m12 + mdx) * 0x10000) - 1; - int v0 = qCeil((0.5 * m21 + 0.5 * m22 + mdy) * 0x10000) - 1; + int u0 = qCeil((qreal(0.5) * m11 + qreal(0.5) * m12 + mdx) * 0x10000) - 1; + int v0 = qCeil((qreal(0.5) * m21 + qreal(0.5) * m22 + mdy) * 0x10000) - 1; int x1 = qFloor(sourceRect.left()); int y1 = qFloor(sourceRect.top()); diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 811f3ae..3ff7eb8 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -49,6 +49,7 @@ #include "qdebug.h" #include <QtCore/qcoreapplication.h> #include "private/qstylehelper_p.h" +#include <QtCore/qnumeric.h> QT_BEGIN_NAMESPACE @@ -839,6 +840,22 @@ const QGradient *QBrush::gradient() const return 0; } +Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush) +{ + if (brush.style() == Qt::RadialGradientPattern) { + const QGradient *g = brush.gradient(); + const QRadialGradient *rg = static_cast<const QRadialGradient *>(g); + + if (!qFuzzyIsNull(rg->focalRadius())) + return true; + + QPointF delta = rg->focalPoint() - rg->center(); + if (delta.x() * delta.x() + delta.y() * delta.y() > rg->radius() * rg->radius()) + return true; + } + + return false; +} /*! Returns true if the brush is fully opaque otherwise false. A brush @@ -848,6 +865,7 @@ const QGradient *QBrush::gradient() const \i The alpha component of the color() is 255. \i Its texture() does not have an alpha channel and is not a QBitmap. \i The colors in the gradient() all have an alpha component that is 255. + \i It is an extended radial gradient. \endlist */ @@ -859,6 +877,9 @@ bool QBrush::isOpaque() const if (d->style == Qt::SolidPattern) return opaqueColor; + if (qt_isExtendedRadialGradient(*this)) + return false; + if (d->style == Qt::LinearGradientPattern || d->style == Qt::RadialGradientPattern || d->style == Qt::ConicalGradientPattern) { @@ -1208,8 +1229,10 @@ QDataStream &operator>>(QDataStream &s, QBrush &b) \list \o \e Linear gradients interpolate colors between start and end points. - \o \e Radial gradients interpolate colors between a focal point and end - points on a circle surrounding it. + \o \e Simple radial gradients interpolate colors between a focal point + and end points on a circle surrounding it. + \o \e Extended radial gradients interpolate colors between a center and + a focal circle. \o \e Conical gradients interpolate colors around a center point. \endlist @@ -1369,13 +1392,14 @@ QGradient::QGradient() void QGradient::setColorAt(qreal pos, const QColor &color) { - if (pos > 1 || pos < 0) { + if ((pos > 1 || pos < 0) && !qIsNaN(pos)) { qWarning("QGradient::setColorAt: Color position must be specified in the range 0 to 1"); return; } int index = 0; - while (index < m_stops.size() && m_stops.at(index).first < pos) ++index; + if (!qIsNaN(pos)) + while (index < m_stops.size() && m_stops.at(index).first < pos) ++index; if (index < m_stops.size() && m_stops.at(index).first == pos) m_stops[index].second = color; @@ -1504,8 +1528,6 @@ void QGradient::setInterpolationMode(InterpolationMode mode) dummy = p; } -#undef Q_DUMMY_ACCESSOR - /*! \fn bool QGradient::operator!=(const QGradient &gradient) const \since 4.2 @@ -1539,7 +1561,7 @@ bool QGradient::operator==(const QGradient &gradient) const || m_data.radial.cy != gradient.m_data.radial.cy || m_data.radial.fx != gradient.m_data.radial.fx || m_data.radial.fy != gradient.m_data.radial.fy - || m_data.radial.radius != gradient.m_data.radial.radius) + || m_data.radial.cradius != gradient.m_data.radial.cradius) return false; } else { // m_type == ConicalGradient if (m_data.conical.cx != gradient.m_data.conical.cx @@ -1745,10 +1767,17 @@ void QLinearGradient::setFinalStop(const QPointF &stop) \brief The QRadialGradient class is used in combination with QBrush to specify a radial gradient brush. - Radial gradients interpolate colors between a focal point and end - points on a circle surrounding it. Outside the end points the - gradient is either padded, reflected or repeated depending on the - currently set \l {QGradient::Spread}{spread} method: + Qt supports both simple and extended radial gradients. + + Simple radial gradients interpolate colors between a focal point and end + points on a circle surrounding it. Extended radial gradients interpolate + colors between a focal circle and a center circle. Points outside the cone + defined by the two circles will be transparent. For simple radial gradients + the focal point is adjusted to lie inside the center circle, whereas the + focal point can have any position in an extended radial gradient. + + Outside the end points the gradient is either padded, reflected or repeated + depending on the currently set \l {QGradient::Spread}{spread} method: \table \row @@ -1785,7 +1814,7 @@ static QPointF qt_radial_gradient_adapt_focal_point(const QPointF ¢er, // We have a one pixel buffer zone to avoid numerical instability on the // circle border //### this is hacky because technically we should adjust based on current matrix - const qreal compensated_radius = radius - radius * 0.001; + const qreal compensated_radius = radius - radius * qreal(0.001); QLineF line(center, focalPoint); if (line.length() > (compensated_radius)) line.setLength(compensated_radius); @@ -1793,9 +1822,14 @@ static QPointF qt_radial_gradient_adapt_focal_point(const QPointF ¢er, } /*! - Constructs a radial gradient with the given \a center, \a + Constructs a simple radial gradient with the given \a center, \a radius and \a focalPoint. + \note If the given focal point is outside the circle defined by the + center (\a cx, \a cy) and the \a radius it will be re-adjusted to + the intersection between the line from the center to the focal point + and the circle. + \sa QGradient::setColorAt(), QGradient::setStops() */ @@ -1805,7 +1839,7 @@ QRadialGradient::QRadialGradient(const QPointF ¢er, qreal radius, const QPoi m_spread = PadSpread; m_data.radial.cx = center.x(); m_data.radial.cy = center.y(); - m_data.radial.radius = radius; + m_data.radial.cradius = radius; QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint); m_data.radial.fx = adapted_focal.x(); @@ -1813,7 +1847,7 @@ QRadialGradient::QRadialGradient(const QPointF ¢er, qreal radius, const QPoi } /*! - Constructs a radial gradient with the given \a center, \a + Constructs a simple radial gradient with the given \a center, \a radius and the focal point in the circle center. \sa QGradient::setColorAt(), QGradient::setStops() @@ -1824,16 +1858,21 @@ QRadialGradient::QRadialGradient(const QPointF ¢er, qreal radius) m_spread = PadSpread; m_data.radial.cx = center.x(); m_data.radial.cy = center.y(); - m_data.radial.radius = radius; + m_data.radial.cradius = radius; m_data.radial.fx = center.x(); m_data.radial.fy = center.y(); } /*! - Constructs a radial gradient with the given center (\a cx, \a cy), + Constructs a simple radial gradient with the given center (\a cx, \a cy), \a radius and focal point (\a fx, \a fy). + \note If the given focal point is outside the circle defined by the + center (\a cx, \a cy) and the \a radius it will be re-adjusted to + the intersection between the line from the center to the focal point + and the circle. + \sa QGradient::setColorAt(), QGradient::setStops() */ @@ -1843,7 +1882,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre m_spread = PadSpread; m_data.radial.cx = cx; m_data.radial.cy = cy; - m_data.radial.radius = radius; + m_data.radial.cradius = radius; QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(QPointF(cx, cy), radius, @@ -1854,7 +1893,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre } /*! - Constructs a radial gradient with the center at (\a cx, \a cy) and the + Constructs a simple radial gradient with the center at (\a cx, \a cy) and the specified \a radius. The focal point lies at the center of the circle. \sa QGradient::setColorAt(), QGradient::setStops() @@ -1865,14 +1904,14 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius) m_spread = PadSpread; m_data.radial.cx = cx; m_data.radial.cy = cy; - m_data.radial.radius = radius; + m_data.radial.cradius = radius; m_data.radial.fx = cx; m_data.radial.fy = cy; } /*! - Constructs a radial gradient with the center and focal point at + Constructs a simple radial gradient with the center and focal point at (0, 0) with a radius of 1. */ QRadialGradient::QRadialGradient() @@ -1881,11 +1920,51 @@ QRadialGradient::QRadialGradient() m_spread = PadSpread; m_data.radial.cx = 0; m_data.radial.cy = 0; - m_data.radial.radius = 1; + m_data.radial.cradius = 1; m_data.radial.fx = 0; m_data.radial.fy = 0; } +/*! + \since 4.8 + + Constructs an extended radial gradient with the given \a center, \a + centerRadius, \a focalPoint, and \a focalRadius. +*/ +QRadialGradient::QRadialGradient(const QPointF ¢er, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius) +{ + m_type = RadialGradient; + m_spread = PadSpread; + m_data.radial.cx = center.x(); + m_data.radial.cy = center.y(); + m_data.radial.cradius = centerRadius; + + m_data.radial.fx = focalPoint.x(); + m_data.radial.fy = focalPoint.y(); + setFocalRadius(focalRadius); +} + +/*! + \since 4.8 + + Constructs an extended radial gradient with the given \a center, \a + centerRadius, \a focalPoint, and \a focalRadius. + Constructs a radial gradient with the given center (\a cx, \a cy), + center radius \a centerRadius, focal point (\a fx, \a fy), and + focal radius \a focalRadius. +*/ +QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius) +{ + m_type = RadialGradient; + m_spread = PadSpread; + m_data.radial.cx = cx; + m_data.radial.cy = cy; + m_data.radial.cradius = centerRadius; + + m_data.radial.fx = fx; + m_data.radial.fy = fy; + setFocalRadius(focalRadius); +} /*! Returns the center of this radial gradient in logical coordinates. @@ -1930,13 +2009,15 @@ void QRadialGradient::setCenter(const QPointF ¢er) /*! Returns the radius of this radial gradient in logical coordinates. + Equivalent to centerRadius() + \sa QGradient::stops() */ qreal QRadialGradient::radius() const { Q_ASSERT(m_type == RadialGradient); - return m_data.radial.radius; + return m_data.radial.cradius; } @@ -1945,13 +2026,81 @@ qreal QRadialGradient::radius() const Sets the radius of this radial gradient in logical coordinates to \a radius + + Equivalent to setCenterRadius() */ void QRadialGradient::setRadius(qreal radius) { Q_ASSERT(m_type == RadialGradient); - m_data.radial.radius = radius; + m_data.radial.cradius = radius; +} + +/*! + \since 4.8 + + Returns the center radius of this radial gradient in logical + coordinates. + + \sa QGradient::stops() +*/ +qreal QRadialGradient::centerRadius() const +{ + Q_ASSERT(m_type == RadialGradient); + return m_data.radial.cradius; +} + +/* + \since 4.8 + + Sets the center radius of this radial gradient in logical coordinates + to \a radius +*/ +void QRadialGradient::setCenterRadius(qreal radius) +{ + Q_ASSERT(m_type == RadialGradient); + m_data.radial.cradius = radius; +} + +/*! + \since 4.8 + + Returns the focal radius of this radial gradient in logical + coordinates. + + \sa QGradient::stops() +*/ +qreal QRadialGradient::focalRadius() const +{ + Q_ASSERT(m_type == RadialGradient); + Q_DUMMY_ACCESSOR + + // mask away low three bits + union { float f; quint32 i; } u; + u.i = i & ~0x07; + return u.f; } +/* + \since 4.8 + + Sets the focal radius of this radial gradient in logical coordinates + to \a radius +*/ +void QRadialGradient::setFocalRadius(qreal radius) +{ + Q_ASSERT(m_type == RadialGradient); + Q_DUMMY_ACCESSOR + + // Since there's no QGradientData, we only have the dummy void * to + // store additional data in. The three lowest bits are already + // taken, thus we cut the three lowest bits from the significand + // and store the radius as a float. + union { float f; quint32 i; } u; + u.f = float(radius); + // add 0x04 to round up when we drop the three lowest bits + i |= (u.i + 0x04) & ~0x07; + dummy = p; +} /*! Returns the focal point of this radial gradient in logical @@ -2191,4 +2340,6 @@ void QConicalGradient::setAngle(qreal angle) \sa setTransform() */ +#undef Q_DUMMY_ACCESSOR + QT_END_NAMESPACE diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h index 8b31319..d914c8c 100644 --- a/src/gui/painting/qbrush.h +++ b/src/gui/painting/qbrush.h @@ -255,6 +255,7 @@ private: friend class QLinearGradient; friend class QRadialGradient; friend class QConicalGradient; + friend class QBrush; Type m_type; Spread m_spread; @@ -264,7 +265,7 @@ private: qreal x1, y1, x2, y2; } linear; struct { - qreal cx, cy, fx, fy, radius; + qreal cx, cy, fx, fy, cradius; } radial; struct { qreal cx, cy, angle; @@ -303,6 +304,9 @@ public: QRadialGradient(const QPointF ¢er, qreal radius); QRadialGradient(qreal cx, qreal cy, qreal radius); + QRadialGradient(const QPointF ¢er, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius); + QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius); + QPointF center() const; void setCenter(const QPointF ¢er); inline void setCenter(qreal x, qreal y) { setCenter(QPointF(x, y)); } @@ -313,6 +317,12 @@ public: qreal radius() const; void setRadius(qreal radius); + + qreal centerRadius() const; + void setCenterRadius(qreal radius); + + qreal focalRadius() const; + void setFocalRadius(qreal radius); }; diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 73a6ed8..ff6c24e 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -629,7 +629,7 @@ void QColor::getHsvF(qreal *h, qreal *s, qreal *v, qreal *a) const return; } - *h = ct.ahsv.hue == USHRT_MAX ? -1.0 : ct.ahsv.hue / 36000.0; + *h = ct.ahsv.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsv.hue / qreal(36000.0); *s = ct.ahsv.saturation / qreal(USHRT_MAX); *v = ct.ahsv.value / qreal(USHRT_MAX); @@ -676,17 +676,17 @@ void QColor::getHsv(int *h, int *s, int *v, int *a) const */ void QColor::setHsvF(qreal h, qreal s, qreal v, qreal a) { - if (((h < 0.0 || h > 1.0) && h != -1.0) - || (s < 0.0 || s > 1.0) - || (v < 0.0 || v > 1.0) - || (a < 0.0 || a > 1.0)) { + if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0)) + || (s < qreal(0.0) || s > qreal(1.0)) + || (v < qreal(0.0) || v > qreal(1.0)) + || (a < qreal(0.0) || a > qreal(1.0))) { qWarning("QColor::setHsvF: HSV parameters out of range"); return; } cspec = Hsv; ct.ahsv.alpha = qRound(a * USHRT_MAX); - ct.ahsv.hue = h == -1.0 ? USHRT_MAX : qRound(h * 36000); + ct.ahsv.hue = h == qreal(-1.0) ? USHRT_MAX : qRound(h * 36000); ct.ahsv.saturation = qRound(s * USHRT_MAX); ct.ahsv.value = qRound(v * USHRT_MAX); ct.ahsv.pad = 0; @@ -740,7 +740,7 @@ void QColor::getHslF(qreal *h, qreal *s, qreal *l, qreal *a) const return; } - *h = ct.ahsl.hue == USHRT_MAX ? -1.0 : ct.ahsl.hue / 36000.0; + *h = ct.ahsl.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsl.hue / qreal(36000.0); *s = ct.ahsl.saturation / qreal(USHRT_MAX); *l = ct.ahsl.lightness / qreal(USHRT_MAX); @@ -790,17 +790,17 @@ void QColor::getHsl(int *h, int *s, int *l, int *a) const */ void QColor::setHslF(qreal h, qreal s, qreal l, qreal a) { - if (((h < 0.0 || h > 1.0) && h != -1.0) - || (s < 0.0 || s > 1.0) - || (l < 0.0 || l > 1.0) - || (a < 0.0 || a > 1.0)) { + if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0)) + || (s < qreal(0.0) || s > qreal(1.0)) + || (l < qreal(0.0) || l > qreal(1.0)) + || (a < qreal(0.0) || a > qreal(1.0))) { qWarning("QColor::setHsvF: HSV parameters out of range"); return; } cspec = Hsl; ct.ahsl.alpha = qRound(a * USHRT_MAX); - ct.ahsl.hue = h == -1.0 ? USHRT_MAX : qRound(h * 36000); + ct.ahsl.hue = h == qreal(-1.0) ? USHRT_MAX : qRound(h * 36000); ct.ahsl.saturation = qRound(s * USHRT_MAX); ct.ahsl.lightness = qRound(l * USHRT_MAX); ct.ahsl.pad = 0; @@ -909,10 +909,10 @@ void QColor::getRgb(int *r, int *g, int *b, int *a) const */ void QColor::setRgbF(qreal r, qreal g, qreal b, qreal a) { - if (r < 0.0 || r > 1.0 - || g < 0.0 || g > 1.0 - || b < 0.0 || b > 1.0 - || a < 0.0 || a > 1.0) { + if (r < qreal(0.0) || r > qreal(1.0) + || g < qreal(0.0) || g > qreal(1.0) + || b < qreal(0.0) || b > qreal(1.0) + || a < qreal(0.0) || a > qreal(1.0)) { qWarning("QColor::setRgbF: RGB parameters out of range"); invalidate(); return; @@ -1322,7 +1322,7 @@ qreal QColor::hsvHueF() const { if (cspec != Invalid && cspec != Hsv) return toHsv().hueF(); - return ct.ahsv.hue == USHRT_MAX ? -1.0 : ct.ahsv.hue / 36000.0; + return ct.ahsv.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsv.hue / qreal(36000.0); } /*! @@ -1418,7 +1418,7 @@ qreal QColor::hslHueF() const { if (cspec != Invalid && cspec != Hsl) return toHsl().hslHueF(); - return ct.ahsl.hue == USHRT_MAX ? -1.0 : ct.ahsl.hue / 36000.0; + return ct.ahsl.hue == USHRT_MAX ? qreal(-1.0) : ct.ahsl.hue / qreal(36000.0); } /*! @@ -1584,10 +1584,10 @@ QColor QColor::toRgb() const const qreal v = ct.ahsv.value / qreal(USHRT_MAX); const int i = int(h); const qreal f = h - i; - const qreal p = v * (1.0 - s); + const qreal p = v * (qreal(1.0) - s); if (i & 1) { - const qreal q = v * (1.0 - (s * f)); + const qreal q = v * (qreal(1.0) - (s * f)); switch (i) { case 1: @@ -1607,7 +1607,7 @@ QColor QColor::toRgb() const break; } } else { - const qreal t = v * (1.0 - (s * (1.0 - f))); + const qreal t = v * (qreal(1.0) - (s * (qreal(1.0) - f))); switch (i) { case 0: @@ -1683,9 +1683,9 @@ QColor QColor::toRgb() const const qreal y = ct.acmyk.yellow / qreal(USHRT_MAX); const qreal k = ct.acmyk.black / qreal(USHRT_MAX); - color.ct.argb.red = qRound((1.0 - (c * (1.0 - k) + k)) * USHRT_MAX); - color.ct.argb.green = qRound((1.0 - (m * (1.0 - k) + k)) * USHRT_MAX); - color.ct.argb.blue = qRound((1.0 - (y * (1.0 - k) + k)) * USHRT_MAX); + color.ct.argb.red = qRound((qreal(1.0) - (c * (qreal(1.0) - k) + k)) * USHRT_MAX); + color.ct.argb.green = qRound((qreal(1.0) - (m * (qreal(1.0) - k) + k)) * USHRT_MAX); + color.ct.argb.blue = qRound((qreal(1.0) - (y * (qreal(1.0) - k) + k)) * USHRT_MAX); break; } default: @@ -1737,15 +1737,15 @@ QColor QColor::toHsv() const if (qFuzzyCompare(r, max)) { hue = ((g - b) /delta); } else if (qFuzzyCompare(g, max)) { - hue = (2.0 + (b - r) / delta); + hue = (qreal(2.0) + (b - r) / delta); } else if (qFuzzyCompare(b, max)) { - hue = (4.0 + (r - g) / delta); + hue = (qreal(4.0) + (r - g) / delta); } else { Q_ASSERT_X(false, "QColor::toHsv", "internal error"); } - hue *= 60.0; - if (hue < 0.0) - hue += 360.0; + hue *= qreal(60.0); + if (hue < qreal(0.0)) + hue += qreal(360.0); color.ct.ahsv.hue = qRound(hue * 100); } @@ -1793,15 +1793,15 @@ QColor QColor::toHsl() const if (qFuzzyCompare(r, max)) { hue = ((g - b) /delta); } else if (qFuzzyCompare(g, max)) { - hue = (2.0 + (b - r) / delta); + hue = (qreal(2.0) + (b - r) / delta); } else if (qFuzzyCompare(b, max)) { - hue = (4.0 + (r - g) / delta); + hue = (qreal(4.0) + (r - g) / delta); } else { Q_ASSERT_X(false, "QColor::toHsv", "internal error"); } - hue *= 60.0; - if (hue < 0.0) - hue += 360.0; + hue *= qreal(60.0); + if (hue < qreal(0.0)) + hue += qreal(360.0); color.ct.ahsl.hue = qRound(hue * 100); } @@ -1829,17 +1829,17 @@ QColor QColor::toCmyk() const const qreal r = ct.argb.red / qreal(USHRT_MAX); const qreal g = ct.argb.green / qreal(USHRT_MAX); const qreal b = ct.argb.blue / qreal(USHRT_MAX); - qreal c = 1.0 - r; - qreal m = 1.0 - g; - qreal y = 1.0 - b; + qreal c = qreal(1.0) - r; + qreal m = qreal(1.0) - g; + qreal y = qreal(1.0) - b; // cmy -> cmyk const qreal k = qMin(c, qMin(m, y)); if (!qFuzzyIsNull(k - 1)) { - c = (c - k) / (1.0 - k); - m = (m - k) / (1.0 - k); - y = (y - k) / (1.0 - k); + c = (c - k) / (qreal(1.0) - k); + m = (m - k) / (qreal(1.0) - k); + y = (y - k) / (qreal(1.0) - k); } color.ct.acmyk.cyan = qRound(c * USHRT_MAX); @@ -1942,10 +1942,10 @@ QColor QColor::fromRgb(int r, int g, int b, int a) */ QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a) { - if (r < 0.0 || r > 1.0 - || g < 0.0 || g > 1.0 - || b < 0.0 || b > 1.0 - || a < 0.0 || a > 1.0) { + if (r < qreal(0.0) || r > qreal(1.0) + || g < qreal(0.0) || g > qreal(1.0) + || b < qreal(0.0) || b > qreal(1.0) + || a < qreal(0.0) || a > qreal(1.0)) { qWarning("QColor::fromRgbF: RGB parameters out of range"); return QColor(); } @@ -2005,10 +2005,10 @@ QColor QColor::fromHsv(int h, int s, int v, int a) */ QColor QColor::fromHsvF(qreal h, qreal s, qreal v, qreal a) { - if (((h < 0.0 || h > 1.0) && h != -1.0) - || (s < 0.0 || s > 1.0) - || (v < 0.0 || v > 1.0) - || (a < 0.0 || a > 1.0)) { + if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0)) + || (s < qreal(0.0) || s > qreal(1.0)) + || (v < qreal(0.0) || v > qreal(1.0)) + || (a < qreal(0.0) || a > qreal(1.0))) { qWarning("QColor::fromHsvF: HSV parameters out of range"); return QColor(); } @@ -2016,7 +2016,7 @@ QColor QColor::fromHsvF(qreal h, qreal s, qreal v, qreal a) QColor color; color.cspec = Hsv; color.ct.ahsv.alpha = qRound(a * USHRT_MAX); - color.ct.ahsv.hue = h == -1.0 ? USHRT_MAX : qRound(h * 36000); + color.ct.ahsv.hue = h == qreal(-1.0) ? USHRT_MAX : qRound(h * 36000); color.ct.ahsv.saturation = qRound(s * USHRT_MAX); color.ct.ahsv.value = qRound(v * USHRT_MAX); color.ct.ahsv.pad = 0; @@ -2069,10 +2069,10 @@ QColor QColor::fromHsl(int h, int s, int l, int a) */ QColor QColor::fromHslF(qreal h, qreal s, qreal l, qreal a) { - if (((h < 0.0 || h > 1.0) && h != -1.0) - || (s < 0.0 || s > 1.0) - || (l < 0.0 || l > 1.0) - || (a < 0.0 || a > 1.0)) { + if (((h < qreal(0.0) || h > qreal(1.0)) && h != qreal(-1.0)) + || (s < qreal(0.0) || s > qreal(1.0)) + || (l < qreal(0.0) || l > qreal(1.0)) + || (a < qreal(0.0) || a > qreal(1.0))) { qWarning("QColor::fromHsvF: HSV parameters out of range"); return QColor(); } @@ -2080,7 +2080,7 @@ QColor QColor::fromHslF(qreal h, qreal s, qreal l, qreal a) QColor color; color.cspec = Hsl; color.ct.ahsl.alpha = qRound(a * USHRT_MAX); - color.ct.ahsl.hue = (h == -1.0) ? USHRT_MAX : qRound(h * 36000); + color.ct.ahsl.hue = (h == qreal(-1.0)) ? USHRT_MAX : qRound(h * 36000); if (color.ct.ahsl.hue == 36000) color.ct.ahsl.hue = 0; color.ct.ahsl.saturation = qRound(s * USHRT_MAX); @@ -2189,11 +2189,11 @@ void QColor::setCmyk(int c, int m, int y, int k, int a) */ void QColor::setCmykF(qreal c, qreal m, qreal y, qreal k, qreal a) { - if (c < 0.0 || c > 1.0 - || m < 0.0 || m > 1.0 - || y < 0.0 || y > 1.0 - || k < 0.0 || k > 1.0 - || a < 0.0 || a > 1.0) { + if (c < qreal(0.0) || c > qreal(1.0) + || m < qreal(0.0) || m > qreal(1.0) + || y < qreal(0.0) || y > qreal(1.0) + || k < qreal(0.0) || k > qreal(1.0) + || a < qreal(0.0) || a > qreal(1.0)) { qWarning("QColor::setCmykF: CMYK parameters out of range"); return; } @@ -2251,11 +2251,11 @@ QColor QColor::fromCmyk(int c, int m, int y, int k, int a) */ QColor QColor::fromCmykF(qreal c, qreal m, qreal y, qreal k, qreal a) { - if (c < 0.0 || c > 1.0 - || m < 0.0 || m > 1.0 - || y < 0.0 || y > 1.0 - || k < 0.0 || k > 1.0 - || a < 0.0 || a > 1.0) { + if (c < qreal(0.0) || c > qreal(1.0) + || m < qreal(0.0) || m > qreal(1.0) + || y < qreal(0.0) || y > qreal(1.0) + || k < qreal(0.0) || k > qreal(1.0) + || a < qreal(0.0) || a > qreal(1.0)) { qWarning("QColor::fromCmykF: CMYK parameters out of range"); return QColor(); } diff --git a/src/gui/painting/qcolormap_qpa.cpp b/src/gui/painting/qcolormap_qpa.cpp index 1f4fea8..f66607b 100644 --- a/src/gui/painting/qcolormap_qpa.cpp +++ b/src/gui/painting/qcolormap_qpa.cpp @@ -70,7 +70,7 @@ void QColormap::initialize() QPlatformIntegration *pi = QApplicationPrivate::platformIntegration(); QList<QPlatformScreen*> screens = pi->screens(); - screenMap->depth = screens[0]->depth(); + screenMap->depth = screens.at(0)->depth(); if (screenMap->depth < 8) { screenMap->mode = QColormap::Indexed; screenMap->numcolors = 256; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 5904296..360292c 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -75,43 +75,9 @@ enum { fixed_scale = 1 << 16, half_point = 1 << 15 }; -static const int buffer_size = 2048; - -struct LinearGradientValues -{ - qreal dx; - qreal dy; - qreal l; - qreal off; -}; - -struct RadialGradientValues -{ - qreal dx; - qreal dy; - qreal a; -}; - -struct Operator; -typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length); -typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length); -typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length); - -struct Operator -{ - QPainter::CompositionMode mode; - DestFetchProc dest_fetch; - DestStoreProc dest_store; - SourceFetchProc src_fetch; - CompositionFunctionSolid funcSolid; - CompositionFunction func; - union { - LinearGradientValues linear; - RadialGradientValues radial; -// TextureValues texture; - }; -}; +// must be multiple of 4 for easier SIMD implementations +static const int buffer_size = 2048; /* Destination fetch. This is simple as we don't have to do bounds checks or @@ -570,8 +536,8 @@ const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const int image_width = data->texture.width; int image_height = data->texture.height; - const qreal cx = x + 0.5; - const qreal cy = y + 0.5; + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); const uint *end = buffer + length; uint *b = buffer; @@ -792,8 +758,8 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator * int image_x2 = data->texture.x2 - 1; int image_y2 = data->texture.y2 - 1; - const qreal cx = x + 0.5; - const qreal cy = y + 0.5; + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); uint *end = buffer + length; uint *b = buffer; @@ -1188,8 +1154,8 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator * while (b < end) { const qreal iw = fw == 0 ? 1 : 1 / fw; - const qreal px = fx * iw - 0.5; - const qreal py = fy * iw - 0.5; + const qreal px = fx * iw - qreal(0.5); + const qreal py = fy * iw - qreal(0.5); int x1 = int(px) - (px < 0); int x2; @@ -1346,64 +1312,13 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { }, }; - -static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos) -{ - int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + 0.5); - - // calculate the actual offset. - if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { - if (data->spread == QGradient::RepeatSpread) { - ipos = ipos % GRADIENT_STOPTABLE_SIZE; - ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; - - } else if (data->spread == QGradient::ReflectSpread) { - const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1; - ipos = ipos % limit; - ipos = ipos < 0 ? limit + ipos : ipos; - ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos; - - } else { - if (ipos < 0) ipos = 0; - else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1; - } - } - - Q_ASSERT(ipos >= 0); - Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); - - return data->colorTable[ipos]; -} - #define FIXPT_BITS 8 #define FIXPT_SIZE (1<<FIXPT_BITS) static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos) { int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS; - - // calculate the actual offset. - if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { - if (data->spread == QGradient::RepeatSpread) { - ipos = ipos % GRADIENT_STOPTABLE_SIZE; - ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; - - } else if (data->spread == QGradient::ReflectSpread) { - const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1; - ipos = ipos % limit; - ipos = ipos < 0 ? limit + ipos : ipos; - ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos; - - } else { - if (ipos < 0) ipos = 0; - else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1; - } - } - - Q_ASSERT(ipos >= 0); - Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); - - return data->colorTable[ipos]; + return data->colorTable[qt_gradient_clamp(data, ipos)]; } static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data) @@ -1419,8 +1334,8 @@ static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const Q } } -static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) { const uint *b = buffer; qreal t, inc; @@ -1430,8 +1345,8 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator if (op->linear.l == 0) { t = inc = 0; } else { - rx = data->m21 * (y + 0.5) + data->m11 * (x + 0.5) + data->dx; - ry = data->m22 * (y + 0.5) + data->m12 * (x + 0.5) + data->dy; + rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx; + ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy; t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off; inc = op->linear.dx * data->m11 + op->linear.dy * data->m12; affine = !data->m13 && !data->m23; @@ -1444,7 +1359,7 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator const uint *end = buffer + length; if (affine) { - if (inc > -1e-5 && inc < 1e-5) { + if (inc > qreal(-1e-5) && inc < qreal(1e-5)) { QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE))); } else { if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) && @@ -1467,7 +1382,7 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator } } } else { // fall back to float math here as well - qreal rw = data->m23 * (y + 0.5) + data->m13 * (x + 0.5) + data->m33; + qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33; while (buffer < end) { qreal x = rx/rw; qreal y = ry/rw; @@ -1487,116 +1402,71 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator return b; } -static inline qreal determinant(qreal a, qreal b, qreal c) -{ - return (b * b) - (4 * a * c); -} - -// function to evaluate real roots -static inline qreal realRoots(qreal a, qreal b, qreal detSqrt) -{ - return (-b + detSqrt)/(2 * a); -} - -static inline qreal qSafeSqrt(qreal x) -{ - return x > 0 ? qSqrt(x) : 0; -} - static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data) { v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x; v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y; - v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy; -} - -static const uint * QT_FASTCALL fetchRadialGradient(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) -{ - const uint *b = buffer; - qreal rx = data->m21 * (y + 0.5) - + data->dx + data->m11 * (x + 0.5); - qreal ry = data->m22 * (y + 0.5) - + data->dy + data->m12 * (x + 0.5); - bool affine = !data->m13 && !data->m23; - //qreal r = data->gradient.radial.radius; - - const uint *end = buffer + length; - if (affine) { - rx -= data->gradient.radial.focal.x; - ry -= data->gradient.radial.focal.y; - - qreal inv_a = 1 / qreal(2 * op->radial.a); - - const qreal delta_rx = data->m11; - const qreal delta_ry = data->m12; - qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy); - qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy); - const qreal b_delta_b = 2 * b * delta_b; - const qreal delta_b_delta_b = 2 * delta_b * delta_b; + v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius; + v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius; - const qreal bb = b * b; - const qreal delta_bb = delta_b * delta_b; + v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy; + v->inv2a = 1 / (2 * v->a); - b *= inv_a; - delta_b *= inv_a; - - const qreal rxrxryry = rx * rx + ry * ry; - const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry; - const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry); - const qreal delta_rx_plus_ry = 2 * delta_rxrxryry; - - inv_a *= inv_a; - - qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a; - qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a; - const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a; + v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0; +} - while (buffer < end) { - *buffer = qt_gradient_pixel(&data->gradient, qSafeSqrt(det) - b); +class RadialFetchPlain +{ +public: + static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, + qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) + { + if (op->radial.extended) { + while (buffer < end) { + quint32 result = 0; + if (det >= 0) { + qreal w = qSqrt(det) - b; + if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0) + result = qt_gradient_pixel(&data->gradient, w); + } - det += delta_det; - delta_det += delta_delta_det; - b += delta_b; + *buffer = result; - ++buffer; - } - } else { - qreal rw = data->m23 * (y + 0.5) - + data->m33 + data->m13 * (x + 0.5); - if (!rw) - rw = 1; - while (buffer < end) { - qreal gx = rx/rw - data->gradient.radial.focal.x; - qreal gy = ry/rw - data->gradient.radial.focal.y; - qreal b = 2*(gx*op->radial.dx + gy*op->radial.dy); - qreal det = determinant(op->radial.a, b , -(gx*gx + gy*gy)); - qreal s = realRoots(op->radial.a, b, qSafeSqrt(det)); + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; - *buffer = qt_gradient_pixel(&data->gradient, s); + ++buffer; + } + } else { + while (buffer < end) { + *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b); - rx += data->m11; - ry += data->m12; - rw += data->m13; - if (!rw) { - rw += data->m13; + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; } - ++buffer; } } +}; - return b; +const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length); } -static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operator *, const QSpanData *data, - int y, int x, int length) +static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain; + +static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) { const uint *b = buffer; - qreal rx = data->m21 * (y + 0.5) - + data->dx + data->m11 * (x + 0.5); - qreal ry = data->m22 * (y + 0.5) - + data->dy + data->m12 * (x + 0.5); + qreal rx = data->m21 * (y + qreal(0.5)) + + data->dx + data->m11 * (x + qreal(0.5)); + qreal ry = data->m22 * (y + qreal(0.5)) + + data->dy + data->m12 * (x + qreal(0.5)); bool affine = !data->m13 && !data->m23; const uint *end = buffer + length; @@ -1613,8 +1483,8 @@ static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operato ++buffer; } } else { - qreal rw = data->m23 * (y + 0.5) - + data->m33 + data->m13 * (x + 0.5); + qreal rw = data->m23 * (y + qreal(0.5)) + + data->m33 + data->m13 * (x + qreal(0.5)); if (!rw) rw = 1; while (buffer < end) { @@ -2819,7 +2689,7 @@ static inline int soft_light_op(int dst, int src, int da, int sa) # ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2 return (dst * sa * 255 + da * (src2 - sa) * (qIntSqrtInt(dst_np * 255) - dst_np) + temp) / 65025; # else - return (dst * sa * 255 + da * (src2 - sa) * (int(sqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; + return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; # endif } } @@ -3347,16 +3217,16 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in case QSpanData::LinearGradient: solidSource = !data->gradient.alphaColor; getLinearGradientValues(&op.linear, data); - op.src_fetch = fetchLinearGradient; + op.src_fetch = qt_fetch_linear_gradient; break; case QSpanData::RadialGradient: solidSource = !data->gradient.alphaColor; getRadialGradientValues(&op.radial, data); - op.src_fetch = fetchRadialGradient; + op.src_fetch = qt_fetch_radial_gradient; break; case QSpanData::ConicalGradient: solidSource = !data->gradient.alphaColor; - op.src_fetch = fetchConicalGradient; + op.src_fetch = qt_fetch_conical_gradient; break; case QSpanData::Texture: op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format]; @@ -5928,8 +5798,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s uint *target = ((uint *)t) + spans->x; uint *image_bits = (uint *)data->texture.imageData; - const qreal cx = spans->x + 0.5; - const qreal cy = spans->y + 0.5; + const qreal cx = spans->x + qreal(0.5); + const qreal cy = spans->y + qreal(0.5); int x = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale); @@ -5976,8 +5846,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s uint *target = ((uint *)t) + spans->x; uint *image_bits = (uint *)data->texture.imageData; - const qreal cx = spans->x + 0.5; - const qreal cy = spans->y + 0.5; + const qreal cx = spans->x + qreal(0.5); + const qreal cy = spans->y + qreal(0.5); qreal x = data->m21 * cy + data->m11 * cx + data->dx; qreal y = data->m22 * cy + data->m12 * cx + data->dy; @@ -6328,8 +6198,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QS uint *target = ((uint *)t) + spans->x; uint *image_bits = (uint *)data->texture.imageData; - const qreal cx = spans->x + 0.5; - const qreal cy = spans->y + 0.5; + const qreal cx = spans->x + qreal(0.5); + const qreal cy = spans->y + qreal(0.5); int x = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale); @@ -6380,8 +6250,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QS uint *target = ((uint *)t) + spans->x; uint *image_bits = (uint *)data->texture.imageData; - const qreal cx = spans->x + 0.5; - const qreal cy = spans->y + 0.5; + const qreal cx = spans->x + qreal(0.5); + const qreal cy = spans->y + qreal(0.5); qreal x = data->m21 * cy + data->m11 * cx + data->dx; qreal y = data->m22 * cy + data->m12 * cx + data->dy; @@ -7067,7 +6937,7 @@ static void qt_gradient_quint32(int count, const QSpan *spans, void *userData) */ const int gss = GRADIENT_STOPTABLE_SIZE - 1; int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE); - int off = int((((linear.dy * (data->m22 * 0.5 + data->dy) + linear.off) * gss) * FIXPT_SIZE)); + int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE)); while (count--) { int y = spans->y; @@ -7115,7 +6985,7 @@ static void qt_gradient_quint16(int count, const QSpan *spans, void *userData) */ const int gss = GRADIENT_STOPTABLE_SIZE - 1; int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE); - int off = int((((linear.dy * (data->m22 * 0.5 + data->dy) + linear.off) * gss) * FIXPT_SIZE)); + int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE)); uint oldColor = data->solid.color; while (count--) { @@ -7194,18 +7064,12 @@ void qt_build_pow_tables() { #ifdef Q_WS_MAC // decided by testing a few things on an iMac, should probably get this from the // system... - smoothing = 2.0; + smoothing = qreal(2.0); #endif #ifdef Q_WS_WIN - int winSmooth; - if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) - smoothing = winSmooth / 1000.0; - - // Safeguard ourselves against corrupt registry values... - if (smoothing > 5 || smoothing < 1) - smoothing = 1.4; - + extern qreal qt_fontsmoothing_gamma; // qapplication_win.cpp + smoothing = qt_fontsmoothing_gamma; #endif #ifdef Q_WS_X11 @@ -7226,7 +7090,7 @@ void qt_build_pow_tables() { for (int i=0; i<256; ++i) qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047)); for (int i=0; i<2048; ++i) - qt_pow_invgamma[i] = uchar(qRound(qPow(i / 2047.0, 1 / gray_gamma) * 255)); + qt_pow_invgamma[i] = uchar(qRound(qPow(i / qreal(2047.0), 1 / gray_gamma) * 255)); #endif } @@ -7888,6 +7752,11 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + + extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length); + + qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2; } #ifdef QT_HAVE_SSSE3 @@ -7983,6 +7852,11 @@ void qInitDrawhelperAsm() qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon; qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon; qt_memfill32 = qt_memfill32_neon; + + extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length); + + qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon; } #endif diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 00b103d..e673dd9 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -327,10 +327,8 @@ void qt_blend_argb32_on_rgb16_neon(uchar *destPixels, int dbpl, blend_8_pixels_argb32_on_rgb16_neon(dstBuffer, srcBuffer, const_alpha); - for (int j = 0; j < tail; ++j) { + for (int j = 0; j < tail; ++j) dst[i + j] = dstBuffer[j]; - src[i + j] = srcBuffer[j]; - } } dst = (quint16 *)(((uchar *) dst) + dbpl); @@ -957,6 +955,46 @@ void qt_memrotate270_16_neon(const uchar *srcPixels, int w, int h, } } +class QSimdNeon +{ +public: + typedef int32x4_t Int32x4; + typedef float32x4_t Float32x4; + + union Vect_buffer_i { Int32x4 v; int i[4]; }; + union Vect_buffer_f { Float32x4 v; float f[4]; }; + + static inline Float32x4 v_dup(float x) { return vdupq_n_f32(x); } + static inline Int32x4 v_dup(int x) { return vdupq_n_s32(x); } + static inline Int32x4 v_dup(uint x) { return vdupq_n_s32(x); } + + static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return vaddq_f32(a, b); } + static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return vaddq_s32(a, b); } + + static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return vmaxq_f32(a, b); } + static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return vminq_f32(a, b); } + static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return vminq_s32(a, b); } + + static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return vandq_s32(a, b); } + + static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return vsubq_f32(a, b); } + static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return vsubq_s32(a, b); } + + static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return vmulq_f32(a, b); } + + static inline Float32x4 v_sqrt(Float32x4 x) { Float32x4 y = vrsqrteq_f32(x); y = vmulq_f32(y, vrsqrtsq_f32(x, vmulq_f32(y, y))); return vmulq_f32(x, y); } + + static inline Int32x4 v_toInt(Float32x4 x) { return vcvtq_s32_f32(x); } + + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return vcge_f32(a, b); } +}; + +const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdNeon> >(buffer, op, data, y, x, length); +} + QT_END_NAMESPACE #endif // QT_HAVE_NEON diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index d4e731b..fa6ad0b 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -63,6 +63,7 @@ #endif #include "private/qrasterdefs_p.h" #include <private/qsimd_p.h> +#include <private/qmath_p.h> #ifdef Q_WS_QWS #include "QtGui/qscreen_qws.h" @@ -178,6 +179,44 @@ void qBlendTextureCallback(int count, const QSpan *spans, void *userData); typedef void (QT_FASTCALL *CompositionFunction)(uint *dest, const uint *src, int length, uint const_alpha); typedef void (QT_FASTCALL *CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha); +struct LinearGradientValues +{ + qreal dx; + qreal dy; + qreal l; + qreal off; +}; + +struct RadialGradientValues +{ + qreal dx; + qreal dy; + qreal dr; + qreal sqrfr; + qreal a; + qreal inv2a; + bool extended; +}; + +struct Operator; +typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length); +typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length); +typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length); + +struct Operator +{ + QPainter::CompositionMode mode; + DestFetchProc dest_fetch; + DestStoreProc dest_store; + SourceFetchProc src_fetch; + CompositionFunctionSolid funcSolid; + CompositionFunction func; + union { + LinearGradientValues linear; + RadialGradientValues radial; + }; +}; + void qInitDrawhelperAsm(); class QRasterPaintEngine; @@ -204,12 +243,13 @@ struct QRadialGradientData struct { qreal x; qreal y; + qreal radius; } center; struct { qreal x; qreal y; + qreal radius; } focal; - qreal radius; }; struct QConicalGradientData @@ -233,8 +273,10 @@ struct QGradientData #ifdef Q_WS_QWS #define GRADIENT_STOPTABLE_SIZE 256 +#define GRADIENT_STOPTABLE_SIZE_SHIFT 8 #else #define GRADIENT_STOPTABLE_SIZE 1024 +#define GRADIENT_STOPTABLE_SIZE_SHIFT 10 #endif uint* colorTable; //[GRADIENT_STOPTABLE_SIZE]; @@ -308,6 +350,218 @@ struct QSpanData void adjustSpanMethods(); }; +static inline uint qt_gradient_clamp(const QGradientData *data, int ipos) +{ + if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { + if (data->spread == QGradient::RepeatSpread) { + ipos = ipos % GRADIENT_STOPTABLE_SIZE; + ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; + } else if (data->spread == QGradient::ReflectSpread) { + const int limit = GRADIENT_STOPTABLE_SIZE * 2; + ipos = ipos % limit; + ipos = ipos < 0 ? limit + ipos : ipos; + ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - 1 - ipos : ipos; + } else { + if (ipos < 0) + ipos = 0; + else if (ipos >= GRADIENT_STOPTABLE_SIZE) + ipos = GRADIENT_STOPTABLE_SIZE-1; + } + } + + Q_ASSERT(ipos >= 0); + Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); + + return ipos; +} + +static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos) +{ + int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5)); + return data->colorTable[qt_gradient_clamp(data, ipos)]; +} + +static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c) +{ + return (b * b) - (4 * a * c); +} + +template <class RadialFetchFunc> +const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + // avoid division by zero + if (qFuzzyIsNull(op->radial.a)) { + extern void (*qt_memfill32)(quint32 *dest, quint32 value, int count); + qt_memfill32(buffer, 0, length); + return buffer; + } + + const uint *b = buffer; + qreal rx = data->m21 * (y + qreal(0.5)) + + data->dx + data->m11 * (x + qreal(0.5)); + qreal ry = data->m22 * (y + qreal(0.5)) + + data->dy + data->m12 * (x + qreal(0.5)); + bool affine = !data->m13 && !data->m23; + + uint *end = buffer + length; + if (affine) { + rx -= data->gradient.radial.focal.x; + ry -= data->gradient.radial.focal.y; + + qreal inv_a = 1 / qreal(2 * op->radial.a); + + const qreal delta_rx = data->m11; + const qreal delta_ry = data->m12; + + qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + rx * op->radial.dx + ry * op->radial.dy); + qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy); + const qreal b_delta_b = 2 * b * delta_b; + const qreal delta_b_delta_b = 2 * delta_b * delta_b; + + const qreal bb = b * b; + const qreal delta_bb = delta_b * delta_b; + + b *= inv_a; + delta_b *= inv_a; + + const qreal rxrxryry = rx * rx + ry * ry; + const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry; + const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry); + const qreal delta_rx_plus_ry = 2 * delta_rxrxryry; + + inv_a *= inv_a; + + qreal det = (bb - 4 * op->radial.a * (op->radial.sqrfr - rxrxryry)) * inv_a; + qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a; + const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a; + + RadialFetchFunc::fetch(buffer, end, op, data, det, delta_det, delta_delta_det, b, delta_b); + } else { + qreal rw = data->m23 * (y + qreal(0.5)) + + data->m33 + data->m13 * (x + qreal(0.5)); + + while (buffer < end) { + if (rw == 0) { + *buffer = 0; + } else { + qreal invRw = 1 / rw; + qreal gx = rx * invRw - data->gradient.radial.focal.x; + qreal gy = ry * invRw - data->gradient.radial.focal.y; + qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + gx*op->radial.dx + gy*op->radial.dy); + qreal det = qRadialDeterminant(op->radial.a, b, op->radial.sqrfr - (gx*gx + gy*gy)); + + quint32 result = 0; + if (det >= 0) { + qreal detSqrt = qSqrt(det); + + qreal s0 = (-b - detSqrt) * op->radial.inv2a; + qreal s1 = (-b + detSqrt) * op->radial.inv2a; + + qreal s = qMax(s0, s1); + + if (data->gradient.radial.focal.radius + op->radial.dr * s >= 0) + result = qt_gradient_pixel(&data->gradient, s); + } + + *buffer = result; + } + + rx += data->m11; + ry += data->m12; + rw += data->m13; + + ++buffer; + } + } + + return b; +} + +template <class Simd> +class QRadialFetchSimd +{ +public: + static void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, + qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) + { + typename Simd::Vect_buffer_f det_vec; + typename Simd::Vect_buffer_f delta_det4_vec; + typename Simd::Vect_buffer_f b_vec; + + for (int i = 0; i < 4; ++i) { + det_vec.f[i] = det; + delta_det4_vec.f[i] = 4 * delta_det; + b_vec.f[i] = b; + + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; + } + + const typename Simd::Float32x4 v_delta_delta_det16 = Simd::v_dup(16 * delta_delta_det); + const typename Simd::Float32x4 v_delta_delta_det6 = Simd::v_dup(6 * delta_delta_det); + const typename Simd::Float32x4 v_delta_b4 = Simd::v_dup(4 * delta_b); + + const typename Simd::Float32x4 v_r0 = Simd::v_dup(data->gradient.radial.focal.radius); + const typename Simd::Float32x4 v_dr = Simd::v_dup(op->radial.dr); + + const typename Simd::Float32x4 v_min = Simd::v_dup(0.0f); + const typename Simd::Float32x4 v_max = Simd::v_dup(float(GRADIENT_STOPTABLE_SIZE-1)); + const typename Simd::Float32x4 v_half = Simd::v_dup(0.5f); + + const typename Simd::Int32x4 v_repeat_mask = Simd::v_dup(~(uint(0xffffff) << GRADIENT_STOPTABLE_SIZE_SHIFT)); + const typename Simd::Int32x4 v_reflect_mask = Simd::v_dup(~(uint(0xffffff) << (GRADIENT_STOPTABLE_SIZE_SHIFT+1))); + + const typename Simd::Int32x4 v_reflect_limit = Simd::v_dup(2 * GRADIENT_STOPTABLE_SIZE - 1); + + const int extended_mask = op->radial.extended ? 0x0 : ~0x0; + +#define FETCH_RADIAL_LOOP_PROLOGUE \ + while (buffer < end) { \ + typename Simd::Vect_buffer_i v_buffer_mask; \ + v_buffer_mask.v = Simd::v_greaterOrEqual(det_vec.v, v_min); \ + const typename Simd::Float32x4 v_index_local = Simd::v_sub(Simd::v_sqrt(Simd::v_max(v_min, det_vec.v)), b_vec.v); \ + const typename Simd::Float32x4 v_index = Simd::v_add(Simd::v_mul(v_index_local, v_max), v_half); \ + v_buffer_mask.v = Simd::v_and(v_buffer_mask.v, Simd::v_greaterOrEqual(Simd::v_add(v_r0, Simd::v_mul(v_dr, v_index_local)), v_min)); \ + typename Simd::Vect_buffer_i index_vec; +#define FETCH_RADIAL_LOOP_CLAMP_REPEAT \ + index_vec.v = Simd::v_and(v_repeat_mask, Simd::v_toInt(v_index)); +#define FETCH_RADIAL_LOOP_CLAMP_REFLECT \ + const typename Simd::Int32x4 v_index_i = Simd::v_and(v_reflect_mask, Simd::v_toInt(v_index)); \ + const typename Simd::Int32x4 v_index_i_inv = Simd::v_sub(v_reflect_limit, v_index_i); \ + index_vec.v = Simd::v_min_16(v_index_i, v_index_i_inv); +#define FETCH_RADIAL_LOOP_CLAMP_PAD \ + index_vec.v = Simd::v_toInt(Simd::v_min(v_max, Simd::v_max(v_min, v_index))); +#define FETCH_RADIAL_LOOP_EPILOGUE \ + det_vec.v = Simd::v_add(Simd::v_add(det_vec.v, delta_det4_vec.v), v_delta_delta_det6); \ + delta_det4_vec.v = Simd::v_add(delta_det4_vec.v, v_delta_delta_det16); \ + b_vec.v = Simd::v_add(b_vec.v, v_delta_b4); \ + for (int i = 0; i < 4; ++i) \ + *buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable[index_vec.i[i]]; \ + } + +#define FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP) \ + FETCH_RADIAL_LOOP_PROLOGUE \ + FETCH_RADIAL_LOOP_CLAMP \ + FETCH_RADIAL_LOOP_EPILOGUE + + switch (data->gradient.spread) { + case QGradient::RepeatSpread: + FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REPEAT) + break; + case QGradient::ReflectSpread: + FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REFLECT) + break; + case QGradient::PadSpread: + FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_PAD) + break; + default: + Q_ASSERT(false); + } + } +}; + #if defined(Q_CC_RVCT) # pragma push # pragma arm diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index aad6bc9..75bb619 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -112,8 +112,6 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, // First, align dest to 16 bytes: ALIGNMENT_PROLOGUE_16BYTES(dst, x, w) { - quint32 s = src[x]; - s = BYTE_MUL(s, const_alpha); dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha); } @@ -127,8 +125,6 @@ void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl, } } for (; x<w; ++x) { - quint32 s = src[x]; - s = BYTE_MUL(s, const_alpha); dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha); } dst = (quint32 *)(((uchar *) dst) + dbpl); @@ -491,6 +487,58 @@ void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y, } } +class QSimdSse2 +{ +public: + typedef __m128i Int32x4; + typedef __m128 Float32x4; + + union Vect_buffer_i { Int32x4 v; int i[4]; }; + union Vect_buffer_f { Float32x4 v; float f[4]; }; + + static inline Float32x4 v_dup(float x) { return _mm_set1_ps(x); } + static inline Float32x4 v_dup(double x) { return _mm_set1_ps(x); } + static inline Int32x4 v_dup(int x) { return _mm_set1_epi32(x); } + static inline Int32x4 v_dup(uint x) { return _mm_set1_epi32(x); } + + static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return _mm_add_ps(a, b); } + static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return _mm_add_epi32(a, b); } + + static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return _mm_max_ps(a, b); } + static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return _mm_min_ps(a, b); } + static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return _mm_min_epi16(a, b); } + + static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return _mm_and_si128(a, b); } + + static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return _mm_sub_ps(a, b); } + static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return _mm_sub_epi32(a, b); } + + static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return _mm_mul_ps(a, b); } + + static inline Float32x4 v_sqrt(Float32x4 x) { return _mm_sqrt_ps(x); } + + static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); } + + // pre-VS 2008 doesn't have cast intrinsics, whereas 2008 and later requires it +#if defined(Q_CC_MSVC) && _MSC_VER < 1500 + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) + { + union Convert { Int32x4 vi; Float32x4 vf; } convert; + convert.vf = _mm_cmpgt_ps(a, b); + return convert.vi; + } +#else + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return _mm_castps_si128(_mm_cmpgt_ps(a, b)); } +#endif +}; + +const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2> >(buffer, op, data, y, x, length); +} + + QT_END_NAMESPACE #endif // QT_HAVE_SSE2 diff --git a/src/gui/painting/qgraphicssystem_runtime.cpp b/src/gui/painting/qgraphicssystem_runtime.cpp index 46a6f81..d1dd7ef 100644 --- a/src/gui/painting/qgraphicssystem_runtime.cpp +++ b/src/gui/painting/qgraphicssystem_runtime.cpp @@ -319,14 +319,9 @@ QPoint QRuntimeWindowSurface::offset(const QWidget *widget) const return m_windowSurface->offset(widget); } -bool QRuntimeWindowSurface::hasStaticContentsSupport() const +QWindowSurface::WindowSurfaceFeatures QRuntimeWindowSurface::features() const { - return m_windowSurface->hasStaticContentsSupport(); -} - -bool QRuntimeWindowSurface::hasPartialUpdateSupport() const -{ - return m_windowSurface->hasPartialUpdateSupport(); + return m_windowSurface->features(); } QRuntimeGraphicsSystem::QRuntimeGraphicsSystem() diff --git a/src/gui/painting/qgraphicssystem_runtime_p.h b/src/gui/painting/qgraphicssystem_runtime_p.h index 998fa98..26d3777 100644 --- a/src/gui/painting/qgraphicssystem_runtime_p.h +++ b/src/gui/painting/qgraphicssystem_runtime_p.h @@ -129,8 +129,7 @@ public: virtual QPoint offset(const QWidget *widget) const; - virtual bool hasStaticContentsSupport() const; - virtual bool hasPartialUpdateSupport() const; + virtual WindowSurfaceFeatures features() const; QScopedPointer<QWindowSurface> m_windowSurface; QScopedPointer<QWindowSurface> m_pendingWindowSurface; diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index fac356c..51171c5 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -47,6 +47,7 @@ #include <private/qimage_p.h> #include <qstatictext.h> #include <private/qstatictext_p.h> +#include <private/qrawfont_p.h> #include <QDebug> @@ -54,8 +55,6 @@ QT_BEGIN_NAMESPACE -Q_GUI_EXPORT extern int qt_defaultDpiX(); -Q_GUI_EXPORT extern int qt_defaultDpiY(); extern void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect, int tabstops, int* tabarray, int tabarraylen, @@ -536,16 +535,6 @@ QString QPaintBuffer::commandDescription(int command) const QTextItemInt &ti = (*tiCopy)(); QString text(ti.text()); - QFont font(ti.font()); - font.setUnderline(false); - font.setStrikeOut(false); - font.setOverline(false); - - const QTextItemInt &si = static_cast<const QTextItemInt &>(ti); - qreal justificationWidth = 0; - if (si.justified) - justificationWidth = si.width.toReal(); - debug << "Cmd_DrawTextItem:" << pos << " " << text; break; } case QPaintBufferPrivate::Cmd_SystemStateChanged: { @@ -1756,26 +1745,38 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) painter->setClipRegion(region, Qt::ClipOperation(cmd.extra)); break; } +#if !defined(QT_NO_RAWFONT) case QPaintBufferPrivate::Cmd_DrawStaticText: { QVariantList variants(d->variants.at(cmd.offset).value<QVariantList>()); QFont font = variants.at(0).value<QFont>(); - QVector<quint32> glyphs; + QVector<quint32> glyphIndexes; QVector<QPointF> positions; for (int i=0; i<(variants.size() - 1) / 2; ++i) { - glyphs.append(variants.at(i*2 + 1).toUInt()); + glyphIndexes.append(variants.at(i*2 + 1).toUInt()); positions.append(variants.at(i*2 + 2).toPointF()); } painter->setFont(font); - qt_draw_glyphs(painter, glyphs.constData(), positions.constData(), glyphs.size()); - - break; + QRawFont rawFont; + QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont); + QFontPrivate *fontD = QFontPrivate::get(font); + rawFontD->fontEngine = fontD->engineForScript(QUnicodeTables::Common); + rawFontD->fontEngine->ref.ref(); + + QGlyphs glyphs; + glyphs.setFont(rawFont); + glyphs.setGlyphIndexes(glyphIndexes); + glyphs.setPositions(positions); + + painter->drawGlyphs(QPointF(), glyphs); + break; } +#endif case QPaintBufferPrivate::Cmd_DrawText: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); diff --git a/src/gui/painting/qpaintengine_alpha.cpp b/src/gui/painting/qpaintengine_alpha.cpp index 339a002..171850d 100644 --- a/src/gui/painting/qpaintengine_alpha.cpp +++ b/src/gui/painting/qpaintengine_alpha.cpp @@ -46,6 +46,7 @@ #include "private/qpaintengine_alpha_p.h" #include "private/qpicture_p.h" +#include "private/qfont_p.h" #include "QtGui/qpicture.h" QT_BEGIN_NAMESPACE @@ -93,9 +94,6 @@ bool QAlphaPaintEngine::begin(QPaintDevice *pdev) return true; } -Q_GUI_EXPORT extern int qt_defaultDpiX(); -Q_GUI_EXPORT extern int qt_defaultDpiY(); - bool QAlphaPaintEngine::end() { Q_D(QAlphaPaintEngine); diff --git a/src/gui/painting/qpaintengine_mac.cpp b/src/gui/painting/qpaintengine_mac.cpp index 2f35dcd..cc75b86 100644 --- a/src/gui/painting/qpaintengine_mac.cpp +++ b/src/gui/painting/qpaintengine_mac.cpp @@ -972,7 +972,7 @@ void QCoreGraphicsPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, co return; bool differentSize = (QRectF(0, 0, pm.width(), pm.height()) != sr), doRestore = false; - CGRect rect = CGRectMake(qRound(r.x()), qRound(r.y()), qRound(r.width()), qRound(r.height())); + CGRect rect = CGRectMake(r.x(), r.y(), r.width(), r.height()); QCFType<CGImageRef> image; bool isBitmap = (pm.depth() == 1); if (isBitmap) { @@ -1544,8 +1544,9 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset) QPointF center(radialGrad->center()); QPointF focal(radialGrad->focalPoint()); qreal radius = radialGrad->radius(); + qreal focalRadius = radialGrad->focalRadius(); shading = CGShadingCreateRadial(colorspace, CGPointMake(focal.x(), focal.y()), - 0.0, CGPointMake(center.x(), center.y()), radius, fill_func, false, true); + focalRadius, CGPointMake(center.x(), center.y()), radius, fill_func, false, true); } CGFunctionRelease(fill_func); diff --git a/src/gui/painting/qpaintengine_mac_p.h b/src/gui/painting/qpaintengine_mac_p.h index 5c459ee..3e71d6c 100644 --- a/src/gui/painting/qpaintengine_mac_p.h +++ b/src/gui/painting/qpaintengine_mac_p.h @@ -57,15 +57,12 @@ #include "private/qt_mac_p.h" #include "private/qpaintengine_p.h" #include "private/qpolygonclipper_p.h" +#include "private/qfont_p.h" #include "QtCore/qhash.h" typedef struct CGColorSpace *CGColorSpaceRef; QT_BEGIN_NAMESPACE -extern int qt_defaultDpi(); -extern int qt_defaultDpiX(); -extern int qt_defaultDpiY(); - class QCoreGraphicsPaintEnginePrivate; class QCoreGraphicsPaintEngine : public QPaintEngine { diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 9242fb6..2119e30 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3076,65 +3076,145 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx blend(current, spans, &s->penData); } -void QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, +bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine) { Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); - QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType; +#if !defined(QT_NO_FREETYPE) + if (fontEngine->type() == QFontEngine::Freetype) { + QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine); + QFontEngineFT::GlyphFormat neededFormat = + painter()->device()->devType() == QInternal::Widget + ? fe->defaultGlyphFormat() + : QFontEngineFT::Format_A8; + + if (d_func()->mono_surface + || fe->isBitmapFont() // alphaPenBlt can handle mono, too + ) + neededFormat = QFontEngineFT::Format_Mono; + + if (neededFormat == QFontEngineFT::Format_None) + neededFormat = QFontEngineFT::Format_A8; + + QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs(); + if (s->matrix.type() >= QTransform::TxScale) { + if (s->matrix.isAffine()) + gset = fe->loadTransformedGlyphSet(s->matrix); + else + gset = 0; + } - QImageTextureGlyphCache *cache = - static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix)); - if (!cache) { - cache = new QImageTextureGlyphCache(glyphType, s->matrix); - fontEngine->setGlyphCache(0, cache); - } + if (!gset || gset->outline_drawing + || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat)) + return false; - cache->populate(fontEngine, numGlyphs, glyphs, positions); - cache->fillInPendingGlyphs(); + FT_Face lockedFace = 0; - const QImage &image = cache->image(); - int bpl = image.bytesPerLine(); + int depth; + switch (neededFormat) { + case QFontEngineFT::Format_Mono: + depth = 1; + break; + case QFontEngineFT::Format_A8: + depth = 8; + break; + case QFontEngineFT::Format_A32: + depth = 32; + break; + default: + Q_ASSERT(false); + depth = 0; + }; - int depth = image.depth(); - int rightShift = 0; - int leftShift = 0; - if (depth == 32) - leftShift = 2; // multiply by 4 - else if (depth == 1) - rightShift = 3; // divide by 8 + for (int i = 0; i < numGlyphs; i++) { + QFixed spp = fe->subPixelPositionForX(positions[i].x); + QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp); - int margin = cache->glyphMargin(); + if (!glyph || glyph->format != neededFormat) { + if (!lockedFace) + lockedFace = fe->lockFace(); + glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat); + } - bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions(); + if (!glyph || !glyph->data) + continue; - const uchar *bits = image.bits(); - for (int i=0; i<numGlyphs; ++i) { + int pitch; + switch (neededFormat) { + case QFontEngineFT::Format_Mono: + pitch = ((glyph->width + 31) & ~31) >> 3; + break; + case QFontEngineFT::Format_A8: + pitch = (glyph->width + 3) & ~3; + break; + case QFontEngineFT::Format_A32: + pitch = glyph->width * 4; + break; + default: + Q_ASSERT(false); + pitch = 0; + }; + + alphaPenBlt(glyph->data, pitch, depth, + qFloor(positions[i].x) + glyph->x, + qFloor(positions[i].y) - glyph->y, + glyph->width, glyph->height); + } + if (lockedFace) + fe->unlockFace(); + } else +#endif + { + QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType; - QFixed subPixelPosition; - if (supportsSubPixelPositions) - subPixelPosition = cache->subPixelPositionForX(positions[i].x); - QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition); - const QTextureGlyphCache::Coord &c = cache->coords[glyph]; - if (c.isNull()) - continue; + QImageTextureGlyphCache *cache = + static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix)); + if (!cache) { + cache = new QImageTextureGlyphCache(glyphType, s->matrix); + fontEngine->setGlyphCache(0, cache); + } - int x = qFloor(positions[i].x) + c.baseLineX - margin; - int y = qFloor(positions[i].y) - c.baseLineY - margin; + cache->populate(fontEngine, numGlyphs, glyphs, positions); + cache->fillInPendingGlyphs(); -// printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n", -// c.x, c.y, -// c.w, c.h, -// c.baseLineX, c.baseLineY, -// glyphs[i], -// x, y, -// positions[i].x.toInt(), positions[i].y.toInt()); + const QImage &image = cache->image(); + int bpl = image.bytesPerLine(); - alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h); - } + int depth = image.depth(); + int rightShift = 0; + int leftShift = 0; + if (depth == 32) + leftShift = 2; // multiply by 4 + else if (depth == 1) + rightShift = 3; // divide by 8 - return; + int margin = cache->glyphMargin(); + const uchar *bits = image.bits(); + for (int i=0; i<numGlyphs; ++i) { + + QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x); + QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition); + const QTextureGlyphCache::Coord &c = cache->coords[glyph]; + if (c.isNull()) + continue; + + int x = qFloor(positions[i].x) + c.baseLineX - margin; + int y = qFloor(positions[i].y) - c.baseLineY - margin; + + // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n", + // c.x, c.y, + // c.w, c.h, + // c.baseLineX, c.baseLineY, + // glyphs[i], + // x, y, + // positions[i].x.toInt(), positions[i].y.toInt()); + + alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h); + } + } + return true; } #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) @@ -3445,91 +3525,10 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte if (glyphs.size() == 0) return; - // only use subpixel antialiasing when drawing to widgets - QFontEngineFT::GlyphFormat neededFormat = - painter()->device()->devType() == QInternal::Widget - ? fe->defaultGlyphFormat() - : QFontEngineFT::Format_A8; - - if (d_func()->mono_surface - || fe->isBitmapFont() // alphaPenBlt can handle mono, too - ) - neededFormat = QFontEngineFT::Format_Mono; - - if (neededFormat == QFontEngineFT::Format_None) - neededFormat = QFontEngineFT::Format_A8; - - QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs(); - if (s->matrix.type() >= QTransform::TxScale) { - if (s->matrix.isAffine()) - gset = fe->loadTransformedGlyphSet(s->matrix); - else - gset = 0; - - } - - if (!gset || gset->outline_drawing - || !fe->loadGlyphs(gset, glyphs.data(), glyphs.size(), neededFormat)) - { + if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine)) QPaintEngine::drawTextItem(p, ti); - return; - } - FT_Face lockedFace = 0; - - int depth; - switch (neededFormat) { - case QFontEngineFT::Format_Mono: - depth = 1; - break; - case QFontEngineFT::Format_A8: - depth = 8; - break; - case QFontEngineFT::Format_A32: - depth = 32; - break; - default: - Q_ASSERT(false); - depth = 0; - }; - - for(int i = 0; i < glyphs.size(); i++) { - QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i]); - - if (!glyph || glyph->format != neededFormat) { - if (!lockedFace) - lockedFace = fe->lockFace(); - glyph = fe->loadGlyph(gset, glyphs[i], neededFormat); - } - - if (!glyph || !glyph->data) - continue; - - int pitch; - switch (neededFormat) { - case QFontEngineFT::Format_Mono: - pitch = ((glyph->width + 31) & ~31) >> 3; - break; - case QFontEngineFT::Format_A8: - pitch = (glyph->width + 3) & ~3; - break; - case QFontEngineFT::Format_A32: - pitch = glyph->width * 4; - break; - default: - Q_ASSERT(false); - pitch = 0; - }; - - alphaPenBlt(glyph->data, pitch, depth, - qFloor(positions[i].x) + glyph->x, - qFloor(positions[i].y) - glyph->y, - glyph->width, glyph->height); - } - if (lockedFace) - fe->unlockFace(); return; - #endif #endif @@ -5034,6 +5033,84 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); + if (stopCount == 2) { + uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); + uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity); + + qreal first_stop = stops[0].first; + qreal second_stop = stops[1].first; + + if (second_stop < first_stop) { + qSwap(first_color, second_color); + qSwap(first_stop, second_stop); + } + + if (colorInterpolation) { + first_color = PREMUL(first_color); + second_color = PREMUL(second_color); + } + + int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1)); + int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1)); + + uint red_first = qRed(first_color) << 16; + uint green_first = qGreen(first_color) << 16; + uint blue_first = qBlue(first_color) << 16; + uint alpha_first = qAlpha(first_color) << 16; + + uint red_second = qRed(second_color) << 16; + uint green_second = qGreen(second_color) << 16; + uint blue_second = qBlue(second_color) << 16; + uint alpha_second = qAlpha(second_color) << 16; + + int i = 0; + for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) { + if (colorInterpolation) + colorTable[i] = first_color; + else + colorTable[i] = PREMUL(first_color); + } + + if (i < second_index) { + qreal reciprocal = qreal(1) / (second_index - first_index); + + int red_delta = qRound(int(red_second - red_first) * reciprocal); + int green_delta = qRound(int(green_second - green_first) * reciprocal); + int blue_delta = qRound(int(blue_second - blue_first) * reciprocal); + int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal); + + // rounding + red_first += 1 << 15; + green_first += 1 << 15; + blue_first += 1 << 15; + alpha_first += 1 << 15; + + for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) { + red_first += red_delta; + green_first += green_delta; + blue_first += blue_delta; + alpha_first += alpha_delta; + + const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000) + | ((green_first >> 8) & 0xff00) | (blue_first >> 16); + + if (colorInterpolation) + colorTable[i] = color; + else + colorTable[i] = PREMUL(color); + } + } + + for (; i < GRADIENT_STOPTABLE_SIZE; ++i) { + if (colorInterpolation) + colorTable[i] = second_color; + else + colorTable[i] = PREMUL(second_color); + } + + return; + } + uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); if (stopCount == 1) { current_color = PREMUL(current_color); @@ -5205,10 +5282,11 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode QPointF center = g->center(); radialData.center.x = center.x(); radialData.center.y = center.y(); + radialData.center.radius = g->centerRadius(); QPointF focal = g->focalPoint(); radialData.focal.x = focal.x(); radialData.focal.y = focal.y(); - radialData.radius = g->radius(); + radialData.focal.radius = g->focalRadius(); } break; diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 7f902a8..52f51fa 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -261,7 +261,7 @@ private: void fillRect(const QRectF &rect, QSpanData *data); void drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fill); - void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, + bool drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine); #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) diff --git a/src/gui/painting/qpaintengine_x11.cpp b/src/gui/painting/qpaintengine_x11.cpp index 8b71b83..6ba9a99 100644 --- a/src/gui/painting/qpaintengine_x11.cpp +++ b/src/gui/painting/qpaintengine_x11.cpp @@ -1611,8 +1611,6 @@ void QX11PaintEnginePrivate::fillPolygon_dev(const QPointF *polygonPoints, int p && (fill.style() != Qt::NoBrush) && ((has_fill_texture && fill.texture().hasAlpha()) || antialias || !solid_fill || has_alpha_pen != has_alpha_brush)) { - QRect br = tessellator->tessellate((QPointF *)clippedPoints, clippedCount, - mode == QPaintEngine::WindingMode); if (tessellator->size > 0) { XRenderPictureAttributes attrs; attrs.poly_edge = antialias ? PolyEdgeSmooth : PolyEdgeSharp; @@ -1771,7 +1769,6 @@ void QX11PaintEngine::drawPath(const QPainterPath &path) Q_D(QX11PaintEngine); if (path.isEmpty()) return; - QTransform old_matrix = d->matrix; if (d->has_brush) d->fillPath(path, QX11PaintEnginePrivate::BrushGC, true); @@ -2385,7 +2382,7 @@ void QX11PaintEngine::drawFreetype(const QPointF &p, const QTextItemInt &ti) set = ft->loadTransformedGlyphSet(d->matrix); if (!set || set->outline_drawing - || !ft->loadGlyphs(set, glyphs.data(), glyphs.size(), QFontEngineFT::Format_Render)) + || !ft->loadGlyphs(set, glyphs.constData(), glyphs.size(), positions.constData(), QFontEngineFT::Format_Render)) { QPaintEngine::drawTextItem(p, ti); return; diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 509fb77..7f601eb 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -1012,4 +1012,50 @@ void QPaintEngineEx::updateState(const QPaintEngineState &) // do nothing... } +Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path) +{ + const qreal *points = path.points(); + const QPainterPath::ElementType *types = path.elements(); + + QPainterPath p; + if (types) { + int id = 0; + for (int i=0; i<path.elementCount(); ++i) { + switch(types[i]) { + case QPainterPath::MoveToElement: + p.moveTo(QPointF(points[id], points[id+1])); + id+=2; + break; + case QPainterPath::LineToElement: + p.lineTo(QPointF(points[id], points[id+1])); + id+=2; + break; + case QPainterPath::CurveToElement: { + QPointF p1(points[id], points[id+1]); + QPointF p2(points[id+2], points[id+3]); + QPointF p3(points[id+4], points[id+5]); + p.cubicTo(p1, p2, p3); + id+=6; + break; + } + case QPainterPath::CurveToDataElement: + ; + break; + } + } + } else { + p.moveTo(QPointF(points[0], points[1])); + int id = 2; + for (int i=1; i<path.elementCount(); ++i) { + p.lineTo(QPointF(points[id], points[id+1])); + id+=2; + } + } + if (path.hints() & QVectorPath::WindingFill) + p.setFillRule(Qt::WindingFill); + + return p; +} + + QT_END_NAMESPACE diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 2c25e70..3fd4c5b 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -75,6 +75,7 @@ #include <private/qstatictext_p.h> #include <private/qglyphs_p.h> #include <private/qstylehelper_p.h> +#include <private/qrawfont_p.h> QT_BEGIN_NAMESPACE @@ -97,10 +98,10 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QTextItem::RenderFlags flags, qreal width, const QTextCharFormat &charFormat); // Helper function to calculate left most position, width and flags for decoration drawing -static void drawDecorationForGlyphs(QPainter *painter, const glyph_t *glyphArray, - const QFixedPoint *positions, int glyphCount, - QFontEngine *fontEngine, const QFont &font, - const QTextCharFormat &charFormat); +Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray, + const QFixedPoint *positions, int glyphCount, + QFontEngine *fontEngine, const QFont &font, + const QTextCharFormat &charFormat); static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush) { @@ -155,7 +156,8 @@ static bool qt_paintengine_supports_transformations(QPaintEngine::Type type) { return type == QPaintEngine::OpenGL2 || type == QPaintEngine::OpenVG - || type == QPaintEngine::OpenGL; + || type == QPaintEngine::OpenGL + || type == QPaintEngine::CoreGraphics; } #ifndef QT_NO_DEBUG @@ -502,8 +504,12 @@ void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperatio q->save(); state->matrix = QTransform(); - state->dirtyFlags |= QPaintEngine::DirtyTransform; - updateState(state); + if (extended) { + extended->transformChanged(); + } else { + state->dirtyFlags |= QPaintEngine::DirtyTransform; + updateState(state); + } engine->drawImage(absPathRect, image, QRectF(0, 0, absPathRect.width(), absPathRect.height()), @@ -686,11 +692,14 @@ void QPainterPrivate::updateInvMatrix() invMatrix = state->matrix.inverted(); } +Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush); + void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) { bool alpha = false; bool linearGradient = false; bool radialGradient = false; + bool extendedRadialGradient = false; bool conicalGradient = false; bool patternBrush = false; bool xform = false; @@ -722,6 +731,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) (brushStyle == Qt::LinearGradientPattern)); radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) || (brushStyle == Qt::RadialGradientPattern)); + extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush)); conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) || (brushStyle == Qt::ConicalGradientPattern)); patternBrush = (((penBrushStyle > Qt::SolidPattern @@ -805,7 +815,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill; // Radial gradient emulation - if (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)) + if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill))) s->emulationSpecifier |= QPaintEngine::RadialGradientFill; else s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill; @@ -5790,12 +5800,14 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR \sa QGlyphs::setFont(), QGlyphs::setPositions(), QGlyphs::setGlyphIndexes() */ +#if !defined(QT_NO_RAWFONT) void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) { Q_D(QPainter); - QFont oldFont = d->state->font; - d->state->font = glyphs.font(); + QRawFont font = glyphs.font(); + if (!font.isValid()) + return; QVector<quint32> glyphIndexes = glyphs.glyphIndexes(); QVector<QPointF> glyphPositions = glyphs.positions(); @@ -5806,7 +5818,7 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) bool paintEngineSupportsTransformations = d->extended != 0 ? qt_paintengine_supports_transformations(d->extended->type()) - : false; + : qt_paintengine_supports_transformations(d->engine->type()); for (int i=0; i<count; ++i) { QPointF processedPosition = position + glyphPositions.at(i); if (!paintEngineSupportsTransformations) @@ -5814,39 +5826,20 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition); } - d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count); - - d->state->font = oldFont; + d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count, font, glyphs.overline(), + glyphs.underline(), glyphs.strikeOut()); } -void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, const QPointF *positionArray, - int glyphCount) -{ - QVarLengthArray<QFixedPoint, 128> positions(glyphCount); - for (int i=0; i<glyphCount; ++i) - positions[i] = QFixedPoint::fromPointF(positionArray[i]); - - QPainterPrivate *painter_d = QPainterPrivate::get(painter); - painter_d->drawGlyphs(const_cast<quint32 *>(glyphArray), positions.data(), glyphCount); -} - -void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount) +void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount, + const QRawFont &font, bool overline, bool underline, + bool strikeOut) { Q_Q(QPainter); updateState(state); - QFontEngine *fontEngine = state->font.d->engineForScript(QUnicodeTables::Common); - - while (fontEngine->type() == QFontEngine::Multi) { - // Pick engine based on first glyph in array if we are using a multi engine. - // (all glyphs must be for same font) - int engineIdx = 0; - if (glyphCount > 0) - engineIdx = glyphArray[0] >> 24; - - fontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx); - } + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + QFontEngine *fontEngine = fontD->fontEngine; QFixed leftMost; QFixed rightMost; @@ -5881,7 +5874,6 @@ void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, in extended->drawStaticTextItem(&staticTextItem); } else { QTextItemInt textItem; - textItem.f = &state->font; textItem.fontEngine = fontEngine; QVarLengthArray<QFixed, 128> advances(glyphCount); @@ -5903,20 +5895,21 @@ void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, in } QTextItemInt::RenderFlags flags; - if (state->font.underline()) + if (underline) flags |= QTextItemInt::Underline; - if (state->font.overline()) + if (overline) flags |= QTextItemInt::Overline; - if (state->font.strikeOut()) + if (strikeOut) flags |= QTextItemInt::StrikeOut; drawTextItemDecoration(q, QPointF(leftMost.toReal(), baseLine.toReal()), fontEngine, - (state->font.underline() - ? QTextCharFormat::SingleUnderline - : QTextCharFormat::NoUnderline), + (underline + ? QTextCharFormat::SingleUnderline + : QTextCharFormat::NoUnderline), flags, width.toReal(), QTextCharFormat()); } +#endif // QT_NO_RAWFONT /*! @@ -6076,9 +6069,9 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText } d->extended->drawStaticTextItem(item); - drawDecorationForGlyphs(this, item->glyphs, item->glyphPositions, - item->numGlyphs, item->fontEngine(), staticText_d->font, - QTextCharFormat()); + qt_draw_decoration_for_glyphs(this, item->glyphs, item->glyphPositions, + item->numGlyphs, item->fontEngine(), staticText_d->font, + QTextCharFormat()); } if (currentColor != oldPen.color()) setPen(oldPen); @@ -6463,12 +6456,13 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const pen.setWidthF(fe->lineThickness().toReal()); pen.setCapStyle(Qt::FlatCap); - QLineF line(pos.x(), pos.y(), pos.x() + width, pos.y()); + QLineF line(pos.x(), pos.y(), pos.x() + qFloor(width), pos.y()); const qreal underlineOffset = fe->underlinePosition().toReal(); // deliberately ceil the offset to avoid the underline coming too close to // the text above it. - const qreal underlinePos = pos.y() + qCeil(underlineOffset); + const qreal aliasedCoordinateDelta = 0.5 - 0.015625; + const qreal underlinePos = pos.y() + qCeil(underlineOffset) - aliasedCoordinateDelta; if (underlineStyle == QTextCharFormat::SpellCheckUnderline) { underlineStyle = QTextCharFormat::UnderlineStyle(QApplication::style()->styleHint(QStyle::SH_SpellCheckUnderlineStyle)); @@ -6522,10 +6516,10 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const painter->setBrush(oldBrush); } -static void drawDecorationForGlyphs(QPainter *painter, const glyph_t *glyphArray, - const QFixedPoint *positions, int glyphCount, - QFontEngine *fontEngine, const QFont &font, - const QTextCharFormat &charFormat) +Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray, + const QFixedPoint *positions, int glyphCount, + QFontEngine *fontEngine, const QFont &font, + const QTextCharFormat &charFormat) { if (!(font.underline() || font.strikeOut() || font.overline())) return; @@ -8246,12 +8240,16 @@ start_lengthVariant: QTextLine line = textLayout.lineAt(i); qreal advance = line.horizontalAdvance(); - if (tf & Qt::AlignRight) - xoff = r.width() - advance; + xoff = 0; + if (tf & Qt::AlignRight) { + QTextEngine *eng = textLayout.engine(); + xoff = r.width() - advance - + eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal(); + } else if (tf & Qt::AlignHCenter) - xoff = (r.width() - advance)/2; + xoff = (r.width() - advance) / 2; - line.draw(painter, QPointF(r.x() + xoff + line.x(), r.y() + yoff)); + line.draw(painter, QPointF(r.x() + xoff, r.y() + yoff)); } if (restore) { diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index ae2fdf2..1a432e6 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -399,7 +399,9 @@ public: void setLayoutDirection(Qt::LayoutDirection direction); Qt::LayoutDirection layoutDirection() const; +#if !defined(QT_NO_RAWFONT) void drawGlyphs(const QPointF &position, const QGlyphs &glyphs); +#endif void drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText); inline void drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText); @@ -551,6 +553,7 @@ private: friend class QPaintEngine; friend class QPaintEngineExPrivate; friend class QOpenGLPaintEngine; + friend class QVGPaintEngine; friend class QX11PaintEngine; friend class QX11PaintEnginePrivate; friend class QWin32PaintEngine; diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 26d8fc3..205c10a 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -184,6 +184,7 @@ struct QPainterDummyState QTransform transform; }; +class QRawFont; class QPainterPrivate { Q_DECLARE_PUBLIC(QPainter) @@ -229,7 +230,12 @@ public: void draw_helper(const QPainterPath &path, DrawOperation operation = StrokeAndFillDraw); void drawStretchedGradient(const QPainterPath &path, DrawOperation operation); void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation); - void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount); + +#if !defined(QT_NO_RAWFONT) + void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount, + const QRawFont &font, bool overline = false, bool underline = false, + bool strikeOut = false); +#endif void updateMatrix(); void updateInvMatrix(); @@ -259,8 +265,6 @@ public: }; Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation); -Q_GUI_EXPORT void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, - const QPointF *positionArray, int glyphCount); QString qt_generate_brush_key(const QBrush &brush); diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 49f1a5f..9fbac13 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -1126,6 +1126,7 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString & QTextEngine *eng = layout.engine(); layout.beginLayout(); QTextLine line = layout.createLine(); + Q_UNUSED(line); layout.endLayout(); const QScriptLine &sl = eng->lines[0]; if (!sl.length || !eng->layoutData) @@ -1897,39 +1898,39 @@ static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y return false; } -static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2) +static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth = 0) { QRectF bounds = bezier.bounds(); if (y >= bounds.top() && y < bounds.bottom() && bounds.right() >= x1 && bounds.left() < x2) { const qreal lower_bound = qreal(.01); - if (bounds.width() < lower_bound && bounds.height() < lower_bound) + if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) return true; QBezier first_half, second_half; bezier.split(&first_half, &second_half); - if (qt_isect_curve_horizontal(first_half, y, x1, x2) - || qt_isect_curve_horizontal(second_half, y, x1, x2)) + if (qt_isect_curve_horizontal(first_half, y, x1, x2, depth + 1) + || qt_isect_curve_horizontal(second_half, y, x1, x2, depth + 1)) return true; } return false; } -static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2) +static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth = 0) { QRectF bounds = bezier.bounds(); if (x >= bounds.left() && x < bounds.right() && bounds.bottom() >= y1 && bounds.top() < y2) { const qreal lower_bound = qreal(.01); - if (bounds.width() < lower_bound && bounds.height() < lower_bound) + if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) return true; QBezier first_half, second_half; bezier.split(&first_half, &second_half); - if (qt_isect_curve_vertical(first_half, x, y1, y2) - || qt_isect_curve_vertical(second_half, x, y1, y2)) + if (qt_isect_curve_vertical(first_half, x, y1, y2, depth + 1) + || qt_isect_curve_vertical(second_half, x, y1, y2, depth + 1)) return true; } return false; diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index bc30038..0271a39 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -47,6 +47,7 @@ #include "private/qcups_p.h" #include "qprinterinfo.h" #include <qnumeric.h> +#include "private/qfont_p.h" #ifdef Q_OS_UNIX #include "private/qcore_unix_p.h" // overrides QT_OPEN @@ -54,8 +55,6 @@ QT_BEGIN_NAMESPACE -Q_GUI_EXPORT extern int qt_defaultDpi(); - #ifndef QT_NO_PRINTER extern QSizeF qt_paperSizeToQSizeF(QPrinter::PaperSize size); diff --git a/src/gui/painting/qprintengine_mac.mm b/src/gui/painting/qprintengine_mac.mm index ec842a9..1dce303 100644 --- a/src/gui/painting/qprintengine_mac.mm +++ b/src/gui/painting/qprintengine_mac.mm @@ -49,7 +49,6 @@ QT_BEGIN_NAMESPACE extern QSizeF qt_paperSizeToQSizeF(QPrinter::PaperSize size); -extern int qt_defaultDpi(); QMacPrintEngine::QMacPrintEngine(QPrinter::PrinterMode mode) : QPaintEngine(*(new QMacPrintEnginePrivate)) { diff --git a/src/gui/painting/qprintengine_pdf.cpp b/src/gui/painting/qprintengine_pdf.cpp index b7f5160..353869f 100644 --- a/src/gui/painting/qprintengine_pdf.cpp +++ b/src/gui/painting/qprintengine_pdf.cpp @@ -534,7 +534,10 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n QImage image = img; QImage::Format format = image.format(); - if (image.depth() == 1 && *bitmap && img.colorTable().size() == 0) { + if (image.depth() == 1 && *bitmap && img.colorTable().size() == 2 + && img.colorTable().at(0) == QColor(Qt::black).rgba() + && img.colorTable().at(1) == QColor(Qt::white).rgba()) + { if (format == QImage::Format_MonoLSB) image = image.convertToFormat(QImage::Format_Mono); format = QImage::Format_Mono; diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index fca46b4..dd723ed 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -552,6 +552,7 @@ void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine // // line to the beginning of the arc segment, (should not be needed). // emitLineTo(qt_real_to_fixed(curve_start.x()), qt_real_to_fixed(curve_start.y())); + Q_UNUSED(curve_start); for (int i=0; i<point_count; i+=3) { emitCubicTo(qt_real_to_fixed(curves[i].x()), diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index e75c0f5..e9e56a2 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -102,7 +102,7 @@ int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const QFixed QTextureGlyphCache::subPixelPositionForX(QFixed x) const { - if (m_subPixelPositionCount == 0) + if (m_subPixelPositionCount <= 1) return QFixed(); QFixed subPixelPosition; @@ -134,9 +134,13 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const if (!supportsSubPixelPositions) { m_subPixelPositionCount = 1; } else { +#if !defined(Q_WS_X11) int i = 0; while (m_subPixelPositionCount == 0 && i < numGlyphs) m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]); +#else + m_subPixelPositionCount = 4; +#endif } } @@ -164,7 +168,7 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const continue; if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition))) continue; - glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, m_transform, format); + glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, format); #ifdef CACHE_DEBUG printf("(%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n", @@ -234,6 +238,11 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const } } + if (maxTextureHeight() > 0 && m_cy + c.h > maxTextureHeight()) { + // We can't make a cache of the required size, so we bail out + return false; + } + c.x = m_cx; c.y = m_cy; @@ -287,7 +296,7 @@ void QTextureGlyphCache::fillInPendingGlyphs() QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const { #if defined(Q_WS_X11) - if (m_transform.type() > QTransform::TxTranslate) { + if (m_transform.type() > QTransform::TxTranslate && m_current_fontengine->type() == QFontEngine::Freetype) { QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_None; QImage::Format imageFormat = QImage::Format_Invalid; switch (m_type) { @@ -307,9 +316,11 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine); QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform); + QFixedPoint positions[1]; + positions[0].x = subPixelPosition; - if (gset && ft->loadGlyphs(gset, &g, 1, format)) { - QFontEngineFT::Glyph *glyph = gset->getGlyph(g); + if (gset && ft->loadGlyphs(gset, &g, 1, positions, format)) { + QFontEngineFT::Glyph *glyph = gset->getGlyph(g, subPixelPosition); const int bytesPerLine = (format == QFontEngineFT::Format_Mono ? ((glyph->width + 31) & ~31) >> 3 : (glyph->width + 3) & ~3); return QImage(glyph->data, glyph->width, glyph->height, bytesPerLine, imageFormat); @@ -356,7 +367,7 @@ void QImageTextureGlyphCache::createTextureData(int width, int height) int QImageTextureGlyphCache::glyphMargin() const { -#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) +#if (defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) || defined(Q_WS_X11) return 0; #else return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 4441b30..7d11e2f 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1085,8 +1085,11 @@ QDebug operator<<(QDebug dbg, const QTransform &m) "TxNone", "TxTranslate", "TxScale", + 0, "TxRotate", + 0, 0, 0, "TxShear", + 0, 0, 0, 0, 0, 0, 0, "TxProject" }; diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp index 3876c3d..2fda6b9 100644 --- a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp +++ b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp @@ -152,7 +152,8 @@ void QUnifiedToolbarSurface::beginPaint(const QRegion &rgn) void QUnifiedToolbarSurface::updateToolbarOffset(QWidget *widget) { QMainWindowLayout *mlayout = qobject_cast<QMainWindowLayout*> (widget->window()->layout()); - mlayout->updateUnifiedToolbarOffset(); + if (mlayout) + mlayout->updateUnifiedToolbarOffset(); } void QUnifiedToolbarSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) diff --git a/src/gui/painting/qwindowsurface.cpp b/src/gui/painting/qwindowsurface.cpp index 9b71818..0fb9bf7 100644 --- a/src/gui/painting/qwindowsurface.cpp +++ b/src/gui/painting/qwindowsurface.cpp @@ -307,11 +307,6 @@ QPoint QWindowSurface::offset(const QWidget *widget) const window surface. */ -bool QWindowSurface::hasStaticContentsSupport() const -{ - return false; -} - void QWindowSurface::setStaticContents(const QRegion ®ion) { d_ptr->staticContents = region; @@ -324,12 +319,12 @@ QRegion QWindowSurface::staticContents() const bool QWindowSurface::hasStaticContents() const { - return hasStaticContentsSupport() && !d_ptr->staticContents.isEmpty(); + return hasFeature(QWindowSurface::StaticContents) && !d_ptr->staticContents.isEmpty(); } -bool QWindowSurface::hasPartialUpdateSupport() const +QWindowSurface::WindowSurfaceFeatures QWindowSurface::features() const { - return true; + return PartialUpdates | PreservedContents; } #ifdef Q_WS_QPA diff --git a/src/gui/painting/qwindowsurface_p.h b/src/gui/painting/qwindowsurface_p.h index 4a2775f..a3fea67 100644 --- a/src/gui/painting/qwindowsurface_p.h +++ b/src/gui/painting/qwindowsurface_p.h @@ -68,6 +68,14 @@ class QPlatformWindow; class Q_GUI_EXPORT QWindowSurface { public: + enum WindowSurfaceFeature { + PartialUpdates = 0x00000001, // Supports doing partial updates. + PreservedContents = 0x00000002, // Supports doing flush without first doing a repaint. + StaticContents = 0x00000004, // Supports having static content regions when being resized. + AllFeatures = 0xffffffff // For convenience + }; + Q_DECLARE_FLAGS(WindowSurfaceFeatures, WindowSurfaceFeature) + QWindowSurface(QWidget *window, bool setDefaultSurface = true); virtual ~QWindowSurface(); @@ -100,8 +108,8 @@ public: virtual QPoint offset(const QWidget *widget) const; inline QRect rect(const QWidget *widget) const; - virtual bool hasStaticContentsSupport() const; - virtual bool hasPartialUpdateSupport() const; + bool hasFeature(WindowSurfaceFeature feature) const; + virtual WindowSurfaceFeatures features() const; void setStaticContents(const QRegion ®ion); QRegion staticContents() const; @@ -113,11 +121,18 @@ private: QWindowSurfacePrivate *d_ptr; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowSurface::WindowSurfaceFeatures) + inline QRect QWindowSurface::rect(const QWidget *widget) const { return widget->rect().translated(offset(widget)); } +inline bool QWindowSurface::hasFeature(WindowSurfaceFeature feature) const +{ + return (features() & feature) != 0; +} + QT_END_NAMESPACE #endif // QWINDOWSURFACE_P_H diff --git a/src/gui/painting/qwindowsurface_raster.cpp b/src/gui/painting/qwindowsurface_raster.cpp index a5c45c0..9860841 100644 --- a/src/gui/painting/qwindowsurface_raster.cpp +++ b/src/gui/painting/qwindowsurface_raster.cpp @@ -410,12 +410,11 @@ bool QRasterWindowSurface::scroll(const QRegion &area, int dx, int dy) #endif } -bool QRasterWindowSurface::hasStaticContentsSupport() const +QWindowSurface::WindowSurfaceFeatures QRasterWindowSurface::features() const { - return true; + return QWindowSurface::AllFeatures; } - void QRasterWindowSurface::prepareBuffer(QImage::Format format, QWidget *widget) { Q_D(QRasterWindowSurface); diff --git a/src/gui/painting/qwindowsurface_raster_p.h b/src/gui/painting/qwindowsurface_raster_p.h index 669511d..06abcd3 100644 --- a/src/gui/painting/qwindowsurface_raster_p.h +++ b/src/gui/painting/qwindowsurface_raster_p.h @@ -109,7 +109,7 @@ public: void beginPaint(const QRegion &rgn); void setGeometry(const QRect &rect); bool scroll(const QRegion &area, int dx, int dy); - bool hasStaticContentsSupport() const; + WindowSurfaceFeatures features() const; #ifdef QT_MAC_USE_COCOA CGContextRef imageContext(); diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index 4fa25cb..9fa01ed 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -239,9 +239,9 @@ void QS60WindowSurface::setGeometry(const QRect& rect) QWindowSurface::setGeometry(rect); } -bool QS60WindowSurface::hasStaticContentsSupport() const +QWindowSurface::WindowSurfaceFeatures QS60WindowSurface::features() const { - return true; + return QWindowSurface::AllFeatures; } CFbsBitmap* QS60WindowSurface::symbianBitmap() const diff --git a/src/gui/painting/qwindowsurface_s60_p.h b/src/gui/painting/qwindowsurface_s60_p.h index f730c87..25018d8 100644 --- a/src/gui/painting/qwindowsurface_s60_p.h +++ b/src/gui/painting/qwindowsurface_s60_p.h @@ -79,7 +79,7 @@ public: void setGeometry(const QRect &rect); - bool hasStaticContentsSupport() const; + WindowSurfaceFeatures features() const; CFbsBitmap *symbianBitmap() const; diff --git a/src/gui/painting/qwindowsurface_x11.cpp b/src/gui/painting/qwindowsurface_x11.cpp index ab4f53e..deb83b4 100644 --- a/src/gui/painting/qwindowsurface_x11.cpp +++ b/src/gui/painting/qwindowsurface_x11.cpp @@ -250,13 +250,16 @@ QPixmap QX11WindowSurface::grabWidget(const QWidget *widget, return px; } -bool QX11WindowSurface::hasStaticContentsSupport() const +QWindowSurface::WindowSurfaceFeatures QX11WindowSurface::features() const { + WindowSurfaceFeatures features = QWindowSurface::PartialUpdates | QWindowSurface::PreservedContents; #ifndef QT_NO_XRENDER - return !d_ptr->translucentBackground; + if (!d_ptr->translucentBackground) + features |= QWindowSurface::StaticContents; #else - return true; + features |= QWindowSurface::StaticContents; #endif + return features; } QT_END_NAMESPACE diff --git a/src/gui/painting/qwindowsurface_x11_p.h b/src/gui/painting/qwindowsurface_x11_p.h index d5179dd..df76f98 100644 --- a/src/gui/painting/qwindowsurface_x11_p.h +++ b/src/gui/painting/qwindowsurface_x11_p.h @@ -80,7 +80,8 @@ public: bool scroll(const QRegion &area, int dx, int dy); QPixmap grabWidget(const QWidget *widget, const QRect& rectangle = QRect()) const; - bool hasStaticContentsSupport() const; + WindowSurfaceFeatures features() const; + private: QX11WindowSurfacePrivate *d_ptr; GC gc; diff --git a/src/gui/s60framework/qs60mainappui.cpp b/src/gui/s60framework/qs60mainappui.cpp index 0c99f80..f591fcb 100644 --- a/src/gui/s60framework/qs60mainappui.cpp +++ b/src/gui/s60framework/qs60mainappui.cpp @@ -62,6 +62,7 @@ //Animated wallpapers in Qt applications are not supported. const TInt KAknDisableAnimationBackground = 0x02000000; +const TInt KAknSingleClickCompatible = 0x01000000; QT_BEGIN_NAMESPACE @@ -118,8 +119,12 @@ void QS60MainAppUi::ConstructL() // 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; + + // Also, add support for single touch for post 5th edition platforms. + // This has only impact when launching native dialogs/menus from inside QApplication. + if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) { + flags |= (KAknDisableAnimationBackground | KAknSingleClickCompatible); + } #endif BaseConstructL(flags); } diff --git a/src/gui/styles/qcleanlooksstyle.cpp b/src/gui/styles/qcleanlooksstyle.cpp index 8a2a88b..786aab3 100644 --- a/src/gui/styles/qcleanlooksstyle.cpp +++ b/src/gui/styles/qcleanlooksstyle.cpp @@ -68,9 +68,6 @@ #include <qlibrary.h> #include <private/qstylehelper_p.h> -#define CL_MAX(a,b) (a)>(b) ? (a):(b) // ### qMin/qMax does not work for vc6 -#define CL_MIN(a,b) (a)<(b) ? (a):(b) // remove this when it is working - QT_BEGIN_NAMESPACE using namespace QStyleHelper; @@ -533,8 +530,8 @@ static void qt_cleanlooks_draw_mdibutton(QPainter *painter, const QStyleOptionTi { QColor dark; dark.setHsv(option->palette.button().color().hue(), - CL_MIN(255, (int)(option->palette.button().color().saturation()*1.9)), - CL_MIN(255, (int)(option->palette.button().color().value()*0.7))); + qMin(255, (int)(option->palette.button().color().saturation()*1.9)), + qMin(255, (int)(option->palette.button().color().value()*0.7))); QColor highlight = option->palette.highlight().color(); @@ -691,11 +688,11 @@ void QCleanlooksStyle::drawPrimitive(PrimitiveElement elem, QColor darkOutline; QColor dark; darkOutline.setHsv(button.hue(), - CL_MIN(255, (int)(button.saturation()*3.0)), - CL_MIN(255, (int)(button.value()*0.6))); + qMin(255, (int)(button.saturation()*3.0)), + qMin(255, (int)(button.value()*0.6))); dark.setHsv(button.hue(), - CL_MIN(255, (int)(button.saturation()*1.9)), - CL_MIN(255, (int)(button.value()*0.7))); + qMin(255, (int)(button.saturation()*1.9)), + qMin(255, (int)(button.value()*0.7))); QColor tabFrameColor = mergedColors(option->palette.background().color(), dark.lighter(135), 60); @@ -844,7 +841,6 @@ void QCleanlooksStyle::drawPrimitive(PrimitiveElement elem, case PE_PanelButtonTool: painter->save(); if ((option->state & State_Enabled || option->state & State_On) || !(option->state & State_AutoRaise)) { - QRect rect = option->rect; QPen oldPen = painter->pen(); if (widget && widget->inherits("QDockWidgetTitleButton")) { @@ -1117,8 +1113,8 @@ void QCleanlooksStyle::drawPrimitive(PrimitiveElement elem, QColor gradientMidColor = option->palette.button().color(); QColor gradientStopColor; gradientStopColor.setHsv(buttonColor.hue(), - CL_MIN(255, (int)(buttonColor.saturation()*1.9)), - CL_MIN(255, (int)(buttonColor.value()*0.96))); + qMin(255, (int)(buttonColor.saturation()*1.9)), + qMin(255, (int)(buttonColor.value()*0.96))); QRect gradRect = rect.adjusted(1, 2, -1, -2); // gradient fill @@ -1244,7 +1240,6 @@ void QCleanlooksStyle::drawPrimitive(PrimitiveElement elem, if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) { QColor borderColor = darkOutline.lighter(110); QColor alphaCornerColor = mergedColors(borderColor, option->palette.background().color()); - QColor innerShadow = mergedColors(borderColor, option->palette.base().color()); int borderThickness = proxy()->pixelMetric(PM_TabBarBaseOverlap, twf, widget); bool reverse = (twf->direction == Qt::RightToLeft); @@ -1384,12 +1379,12 @@ void QCleanlooksStyle::drawControl(ControlElement element, const QStyleOption *o QColor button = option->palette.button().color(); QColor dark; dark.setHsv(button.hue(), - CL_MIN(255, (int)(button.saturation()*1.9)), - CL_MIN(255, (int)(button.value()*0.7))); + qMin(255, (int)(button.saturation()*1.9)), + qMin(255, (int)(button.value()*0.7))); QColor darkOutline; darkOutline.setHsv(button.hue(), - CL_MIN(255, (int)(button.saturation()*2.0)), - CL_MIN(255, (int)(button.value()*0.6))); + qMin(255, (int)(button.saturation()*2.0)), + qMin(255, (int)(button.value()*0.6))); QRect rect = option->rect; QColor shadow = mergedColors(option->palette.background().color().darker(120), dark.lighter(130), 60); @@ -1662,8 +1657,8 @@ void QCleanlooksStyle::drawControl(ControlElement element, const QStyleOption *o QColor gradientStopColor; QColor gradientStartColor = option->palette.button().color(); gradientStopColor.setHsv(gradientStartColor.hue(), - CL_MIN(255, (int)(gradientStartColor.saturation()*2)), - CL_MIN(255, (int)(gradientStartColor.value()*0.96))); + qMin(255, (int)(gradientStartColor.saturation()*2)), + qMin(255, (int)(gradientStartColor.value()*0.96))); QLinearGradient gradient(rect.topLeft(), rect.bottomLeft()); if (option->palette.background().gradient()) { gradient.setStops(option->palette.background().gradient()->stops()); @@ -1882,7 +1877,6 @@ void QCleanlooksStyle::drawControl(ControlElement element, const QStyleOption *o } else { alphaCornerColor = mergedColors(option->palette.background().color(), borderColor); } - QColor alphaTextColor = mergedColors(option->palette.background().color(), option->palette.text().color()); if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { painter->fillRect(menuItem->rect, menuBackground); int w = 0; @@ -2223,7 +2217,6 @@ void QCleanlooksStyle::drawControl(ControlElement element, const QStyleOption *o && tabBarAlignment == Qt::AlignLeft); QColor light = tab->palette.light().color(); - QColor midlight = tab->palette.midlight().color(); QColor background = tab->palette.background().color(); int borderThinkness = proxy()->pixelMetric(PM_TabBarBaseOverlap, tab, widget); @@ -2425,14 +2418,14 @@ void QCleanlooksStyle::drawComplexControl(ComplexControl control, const QStyleOp QColor grooveColor; QColor darkOutline; dark.setHsv(button.hue(), - CL_MIN(255, (int)(button.saturation()*1.9)), - CL_MIN(255, (int)(button.value()*0.7))); + qMin(255, (int)(button.saturation()*1.9)), + qMin(255, (int)(button.value()*0.7))); grooveColor.setHsv(button.hue(), - CL_MIN(255, (int)(button.saturation()*2.6)), - CL_MIN(255, (int)(button.value()*0.9))); + qMin(255, (int)(button.saturation()*2.6)), + qMin(255, (int)(button.value()*0.9))); darkOutline.setHsv(button.hue(), - CL_MIN(255, (int)(button.saturation()*3.0)), - CL_MIN(255, (int)(button.value()*0.6))); + qMin(255, (int)(button.saturation()*3.0)), + qMin(255, (int)(button.value()*0.6))); QColor alphaCornerColor; if (widget) { @@ -2447,14 +2440,6 @@ void QCleanlooksStyle::drawComplexControl(ComplexControl control, const QStyleOp QColor gradientStartColor = option->palette.button().color().lighter(108); QColor gradientStopColor = mergedColors(option->palette.button().color().darker(108), dark.lighter(150), 70); - QColor highlightedGradientStartColor = option->palette.button().color(); - QColor highlightedGradientStopColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 85); - - QColor highlightedDarkInnerBorderColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 35); - QColor highlightedLightInnerBorderColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 58); - - QColor buttonShadowAlpha = option->palette.background().color().darker(105); - QPalette palette = option->palette; switch (control) { @@ -3440,7 +3425,6 @@ void QCleanlooksStyle::drawComplexControl(ComplexControl control, const QStyleOp if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget); QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget); - QRect ticks = proxy()->subControlRect(CC_Slider, option, SC_SliderTickmarks, widget); bool horizontal = slider->orientation == Qt::Horizontal; bool ticksAbove = slider->tickPosition & QSlider::TicksAbove; @@ -3542,8 +3526,6 @@ void QCleanlooksStyle::drawComplexControl(ComplexControl control, const QStyleOp QRect pixmapRect(0, 0, handle.width(), handle.height()); QPainter handlePainter(&cache); - QColor highlightedGradientStartColor = option->palette.button().color(); - QColor highlightedGradientStopColor = option->palette.light().color(); QColor gradientStartColor = mergedColors(option->palette.button().color().lighter(155), dark.lighter(155), 50); QColor gradientStopColor = gradientStartColor.darker(108); @@ -3560,7 +3542,6 @@ void QCleanlooksStyle::drawComplexControl(ComplexControl control, const QStyleOp } // gradient fill - QRect innerBorder = gradRect; QRect r = pixmapRect.adjusted(1, 1, -1, -1); qt_cleanlooks_draw_gradient(&handlePainter, gradRect, diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index 8f99d6a..95ebdb4 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -223,16 +223,13 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q --yy; } if (!(opt->state & State_Enabled) && !(opt->state & State_On)) { - int pnt; - p->setPen(opt->palette.highlightedText().color()); - QPoint offset(1, 1); - for (pnt = 0; pnt < a.size(); ++pnt) - a[pnt].translate(offset.x(), offset.y()); + p->save(); + p->translate(1, 1); + p->setPen(opt->palette.light().color()); p->drawLines(a); - for (pnt = 0; pnt < a.size(); ++pnt) - a[pnt].translate(offset.x(), offset.y()); + p->restore(); } - p->setPen(opt->palette.text().color()); + p->setPen((opt->state & State_On) ? opt->palette.highlightedText().color() : opt->palette.text().color()); p->drawLines(a); break; } case PE_Frame: @@ -919,6 +916,7 @@ static QSizeF viewItemTextLayout(QTextLayout &textLayout, int lineWidth) return QSizeF(widthUsed, height); } + void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewItemV4 *option, const QRect &rect) const { Q_Q(const QCommonStyle); @@ -936,7 +934,7 @@ void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewIt textLayout.setFont(option->font); textLayout.setText(option->text); - QSizeF textLayoutSize = viewItemTextLayout(textLayout, textRect.width()); + viewItemTextLayout(textLayout, textRect.width()); QString elidedText; qreal height = 0; diff --git a/src/gui/styles/qgtkpainter.cpp b/src/gui/styles/qgtkpainter.cpp index 68ade04..6258fe4 100644 --- a/src/gui/styles/qgtkpainter.cpp +++ b/src/gui/styles/qgtkpainter.cpp @@ -586,7 +586,6 @@ void QGtkPainter::paintShadow(GtkWidget *gtkWidget, const gchar* part, if (!rect.isValid()) return; - QRect r = rect; QPixmap cache; QString pixmapName = uniqueName(QLS(part), state, shadow, rect.size()) % pmKey; if (!m_usePixmapCache || !QPixmapCache::find(pixmapName, cache)) { @@ -605,7 +604,6 @@ void QGtkPainter::paintFlatBox(GtkWidget *gtkWidget, const gchar* part, { if (!rect.isValid()) return; - QRect r = rect; QPixmap cache; QString pixmapName = uniqueName(QLS(part), state, shadow, rect.size()) % pmKey; if (!m_usePixmapCache || !QPixmapCache::find(pixmapName, cache)) { @@ -632,7 +630,6 @@ void QGtkPainter::paintExtention(GtkWidget *gtkWidget, if (!rect.isValid()) return; - QRect r = rect; QPixmap cache; QString pixmapName = uniqueName(QLS(part), state, shadow, rect.size(), gtkWidget) % HexString<uchar>(gap_pos); @@ -660,7 +657,6 @@ void QGtkPainter::paintOption(GtkWidget *gtkWidget, const QRect &radiorect, if (!rect.isValid()) return; - QRect r = rect; QPixmap cache; QString pixmapName = uniqueName(detail, state, shadow, rect.size()); GdkRectangle gtkCliprect = {0, 0, rect.width(), rect.height()}; @@ -692,7 +688,6 @@ void QGtkPainter::paintCheckbox(GtkWidget *gtkWidget, const QRect &checkrect, if (!rect.isValid()) return; - QRect r = rect; QPixmap cache; QString pixmapName = uniqueName(detail, state, shadow, rect.size()); GdkRectangle gtkCliprect = {0, 0, rect.width(), rect.height()}; diff --git a/src/gui/styles/qgtkstyle.cpp b/src/gui/styles/qgtkstyle.cpp index 277e302..d6dd527 100644 --- a/src/gui/styles/qgtkstyle.cpp +++ b/src/gui/styles/qgtkstyle.cpp @@ -782,7 +782,6 @@ void QGtkStyle::drawPrimitive(PrimitiveElement element, GtkStateType state = gtkPainter.gtkState(option); style = gtkTreeHeader->style; GtkArrowType type = GTK_ARROW_UP; - QRect r = header->rect; QImage arrow; // This sorting indicator inversion is intentional, and follows the GNOME HIG. // See http://library.gnome.org/devel/hig-book/stable/controls-lists.html.en#controls-lists-sortable @@ -1857,7 +1856,6 @@ void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionCom editArea.setRight(upRect.left()); } if (spinBox->frame) { - GtkShadowType shadow = GTK_SHADOW_OUT; GtkStateType state = gtkPainter.gtkState(option); if (!(option->state & State_Enabled)) @@ -1867,7 +1865,6 @@ void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionCom else if (state == GTK_STATE_PRELIGHT) state = GTK_STATE_NORMAL; - shadow = GTK_SHADOW_IN; style = gtkPainter.getStyle(gtkSpinButton); diff --git a/src/gui/styles/qmacstyle_mac.mm b/src/gui/styles/qmacstyle_mac.mm index 2d21628..18003ce 100644 --- a/src/gui/styles/qmacstyle_mac.mm +++ b/src/gui/styles/qmacstyle_mac.mm @@ -4707,7 +4707,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex HIThemeFrameDrawInfo fdi; fdi.version = qt_mac_hitheme_version; - fdi.state = kThemeStateInactive; + fdi.state = tds; fdi.kind = kHIThemeFrameTextFieldSquare; fdi.isFocused = false; HIRect hirect = qt_hirectForQRect(lineeditRect); diff --git a/src/gui/styles/qplastiquestyle.cpp b/src/gui/styles/qplastiquestyle.cpp index 02ce60e..1d33212 100644 --- a/src/gui/styles/qplastiquestyle.cpp +++ b/src/gui/styles/qplastiquestyle.cpp @@ -2007,14 +2007,10 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op } else { alphaCornerColor = mergedColors(option->palette.background().color(), borderColor); } - QColor alphaTextColor = mergedColors(option->palette.background().color(), option->palette.text().color()); QColor gradientStartColor = option->palette.button().color().lighter(104); QColor gradientStopColor = option->palette.button().color().darker(105); - QColor shadowGradientStartColor = option->palette.button().color().darker(115); - QColor shadowGradientStopColor = option->palette.button().color().darker(120); - QColor highlightedGradientStartColor = option->palette.button().color().lighter(101); QColor highlightedGradientStopColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 85); @@ -2025,8 +2021,6 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op QColor highlightedLightInnerBorderColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 58); QColor alphaInnerColor = mergedColors(highlightedDarkInnerBorderColor, option->palette.base().color()); - QColor lightShadow = lightShadowGradientStartColor; - QColor shadow = shadowGradientStartColor; switch (element) { #ifndef QT_NO_TABBAR @@ -3786,10 +3780,6 @@ void QPlastiqueStyle::drawComplexControl(ComplexControl control, const QStyleOpt } QColor gradientStartColor = option->palette.button().color().lighter(104); QColor gradientStopColor = option->palette.button().color().darker(105); - QColor highlightedGradientStartColor = option->palette.button().color().lighter(101); - QColor highlightedGradientStopColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 85); - QColor highlightedDarkInnerBorderColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 35); - QColor highlightedLightInnerBorderColor = mergedColors(option->palette.button().color(), option->palette.highlight().color(), 58); switch (control) { #ifndef QT_NO_SLIDER @@ -3797,7 +3787,6 @@ void QPlastiqueStyle::drawComplexControl(ComplexControl control, const QStyleOpt if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { QRect grooveRegion = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget); QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget); - QRect ticks = proxy()->subControlRect(CC_Slider, option, SC_SliderTickmarks, widget); bool horizontal = slider->orientation == Qt::Horizontal; bool ticksAbove = slider->tickPosition & QSlider::TicksAbove; bool ticksBelow = slider->tickPosition & QSlider::TicksBelow; diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 7a89478..fa6eeb7 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -72,19 +72,18 @@ #include "qcheckbox.h" #include "qdesktopwidget.h" #include "qprogressbar.h" +#include "qlabel.h" #include "private/qtoolbarextension_p.h" #include "private/qcombobox_p.h" #include "private/qwidget_p.h" #include "private/qapplication_p.h" +#include "private/qfont_p.h" #if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) QT_BEGIN_NAMESPACE -// from text/qfont.cpp -extern Q_GUI_EXPORT int qt_defaultDpiY(); - const QS60StylePrivate::SkinElementFlags QS60StylePrivate::KDefaultSkinElementFlags = SkinElementFlags(SF_PointNorth | SF_StateEnabled); @@ -107,8 +106,8 @@ const short QS60StylePrivate::data[][MAX_PIXELMETRICS] = { // *** generated pixel metrics *** {5,0,-909,0,0,2,0,2,-1,7,12,22,15,15,7,198,-909,-909,-909,20,13,2,0,0,21,7,18,30,3,3,1,-909,-909,0,1,0,0,12,20,15,15,18,18,1,115,18,0,-909,-909,-909,-909,0,0,16,2,-909,0,0,-909,16,-909,-909,-909,-909,32,18,55,24,55,4,4,4,9,13,-909,5,51,11,5,0,3,3,6,8,3,3,-909,2,-909,-909,-909,-909,5,5,3,1,106}, {5,0,-909,0,0,1,0,2,-1,8,14,22,15,15,7,164,-909,-909,-909,19,15,2,0,0,21,8,27,28,4,4,1,-909,-909,0,7,6,0,13,23,17,17,21,21,7,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,65,27,65,3,3,5,10,15,-909,5,58,13,5,0,4,4,7,9,4,4,-909,2,-909,-909,-909,-909,6,6,3,1,106}, -{7,0,-909,0,0,2,0,5,-1,25,69,46,37,37,9,258,-909,-909,-909,23,19,26,0,0,32,25,72,44,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,13,3,6,8,19,-909,7,74,19,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, -{7,0,-909,0,0,2,0,5,-1,25,68,46,37,37,9,258,-909,-909,-909,31,19,6,0,0,32,25,60,52,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,96,35,96,12,3,6,8,19,-909,7,74,22,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, +{7,0,-909,0,0,2,0,5,-1,25,69,46,37,37,9,258,-909,-909,-909,23,19,11,0,0,32,25,72,44,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,13,3,6,8,19,-909,7,74,19,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, +{7,0,-909,0,0,2,0,5,-1,25,68,46,37,37,9,258,-909,-909,-909,31,19,13,0,0,32,25,60,52,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,96,35,96,12,3,6,8,19,-909,7,74,22,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, {7,0,-909,0,0,2,0,2,-1,10,20,27,18,18,9,301,-909,-909,-909,29,18,5,0,0,35,7,32,30,5,5,2,-909,-909,0,2,8,0,16,28,21,21,26,26,2,170,26,0,-909,-909,-909,-909,0,0,21,6,-909,0,0,-909,-909,-909,-909,-909,-909,54,26,265,34,265,5,5,6,3,18,-909,7,72,19,7,0,5,6,8,11,6,5,-909,2,-909,-909,-909,-909,5,5,3,1,106}, {9,0,-909,0,0,2,0,5,-1,34,99,76,51,51,25,352,-909,-909,-909,29,25,7,0,0,43,34,42,76,7,7,2,-909,-909,0,9,14,0,23,39,30,30,37,37,9,391,40,0,-909,-909,-909,-909,0,0,29,2,-909,0,0,-909,29,-909,-909,-909,-909,115,37,96,48,96,19,19,9,1,25,-909,9,101,24,9,0,7,7,7,16,7,7,-909,3,-909,-909,-909,-909,9,9,3,1,184} // *** End of generated data *** @@ -683,6 +682,13 @@ void QS60StylePrivate::setThemePalette(QWidget *widget) if (header->viewport()) header->viewport()->setPalette(widgetPalette); QApplication::setPalette(widgetPalette, "QHeaderView"); + } else if (qobject_cast<QLabel *>(widget)) { + if (widget->window() && widget->window()->windowType() == Qt::Dialog) { + QPalette widgetPalette = widget->palette(); + widgetPalette.setColor(QPalette::WindowText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 19, 0)); + widget->setPalette(widgetPalette); + } } } @@ -957,6 +963,17 @@ bool QS60StylePrivate::isWidgetPressed(const QWidget *widget) return (widget && widget == m_pressedWidget); } +// Generates 1*1 white pixmap as a placeholder for real texture. +// The actual theme texture is drawn in qt_s60_fill_background(). +QPixmap QS60StylePrivate::placeHolderTexture() +{ + if (!m_placeHolderTexture) { + m_placeHolderTexture = new QPixmap(1,1); + m_placeHolderTexture->fill(Qt::green); + } + return *m_placeHolderTexture; +} + /*! \class QS60Style \brief The QS60Style class provides a look and feel suitable for applications on S60. @@ -1542,8 +1559,10 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, skinElement==QS60StylePrivate::SE_TabBarTabWestActive) { const int borderThickness = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); - const int tabOverlap = - QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap) - borderThickness; + int tabOverlap = pixelMetric(PM_TabBarTabOverlap); + if (tabOverlap > borderThickness) + tabOverlap -= borderThickness; + const bool usesScrollButtons = (widget) ? (qobject_cast<const QTabBar*>(widget))->usesScrollButtons() : false; const int roomForScrollButton = @@ -1582,9 +1601,11 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, QStyleOptionTabV3 optionTab = *tab; QRect tr = optionTab.rect; const bool directionMirrored = (optionTab.direction == Qt::RightToLeft); - const int borderThickness = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); - const int tabOverlap = - QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap) - borderThickness; + const int borderThickness = + QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + int tabOverlap = pixelMetric(PM_TabBarTabOverlap); + if (tabOverlap > borderThickness) + tabOverlap -= borderThickness; const bool usesScrollButtons = (widget) ? (qobject_cast<const QTabBar*>(widget))->usesScrollButtons() : false; const int roomForScrollButton = @@ -1743,16 +1764,26 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, QStyleOptionMenuItem optionMenuItem = *menuItem; bool drawSubMenuIndicator = false; + bool drawSeparator = false; switch(menuItem->menuItemType) { - case QStyleOptionMenuItem::Scroller: case QStyleOptionMenuItem::Separator: - return; // no separators or scrollers in S60 menus + drawSeparator = true; + break; + case QStyleOptionMenuItem::Scroller: + return; // no scrollers in S60 menus case QStyleOptionMenuItem::SubMenu: drawSubMenuIndicator = true; break; default: break; } + if (drawSeparator) { + painter->save(); + painter->setPen(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 10, 0)); + painter->drawLine(optionMenuItem.rect.topLeft(), optionMenuItem.rect.bottomRight()); + painter->restore(); + return; + } const bool enabled = optionMenuItem.state & State_Enabled; const bool checkable = optionMenuItem.checkType != QStyleOptionMenuItem::NotCheckable; bool ignoreCheckMark = false; @@ -1856,20 +1887,26 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, //In Sym^3, native menu items have "lines" between them if (QS60StylePrivate::isSingleClickUi()) { - const QColor lineColorAlpha = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 15, 0); - const int spacing = QS60StylePrivate::pixelMetric(PM_FrameCornerWidth); - //native platform sets each color byte to same value for "line 16" which just defines alpha for - //menuitem lines; lets use first byte "red". - QColor lineColor = optionMenuItem.palette.text().color(); - if (lineColorAlpha.isValid()) - lineColor.setAlpha(lineColorAlpha.red()); - painter->save(); - painter->setPen(lineColor); - - const int lineStartX = optionMenuItem.rect.left() + (QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) - 2) + spacing; - const int lineEndX = optionMenuItem.rect.right() - (QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) - 2) - spacing; - painter->drawLine(QPoint(lineStartX, optionMenuItem.rect.bottom()), QPoint(lineEndX, optionMenuItem.rect.bottom())); - painter->restore(); + int diff = widget->geometry().bottom() - optionMenuItem.rect.bottom(); + if (const QComboBox *cb = qobject_cast<const QComboBox*>(widget)) + diff = cb->view()->geometry().bottom() - optionMenuItem.rect.bottom(); + + // Skip drawing the horizontal line for the last menu item. + if (diff > optionMenuItem.rect.height()) { + const QColor lineColorAlpha = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 15, 0); + //native platform sets each color byte to same value for "line 16" which just defines alpha for + //menuitem lines; lets use first byte "red". + QColor lineColor = optionMenuItem.palette.text().color(); + if (lineColorAlpha.isValid()) + lineColor.setAlpha(lineColorAlpha.red()); + painter->save(); + painter->setPen(lineColor); + const int horizontalMargin = 2 * QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) - QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + const int lineStartX = optionMenuItem.rect.left() + horizontalMargin; + const int lineEndX = optionMenuItem.rect.right() - horizontalMargin; + painter->drawLine(QPoint(lineStartX, optionMenuItem.rect.bottom()), QPoint(lineEndX, optionMenuItem.rect.bottom())); + painter->restore(); + } } if (!enabled) painter->restore(); @@ -2264,13 +2301,16 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti #endif //QT_NO_MENU ) { //Need extra check since dialogs have their own theme background - if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget) && - QS60StylePrivate::equalToThemePalette(option->palette.window().texture().cacheKey(), QPalette::Window)) - //todo: for combobox listviews, the background should include area for menu scrollers, - //but this produces drawing issues as we need to turn clipping off. - QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_PopupBackground, painter, option->rect, flags); - else + if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget) + && QS60StylePrivate::equalToThemePalette(option->palette.window().texture().cacheKey(), QPalette::Window)) { + const bool comboMenu = qobject_cast<const QComboBoxListView *>(widget); + // Add margin area to the background, to avoid background being cut for first and last item. + const int verticalMenuAdjustment = comboMenu ? QS60StylePrivate::pixelMetric(PM_MenuVMargin) : 0; + const QRect adjustedMenuRect = option->rect.adjusted(0, -verticalMenuAdjustment, 0, verticalMenuAdjustment); + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_PopupBackground, painter, adjustedMenuRect, flags); + } else { commonStyleDraws = true; + } } break; case PE_FrameWindow: @@ -2514,6 +2554,11 @@ int QS60Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const //without having to define custom pixel metric metricValue *= 2; +#if defined(Q_WS_S60) + if (metric == PM_TabBarTabOverlap && (QSysInfo::s60Version() > QSysInfo::SV_S60_5_2)) + metricValue = 0; +#endif + return metricValue; } @@ -2538,17 +2583,16 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, tb->sizePolicy().horizontalPolicy() == QSizePolicy::Maximum) && tb->orientation() == Qt::Horizontal; if (parentCanGrowHorizontally) { - int visibleButtons = 0; + int buttons = 0; //Make the auto-stretch to happen only for horizontal orientation if (tb && tb->orientation() == Qt::Horizontal) { QList<QAction*> actionList = tb->actions(); for (int i = 0; i < actionList.count(); i++) { - if (actionList.at(i)->isVisible()) - visibleButtons++; + buttons++; } } - if (widget->parentWidget() && visibleButtons > 0) { + if (widget->parentWidget() && buttons > 0) { QWidget *w = const_cast<QWidget *>(widget); int toolBarMaxWidth = 0; int totalMargin = 0; @@ -2571,7 +2615,7 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, toolBarMaxWidth -= totalMargin; //ensure that buttons are side-by-side and not on top of each other - const int toolButtonWidth = (toolBarMaxWidth / visibleButtons) + const int toolButtonWidth = (toolBarMaxWidth / buttons) - pixelMetric(QStyle::PM_ToolBarItemSpacing) - pixelMetric(QStyle::PM_ToolBarItemMargin) //toolbar frame needs to be reduced again, since QToolBarLayout adds it for each toolbar action @@ -2604,10 +2648,7 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, sz += QSize(2 * f->lineWidth, 4 * f->lineWidth); break; case CT_TabBarTab: { - const QSize naviPaneSize = QS60StylePrivate::naviPaneSize(); sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); - if (naviPaneSize.height() > sz.height()) - sz.setHeight(naviPaneSize.height()); // Adjust beginning tabbar item size, if scrollbuttons are used. This is to ensure that the // tabbar item content fits, since scrollbuttons are making beginning tabbar item smaller. int scrollButtonSize = 0; @@ -2627,13 +2668,11 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, case CT_ItemViewItem: if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) { if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { - sz = QSize(); + sz = QSize(menuItem->rect.width() - 2 * pixelMetric(PM_MenuHMargin) - 2 * QS60StylePrivate::pixelMetric(PM_FrameCornerWidth), 1); break; } } sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); - //native items have small empty areas at the beginning and end of menu item - sz.setWidth(sz.width() + 2 * pixelMetric(PM_MenuHMargin) + 2 * QS60StylePrivate::pixelMetric(PM_FrameCornerWidth)); if (QS60StylePrivate::isTouchSupported()) { //Make itemview easier to use in touch devices sz.setHeight(sz.height() + 2 * pixelMetric(PM_FocusFrameVMargin)); @@ -2992,10 +3031,11 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con ret = QCommonStyle::subElementRect(element, opt, widget); if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) { - const int tabOverlapNoBorder = - QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap); - const int tabOverlap = - tabOverlapNoBorder - QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + const int borderThickness = + QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + int tabOverlap = pixelMetric(PM_TabBarTabOverlap); + if (tabOverlap > borderThickness) + tabOverlap -= borderThickness; const QTabWidget *tab = qobject_cast<const QTabWidget *>(widget); int gain = (tab) ? tabOverlap * tab->count() : 0; switch (twf->shape) { @@ -3013,7 +3053,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con if ((ret.right() + gain) > widget->rect().right()) gain = widget->rect().right() - ret.right(); ret.adjust(0, 0, gain, 0); - } + } } break; } @@ -3101,7 +3141,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con } break; case SE_ItemViewItemCheckIndicator: - if (const QStyleOptionViewItemV2 *vopt = qstyleoption_cast<const QStyleOptionViewItemV2 *>(opt)) { + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) { const QAbstractItemView *listItem = qobject_cast<const QAbstractItemView *>(widget); const bool singleSelection = listItem && @@ -3109,7 +3149,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con listItem->selectionMode() == QAbstractItemView::NoSelection); const bool checkBoxOnly = (vopt->features & QStyleOptionViewItemV2::HasCheckIndicator) && listItem && - singleSelection; + singleSelection && vopt->text.isEmpty() && vopt->icon.isNull(); // Selection check mark rect. const int indicatorWidth = QS60StylePrivate::pixelMetric(PM_IndicatorWidth); @@ -3353,9 +3393,9 @@ bool QS60Style::event(QEvent *e) QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const { - const int iconDimension = QS60StylePrivate::pixelMetric(PM_ToolBarIconSize); - const QRect iconSize = (!option) ? QRect(0, 0, iconDimension, iconDimension) : option->rect; QS60StyleEnums::SkinParts part; + qreal iconHeightMultiplier = 1.0; + qreal iconWidthMultiplier = 1.0; QS60StylePrivate::SkinElementFlags adjustedFlags; if (option) adjustedFlags = (option->state & State_Enabled || option->state == 0) ? @@ -3364,15 +3404,20 @@ QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, switch(standardIcon) { case SP_MessageBoxWarning: + // By default, S60 messagebox icons have 4:3 ratio. Value is from S60 LAF documentation. + iconHeightMultiplier = 1.33; part = QS60StyleEnums::SP_QgnNoteWarning; break; case SP_MessageBoxInformation: + iconHeightMultiplier = 1.33; part = QS60StyleEnums::SP_QgnNoteInfo; break; case SP_MessageBoxCritical: + iconHeightMultiplier = 1.33; part = QS60StyleEnums::SP_QgnNoteError; break; case SP_MessageBoxQuestion: + iconHeightMultiplier = 1.33; part = QS60StyleEnums::SP_QgnNoteQuery; break; case SP_ArrowRight: @@ -3427,11 +3472,13 @@ QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, adjustedFlags |= QS60StylePrivate::SF_PointEast; part = QS60StyleEnums::SP_QgnIndiSubmenu; break; - default: return QCommonStyle::standardIconImplementation(standardIcon, option, widget); } const QS60StylePrivate::SkinElementFlags flags = adjustedFlags; + const int iconDimension = QS60StylePrivate::pixelMetric(PM_ToolBarIconSize); + const QRect iconSize = (!option) ? + QRect(0, 0, iconDimension * iconWidthMultiplier, iconDimension * iconHeightMultiplier) : option->rect; const QPixmap cachedPixMap(QS60StylePrivate::cachedPart(part, iconSize.size(), 0, flags)); return cachedPixMap.isNull() ? QCommonStyle::standardIconImplementation(standardIcon, option, widget) : QIcon(cachedPixMap); diff --git a/src/gui/styles/qs60style_p.h b/src/gui/styles/qs60style_p.h index 3628b27..e146a4e 100644 --- a/src/gui/styles/qs60style_p.h +++ b/src/gui/styles/qs60style_p.h @@ -562,8 +562,6 @@ public: void handleSkinChange(); #endif // Q_WS_S60 - static QSize naviPaneSize(); - //Checks that the current brush is transparent or has BrushStyle NoBrush, //so that theme graphic background can be drawn. static bool canDrawThemeBackground(const QBrush &backgroundBrush, const QWidget *widget); diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index c5149a3..1e374cb 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -89,17 +89,25 @@ enum TSupportRelease { ES60_5_0 = 0x0004, ES60_5_1 = 0x0008, ES60_5_2 = 0x0010, + ES60_5_3 = 0x0020, ES60_3_X = ES60_3_1 | ES60_3_2, // Releases before Symbian Foundation ES60_PreSF = ES60_3_1 | ES60_3_2 | ES60_5_0, + // Releases before the S60 5.2 + ES60_Pre52 = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1, + // Releases before S60 5.3 + ES60_Pre53 = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2, // Add all new releases here - ES60_All = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 + ES60_All = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 | ES60_5_3 }; typedef struct { - const TAknsItemID &skinID; - TDrawType drawType; - int supportInfo; + const TAknsItemID &skinID; // Determines default theme graphics ID. + TDrawType drawType; // Determines which native drawing routine is used to draw this item. + int supportInfo; // Defines the S60 versions that use the default graphics. + // These two, define new graphics that are used in releases other than partMapEntry.supportInfo defined releases. + // In general, these are given in numeric form to allow style compilation in earlier + // native releases that do not contain the new graphics. int newMajorSkinId; int newMinorSkinId; } partMapEntry; @@ -158,7 +166,6 @@ public: static bool disabledPartGraphic(QS60StyleEnums::SkinParts &part); static bool disabledFrameGraphic(QS60StylePrivate::SkinFrameElements &frame); static QPixmap generateMissingThemeGraphic(QS60StyleEnums::SkinParts &part, const QSize &size, QS60StylePrivate::SkinElementFlags flags); - static QSize naviPaneSize(); static TAknsItemID partSpecificThemeId(int part); static QVariant themeDefinition(QS60StyleEnums::ThemeDefinitions definition, QS60StyleEnums::SkinParts part); @@ -189,12 +196,14 @@ const partMapEntry QS60StyleModeSpecifics::m_partMap[] = { /* SP_QgnGrafScrollArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawGulIcon, ES60_All, -1,-1}, /* SP_QgnGrafScrollArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawGulIcon, ES60_All, -1,-1}, /* SP_QgnGrafScrollArrowUp */ {KAknsIIDQgnGrafScrollArrowUp, EDrawGulIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_All, -1,-1}, + + // In S60 5.3 there is a new tab graphic + /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2219}, //KAknsIIDQtgFrTabActiveNormalL + /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x221b}, //KAknsIIDQtgFrTabActiveNormalC + /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x221a}, //KAknsIIDQtgFrTabActiveNormalR + /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2221}, //KAknsIIDQtgFrTabPassiveNormalL + /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2223}, //KAknsIIDQtgFrTabPassiveNormalC + /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2222}, //KAknsIIDQtgFrTabPassiveNormalR // In 3.1 there is no slider groove. /* SP_QgnGrafNsliderEndLeft */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x19cf /* KAknsIIDQgnGrafNsliderEndLeft */}, @@ -777,16 +786,8 @@ QPoint qt_s60_fill_background_offset(const QWidget *targetWidget) { CCoeControl *control = targetWidget->effectiveWinId(); TPoint pos(0,0); - if (control) { - // FIXME properly: S60 3.1 has a bug that CCoeControl::PositionRelativeToScreen sometimes - // freezes the device, possibly in cases where we run out of memory. - // We use CCoeControl::Position instead in S60 3.1, which returns same values - // in most cases. - if (QSysInfo::s60Version() == QSysInfo::SV_S60_3_1) - pos = control->Position(); - else - pos = control->PositionRelativeToScreen(); - } + if (control) + pos = control->PositionRelativeToScreen(); return QPoint(pos.iX, pos.iY); } @@ -1141,7 +1142,8 @@ bool QS60StyleModeSpecifics::checkSupport(const int supportedRelease) (currentRelease == QSysInfo::SV_S60_3_2 && supportedRelease & ES60_3_2) || (currentRelease == QSysInfo::SV_S60_5_0 && supportedRelease & ES60_5_0) || (currentRelease == QSysInfo::SV_S60_5_1 && supportedRelease & ES60_5_1) || - (currentRelease == QSysInfo::SV_S60_5_2 && supportedRelease & ES60_5_2)); + (currentRelease == QSysInfo::SV_S60_5_2 && supportedRelease & ES60_5_2) || + (currentRelease == QSysInfo::SV_S60_5_3 && supportedRelease & ES60_5_3) ); } TAknsItemID QS60StyleModeSpecifics::partSpecificThemeId(int part) @@ -1402,6 +1404,7 @@ QPixmap QS60StylePrivate::backgroundTexture(bool skipCreation) if (m_background->width() != applicationRect.Width() || m_background->height() != applicationRect.Height()) { delete m_background; + m_background = 0; createNewBackground = true; } } @@ -1429,17 +1432,6 @@ QPixmap QS60StylePrivate::backgroundTexture(bool skipCreation) return *m_background; } -// Generates 1*1 white pixmap as a placeholder for real texture. -// The actual theme texture is drawn in qt_s60_fill_background(). -QPixmap QS60StylePrivate::placeHolderTexture() -{ - if (!m_placeHolderTexture) { - m_placeHolderTexture = new QPixmap(1,1); - m_placeHolderTexture->fill(Qt::white); - } - return *m_placeHolderTexture; -} - QSize QS60StylePrivate::screenSize() { return QSize(S60->screenWidthInPixels, S60->screenHeightInPixels); @@ -1477,23 +1469,6 @@ void QS60StylePrivate::handleSkinChange() #endif } -QSize QS60StylePrivate::naviPaneSize() -{ - return QS60StyleModeSpecifics::naviPaneSize(); -} - -QSize QS60StyleModeSpecifics::naviPaneSize() -{ - CAknNavigationControlContainer* naviContainer; - if (S60->statusPane()) { - TRAPD(err, naviContainer = static_cast<CAknNavigationControlContainer*> - (S60->statusPane()->ControlL(TUid::Uid(EEikStatusPaneUidNavi)))); - if (err==KErrNone) - return QSize(naviContainer->Size().iWidth, naviContainer->Size().iHeight); - } - return QSize(0,0); -} - int QS60StylePrivate::currentAnimationFrame(QS60StyleEnums::SkinParts part) { QS60StyleAnimation *animation = animationDefinition(part); diff --git a/src/gui/styles/qs60style_simulated.cpp b/src/gui/styles/qs60style_simulated.cpp index 7223c6b..a5aeac3 100644 --- a/src/gui/styles/qs60style_simulated.cpp +++ b/src/gui/styles/qs60style_simulated.cpp @@ -318,11 +318,6 @@ QPixmap QS60StylePrivate::backgroundTexture(bool /*skipCreation*/) return *m_background; } -QSize QS60StylePrivate::naviPaneSize() -{ - return QSize(0, 0); -} - bool QS60StylePrivate::isTouchSupported() { #ifdef QT_KEYPAD_NAVIGATION diff --git a/src/gui/styles/qstylehelper_p.h b/src/gui/styles/qstylehelper_p.h index 559f7f7..27587e3 100644 --- a/src/gui/styles/qstylehelper_p.h +++ b/src/gui/styles/qstylehelper_p.h @@ -110,6 +110,7 @@ template <typename T> enum { ExactSize = true }; static int size(const HexString<T> &) { return sizeof(T) * 2; } static inline void appendTo(const HexString<T> &str, QChar *&out) { str.write(out); } + typedef QString ConvertTo; }; QT_END_NAMESPACE diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index ecf924c..faa929e 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -3323,6 +3323,13 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q } break; + case CE_FocusFrame: + if (!rule.hasNativeBorder()) { + rule.drawBorder(p, opt->rect); + return; + } + break; + case CE_PushButton: if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) { if (rule.hasDrawable() || rule.hasBox() || rule.hasPosition() || rule.hasPalette() || diff --git a/src/gui/styles/qwindowsstyle.cpp b/src/gui/styles/qwindowsstyle.cpp index 44f3f92..754486e 100644 --- a/src/gui/styles/qwindowsstyle.cpp +++ b/src/gui/styles/qwindowsstyle.cpp @@ -1858,8 +1858,8 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai } QRect vCheckRect = visualRect(opt->direction, menuitem->rect, QRect(menuitem->rect.x(), menuitem->rect.y(), checkcol, menuitem->rect.height())); - if (checked) { - if (act && !dis) { + if (!menuitem->icon.isNull() && checked) { + if (act) { qDrawShadePanel(p, vCheckRect, menuitem->palette, true, 1, &menuitem->palette.brush(QPalette::Button)); @@ -2028,10 +2028,8 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai && tabBarAlignment == Qt::AlignLeft); QColor light = tab->palette.light().color(); - QColor midlight = tab->palette.midlight().color(); QColor dark = tab->palette.dark().color(); QColor shadow = tab->palette.shadow().color(); - QColor background = tab->palette.background().color(); int borderThinkness = proxy()->pixelMetric(PM_TabBarBaseOverlap, tab, widget); if (selected) borderThinkness /= 2; diff --git a/src/gui/styles/qwindowsvistastyle.cpp b/src/gui/styles/qwindowsvistastyle.cpp index 7f1a3ab..123741e 100644 --- a/src/gui/styles/qwindowsvistastyle.cpp +++ b/src/gui/styles/qwindowsvistastyle.cpp @@ -969,7 +969,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) { - if (QWindowsVistaAnimation *anim = d->widgetAnimation(widget)) { + QWindowsVistaAnimation *anim = d->widgetAnimation(widget); + if (anim && (btn->state & State_Enabled)) { anim->paint(painter, option); } else { name = QLatin1String("BUTTON"); @@ -996,7 +997,6 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) && (state & State_Enabled) && (state & State_Active)) { - QWindowsVistaAnimation *anim = d->widgetAnimation(widget); if (!anim && widget) { QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); startImage.fill(0); @@ -1074,8 +1074,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption } if (const QProgressBar *progressbar = qobject_cast<const QProgressBar *>(widget)) { - if (((progressbar->value() > 0 && d->transitionsEnabled()) || isIndeterminate)) { - if (!d->widgetAnimation(progressbar) && progressbar->value() < progressbar->maximum()) { + if (isIndeterminate || (progressbar->value() > 0 && (progressbar->value() < progressbar->maximum()) && d->transitionsEnabled())) { + if (!d->widgetAnimation(progressbar)) { QWindowsVistaAnimation *a = new QWindowsVistaAnimation; a->setWidget(const_cast<QWidget*>(widget)); a->setStartTime(QTime::currentTime()); @@ -2502,7 +2502,6 @@ void QWindowsVistaStylePrivate::timerEvent() animations[i]->widget()->update(); if (!animations[i]->widget() || - !animations[i]->widget()->isEnabled() || !animations[i]->widget()->isVisible() || animations[i]->widget()->window()->isMinimized() || !animations[i]->running() || diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp index 74a20fc..4b2c3a5 100644 --- a/src/gui/styles/qwindowsxpstyle.cpp +++ b/src/gui/styles/qwindowsxpstyle.cpp @@ -1196,8 +1196,14 @@ QRect QWindowsXPStyle::subElementRect(SubElement sr, const QStyleOption *option, if (qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) { rect = QWindowsStyle::subElementRect(sr, option, widget); - if (sr == SE_TabWidgetTabContents) - rect.adjust(0, 0, -2, -2); + if (sr == SE_TabWidgetTabContents) { + if (const QTabWidget *tabWidget = qobject_cast<const QTabWidget *>(widget)) { + if (tabWidget->documentMode()) + break; + } + + rect.adjust(0, 0, -2, -2); + } } break; case SE_TabWidgetTabBar: { diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index f77e237..b8cfb1f 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -282,27 +282,16 @@ QFontPrivate::~QFontPrivate() scFont = 0; } -#if !defined(Q_WS_MAC) extern QMutex *qt_fontdatabase_mutex(); -QFontEngine *QFontPrivate::engineForScript(int script) const -{ - QMutexLocker locker(qt_fontdatabase_mutex()); - if (script >= QUnicodeTables::Inherited) - script = QUnicodeTables::Common; - if (engineData && engineData->fontCache != QFontCache::instance()) { - // throw out engineData that came from a different thread - engineData->ref.deref(); - engineData = 0; - } - if (!engineData || !engineData->engines[script]) - QFontDatabase::load(this, script); - return engineData->engines[script]; -} +#if !defined(Q_WS_MAC) +#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engines[script] #else +#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engine +#endif + QFontEngine *QFontPrivate::engineForScript(int script) const { - extern QMutex *qt_fontdatabase_mutex(); QMutexLocker locker(qt_fontdatabase_mutex()); if (script >= QUnicodeTables::Inherited) script = QUnicodeTables::Common; @@ -311,11 +300,10 @@ QFontEngine *QFontPrivate::engineForScript(int script) const engineData->ref.deref(); engineData = 0; } - if (!engineData || !engineData->engine) + if (!engineData || !QT_FONT_ENGINE_FROM_DATA(engineData, script)) QFontDatabase::load(this, script); - return engineData->engine; + return QT_FONT_ENGINE_FROM_DATA(engineData, script); } -#endif void QFontPrivate::alterCharForCapitalization(QChar &c) const { switch (capital) { diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index 8dbc746..0c7b6f8 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -239,7 +239,7 @@ public: bool isCopyOf(const QFont &) const; #ifdef Q_COMPILER_RVALUE_REFS inline QFont &operator=(QFont &&other) - { qSwap(d, other.d); return *this; } + { qSwap(d, other.d); qSwap(resolve_mask, other.resolve_mask); return *this; } #endif #ifdef Q_WS_WIN diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index c1a5048..43dca81 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -281,6 +281,10 @@ public: int timer_id; }; +Q_GUI_EXPORT int qt_defaultDpiX(); +Q_GUI_EXPORT int qt_defaultDpiY(); +Q_GUI_EXPORT int qt_defaultDpi(); + QT_END_NAMESPACE #endif // QFONT_P_H diff --git a/src/gui/text/qfont_win.cpp b/src/gui/text/qfont_win.cpp index 7d710ea..3ef761b 100644 --- a/src/gui/text/qfont_win.cpp +++ b/src/gui/text/qfont_win.cpp @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE extern HDC shared_dc(); // common dc for all fonts +extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp // ### maybe move to qapplication_win QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/) @@ -65,20 +66,8 @@ QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/) QString family = QString::fromWCharArray(lf.lfFaceName); QFont qf(family); qf.setItalic(lf.lfItalic); - if (lf.lfWeight != FW_DONTCARE) { - int weight; - if (lf.lfWeight < 400) - weight = QFont::Light; - else if (lf.lfWeight < 600) - weight = QFont::Normal; - else if (lf.lfWeight < 700) - weight = QFont::DemiBold; - else if (lf.lfWeight < 800) - weight = QFont::Bold; - else - weight = QFont::Black; - qf.setWeight(weight); - } + if (lf.lfWeight != FW_DONTCARE) + qf.setWeight(weightFromInteger(lf.lfWeight)); int lfh = qAbs(lf.lfHeight); qf.setPointSizeF(lfh * 72.0 / GetDeviceCaps(shared_dc(),LOGPIXELSY)); qf.setUnderline(false); diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index cbe0423..36b0ea9 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -89,8 +89,6 @@ QT_BEGIN_NAMESPACE #define SMOOTH_SCALABLE 0xffff -Q_GUI_EXPORT extern int qt_defaultDpiY(); // in qfont.cpp - bool qt_enable_test_font = false; Q_AUTOTEST_EXPORT void qt_setQtEnableTestFont(bool value) @@ -138,6 +136,21 @@ static int getFontWeight(const QString &weightString) return (int) QFont::Normal; } +// convert 0 ~ 1000 integer to QFont::Weight +QFont::Weight weightFromInteger(int weight) +{ + if (weight < 400) + return QFont::Light; + else if (weight < 600) + return QFont::Normal; + else if (weight < 700) + return QFont::DemiBold; + else if (weight < 800) + return QFont::Bold; + else + return QFont::Black; +} + struct QtFontEncoding { signed int encoding : 16; @@ -499,8 +512,6 @@ QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create) // ### copied to tools/makeqpf/qpf2.cpp -#if (defined(Q_WS_QWS) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || (defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)) - // see the Unicode subset bitfields in the MSDN docs static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { // Any, @@ -578,7 +589,7 @@ static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { #define JapaneseCsbBit 17 #define KoreanCsbBit 21 -static QList<QFontDatabase::WritingSystem> determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]) +QList<QFontDatabase::WritingSystem> qt_determine_writing_systems_from_truetype_bits(quint32 unicodeRange[4], quint32 codePageRange[2]) { QList<QFontDatabase::WritingSystem> writingSystems; bool hasScript = false; @@ -625,7 +636,6 @@ static QList<QFontDatabase::WritingSystem> determineWritingSystemsFromTrueTypeBi return writingSystems; } -#endif #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // class with virtual destructor, derived in qfontdatabase_s60.cpp @@ -875,7 +885,7 @@ QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteA os2->ulCodePageRange1, os2->ulCodePageRange2 }; - writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + writingSystems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); //for (int i = 0; i < writingSystems.count(); ++i) // qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i)); } @@ -938,6 +948,11 @@ static const int scriptForWritingSystem[] = { QUnicodeTables::Nko // Nko }; +int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem) +{ + return scriptForWritingSystem[writingSystem]; +} + #if defined Q_WS_QWS || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)) || defined(Q_WS_WIN) static inline bool requiresOpenType(int writingSystem) diff --git a/src/gui/text/qfontdatabase_mac.cpp b/src/gui/text/qfontdatabase_mac.cpp index ad2c1b2..5ba236b 100644 --- a/src/gui/text/qfontdatabase_mac.cpp +++ b/src/gui/text/qfontdatabase_mac.cpp @@ -72,7 +72,7 @@ static void initWritingSystems(QtFontFamily *family, ATSFontRef atsFont) qFromBigEndian<quint32>(os2Table.data() + 54) }; quint32 codePageRange[2] = { qFromBigEndian<quint32>(os2Table.data() + 78), qFromBigEndian<quint32>(os2Table.data() + 82) }; - QList<QFontDatabase::WritingSystem> systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + QList<QFontDatabase::WritingSystem> systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); #if 0 QCFString name; ATSFontGetName(atsFont, kATSOptionFlagsDefault, &name); @@ -244,6 +244,11 @@ static const char *styleHint(const QFontDef &request) return stylehint; } +static inline float weightToFloat(unsigned int weight) +{ + return (weight - 50) / 100.0; +} + void QFontDatabase::load(const QFontPrivate *d, int script) { // sanity checks diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp index 6d3970e..3ab1ac8 100644 --- a/src/gui/text/qfontdatabase_s60.cpp +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -152,7 +152,6 @@ public: COpenFontRasterizer *m_rasterizer; mutable QList<const QSymbianTypeFaceExtras *> m_extras; - mutable QHash<QString, const QSymbianTypeFaceExtras *> m_extrasHash; mutable QSet<QString> m_applicationFontFamilies; }; @@ -255,8 +254,9 @@ void QSymbianFontDatabaseExtrasImplementation::clear() static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras); if (!dbExtras) return; // initializeDb() has never been called + QSymbianTypeFaceExtrasHash &extrasHash = S60->fontData(); if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) { - qDeleteAll(dbExtras->m_extrasHash); + qDeleteAll(extrasHash); } else { typedef QList<const QSymbianTypeFaceExtras *>::iterator iterator; for (iterator p = dbExtras->m_extras.begin(); p != dbExtras->m_extras.end(); ++p) { @@ -265,11 +265,16 @@ void QSymbianFontDatabaseExtrasImplementation::clear() } dbExtras->m_extras.clear(); } - dbExtras->m_extrasHash.clear(); + extrasHash.clear(); } void qt_cleanup_symbianFontDatabase() { + static bool cleanupDone = false; + if (cleanupDone) + return; + cleanupDone = true; + QFontDatabasePrivate *db = privateDb(); if (!db) return; @@ -320,9 +325,12 @@ COpenFont* OpenFontFromBitmapFont(const CBitmapFont* aBitmapFont) const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &aTypeface, bool bold, bool italic) const { + QSymbianTypeFaceExtrasHash &extrasHash = S60->fontData(); + if (extrasHash.isEmpty() && QThread::currentThread() != QApplication::instance()->thread()) + S60->addThreadLocalReleaseFunc(clear); const QString typeface = qt_symbian_fontNameWithAppFontMarker(aTypeface); const QString searchKey = typeface + QString::number(int(bold)) + QString::number(int(italic)); - if (!m_extrasHash.contains(searchKey)) { + if (!extrasHash.contains(searchKey)) { TFontSpec searchSpec(qt_QString2TPtrC(typeface), 1); if (bold) searchSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold); @@ -336,7 +344,7 @@ const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(c QScopedPointer<CFont, CFontFromScreenDeviceReleaser> sFont(font); QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font); sFont.take(); - m_extrasHash.insert(searchKey, extras); + extrasHash.insert(searchKey, extras); } else { const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, searchSpec); Q_ASSERT(err == KErrNone && font); @@ -350,20 +358,20 @@ const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(c const TOpenFontFaceAttrib* const attrib = openFont->FaceAttrib(); const QString foundKey = QString((const QChar*)attrib->FullName().Ptr(), attrib->FullName().Length()); - if (!m_extrasHash.contains(foundKey)) { + if (!extrasHash.contains(foundKey)) { QScopedPointer<CFont, CFontFromFontStoreReleaser> sFont(font); QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font, openFont); sFont.take(); m_extras.append(extras); - m_extrasHash.insert(searchKey, extras); - m_extrasHash.insert(foundKey, extras); + extrasHash.insert(searchKey, extras); + extrasHash.insert(foundKey, extras); } else { m_store->ReleaseFont(font); - m_extrasHash.insert(searchKey, m_extrasHash.value(foundKey)); + extrasHash.insert(searchKey, extrasHash.value(foundKey)); } } } - return m_extrasHash.value(searchKey); + return extrasHash.value(searchKey); } void QSymbianFontDatabaseExtrasImplementation::removeAppFontData( @@ -521,7 +529,7 @@ static bool registerScreenDeviceFont(int screenDeviceFontIndex, qFromBigEndian<quint32>(ulCodePageRange + 4) }; const QList<QFontDatabase::WritingSystem> writingSystems = - determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); foreach (const QFontDatabase::WritingSystem system, writingSystems) family->writingSystems[system] = QtFontFamily::Supported; return true; @@ -956,7 +964,7 @@ bool QFontDatabase::removeAllApplicationFonts() bool QFontDatabase::supportsThreadedFontRendering() { - return false; + return QSymbianTypeFaceExtras::symbianFontTableApiAvailable(); } static diff --git a/src/gui/text/qfontdatabase_win.cpp b/src/gui/text/qfontdatabase_win.cpp index 8279195..05b7509 100644 --- a/src/gui/text/qfontdatabase_win.cpp +++ b/src/gui/text/qfontdatabase_win.cpp @@ -242,6 +242,8 @@ error: return i18n_name; } +extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp + static void addFontToDatabase(QString familyName, const QString &scriptName, TEXTMETRIC *textmetric, @@ -274,16 +276,7 @@ void addFontToDatabase(QString familyName, const QString &scriptName, if (familyName[0] != QLatin1Char('@') && !familyName.startsWith(QLatin1String("WST_"))) { QtFontStyle::Key styleKey; styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal; - if (weight < 400) - styleKey.weight = QFont::Light; - else if (weight < 600) - styleKey.weight = QFont::Normal; - else if (weight < 700) - styleKey.weight = QFont::DemiBold; - else if (weight < 800) - styleKey.weight = QFont::Bold; - else - styleKey.weight = QFont::Black; + styleKey.weight = weightFromInteger(weight); QtFontFamily *family = privateDb()->family(familyName, true); @@ -340,7 +333,7 @@ void addFontToDatabase(QString familyName, const QString &scriptName, quint32 codePageRange[2] = { signature->fsCsb[0], signature->fsCsb[1] }; - QList<QFontDatabase::WritingSystem> systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + QList<QFontDatabase::WritingSystem> systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); for (int i = 0; i < systems.count(); ++i) { QFontDatabase::WritingSystem writingSystem = systems.at(i); @@ -530,26 +523,26 @@ static inline void load(const QString &family = QString(), int = -1) -static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, const QFontPrivate *fp) +static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, HDC fontHdc, int dpi) { fe->fontDef = request; // most settings are equal - HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fp->hdc) ? fp->hdc : shared_dc(); + HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : shared_dc(); SelectObject(dc, fe->hfont); wchar_t n[64]; GetTextFace(dc, 64, n); fe->fontDef.family = QString::fromWCharArray(n); fe->fontDef.fixedPitch = !(fe->tm.tmPitchAndFamily & TMPF_FIXED_PITCH); if (fe->fontDef.pointSize < 0) { - fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi; + fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi; } else if (fe->fontDef.pixelSize == -1) { - fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.); + fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.); } } #if !defined(QT_NO_DIRECTWRITE) static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request, - const QFontPrivate *fp, IDWriteFont *font) + int dpi, IDWriteFont *font) { fe->fontDef = request; @@ -601,9 +594,9 @@ static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request, qErrnoWarning(hr, "initFontInfo: Failed to get family name"); if (fe->fontDef.pointSize < 0) - fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi; + fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi; else if (fe->fontDef.pixelSize == -1) - fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.); + fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.); } #endif @@ -679,20 +672,21 @@ static inline HFONT systemFont() #define DEFAULT_GUI_FONT 17 #endif -static -QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &request, const QtFontDesc *desc, - const QStringList &family_list) +static QFontEngine *loadEngine(int script, const QFontDef &request, + HDC fontHdc, int dpi, bool rawMode, + const QtFontDesc *desc, + const QStringList &family_list) { LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); - bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fp->hdc; + bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc; HDC hdc = shared_dc(); - QString font_name = desc->family->name; + QString font_name = desc != 0 ? desc->family->name : request.family; if (useDevice) { - hdc = fp->hdc; + hdc = fontHdc; font_name = request.family; } @@ -710,9 +704,9 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ bool useDirectWrite = false; #endif - if (fp->rawMode) { // will choose a stock font + if (rawMode) { // will choose a stock font int f, deffnt = SYSTEM_FONT; - QString fam = desc->family->name.toLower(); + QString fam = desc != 0 ? desc->family->name.toLower() : request.family.toLower(); if (fam == QLatin1String("default")) f = deffnt; else if (fam == QLatin1String("system")) @@ -766,11 +760,11 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; - if (desc->style->key.weight == 50) + if (desc == 0 || desc->style->key.weight == 50) lf.lfWeight = FW_DONTCARE; else lf.lfWeight = (desc->style->key.weight*900)/99; - lf.lfItalic = (desc->style->key.style != QFont::StyleNormal); + lf.lfItalic = (desc != 0 && desc->style->key.style != QFont::StyleNormal); lf.lfCharSet = DEFAULT_CHARSET; int strat = OUT_DEFAULT_PRECIS; @@ -901,9 +895,11 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ &lf, &directWriteFont); if (FAILED(hr)) { +#ifndef QT_NO_DEBUG qErrnoWarning("QFontEngine::loadEngine: CreateFontFromLOGFONT failed " "for %ls (0x%lx)", lf.lfFaceName, hr); +#endif } else { DeleteObject(hfont); useDirectWrite = true; @@ -933,22 +929,27 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ } } - initFontInfo(few, request, fp); + initFontInfo(few, request, fontHdc, dpi); fe = few; } #if !defined(QT_NO_DIRECTWRITE) else { QFontDatabasePrivate *db = privateDb(); - QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(font_name, - db->directWriteFactory, - db->directWriteGdiInterop, - directWriteFont, - request.pixelSize); - initFontInfo(fedw, request, fp, directWriteFont); + IDWriteFontFace *directWriteFontFace = NULL; + HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace); + if (SUCCEEDED(hr)) { + QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(db->directWriteFactory, + directWriteFontFace, + request.pixelSize); + + initFontInfo(fedw, request, dpi, directWriteFont); - fe = fedw; + fe = fedw; + } else { + qErrnoWarning(hr, "QFontEngine::loadEngine: CreateFontFace failed"); + } } if (directWriteFont != 0) @@ -957,6 +958,7 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ if(script == QUnicodeTables::Common && !(request.styleStrategy & QFont::NoFontMerging) + && desc != 0 && !(desc->family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) { if(!tryFonts) { LANGID lid = GetUserDefaultLangID(); @@ -993,6 +995,20 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ return fe; } +QFontEngine *qt_load_font_engine_win(const QFontDef &request) +{ + // From qfont.cpp + extern int qt_defaultDpi(); + + QFontCache::Key key(request, QUnicodeTables::Common); + QFontEngine *fe = QFontCache::instance()->findEngine(key); + if (fe != 0) + return fe; + else + return loadEngine(QUnicodeTables::Common, request, 0, qt_defaultDpi(), false, 0, + QStringList()); +} + const char *styleHint(const QFontDef &request) { const char *stylehint = 0; @@ -1053,7 +1069,7 @@ static QFontEngine *loadWin(const QFontPrivate *d, int script, const QFontDef &r } if (!desc.family) break; - fe = loadEngine(script, d, req, &desc, family_list); + fe = loadEngine(script, req, d->hdc, d->dpi, d->rawMode, &desc, family_list); if (!fe) blacklistedFamilies.append(desc.familyIndex); } diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp index 02b0148..0c0c4c8 100644 --- a/src/gui/text/qfontdatabase_x11.cpp +++ b/src/gui/text/qfontdatabase_x11.cpp @@ -746,6 +746,7 @@ QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &request) QFontDef fontDef; fontDef.styleStrategy = request.styleStrategy; + fontDef.hintingPreference = request.hintingPreference; FcChar8 *value = 0; if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) == FcResultMatch) { fontDef.family = QString::fromUtf8(reinterpret_cast<const char *>(value)); diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 3adf4eb..2f76cc6 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -237,24 +237,6 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix return metrics; } -QFont QFontEngine::createExplicitFont() const -{ - return createExplicitFontWithName(fontDef.family); -} - -QFont QFontEngine::createExplicitFontWithName(const QString &familyName) const -{ - QFont font(familyName); - font.setStyleStrategy(QFont::NoFontMerging); - font.setWeight(fontDef.weight); - font.setItalic(fontDef.style == QFont::StyleItalic); - if (fontDef.pointSize < 0) - font.setPixelSize(fontDef.pixelSize); - else - font.setPointSizeF(fontDef.pointSize); - return font; -} - QFixed QFontEngine::xHeight() const { QGlyphLayoutArray<8> glyphs; diff --git a/src/gui/text/qfontengine_coretext.mm b/src/gui/text/qfontengine_coretext.mm index 4d9192e..d4df218 100644 --- a/src/gui/text/qfontengine_coretext.mm +++ b/src/gui/text/qfontengine_coretext.mm @@ -52,6 +52,31 @@ QT_BEGIN_NAMESPACE static float SYNTHETIC_ITALIC_SKEW = tanf(14 * acosf(0) / 90); +static void loadAdvancesForGlyphs(CTFontRef ctfont, + QVarLengthArray<CGGlyph> &cgGlyphs, + QGlyphLayout *glyphs, int len, + QTextEngine::ShaperFlags flags, + const QFontDef &fontDef) +{ + Q_UNUSED(flags); + QVarLengthArray<CGSize> advances(len); + CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len); + + for (int i = 0; i < len; ++i) { + if (glyphs->glyphs[i] & 0xff000000) + continue; + glyphs->advances_x[i] = QFixed::fromReal(advances[i].width); + glyphs->advances_y[i] = QFixed::fromReal(advances[i].height); + } + + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + for (int i = 0; i < len; ++i) { + glyphs->advances_x[i] = glyphs->advances_x[i].round(); + glyphs->advances_y[i] = glyphs->advances_y[i].round(); + } + } +} + QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning) : QFontEngineMulti(0) { @@ -83,7 +108,31 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const ctfont = baseFont; CFRetain(ctfont); } + init(kerning); +} + +QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(CGFontRef cgFontRef, const QFontDef &fontDef, bool kerning) + : QFontEngineMulti(0) +{ + this->fontDef = fontDef; + + transform = CGAffineTransformIdentity; + if (fontDef.stretch != 100) { + transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); + } + ctfont = CTFontCreateWithGraphicsFont(cgFontRef, fontDef.pixelSize, &transform, NULL); + init(kerning); +} + +QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti() +{ + CFRelease(ctfont); +} + +void QCoreTextFontEngineMulti::init(bool kerning) +{ + Q_ASSERT(ctfont != NULL); attributeDict = CFDictionaryCreateMutable(0, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -94,33 +143,29 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const CFDictionaryAddValue(attributeDict, kCTKernAttributeName, noKern); } - QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef, this); + QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef); fe->ref.ref(); engines.append(fe); - } -QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti() -{ - CFRelease(ctfont); -} - -uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef id) const +uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef font) const { for (int i = 0; i < engines.count(); ++i) { - if (CFEqual(engineAt(i)->ctfont, id)) + if (CFEqual(engineAt(i)->ctfont, font)) return i; } QCoreTextFontEngineMulti *that = const_cast<QCoreTextFontEngineMulti *>(this); - QCoreTextFontEngine *fe = new QCoreTextFontEngine(id, fontDef, that); + QCoreTextFontEngine *fe = new QCoreTextFontEngine(font, fontDef); fe->ref.ref(); that->engines.append(fe); return engines.count() - 1; } -bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags, - unsigned short *logClusters, const HB_CharAttributes *) const +bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, + int *nglyphs, QTextEngine::ShaperFlags flags, + unsigned short *logClusters, const HB_CharAttributes *, + QScriptItem *si) const { QCFType<CFStringRef> cfstring = CFStringCreateWithCharactersNoCopy(0, reinterpret_cast<const UniChar *>(str), @@ -137,6 +182,8 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); typeSetter = CTTypesetterCreateWithAttributedStringAndOptions(attributedString, options); } else +#else + Q_UNUSED(flags); #endif typeSetter = CTTypesetterCreateWithAttributedString(attributedString); @@ -176,6 +223,25 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay Q_ASSERT((CTRunGetStatus(run) & kCTRunStatusRightToLeft) == rtl); CFRange stringRange = CTRunGetStringRange(run); + int prepend = 0; +#if MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5 + UniChar beginGlyph = CFStringGetCharacterAtIndex(cfstring, stringRange.location); + QChar dir = QChar::direction(beginGlyph); + bool beginWithOverride = dir == QChar::DirLRO || dir == QChar::DirRLO || dir == QChar::DirLRE || dir == QChar::DirRLE; + if (beginWithOverride) { + logClusters[stringRange.location] = 0; + outGlyphs[0] = 0xFFFF; + outAdvances_x[0] = 0; + outAdvances_y[0] = 0; + outAttributes[0].clusterStart = true; + outAttributes[0].dontPrint = true; + outGlyphs++; + outAdvances_x++; + outAdvances_y++; + outAttributes++; + prepend = 1; + } +#endif UniChar endGlyph = CFStringGetCharacterAtIndex(cfstring, stringRange.location + stringRange.length - 1); bool endWithPDF = QChar::direction(endGlyph) == QChar::DirPDF; if (endWithPDF) @@ -190,7 +256,12 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay if (!runAttribs) runAttribs = attributeDict; CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(runAttribs, NSFontAttributeName)); - const uint fontIndex = (fontIndexForFont(runFont) << 24); + uint fontIndex = fontIndexForFont(runFont); + const QFontEngine *engine = engineAt(fontIndex); + fontIndex <<= 24; + si->ascent = qMax(engine->ascent(), si->ascent); + si->descent = qMax(engine->descent(), si->descent); + si->leading = qMax(engine->leading(), si->leading); //NSLog(@"Run Font Name = %@", CTFontCopyFamilyName(runFont)); if (endWithPDF) glyphCount--; @@ -228,9 +299,9 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay CFIndex k = 0; CFIndex i = 0; - for (i = stringRange.location; + for (i = stringRange.location + prepend; (i < stringRange.location + stringRange.length) && (k < glyphCount); ++i) { - if (tmpIndices[k * rtlSign + rtlOffset] == i || i == stringRange.location) { + if (tmpIndices[k * rtlSign + rtlOffset] == i || i == stringRange.location + prepend) { logClusters[i] = k + firstGlyphIndex; outAttributes[k].clusterStart = true; ++k; @@ -265,7 +336,7 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay : QFixed::fromReal(lastGlyphAdvance.width); if (endWithPDF) { - logClusters[stringRange.location + stringRange.length - 1] = glyphCount; + logClusters[stringRange.location + stringRange.length - 1] = glyphCount + prepend; outGlyphs[glyphCount] = 0xFFFF; outAdvances_x[glyphCount] = 0; outAdvances_y[glyphCount] = 0; @@ -317,72 +388,45 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay if (flags & QTextEngine::GlyphIndicesOnly) return true; - QVarLengthArray<CGSize> advances(len); - CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len); - - for (int i = 0; i < len; ++i) { - if (glyphs->glyphs[i] & 0xff000000) - continue; - glyphs->advances_x[i] = QFixed::fromReal(advances[i].width); - glyphs->advances_y[i] = QFixed::fromReal(advances[i].height); - } - - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - for (int i = 0; i < len; ++i) { - glyphs->advances_x[i] = glyphs->advances_x[i].round(); - glyphs->advances_y[i] = glyphs->advances_y[i].round(); - } - } - + loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef); return true; } -void QCoreTextFontEngineMulti::recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const -{ -} -void QCoreTextFontEngineMulti::doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const -{ -} - void QCoreTextFontEngineMulti::loadEngine(int) { // Do nothing Q_ASSERT(false); } +extern int qt_antialiasing_threshold; // from qapplication.cpp +static inline CGAffineTransform transformFromFontDef(const QFontDef &fontDef) +{ + CGAffineTransform transform = CGAffineTransformIdentity; + if (fontDef.stretch != 100) + transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); + return transform; +} -QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def, - QCoreTextFontEngineMulti *multiEngine) +QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) { fontDef = def; - parentEngine = multiEngine; - synthesisFlags = 0; + transform = transformFromFontDef(fontDef); ctfont = font; CFRetain(ctfont); - cgFont = CTFontCopyGraphicsFont(ctfont, NULL); - CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont); - if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) { - synthesisFlags |= SynthesizedBold; - } - - if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) { - synthesisFlags |= SynthesizedItalic; - } - transform = CGAffineTransformIdentity; - if (fontDef.stretch != 100) { - transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); - } - QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); - if (os2Table.size() >= 10) - fsType = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 8)); + cgFont = CTFontCopyGraphicsFont(font, NULL); + init(); +} - QSettings appleSettings(QLatin1String("apple.com")); - QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold")); - if (appleValue.isValid()) - antialiasing_threshold = appleValue.toInt(); - else - antialiasing_threshold = -1; +QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def) +{ + fontDef = def; + transform = transformFromFontDef(fontDef); + cgFont = font; + // Keep reference count balanced + CFRetain(cgFont); + ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, NULL); + init(); } QCoreTextFontEngine::~QCoreTextFontEngine() @@ -391,9 +435,89 @@ QCoreTextFontEngine::~QCoreTextFontEngine() CFRelease(ctfont); } -bool QCoreTextFontEngine::stringToCMap(const QChar *, int, QGlyphLayout *, int *, QTextEngine::ShaperFlags) const +extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp + +int getTraitValue(CFDictionaryRef allTraits, CFStringRef trait) +{ + if (CFDictionaryContainsKey(allTraits, trait)) { + CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait); + float v = 0; + CFNumberGetValue(traitNum, kCFNumberFloatType, &v); + // the value we get from CFNumberRef is from -1.0 to 1.0 + int value = v * 500 + 500; + return value; + } + + return 0; +} + +void QCoreTextFontEngine::init() { - return false; + Q_ASSERT(ctfont != NULL); + Q_ASSERT(cgFont != NULL); + + QCFString family = CTFontCopyFamilyName(ctfont); + fontDef.family = family; + + synthesisFlags = 0; + CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont); + if (traits & kCTFontItalicTrait) + fontDef.style = QFont::StyleItalic; + + CFDictionaryRef allTraits = CTFontCopyTraits(ctfont); + fontDef.weight = weightFromInteger(getTraitValue(allTraits, kCTFontWeightTrait)); + int slant = getTraitValue(allTraits, kCTFontSlantTrait); + if (slant > 500 && !(traits & kCTFontItalicTrait)) + fontDef.style = QFont::StyleOblique; + CFRelease(allTraits); + + if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) + synthesisFlags |= SynthesizedBold; + // XXX: we probably don't need to synthesis italic for oblique font + if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) + synthesisFlags |= SynthesizedItalic; + + avgCharWidth = 0; + QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); + unsigned emSize = CTFontGetUnitsPerEm(ctfont); + if (os2Table.size() >= 10) { + fsType = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 8)); + // qAbs is a workaround for weird fonts like Lucida Grande + qint16 width = qAbs(qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 2))); + avgCharWidth = QFixed::fromReal(width * fontDef.pixelSize / emSize); + } else + avgCharWidth = QFontEngine::averageCharWidth(); + + ctMaxCharWidth = ctMinLeftBearing = ctMinRightBearing = 0; + QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a')); + if (hheaTable.size() >= 16) { + quint16 width = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(hheaTable.constData() + 10)); + ctMaxCharWidth = width * fontDef.pixelSize / emSize; + qint16 bearing = qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(hheaTable.constData() + 12)); + ctMinLeftBearing = bearing * fontDef.pixelSize / emSize; + bearing = qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(hheaTable.constData() + 14)); + ctMinRightBearing = bearing * fontDef.pixelSize / emSize; + } +} + +bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, + int *nglyphs, QTextEngine::ShaperFlags flags) const +{ + *nglyphs = len; + QCFType<CFStringRef> cfstring; + + QVarLengthArray<CGGlyph> cgGlyphs(len); + CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len); + + for (int i = 0; i < len; ++i) + if (cgGlyphs[i]) + glyphs->glyphs[i] = cgGlyphs[i]; + + if (flags & QTextEngine::GlyphIndicesOnly) + return true; + + loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef); + return true; } glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs) @@ -407,6 +531,7 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs) } return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0); } + glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) { glyph_metrics_t ret; @@ -460,31 +585,29 @@ QFixed QCoreTextFontEngine::xHeight() const ? QFixed::fromReal(CTFontGetXHeight(ctfont)).round() : QFixed::fromReal(CTFontGetXHeight(ctfont)); } + QFixed QCoreTextFontEngine::averageCharWidth() const { - // ### Need to implement properly and get the information from the OS/2 Table. return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - ? QFontEngine::averageCharWidth().round() - : QFontEngine::averageCharWidth(); + ? avgCharWidth.round() : avgCharWidth; } qreal QCoreTextFontEngine::maxCharWidth() const { - // ### Max Help! - return 0; - + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qRound(ctMaxCharWidth) : ctMaxCharWidth; } + qreal QCoreTextFontEngine::minLeftBearing() const { - // ### Min Help! - return 0; - + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qRound(ctMinLeftBearing) : ctMinLeftBearing; } + qreal QCoreTextFontEngine::minRightBearing() const { - // ### Max Help! (even thought it's right) - return 0; - + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qRound(ctMinRightBearing) : ctMinLeftBearing; } void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight) @@ -602,12 +725,6 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position } } -QFont QCoreTextFontEngine::createExplicitFont() const -{ - QString familyName = QCFString::toQString(CTFontCopyFamilyName(ctfont)); - return createExplicitFontWithName(familyName); -} - QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int /*margin*/, bool aa) { const glyph_metrics_t br = boundingBox(glyph); @@ -624,7 +741,7 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition cgflags); CGContextSetFontSize(ctx, fontDef.pixelSize); CGContextSetShouldAntialias(ctx, aa || - (fontDef.pointSize > antialiasing_threshold + (fontDef.pointSize > qt_antialiasing_threshold && !(fontDef.styleStrategy & QFont::NoAntialias))); CGContextSetShouldSmoothFonts(ctx, aa); CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx); @@ -696,12 +813,19 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo return im; } -void QCoreTextFontEngine::recalcAdvances(int numGlyphs, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const +void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const { - Q_ASSERT(false); - Q_UNUSED(numGlyphs); - Q_UNUSED(glyphs); - Q_UNUSED(flags); + int i, numGlyphs = glyphs->numGlyphs; + QVarLengthArray<CGGlyph> cgGlyphs(numGlyphs); + + for (i = 0; i < numGlyphs; ++i) { + if (glyphs->glyphs[i] & 0xff000000) + cgGlyphs[i] = 0; + else + cgGlyphs[i] = glyphs->glyphs[i]; + } + + loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, numGlyphs, flags, fontDef); } QFontEngine::FaceId QCoreTextFontEngine::faceId() const @@ -711,36 +835,45 @@ QFontEngine::FaceId QCoreTextFontEngine::faceId() const bool QCoreTextFontEngine::canRender(const QChar *string, int len) { - QCFType<CTFontRef> retFont = CTFontCreateForString(ctfont, - QCFType<CFStringRef>(CFStringCreateWithCharactersNoCopy(0, - reinterpret_cast<const UniChar *>(string), - len, kCFAllocatorNull)), - CFRangeMake(0, len)); - return retFont != 0; - return false; -} - - bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const - { - QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0); - if (!table || !length) - return false; - CFIndex tableLength = CFDataGetLength(table); - int availableLength = *length; - *length = tableLength; - if (buffer) { - if (tableLength > availableLength) - return false; - CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); - } - return true; - } + QVarLengthArray<CGGlyph> cgGlyphs(len); + return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len); +} + +bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const +{ + QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0); + if (!table || !length) + return false; + CFIndex tableLength = CFDataGetLength(table); + int availableLength = *length; + *length = tableLength; + if (buffer) { + if (tableLength > availableLength) + return false; + CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); + } + return true; +} void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metrics_t *) { // ### } +QFixed QCoreTextFontEngine::emSquareSize() const +{ + return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); +} + +QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const +{ + QFontDef newFontDef = fontDef; + newFontDef.pixelSize = pixelSize; + newFontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + + return new QCoreTextFontEngine(cgFont, fontDef); +} + QT_END_NAMESPACE #endif// !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) diff --git a/src/gui/text/qfontengine_coretext_p.h b/src/gui/text/qfontengine_coretext_p.h index 7d17aef..bb80a9b 100644 --- a/src/gui/text/qfontengine_coretext_p.h +++ b/src/gui/text/qfontengine_coretext_p.h @@ -46,15 +46,17 @@ #if !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) +class QRawFontPrivate; class QCoreTextFontEngineMulti; class QCoreTextFontEngine : public QFontEngine { public: - QCoreTextFontEngine(CTFontRef font, const QFontDef &def, - QCoreTextFontEngineMulti *multiEngine = 0); + QCoreTextFontEngine(CTFontRef font, const QFontDef &def); + QCoreTextFontEngine(CGFontRef font, const QFontDef &def); ~QCoreTextFontEngine(); + virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; - virtual void recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const; + virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const; virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); virtual glyph_metrics_t boundingBox(glyph_t glyph); @@ -87,44 +89,50 @@ public: virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, int margin, const QTransform &t); virtual qreal minRightBearing() const; virtual qreal minLeftBearing() const; - virtual QFont createExplicitFont() const; + virtual QFixed emSquareSize() const; + + virtual QFontEngine *cloneWithSize(qreal pixelSize) const; private: + friend class QRawFontPrivate; + + void init(); QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int margin, bool colorful); CTFontRef ctfont; CGFontRef cgFont; - QCoreTextFontEngineMulti *parentEngine; int synthesisFlags; CGAffineTransform transform; + QFixed avgCharWidth; + qreal ctMaxCharWidth; + qreal ctMinLeftBearing; + qreal ctMinRightBearing; friend class QCoreTextFontEngineMulti; - int antialiasing_threshold; }; class QCoreTextFontEngineMulti : public QFontEngineMulti { public: QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning); + QCoreTextFontEngineMulti(CGFontRef cgFontRef, const QFontDef &fontDef, bool kerning); ~QCoreTextFontEngineMulti(); virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags, - unsigned short *logClusters, const HB_CharAttributes *charAttributes) const; - - - virtual void recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const; - virtual void doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const; + unsigned short *logClusters, const HB_CharAttributes *charAttributes, + QScriptItem *si) const; virtual const char *name() const { return "CoreText"; } protected: virtual void loadEngine(int at); private: + void init(bool kerning); inline const QCoreTextFontEngine *engineAt(int i) const { return static_cast<const QCoreTextFontEngine *>(engines.at(i)); } - uint fontIndexForFont(CTFontRef id) const; + uint fontIndexForFont(CTFontRef font) const; CTFontRef ctfont; mutable QCFType<CFMutableDictionaryRef> attributeDict; CGAffineTransform transform; diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index f5e9e1c..237cde4 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -174,9 +174,7 @@ int QFreetypeFace::fsType() const HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints) { - int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT; - - if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags)) + if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, flags)) return error; if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) @@ -202,9 +200,10 @@ HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 p * Returns the freetype face or 0 in case of an empty file or any other problems * (like not being able to open the file) */ -QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id) +QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, + const QByteArray &fontData) { - if (face_id.filename.isEmpty()) + if (face_id.filename.isEmpty() && fontData.isEmpty()) return 0; QtFreetypeData *freetypeData = qt_getFreetypeData(); @@ -217,21 +216,25 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id) } else { QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace); FT_Face face; - QFile file(QString::fromUtf8(face_id.filename)); - if (face_id.filename.startsWith(":qmemoryfonts/")) { - // from qfontdatabase.cpp - extern QByteArray qt_fontdata_from_index(int); - QByteArray idx = face_id.filename; - idx.remove(0, 14); // remove ':qmemoryfonts/' - bool ok = false; - newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok)); - if (!ok) - newFreetype->fontData = QByteArray(); - } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) { - if (!file.open(QIODevice::ReadOnly)) { - return 0; + if (!face_id.filename.isEmpty()) { + QFile file(QString::fromUtf8(face_id.filename)); + if (face_id.filename.startsWith(":qmemoryfonts/")) { + // from qfontdatabase.cpp + extern QByteArray qt_fontdata_from_index(int); + QByteArray idx = face_id.filename; + idx.remove(0, 14); // remove ':qmemoryfonts/' + bool ok = false; + newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok)); + if (!ok) + newFreetype->fontData = QByteArray(); + } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) { + if (!file.open(QIODevice::ReadOnly)) { + return 0; + } + newFreetype->fontData = file.readAll(); } - newFreetype->fontData = file.readAll(); + } else { + newFreetype->fontData = fontData; } if (!newFreetype->fontData.isEmpty()) { if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) { @@ -653,8 +656,21 @@ void QFontEngineFT::freeGlyphSets() freeServerGlyphSet(transformedGlyphSets.at(i).id); } -bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format) +bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, + const QByteArray &fontData) +{ + return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData)); +} + +bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, + QFreetypeFace *freetypeFace) { + freetype = freetypeFace; + if (!freetype) { + xsize = 0; + ysize = 0; + return false; + } defaultFormat = format; this->antialias = antialias; @@ -666,12 +682,6 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format) glyphFormat = QFontEngineGlyphCache::Raster_RGBMask; face_id = faceId; - freetype = QFreetypeFace::getFace(face_id); - if (!freetype) { - xsize = 0; - ysize = 0; - return false; - } symbol = freetype->symbol_map != 0; PS_FontInfoRec psrec; @@ -760,12 +770,9 @@ void QFontEngineFT::setDefaultHintStyle(HintStyle style) default_hint_style = style; } -QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const +int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags, + bool &hsubpixel, int &vfactor) const { - Glyph *g = set->getGlyph(glyph); - if (g && g->format == format) - return g; - int load_flags = FT_LOAD_DEFAULT | default_load_flags; int load_target = default_hint_style == HintLight ? FT_LOAD_TARGET_LIGHT @@ -777,111 +784,29 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) { if (default_hint_style == HintFull) load_target = FT_LOAD_TARGET_LCD; + hsubpixel = true; } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) { if (default_hint_style == HintFull) load_target = FT_LOAD_TARGET_LCD_V; + vfactor = 3; } } - if (set->outline_drawing) + if (set && set->outline_drawing) load_flags = FT_LOAD_NO_BITMAP; - if (default_hint_style == HintNone) + if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics)) load_flags |= FT_LOAD_NO_HINTING; else load_flags |= load_target; - // apply our matrix to this, but note that the metrics will not be affected by this. - FT_Face face = lockFace(); - FT_Matrix matrix = this->matrix; - FT_Matrix_Multiply(&set->transformationMatrix, &matrix); - FT_Set_Transform(face, &matrix, 0); - freetype->matrix = matrix; - - bool transform = matrix.xx != 0x10000 || matrix.yy != 0x10000 || matrix.xy != 0 || matrix.yx != 0; - if (transform) - load_flags |= FT_LOAD_NO_BITMAP; - - FT_Error err = FT_Load_Glyph(face, glyph, load_flags); - if (err && (load_flags & FT_LOAD_NO_BITMAP)) { - load_flags &= ~FT_LOAD_NO_BITMAP; - err = FT_Load_Glyph(face, glyph, load_flags); - } - if (err == FT_Err_Too_Few_Arguments) { - // this is an error in the bytecode interpreter, just try to run without it - load_flags |= FT_LOAD_FORCE_AUTOHINT; - err = FT_Load_Glyph(face, glyph, load_flags); - } - if (err != FT_Err_Ok) - qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph); - - unlockFace(); - if (set->outline_drawing) - return 0; - - if (!g) { - g = new Glyph; - g->uploadedToServer = false; - g->data = 0; - } - - FT_GlyphSlot slot = face->glyph; - if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot); - int left = slot->metrics.horiBearingX; - int right = slot->metrics.horiBearingX + slot->metrics.width; - int top = slot->metrics.horiBearingY; - int bottom = slot->metrics.horiBearingY - slot->metrics.height; - if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) { // freetype doesn't apply the transformation on the metrics - int l, r, t, b; - FT_Vector vector; - vector.x = left; - vector.y = top; - FT_Vector_Transform(&vector, &matrix); - l = r = vector.x; - t = b = vector.y; - vector.x = right; - vector.y = top; - FT_Vector_Transform(&vector, &matrix); - if (l > vector.x) l = vector.x; - if (r < vector.x) r = vector.x; - if (t < vector.y) t = vector.y; - if (b > vector.y) b = vector.y; - vector.x = right; - vector.y = bottom; - FT_Vector_Transform(&vector, &matrix); - if (l > vector.x) l = vector.x; - if (r < vector.x) r = vector.x; - if (t < vector.y) t = vector.y; - if (b > vector.y) b = vector.y; - vector.x = left; - vector.y = bottom; - FT_Vector_Transform(&vector, &matrix); - if (l > vector.x) l = vector.x; - if (r < vector.x) r = vector.x; - if (t < vector.y) t = vector.y; - if (b > vector.y) b = vector.y; - left = l; - right = r; - top = t; - bottom = b; - } - left = FLOOR(left); - right = CEIL(right); - bottom = FLOOR(bottom); - top = CEIL(top); - - g->linearAdvance = face->glyph->linearHoriAdvance >> 10; - g->width = TRUNC(right-left); - g->height = TRUNC(top-bottom); - g->x = TRUNC(left); - g->y = TRUNC(top); - g->advance = TRUNC(ROUND(face->glyph->advance.x)); - g->format = Format_None; - - return g; + return load_flags; } -QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, GlyphFormat format, bool fetchMetricsOnly) const +QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, + QFixed subPixelPosition, + GlyphFormat format, + bool fetchMetricsOnly) const { // Q_ASSERT(freetype->lock == 1); @@ -896,10 +821,10 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph } } - Glyph *g = set->getGlyph(glyph); + Glyph *g = set->getGlyph(glyph, subPixelPosition); if (g && g->format == format) { if (uploadToServer && !g->uploadedToServer) { - set->setGlyph(glyph, 0); + set->setGlyph(glyph, subPixelPosition, 0); delete g; g = 0; } else { @@ -912,33 +837,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph Q_ASSERT(format != Format_None); bool hsubpixel = false; int vfactor = 1; - int load_flags = FT_LOAD_DEFAULT | default_load_flags; - - int load_target = default_hint_style == HintLight - ? FT_LOAD_TARGET_LIGHT - : FT_LOAD_TARGET_NORMAL; - - if (set->outline_drawing) - load_flags |= FT_LOAD_NO_BITMAP; - - if (format == Format_Mono) { - load_target = FT_LOAD_TARGET_MONO; - } else if (format == Format_A32) { - if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) { - if (default_hint_style == HintFull) - load_target = FT_LOAD_TARGET_LCD; - hsubpixel = true; - } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) { - if (default_hint_style == HintFull) - load_target = FT_LOAD_TARGET_LCD_V; - vfactor = 3; - } - } - - if (default_hint_style == HintNone) - load_flags |= FT_LOAD_NO_HINTING; - else - load_flags |= load_target; + int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor); #ifndef Q_WS_QWS if (format != Format_Mono && !embeddedbitmap) @@ -955,6 +854,12 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph load_flags |= FT_LOAD_NO_BITMAP; FT_Face face = freetype->face; + + FT_Vector v; + v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64); + v.y = 0; + FT_Set_Transform(face, &freetype->matrix, &v); + FT_Error err = FT_Load_Glyph(face, glyph, load_flags); if (err && (load_flags & FT_LOAD_NO_BITMAP)) { load_flags &= ~FT_LOAD_NO_BITMAP; @@ -1055,6 +960,10 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph top = CEIL(top); int hpixels = TRUNC(right - left); + // subpixel position requires one more pixel + if (subPixelPosition > 0 && format != Format_Mono) + hpixels++; + if (hsubpixel) hpixels = hpixels*3 + 8; info.width = hpixels; @@ -1197,7 +1106,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, Glyph uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size); } - set->setGlyph(glyph, g); + set->setGlyph(glyph, subPixelPosition, g); return g; } @@ -1430,12 +1339,30 @@ QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransfor return gs; } -bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, GlyphFormat format) +QFixed QFontEngineFT::subPixelPositionForX(QFixed x) +{ + int m_subPixelPositionCount = 4; + if (!supportsSubPixelPositions()) + return 0; + + QFixed subPixelPosition; + if (x != 0) { + subPixelPosition = x - x.floor(); + QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor(); + subPixelPosition = fraction / QFixed(m_subPixelPositionCount); + } + return subPixelPosition; +} + +bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs, + const QFixedPoint *positions, + GlyphFormat format) { FT_Face face = 0; for (int i = 0; i < num_glyphs; ++i) { - Glyph *glyph = gs->getGlyph(glyphs[i]); + QFixed spp = subPixelPositionForX(positions[i].x); + Glyph *glyph = gs->getGlyph(glyphs[i], spp); if (glyph == 0 || glyph->format != format) { if (!face) { face = lockFace(); @@ -1444,7 +1371,7 @@ bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, G FT_Set_Transform(face, &m, 0); freetype->matrix = m; } - if (!loadGlyph(gs, glyphs[i], format)) { + if (!loadGlyph(gs, glyphs[i], spp, format)) { unlockFace(); return false; } @@ -1596,7 +1523,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs mtx->lock(); } - if (FcCharSetHasChar(freetype->charset, uc)) { + if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) { #else if (false) { #endif @@ -1631,7 +1558,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs mtx->lock(); } - if (FcCharSetHasChar(freetype->charset, uc)) + if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc)) #endif { redo: @@ -1668,32 +1595,23 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const { FT_Face face = 0; - if (flags & QTextEngine::DesignMetrics) { - for (int i = 0; i < glyphs->numGlyphs; i++) { - Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]); - if (g) { - glyphs->advances_x[i] = QFixed::fromFixed(g->linearAdvance); - } else { - if (!face) - face = lockFace(); - g = loadGlyph(glyphs->glyphs[i], Format_None, true); - glyphs->advances_x[i] = QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10); - } - glyphs->advances_y[i] = 0; - } - } else { - for (int i = 0; i < glyphs->numGlyphs; i++) { - Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]); - if (g) { - glyphs->advances_x[i] = QFixed(g->advance); - } else { - if (!face) - face = lockFace(); - g = loadGlyph(glyphs->glyphs[i], Format_None, true); - glyphs->advances_x[i] = QFixed::fromFixed(face->glyph->metrics.horiAdvance).round(); - } - glyphs->advances_y[i] = 0; + bool design = (default_hint_style == HintNone || + default_hint_style == HintLight || + (flags & HB_ShaperFlag_UseDesignMetrics)); + for (int i = 0; i < glyphs->numGlyphs; i++) { + Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]); + if (g) { + glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance); + } else { + if (!face) + face = lockFace(); + g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true); + glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10) + : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round(); } + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + glyphs->advances_x[i] = glyphs->advances_x[i].round(); + glyphs->advances_y[i] = 0; } if (face) unlockFace(); @@ -1716,7 +1634,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs) if (!g) { if (!face) face = lockFace(); - g = loadGlyph(glyphs.glyphs[i], Format_None, true); + g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true); } if (g) { QFixed x = overall.xoff + glyphs.offsets[i].x + g->x; @@ -1757,7 +1675,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph) Glyph *g = defaultGlyphSet.getGlyph(glyph); if (!g) { face = lockFace(); - g = loadGlyph(glyph, Format_None, true); + g = loadGlyph(glyph, 0, Format_None, true); } if (g) { overall.x = g->x; @@ -1765,6 +1683,8 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph) overall.width = g->width; overall.height = g->height; overall.xoff = g->advance; + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + overall.xoff = overall.xoff.round(); } else { int left = FLOOR(face->glyph->metrics.horiBearingX); int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width); @@ -1784,10 +1704,10 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph) glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix) { - return alphaMapBoundingBox(glyph, matrix, QFontEngine::Format_None); + return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None); } -glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, const QTransform &matrix, QFontEngine::GlyphFormat format) +glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format) { FT_Face face = 0; glyph_metrics_t overall; @@ -1834,7 +1754,10 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, const QTransfo Glyph * g = glyphSet->getGlyph(glyph); if (!g || g->format != format) { face = lockFace(); - g = loadGlyphMetrics(glyphSet, glyph, format); + FT_Matrix m = this->matrix; + FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m); + freetype->matrix = m; + g = loadGlyph(glyphSet, glyph, subPixelPosition, format); } if (g) { @@ -1860,13 +1783,13 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, const QTransfo return overall; } -QImage QFontEngineFT::alphaMapForGlyph(glyph_t g) +QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition) { lockFace(); GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono; - Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, glyph_format); + Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format); if (!glyph) { unlockFace(); return QFontEngine::alphaMapForGlyph(g); @@ -1905,7 +1828,7 @@ QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, in GlyphFormat glyph_format = Format_A32; - Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, glyph_format); + Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format); if (!glyph) { unlockFace(); return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t); @@ -1920,7 +1843,7 @@ QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, in void QFontEngineFT::removeGlyphFromCache(glyph_t glyph) { - defaultGlyphSet.removeGlyphFromCache(glyph); + defaultGlyphSet.removeGlyphFromCache(glyph, 0); } int QFontEngineFT::glyphCount() const @@ -2000,9 +1923,9 @@ void QFontEngineFT::QGlyphSet::clear() glyph_data.clear(); } -void QFontEngineFT::QGlyphSet::removeGlyphFromCache(int index) +void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition) { - if (index < 256) { + if (useFastGlyphData(index, subPixelPosition)) { if (fast_glyph_data[index]) { delete fast_glyph_data[index]; fast_glyph_data[index] = 0; @@ -2010,18 +1933,18 @@ void QFontEngineFT::QGlyphSet::removeGlyphFromCache(int index) --fast_glyph_count; } } else { - delete glyph_data.take(index); + delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition)); } } -void QFontEngineFT::QGlyphSet::setGlyph(int index, Glyph *glyph) +void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph) { - if (index < 256) { + if (useFastGlyphData(index, subPixelPosition)) { if (!fast_glyph_data[index]) ++fast_glyph_count; fast_glyph_data[index] = glyph; } else { - glyph_data.insert(index, glyph); + glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph); } } @@ -2038,11 +1961,49 @@ void QFontEngineFT::freeServerGlyphSet(unsigned long id) HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints) { lockFace(); - HB_Error result = freetype->getPointInOutline(glyph, flags, point, xpos, ypos, nPoints); + bool hsubpixel = true; + int vfactor = 1; + int load_flags = loadFlags(0, Format_A8, flags, hsubpixel, vfactor); + HB_Error result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints); unlockFace(); return result; } +bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe) +{ + if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype)) + return false; + + // Increase the reference of this QFreetypeFace since one more QFontEngineFT + // will be using it + freetype->ref.ref(); + + default_load_flags = fe->default_load_flags; + default_hint_style = fe->default_hint_style; + antialias = fe->antialias; + transform = fe->transform; + embolden = fe->embolden; + subpixelType = fe->subpixelType; + lcdFilterType = fe->lcdFilterType; + canUploadGlyphsToServer = fe->canUploadGlyphsToServer; + embeddedbitmap = fe->embeddedbitmap; + + return true; +} + +QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const +{ + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + QFontEngineFT *fe = new QFontEngineFT(fontDef); + if (!fe->initFromFontEngine(this)) { + delete fe; + return 0; + } else { + return fe; + } +} + QT_END_NAMESPACE #endif // QT_NO_FREETYPE diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index abdbd20..a620006 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -74,6 +74,8 @@ QT_BEGIN_NAMESPACE +class QFontEngineFTRawFont; + /* * This struct represents one font file on disk (like Arial.ttf) and is shared between all the font engines * that show this font file (at different pixel sizes). @@ -84,7 +86,8 @@ struct QFreetypeFace QFontEngine::Properties properties() const; bool getSfntTable(uint tag, uchar *buffer, uint *length) const; - static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id); + static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id, + const QByteArray &fontData = QByteArray()); void release(const QFontEngine::FaceId &face_id); // locks the struct for usage. Any read/write operations require locking. @@ -119,6 +122,7 @@ struct QFreetypeFace static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool = false); private: + friend class QFontEngineFT; friend class QScopedPointerDeleter<QFreetypeFace>; QFreetypeFace() : _lock(QMutex::Recursive) {} ~QFreetypeFace() {} @@ -166,6 +170,19 @@ public: }; #endif + struct GlyphAndSubPixelPosition + { + GlyphAndSubPixelPosition(glyph_t g, QFixed spp) : glyph(g), subPixelPosition(spp) {} + + bool operator==(const GlyphAndSubPixelPosition &other) const + { + return glyph == other.glyph && subPixelPosition == other.subPixelPosition; + } + + glyph_t glyph; + QFixed subPixelPosition; + }; + struct QGlyphSet { QGlyphSet(); @@ -174,18 +191,21 @@ public: unsigned long id; // server sided id, GlyphSet for X11 bool outline_drawing; - void removeGlyphFromCache(int index); + void removeGlyphFromCache(glyph_t index, QFixed subPixelPosition); void clear(); - inline Glyph *getGlyph(int index) const + inline bool useFastGlyphData(glyph_t index, QFixed subPixelPosition) const { + return (index < 256 && subPixelPosition == 0); + } + inline Glyph *getGlyph(glyph_t index, QFixed subPixelPosition = 0) const { - if (index < 256) + if (useFastGlyphData(index, subPixelPosition)) return fast_glyph_data[index]; - return glyph_data.value(index); + return glyph_data.value(GlyphAndSubPixelPosition(index, subPixelPosition)); } - void setGlyph(int index, Glyph *glyph); + void setGlyph(glyph_t index, QFixed spp, Glyph *glyph); private: - mutable QHash<int, Glyph *> glyph_data; // maps from glyph index to glyph data + mutable QHash<GlyphAndSubPixelPosition, Glyph *> glyph_data; // maps from glyph index to glyph data mutable Glyph *fast_glyph_data[256]; // for fast lookup of glyphs < 256 mutable int fast_glyph_count; }; @@ -193,6 +213,11 @@ private: virtual QFontEngine::FaceId faceId() const; virtual QFontEngine::Properties properties() const; virtual QFixed emSquareSize() const; + virtual bool supportsSubPixelPositions() const + { + return default_hint_style == HintLight || + default_hint_style == HintNone; + } virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; virtual int synthesized() const; @@ -233,9 +258,12 @@ private: virtual glyph_metrics_t boundingBox(glyph_t glyph, const QTransform &matrix); virtual void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const; - virtual QImage alphaMapForGlyph(glyph_t); + virtual QImage alphaMapForGlyph(glyph_t g) { return alphaMapForGlyph(g, 0); } + virtual QImage alphaMapForGlyph(glyph_t, QFixed); virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, int margin, const QTransform &t); - virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QTransform &matrix, + virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, + QFixed subPixelPosition, + const QTransform &matrix, QFontEngine::GlyphFormat format); virtual void removeGlyphFromCache(glyph_t glyph); @@ -254,17 +282,20 @@ private: inline bool invalid() const { return xsize == 0 && ysize == 0; } inline bool isBitmapFont() const { return defaultFormat == Format_Mono; } - inline Glyph *loadGlyph(uint glyph, GlyphFormat format = Format_None, bool fetchMetricsOnly = false) const - { return loadGlyph(&defaultGlyphSet, glyph, format, fetchMetricsOnly); } - Glyph *loadGlyph(QGlyphSet *set, uint glyph, GlyphFormat = Format_None, bool fetchMetricsOnly = false) const; + inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false) const + { return loadGlyph(&defaultGlyphSet, glyph, subPixelPosition, format, fetchMetricsOnly); } + Glyph *loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat = Format_None, bool fetchMetricsOnly = false) const; QGlyphSet *defaultGlyphs() { return &defaultGlyphSet; } GlyphFormat defaultGlyphFormat() const { return defaultFormat; } - inline Glyph *cachedGlyph(glyph_t g) const { return defaultGlyphSet.getGlyph(g); } + inline Glyph *cachedGlyph(glyph_t g) const { return defaultGlyphSet.getGlyph(g, 0); } QGlyphSet *loadTransformedGlyphSet(const QTransform &matrix); - bool loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, GlyphFormat format = Format_Render); + QFixed subPixelPositionForX(QFixed x); + bool loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs, + const QFixedPoint *positions, + GlyphFormat format = Format_Render); #if defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) virtual void draw(QPaintEngine * /*p*/, qreal /*x*/, qreal /*y*/, const QTextItemInt & /*si*/) {} @@ -273,7 +304,10 @@ private: QFontEngineFT(const QFontDef &fd); virtual ~QFontEngineFT(); - bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None); + bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None, + const QByteArray &fontData = QByteArray()); + bool init(FaceId faceId, bool antialias, GlyphFormat format, + QFreetypeFace *freetypeFace); virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints); @@ -285,6 +319,11 @@ private: }; void setDefaultHintStyle(HintStyle style); + + virtual QFontEngine *cloneWithSize(qreal pixelSize) const; + bool initFromFontEngine(const QFontEngineFT *fontEngine); + + HintStyle defaultHintStyle() const { return default_hint_style; } protected: void freeGlyphSets(); @@ -308,7 +347,9 @@ protected: bool embeddedbitmap; private: - QFontEngineFT::Glyph *loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const; + friend class QFontEngineFTRawFont; + + int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const; GlyphFormat defaultFormat; FT_Matrix matrix; @@ -330,6 +371,11 @@ private: mutable bool kerning_pairs_loaded; }; +inline uint qHash(const QFontEngineFT::GlyphAndSubPixelPosition &g) +{ + return (g.glyph << 8) | (g.subPixelPosition * 10).round().toInt(); +} + QT_END_NAMESPACE #endif // QT_NO_FREETYPE diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index 7751bbe..9f094ad 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -377,7 +377,7 @@ bool QFontEngineMacMulti::stringToCMap(const QChar *str, int len, QGlyphLayout * } bool QFontEngineMacMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags, - unsigned short *logClusters, const HB_CharAttributes *charAttributes) const + unsigned short *logClusters, const HB_CharAttributes *charAttributes, QScriptItem *) const { if (*nglyphs < len) { *nglyphs = len; @@ -922,27 +922,6 @@ static void addGlyphsToPathHelper(ATSUStyle style, glyph_t *glyphs, QFixedPoint DisposeATSCubicClosePathUPP(closePath); } -QFont QFontEngineMac::createExplicitFont() const -{ - FMFont fmFont = FMGetFontFromATSFontRef(fontID); - - FMFontFamily fmFamily; - FMFontStyle fmStyle; - QString familyName; - if (!FMGetFontFamilyInstanceFromFont(fmFont, &fmFamily, &fmStyle)) { - ATSFontFamilyRef familyRef = FMGetATSFontFamilyRefFromFontFamily(fmFamily); - QCFString cfFamilyName;; - ATSFontFamilyGetName(familyRef, kATSOptionFlagsDefault, &cfFamilyName); - familyName = cfFamilyName; - } else { - QCFString cfFontName; - ATSFontGetName(fontID, kATSOptionFlagsDefault, &cfFontName); - familyName = cfFontName; - } - - return createExplicitFontWithName(familyName); -} - void QFontEngineMac::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags) { diff --git a/src/gui/text/qfontengine_mac_p.h b/src/gui/text/qfontengine_mac_p.h index 6967348..292ea98 100644 --- a/src/gui/text/qfontengine_mac_p.h +++ b/src/gui/text/qfontengine_mac_p.h @@ -66,8 +66,6 @@ public: virtual qreal maxCharWidth() const; virtual QFixed averageCharWidth() const; - virtual QFont createExplicitFont() const; - virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags); @@ -133,7 +131,7 @@ public: virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags, - unsigned short *logClusters, const HB_CharAttributes *charAttributes) const; + unsigned short *logClusters, const HB_CharAttributes *charAttributes, QScriptItem *) const; virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const; virtual void doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const; diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index f501141..6db0aa6 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -185,9 +185,6 @@ public: virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags); - /* Creates a QFont object to represent this particular QFontEngine */ - virtual QFont createExplicitFont() const; - void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray<glyph_t> &glyphs_out, QVarLengthArray<QFixedPoint> &positions); @@ -203,7 +200,7 @@ public: virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t); virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, int margin, const QTransform &t); - virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QTransform &matrix, GlyphFormat /*format*/) + virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &matrix, GlyphFormat /*format*/) { return boundingBox(glyph, matrix); } @@ -238,6 +235,8 @@ public: virtual int glyphCount() const; + virtual QFontEngine *cloneWithSize(qreal /*pixelSize*/) const { return 0; } + HB_Font harfbuzzFont() const; HB_Face harfbuzzFace() const; @@ -276,7 +275,6 @@ public: int glyphFormat; protected: - QFont createExplicitFontWithName(const QString &familyName) const; static const QVector<QRgb> &grayPalette(); QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round = false); @@ -431,6 +429,7 @@ public: protected: friend class QPSPrintEnginePrivate; friend class QPSPrintEngineFontMulti; + friend class QRawFont; virtual void loadEngine(int at) = 0; QVector<QFontEngine *> engines; }; diff --git a/src/gui/text/qfontengine_qpf.cpp b/src/gui/text/qfontengine_qpf.cpp index 2fd4716..d35bbe5 100644 --- a/src/gui/text/qfontengine_qpf.cpp +++ b/src/gui/text/qfontengine_qpf.cpp @@ -306,6 +306,8 @@ QFontEngineQPF::QFontEngineQPF(const QFontDef &def, int fileDescriptor, QFontEng glyphMapEntries = 0; glyphDataOffset = 0; glyphDataSize = 0; + if (renderingFontEngine) + glyphFormat = renderingFontEngine->glyphFormat; kerning_pairs_loaded = false; readOnly = true; diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp index 82d9da0..54d7ec2 100644 --- a/src/gui/text/qfontengine_win.cpp +++ b/src/gui/text/qfontengine_win.cpp @@ -1284,6 +1284,23 @@ QImage QFontEngineWin::alphaRGBMapForGlyph(glyph_t glyph, QFixed, int margin, co return rgbMask; } +// From qfontdatabase_win.cpp +extern QFontEngine *qt_load_font_engine_win(const QFontDef &request); +QFontEngine *QFontEngineWin::cloneWithSize(qreal pixelSize) const +{ + QFontDef request = fontDef; + QString actualFontName = request.family; + if (!uniqueFamilyName.isEmpty()) + request.family = uniqueFamilyName; + request.pixelSize = pixelSize; + + QFontEngine *fontEngine = qt_load_font_engine_win(request); + if (fontEngine != NULL) + fontEngine->fontDef.family = actualFontName; + + return fontEngine; +} + // -------------------------------------- Multi font engine QFontEngineMultiWin::QFontEngineMultiWin(QFontEngine *first, const QStringList &fallbacks) diff --git a/src/gui/text/qfontengine_win_p.h b/src/gui/text/qfontengine_win_p.h index 28d8000..114149d 100644 --- a/src/gui/text/qfontengine_win_p.h +++ b/src/gui/text/qfontengine_win_p.h @@ -106,6 +106,8 @@ public: virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform); virtual QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); + virtual QFontEngine *cloneWithSize(qreal pixelSize) const; + #ifndef Q_CC_MINGW virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0); #endif @@ -118,6 +120,7 @@ public: #endif QString _name; + QString uniqueFamilyName; HFONT hfont; LOGFONT logfont; uint stockFont : 1; diff --git a/src/gui/text/qfontengine_x11.cpp b/src/gui/text/qfontengine_x11.cpp index d5ec584..4260b85 100644 --- a/src/gui/text/qfontengine_x11.cpp +++ b/src/gui/text/qfontengine_x11.cpp @@ -1012,10 +1012,29 @@ QFontEngineX11FT::QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int s } } + if (fd.hintingPreference != QFont::PreferDefaultHinting) { + switch (fd.hintingPreference) { + case QFont::PreferNoHinting: + default_hint_style = HintNone; + break; + case QFont::PreferVerticalHinting: + default_hint_style = HintLight; + break; + case QFont::PreferFullHinting: + default: + default_hint_style = HintFull; + break; + } + } #ifdef FC_HINT_STYLE - { + else { int hint_style = 0; - if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch) + // Try to use Xft.hintstyle from XDefaults first if running in GNOME, to match + // the behavior of cairo + if (X11->fc_hint_style > -1 && X11->desktopEnvironment == DE_GNOME) + hint_style = X11->fc_hint_style; + else if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch + && X11->fc_hint_style > -1) hint_style = X11->fc_hint_style; switch (hint_style) { @@ -1177,6 +1196,20 @@ bool QFontEngineX11FT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph * #endif } +QFontEngine *QFontEngineX11FT::cloneWithSize(qreal pixelSize) const +{ + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + QFontEngineX11FT *fe = new QFontEngineX11FT(fontDef); + if (!fe->initFromFontEngine(this)) { + delete fe; + return 0; + } else { + fe->xglyph_format = xglyph_format; + return fe; + } +} + #endif // QT_NO_FONTCONFIG QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine_x11_p.h b/src/gui/text/qfontengine_x11_p.h index 2a4a9cd..d7eb39d 100644 --- a/src/gui/text/qfontengine_x11_p.h +++ b/src/gui/text/qfontengine_x11_p.h @@ -157,9 +157,12 @@ private: class Q_GUI_EXPORT QFontEngineX11FT : public QFontEngineFT { public: + explicit QFontEngineX11FT(const QFontDef &fontDef) : QFontEngineFT(fontDef) {} explicit QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen); ~QFontEngineX11FT(); + QFontEngine *cloneWithSize(qreal pixelSize) const; + #ifndef QT_NO_XRENDER int xglyph_format; #endif diff --git a/src/gui/text/qfontenginedirectwrite.cpp b/src/gui/text/qfontenginedirectwrite.cpp index af5bab2..aab00c0 100644 --- a/src/gui/text/qfontenginedirectwrite.cpp +++ b/src/gui/text/qfontenginedirectwrite.cpp @@ -170,17 +170,12 @@ namespace { } -QFontEngineDirectWrite::QFontEngineDirectWrite(const QString &name, - IDWriteFactory *directWriteFactory, - IDWriteGdiInterop *directWriteGdiInterop, - IDWriteFont *directWriteFont, +QFontEngineDirectWrite::QFontEngineDirectWrite(IDWriteFactory *directWriteFactory, + IDWriteFontFace *directWriteFontFace, qreal pixelSize) - : m_name(name) - , m_directWriteFont(directWriteFont) - , m_directWriteFontFace(0) + : m_directWriteFontFace(directWriteFontFace) , m_directWriteFactory(directWriteFactory) , m_directWriteBitmapRenderTarget(0) - , m_directWriteGdiInterop(directWriteGdiInterop) , m_lineThickness(-1) , m_unitsPerEm(-1) , m_ascent(-1) @@ -188,24 +183,17 @@ QFontEngineDirectWrite::QFontEngineDirectWrite(const QString &name, , m_xHeight(-1) , m_lineGap(-1) { - m_directWriteFont->AddRef(); m_directWriteFactory->AddRef(); - m_directWriteGdiInterop->AddRef(); + m_directWriteFontFace->AddRef(); fontDef.pixelSize = pixelSize; - - HRESULT hr = m_directWriteFont->CreateFontFace(&m_directWriteFontFace); - if (FAILED(hr)) - qErrnoWarning("QFontEngineDirectWrite: CreateFontFace failed"); - collectMetrics(); } QFontEngineDirectWrite::~QFontEngineDirectWrite() { - m_directWriteFont->Release(); m_directWriteFactory->Release(); - m_directWriteGdiInterop->Release(); + m_directWriteFontFace->Release(); if (m_directWriteBitmapRenderTarget != 0) m_directWriteBitmapRenderTarget->Release(); @@ -213,10 +201,10 @@ QFontEngineDirectWrite::~QFontEngineDirectWrite() void QFontEngineDirectWrite::collectMetrics() { - if (m_directWriteFont != 0) { + if (m_directWriteFontFace != 0) { DWRITE_FONT_METRICS metrics; - m_directWriteFont->GetMetrics(&metrics); + m_directWriteFontFace->GetMetrics(&metrics); m_unitsPerEm = metrics.designUnitsPerEm; m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); @@ -616,19 +604,25 @@ const char *QFontEngineDirectWrite::name() const bool QFontEngineDirectWrite::canRender(const QChar *string, int len) { - for (int i=0; i<len; ++i) { - BOOL exists; - UINT32 codePoint = getChar(string, i, len); - HRESULT hr = m_directWriteFont->HasCharacter(codePoint, &exists); - if (FAILED(hr)) { - qErrnoWarning("QFontEngineDirectWrite::canRender: HasCharacter failed"); - return false; - } else if (!exists) { - return false; + QVarLengthArray<UINT32> codePoints(len); + int actualLength = 0; + for (int i=0; i<len; ++i, actualLength++) + codePoints[actualLength] = getChar(string, i, len); + + QVarLengthArray<UINT16> glyphIndices(actualLength); + HRESULT hr = m_directWriteFontFace->GetGlyphIndices(codePoints.data(), actualLength, + glyphIndices.data()); + if (FAILED(hr)) { + qErrnoWarning(hr, "QFontEngineDirectWrite::canRender: GetGlyphIndices failed"); + return false; + } else { + for (int i=0; i<glyphIndices.size(); ++i) { + if (glyphIndices.at(i) == 0) + return false; } - } - return true; + return true; + } } QFontEngine::Type QFontEngineDirectWrite::type() const @@ -636,6 +630,17 @@ QFontEngine::Type QFontEngineDirectWrite::type() const return QFontEngine::DirectWrite; } +QFontEngine *QFontEngineDirectWrite::cloneWithSize(qreal pixelSize) const +{ + QFontEngine *fontEngine = new QFontEngineDirectWrite(m_directWriteFactory, m_directWriteFontFace, + pixelSize); + + fontEngine->fontDef = fontDef; + fontEngine->fontDef.pixelSize = pixelSize; + + return fontEngine; +} + QT_END_NAMESPACE #endif // QT_NO_DIRECTWRITE diff --git a/src/gui/text/qfontenginedirectwrite_p.h b/src/gui/text/qfontenginedirectwrite_p.h index 80f90b8..53a4b0a 100644 --- a/src/gui/text/qfontenginedirectwrite_p.h +++ b/src/gui/text/qfontenginedirectwrite_p.h @@ -69,10 +69,8 @@ class QFontEngineDirectWrite : public QFontEngine { Q_OBJECT public: - explicit QFontEngineDirectWrite(const QString &name, - IDWriteFactory *directWriteFactory, - IDWriteGdiInterop *directWriteGdiInterop, - IDWriteFont *directWriteFont, + explicit QFontEngineDirectWrite(IDWriteFactory *directWriteFactory, + IDWriteFontFace *directWriteFontFace, qreal pixelSize); ~QFontEngineDirectWrite(); @@ -103,19 +101,20 @@ public: QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); + QFontEngine *cloneWithSize(qreal pixelSize) const; + bool canRender(const QChar *string, int len); Type type() const; private: + friend class QRawFontPrivate; + QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); void collectMetrics(); - QString m_name; - IDWriteFont *m_directWriteFont; IDWriteFontFace *m_directWriteFontFace; IDWriteFactory *m_directWriteFactory; IDWriteBitmapRenderTarget *m_directWriteBitmapRenderTarget; - IDWriteGdiInterop *m_directWriteGdiInterop; QFixed m_lineThickness; int m_unitsPerEm; diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 5cd85fb..2ec245e 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -63,7 +63,6 @@ extern void qt_format_text(const QFont& font, const QRectF &_r, int tf, const QString &text, QRectF *brect, int tabStops, int *tabArray, int tabArrayLen, QPainter *painter); -Q_GUI_EXPORT extern int qt_defaultDpi(); /***************************************************************************** QFontMetrics member functions diff --git a/src/gui/text/qfragmentmap_p.h b/src/gui/text/qfragmentmap_p.h index 501bfff..4057142 100644 --- a/src/gui/text/qfragmentmap_p.h +++ b/src/gui/text/qfragmentmap_p.h @@ -195,6 +195,10 @@ public: head->root = new_root; } + inline bool isValid(uint n) const { + return n > 0 && n != head->freelist; + } + union { Header *head; Fragment *fragments; @@ -854,6 +858,7 @@ public: return data.fragment(index); } inline uint position(uint node, uint field = 0) const { return data.position(node, field); } + inline bool isValid(uint n) const { return data.isValid(n); } inline uint next(uint n) const { return data.next(n); } inline uint previous(uint n) const { return data.previous(n); } inline uint size(uint node, uint field = 0) const { return data.size(node, field); } diff --git a/src/gui/text/qglyphs.cpp b/src/gui/text/qglyphs.cpp index affa08a..cfea6ec 100644 --- a/src/gui/text/qglyphs.cpp +++ b/src/gui/text/qglyphs.cpp @@ -39,6 +39,10 @@ ** ****************************************************************************/ +#include "qglobal.h" + +#if !defined(QT_NO_RAWFONT) + #include "qglyphs.h" #include "qglyphs_p.h" @@ -46,7 +50,7 @@ QT_BEGIN_NAMESPACE /*! \class QGlyphs - \brief the QGlyphs class provides direct access to the internal glyphs in a font + \brief The QGlyphs class provides direct access to the internal glyphs in a font. \since 4.8 \ingroup text @@ -69,8 +73,14 @@ QT_BEGIN_NAMESPACE It is the user's responsibility to ensure that the selected font actually contains the provided glyph indexes. - QTextLayout::glyphs() can be used to convert unicode encoded text into a list of QGlyphs - objects, and QPainter::drawGlyphs() can be used to draw the glyphs. + QTextLayout::glyphs() or QTextFragment::glyphs() can be used to convert unicode encoded text + into a list of QGlyphs objects, and QPainter::drawGlyphs() can be used to draw the glyphs. + + \note Please note that QRawFont is considered local to the thread in which it is constructed. + This in turn means that a new QRawFont will have to be created and set on the QGlyphs if it is + moved to a different thread. If the QGlyphs contains a reference to a QRawFont from a different + thread than the current, it will not be possible to draw the glyphs using a QPainter, as the + QRawFont is considered invalid and inaccessible in this case. */ @@ -124,6 +134,9 @@ bool QGlyphs::operator==(const QGlyphs &other) const return ((d == other.d) || (d->glyphIndexes == other.d->glyphIndexes && d->glyphPositions == other.d->glyphPositions + && d->overline == other.d->overline + && d->underline == other.d->underline + && d->strikeOut == other.d->strikeOut && d->font == other.d->font)); } @@ -171,18 +184,17 @@ QGlyphs &QGlyphs::operator+=(const QGlyphs &other) \sa setFont() */ -QFont QGlyphs::font() const +QRawFont QGlyphs::font() const { return d->font; } /*! - Sets the font in which to look up the glyph indexes to \a font. This must be an explicitly - resolvable font which defines glyphs for the specified glyph indexes. + Sets the font in which to look up the glyph indexes to \a font. \sa font(), setGlyphIndexes() */ -void QGlyphs::setFont(const QFont &font) +void QGlyphs::setFont(const QRawFont &font) { detach(); d->font = font; @@ -234,7 +246,78 @@ void QGlyphs::clear() detach(); d->glyphPositions = QVector<QPointF>(); d->glyphIndexes = QVector<quint32>(); - d->font = QFont(); + d->font = QRawFont(); + d->strikeOut = false; + d->overline = false; + d->underline = false; +} + +/*! + Returns true if this QGlyphs should be painted with an overline decoration. + + \sa setOverline() +*/ +bool QGlyphs::overline() const +{ + return d->overline; +} + +/*! + Indicates that this QGlyphs should be painted with an overline decoration if \a overline is true. + Otherwise the QGlyphs should be painted with no overline decoration. + + \sa overline() +*/ +void QGlyphs::setOverline(bool overline) +{ + detach(); + d->overline = overline; +} + +/*! + Returns true if this QGlyphs should be painted with an underline decoration. + + \sa setUnderline() +*/ +bool QGlyphs::underline() const +{ + return d->underline; +} + +/*! + Indicates that this QGlyphs should be painted with an underline decoration if \a underline is + true. Otherwise the QGlyphs should be painted with no underline decoration. + + \sa underline() +*/ +void QGlyphs::setUnderline(bool underline) +{ + detach(); + d->underline = underline; +} + +/*! + Returns true if this QGlyphs should be painted with a strike out decoration. + + \sa setStrikeOut() +*/ +bool QGlyphs::strikeOut() const +{ + return d->strikeOut; +} + +/*! + Indicates that this QGlyphs should be painted with an strike out decoration if \a strikeOut is + true. Otherwise the QGlyphs should be painted with no strike out decoration. + + \sa strikeOut() +*/ +void QGlyphs::setStrikeOut(bool strikeOut) +{ + detach(); + d->strikeOut = strikeOut; } QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qglyphs.h b/src/gui/text/qglyphs.h index 5f37136..4d7dcaf 100644 --- a/src/gui/text/qglyphs.h +++ b/src/gui/text/qglyphs.h @@ -45,7 +45,9 @@ #include <QtCore/qsharedpointer.h> #include <QtCore/qvector.h> #include <QtCore/qpoint.h> -#include <QtGui/qfont.h> +#include <QtGui/qrawfont.h> + +#if !defined(QT_NO_RAWFONT) QT_BEGIN_HEADER @@ -61,8 +63,8 @@ public: QGlyphs(const QGlyphs &other); ~QGlyphs(); - QFont font() const; - void setFont(const QFont &font); + QRawFont font() const; + void setFont(const QRawFont &font); QVector<quint32> glyphIndexes() const; void setGlyphIndexes(const QVector<quint32> &glyphIndexes); @@ -76,6 +78,15 @@ public: bool operator==(const QGlyphs &other) const; bool operator!=(const QGlyphs &other) const; + void setOverline(bool overline); + bool overline() const; + + void setUnderline(bool underline); + bool underline() const; + + void setStrikeOut(bool strikeOut); + bool strikeOut() const; + private: friend class QGlyphsPrivate; friend class QTextLine; @@ -85,12 +96,12 @@ private: void detach(); QExplicitlySharedDataPointer<QGlyphsPrivate> d; - }; QT_END_NAMESPACE QT_END_HEADER +#endif // QT_NO_RAWFONT #endif // QGLYPHS_H diff --git a/src/gui/text/qglyphs_p.h b/src/gui/text/qglyphs_p.h index c632e2f..944f777 100644 --- a/src/gui/text/qglyphs_p.h +++ b/src/gui/text/qglyphs_p.h @@ -53,8 +53,12 @@ // We mean it. // -#include <qfont.h> #include "qglyphs.h" +#include "qrawfont.h" + +#include <qfont.h> + +#if !defined(QT_NO_RAWFONT) QT_BEGIN_HEADER @@ -64,17 +68,30 @@ class QGlyphsPrivate: public QSharedData { public: QGlyphsPrivate() + : overline(false) + , underline(false) + , strikeOut(false) { } QGlyphsPrivate(const QGlyphsPrivate &other) - : QSharedData(other), glyphIndexes(other.glyphIndexes), glyphPositions(other.glyphPositions), font(other.font) + : QSharedData(other) + , glyphIndexes(other.glyphIndexes) + , glyphPositions(other.glyphPositions) + , font(other.font) + , overline(other.overline) + , underline(other.underline) + , strikeOut(other.strikeOut) { } QVector<quint32> glyphIndexes; QVector<QPointF> glyphPositions; - QFont font; + QRawFont font; + + uint overline : 1; + uint underline : 1; + uint strikeOut : 1; }; QT_END_NAMESPACE @@ -82,3 +99,5 @@ QT_END_NAMESPACE QT_END_HEADER #endif // QGLYPHS_P_H + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qplatformfontdatabase_qpa.cpp b/src/gui/text/qplatformfontdatabase_qpa.cpp index 6fa25e7..82ec279 100644 --- a/src/gui/text/qplatformfontdatabase_qpa.cpp +++ b/src/gui/text/qplatformfontdatabase_qpa.cpp @@ -218,6 +218,16 @@ QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, QUnicode return engine; } +QFontEngine *QPlatformFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, + QFont::HintingPreference hintingPreference) +{ + Q_UNUSED(fontData); + Q_UNUSED(pixelSize); + Q_UNUSED(hintingPreference); + qWarning("This plugin does not support font engines created directly from font data"); + return 0; +} + /*! */ diff --git a/src/gui/text/qplatformfontdatabase_qpa.h b/src/gui/text/qplatformfontdatabase_qpa.h index e0e4f04..046311f 100644 --- a/src/gui/text/qplatformfontdatabase_qpa.h +++ b/src/gui/text/qplatformfontdatabase_qpa.h @@ -92,6 +92,8 @@ public: virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); virtual void releaseHandle(void *handle); + virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); + virtual QString fontDir() const; //callback diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp new file mode 100644 index 0000000..46c892c --- /dev/null +++ b/src/gui/text/qrawfont.cpp @@ -0,0 +1,675 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglobal.h" + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont.h" +#include "qrawfont_p.h" + +#include <QtCore/qthread.h> +#include <QtCore/qendian.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QRawFont + \brief The QRawFont class provides access to a single physical instance of a font. + \since 4.8 + + \ingroup text + \mainclass + + \note QRawFont is a low level class. For most purposes QFont is a more appropriate class. + + Most commonly, when presenting text in a user interface, the exact fonts used + to render the characters is to some extent unknown. This can be the case for several + reasons: For instance, the actual, physical fonts present on the target system could be + unexpected to the developers, or the text could contain user selected styles, sizes or + writing systems that are not supported by font chosen in the code. + + Therefore, Qt's QFont class really represents a query for fonts. When text is interpreted, + Qt will do its best to match the text to the query, but depending on the support, different + fonts can be used behind the scenes. + + For most use cases, this is both expected and necessary, as it minimizes the possibility of + text in the user interface being undisplayable. In some cases, however, more direct control + over the process might be useful. It is for these use cases the QRawFont class exists. + + A QRawFont object represents a single, physical instance of a given font in a given pixel size. + I.e. in the typical case it represents a set of TrueType or OpenType font tables and uses a + user specified pixel size to convert metrics into logical pixel units. In can be used in + combination with the QGlyphs class to draw specific glyph indexes at specific positions, and + also have accessors to some relevant data in the physical font. + + QRawFont only provides support for the main font technologies: GDI and DirectWrite on Windows + platforms, FreeType on Symbian and Linux platforms and CoreText on Mac OS X. For other + font back-ends, the APIs will be disabled. + + QRawFont can be constructed in a number of ways: + \list + \o \l It can be constructed by calling QTextLayout::glyphs() or QTextFragment::glyphs(). The + returned QGlyphs objects will contain QRawFont objects which represent the actual fonts + used to render each portion of the text. + \o \l It can be constructed by passing a QFont object to QRawFont::fromFont(). The function + will return a QRawFont object representing the font that will be selected as response to + the QFont query and the selected writing system. + \o \l It can be constructed by passing a file name or QByteArray directly to the QRawFont + constructor, or by calling loadFromFile() or loadFromData(). In this case, the + font will not be registered in QFontDatabase, and it will not be available as part of + regular font selection. + \endlist + + QRawFont is considered local to the thread in which it is constructed (either using a + constructor, or by calling loadFromData() or loadFromFile()). The QRawFont cannot be moved to a + different thread, but will have to be recreated in the thread in question. + + \note For the requirement of caching glyph indexes and font selections for static text to avoid + reshaping and relayouting in the inner loop of an application, a better choice is the QStaticText + class, since it optimizes the memory cost of the cache and also provides the possibility of paint + engine specific caches for an additional speed-up. +*/ + +/*! + \enum QRawFont::AntialiasingType + + This enum represents the different ways a glyph can be rasterized in the function + alphaMapForGlyph(). + + \value PixelAntialiasing Will rasterize by measuring the coverage of the shape on whole pixels. + The returned image contains the alpha values of each pixel based on the coverage of + the glyph shape. + \value SubPixelAntialiasing Will rasterize by measuring the coverage of each subpixel, + returning a separate alpha value for each of the red, green and blue components of + each pixel. +*/ + +/*! + Constructs an invalid QRawFont. +*/ +QRawFont::QRawFont() + : d(new QRawFontPrivate) +{ +} + +/*! + Constructs a QRawFont representing the font contained in the file referenced by \a fileName, + with \a pixelSize size in pixels, and the selected \a hintingPreference. + + \note The referenced file must contain a TrueType or OpenType font. +*/ +QRawFont::QRawFont(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference) + : d(new QRawFontPrivate) +{ + loadFromFile(fileName, pixelSize, hintingPreference); +} + +/*! + Constructs a QRawFont representing the font contained in \a fontData. + + \note The data must contain a TrueType or OpenType font. +*/ +QRawFont::QRawFont(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) + : d(new QRawFontPrivate) +{ + loadFromData(fontData, pixelSize, hintingPreference); +} + +/*! + Creates a QRawFont which is a copy of \a other. +*/ +QRawFont::QRawFont(const QRawFont &other) +{ + d = other.d; +} + +/*! + Destroys the QRawFont +*/ +QRawFont::~QRawFont() +{ +} + +/*! + Assigns \a other to this QRawFont. +*/ +QRawFont &QRawFont::operator=(const QRawFont &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if the QRawFont is valid and false otherwise. +*/ +bool QRawFont::isValid() const +{ + Q_ASSERT(d->thread == 0 || d->thread == QThread::currentThread()); + return d->fontEngine != 0; +} + +/*! + Replaces the current QRawFont with the contents of the file references by \a fileName. + + The file must reference a TrueType or OpenType font. + + \sa loadFromData() +*/ +void QRawFont::loadFromFile(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) + loadFromData(file.readAll(), pixelSize, hintingPreference); +} + +/*! + Replaces the current QRawFont with the contents of \a fontData. + + The \a fontData must contain a TrueType or OpenType font. + + \sa loadFromFile() +*/ +void QRawFont::loadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + detach(); + d->cleanUp(); + d->hintingPreference = hintingPreference; + d->thread = QThread::currentThread(); + d->platformLoadFromData(fontData, pixelSize, hintingPreference); +} + +/*! + This function returns a rasterized image of the glyph at a given \a glyphIndex in the underlying + font, if the QRawFont is valid, otherwise it will return an invalid QImage. + + If \a antialiasingType is set to QRawFont::SubPixelAntialiasing, then the resulting image will be + in QImage::Format_RGB32 and the RGB values of each pixel will represent the subpixel opacities of + the pixel in the rasterization of the glyph. Otherwise, the image will be in the format of + QImage::Format_A8 and each pixel will contain the opacity of the pixel in the rasterization. + + \sa pathForGlyph(), QPainter::drawGlyphs() +*/ +QImage QRawFont::alphaMapForGlyph(quint32 glyphIndex, AntialiasingType antialiasingType, + const QTransform &transform) const +{ + if (!isValid()) + return QImage(); + + if (antialiasingType == SubPixelAntialiasing) + return d->fontEngine->alphaRGBMapForGlyph(glyphIndex, QFixed(), 0, transform); + else + return d->fontEngine->alphaMapForGlyph(glyphIndex, QFixed(), transform); +} + +/*! + This function returns the shape of the glyph at a given \a glyphIndex in the underlying font + if the QRawFont is valid. Otherwise, it returns an empty QPainterPath. + + The returned glyph will always be unhinted. + + \sa alphaMapForGlyph(), QPainterPath::addText() +*/ +QPainterPath QRawFont::pathForGlyph(quint32 glyphIndex) const +{ + if (!isValid()) + return QPainterPath(); + + QFixedPoint position; + QPainterPath path; + d->fontEngine->addGlyphsToPath(&glyphIndex, &position, 1, &path, 0); + return path; +} + +/*! + Returns true if this QRawFont is equal to \a other. Otherwise, returns false. +*/ +bool QRawFont::operator==(const QRawFont &other) const +{ + return d->fontEngine == other.d->fontEngine; +} + +/*! + Returns the ascent of this QRawFont in pixel units. + + \sa QFontMetricsF::ascent() +*/ +qreal QRawFont::ascent() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->ascent().toReal(); +} + +/*! + Returns the descent of this QRawFont in pixel units. + + \sa QFontMetricsF::descent() +*/ +qreal QRawFont::descent() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->descent().toReal(); +} + +/*! + Returns the xHeight of this QRawFont in pixel units. + + \sa QFontMetricsF::xHeight() +*/ +qreal QRawFont::xHeight() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->xHeight().toReal(); +} + +/*! + Returns the leading of this QRawFont in pixel units. + + \sa QFontMetricsF::leading() +*/ +qreal QRawFont::leading() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->leading().toReal(); +} + +/*! + Returns the average character width of this QRawFont in pixel units. + + \sa QFontMetricsF::averageCharWidth() +*/ +qreal QRawFont::averageCharWidth() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->averageCharWidth().toReal(); +} + +/*! + Returns the width of the widest character in the font. + + \sa QFontMetricsF::maxWidth() +*/ +qreal QRawFont::maxCharWidth() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->maxCharWidth(); +} + +/*! + Returns the pixel size set for this QRawFont. The pixel size affects how glyphs are + rasterized, the size of glyphs returned by pathForGlyph(), and is used to convert + internal metrics from design units to logical pixel units. + + \sa setPixelSize() +*/ +qreal QRawFont::pixelSize() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->fontDef.pixelSize; +} + +/*! + Returns the number of design units define the width and height of the em square + for this QRawFont. This value is used together with the pixel size when converting design metrics + to pixel units, as the internal metrics are specified in design units and the pixel size gives + the size of 1 em in pixels. + + \sa pixelSize(), setPixelSize() +*/ +qreal QRawFont::unitsPerEm() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->emSquareSize().toReal(); +} + +/*! + Returns the family name of this QRawFont. +*/ +QString QRawFont::familyName() const +{ + if (!isValid()) + return QString(); + + return d->fontEngine->fontDef.family; +} + +/*! + Returns the style of this QRawFont. + + \sa QFont::style() +*/ +QFont::Style QRawFont::style() const +{ + if (!isValid()) + return QFont::StyleNormal; + + return QFont::Style(d->fontEngine->fontDef.style); +} + +/*! + Returns the weight of this QRawFont. + + \sa QFont::weight() +*/ +int QRawFont::weight() const +{ + if (!isValid()) + return -1; + + return int(d->fontEngine->fontDef.weight); +} + +/*! + Converts a string of unicode points to glyph indexes using the CMAP table in the + underlying font. Note that in cases where there are other tables in the font that affect the + shaping of the text, the returned glyph indexes will not correctly represent the rendering + of the text. To get the correctly shaped text, you can use QTextLayout to lay out and shape the + text, and then call QTextLayout::glyphs() to get the set of glyph index list and QRawFont pairs. + + \sa advancesForGlyphIndexes(), QGlyphs, QTextLayout::glyphs(), QTextFragment::glyphs() +*/ +QVector<quint32> QRawFont::glyphIndexesForString(const QString &text) const +{ + if (!isValid()) + return QVector<quint32>(); + + int nglyphs = text.size(); + QVarLengthGlyphLayoutArray glyphs(nglyphs); + if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &nglyphs, + QTextEngine::GlyphIndicesOnly)) { + glyphs.resize(nglyphs); + if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &nglyphs, + QTextEngine::GlyphIndicesOnly)) { + Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); + return QVector<quint32>(); + } + } + + QVector<quint32> glyphIndexes; + for (int i=0; i<nglyphs; ++i) + glyphIndexes.append(glyphs.glyphs[i]); + + return glyphIndexes; +} + +/*! + Returns the QRawFont's advances for each of the \a glyphIndexes in pixel units. The advances + give the distance from the position of a given glyph to where the next glyph should be drawn + to make it appear as if the two glyphs are unspaced. + + \sa QTextLine::horizontalAdvance(), QFontMetricsF::width() +*/ +QVector<QPointF> QRawFont::advancesForGlyphIndexes(const QVector<quint32> &glyphIndexes) const +{ + if (!isValid()) + return QVector<QPointF>(); + + int numGlyphs = glyphIndexes.size(); + QVarLengthGlyphLayoutArray glyphs(numGlyphs); + qMemCopy(glyphs.glyphs, glyphIndexes.data(), numGlyphs * sizeof(quint32)); + + d->fontEngine->recalcAdvances(&glyphs, 0); + + QVector<QPointF> advances; + for (int i=0; i<numGlyphs; ++i) + advances.append(QPointF(glyphs.advances_x[i].toReal(), glyphs.advances_y[i].toReal())); + + return advances; +} + +/*! + Returns the hinting preference used to construct this QRawFont. + + \sa QFont::hintingPreference() +*/ +QFont::HintingPreference QRawFont::hintingPreference() const +{ + if (!isValid()) + return QFont::PreferDefaultHinting; + + return d->hintingPreference; +} + +/*! + Retrieves the sfnt table named \a tagName from the underlying physical font, or an empty + byte array if no such table was found. The returned font table's byte order is Big Endian, like + the sfnt format specifies. The \a tagName must be four characters long and should be formatted + in the default endianness of the current platform. +*/ +QByteArray QRawFont::fontTable(const char *tagName) const +{ + if (!isValid()) + return QByteArray(); + + const quint32 *tagId = reinterpret_cast<const quint32 *>(tagName); + return d->fontEngine->getSfntTable(qToBigEndian(*tagId)); +} + +// From qfontdatabase.cpp +extern QList<QFontDatabase::WritingSystem> qt_determine_writing_systems_from_truetype_bits(quint32 unicodeRange[4], quint32 codePageRange[2]); + +/*! + Returns a list of writing systems supported by the font according to designer supplied + information in the font file. Please note that this does not guarantee support for a + specific unicode point in the font. You can use the supportsCharacter() to check support + for a single, specific character. + + \note The list is determined based on the unicode ranges and codepage ranges set in the font's + OS/2 table and requires such a table to be present in the underlying font file. + + \sa supportsCharacter() +*/ +QList<QFontDatabase::WritingSystem> QRawFont::supportedWritingSystems() const +{ + if (isValid()) { + QByteArray os2Table = fontTable("OS/2"); + if (!os2Table.isEmpty() && os2Table.size() > 86) { + char *data = os2Table.data(); + quint32 *bigEndianUnicodeRanges = reinterpret_cast<quint32 *>(data + 42); + quint32 *bigEndianCodepageRanges = reinterpret_cast<quint32 *>(data + 78); + + quint32 unicodeRanges[4]; + quint32 codepageRanges[2]; + + for (int i=0; i<4; ++i) { + if (i < 2) + codepageRanges[i] = qFromBigEndian(bigEndianCodepageRanges[i]); + unicodeRanges[i] = qFromBigEndian(bigEndianUnicodeRanges[i]); + } + + return qt_determine_writing_systems_from_truetype_bits(unicodeRanges, codepageRanges); + } + } + + return QList<QFontDatabase::WritingSystem>(); +} + +/*! + Returns true if the font has a glyph that corresponds to the given \a character. + + \sa supportedWritingSystems() +*/ +bool QRawFont::supportsCharacter(const QChar &character) const +{ + if (!isValid()) + return false; + + return d->fontEngine->canRender(&character, 1); +} + +/*! + Returns true if the font has a glyph that corresponds to the UCS-4 encoded character \a ucs4. + + \sa supportedWritingSystems() +*/ +bool QRawFont::supportsCharacter(quint32 ucs4) const +{ + if (!isValid()) + return false; + + QString str = QString::fromUcs4(&ucs4, 1); + return d->fontEngine->canRender(str.constData(), str.size()); +} + +// qfontdatabase.cpp +extern int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem); + +/*! + Fetches the physical representation based on a \a font query. The physical font returned is + the font that will be preferred by Qt in order to display text in the selected \a writingSystem. +*/ +QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writingSystem) +{ +#if defined(Q_WS_MAC) + QTextLayout layout(QFontDatabase::writingSystemSample(writingSystem), font); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + QList<QGlyphs> list = layout.glyphs(); + if (list.size()) { + // Pick the one matches the family name we originally requested, + // if none of them match, just pick the first one + for (int i = 0; i < list.size(); i++) { + QGlyphs glyphs = list.at(i); + QRawFont rawfont = glyphs.font(); + if (rawfont.familyName() == font.family()) + return rawfont; + } + return list.at(0).font(); + } + return QRawFont(); +#else + QFontPrivate *font_d = QFontPrivate::get(font); + int script = qt_script_for_writing_system(writingSystem); + QFontEngine *fe = font_d->engineForScript(script); + + if (fe != 0 && fe->type() == QFontEngine::Multi) { + QFontEngineMulti *multiEngine = static_cast<QFontEngineMulti *>(fe); + fe = multiEngine->engine(0); + if (fe == 0) { + multiEngine->loadEngine(0); + fe = multiEngine->engine(0); + } + } + + if (fe != 0) { + QRawFont rawFont; + rawFont.d.data()->fontEngine = fe; + rawFont.d.data()->fontEngine->ref.ref(); + rawFont.d.data()->hintingPreference = font.hintingPreference(); + return rawFont; + } else { + return QRawFont(); + } +#endif +} + +/*! + Sets the pixel size with which this font should be rendered to \a pixelSize. +*/ +void QRawFont::setPixelSize(qreal pixelSize) +{ + if (d->fontEngine == 0) + return; + + detach(); + QFontEngine *oldFontEngine = d->fontEngine; + + d->fontEngine = d->fontEngine->cloneWithSize(pixelSize); + if (d->fontEngine != 0) + d->fontEngine->ref.ref(); + + oldFontEngine->ref.deref(); + if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0) + delete oldFontEngine; +} + +/*! + \internal +*/ +void QRawFont::detach() +{ + if (d->ref != 1) + d.detach(); +} + +/*! + \internal +*/ +void QRawFontPrivate::cleanUp() +{ + platformCleanUp(); + if (fontEngine != 0) { + fontEngine->ref.deref(); + if (fontEngine->cache_count == 0 && fontEngine->ref == 0) + delete fontEngine; + fontEngine = 0; + } + hintingPreference = QFont::PreferDefaultHinting; +} + +#endif // QT_NO_RAWFONT + +QT_END_NAMESPACE diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h new file mode 100644 index 0000000..900c07a --- /dev/null +++ b/src/gui/text/qrawfont.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRAWFONT_H +#define QRAWFONT_H + +#include <QtCore/qstring.h> +#include <QtCore/qiodevice.h> +#include <QtCore/qglobal.h> +#include <QtCore/qobject.h> +#include <QtCore/qpoint.h> +#include <QtGui/qfont.h> +#include <QtGui/qtransform.h> +#include <QtGui/qfontdatabase.h> + +#if !defined(QT_NO_RAWFONT) + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QRawFontPrivate; +class Q_GUI_EXPORT QRawFont +{ +public: + enum AntialiasingType { + PixelAntialiasing, + SubPixelAntialiasing + }; + + QRawFont(); + QRawFont(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); + QRawFont(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); + QRawFont(const QRawFont &other); + ~QRawFont(); + + bool isValid() const; + + QRawFont &operator=(const QRawFont &other); + bool operator==(const QRawFont &other) const; + + QString familyName() const; + + QFont::Style style() const; + int weight() const; + + QVector<quint32> glyphIndexesForString(const QString &text) const; + QVector<QPointF> advancesForGlyphIndexes(const QVector<quint32> &glyphIndexes) const; + + QImage alphaMapForGlyph(quint32 glyphIndex, + AntialiasingType antialiasingType = SubPixelAntialiasing, + const QTransform &transform = QTransform()) const; + QPainterPath pathForGlyph(quint32 glyphIndex) const; + + void setPixelSize(qreal pixelSize); + qreal pixelSize() const; + + QFont::HintingPreference hintingPreference() const; + + qreal ascent() const; + qreal descent() const; + qreal leading() const; + qreal xHeight() const; + qreal averageCharWidth() const; + qreal maxCharWidth() const; + + qreal unitsPerEm() const; + + void loadFromFile(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference); + + void loadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference); + + bool supportsCharacter(quint32 ucs4) const; + bool supportsCharacter(const QChar &character) const; + QList<QFontDatabase::WritingSystem> supportedWritingSystems() const; + + QByteArray fontTable(const char *tagName) const; + + static QRawFont fromFont(const QFont &font, + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Any); + +private: + friend class QRawFontPrivate; + + void detach(); + + QExplicitlySharedDataPointer<QRawFontPrivate> d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_RAWFONT + +#endif // QRAWFONT_H diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp new file mode 100644 index 0000000..23d47eb --- /dev/null +++ b/src/gui/text/qrawfont_ft.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qglobal.h> + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont_p.h" +#include "qfontengine_ft_p.h" + +#if defined(Q_WS_X11) +# include "qfontengine_x11_p.h" +#endif + +QT_BEGIN_NAMESPACE + +class QFontEngineFTRawFont + +#if defined(Q_WS_X11) + : public QFontEngineX11FT +#else + : public QFontEngineFT +#endif + +{ +public: + QFontEngineFTRawFont(const QFontDef &fontDef) +#if defined(Q_WS_X11) + : QFontEngineX11FT(fontDef) +#else + : QFontEngineFT(fontDef) +#endif + { + } + + void updateFamilyNameAndStyle() + { + fontDef.family = QString::fromAscii(freetype->face->family_name); + + if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC) + fontDef.style = QFont::StyleItalic; + + if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD) + fontDef.weight = QFont::Bold; + } + + bool initFromData(const QByteArray &fontData) + { + FaceId faceId; + faceId.filename = ""; + faceId.index = 0; + + return init(faceId, true, Format_None, fontData); + } +}; + + +void QRawFontPrivate::platformCleanUp() +{ + // Font engine handles all resources +} + +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, + QFont::HintingPreference hintingPreference) +{ + Q_ASSERT(fontEngine == 0); + + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + + QFontEngineFTRawFont *fe = new QFontEngineFTRawFont(fontDef); + if (!fe->initFromData(fontData)) { + delete fe; + return; + } + + fe->updateFamilyNameAndStyle(); + + switch (hintingPreference) { + case QFont::PreferNoHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintNone); + break; + case QFont::PreferFullHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintFull); + break; + case QFont::PreferVerticalHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintLight); + break; + default: + // Leave it as it is + break; + } + + fontEngine = fe; + fontEngine->ref.ref(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qrawfont_mac.cpp b/src/gui/text/qrawfont_mac.cpp new file mode 100644 index 0000000..1ed4185 --- /dev/null +++ b/src/gui/text/qrawfont_mac.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 <QtCore/qglobal.h> + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont_p.h" +#include "qfontengine_coretext_p.h" + +QT_BEGIN_NAMESPACE + +void QRawFontPrivate::platformCleanUp() +{ +} + +extern int qt_defaultDpi(); + +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + // Mac OS X ignores it + Q_UNUSED(hintingPreference); + + QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(NULL, + fontData.constData(), fontData.size(), NULL); + + CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider); + + if (cgFont == NULL) { + qWarning("QRawFont::platformLoadFromData: CGFontCreateWithDataProvider failed"); + } else { + QFontDef def; + def.pixelSize = pixelSize; + def.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + fontEngine = new QCoreTextFontEngine(cgFont, def); + CFRelease(cgFont); + fontEngine->ref.ref(); + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qrawfont_p.h b/src/gui/text/qrawfont_p.h new file mode 100644 index 0000000..e29ea9c --- /dev/null +++ b/src/gui/text/qrawfont_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRAWFONTPRIVATE_P_H +#define QRAWFONTPRIVATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qrawfont.h" +#include "qfontengine_p.h" +#include <QtCore/qthreadstorage.h> + +#if !defined(QT_NO_RAWFONT) + +QT_BEGIN_NAMESPACE + +namespace { class CustomFontFileLoader; } +class Q_AUTOTEST_EXPORT QRawFontPrivate +{ +public: + QRawFontPrivate() + : fontEngine(0) + , hintingPreference(QFont::PreferDefaultHinting) + , thread(0) +#if defined(Q_WS_WIN) + , fontHandle(NULL) + , ptrAddFontMemResourceEx(NULL) + , ptrRemoveFontMemResourceEx(NULL) +#endif + {} + + QRawFontPrivate(const QRawFontPrivate &other) + : hintingPreference(other.hintingPreference) + , thread(other.thread) +#if defined(Q_WS_WIN) + , fontHandle(NULL) + , ptrAddFontMemResourceEx(other.ptrAddFontMemResourceEx) + , ptrRemoveFontMemResourceEx(other.ptrRemoveFontMemResourceEx) +#endif + { + fontEngine = other.fontEngine; + if (fontEngine != 0) + fontEngine->ref.ref(); + } + + ~QRawFontPrivate() + { + Q_ASSERT(ref == 0); + cleanUp(); + } + + void cleanUp(); + void platformCleanUp(); + void platformLoadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference); + + static QRawFontPrivate *get(const QRawFont &font) { return font.d.data(); } + + QFontEngine *fontEngine; + QFont::HintingPreference hintingPreference; + QThread *thread; + QAtomicInt ref; + +#if defined(Q_WS_WIN) + HANDLE fontHandle; + + typedef HANDLE (WINAPI *PtrAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *); + typedef BOOL (WINAPI *PtrRemoveFontMemResourceEx)(HANDLE); + + PtrAddFontMemResourceEx ptrAddFontMemResourceEx; + PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx; + +#endif // Q_WS_WIN +}; + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT + +#endif // QRAWFONTPRIVATE_P_H diff --git a/src/gui/text/qrawfont_qpa.cpp b/src/gui/text/qrawfont_qpa.cpp new file mode 100644 index 0000000..103619c --- /dev/null +++ b/src/gui/text/qrawfont_qpa.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qglobal.h> + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont_p.h" +#include <QtGui/qplatformfontdatabase_qpa.h> +#include <private/qapplication_p.h> + +QT_BEGIN_NAMESPACE + +void QRawFontPrivate::platformCleanUp() +{ +} + +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, + QFont::HintingPreference hintingPreference) +{ + Q_ASSERT(fontEngine == 0); + + QPlatformFontDatabase *pfdb = QApplicationPrivate::platformIntegration()->fontDatabase(); + fontEngine = pfdb->fontEngine(fontData, pixelSize, hintingPreference); + if (fontEngine != 0) + fontEngine->ref.ref(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qrawfont_win.cpp b/src/gui/text/qrawfont_win.cpp new file mode 100644 index 0000000..d8acf57 --- /dev/null +++ b/src/gui/text/qrawfont_win.cpp @@ -0,0 +1,707 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 "qrawfont_p.h" +#include <private/qsystemlibrary_p.h> + +#if !defined(QT_NO_DIRECTWRITE) +# include "qfontenginedirectwrite_p.h" +# include <dwrite.h> +#endif + +#if !defined(QT_NO_RAWFONT) + +QT_BEGIN_NAMESPACE + +namespace { + + template<typename T> + struct BigEndian + { + quint8 data[sizeof(T)]; + + operator T() const + { + T littleEndian = 0; + for (int i=0; i<sizeof(T); ++i) { + littleEndian |= data[i] << ((sizeof(T) - i - 1) * 8); + } + + return littleEndian; + } + + BigEndian<T> &operator=(const T &t) + { + for (int i=0; i<sizeof(T); ++i) { + data[i] = ((t >> (sizeof(T) - i - 1) * 8) & 0xff); + } + + return *this; + } + }; + +# pragma pack(1) + + // Common structure for all formats of the "name" table + struct NameTable + { + BigEndian<quint16> format; + BigEndian<quint16> count; + BigEndian<quint16> stringOffset; + }; + + struct NameRecord + { + BigEndian<quint16> platformID; + BigEndian<quint16> encodingID; + BigEndian<quint16> languageID; + BigEndian<quint16> nameID; + BigEndian<quint16> length; + BigEndian<quint16> offset; + }; + + struct OffsetSubTable + { + BigEndian<quint32> scalerType; + BigEndian<quint16> numTables; + BigEndian<quint16> searchRange; + BigEndian<quint16> entrySelector; + BigEndian<quint16> rangeShift; + }; + + struct TableDirectory + { + BigEndian<quint32> identifier; + BigEndian<quint32> checkSum; + BigEndian<quint32> offset; + BigEndian<quint32> length; + }; + + struct OS2Table + { + BigEndian<quint16> version; + BigEndian<qint16> avgCharWidth; + BigEndian<quint16> weightClass; + BigEndian<quint16> widthClass; + BigEndian<quint16> type; + BigEndian<qint16> subscriptXSize; + BigEndian<qint16> subscriptYSize; + BigEndian<qint16> subscriptXOffset; + BigEndian<qint16> subscriptYOffset; + BigEndian<qint16> superscriptXSize; + BigEndian<qint16> superscriptYSize; + BigEndian<qint16> superscriptXOffset; + BigEndian<qint16> superscriptYOffset; + BigEndian<qint16> strikeOutSize; + BigEndian<qint16> strikeOutPosition; + BigEndian<qint16> familyClass; + quint8 panose[10]; + BigEndian<quint32> unicodeRanges[4]; + quint8 vendorID[4]; + BigEndian<quint16> selection; + BigEndian<quint16> firstCharIndex; + BigEndian<quint16> lastCharIndex; + BigEndian<qint16> typoAscender; + BigEndian<qint16> typoDescender; + BigEndian<qint16> typoLineGap; + BigEndian<quint16> winAscent; + BigEndian<quint16> winDescent; + BigEndian<quint32> codepageRanges[2]; + BigEndian<qint16> height; + BigEndian<qint16> capHeight; + BigEndian<quint16> defaultChar; + BigEndian<quint16> breakChar; + BigEndian<quint16> maxContext; + }; + +# pragma pack() + + class EmbeddedFont + { + public: + EmbeddedFont(const QByteArray &fontData); + + QString changeFamilyName(const QString &newFamilyName); + QByteArray data() const { return m_fontData; } + TableDirectory *tableDirectoryEntry(const QByteArray &tagName); + QString familyName(TableDirectory *nameTableDirectory = 0); + + private: + QByteArray m_fontData; + }; + + EmbeddedFont::EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) + { + } + + TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName) + { + Q_ASSERT(tagName.size() == 4); + + const BigEndian<quint32> *tagIdPtr = + reinterpret_cast<const BigEndian<quint32> *>(tagName.constData()); + quint32 tagId = *tagIdPtr; + + OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data()); + TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1); + + TableDirectory *nameTableDirectoryEntry = 0; + for (int i=0; i<offsetSubTable->numTables; ++i, ++tableDirectory) { + if (tableDirectory->identifier == tagId) { + nameTableDirectoryEntry = tableDirectory; + break; + } + } + + return nameTableDirectoryEntry; + } + + QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry) + { + QString name; + + if (nameTableDirectoryEntry == 0) + nameTableDirectoryEntry = tableDirectoryEntry("name"); + + if (nameTableDirectoryEntry != 0) { + NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data() + + nameTableDirectoryEntry->offset); + NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1); + for (int i=0; i<nameTable->count; ++i, ++nameRecord) { + if (nameRecord->nameID == 1 + && nameRecord->platformID == 3 // Windows + && nameRecord->languageID == 0x0409) { // US English + const void *ptr = reinterpret_cast<const quint8 *>(nameTable) + + nameTable->stringOffset + + nameRecord->offset; + + const BigEndian<quint16> *s = reinterpret_cast<const BigEndian<quint16> *>(ptr); + for (int j=0; j<nameRecord->length / sizeof(quint16); ++j) + name += QChar(s[j]); + + break; + } + } + } + + return name; + } + + QString EmbeddedFont::changeFamilyName(const QString &newFamilyName) + { + TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name"); + if (nameTableDirectoryEntry == 0) + return QString(); + + QString oldFamilyName = familyName(nameTableDirectoryEntry); + + // Reserve size for name table header, five required name records and string + const int requiredRecordCount = 5; + quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 }; + + int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount; + int newFamilyNameSize = newFamilyName.size() * sizeof(quint16); + + const QString regularString = QString::fromLatin1("Regular"); + int regularStringSize = regularString.size() * sizeof(quint16); + + // Align table size of table to 32 bits (pad with 0) + int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4; + + QByteArray newNameTable(fullSize, char(0)); + + { + NameTable *nameTable = reinterpret_cast<NameTable *>(newNameTable.data()); + nameTable->count = requiredRecordCount; + nameTable->stringOffset = sizeOfHeader; + + NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1); + for (int i=0; i<requiredRecordCount; ++i, nameRecord++) { + nameRecord->nameID = nameIds[i]; + nameRecord->encodingID = 1; + nameRecord->languageID = 0x0409; + nameRecord->platformID = 3; + nameRecord->length = newFamilyNameSize; + + // Special case for sub-family + if (nameIds[i] == 4) { + nameRecord->offset = newFamilyNameSize; + nameRecord->length = regularStringSize; + } + } + + // nameRecord now points to string data + BigEndian<quint16> *stringStorage = reinterpret_cast<BigEndian<quint16> *>(nameRecord); + const quint16 *sourceString = newFamilyName.utf16(); + for (int i=0; i<newFamilyName.size(); ++i) + stringStorage[i] = sourceString[i]; + stringStorage += newFamilyName.size(); + + sourceString = regularString.utf16(); + for (int i=0; i<regularString.size(); ++i) + stringStorage[i] = sourceString[i]; + } + + quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data()); + quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize); + + quint32 checkSum = 0; + while (p < tableEnd) + checkSum += *(p++); + + nameTableDirectoryEntry->checkSum = checkSum; + nameTableDirectoryEntry->offset = m_fontData.size(); + nameTableDirectoryEntry->length = fullSize; + + m_fontData.append(newNameTable); + + return oldFamilyName; + } + +#if !defined(QT_NO_DIRECTWRITE) + + class DirectWriteFontFileStream: public IDWriteFontFileStream + { + public: + DirectWriteFontFileStream(const QByteArray &fontData) + : m_fontData(fontData) + , m_referenceCount(0) + { + } + + ~DirectWriteFontFileStream() + { + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset, + UINT64 fragmentSize, OUT void **fragmentContext); + void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext); + HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize); + HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime); + + private: + QByteArray m_fontData; + ULONG m_referenceCount; + }; + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object) + { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { + *object = this; + AddRef(); + return S_OK; + } else { + *object = NULL; + return E_NOINTERFACE; + } + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef() + { + return InterlockedIncrement(&m_referenceCount); + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release() + { + ULONG newCount = InterlockedDecrement(&m_referenceCount); + if (newCount == 0) + delete this; + return newCount; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment( + const void **fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + OUT void **fragmentContext) + { + *fragmentContext = NULL; + if (fragmentSize + fileOffset <= m_fontData.size()) { + *fragmentStart = m_fontData.data() + fileOffset; + return S_OK; + } else { + *fragmentStart = NULL; + return E_FAIL; + } + } + + void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *) + { + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize) + { + *fileSize = m_fontData.size(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) + { + *lastWriteTime = 0; + return E_NOTIMPL; + } + + class DirectWriteFontFileLoader: public IDWriteFontFileLoader + { + public: + DirectWriteFontFileLoader() : m_referenceCount(0) {} + + ~DirectWriteFontFileLoader() + { + } + + inline void addKey(const void *key, const QByteArray &fontData) + { + Q_ASSERT(!m_fontDatas.contains(key)); + m_fontDatas.insert(key, fontData); + } + + inline void removeKey(const void *key) + { + m_fontDatas.remove(key); + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + OUT IDWriteFontFileStream **fontFileStream); + + private: + ULONG m_referenceCount; + QHash<const void *, QByteArray> m_fontDatas; + }; + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid, + void **object) + { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { + *object = this; + AddRef(); + return S_OK; + } else { + *object = NULL; + return E_NOINTERFACE; + } + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef() + { + return InterlockedIncrement(&m_referenceCount); + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release() + { + ULONG newCount = InterlockedDecrement(&m_referenceCount); + if (newCount == 0) + delete this; + return newCount; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey( + void const *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + IDWriteFontFileStream **fontFileStream) + { + Q_UNUSED(fontFileReferenceKeySize); + + if (fontFileReferenceKeySize != sizeof(const void *)) { + qWarning("DirectWriteFontFileLoader::CreateStreamFromKey: Wrong key size"); + return E_FAIL; + } + + const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey); + *fontFileStream = NULL; + if (!m_fontDatas.contains(key)) + return E_FAIL; + + QByteArray fontData = m_fontDatas.value(key); + DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData); + stream->AddRef(); + *fontFileStream = stream; + + return S_OK; + } + + class CustomFontFileLoader + { + public: + CustomFontFileLoader() : m_directWriteFactory(0), m_directWriteFontFileLoader(0) + { + HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast<IUnknown **>(&m_directWriteFactory)); + if (FAILED(hres)) { + qErrnoWarning(hres, "CustomFontFileLoader::CustomFontFileLoader: " + "DWriteCreateFactory failed."); + } else { + m_directWriteFontFileLoader = new DirectWriteFontFileLoader(); + m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader); + } + } + + ~CustomFontFileLoader() + { + if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0) + m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader); + + if (m_directWriteFactory != 0) + m_directWriteFactory->Release(); + } + + void addKey(const void *key, const QByteArray &fontData) + { + if (m_directWriteFontFileLoader != 0) + m_directWriteFontFileLoader->addKey(key, fontData); + } + + void removeKey(const void *key) + { + if (m_directWriteFontFileLoader != 0) + m_directWriteFontFileLoader->removeKey(key); + } + + IDWriteFontFileLoader *loader() const + { + return m_directWriteFontFileLoader; + } + + private: + IDWriteFactory *m_directWriteFactory; + DirectWriteFontFileLoader *m_directWriteFontFileLoader; + }; + +#endif + +} // Anonymous namespace + + +// From qfontdatabase_win.cpp +extern QFontEngine *qt_load_font_engine_win(const QFontDef &request); +// From qfontdatabase.cpp +extern QFont::Weight weightFromInteger(int weight); + +void QRawFontPrivate::platformCleanUp() +{ + if (fontHandle != NULL) { + if (ptrRemoveFontMemResourceEx == NULL) { + void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + ptrRemoveFontMemResourceEx = + reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func); + } + + if (ptrRemoveFontMemResourceEx == NULL) { + qWarning("QRawFont::platformCleanUp: Can't find RemoveFontMemResourceEx in gdi32"); + fontHandle = NULL; + } else { + ptrRemoveFontMemResourceEx(fontHandle); + fontHandle = NULL; + } + } +} + +void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + QByteArray fontData(_fontData); + EmbeddedFont font(fontData); + +#if !defined(QT_NO_DIRECTWRITE) + if (hintingPreference == QFont::PreferDefaultHinting + || hintingPreference == QFont::PreferFullHinting) +#endif + { + GUID guid; + CoCreateGuid(&guid); + + QString uniqueFamilyName = QString::fromLatin1("f") + + QString::number(guid.Data1, 36) + QLatin1Char('-') + + QString::number(guid.Data2, 36) + QLatin1Char('-') + + QString::number(guid.Data3, 36) + QLatin1Char('-') + + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36); + + QString actualFontName = font.changeFamilyName(uniqueFamilyName); + if (actualFontName.isEmpty()) { + qWarning("QRawFont::platformLoadFromData: Can't change family name of font"); + return; + } + + if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) { + void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + ptrRemoveFontMemResourceEx = + reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func); + + func = QSystemLibrary::resolve(QLatin1String("gdi32"), "AddFontMemResourceEx"); + ptrAddFontMemResourceEx = + reinterpret_cast<QRawFontPrivate::PtrAddFontMemResourceEx>(func); + } + + Q_ASSERT(fontHandle == NULL); + if (ptrAddFontMemResourceEx != NULL && ptrRemoveFontMemResourceEx != NULL) { + DWORD count = 0; + fontData = font.data(); + fontHandle = ptrAddFontMemResourceEx(fontData.data(), fontData.size(), 0, &count); + + if (count == 0 && fontHandle != NULL) { + ptrRemoveFontMemResourceEx(fontHandle); + fontHandle = NULL; + } + } + + if (fontHandle == NULL) { + qWarning("QRawFont::platformLoadFromData: AddFontMemResourceEx failed"); + } else { + QFontDef request; + request.family = uniqueFamilyName; + request.pixelSize = pixelSize; + request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch; + request.hintingPreference = hintingPreference; + + fontEngine = qt_load_font_engine_win(request); + if (request.family != fontEngine->fontDef.family) { + qWarning("QRawFont::platformLoadFromData: Failed to load font. " + "Got fallback instead: %s", qPrintable(fontEngine->fontDef.family)); + if (fontEngine->cache_count == 0 && fontEngine->ref == 0) + delete fontEngine; + fontEngine = 0; + } else { + Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref == 0); + + // Override the generated font name + static_cast<QFontEngineWin *>(fontEngine)->uniqueFamilyName = uniqueFamilyName; + fontEngine->fontDef.family = actualFontName; + fontEngine->ref.ref(); + } + } + } +#if !defined(QT_NO_DIRECTWRITE) + else { + CustomFontFileLoader fontFileLoader; + fontFileLoader.addKey(this, fontData); + + IDWriteFactory *factory = NULL; + HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast<IUnknown **>(&factory)); + if (FAILED(hres)) { + qErrnoWarning(hres, "QRawFont::platformLoadFromData: DWriteCreateFactory failed"); + return; + } + + IDWriteFontFile *fontFile = NULL; + void *key = this; + + hres = factory->CreateCustomFontFileReference(&key, sizeof(void *), + fontFileLoader.loader(), &fontFile); + if (FAILED(hres)) { + qErrnoWarning(hres, "QRawFont::platformLoadFromData: " + "CreateCustomFontFileReference failed"); + factory->Release(); + return; + } + + BOOL isSupportedFontType; + DWRITE_FONT_FILE_TYPE fontFileType; + DWRITE_FONT_FACE_TYPE fontFaceType; + UINT32 numberOfFaces; + fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces); + if (!isSupportedFontType) { + fontFile->Release(); + factory->Release(); + return; + } + + IDWriteFontFace *directWriteFontFace = NULL; + hres = factory->CreateFontFace(fontFaceType, 1, &fontFile, 0, DWRITE_FONT_SIMULATIONS_NONE, + &directWriteFontFace); + if (FAILED(hres)) { + qErrnoWarning(hres, "QRawFont::platformLoadFromData: CreateFontFace failed"); + fontFile->Release(); + factory->Release(); + return; + } + + fontFile->Release(); + + fontEngine = new QFontEngineDirectWrite(factory, directWriteFontFace, pixelSize); + + // Get font family from font data + fontEngine->fontDef.family = font.familyName(); + fontEngine->ref.ref(); + + directWriteFontFace->Release(); + factory->Release(); + } +#endif + + // Get style and weight info + if (fontEngine != 0) { + TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2"); + if (os2TableEntry != 0) { + const OS2Table *os2Table = + reinterpret_cast<const OS2Table *>(fontData.constData() + + os2TableEntry->offset); + + bool italic = os2Table->selection & 1; + bool oblique = os2Table->selection & 128; + + if (italic) + fontEngine->fontDef.style = QFont::StyleItalic; + else if (oblique) + fontEngine->fontDef.style = QFont::StyleOblique; + else + fontEngine->fontDef.style = QFont::StyleNormal; + + fontEngine->fontDef.weight = weightFromInteger(os2Table->weightClass); + } + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 452b60a..1cfb4b6 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -420,9 +420,6 @@ QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q) return q->data.data(); } -Q_GUI_EXPORT extern int qt_defaultDpiX(); -Q_GUI_EXPORT extern int qt_defaultDpiY(); - namespace { class DrawTextItemRecorder: public QPaintEngine diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index b7a2697..4396730 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1519,7 +1519,7 @@ void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, con const QTextCursor oldSelection = cursor; const int oldCursorPos = cursor.position(); - mousePressed = true; + mousePressed = (interactionFlags & Qt::TextSelectableByMouse); #ifndef QT_NO_DRAGANDDROP mightStartDrag = false; #endif @@ -1552,7 +1552,7 @@ void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, con extendBlockwiseSelection(cursorPos); else if (selectedWordOnDoubleClick.hasSelection()) extendWordwiseSelection(cursorPos, pos.x()); - else if (wordSelectionEnabled) + else if (!wordSelectionEnabled) setCursorPosition(cursorPos, QTextCursor::KeepAnchor); } else { @@ -1608,13 +1608,11 @@ void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, cons if (!(buttons & Qt::LeftButton)) return; - const bool selectable = interactionFlags & Qt::TextSelectableByMouse; const bool editable = interactionFlags & Qt::TextEditable; - if (!selectable && !editable) - return; - if (!(mousePressed + || editable + || mightStartDrag || selectedWordOnDoubleClick.hasSelection() || selectedBlockOnTrippleClick.hasSelection())) return; @@ -1628,7 +1626,7 @@ void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, cons return; } - if (!selectable) + if (!mousePressed) return; const qreal mouseX = qreal(mousePos.x()); @@ -1696,10 +1694,8 @@ void QTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton button, c if (mousePressed) { mousePressed = false; #ifndef QT_NO_CLIPBOARD - if (interactionFlags & Qt::TextSelectableByMouse) { - setClipboardSelection(); - selectionChanged(true); - } + setClipboardSelection(); + selectionChanged(true); } else if (button == Qt::MidButton && (interactionFlags & Qt::TextEditable) && QApplication::clipboard()->supportsSelection()) { @@ -1951,6 +1947,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) if (isGettingInput) layout->setPreeditArea(cursor.position() - block.position(), e->preeditString()); QList<QTextLayout::FormatRange> overrides; + const int oldPreeditCursor = preeditCursor; preeditCursor = e->preeditString().length(); hideCursor = false; for (int i = 0; i < e->attributes().size(); ++i) { @@ -1973,6 +1970,8 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) cursor.endEditBlock(); if (cursor.d) cursor.d->setX(); + if (oldPreeditCursor != preeditCursor) + emit q->microFocusChanged(); } QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index 6ddfdb0..4f6857a 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -362,20 +362,23 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor currentCharFormat = -1; bool adjustX = true; QTextBlock blockIt = block(); + bool visualMovement = priv->defaultCursorMoveStyle == QTextCursor::Visual; if (!blockIt.isValid()) return false; - if (op >= QTextCursor::Left && op <= QTextCursor::WordRight - && blockIt.textDirection() == Qt::RightToLeft) { - if (op == QTextCursor::Left) - op = QTextCursor::NextCharacter; - else if (op == QTextCursor::Right) - op = QTextCursor::PreviousCharacter; - else if (op == QTextCursor::WordLeft) + if (blockIt.textDirection() == Qt::RightToLeft) { + if (op == QTextCursor::WordLeft) op = QTextCursor::NextWord; else if (op == QTextCursor::WordRight) op = QTextCursor::PreviousWord; + + if (!visualMovement) { + if (op == QTextCursor::Left) + op = QTextCursor::NextCharacter; + else if (op == QTextCursor::Right) + op = QTextCursor::PreviousCharacter; + } } const QTextLayout *layout = blockLayout(blockIt); @@ -418,9 +421,12 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor break; } case QTextCursor::PreviousCharacter: - case QTextCursor::Left: newPosition = priv->previousCursorPosition(position, QTextLayout::SkipCharacters); break; + case QTextCursor::Left: + newPosition = visualMovement ? priv->leftCursorPosition(position) + : priv->previousCursorPosition(position, QTextLayout::SkipCharacters); + break; case QTextCursor::StartOfWord: { if (relativePos == 0) break; @@ -529,9 +535,12 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor break; } case QTextCursor::NextCharacter: - case QTextCursor::Right: newPosition = priv->nextCursorPosition(position, QTextLayout::SkipCharacters); break; + case QTextCursor::Right: + newPosition = visualMovement ? priv->rightCursorPosition(position) + : priv->nextCursorPosition(position, QTextLayout::SkipCharacters); + break; case QTextCursor::NextWord: case QTextCursor::WordRight: newPosition = priv->nextCursorPosition(position, QTextLayout::SkipWords); @@ -2558,4 +2567,19 @@ QTextDocument *QTextCursor::document() const return 0; // document went away } +/*! + \enum QTextCursor::MoveStyle + + This enum describes the movement style available to QTextCursor. The options + are: + + \value Logical Within a left-to-right text block, increase cursor position + when pressing left arrow key, decrease cursor position when pressing the + right arrow key. If the text block is right-to-left, the opposite behavior + applies. + \value Visual Pressing the left arrow key will always cause the cursor to move + left, regardless of the text's writing direction. The same behavior applies to + right arrow key. +*/ + QT_END_NAMESPACE diff --git a/src/gui/text/qtextcursor.h b/src/gui/text/qtextcursor.h index 4eaeb41..9e4c0b8 100644 --- a/src/gui/text/qtextcursor.h +++ b/src/gui/text/qtextcursor.h @@ -86,6 +86,10 @@ public: MoveAnchor, KeepAnchor }; + enum MoveStyle { + Logical, + Visual + }; void setPosition(int pos, MoveMode mode = MoveAnchor); int position() const; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index be67279..36f3c6c 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -60,6 +60,7 @@ #include <qdir.h> #include <qapplication.h> #include "qtextcontrol_p.h" +#include "qfont_p.h" #include "private/qtextedit_p.h" #include "private/qdataurl_p.h" @@ -585,6 +586,29 @@ void QTextDocument::setDefaultTextOption(const QTextOption &option) } /*! + \since 4.8 + + The default cursor movement style is used by all QTextCursor objects + created from the document. The default is QTextCursor::Logical. +*/ +QTextCursor::MoveStyle QTextDocument::defaultCursorMoveStyle() const +{ + Q_D(const QTextDocument); + return d->defaultCursorMoveStyle; +} + +/*! + \since 4.8 + + Set the default cursor movement style. +*/ +void QTextDocument::setDefaultCursorMoveStyle(QTextCursor::MoveStyle style) +{ + Q_D(QTextDocument); + d->defaultCursorMoveStyle = style; +} + +/*! \fn void QTextDocument::markContentsDirty(int position, int length) Marks the contents specified by the given \a position and \a length @@ -1671,8 +1695,6 @@ static void printPage(int index, QPainter *painter, const QTextDocument *doc, co painter->restore(); } -Q_GUI_EXPORT extern int qt_defaultDpi(); - /*! Prints the document to the given \a printer. The QPrinter must be set up before being used with this function. diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index f87ccc9..e515b36 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -46,6 +46,7 @@ #include <QtCore/qsize.h> #include <QtCore/qrect.h> #include <QtGui/qfont.h> +#include <QtGui/qtextcursor.h> QT_BEGIN_HEADER @@ -60,7 +61,6 @@ class QPainter; class QPrinter; class QAbstractTextDocumentLayout; class QPoint; -class QTextCursor; class QTextObject; class QTextFormat; class QTextFrame; @@ -269,6 +269,9 @@ public: QTextOption defaultTextOption() const; void setDefaultTextOption(const QTextOption &option); + QTextCursor::MoveStyle defaultCursorMoveStyle() const; + void setDefaultCursorMoveStyle(QTextCursor::MoveStyle style); + Q_SIGNALS: void contentsChange(int from, int charsRemoves, int charsAdded); void contentsChanged(); diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index 2172f74..779b1ff 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -209,6 +209,7 @@ QTextDocumentPrivate::QTextDocumentPrivate() defaultTextOption.setTabStop(80); // same as in qtextengine.cpp defaultTextOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + defaultCursorMoveStyle = QTextCursor::Logical; indentWidth = 40; documentMargin = 4; @@ -1382,6 +1383,20 @@ int QTextDocumentPrivate::previousCursorPosition(int position, QTextLayout::Curs return it.layout()->previousCursorPosition(position-start, mode) + start; } +int QTextDocumentPrivate::leftCursorPosition(int position) const +{ + QTextBlock it = blocksFind(position); + int start = it.position(); + return it.layout()->leftCursorPosition(position-start) + start; +} + +int QTextDocumentPrivate::rightCursorPosition(int position) const +{ + QTextBlock it = blocksFind(position); + int start = it.position(); + return it.layout()->rightCursorPosition(position-start) + start; +} + void QTextDocumentPrivate::changeObjectFormat(QTextObject *obj, int format) { beginEditBlock(); @@ -1406,11 +1421,18 @@ void QTextDocumentPrivate::changeObjectFormat(QTextObject *obj, int format) static QTextFrame *findChildFrame(QTextFrame *f, int pos) { - // ##### use binary search - QList<QTextFrame *> children = f->childFrames(); - for (int i = 0; i < children.size(); ++i) { - QTextFrame *c = children.at(i); - if (pos >= c->firstPosition() && pos <= c->lastPosition()) + /* Binary search for frame at pos */ + const QList<QTextFrame *> children = f->childFrames(); + int first = 0; + int last = children.size() - 1; + while (first <= last) { + int mid = (first + last) / 2; + QTextFrame *c = children.at(mid); + if (pos > c->lastPosition()) + first = mid + 1; + else if (pos < c->firstPosition()) + last = mid - 1; + else return c; } return 0; diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h index b464f2e..6563920 100644 --- a/src/gui/text/qtextdocument_p.h +++ b/src/gui/text/qtextdocument_p.h @@ -64,6 +64,7 @@ #include "private/qtextformat_p.h" #include "QtGui/qtextdocument.h" #include "QtGui/qtextobject.h" +#include "QtGui/qtextcursor.h" #include "QtCore/qmap.h" #include "QtCore/qvariant.h" #include "QtCore/qurl.h" @@ -244,6 +245,8 @@ public: int nextCursorPosition(int position, QTextLayout::CursorMode mode) const; int previousCursorPosition(int position, QTextLayout::CursorMode mode) const; + int leftCursorPosition(int position) const; + int rightCursorPosition(int position) const; void changeObjectFormat(QTextObject *group, int format); @@ -339,6 +342,7 @@ private: public: QTextOption defaultTextOption; + QTextCursor::MoveStyle defaultCursorMoveStyle; #ifndef QT_NO_CSSPARSER QCss::StyleSheet parsedDefaultStyleSheet; #endif diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 684de00..f3dc975 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -75,8 +75,6 @@ QT_BEGIN_NAMESPACE -Q_GUI_EXPORT extern int qt_defaultDpi(); - // ################ should probably add frameFormatChange notification! struct QTextLayoutStruct; @@ -2998,10 +2996,19 @@ void QTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int posInDo QSizeF inlineSize = (pos == QTextFrameFormat::InFlow ? intrinsic : QSizeF(0, 0)); item.setWidth(inlineSize.width()); - if (f.verticalAlignment() == QTextCharFormat::AlignMiddle) { + + QFontMetrics m(f.font()); + switch (f.verticalAlignment()) + { + case QTextCharFormat::AlignMiddle: item.setDescent(inlineSize.height() / 2); item.setAscent(inlineSize.height() / 2 - 1); - } else { + break; + case QTextCharFormat::AlignBaseline: + item.setDescent(m.descent()); + item.setAscent(inlineSize.height() - m.descent() - 1); + break; + default: item.setDescent(0); item.setAscent(inlineSize.height() - 1); } @@ -3083,6 +3090,7 @@ void QTextDocumentLayoutPrivate::ensureLayouted(QFixed y) const if (currentLazyLayoutPosition == -1) return; const QSizeF oldSize = q->dynamicDocumentSize(); + Q_UNUSED(oldSize); if (checkPoints.isEmpty()) layoutStep(); diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index a63fdbf..ff27bc6 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -856,7 +856,20 @@ void QTextEngine::shapeLine(const QScriptLine &line) } } -Q_GUI_EXPORT extern int qt_defaultDpiY(); // in qfont.cpp +#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC) +static bool enableHarfBuzz() +{ + static enum { Yes, No, Unknown } status = Unknown; + + if (status == Unknown) { + QByteArray v = qgetenv("QT_ENABLE_HARFBUZZ"); + bool value = !v.isEmpty() && v != "0" && v != "false"; + if (value) status = Yes; + else status = No; + } + return status == Yes; +} +#endif void QTextEngine::shapeText(int item) const { @@ -867,7 +880,24 @@ void QTextEngine::shapeText(int item) const return; #if defined(Q_WS_MAC) - shapeTextMac(item); +#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC) + if (enableHarfBuzz()) { +#endif + QFontEngine *actualFontEngine = fontEngine(si, &si.ascent, &si.descent, &si.leading); + if (actualFontEngine->type() == QFontEngine::Multi) + actualFontEngine = static_cast<QFontEngineMulti *>(actualFontEngine)->engine(0); + + HB_Face face = actualFontEngine->harfbuzzFace(); + HB_Script script = (HB_Script) si.analysis.script; + if (face->supported_scripts[script]) + shapeTextWithHarfbuzz(item); + else + shapeTextMac(item); +#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC) + } else { + shapeTextMac(item); + } +#endif #elif defined(Q_WS_WINCE) shapeTextWithCE(item); #else @@ -1244,6 +1274,10 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const actualFontEngine = static_cast<QFontEngineMulti *>(font)->engine(engineIdx); } + si.ascent = qMax(actualFontEngine->ascent(), si.ascent); + si.descent = qMax(actualFontEngine->descent(), si.descent); + si.leading = qMax(actualFontEngine->leading(), si.leading); + shaper_item.font = actualFontEngine->harfbuzzFont(); shaper_item.face = actualFontEngine->harfbuzzFace(); @@ -1306,6 +1340,7 @@ static void init(QTextEngine *e) e->ignoreBidi = false; e->cacheGlyphs = false; e->forceJustification = false; + e->visualMovement = false; e->layoutData = 0; @@ -1567,6 +1602,8 @@ bool QTextEngine::isRightToLeft() const default: break; } + if (!layoutData) + itemize(); // this places the cursor in the right position depending on the keyboard layout if (layoutData->string.isEmpty()) return QApplication::keyboardInputDirection() == Qt::RightToLeft; @@ -2611,8 +2648,6 @@ void QTextEngine::splitItem(int item, int pos) const // qDebug("split at position %d itempos=%d", pos, item); } -Q_GUI_EXPORT extern int qt_defaultDpiY(); - QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const { const QScriptItem &si = layoutData->items[item]; @@ -2725,6 +2760,198 @@ void QTextEngine::resolveAdditionalFormats() const specialData->resolvedFormatIndices = indices; } +QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line) +{ + if (!line.hasTrailingSpaces + || (option.flags() & QTextOption::IncludeTrailingSpaces) + || !isRightToLeft()) + return QFixed(); + + int pos = line.length; + const HB_CharAttributes *attributes = this->attributes(); + if (!attributes) + return QFixed(); + while (pos > 0 && attributes[line.from + pos - 1].whiteSpace) + --pos; + return width(line.from + pos, line.length - pos); +} + +QFixed QTextEngine::alignLine(const QScriptLine &line) +{ + QFixed x = 0; + justify(line); + // if width is QFIXED_MAX that means we used setNumColumns() and that implicitly makes this line left aligned. + if (!line.justified && line.width != QFIXED_MAX) { + int align = option.alignment(); + if (align & Qt::AlignLeft) + x -= leadingSpaceWidth(line); + if (align & Qt::AlignJustify && isRightToLeft()) + align = Qt::AlignRight; + if (align & Qt::AlignRight) + x = line.width - (line.textAdvance + leadingSpaceWidth(line)); + else if (align & Qt::AlignHCenter) + x = (line.width - (line.textAdvance + leadingSpaceWidth(line)))/2; + } + return x; +} + +QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos) +{ + unsigned short *logClusters = this->logClusters(si); + const QGlyphLayout &glyphs = shapedGlyphs(si); + + int offsetInCluster = 0; + for (int i = pos - 1; i >= 0; i--) { + if (logClusters[i] == glyph_pos) + offsetInCluster++; + else + break; + } + + // in the case that the offset is inside a (multi-character) glyph, + // interpolate the position. + if (offsetInCluster > 0) { + int clusterLength = 0; + for (int i = pos - offsetInCluster; i < max; i++) { + if (logClusters[i] == glyph_pos) + clusterLength++; + else + break; + } + if (clusterLength) + return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength; + } + + return 0; +} + +int QTextEngine::previousLogicalPosition(int oldPos) const +{ + const HB_CharAttributes *attrs = attributes(); + if (!attrs || oldPos < 0) + return oldPos; + + if (oldPos <= 0) + return 0; + oldPos--; + while (oldPos && !attrs[oldPos].charStop) + oldPos--; + return oldPos; +} + +int QTextEngine::nextLogicalPosition(int oldPos) const +{ + const HB_CharAttributes *attrs = attributes(); + int len = block.isValid() ? block.length() - 1 + : layoutData->string.length(); + Q_ASSERT(len <= layoutData->string.length()); + if (!attrs || oldPos < 0 || oldPos >= len) + return oldPos; + + oldPos++; + while (oldPos < len && !attrs[oldPos].charStop) + oldPos++; + return oldPos; +} + +int QTextEngine::lineNumberForTextPosition(int pos) +{ + if (!layoutData) + itemize(); + if (pos == layoutData->string.length() && lines.size()) + return lines.size() - 1; + for (int i = 0; i < lines.size(); ++i) { + const QScriptLine& line = lines[i]; + if (line.from + line.length > pos) + return i; + } + return -1; +} + +void QTextEngine::insertionPointsForLine(int lineNum, QVector<int> &insertionPoints) +{ + QTextLineItemIterator iterator(this, lineNum); + bool rtl = isRightToLeft(); + bool lastLine = lineNum >= lines.size() - 1; + + while (!iterator.atEnd()) { + iterator.next(); + const QScriptItem *si = &layoutData->items[iterator.item]; + if (si->analysis.bidiLevel % 2) { + int i = iterator.itemEnd - 1, min = iterator.itemStart; + if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd())) + i++; + for (; i >= min; i--) + insertionPoints.push_back(i); + } else { + int i = iterator.itemStart, max = iterator.itemEnd; + if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd())) + max++; + for (; i < max; i++) + insertionPoints.push_back(i); + } + } +} + +int QTextEngine::endOfLine(int lineNum) +{ + QVector<int> insertionPoints; + insertionPointsForLine(lineNum, insertionPoints); + + if (insertionPoints.size() > 0) + return insertionPoints.last(); + return 0; +} + +int QTextEngine::beginningOfLine(int lineNum) +{ + QVector<int> insertionPoints; + insertionPointsForLine(lineNum, insertionPoints); + + if (insertionPoints.size() > 0) + return insertionPoints.first(); + return 0; +} + +int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation op) +{ + if (!layoutData) + itemize(); + + bool moveRight = (op == QTextCursor::Right); + bool alignRight = isRightToLeft(); + if (!layoutData->hasBidi) + return moveRight ^ alignRight ? nextLogicalPosition(pos) : previousLogicalPosition(pos); + + int lineNum = lineNumberForTextPosition(pos); + Q_ASSERT(lineNum >= 0); + + QVector<int> insertionPoints; + insertionPointsForLine(lineNum, insertionPoints); + int i, max = insertionPoints.size(); + for (i = 0; i < max; i++) + if (pos == insertionPoints[i]) { + if (moveRight) { + if (i + 1 < max) + return insertionPoints[i + 1]; + } else { + if (i > 0) + return insertionPoints[i - 1]; + } + + if (moveRight ^ alignRight) { + if (lineNum + 1 < lines.size()) + return alignRight ? endOfLine(lineNum + 1) : beginningOfLine(lineNum + 1); + } + else { + if (lineNum > 0) + return alignRight ? beginningOfLine(lineNum - 1) : endOfLine(lineNum - 1); + } + } + + return pos; +} + QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f) : QTextEngine(string, f), _layoutData(string, _memory, MemSize) @@ -2829,5 +3056,127 @@ glyph_metrics_t glyph_metrics_t::transformed(const QTransform &matrix) const return m; } +QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int _lineNum, const QPointF &pos, + const QTextLayout::FormatRange *_selection) + : eng(_eng), + line(eng->lines[_lineNum]), + si(0), + lineNum(_lineNum), + lineEnd(line.from + line.length), + firstItem(eng->findItem(line.from)), + lastItem(eng->findItem(lineEnd - 1)), + nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0), + logicalItem(-1), + item(-1), + visualOrder(nItems), + levels(nItems), + selection(_selection) +{ + pos_x = x = QFixed::fromReal(pos.x()); + + x += line.x; + + x += eng->alignLine(line); + + for (int i = 0; i < nItems; ++i) + levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; + QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); + + eng->shapeLine(line); +} + +QScriptItem &QTextLineItemIterator::next() +{ + x += itemWidth; + + ++logicalItem; + item = visualOrder[logicalItem] + firstItem; + itemLength = eng->length(item); + si = &eng->layoutData->items[item]; + if (!si->num_glyphs) + eng->shape(item); + + if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { + itemWidth = si->width; + return *si; + } + + unsigned short *logClusters = eng->logClusters(si); + QGlyphLayout glyphs = eng->shapedGlyphs(si); + + itemStart = qMax(line.from, si->position); + glyphsStart = logClusters[itemStart - si->position]; + if (lineEnd < si->position + itemLength) { + itemEnd = lineEnd; + glyphsEnd = logClusters[itemEnd-si->position]; + } else { + itemEnd = si->position + itemLength; + glyphsEnd = si->num_glyphs; + } + // show soft-hyphen at line-break + if (si->position + itemLength >= lineEnd + && eng->layoutData->string.at(lineEnd - 1) == 0x00ad) + glyphs.attributes[glyphsEnd - 1].dontPrint = false; + + itemWidth = 0; + for (int g = glyphsStart; g < glyphsEnd; ++g) + itemWidth += glyphs.effectiveAdvance(g); + + return *si; +} + +bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const +{ + *selectionX = *selectionWidth = 0; + + if (!selection) + return false; + + if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { + if (si->position >= selection->start + selection->length + || si->position + itemLength <= selection->start) + return false; + + *selectionX = x; + *selectionWidth = itemWidth; + } else { + unsigned short *logClusters = eng->logClusters(si); + QGlyphLayout glyphs = eng->shapedGlyphs(si); + + int from = qMax(itemStart, selection->start) - si->position; + int to = qMin(itemEnd, selection->start + selection->length) - si->position; + if (from >= to) + return false; + + int start_glyph = logClusters[from]; + int end_glyph = (to == eng->length(item)) ? si->num_glyphs : logClusters[to]; + QFixed soff; + QFixed swidth; + if (si->analysis.bidiLevel %2) { + for (int g = glyphsEnd - 1; g >= end_glyph; --g) + soff += glyphs.effectiveAdvance(g); + for (int g = end_glyph - 1; g >= start_glyph; --g) + swidth += glyphs.effectiveAdvance(g); + } else { + for (int g = glyphsStart; g < start_glyph; ++g) + soff += glyphs.effectiveAdvance(g); + for (int g = start_glyph; g < end_glyph; ++g) + swidth += glyphs.effectiveAdvance(g); + } + + // If the starting character is in the middle of a ligature, + // selection should only contain the right part of that ligature + // glyph, so we need to get the width of the left part here and + // add it to *selectionX + QFixed leftOffsetInLigature = eng->offsetInLigature(si, from, to, start_glyph); + *selectionX = x + soff + leftOffsetInLigature; + *selectionWidth = swidth - leftOffsetInLigature; + // If the ending character is also part of a ligature, swidth does + // not contain that part yet, we also need to find out the width of + // that left part + *selectionWidth += eng->offsetInLigature(si, to, eng->length(item), end_glyph); + } + return true; +} QT_END_NAMESPACE diff --git a/src/gui/text/qtextengine_mac.cpp b/src/gui/text/qtextengine_mac.cpp index 97e8c5b..2c6e579 100644 --- a/src/gui/text/qtextengine_mac.cpp +++ b/src/gui/text/qtextengine_mac.cpp @@ -605,11 +605,11 @@ void QTextEngine::shapeTextMac(int item) const unsigned short *log_clusters = logClusters(&si); bool stringToCMapFailed = false; - if (!fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters, attributes())) { + if (!fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters, attributes(), &si)) { ensureSpace(num_glyphs); g = availableGlyphs(&si); stringToCMapFailed = !fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters, - attributes()); + attributes(), &si); } if (!stringToCMapFailed) { diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 50d1ff8..c476485 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -64,6 +64,7 @@ #include "QtGui/qpaintengine.h" #include "QtGui/qtextobject.h" #include "QtGui/qtextoption.h" +#include "QtGui/qtextcursor.h" #include "QtCore/qset.h" #include "QtCore/qdebug.h" #ifndef QT_BUILD_COMPAT_LIB @@ -471,6 +472,7 @@ public: void shape(int item) const; void justify(const QScriptLine &si); + QFixed alignLine(const QScriptLine &line); QFixed width(int charFrom, int numChars) const; glyph_metrics_t boundingBox(int from, int len) const; @@ -586,12 +588,18 @@ public: uint cacheGlyphs : 1; uint stackEngine : 1; uint forceJustification : 1; + uint visualMovement : 1; int *underlinePositions; mutable LayoutData *layoutData; inline bool hasFormats() const { return (block.docHandle() || specialData); } + inline bool visualCursorMovement() const + { + return (visualMovement || + (block.docHandle() ? block.docHandle()->defaultCursorMoveStyle == QTextCursor::Visual : false)); + } struct SpecialData { int preeditPosition; @@ -609,6 +617,14 @@ public: QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const; void shapeLine(const QScriptLine &line); + QFixed leadingSpaceWidth(const QScriptLine &line); + + QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos); + int previousLogicalPosition(int oldPos) const; + int nextLogicalPosition(int oldPos) const; + int lineNumberForTextPosition(int pos); + int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op); + void insertionPointsForLine(int lineNum, QVector<int> &insertionPoints); private: void setBoundary(int strPos) const; @@ -624,6 +640,8 @@ private: void splitItem(int item, int pos) const; void resolveAdditionalFormats() const; + int endOfLine(int lineNum); + int beginningOfLine(int lineNum); }; class QStackTextEngine : public QTextEngine { @@ -634,6 +652,49 @@ public: void *_memory[MemSize]; }; +struct QTextLineItemIterator +{ + QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(), + const QTextLayout::FormatRange *_selection = 0); + + inline bool atEnd() const { return logicalItem >= nItems - 1; } + inline bool atBeginning() const { return logicalItem <= 0; } + QScriptItem &next(); + + bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const; + inline bool isOutsideSelection() const { + QFixed tmp1, tmp2; + return !getSelectionBounds(&tmp1, &tmp2); + } + + QTextEngine *eng; + + QFixed x; + QFixed pos_x; + const QScriptLine &line; + QScriptItem *si; + + int lineNum; + int lineEnd; + int firstItem; + int lastItem; + int nItems; + int logicalItem; + int item; + int itemLength; + + int glyphsStart; + int glyphsEnd; + int itemStart; + int itemEnd; + + QFixed itemWidth; + + QVarLengthArray<int> visualOrder; + QVarLengthArray<uchar> levels; + + const QTextLayout::FormatRange *selection; +}; Q_DECLARE_OPERATORS_FOR_FLAGS(QTextEngine::ShaperFlags) diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h index ff28eaa..4f4752a 100644 --- a/src/gui/text/qtextformat.h +++ b/src/gui/text/qtextformat.h @@ -378,7 +378,8 @@ public: AlignSubScript, AlignMiddle, AlignTop, - AlignBottom + AlignBottom, + AlignBaseline }; enum UnderlineStyle { // keep in sync with Qt::PenStyle! NoUnderline, diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp index a6d085a..bbff79c 100644 --- a/src/gui/text/qtextimagehandler.cpp +++ b/src/gui/text/qtextimagehandler.cpp @@ -123,7 +123,6 @@ static QSize getPixmapSize(QTextDocument *doc, const QTextImageFormat &format) qreal scale = 1.0; QPaintDevice *pdev = doc->documentLayout()->paintDevice(); if (pdev) { - Q_GUI_EXPORT extern int qt_defaultDpi(); if (pm.isNull()) pm = getPixmap(doc, format); if (!pm.isNull()) @@ -191,7 +190,6 @@ static QSize getImageSize(QTextDocument *doc, const QTextImageFormat &format) qreal scale = 1.0; QPaintDevice *pdev = doc->documentLayout()->paintDevice(); if (pdev) { - extern int qt_defaultDpi(); if (image.isNull()) image = getImage(doc, format); if (!image.isNull()) diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 8eff7d2..01748b9 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -54,52 +54,24 @@ #include "qpainterpath.h" #include "qglyphs.h" #include "qglyphs_p.h" +#include "qrawfont.h" +#include "qrawfont_p.h" #include <limits.h> #include <qdebug.h> #include "qfontengine_p.h" +#if !defined(QT_NO_FREETYPE) +# include "qfontengine_ft_p.h" +#endif + QT_BEGIN_NAMESPACE #define ObjectSelectionBrush (QTextFormat::ForegroundBrush + 1) #define SuppressText 0x5012 #define SuppressBackground 0x513 -static inline QFixed leadingSpaceWidth(QTextEngine *eng, const QScriptLine &line) -{ - if (!line.hasTrailingSpaces - || (eng->option.flags() & QTextOption::IncludeTrailingSpaces) - || !(eng->option.alignment() & Qt::AlignRight) - || !eng->isRightToLeft()) - return QFixed(); - - int pos = line.length; - const HB_CharAttributes *attributes = eng->attributes(); - if (!attributes) - return QFixed(); - while (pos > 0 && attributes[line.from + pos - 1].whiteSpace) - --pos; - return eng->width(line.from + pos, line.length - pos); -} - -static QFixed alignLine(QTextEngine *eng, const QScriptLine &line) -{ - QFixed x = 0; - eng->justify(line); - // if width is QFIXED_MAX that means we used setNumColumns() and that implicitly makes this line left aligned. - if (!line.justified && line.width != QFIXED_MAX) { - int align = eng->option.alignment(); - if (align & Qt::AlignJustify && eng->isRightToLeft()) - align = Qt::AlignRight; - if (align & Qt::AlignRight) - x = line.width - (line.textAdvance + leadingSpaceWidth(eng, line)); - else if (align & Qt::AlignHCenter) - x = (line.width - line.textAdvance)/2; - } - return x; -} - /*! \class QTextLayout::FormatRange \reentrant @@ -607,6 +579,30 @@ bool QTextLayout::cacheEnabled() const } /*! + Set the visual cursor movement style. If the QTextLayout is backed by + a document, you can ignore this and use the option in QTextDocument, + this option is for widgets like QLineEdit or custom widgets without + a QTextDocument. Default value is QTextCursor::Logical. + + \sa setCursorMoveStyle() +*/ +void QTextLayout::setCursorMoveStyle(QTextCursor::MoveStyle style) +{ + d->visualMovement = style == QTextCursor::Visual ? true : false; +} + +/*! + The cursor movement style of this QTextLayout. The default is + QTextCursor::Logical. + + \sa setCursorMoveStyle() +*/ +QTextCursor::MoveStyle QTextLayout::cursorMoveStyle() const +{ + return d->visualMovement ? QTextCursor::Visual : QTextCursor::Logical; +} + +/*! Begins the layout process. \sa endLayout() @@ -729,6 +725,34 @@ int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const } /*! + Returns the cursor position to the right of \a oldPos, next to it. + It's dependent on the visual position of characters, after bi-directional + reordering. + + \sa leftCursorPosition(), nextCursorPosition() +*/ +int QTextLayout::rightCursorPosition(int oldPos) const +{ + int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Right); +// qDebug("%d -> %d", oldPos, newPos); + return newPos; +} + +/*! + Returns the cursor position to the left of \a oldPos, next to it. + It's dependent on the visual position of characters, after bi-directional + reordering. + + \sa rightCursorPosition(), previousCursorPosition() +*/ +int QTextLayout::leftCursorPosition(int oldPos) const +{ + int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Left); +// qDebug("%d -> %d", oldPos, newPos); + return newPos; +} + +/*!/ Returns true if position \a pos is a valid cursor position. In a Unicode context some positions in the text are not valid @@ -826,16 +850,8 @@ QTextLine QTextLayout::lineAt(int i) const */ QTextLine QTextLayout::lineForTextPosition(int pos) const { - for (int i = 0; i < d->lines.size(); ++i) { - const QScriptLine& line = d->lines[i]; - if (line.from + (int)line.length > pos) - return QTextLine(i, d); - } - if (!d->layoutData) - d->itemize(); - if (pos == d->layoutData->string.length() && d->lines.size()) - return QTextLine(d->lines.size()-1, d); - return QTextLine(); + int lineNum = d->lineNumberForTextPosition(pos); + return lineNum >= 0 ? lineAt(lineNum) : QTextLine(); } /*! @@ -930,201 +946,6 @@ void QTextLayout::setFlags(int flags) } } -struct QTextLineItemIterator -{ - QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(), - const QTextLayout::FormatRange *_selection = 0); - - inline bool atEnd() const { return logicalItem >= nItems - 1; } - QScriptItem &next(); - - bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const; - inline bool isOutsideSelection() const { - QFixed tmp1, tmp2; - return !getSelectionBounds(&tmp1, &tmp2); - } - - QTextEngine *eng; - - QFixed x; - QFixed pos_x; - const QScriptLine &line; - QScriptItem *si; - - int lineEnd; - int firstItem; - int lastItem; - int nItems; - int logicalItem; - int item; - int itemLength; - - int glyphsStart; - int glyphsEnd; - int itemStart; - int itemEnd; - - QFixed itemWidth; - - QVarLengthArray<int> visualOrder; - QVarLengthArray<uchar> levels; - - const QTextLayout::FormatRange *selection; -}; - -QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int lineNum, const QPointF &pos, - const QTextLayout::FormatRange *_selection) - : eng(_eng), - line(eng->lines[lineNum]), - si(0), - lineEnd(line.from + line.length), - firstItem(eng->findItem(line.from)), - lastItem(eng->findItem(lineEnd - 1)), - nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0), - logicalItem(-1), - item(-1), - visualOrder(nItems), - levels(nItems), - selection(_selection) -{ - pos_x = x = QFixed::fromReal(pos.x()); - - x += line.x; - - x += alignLine(eng, line); - - for (int i = 0; i < nItems; ++i) - levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; - QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); - - eng->shapeLine(line); -} - -QScriptItem &QTextLineItemIterator::next() -{ - x += itemWidth; - - ++logicalItem; - item = visualOrder[logicalItem] + firstItem; - itemLength = eng->length(item); - si = &eng->layoutData->items[item]; - if (!si->num_glyphs) - eng->shape(item); - - if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { - itemWidth = si->width; - return *si; - } - - unsigned short *logClusters = eng->logClusters(si); - QGlyphLayout glyphs = eng->shapedGlyphs(si); - - itemStart = qMax(line.from, si->position); - glyphsStart = logClusters[itemStart - si->position]; - if (lineEnd < si->position + itemLength) { - itemEnd = lineEnd; - glyphsEnd = logClusters[itemEnd-si->position]; - } else { - itemEnd = si->position + itemLength; - glyphsEnd = si->num_glyphs; - } - // show soft-hyphen at line-break - if (si->position + itemLength >= lineEnd - && eng->layoutData->string.at(lineEnd - 1) == 0x00ad) - glyphs.attributes[glyphsEnd - 1].dontPrint = false; - - itemWidth = 0; - for (int g = glyphsStart; g < glyphsEnd; ++g) - itemWidth += glyphs.effectiveAdvance(g); - - return *si; -} - -static QFixed offsetInLigature(const unsigned short *logClusters, - const QGlyphLayout &glyphs, - int pos, int max, int glyph_pos) -{ - int offsetInCluster = 0; - for (int i = pos - 1; i >= 0; i--) { - if (logClusters[i] == glyph_pos) - offsetInCluster++; - else - break; - } - - // in the case that the offset is inside a (multi-character) glyph, - // interpolate the position. - if (offsetInCluster > 0) { - int clusterLength = 0; - for (int i = pos - offsetInCluster; i < max; i++) { - if (logClusters[i] == glyph_pos) - clusterLength++; - else - break; - } - if (clusterLength) - return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength; - } - - return 0; -} - -bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const -{ - *selectionX = *selectionWidth = 0; - - if (!selection) - return false; - - if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { - if (si->position >= selection->start + selection->length - || si->position + itemLength <= selection->start) - return false; - - *selectionX = x; - *selectionWidth = itemWidth; - } else { - unsigned short *logClusters = eng->logClusters(si); - QGlyphLayout glyphs = eng->shapedGlyphs(si); - - int from = qMax(itemStart, selection->start) - si->position; - int to = qMin(itemEnd, selection->start + selection->length) - si->position; - if (from >= to) - return false; - - int start_glyph = logClusters[from]; - int end_glyph = (to == eng->length(item)) ? si->num_glyphs : logClusters[to]; - QFixed soff; - QFixed swidth; - if (si->analysis.bidiLevel %2) { - for (int g = glyphsEnd - 1; g >= end_glyph; --g) - soff += glyphs.effectiveAdvance(g); - for (int g = end_glyph - 1; g >= start_glyph; --g) - swidth += glyphs.effectiveAdvance(g); - } else { - for (int g = glyphsStart; g < start_glyph; ++g) - soff += glyphs.effectiveAdvance(g); - for (int g = start_glyph; g < end_glyph; ++g) - swidth += glyphs.effectiveAdvance(g); - } - - // If the starting character is in the middle of a ligature, - // selection should only contain the right part of that ligature - // glyph, so we need to get the width of the left part here and - // add it to *selectionX - QFixed leftOffsetInLigature = offsetInLigature(logClusters, glyphs, from, - to, start_glyph); - *selectionX = x + soff + leftOffsetInLigature; - *selectionWidth = swidth - leftOffsetInLigature; - // If the ending character is also part of a ligature, swidth does - // not contain that part yet, we also need to find out the width of - // that left part - *selectionWidth += offsetInLigature(logClusters, glyphs, to, - eng->length(item), end_glyph); - } - return true; -} - static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPointF &pos, QTextLayout::FormatRange *selection, QPainterPath *region, QRectF boundingRect) { @@ -1175,6 +996,7 @@ static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip) \sa draw(), QPainter::drawGlyphs() */ +#if !defined(QT_NO_RAWFONT) QList<QGlyphs> QTextLayout::glyphs() const { QList<QGlyphs> glyphs; @@ -1183,6 +1005,7 @@ QList<QGlyphs> QTextLayout::glyphs() const return glyphs; } +#endif // QT_NO_RAWFONT /*! Draws the whole layout on the painter \a p at the position specified by \a pos. @@ -1237,6 +1060,7 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRang QRectF lineRect(tl.naturalTextRect()); lineRect.translate(position); + lineRect.adjust(0, 0, d->leadingSpaceWidth(sl).toReal(), 0); bool isLastLineInBlock = (line == d->lines.size()-1); int sl_length = sl.length + (isLastLineInBlock? 1 : 0); // the infamous newline @@ -1387,22 +1211,11 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition d->itemize(); QPointF position = pos + d->position; - QFixed pos_x = QFixed::fromReal(position.x()); - QFixed pos_y = QFixed::fromReal(position.y()); cursorPosition = qBound(0, cursorPosition, d->layoutData->string.length()); - int line = 0; - if (cursorPosition == d->layoutData->string.length()) { - line = d->lines.size() - 1; - } else { - // ### binary search - for (line = 0; line < d->lines.size(); line++) { - const QScriptLine &sl = d->lines[line]; - if (sl.from <= cursorPosition && sl.from + (int)sl.length > cursorPosition) - break; - } - } - + int line = d->lineNumberForTextPosition(cursorPosition); + if (line < 0) + line = 0; if (line >= d->lines.size()) return; @@ -1411,7 +1224,15 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition qreal x = position.x() + l.cursorToX(cursorPosition); - int itm = d->findItem(cursorPosition - 1); + int itm; + + if (d->visualCursorMovement()) { + if (cursorPosition == sl.from + sl.length) + cursorPosition--; + itm = d->findItem(cursorPosition); + } else + itm = d->findItem(cursorPosition - 1); + QFixed base = sl.base(); QFixed descent = sl.descent; bool rightToLeft = d->isRightToLeft(); @@ -1521,7 +1342,7 @@ QRectF QTextLine::rect() const QRectF QTextLine::naturalTextRect() const { const QScriptLine& sl = eng->lines[i]; - QFixed x = sl.x + alignLine(eng, sl); + QFixed x = sl.x + eng->alignLine(sl); QFixed width = sl.textWidth; if (sl.justified) @@ -2274,6 +2095,7 @@ namespace { \sa QTextLayout::glyphs() */ +#if !defined(QT_NO_RAWFONT) QList<QGlyphs> QTextLine::glyphs(int from, int length) const { const QScriptLine &line = eng->lines[i]; @@ -2325,6 +2147,9 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const QGlyphLayout subLayout = glyphLayout.mid(start, end - start); glyphLayoutHash.insertMulti(multiFontEngine->engine(which), GlyphInfo(subLayout, pos, flags)); + for (int i = 0; i < subLayout.numGlyphs; i++) + pos += QPointF(subLayout.advances_x[i].toReal(), + subLayout.advances_y[i].toReal()); start = end; which = e; @@ -2348,7 +2173,35 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const QFontEngine *fontEngine = keys.at(i); // Make a font for this particular engine - QFont font = fontEngine->createExplicitFont(); + QRawFont font; + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + fontD->fontEngine = fontEngine; + fontD->fontEngine->ref.ref(); + +#if defined(Q_WS_WIN) + if (fontEngine->supportsSubPixelPositions()) + fontD->hintingPreference = QFont::PreferVerticalHinting; + else + fontD->hintingPreference = QFont::PreferFullHinting; +#elif defined(Q_WS_MAC) + fontD->hintingPreference = QFont::PreferNoHinting; +#elif !defined(QT_NO_FREETYPE) + if (fontEngine->type() == QFontEngine::Freetype) { + QFontEngineFT *freeTypeEngine = static_cast<QFontEngineFT *>(fontEngine); + switch (freeTypeEngine->defaultHintStyle()) { + case QFontEngineFT::HintNone: + fontD->hintingPreference = QFont::PreferNoHinting; + break; + case QFontEngineFT::HintLight: + fontD->hintingPreference = QFont::PreferVerticalHinting; + break; + case QFontEngineFT::HintMedium: + case QFontEngineFT::HintFull: + fontD->hintingPreference = QFont::PreferFullHinting; + break; + }; + } +#endif QList<GlyphInfo> glyphLayouts = glyphLayoutHash.values(fontEngine); for (int j=0; j<glyphLayouts.size(); ++j) { @@ -2356,10 +2209,6 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const const QGlyphLayout &glyphLayout = glyphLayouts.at(j).glyphLayout; const QTextItem::RenderFlags &flags = glyphLayouts.at(j).flags; - font.setOverline(flags.testFlag(QTextItem::Overline)); - font.setUnderline(flags.testFlag(QTextItem::Underline)); - font.setStrikeOut(flags.testFlag(QTextItem::StrikeOut)); - QVarLengthArray<glyph_t> glyphsArray; QVarLengthArray<QFixedPoint> positionsArray; @@ -2378,19 +2227,22 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const glyphIndexes.setGlyphIndexes(glyphs); glyphIndexes.setPositions(positions); - QPair<QFontEngine *, int> key(fontEngine, int(flags)); + glyphIndexes.setOverline(flags.testFlag(QTextItem::Overline)); + glyphIndexes.setUnderline(flags.testFlag(QTextItem::Underline)); + glyphIndexes.setStrikeOut(flags.testFlag(QTextItem::StrikeOut)); + glyphIndexes.setFont(font); + QPair<QFontEngine *, int> key(fontEngine, int(flags)); if (!glyphsHash.contains(key)) - glyphsHash.insert(key, QGlyphs()); - - QGlyphs &target = glyphsHash[key]; - target += glyphIndexes; - target.setFont(font); + glyphsHash.insert(key, glyphIndexes); + else + glyphsHash[key] += glyphIndexes; } } return glyphsHash.values(); } +#endif // QT_NO_RAWFONT /*! \fn void QTextLine::draw(QPainter *painter, const QPointF &position, const QTextLayout::FormatRange *selection) const @@ -2613,9 +2465,10 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const eng->itemize(); const QScriptLine &line = eng->lines[i]; + bool lastLine = i >= eng->lines.size() - 1; QFixed x = line.x; - x += alignLine(eng, line); + x += eng->alignLine(line); if (!i && !eng->layoutData->items.size()) { *cursorPos = 0; @@ -2701,21 +2554,29 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const logClusters = eng->logClusters(si); glyphs = eng->shapedGlyphs(si); if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { - if(pos == l) + if (pos == (reverse ? 0 : l)) x += si->width; } else { + bool rtl = eng->isRightToLeft(); + bool visual = eng->visualCursorMovement(); if (reverse) { int end = qMin(lineEnd, si->position + l) - si->position; int glyph_end = end == l ? si->num_glyphs : logClusters[end]; - for (int i = glyph_end - 1; i >= glyph_pos; i--) + int glyph_start = glyph_pos; + if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem))) + glyph_start++; + for (int i = glyph_end - 1; i >= glyph_start; i--) x += glyphs.effectiveAdvance(i); } else { int start = qMax(line.from - si->position, 0); int glyph_start = logClusters[start]; - for (int i = glyph_start; i < glyph_pos; i++) + int glyph_end = glyph_pos; + if (!visual || !rtl || (lastLine && itm == visualOrder[0] + firstItem)) + glyph_end--; + for (int i = glyph_start; i <= glyph_end; i++) x += glyphs.effectiveAdvance(i); } - x += offsetInLigature(logClusters, glyphs, pos, line.length, glyph_pos); + x += eng->offsetInLigature(si, pos, line.length, glyph_pos); } *cursorPos = pos + si->position; @@ -2734,6 +2595,8 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const { QFixed x = QFixed::fromReal(_x); const QScriptLine &line = eng->lines[i]; + bool lastLine = i >= eng->lines.size() - 1; + int lineNum = i; if (!eng->layoutData) eng->itemize(); @@ -2751,7 +2614,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const return 0; x -= line.x; - x -= alignLine(eng, line); + x -= eng->alignLine(line); // qDebug("xToCursor: x=%f, cpos=%d", x.toReal(), cpos); QVarLengthArray<int> visualOrder(nItems); @@ -2760,6 +2623,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); + bool visual = eng->visualCursorMovement(); if (x <= 0) { // left of first item int item = visualOrder[0]+firstItem; @@ -2776,8 +2640,13 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const || (line.justified && x < line.width)) { // has to be in one of the runs QFixed pos; + bool rtl = eng->isRightToLeft(); eng->shapeLine(line); + QVector<int> insertionPoints; + if (visual && rtl) + eng->insertionPointsForLine(lineNum, insertionPoints); + int nchars = 0; for (int i = 0; i < nItems; ++i) { int item = visualOrder[i]+firstItem; QScriptItem &si = eng->layoutData->items[item]; @@ -2807,6 +2676,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const if (pos + item_width < x) { pos += item_width; + nchars += end; continue; } // qDebug(" inside run"); @@ -2851,27 +2721,60 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const } else { QFixed dist = INT_MAX/256; if (si.analysis.bidiLevel % 2) { - pos += item_width; - while (gs <= ge) { - if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { - glyph_pos = gs; - dist = qAbs(x-pos); + if (!visual || rtl || (lastLine && i == nItems - 1)) { + pos += item_width; + while (gs <= ge) { + if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { + glyph_pos = gs; + dist = qAbs(x-pos); + } + pos -= glyphs.effectiveAdvance(gs); + ++gs; + } + } else { + while (ge >= gs) { + if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) { + glyph_pos = ge; + dist = qAbs(x-pos); + } + pos += glyphs.effectiveAdvance(ge); + --ge; } - pos -= glyphs.effectiveAdvance(gs); - ++gs; } } else { - while (gs <= ge) { - if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { - glyph_pos = gs; - dist = qAbs(x-pos); + if (!visual || !rtl || (lastLine && i == 0)) { + while (gs <= ge) { + if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { + glyph_pos = gs; + dist = qAbs(x-pos); + } + pos += glyphs.effectiveAdvance(gs); + ++gs; } - pos += glyphs.effectiveAdvance(gs); - ++gs; + } else { + QFixed oldPos = pos; + while (gs <= ge) { + pos += glyphs.effectiveAdvance(gs); + if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { + glyph_pos = gs; + dist = qAbs(x-pos); + } + ++gs; + } + pos = oldPos; } } - if (qAbs(x-pos) < dist) + if (qAbs(x-pos) < dist) { + if (visual) { + if (!rtl && i < nItems - 1) { + nchars += end; + continue; + } + if (rtl && nchars > 0) + return insertionPoints[lastLine ? nchars : nchars - 1]; + } return si.position + end; + } } Q_ASSERT(glyph_pos != -1); int j; diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h index 0f64c33..6aa81f9 100644 --- a/src/gui/text/qtextlayout.h +++ b/src/gui/text/qtextlayout.h @@ -50,6 +50,7 @@ #include <QtGui/qevent.h> #include <QtGui/qtextformat.h> #include <QtGui/qglyphs.h> +#include <QtGui/qtextcursor.h> QT_BEGIN_HEADER @@ -136,6 +137,9 @@ public: void setCacheEnabled(bool enable); bool cacheEnabled() const; + void setCursorMoveStyle(QTextCursor::MoveStyle style); + QTextCursor::MoveStyle cursorMoveStyle() const; + void beginLayout(); void endLayout(); void clearLayout(); @@ -153,6 +157,8 @@ public: bool isValidCursorPosition(int pos) const; int nextCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const; int previousCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const; + int leftCursorPosition(int oldPos) const; + int rightCursorPosition(int oldPos) const; void draw(QPainter *p, const QPointF &pos, const QVector<FormatRange> &selections = QVector<FormatRange>(), const QRectF &clip = QRectF()) const; @@ -167,7 +173,9 @@ public: qreal minimumWidth() const; qreal maximumWidth() const; +#if !defined(QT_NO_RAWFONT) QList<QGlyphs> glyphs() const; +#endif QTextEngine *engine() const { return d; } void setFlags(int flags); @@ -239,7 +247,10 @@ public: private: QTextLine(int line, QTextEngine *e) : i(line), eng(e) {} void layout_helper(int numGlyphs); + +#if !defined(QT_NO_RAWFONT) QList<QGlyphs> glyphs(int from, int length) const; +#endif friend class QTextLayout; friend class QTextFragment; diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index 0081550..5c1c8b9 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -891,6 +891,11 @@ QTextBlockUserData::~QTextBlockUserData() Returns true if this text block is valid; otherwise returns false. */ +bool QTextBlock::isValid() const +{ + return p != 0 && p->blockMap().isValid(n); +} + /*! \fn QTextBlock &QTextBlock::operator=(const QTextBlock &other) @@ -1661,6 +1666,7 @@ QTextBlock::iterator &QTextBlock::iterator::operator--() \sa QGlyphs, QTextBlock::layout(), QTextLayout::position(), QPainter::drawGlyphs() */ +#if !defined(QT_NO_RAWFONT) QList<QGlyphs> QTextFragment::glyphs() const { if (!p || !n) @@ -1684,6 +1690,7 @@ QList<QGlyphs> QTextFragment::glyphs() const return ret; } +#endif // QT_NO_RAWFONT /*! Returns the position of this text fragment in the document. diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h index fface3f..ad8e657 100644 --- a/src/gui/text/qtextobject.h +++ b/src/gui/text/qtextobject.h @@ -205,7 +205,7 @@ public: inline QTextBlock(const QTextBlock &o) : p(o.p), n(o.n) {} inline QTextBlock &operator=(const QTextBlock &o) { p = o.p; n = o.n; return *this; } - inline bool isValid() const { return p != 0 && n != 0; } + bool isValid() const; inline bool operator==(const QTextBlock &o) const { return p == o.p && n == o.n; } inline bool operator!=(const QTextBlock &o) const { return p != o.p || n != o.n; } @@ -316,7 +316,9 @@ public: int charFormatIndex() const; QString text() const; +#if !defined(QT_NO_RAWFONT) QList<QGlyphs> glyphs() const; +#endif private: const QTextDocumentPrivate *p; diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp index c2e47f3..c5ea0cf 100644 --- a/src/gui/text/qtextodfwriter.cpp +++ b/src/gui/text/qtextodfwriter.cpp @@ -124,6 +124,7 @@ public: manifestWriter.writeNamespace(manifestNS, QString::fromLatin1("manifest")); manifestWriter.writeStartDocument(); manifestWriter.writeStartElement(manifestNS, QString::fromLatin1("manifest")); + manifestWriter.writeAttribute(manifestNS, QString::fromLatin1("version"), QString::fromLatin1("1.2")); addFile(QString::fromLatin1("/"), QString::fromLatin1("application/vnd.oasis.opendocument.text")); addFile(QString::fromLatin1("content.xml"), QString::fromLatin1("text/xml")); } @@ -786,6 +787,7 @@ bool QTextOdfWriter::writeAll() writer.writeNamespace(svgNS, QString::fromLatin1("svg")); writer.writeStartDocument(); writer.writeStartElement(officeNS, QString::fromLatin1("document-content")); + writer.writeAttribute(officeNS, QString::fromLatin1("version"), QString::fromLatin1("1.2")); // add fragments. (for character formats) QTextDocumentPrivate::FragmentIterator fragIt = m_document->docHandle()->begin(); diff --git a/src/gui/text/qzip.cpp b/src/gui/text/qzip.cpp index 0f7edae..9f21886 100644 --- a/src/gui/text/qzip.cpp +++ b/src/gui/text/qzip.cpp @@ -572,7 +572,7 @@ void QZipWriterPrivate::addEntry(EntryType type, const QString &fileName, const "directory", "file ", "symlink " }; - ZDEBUG() << "adding" << entryTypes[type] <<":" << fileName.toUtf8().data() << (type == 2 ? (" -> " + contents).constData() : ""); + ZDEBUG() << "adding" << entryTypes[type] <<":" << fileName.toUtf8().data() << (type == 2 ? QByteArray(" -> " + contents).constData() : ""); #endif if (! (device->isOpen() || device->open(QIODevice::WriteOnly))) { diff --git a/src/gui/text/qzipwriter_p.h b/src/gui/text/qzipwriter_p.h index 0ee445e..153ef19 100644 --- a/src/gui/text/qzipwriter_p.h +++ b/src/gui/text/qzipwriter_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE class QZipWriterPrivate; -class Q_AUTOTEST_EXPORT QZipWriter +class Q_GUI_EXPORT QZipWriter { public: QZipWriter(const QString &fileName, QIODevice::OpenMode mode = (QIODevice::WriteOnly | QIODevice::Truncate) ); diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 7fb2783..e5d57d0 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -41,7 +41,9 @@ HEADERS += \ text/qstatictext_p.h \ text/qstatictext.h \ text/qglyphs.h \ - text/qglyphs_p.h + text/qglyphs_p.h \ + text/qrawfont.h \ + text/qrawfont_p.h SOURCES += \ text/qfont.cpp \ @@ -72,12 +74,14 @@ SOURCES += \ text/qzip.cpp \ text/qtextodfwriter.cpp \ text/qstatictext.cpp \ - text/qglyphs.cpp + text/qglyphs.cpp \ + text/qrawfont.cpp win32 { SOURCES += \ text/qfont_win.cpp \ - text/qfontengine_win.cpp + text/qfontengine_win.cpp \ + text/qrawfont_win.cpp HEADERS += text/qfontengine_win_p.h } @@ -95,7 +99,8 @@ unix:x11 { SOURCES += \ text/qfont_x11.cpp \ text/qfontengine_x11.cpp \ - text/qfontengine_ft.cpp + text/qfontengine_ft.cpp \ + text/qrawfont_ft.cpp } !embedded:!qpa:!x11:mac { @@ -104,10 +109,14 @@ unix:x11 { OBJECTIVE_HEADERS += \ text/qfontengine_coretext_p.h SOURCES += \ - text/qfont_mac.cpp + text/qfont_mac.cpp \ + text/qrawfont_mac.cpp OBJECTIVE_SOURCES += \ text/qfontengine_coretext.mm \ text/qfontengine_mac.mm + contains(QT_CONFIG, harfbuzz) { + DEFINES += QT_ENABLE_HARFBUZZ_FOR_MAC + } } embedded { @@ -116,7 +125,8 @@ embedded { text/qfontengine_qws.cpp \ text/qfontengine_ft.cpp \ text/qfontengine_qpf.cpp \ - text/qabstractfontengine_qws.cpp + text/qabstractfontengine_qws.cpp \ + text/qrawfont_ft.cpp HEADERS += \ text/qfontengine_ft_p.h \ text/qfontengine_qpf_p.h \ @@ -129,7 +139,8 @@ qpa { SOURCES += \ text/qfont_qpa.cpp \ text/qfontengine_qpa.cpp \ - text/qplatformfontdatabase_qpa.cpp + text/qplatformfontdatabase_qpa.cpp \ + text/qrawfont_qpa.cpp HEADERS += \ text/qplatformfontdatabase_qpa.h @@ -143,7 +154,8 @@ symbian { text/qfont_s60.cpp contains(QT_CONFIG, freetype) { SOURCES += \ - text/qfontengine_ft.cpp + text/qfontengine_ft.cpp \ + text/qrawfont_ft.cpp HEADERS += \ text/qfontengine_ft_p.h DEFINES += \ diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp index 27684bf..0cb3bbd 100644 --- a/src/gui/util/qcompleter.cpp +++ b/src/gui/util/qcompleter.cpp @@ -926,7 +926,7 @@ void QCompleterPrivate::_q_fileSystemModelDirectoryLoaded(const QString &path) // If we hide the popup because there was no match because the model was not loaded yet, // we re-start the completion when we get the results if (hiddenBecauseNoMatch - && prefix.startsWith(path) && prefix != (path + '/') + && prefix.startsWith(path) && prefix != (path + QLatin1Char('/')) && widget) { q->complete(); } diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp index 96860df..8caeb74 100644 --- a/src/gui/util/qdesktopservices_s60.cpp +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -314,7 +314,7 @@ static bool handleUrl(const QUrl &url) if (!url.isValid()) return false; - QString urlString(url.toString()); + QString urlString(url.toEncoded()); TPtrC urlPtr(qt_QString2TPtrC(urlString)); TRAPD( err, handleUrlL(urlPtr)); return err ? false : true; diff --git a/src/gui/util/qflickgesture.cpp b/src/gui/util/qflickgesture.cpp index 8baca07..f87c84c 100644 --- a/src/gui/util/qflickgesture.cpp +++ b/src/gui/util/qflickgesture.cpp @@ -75,6 +75,7 @@ static QMouseEvent *copyMouseEvent(QEvent *e) QMouseEvent *me = static_cast<QMouseEvent *>(e); return new QMouseEvent(me->type(), QPoint(0, 0), me->globalPos(), me->button(), me->buttons(), me->modifiers()); } +#ifndef QT_NO_GRAPHICSVIEW case QEvent::GraphicsSceneMousePress: case QEvent::GraphicsSceneMouseRelease: case QEvent::GraphicsSceneMouseMove: { @@ -103,6 +104,7 @@ static QMouseEvent *copyMouseEvent(QEvent *e) return copy; #endif } +#endif // QT_NO_GRAPHICSVIEW default: return 0; } @@ -216,10 +218,10 @@ public: mouseTarget = 0; } else if (mouseTarget) { // we did send a press, so we need to fake a release now - Qt::MouseButtons mouseButtons = QApplication::mouseButtons(); // release all pressed mouse buttons - /*for (int i = 0; i < 32; ++i) { + /* Qt::MouseButtons mouseButtons = QApplication::mouseButtons(); + for (int i = 0; i < 32; ++i) { if (mouseButtons & (1 << i)) { Qt::MouseButton b = static_cast<Qt::MouseButton>(1 << i); mouseButtons &= ~b; @@ -265,6 +267,7 @@ protected: if (mouseTarget) { sendingEvent = true; +#ifndef QT_NO_GRAPHICSVIEW QGraphicsItem *grabber = 0; if (mouseTarget->parentWidget()) { if (QGraphicsView *gv = qobject_cast<QGraphicsView *>(mouseTarget->parentWidget())) { @@ -281,12 +284,14 @@ protected: qFGDebug() << "QFG: ungrabbing" << grabber; grabber->ungrabMouse(); } +#endif // QT_NO_GRAPHICSVIEW if (me) { QMouseEvent copy(me->type(), mouseTarget->mapFromGlobal(me->globalPos()), me->globalPos(), me->button(), me->buttons(), me->modifiers()); qt_sendSpontaneousEvent(mouseTarget, ©); } +#ifndef QT_NO_GRAPHICSVIEW if (grabber && (flags & RegrabMouseAfterwards)) { // GraphicsView Mouse Handling Workaround #2: // we need to re-grab the mouse after sending a faked mouse @@ -296,6 +301,7 @@ protected: qFGDebug() << "QFG: re-grabbing" << grabber; grabber->grabMouse(); } +#endif sendingEvent = false; } } @@ -357,10 +363,12 @@ QFlickGestureRecognizer::QFlickGestureRecognizer(Qt::MouseButton button) */ QGesture *QFlickGestureRecognizer::create(QObject *target) { +#ifndef QT_NO_GRAPHICSVIEW QGraphicsObject *go = qobject_cast<QGraphicsObject*>(target); if (go && button == Qt::NoButton) { go->setAcceptTouchEvents(true); } +#endif return new QFlickGesture(target, button); } @@ -389,7 +397,9 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, return Ignore; // nothing to do without a scroller? QWidget *receiverWidget = qobject_cast<QWidget *>(d->receiver); +#ifndef QT_NO_GRAPHICSVIEW QGraphicsObject *receiverGraphicsObject = qobject_cast<QGraphicsObject *>(d->receiver); +#endif // this is only set for events that we inject into the event loop via sendEvent() if (PressDelayHandler::instance()->shouldEventBeIgnored(event)) { @@ -398,7 +408,9 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, } const QMouseEvent *me = 0; +#ifndef QT_NO_GRAPHICSVIEW const QGraphicsSceneMouseEvent *gsme = 0; +#endif const QTouchEvent *te = 0; QPoint globalPos; @@ -415,6 +427,7 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, globalPos = me->globalPos(); } break; +#ifndef QT_NO_GRAPHICSVIEW case QEvent::GraphicsSceneMousePress: case QEvent::GraphicsSceneMouseRelease: case QEvent::GraphicsSceneMouseMove: @@ -425,6 +438,7 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, globalPos = gsme->screenPos(); } break; +#endif case QEvent::TouchBegin: case QEvent::TouchEnd: case QEvent::TouchUpdate: @@ -466,7 +480,11 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, break; } - if (!me && !gsme && !te) // Neither mouse nor touch + if (!me +#ifndef QT_NO_GRAPHICSVIEW + && !gsme +#endif + && !te) // Neither mouse nor touch return Ignore; // get the current pointer position in local coordinates. @@ -502,6 +520,7 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, } break; +#ifndef QT_NO_GRAPHICSVIEW case QEvent::GraphicsSceneMousePress: if (gsme && gsme->button() == button && gsme->buttons() == button) { point = gsme->scenePos(); @@ -529,6 +548,7 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, inputType = QScroller::InputMove; } break; +#endif case QEvent::TouchBegin: inputType = QScroller::InputPress; @@ -568,12 +588,14 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, if (QWidget *w = qobject_cast<QWidget *>(as->target())) { scrollerRegion = QRect(w->mapToGlobal(QPoint(0, 0)), w->size()); +#ifndef QT_NO_GRAPHICSVIEW } else if (QGraphicsObject *go = qobject_cast<QGraphicsObject *>(as->target())) { if (go->scene() && !go->scene()->views().isEmpty()) { foreach (QGraphicsView *gv, go->scene()->views()) scrollerRegion |= gv->mapFromScene(go->mapToScene(go->boundingRect())) .translated(gv->mapToGlobal(QPoint(0, 0))); } +#endif } // active scrollers always have priority if (scrollerRegion.contains(globalPos)) @@ -588,8 +610,10 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, if (inputType) { if (QWidget *w = qobject_cast<QWidget *>(d->receiver)) point = w->mapFromGlobal(point.toPoint()); +#ifndef QT_NO_GRAPHICSVIEW else if (QGraphicsObject *go = qobject_cast<QGraphicsObject *>(d->receiver)) point = go->mapFromScene(point); +#endif // inform the scroller about the new event scroller->handleInput(inputType, point, monotonicTimer.elapsed()); @@ -602,7 +626,11 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, // Consume all mouse events while dragging or scrolling to avoid nasty // side effects with Qt's standard widgets. - if ((me || gsme) && scrollerIsActive) + if ((me +#ifndef QT_NO_GRAPHICSVIEW + || gsme +#endif + ) && scrollerIsActive) result |= ConsumeEventHint; // The only problem with this approach is that we consume the @@ -610,7 +638,11 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, // have to fake a MouseRelease "somewhere" to not mess with the internal // states of Qt's widgets (a QPushButton would stay in 'pressed' state // forever, if it doesn't receive a MouseRelease). - if (me || gsme) { + if (me +#ifndef QT_NO_GRAPHICSVIEW + || gsme +#endif + ) { if (!scrollerWasDragging && !scrollerWasScrolling && scrollerIsActive) PressDelayHandler::instance()->scrollerBecameActive(); else if (scrollerWasScrolling && (scroller->state() == QScroller::Dragging || scroller->state() == QScroller::Inactive)) @@ -622,7 +654,9 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, } else { switch (event->type()) { case QEvent::MouseButtonPress: +#ifndef QT_NO_GRAPHICSVIEW case QEvent::GraphicsSceneMousePress: +#endif if (scroller->state() == QScroller::Pressed) { int pressDelay = int(1000 * scroller->scrollerProperties().scrollMetric(QScrollerProperties::MousePressEventDelay).toReal()); if (pressDelay > 0) { @@ -639,7 +673,9 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, break; case QEvent::MouseMove: +#ifndef QT_NO_GRAPHICSVIEW case QEvent::GraphicsSceneMouseMove: +#endif if (PressDelayHandler::instance()->isDelaying()) result |= ConsumeEventHint; // fall through @@ -647,7 +683,9 @@ QGestureRecognizer::Result QFlickGestureRecognizer::recognize(QGesture *state, result |= scrollerIsActive ? TriggerGesture : Ignore; break; +#ifndef QT_NO_GRAPHICSVIEW case QEvent::GraphicsSceneMouseRelease: +#endif case QEvent::MouseButtonRelease: if (PressDelayHandler::instance()->released(event, scrollerWasDragging || scrollerWasScrolling, scrollerIsActive)) result |= ConsumeEventHint; diff --git a/src/gui/util/qscroller.cpp b/src/gui/util/qscroller.cpp index ac5607c..870d56f 100644 --- a/src/gui/util/qscroller.cpp +++ b/src/gui/util/qscroller.cpp @@ -192,6 +192,7 @@ static qreal progressForValue(const QEasingCurve &curve, qreal value) } +#ifndef QT_NO_ANIMATION class QScrollTimer : public QAbstractAnimation { public: @@ -230,6 +231,7 @@ private: bool ignoreUpdate; int skip; }; +#endif // QT_NO_ANIMATION /*! \class QScroller @@ -277,9 +279,11 @@ private: \sa QScrollEvent, QScrollPrepareEvent, QScrollerProperties */ +typedef QMap<QObject *, QScroller *> ScrollerHash; +typedef QSet<QScroller *> ScrollerSet; -QMap<QObject *, QScroller *> QScrollerPrivate::allScrollers; -QSet<QScroller *> QScrollerPrivate::activeScrollers; +Q_GLOBAL_STATIC(ScrollerHash, qt_allScrollers) +Q_GLOBAL_STATIC(ScrollerSet, qt_activeScrollers) /*! Returns \c true if a QScroller object was already created for \a target; \c false otherwise. @@ -288,7 +292,7 @@ QSet<QScroller *> QScrollerPrivate::activeScrollers; */ bool QScroller::hasScroller(QObject *target) { - return (QScrollerPrivate::allScrollers.value(target)); + return (qt_allScrollers()->value(target)); } /*! @@ -306,11 +310,11 @@ QScroller *QScroller::scroller(QObject *target) return 0; } - if (QScrollerPrivate::allScrollers.contains(target)) - return QScrollerPrivate::allScrollers.value(target); + if (qt_allScrollers()->contains(target)) + return qt_allScrollers()->value(target); QScroller *s = new QScroller(target); - QScrollerPrivate::allScrollers.insert(target, s); + qt_allScrollers()->insert(target, s); return s; } @@ -330,7 +334,7 @@ const QScroller *QScroller::scroller(const QObject *target) */ QList<QScroller *> QScroller::activeScrollers() { - return QScrollerPrivate::activeScrollers.toList(); + return qt_activeScrollers()->toList(); } /*! @@ -376,6 +380,7 @@ void QScroller::setScrollerProperties(const QScrollerProperties &sp) } } +#ifndef QT_NO_GESTURES /*! Registers a custom scroll gesture recognizer, grabs it for the \a @@ -426,11 +431,12 @@ Qt::GestureType QScroller::grabGesture(QObject *target, ScrollerGestureType scro widget->grabGesture(sp->recognizerType); if (scrollGestureType == TouchGesture) widget->setAttribute(Qt::WA_AcceptTouchEvents); - +#ifndef QT_NO_GRAPHICSVIEW } else if (QGraphicsObject *go = qobject_cast<QGraphicsObject*>(target)) { if (scrollGestureType == TouchGesture) go->setAcceptTouchEvents(true); go->grabGesture(sp->recognizerType); +#endif // QT_NO_GRAPHICSVIEW } return sp->recognizerType; } @@ -469,9 +475,10 @@ void QScroller::ungrabGesture(QObject *target) if (target->isWidgetType()) { QWidget *widget = static_cast<QWidget *>(target); widget->ungrabGesture(sp->recognizerType); - +#ifndef QT_NO_GRAPHICSVIEW } else if (QGraphicsObject *go = qobject_cast<QGraphicsObject*>(target)) { go->ungrabGesture(sp->recognizerType); +#endif } QGestureRecognizer::unregisterRecognizer(sp->recognizerType); @@ -479,6 +486,8 @@ void QScroller::ungrabGesture(QObject *target) sp->recognizer = 0; } +#endif // QT_NO_GESTURES + /*! \internal */ @@ -496,11 +505,13 @@ QScroller::QScroller(QObject *target) QScroller::~QScroller() { Q_D(QScroller); +#ifndef QT_NO_GESTURES QGestureRecognizer::unregisterRecognizer(d->recognizerType); // do not delete the recognizer. The QGestureManager is doing this. d->recognizer = 0; - QScrollerPrivate::allScrollers.remove(d->target); - QScrollerPrivate::activeScrollers.remove(this); +#endif + qt_allScrollers()->remove(d->target); + qt_activeScrollers()->remove(this); delete d_ptr; } @@ -562,6 +573,7 @@ QPointF QScroller::pixelPerMeter() const Q_D(const QScroller); QPointF ppm = d->pixelPerMeter; +#ifndef QT_NO_GRAPHICSVIEW if (QGraphicsObject *go = qobject_cast<QGraphicsObject *>(d->target)) { QTransform viewtr; //TODO: the first view isn't really correct - maybe use an additional field in the prepare event? @@ -576,6 +588,7 @@ QPointF QScroller::pixelPerMeter() const ppm.ry() /= QLineF(p0, py).length(); } } +#endif // QT_NO_GRAPHICSVIEW return ppm; } @@ -869,8 +882,10 @@ void QScroller::setSnapPositionsY(qreal first, qreal interval) QScrollerPrivate::QScrollerPrivate(QScroller *q, QObject *_target) : target(_target) +#ifndef QT_NO_GESTURES , recognizer(0) , recognizerType(Qt::CustomGesture) +#endif , state(QScroller::Inactive) , firstScroll(true) , pressTimestamp(0) @@ -879,7 +894,9 @@ QScrollerPrivate::QScrollerPrivate(QScroller *q, QObject *_target) , snapIntervalX(0.0) , snapFirstY(-1.0) , snapIntervalY(0.0) +#ifndef QT_NO_ANIMATION , scrollTimer(new QScrollTimer(this)) +#endif , q_ptr(q) { connect(target, SIGNAL(destroyed(QObject*)), this, SLOT(targetDestroyed())); @@ -919,7 +936,9 @@ const char *QScrollerPrivate::inputName(QScroller::Input input) void QScrollerPrivate::targetDestroyed() { +#ifndef QT_NO_ANIMATION scrollTimer->stop(); +#endif delete q_ptr; } @@ -945,7 +964,9 @@ void QScrollerPrivate::timerTick() } } +#ifndef QT_NO_ANIMATION scrollTimer->stop(); +#endif } /*! @@ -1436,11 +1457,13 @@ bool QScrollerPrivate::prepareScrolling(const QPointF &position) if (QWidget *w = qobject_cast<QWidget *>(target)) setDpiFromWidget(w); +#ifndef QT_NO_GRAPHICSVIEW if (QGraphicsObject *go = qobject_cast<QGraphicsObject *>(target)) { //TODO: the first view isn't really correct - maybe use an additional field in the prepare event? if (go->scene() && !go->scene()->views().isEmpty()) setDpiFromWidget(go->scene()->views().first()); } +#endif if (state == QScroller::Scrolling) { recalcScrollingSegments(); @@ -1690,7 +1713,9 @@ void QScrollerPrivate::setState(QScroller::State newstate) switch (newstate) { case QScroller::Inactive: +#ifndef QT_NO_ANIMATION scrollTimer->stop(); +#endif // send the last scroll event (but only after the current state change was finished) if (!firstScroll) @@ -1700,7 +1725,9 @@ void QScrollerPrivate::setState(QScroller::State newstate) break; case QScroller::Pressed: +#ifndef QT_NO_ANIMATION scrollTimer->stop(); +#endif oldVelocity = releaseVelocity; releaseVelocity = QPointF(0, 0); @@ -1708,12 +1735,16 @@ void QScrollerPrivate::setState(QScroller::State newstate) case QScroller::Dragging: dragDistance = QPointF(0, 0); +#ifndef QT_NO_ANIMATION if (state == QScroller::Pressed) scrollTimer->start(); +#endif break; case QScroller::Scrolling: +#ifndef QT_NO_ANIMATION scrollTimer->start(); +#endif break; } @@ -1725,9 +1756,9 @@ void QScrollerPrivate::setState(QScroller::State newstate) firstScroll = true; } if (state == QScroller::Dragging || state == QScroller::Scrolling) - activeScrollers.insert(q); + qt_activeScrollers()->insert(q); else - activeScrollers.remove(q); + qt_activeScrollers()->remove(q); emit q->stateChanged(state); } @@ -1746,10 +1777,7 @@ void QScrollerPrivate::setState(QScroller::State newstate) */ void QScrollerPrivate::setContentPositionHelperDragging(const QPointF &deltaPos) { - Q_Q(QScroller); - QPointF ppm = q->pixelPerMeter(); const QScrollerPropertiesPrivate *sp = properties.d.data(); - QPointF v = q->velocity(); if (sp->overshootDragResistanceFactor) overshootPosition /= sp->overshootDragResistanceFactor; diff --git a/src/gui/util/qscroller.h b/src/gui/util/qscroller.h index a026be4..1599c7d 100644 --- a/src/gui/util/qscroller.h +++ b/src/gui/util/qscroller.h @@ -55,8 +55,10 @@ QT_MODULE(Gui) class QWidget; class QScrollerPrivate; class QScrollerProperties; +#ifndef QT_NO_GESTURES class QFlickGestureRecognizer; class QMouseFlickGestureRecognizer; +#endif class Q_GUI_EXPORT QScroller : public QObject { @@ -94,9 +96,11 @@ public: static QScroller *scroller(QObject *target); static const QScroller *scroller(const QObject *target); +#ifndef QT_NO_GESTURES static Qt::GestureType grabGesture(QObject *target, ScrollerGestureType gestureType = TouchGesture); static Qt::GestureType grabbedGesture(QObject *target); static void ungrabGesture(QObject *target); +#endif static QList<QScroller *> activeScrollers(); @@ -139,7 +143,9 @@ private: Q_DISABLE_COPY(QScroller) Q_DECLARE_PRIVATE(QScroller) +#ifndef QT_NO_GESTURES friend class QFlickGestureRecognizer; +#endif }; QT_END_NAMESPACE diff --git a/src/gui/util/qscroller_p.h b/src/gui/util/qscroller_p.h index fb2b257..c119615 100644 --- a/src/gui/util/qscroller_p.h +++ b/src/gui/util/qscroller_p.h @@ -69,10 +69,13 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_GESTURES class QFlickGestureRecognizer; +#endif +#ifndef QT_NO_ANIMATION class QScrollTimer; - +#endif class QScrollerPrivate : public QObject { Q_OBJECT @@ -145,15 +148,13 @@ public slots: void targetDestroyed(); public: - // static - static QMap<QObject *, QScroller *> allScrollers; - static QSet<QScroller *> activeScrollers; - // non static QObject *target; QScrollerProperties properties; +#ifndef QT_NO_GESTURES QFlickGestureRecognizer *recognizer; Qt::GestureType recognizerType; +#endif // scroller state: @@ -194,7 +195,9 @@ public: QElapsedTimer monotonicTimer; QPointF releaseVelocity; // the starting velocity of the scrolling state +#ifndef QT_NO_ANIMATION QScrollTimer *scrollTimer; +#endif QScroller *q_ptr; }; diff --git a/src/gui/util/qundogroup.cpp b/src/gui/util/qundogroup.cpp index 42cda74..a24ce8d 100644 --- a/src/gui/util/qundogroup.cpp +++ b/src/gui/util/qundogroup.cpp @@ -375,15 +375,18 @@ bool QUndoGroup::isClean() const for undo, if the group is empty or if none of the stacks are active, this action will be disabled. - If \a prefix is empty, the default prefix "Undo" is used. + If \a prefix is empty, the default template "Undo %1" is used instead of prefix. + Before Qt 4.8, the prefix "Undo" was used by default. \sa createRedoAction() canUndo() QUndoCommand::text() */ QAction *QUndoGroup::createUndoAction(QObject *parent, const QString &prefix) const { - QString pref = prefix.isEmpty() ? tr("Undo") : prefix; - QUndoAction *result = new QUndoAction(pref, parent); + QUndoAction *result = new QUndoAction(prefix, parent); + if (prefix.isEmpty()) + result->setTextFormat(tr("Undo %1"), tr("Undo", "Default text for undo action")); + result->setEnabled(canUndo()); result->setPrefixedText(undoText()); connect(this, SIGNAL(canUndoChanged(bool)), @@ -403,15 +406,18 @@ QAction *QUndoGroup::createUndoAction(QObject *parent, const QString &prefix) co for redo, if the group is empty or if none of the stacks are active, this action will be disabled. - If \a prefix is empty, the default prefix "Undo" is used. + If \a prefix is empty, the default template "Redo %1" is used instead of prefix. + Before Qt 4.8, the prefix "Redo" was used by default. \sa createUndoAction() canRedo() QUndoCommand::text() */ QAction *QUndoGroup::createRedoAction(QObject *parent, const QString &prefix) const { - QString pref = prefix.isEmpty() ? tr("Redo") : prefix; - QUndoAction *result = new QUndoAction(pref, parent); + QUndoAction *result = new QUndoAction(prefix, parent); + if (prefix.isEmpty()) + result->setTextFormat(tr("Redo %1"), tr("Redo", "Default text for redo action")); + result->setEnabled(canRedo()); result->setPrefixedText(redoText()); connect(this, SIGNAL(canRedoChanged(bool)), diff --git a/src/gui/util/qundostack.cpp b/src/gui/util/qundostack.cpp index 6b038ee..1dfab5d 100644 --- a/src/gui/util/qundostack.cpp +++ b/src/gui/util/qundostack.cpp @@ -114,7 +114,7 @@ QUndoCommand::QUndoCommand(const QString &text, QUndoCommand *parent) d = new QUndoCommandPrivate; if (parent != 0) parent->d->child_list.append(this); - d->text = text; + setText(text); } /*! @@ -230,10 +230,9 @@ void QUndoCommand::undo() Returns a short text string describing what this command does; for example, "insert text". - The text is used when the text properties of the stack's undo and redo - actions are updated. + The text is used for names of items in QUndoView. - \sa setText(), QUndoStack::createUndoAction(), QUndoStack::createRedoAction() + \sa actionText(), setText(), QUndoStack::createUndoAction(), QUndoStack::createRedoAction() */ QString QUndoCommand::text() const @@ -242,17 +241,47 @@ QString QUndoCommand::text() const } /*! + \since 4.8 + + Returns a short text string describing what this command does; for example, + "insert text". + + The text is used when the text properties of the stack's undo and redo + actions are updated. + + \sa text(), setText(), QUndoStack::createUndoAction(), QUndoStack::createRedoAction() +*/ + +QString QUndoCommand::actionText() const +{ + return d->actionText; +} + +/*! Sets the command's text to be the \a text specified. The specified text should be a short user-readable string describing what this command does. - \sa text() QUndoStack::createUndoAction() QUndoStack::createRedoAction() + If you need to have two different strings for text() and actionText(), separate + them with "\n" and pass into this function. Even if you do not use this feature + for English strings during development, you can still let translators use two + different strings in order to match specific languages' needs. + The described feature and the function actionText() are available since Qt 4.8. + + \sa text() actionText() QUndoStack::createUndoAction() QUndoStack::createRedoAction() */ void QUndoCommand::setText(const QString &text) { - d->text = text; + int cdpos = text.indexOf(QLatin1Char('\n')); + if (cdpos > 0) { + d->text = text.left(cdpos); + d->actionText = text.mid(cdpos + 1); + } else { + d->text = text; + d->actionText = text; + } } /*! @@ -374,11 +403,24 @@ QUndoAction::QUndoAction(const QString &prefix, QObject *parent) void QUndoAction::setPrefixedText(const QString &text) { - QString s = m_prefix; - if (!m_prefix.isEmpty() && !text.isEmpty()) - s.append(QLatin1Char(' ')); - s.append(text); - setText(s); + if (m_defaultText.isEmpty()) { + QString s = m_prefix; + if (!m_prefix.isEmpty() && !text.isEmpty()) + s.append(QLatin1Char(' ')); + s.append(text); + setText(s); + } else { + if (text.isEmpty()) + setText(m_defaultText); + else + setText(m_prefix.arg(text)); + } +} + +void QUndoAction::setTextFormat(const QString &textFormat, const QString &defaultText) +{ + m_prefix = textFormat; + m_defaultText = defaultText; } #endif // QT_NO_ACTION @@ -783,7 +825,7 @@ bool QUndoStack::canRedo() const /*! Returns the text of the command which will be undone in the next call to undo(). - \sa QUndoCommand::text() redoText() + \sa QUndoCommand::actionText() redoText() */ QString QUndoStack::undoText() const @@ -792,14 +834,14 @@ QString QUndoStack::undoText() const if (!d->macro_stack.isEmpty()) return QString(); if (d->index > 0) - return d->command_list.at(d->index - 1)->text(); + return d->command_list.at(d->index - 1)->actionText(); return QString(); } /*! Returns the text of the command which will be redone in the next call to redo(). - \sa QUndoCommand::text() undoText() + \sa QUndoCommand::actionText() undoText() */ QString QUndoStack::redoText() const @@ -808,7 +850,7 @@ QString QUndoStack::redoText() const if (!d->macro_stack.isEmpty()) return QString(); if (d->index < d->command_list.size()) - return d->command_list.at(d->index)->text(); + return d->command_list.at(d->index)->actionText(); return QString(); } @@ -822,15 +864,18 @@ QString QUndoStack::redoText() const prefixed by the specified \a prefix. If there is no command available for undo, this action will be disabled. - If \a prefix is empty, the default prefix "Undo" is used. + If \a prefix is empty, the default template "Undo %1" is used instead of prefix. + Before Qt 4.8, the prefix "Undo" was used by default. \sa createRedoAction(), canUndo(), QUndoCommand::text() */ QAction *QUndoStack::createUndoAction(QObject *parent, const QString &prefix) const { - QString pref = prefix.isEmpty() ? tr("Undo") : prefix; - QUndoAction *result = new QUndoAction(pref, parent); + QUndoAction *result = new QUndoAction(prefix, parent); + if (prefix.isEmpty()) + result->setTextFormat(tr("Undo %1"), tr("Undo", "Default text for undo action")); + result->setEnabled(canUndo()); result->setPrefixedText(undoText()); connect(this, SIGNAL(canUndoChanged(bool)), @@ -849,15 +894,18 @@ QAction *QUndoStack::createUndoAction(QObject *parent, const QString &prefix) co prefixed by the specified \a prefix. If there is no command available for redo, this action will be disabled. - If \a prefix is empty, the default prefix "Redo" is used. + If \a prefix is empty, the default template "Redo %1" is used instead of prefix. + Before Qt 4.8, the prefix "Redo" was used by default. \sa createUndoAction(), canRedo(), QUndoCommand::text() */ QAction *QUndoStack::createRedoAction(QObject *parent, const QString &prefix) const { - QString pref = prefix.isEmpty() ? tr("Redo") : prefix; - QUndoAction *result = new QUndoAction(pref, parent); + QUndoAction *result = new QUndoAction(prefix, parent); + if (prefix.isEmpty()) + result->setTextFormat(tr("Redo %1"), tr("Redo", "Default text for redo action")); + result->setEnabled(canRedo()); result->setPrefixedText(redoText()); connect(this, SIGNAL(canRedoChanged(bool)), diff --git a/src/gui/util/qundostack.h b/src/gui/util/qundostack.h index 65941b5..700996f 100644 --- a/src/gui/util/qundostack.h +++ b/src/gui/util/qundostack.h @@ -70,6 +70,7 @@ public: virtual void redo(); QString text() const; + QString actionText() const; void setText(const QString &text); virtual int id() const; diff --git a/src/gui/util/qundostack_p.h b/src/gui/util/qundostack_p.h index 3c7d0e7..a100763 100644 --- a/src/gui/util/qundostack_p.h +++ b/src/gui/util/qundostack_p.h @@ -70,6 +70,7 @@ public: QUndoCommandPrivate() : id(-1) {} QList<QUndoCommand*> child_list; QString text; + QString actionText; int id; }; @@ -98,10 +99,12 @@ class QUndoAction : public QAction Q_OBJECT public: QUndoAction(const QString &prefix, QObject *parent = 0); + void setTextFormat(const QString &textFormat, const QString &defaultText); public Q_SLOTS: void setPrefixedText(const QString &text); private: QString m_prefix; + QString m_defaultText; }; #endif // QT_NO_ACTION diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp index 7460f32..dabfec0 100644 --- a/src/gui/widgets/qabstractscrollarea.cpp +++ b/src/gui/widgets/qabstractscrollarea.cpp @@ -511,7 +511,7 @@ QAbstractScrollArea::QAbstractScrollArea(QAbstractScrollAreaPrivate &dd, QWidget /*! Constructs a viewport. - The \a parent arguments is sent to the QWidget constructor. + The \a parent argument is sent to the QWidget constructor. */ QAbstractScrollArea::QAbstractScrollArea(QWidget *parent) :QFrame(*new QAbstractScrollAreaPrivate, parent) @@ -1386,6 +1386,7 @@ bool QAbstractScrollAreaPrivate::canStartScrollingAt( const QPoint &startPos ) { Q_Q(QAbstractScrollArea); +#ifndef QT_NO_GRAPHICSVIEW // don't start scrolling when a drag mode has been set. // don't start scrolling on a movable item. if (QGraphicsView *view = qobject_cast<QGraphicsView *>(q)) { @@ -1397,6 +1398,7 @@ bool QAbstractScrollAreaPrivate::canStartScrollingAt( const QPoint &startPos ) if (childItem && (childItem->flags() & QGraphicsItem::ItemIsMovable)) return false; } +#endif // don't start scrolling on a QAbstractSlider if (qobject_cast<QAbstractSlider *>(q->viewport()->childAt(startPos))) { diff --git a/src/gui/widgets/qabstractslider.cpp b/src/gui/widgets/qabstractslider.cpp index cb36398..2570496 100644 --- a/src/gui/widgets/qabstractslider.cpp +++ b/src/gui/widgets/qabstractslider.cpp @@ -265,7 +265,7 @@ void QAbstractSliderPrivate::setSteps(int single, int page) /*! Constructs an abstract slider. - The \a parent arguments is sent to the QWidget constructor. + The \a parent argument is sent to the QWidget constructor. The \l minimum defaults to 0, the \l maximum to 99, with a \l singleStep size of 1 and a \l pageStep size of 10, and an initial diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index b5dda5a..dd1ad9c 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -399,7 +399,7 @@ void QComboBoxPrivateContainer::leaveEvent(QEvent *) #ifdef Q_WS_MAC QStyleOptionComboBox opt = comboStyleOption(); if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) - view->setCurrentIndex(QModelIndex()); + view->clearSelection(); #endif } @@ -672,8 +672,8 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive()) blockMouseReleaseTimer.stop(); QModelIndex indexUnderMouse = view->indexAt(m->pos()); - if (indexUnderMouse.isValid() && indexUnderMouse != view->currentIndex() - && !QComboBoxDelegate::isSeparator(indexUnderMouse)) { + if (indexUnderMouse.isValid() + && !QComboBoxDelegate::isSeparator(indexUnderMouse)) { view->setCurrentIndex(indexUnderMouse); } } @@ -705,11 +705,13 @@ void QComboBoxPrivateContainer::hideEvent(QHideEvent *) { emit resetButton(); combo->update(); +#ifndef QT_NO_GRAPHICSVIEW // 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(); +#endif } void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e) @@ -945,7 +947,10 @@ QComboBox::QComboBox(bool rw, QWidget *parent, const char *name) to set and get item data (e.g., setItemData() and itemText()). You can also set a new model and view (with setModel() and setView()). For the text and icon in the combobox label, the data in the model - that has the Qt::DisplayRole and Qt::DecorationRole is used. + that has the Qt::DisplayRole and Qt::DecorationRole is used. Note + that you cannot alter the \l{QAbstractItemView::}{SelectionMode} + of the view(), e.g., by using + \l{QAbstractItemView::}{setSelectionMode()}. \image qstyle-comboboxes.png Comboboxes in the different built-in styles. @@ -2358,7 +2363,12 @@ void QComboBox::showPopup() initStyleOption(&opt); QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxListBoxPopup, this)); +#ifndef Q_WS_S60 QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); +#else + QRect screen = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect()); +#endif + QPoint below = mapToGlobal(listRect.bottomLeft()); int belowHeight = screen.bottom() - below.y(); QPoint above = mapToGlobal(listRect.topLeft()); @@ -2463,12 +2473,7 @@ void QComboBox::showPopup() // available screen geometry.This may override the vertical position, but it is more // important to show as much as possible of the popup. const int height = !boundToScreen ? listRect.height() : qMin(listRect.height(), screen.height()); -#ifdef Q_WS_S60 - //popup needs to be stretched with screen minimum dimension - listRect.setHeight(qMin(screen.height(), screen.width())); -#else listRect.setHeight(height); -#endif if (boundToScreen) { if (listRect.top() < screen.top()) @@ -2486,18 +2491,10 @@ void QComboBox::showPopup() listRect.setWidth(listRect.height()); //by default popup is centered on screen in landscape listRect.moveCenter(screen.center()); - if (staConTopRect.IsEmpty()) { - TRect cbaRect = TRect(); - AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, cbaRect); - AknLayoutUtils::TAknCbaLocation cbaLocation = AknLayoutUtils::CbaLocation(); - switch (cbaLocation) { - case AknLayoutUtils::EAknCbaLocationRight: - listRect.setRight(screen.right()); - break; - case AknLayoutUtils::EAknCbaLocationLeft: - listRect.setLeft(screen.left()); - break; - } + if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) { + // landscape without stacon, menu should be at the right + (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) : + listRect.setLeft(screen.left()); } } #endif @@ -2716,7 +2713,7 @@ void QComboBox::changeEvent(QEvent *e) initStyleOption(&opt); if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) { - const QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this)); + QRect screen = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect()); QRect listRect(style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxListBoxPopup, this)); @@ -2731,13 +2728,14 @@ void QComboBox::changeEvent(QEvent *e) listRect.setWidth(listRect.height()); //by default popup is centered on screen in landscape listRect.moveCenter(screen.center()); - if (staConTopRect.IsEmpty()) { + if (staConTopRect.IsEmpty() && AknLayoutUtils::CbaLocation() != AknLayoutUtils::EAknCbaLocationBottom) { // landscape without stacon, menu should be at the right (opt.direction == Qt::LeftToRight) ? listRect.setRight(screen.right()) : listRect.setLeft(screen.left()); } - d->container->setGeometry(listRect); } + + d->container->setGeometry(listRect); } } #endif @@ -2770,6 +2768,10 @@ void QComboBox::changeEvent(QEvent *e) void QComboBox::resizeEvent(QResizeEvent *) { Q_D(QComboBox); +#ifdef Q_WS_S60 + if (d->viewContainer() && d->viewContainer()->isVisible()) + showPopup(); +#endif d->updateLineEditGeometry(); } diff --git a/src/gui/widgets/qdatetimeedit.cpp b/src/gui/widgets/qdatetimeedit.cpp index 6337113..a4739a7 100644 --- a/src/gui/widgets/qdatetimeedit.cpp +++ b/src/gui/widgets/qdatetimeedit.cpp @@ -2538,20 +2538,32 @@ void QDateTimeEditPrivate::syncCalendarWidget() } QCalendarPopup::QCalendarPopup(QWidget * parent, QCalendarWidget *cw) - : QWidget(parent, Qt::Popup), calendar(0) + : QWidget(parent, Qt::Popup) { setAttribute(Qt::WA_WindowPropagation); dateChanged = false; if (!cw) { - cw = new QCalendarWidget(this); + verifyCalendarInstance(); + } else { + setCalendarWidget(cw); + } +} + +QCalendarWidget *QCalendarPopup::verifyCalendarInstance() +{ + if (calendar.isNull()) { + QCalendarWidget *cw = new QCalendarWidget(this); cw->setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader); #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled()) cw->setHorizontalHeaderFormat(QCalendarWidget::SingleLetterDayNames); #endif + setCalendarWidget(cw); + return cw; + } else { + return calendar.data(); } - setCalendarWidget(cw); } void QCalendarPopup::setCalendarWidget(QCalendarWidget *cw) @@ -2563,28 +2575,29 @@ void QCalendarPopup::setCalendarWidget(QCalendarWidget *cw) widgetLayout->setMargin(0); widgetLayout->setSpacing(0); } - delete calendar; - calendar = cw; - widgetLayout->addWidget(calendar); + delete calendar.data(); + calendar = QWeakPointer<QCalendarWidget>(cw); + widgetLayout->addWidget(cw); - connect(calendar, SIGNAL(activated(QDate)), this, SLOT(dateSelected(QDate))); - connect(calendar, SIGNAL(clicked(QDate)), this, SLOT(dateSelected(QDate))); - connect(calendar, SIGNAL(selectionChanged()), this, SLOT(dateSelectionChanged())); + connect(cw, SIGNAL(activated(QDate)), this, SLOT(dateSelected(QDate))); + connect(cw, SIGNAL(clicked(QDate)), this, SLOT(dateSelected(QDate))); + connect(cw, SIGNAL(selectionChanged()), this, SLOT(dateSelectionChanged())); - calendar->setFocus(); + cw->setFocus(); } void QCalendarPopup::setDate(const QDate &date) { oldDate = date; - calendar->setSelectedDate(date); + verifyCalendarInstance()->setSelectedDate(date); } void QCalendarPopup::setDateRange(const QDate &min, const QDate &max) { - calendar->setMinimumDate(min); - calendar->setMaximumDate(max); + QCalendarWidget *cw = verifyCalendarInstance(); + cw->setMinimumDate(min); + cw->setMaximumDate(max); } void QCalendarPopup::mousePressEvent(QMouseEvent *event) @@ -2620,7 +2633,7 @@ bool QCalendarPopup::event(QEvent *event) void QCalendarPopup::dateSelectionChanged() { dateChanged = true; - emit newDateSelected(calendar->selectedDate()); + emit newDateSelected(verifyCalendarInstance()->selectedDate()); } void QCalendarPopup::dateSelected(const QDate &date) { diff --git a/src/gui/widgets/qdatetimeedit_p.h b/src/gui/widgets/qdatetimeedit_p.h index acdc878..c85c0fb 100644 --- a/src/gui/widgets/qdatetimeedit_p.h +++ b/src/gui/widgets/qdatetimeedit_p.h @@ -148,11 +148,11 @@ class QCalendarPopup : public QWidget Q_OBJECT public: QCalendarPopup(QWidget *parent = 0, QCalendarWidget *cw = 0); - QDate selectedDate() { return calendar->selectedDate(); } + QDate selectedDate() { return verifyCalendarInstance()->selectedDate(); } void setDate(const QDate &date); void setDateRange(const QDate &min, const QDate &max); - void setFirstDayOfWeek(Qt::DayOfWeek dow) { calendar->setFirstDayOfWeek(dow); } - QCalendarWidget *calendarWidget() const { return calendar; } + void setFirstDayOfWeek(Qt::DayOfWeek dow) { verifyCalendarInstance()->setFirstDayOfWeek(dow); } + QCalendarWidget *calendarWidget() const { return const_cast<QCalendarPopup*>(this)->verifyCalendarInstance(); } void setCalendarWidget(QCalendarWidget *cw); Q_SIGNALS: void activated(const QDate &date); @@ -171,7 +171,9 @@ protected: bool event(QEvent *e); private: - QCalendarWidget *calendar; + QCalendarWidget *verifyCalendarInstance(); + + QWeakPointer<QCalendarWidget> calendar; QDate oldDate; bool dateChanged; }; diff --git a/src/gui/widgets/qdockarealayout.cpp b/src/gui/widgets/qdockarealayout.cpp index 223421d..28c0388 100644 --- a/src/gui/widgets/qdockarealayout.cpp +++ b/src/gui/widgets/qdockarealayout.cpp @@ -2100,7 +2100,6 @@ bool QDockAreaLayoutInfo::updateTabBar() const bool gap = false; int tab_idx = 0; - bool changed = false; for (int i = 0; i < item_list.count(); ++i) { const QDockAreaLayoutItem &item = item_list.at(i); if (item.skip()) @@ -2121,7 +2120,6 @@ bool QDockAreaLayoutInfo::updateTabBar() const tabBar->setTabToolTip(tab_idx, title); #endif tabBar->setTabData(tab_idx, id); - changed = true; } else if (qvariant_cast<quintptr>(tabBar->tabData(tab_idx)) != id) { if (tab_idx + 1 < tabBar->count() && qvariant_cast<quintptr>(tabBar->tabData(tab_idx + 1)) == id) @@ -2133,7 +2131,6 @@ bool QDockAreaLayoutInfo::updateTabBar() const #endif tabBar->setTabData(tab_idx, id); } - changed = true; } if (title != tabBar->tabText(tab_idx)) { @@ -2141,7 +2138,6 @@ bool QDockAreaLayoutInfo::updateTabBar() const #ifndef QT_NO_TOOLTIP tabBar->setTabToolTip(tab_idx, title); #endif - changed = true; } ++tab_idx; @@ -2149,7 +2145,6 @@ bool QDockAreaLayoutInfo::updateTabBar() const while (tab_idx < tabBar->count()) { tabBar->removeTab(tab_idx); - changed = true; } tabBar->blockSignals(blocked); diff --git a/src/gui/widgets/qdockwidget.cpp b/src/gui/widgets/qdockwidget.cpp index 9d1a737..16b60c8 100644 --- a/src/gui/widgets/qdockwidget.cpp +++ b/src/gui/widgets/qdockwidget.cpp @@ -161,7 +161,6 @@ void QDockWidgetTitleButton::paintEvent(QPaintEvent *) { QPainter p(this); - QRect r = rect(); QStyleOptionToolButton opt; opt.init(this); opt.state |= QStyle::State_AutoRaise; diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 3eac64a..4fb0f0c 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -254,12 +254,20 @@ void QLineControl::setSelection(int start, int length) m_selstart = start; m_selend = qMin(start + length, (int)m_text.length()); m_cursor = m_selend; - } else { + } else if (length < 0){ if (start == m_selend && start + length == m_selstart) return; m_selstart = qMax(start + length, 0); m_selend = start; m_cursor = m_selstart; + } else if (m_selstart != m_selend) { + m_selstart = 0; + m_selend = 0; + m_cursor = start; + } else { + m_cursor = start; + emitCursorPositionChanged(); + return; } emit selectionChanged(); emitCursorPositionChanged(); @@ -435,7 +443,7 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) removeSelectedText(); } if (!event->commitString().isEmpty()) { - insert(event->commitString()); + internalInsert(event->commitString()); cursorPositionChanged = true; } @@ -643,7 +651,12 @@ void QLineControl::internalSetText(const QString &txt, int pos, bool edited) m_modifiedState = m_undoState = 0; m_cursor = (pos < 0 || pos > m_text.length()) ? m_text.length() : pos; m_textDirty = (oldText != m_text); - finishChange(-1, true, edited); + bool changed = finishChange(-1, true, edited); + +#ifndef QT_NO_ACCESSIBILITY + if (changed) + QAccessible::updateAccessibility(parent(), 0, QAccessible::TextUpdated); +#endif } @@ -1230,6 +1243,9 @@ void QLineControl::emitCursorPositionChanged() const int oldLast = m_lastCursorPos; m_lastCursorPos = m_cursor; cursorPositionChanged(oldLast, m_cursor); +#ifndef QT_NO_ACCESSIBILITY + QAccessible::updateAccessibility(parent(), 0, QAccessible::TextCaretMoved); +#endif } } @@ -1577,6 +1593,7 @@ void QLineControl::processKeyEvent(QKeyEvent* event) } bool unknown = false; + bool visual = cursorMoveStyle() == QTextCursor::Visual; if (false) { } @@ -1641,11 +1658,11 @@ void QLineControl::processKeyEvent(QKeyEvent* event) #endif moveCursor(selectionEnd(), false); } else { - cursorForward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1); + cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1)); } } else if (event == QKeySequence::SelectNextChar) { - cursorForward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1); + cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1)); } else if (event == QKeySequence::MoveToPreviousChar) { #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) @@ -1656,11 +1673,11 @@ void QLineControl::processKeyEvent(QKeyEvent* event) #endif moveCursor(selectionStart(), false); } else { - cursorForward(0, layoutDirection() == Qt::LeftToRight ? -1 : 1); + cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1)); } } else if (event == QKeySequence::SelectPreviousChar) { - cursorForward(1, layoutDirection() == Qt::LeftToRight ? -1 : 1); + cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1)); } else if (event == QKeySequence::MoveToNextWord) { if (echoMode() == QLineEdit::Normal) diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index 3c505c8..0655276 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -61,10 +61,10 @@ #include "QtGui/qtextlayout.h" #include "QtGui/qstyleoption.h" #include "QtCore/qpointer.h" -#include "QtGui/qlineedit.h" #include "QtGui/qclipboard.h" #include "QtCore/qpoint.h" #include "QtGui/qcompleter.h" +#include "QtGui/qaccessible.h" QT_BEGIN_HEADER @@ -160,6 +160,8 @@ public: int cursorWidth() const { return m_cursorWidth; } void setCursorWidth(int value) { m_cursorWidth = value; } + QTextCursor::MoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); } + void setCursorMoveStyle(QTextCursor::MoveStyle style) { m_textLayout.setCursorMoveStyle(style); } void moveCursor(int pos, bool mark = false); void cursorForward(bool mark, int steps) @@ -167,10 +169,12 @@ public: int c = m_cursor; if (steps > 0) { while (steps--) - c = m_textLayout.nextCursorPosition(c); + c = cursorMoveStyle() == QTextCursor::Visual ? m_textLayout.rightCursorPosition(c) + : m_textLayout.nextCursorPosition(c); } else if (steps < 0) { while (steps++) - c = m_textLayout.previousCursorPosition(c); + c = cursorMoveStyle() == QTextCursor::Visual ? m_textLayout.leftCursorPosition(c) + : m_textLayout.previousCursorPosition(c); } moveCursor(c, mark); } diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 07bd273..43c3f52 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1112,6 +1112,34 @@ void QLineEdit::setDragEnabled(bool b) /*! + \property QLineEdit::cursorMoveStyle + \brief the movement style of cursor in this line edit + \since 4.8 + + When this property is set to QTextCursor::Visual, the line edit will use visual + movement style. Pressing the left arrow key will always cause the cursor to move + left, regardless of the text's writing direction. The same behavior applies to + right arrow key. + + When the property is QTextCursor::Logical (the default), within a LTR text block, + increase cursor position when pressing left arrow key, decrease cursor position + when pressing the right arrow key. If the text block is right to left, the opposite + behavior applies. +*/ + +QTextCursor::MoveStyle QLineEdit::cursorMoveStyle() const +{ + Q_D(const QLineEdit); + return d->control->cursorMoveStyle(); +} + +void QLineEdit::setCursorMoveStyle(QTextCursor::MoveStyle style) +{ + Q_D(QLineEdit); + d->control->setCursorMoveStyle(style); +} + +/*! \property QLineEdit::acceptableInput \brief whether the input satisfies the inputMask and the validator. diff --git a/src/gui/widgets/qlineedit.h b/src/gui/widgets/qlineedit.h index 636cee7..73a736c 100644 --- a/src/gui/widgets/qlineedit.h +++ b/src/gui/widgets/qlineedit.h @@ -43,6 +43,7 @@ #define QLINEEDIT_H #include <QtGui/qframe.h> +#include <QtGui/qtextcursor.h> #include <QtCore/qstring.h> #include <QtCore/qmargins.h> @@ -158,6 +159,9 @@ public: void setDragEnabled(bool b); bool dragEnabled() const; + void setCursorMoveStyle(QTextCursor::MoveStyle style); + QTextCursor::MoveStyle cursorMoveStyle() const; + QString inputMask() const; void setInputMask(const QString &inputMask); bool hasAcceptableInput() const; diff --git a/src/gui/widgets/qlineedit_p.cpp b/src/gui/widgets/qlineedit_p.cpp index 23ac613..03716d4 100644 --- a/src/gui/widgets/qlineedit_p.cpp +++ b/src/gui/widgets/qlineedit_p.cpp @@ -153,6 +153,7 @@ void QLineEditPrivate::init(const QString& txt) { Q_Q(QLineEdit); control = new QLineControl(txt); + control->setParent(q); control->setFont(q->font()); QObject::connect(control, SIGNAL(textChanged(QString)), q, SIGNAL(textChanged(QString))); diff --git a/src/gui/widgets/qlineedit_p.h b/src/gui/widgets/qlineedit_p.h index 32f6077..3169776 100644 --- a/src/gui/widgets/qlineedit_p.h +++ b/src/gui/widgets/qlineedit_p.h @@ -84,7 +84,6 @@ public: ~QLineEditPrivate() { - delete control; } QLineControl *control; diff --git a/src/gui/widgets/qmainwindowlayout.cpp b/src/gui/widgets/qmainwindowlayout.cpp index 6bc07e1..d4afe07 100644 --- a/src/gui/widgets/qmainwindowlayout.cpp +++ b/src/gui/widgets/qmainwindowlayout.cpp @@ -73,6 +73,10 @@ # include <private/qt_cocoa_helpers_mac_p.h> #endif +#ifdef QT_NO_DOCKWIDGET +extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window); +#endif + #ifdef Q_DEBUG_MAINWINDOW_LAYOUT # include <QTextStream> #endif diff --git a/src/gui/widgets/qmainwindowlayout_p.h b/src/gui/widgets/qmainwindowlayout_p.h index 2a44432..20aca61 100644 --- a/src/gui/widgets/qmainwindowlayout_p.h +++ b/src/gui/widgets/qmainwindowlayout_p.h @@ -70,12 +70,12 @@ //#define Q_DEBUG_MAINWINDOW_LAYOUT -#ifdef Q_DEBUG_MAINWINDOW_LAYOUT +#if defined(Q_DEBUG_MAINWINDOW_LAYOUT) && !defined(QT_NO_DOCKWIDGET) QT_BEGIN_NAMESPACE class QTextStream; Q_GUI_EXPORT void qt_dumpLayout(QTextStream &qout, QMainWindow *window); QT_END_NAMESPACE -#endif // Q_DEBUG_MAINWINDOW_LAYOUT +#endif // Q_DEBUG_MAINWINDOW_LAYOUT && !QT_NO_DOCKWIDGET #ifdef Q_WS_MAC // Forward defs to make avoid including Carbon.h (faster compile you know ;). diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index c09b5a4..b0ea00f 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -228,6 +228,12 @@ QList<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const void QMenuPrivate::updateActionRects() const { Q_Q(const QMenu); + updateActionRects(popupGeometry(q)); +} + +void QMenuPrivate::updateActionRects(const QRect &screen) const +{ + Q_Q(const QMenu); if (!itemsDirty) return; @@ -237,20 +243,10 @@ void QMenuPrivate::updateActionRects() const actionRects.resize(actions.count()); actionRects.fill(QRect()); - //let's try to get the last visible action - int lastVisibleAction = actions.count() - 1; - for(;lastVisibleAction >= 0; --lastVisibleAction) { - const QAction *action = actions.at(lastVisibleAction); - if (action->isVisible()) { - //removing trailing separators - if (action->isSeparator() && collapsibleSeparators) - continue; - break; - } - } + int lastVisibleAction = getLastVisibleAction(); int max_column_width = 0, - dh = popupGeometry(q).height(), + dh = screen.height(), y = 0; QStyle *style = q->style(); QStyleOption opt; @@ -351,7 +347,6 @@ void QMenuPrivate::updateActionRects() const const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin)); max_column_width = qMax(min_column_width, max_column_width); - //calculate position const int base_y = vmargin + fw + topmargin + (scroll ? scroll->scrollOffset : 0) + @@ -382,6 +377,34 @@ void QMenuPrivate::updateActionRects() const itemsDirty = 0; } +QSize QMenuPrivate::adjustMenuSizeForScreen(const QRect &screen) +{ + Q_Q(QMenu); + QSize ret = screen.size(); + itemsDirty = true; + updateActionRects(screen); + const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q); + ret.setWidth(actionRects.at(getLastVisibleAction()).right() + fw); + return ret; +} + +int QMenuPrivate::getLastVisibleAction() const +{ + //let's try to get the last visible action + int lastVisibleAction = actions.count() - 1; + for (;lastVisibleAction >= 0; --lastVisibleAction) { + const QAction *action = actions.at(lastVisibleAction); + if (action->isVisible()) { + //removing trailing separators + if (action->isSeparator() && collapsibleSeparators) + continue; + break; + } + } + return lastVisibleAction; +} + + QRect QMenuPrivate::actionRect(QAction *act) const { int index = actions.indexOf(act); @@ -1247,37 +1270,15 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) response to button presses; these are just like context menus except for how they are invoked. - \raw HTML - <table align="center" cellpadding="0"> - <tr> - <td> - \endraw - \inlineimage plastique-menu.png - \raw HTML - </td> - <td> - \endraw - \inlineimage windowsxp-menu.png - \raw HTML - </td> - <td> - \endraw - \inlineimage macintosh-menu.png - \raw HTML - </td> - - </tr> - <tr> - <td colspan="3"> - \endraw - A menu shown in \l{Plastique Style Widget Gallery}{Plastique widget style}, + \table 100% + \row + \o \inlineimage plastique-menu.png + \o \inlineimage windowsxp-menu.png + \o \inlineimage macintosh-menu.png + \endtable + \caption Fig. A menu shown in \l{Plastique Style Widget Gallery}{Plastique widget style}, \l{Windows XP Style Widget Gallery}{Windows XP widget style}, and \l{Macintosh Style Widget Gallery}{Macintosh widget style}. - \raw HTML - </td> - </tr> - </table> - \endraw \section1 Actions @@ -1835,9 +1836,20 @@ void QMenu::popup(const QPoint &p, QAction *atAction) else #endif screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); - const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this); bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen); + + // if the screens have very different geometries and the menu is too big, we have to recalculate + if (size.height() > screen.height() || size.width() > screen.width()) { + size = d->adjustMenuSizeForScreen(screen); + adjustToDesktop = true; + } + // Layout is not right, we might be able to save horizontal space + if (d->ncols >1 && size.height() < screen.height()) { + size = d->adjustMenuSizeForScreen(screen); + adjustToDesktop = true; + } + #ifdef QT_KEYPAD_NAVIGATION if (!atAction && QApplication::keypadNavigationEnabled()) { // Try to have one item activated @@ -1931,6 +1943,27 @@ void QMenu::popup(const QPoint &p, QAction *atAction) } } } + const int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this); + const QSize menuSize(sizeHint()); + QMenu *caused = qobject_cast<QMenu*>(d_func()->causedPopup.widget); + if (caused && caused->geometry().width() + menuSize.width() + subMenuOffset < screen.width()) { + QRect parentActionRect(caused->d_func()->actionRect(caused->d_func()->currentAction)); + const QPoint actionTopLeft = caused->mapToGlobal(parentActionRect.topLeft()); + parentActionRect.moveTopLeft(actionTopLeft); + if (isRightToLeft()) { + if ((pos.x() + menuSize.width() > parentActionRect.left() - subMenuOffset) + && (pos.x() < parentActionRect.right())) + { + pos.rx() = parentActionRect.right(); + } + } else { + if ((pos.x() < parentActionRect.right() + subMenuOffset) + && (pos.x() + menuSize.width() > parentActionRect.left())) + { + pos.rx() = parentActionRect.left() - menuSize.width(); + } + } + } setGeometry(QRect(pos, size)); #ifndef QT_NO_EFFECTS int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll; @@ -2963,28 +2996,8 @@ void QMenu::internalDelayedPopup() const QRect actionRect(d->actionRect(d->currentAction)); const QSize menuSize(d->activeMenu->sizeHint()); const QPoint rightPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top()))); - const QPoint leftPos(mapToGlobal(QPoint(actionRect.left() - subMenuOffset - menuSize.width(), actionRect.top()))); QPoint pos(rightPos); - QMenu *caused = qobject_cast<QMenu*>(d->activeMenu->d_func()->causedPopup.widget); - - const QRect availGeometry(d->popupGeometry(caused)); - if (isRightToLeft()) { - pos = leftPos; - if ((caused && caused->x() < x()) || pos.x() < availGeometry.left()) { - if(rightPos.x() + menuSize.width() < availGeometry.right()) - pos = rightPos; - else - pos.rx() = availGeometry.left(); - } - } else { - if ((caused && caused->x() > x()) || pos.x() + menuSize.width() > availGeometry.right()) { - if(leftPos.x() < availGeometry.left()) - pos.rx() = availGeometry.right() - menuSize.width(); - else - pos = leftPos; - } - } //calc sloppy focus buffer if (style()->styleHint(QStyle::SH_Menu_SloppySubMenus, 0, this)) { diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index b6efde3..005ce1d 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -194,10 +194,13 @@ public: mutable QVector<QRect> actionRects; mutable QHash<QAction *, QWidget *> widgetItems; void updateActionRects() const; + void updateActionRects(const QRect &screen) const; QRect popupGeometry(const QWidget *widget) const; QRect popupGeometry(int screen = -1) const; mutable uint ncols : 4; //4 bits is probably plenty uint collapsibleSeparators : 1; + QSize adjustMenuSizeForScreen(const QRect & screen); + int getLastVisibleAction() const; bool activationRecursionGuard; @@ -296,7 +299,6 @@ public: void updateLayoutDirection(); - //menu fading/scrolling effects bool doChildEffects; diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index 7435691..51c4ccb 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -483,6 +483,7 @@ int QPlainTextEditPrivate::verticalOffset(int topBlock, int topLine) const QPlainTextDocumentLayout *documentLayout = qobject_cast<QPlainTextDocumentLayout*>(doc->documentLayout()); Q_ASSERT(documentLayout); QRectF r = documentLayout->blockBoundingRect(currentBlock); + Q_UNUSED(r); QTextLayout *layout = currentBlock.layout(); if (layout && topLine <= layout->lineCount()) { QTextLine line = layout->lineAt(topLine - 1); @@ -648,6 +649,11 @@ void QPlainTextEditPrivate::setTopBlock(int blockNumber, int lineNumber, int dx) } control->topBlock = blockNumber; topLine = lineNumber; + + bool vbarSignalsBlocked = vbar->blockSignals(true); + vbar->setValue(block.firstLineNumber() + lineNumber); + vbar->blockSignals(vbarSignalsBlocked); + if (dx || dy) viewport->scroll(q->isRightToLeft() ? -dx : dx, dy); else diff --git a/src/gui/widgets/qscrollbar.cpp b/src/gui/widgets/qscrollbar.cpp index c895b1b..87738a0 100644 --- a/src/gui/widgets/qscrollbar.cpp +++ b/src/gui/widgets/qscrollbar.cpp @@ -330,7 +330,7 @@ void QScrollBar::initStyleOption(QStyleOptionSlider *option) const /*! Constructs a vertical scroll bar. - The \a parent arguments is sent to the QWidget constructor. + The \a parent argument is sent to the QWidget constructor. The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the \l {QAbstractSlider::maximum} {maximum} to 99, with a diff --git a/src/gui/widgets/qsplitter.cpp b/src/gui/widgets/qsplitter.cpp index 964a6e1..ca8fc37 100644 --- a/src/gui/widgets/qsplitter.cpp +++ b/src/gui/widgets/qsplitter.cpp @@ -1016,7 +1016,7 @@ QSplitterLayoutStruct *QSplitterPrivate::insertWidget(int index, QWidget *w) /*! Constructs a horizontal splitter with the \a parent - arguments is passed on to the QFrame constructor. + argument passed on to the QFrame constructor. \sa setOrientation() */ diff --git a/src/gui/widgets/qtextedit.cpp b/src/gui/widgets/qtextedit.cpp index ff924bf..8df436f 100644 --- a/src/gui/widgets/qtextedit.cpp +++ b/src/gui/widgets/qtextedit.cpp @@ -2614,7 +2614,6 @@ Qt::TextFormat QTextEdit::textFormat() const void QTextEdit::append(const QString &text) { Q_D(QTextEdit); - QTextBlock lastBlock = d->control->document()->lastBlock(); const bool atBottom = isReadOnly() ? d->verticalOffset() >= d->vbar->maximum() : d->control->textCursor().atEnd(); d->control->append(text); diff --git a/src/gui/widgets/qworkspace.cpp b/src/gui/widgets/qworkspace.cpp index bf50d07..13ef13b 100644 --- a/src/gui/widgets/qworkspace.cpp +++ b/src/gui/widgets/qworkspace.cpp @@ -1239,7 +1239,6 @@ QWidget * QWorkspace::addWindow(QWidget *w, Qt::WindowFlags flags) int x = w->x(); int y = w->y(); bool hasPos = w->testAttribute(Qt::WA_Moved); - QSize s = w->size().expandedTo(qSmartMinSize(w)); if (!hasSize && w->sizeHint().isValid()) w->adjustSize(); |