diff options
author | Eckhart Koppen <eckhart.koppen@nokia.com> | 2011-03-08 07:12:58 (GMT) |
---|---|---|
committer | Eckhart Koppen <eckhart.koppen@nokia.com> | 2011-03-08 07:12:58 (GMT) |
commit | cddc9fd3913fa511fbe5feac4c6ff61464bc78fa (patch) | |
tree | 9ae83863ed3b805d3bb0639d1268906564f9801a | |
parent | f96b9e139dd67d2be992e86af9fb41e4cdfcb6cf (diff) | |
parent | 0766bf2fa4a89e629bbdad185e4919fd49c033a1 (diff) | |
download | Qt-cddc9fd3913fa511fbe5feac4c6ff61464bc78fa.zip Qt-cddc9fd3913fa511fbe5feac4c6ff61464bc78fa.tar.gz Qt-cddc9fd3913fa511fbe5feac4c6ff61464bc78fa.tar.bz2 |
Merge remote branch 'qt-master/master'
335 files changed, 11265 insertions, 2831 deletions
@@ -249,3 +249,13 @@ src/network/lib src/xml/lib/ .pc/ + +# INTEGRITY generated files +*.gpj +*.int +*.ael +*.dla +*.dnm +*.dep +*.map +work diff --git a/config.profiles/symbian/package_definition.xml b/config.profiles/symbian/package_definition.xml index f0c6652..1c3c1d3 100644 --- a/config.profiles/symbian/package_definition.xml +++ b/config.profiles/symbian/package_definition.xml @@ -5,7 +5,7 @@ <package id="qt" name="Qt" levels="tool mw app"> <collection id="qtconf" name="Qt Config" level="tool"> <component id="qt_deviceconfiguration" name="Qt Device Configuration" class="config tool" filter="s60,qt_tools" introduced="^2"> - <unit bldFile="src/config.profiles/symbian"/> + <unit bldFile="config.profiles/symbian"/> </component> </collection> <collection id="qt_info" name="Qt Info" level="mw"> @@ -16,7 +16,7 @@ <collection id="qtlocalization" name="Qt Localization" level="app"> <component id="qtlocalization_build" name="Qt localization Build" introduced="^2" filter="s60"> - <unit bldFile="src/config.profiles/symbian/translations_symbian" qt:proFile="translations.pro"/> + <unit bldFile="config.profiles/symbian/translations_symbian" qt:proFile="translations.pro"/> </component> </collection> @@ -728,6 +728,11 @@ if [ -f "$relpath/src/gui/embedded/qscreenqnx_qws.cpp" ]; then CFG_MOUSE_AVAILABLE="${CFG_MOUSE_AVAILABLE} qnx" CFG_GFX_AVAILABLE="${CFG_GFX_AVAILABLE} qnx" fi +if [ -f "$relpath/src/gui/embedded/qscreenintegrityfb_qws.cpp" ]; then + CFG_KBD_AVAILABLE="${CFG_KBD_AVAILABLE} integrity" + CFG_MOUSE_AVAILABLE="${CFG_MOUSE_AVAILABLE} integrity" + CFG_GFX_AVAILABLE="${CFG_GFX_AVAILABLE} integrityfb" +fi CFG_ARCH= CFG_HOST_ARCH= @@ -6702,6 +6707,8 @@ if [ "$CFG_JAVASCRIPTCORE_JIT" = "yes" ] || [ "$CFG_JAVASCRIPTCORE_JIT" = "auto" if [ $? != "0" ]; then CFG_JAVASCRIPTCORE_JIT=no fi + elif [ "$XPLATFORM" = "symbian-gcce" ]; then + CFG_JAVASCRIPTCORE_JIT=no fi fi @@ -7407,11 +7414,11 @@ EOF canBuildWebKit="no" canBuildQtConcurrent="no" ;; - symbian/*-gcce) + symbian-gcce) canBuildWebKit="no" canBuildQtConcurrent="no" ;; - symbian/*-armcc) + symbian-armcc) canBuildQtConcurrent="no" ;; esac diff --git a/dist/changes-4.7.2 b/dist/changes-4.7.2 index 17a066f..c7e0089 100644 --- a/dist/changes-4.7.2 +++ b/dist/changes-4.7.2 @@ -16,35 +16,48 @@ Qt Bug Tracker: http://bugreports.qt.nokia.com Merge Request: http://qt.gitorious.org **************************************************************************** -* General * -**************************************************************************** - -New features ------------- - - - SomeClass, SomeOtherClass - * New classes for foo, bar and baz - -Optimizations -------------- - - - Optimized foo in QSomeClass - * See list of Important Behavior Changes below - - -**************************************************************************** * Library * **************************************************************************** QtCore ------ + - QMutex + * [QTBUG-16115] Fixed deadlock when calling tryLock repeatedly. - QStateMachine - * [QTBUG-14491] Fix compilation on AIX 5.3 with gcc. + * [QTBUG-14491] Fixed compilation on AIX 5.3 with gcc. + - QThread + * [QTBUG-15378] QThread::exec returaed immediately if QThread::exit had + been called when event loop was not running. QtGui ----- + - Painting + * [QTBUG-14907] Fix OpenVG painting artifacts after restoreState(). + * [QTBUG-15320] QPainter::drawRect crashed when drawing a null QRectF + with OpenGL. + * [QTBUG-15693] Prevent crash in drawhelper code when the cpu has MMXEXT + but no SSE. + - QDoubleValidator + * [QTBUG-14935] With some locales, QDoubleValidator would not accept "C" + locale valid numbers. + - QFileDialog + * [QTBUG-17298] QFileDialog::getOpenFileNames didn't show any file. + - QGraphicsView + * [QTBUG-16063] Fix precision loss when querying micro focus rectangle + in QGraphicsView. + - QPainterPath + * [QTBUG-16377] Prevent QPainterPath::connectPath() returning incorrect + path, which caused OpenGL paint engine to crash. + - QTableWidget + * [QTBUG-15973] Resizinag a QTableWidget column where a cell contains a + QProgressBar made it crash. + - QTextDocument + * [QTBUG-15777] Fxied crash in QTextDocument::markContentsDirty. + - QTextLayout + * [QTBUG-15823] Fixed crash in QTextLayout when drawing full width + selection spanning multiple QTextLine's. - QWidget * [QTMOBILITY-645] Send WinIdChange event when winId is set to zero. The window handle of a native widget may be set to zero in two @@ -52,27 +65,32 @@ QtGui widget destruction. Previously, no WinIdChange event was sent in either of these cases; now, it is sent in both cases. -QtDBus ------- - - - foo - * bar - QtNetwork --------- - - foo - * bar + - Bearer Management + * [QTBUG-15276] Fixed possible crash when parsing new connection. + - QUrl + * [QTBUG-16425] QUrl::setUrl() did not call detach(). -QtOpenGL --------- +QtQuick +------- - - foo - * bar + - [QTBUG-14374] Fixed broken alignment of rich text. + - [QTBUG-14727] QML Text element did not play nice with transformations. + - [QTBUG-14761] Fixed memory leak in QDeclarativeComponent. + - [QTBUG-14830] Fixed crash when adjusting width inside onWidthChanged. + - [QTBUG-15710] Ensure header is considered when positioning content with + snapping. + - [QTBUG-16365] When using a PathView with a VisualDataModel which in turn + used a Tree model (DirModel, for example), nothing was shown. + - [QTBUG-16769] QML BorderImage failed if .sci file contained a URL. QtScript -------- + - General + * [QTBUG-17166] Fix ScopeChainNode memory leak in JavaScriptCore. - QScriptContext * [QTBUG-17137] Fix crash when generating backtrace involving a built-in (ECMA) function. @@ -94,56 +112,55 @@ QtScript QtSql ----- - - foo - * bar - -QtXml ------ - - - foo - * bar - -Qt Plugins ----------- - - - foo - * bar - -Third party components ----------------------- - - - Updated foo to version 2.3.9. - - - Updated bar to the latest version from baz.org. + - [QTBUG-14132] Fix errors in Oracle (xe) stored procedures with bind + variables. + - [QTBUG-14831] Fix regression in dynamic sorting of a QSortFilterProxyModel + on a QSqlTableModel with OnManualSubmit. + - [QTBUG-17076] Fix plugins/sqldrivers/oci compile error when using + QT_NAMESPACE. **************************************************************************** * Platform Specific Changes * **************************************************************************** -Qt for Unix (X11 and Mac OS X) ------------------------------- - - - - Qt for Linux/X11 ---------------- - - + - [QTBUG-15008] Fix broken prefix setting in configure when EPOCROOT shell + variable is set. Qt for Windows -------------- - - + - QtQuick + * [QTBUG-16885] QDeclarativeEngine::addImportPath() did not work if the + drive letter is in lowercase. + * [QTBUG-17360] Make sure $QTDIR/plugins/qmldebugging/tcpserver.dll is + found in windows release builds. Qt for Mac OS X --------------- - - + - [QTBUG-13772] Returning form fullscreen mode causes assertion failure. + - [QTBUG-14023] Added missing plugins to debug-libs package. + - [QTBUG-14420] Switching from an application with undocked widgets hid the + application. + - [QTBUG-15638] Fixed incorrect QComboBox drop-down menu Z-ordering. + - [QTBUG-15666] Fixed crash when closing QFontDialog::getFont() dialog before + its event loop finished. + - [QTBUG-16279] Fixed deadlock in QSyntaxHighlighter::highlightBlock. Qt for Symbian -------------- + - Multimedia + * [QTBUG-17040] Prevent menu and native title pane area popping up when + setting fullscreen mode off during video playback. + - Packaging changes + * [QTBUG-17399] Remove sqlite3 from Qt SIS for S60 3.2 and 5.0 to allow + Nokia Content Signing, which doesn't permit sis files to have other + sis files embedded inside. - Paging changes * [QT-3503] Remove PAGED keyword from all Qt-based binaries for MMP-based build systems (abld, SBSv2 (a.k.a. Raptor)). @@ -159,65 +176,92 @@ Qt for Symbian appropriate types of paging rather than being forced by the binary (which may be deployed to several different devices with different characteristics). - - Phonon MMF backend * [QTBUG-11436] Added a MediaObject property which allows the client to specify which Internet Access Point should be used for streaming. - - - QNetworkProxyFactory - * [QTBUG-13857] Added systemProxyForQuery() for Symbian, allowing - network proxies configured on the device to be used by applications. - - QApplication - * [QTBUG-15915] Fix crash when creating more than one QApplication in single test case. - + * [QTBUG-15915] Fix crash when creating more than one QApplication in single + test case. + * [QTBUG-16065] QApplication object with QApplication::GuiServer type caused + crash on Symbian devices. - QDesktopWidget * [QTBUG-16095] Resize event for QDesktopWidget was sent too early. - - - QFileDialog - * [QTBUG-16204] Fix using QFileDialog statics in Symbian. - - QDialog * [QTBUG-16277] Fix fullscreen/Maximized dialog misplacement in Symbian. - - - QSystemSemaphore - * [QTBUG-16615] Fix QSystemSemaphore handle management issues in Symbian. - + * [QTBUG-16110] QMessageBox softkeys were dimmed when application returned + to foreground. + - QEventDispatcherSymbian + * [QTBUG-16380] Fix leaking of RTimer handles. + - QFileDialog + * [QTBUG-16204] Fix using QFileDialog statics in Symbian. + - QFontDatabase + * [QTBUG-16514] Avoid collision of application fonts. + - QGraphicsView + * [QTBUG-16932] Fix rendering errors on QGraphicsView with OpenVG engine. - QLineEdit * [QTBUG-16238] Fix one character displacement for cursor in line edits. - - - QtScript - * [QTBUG-16685] Fix crash in JavaScript stack allocator. - * [QTBUG-15847] Add compiler optimizations. - * [QTBUG-14293] Enhanced JavaScript heap allocator. - - qmake & mkspecs * [QT-4193] Only add ICON for application projects in symbianpkgrules.pri - * [QTBUG-13159] Allow pkg_prerules and pkg_postrules to be targeted to separate files. - * [QTBUG-13367] Make default application deployment removable & added .flags modifier - support for DEPLOYMENT items in Symbian. + * [QTBUG-13159] Allow pkg_prerules and pkg_postrules to be targeted to separate + files. + * [QTBUG-13367] Make default application deployment removable & added .flags + modifier support for DEPLOYMENT items in Symbian. * [QTBUG-14280] Implement support for DEPLOYMENT.display_name in Symbian. * [QTBUG-13917] Localize .loc and .pkg content based on TRANSLATIONS. - * [QTBUG-15159] Use include(original mkspec) instead of copying of mkspec to default. + * [QTBUG-15159] Use include(original mkspec) instead of copying of mkspec to + default. * [QTBUG-15393] Resolve EPOCROOT in qt.conf using same logic as in .pro. * [QTBUG-15501] Fix symbian-mmp.conf include path. - * [QTBUG-15539] Use parent class function to generate Makefile headers in Symbian. - * [QTBUG-14472] Add NetworkServices capability automatically for network apps + * [QTBUG-15539] Use parent class function to generate Makefile headers. + * [QTBUG-14472] Add NetworkServices capability automatically for network apps. * [QTBUG-14736] Add libinfix support for QML plugins in Symbian. - * [QT-4375] Fix incorrect file name case for OpenGL libraries in symbian.conf. - * [QTBUG-16172] Use relative include instead of absolute in default qmake.conf. + * [QT-4375] Fix incorrect file name case for OpenGL libraries in + symbian.conf. + * [QTBUG-16172] Use relative include instead of absolute in default + qmake.conf. * [QTBUG-16221] Fix libinfixed usage in Symbian when def files are used. * [QTBUG-16261] Fix infinite loop in qmake when reading malformed .ts files. * [QTBUG-16298] Ignore static_and_shared in Symbian builds. + * [QTBUG-16477] Fix compile error when QT_NO_BEARERMANAGEMENT is defined. * [QTBUG-13769] Generate freeze targets in Symbian. - * [QTBUG-16691] Remove toolcheck from generic clean targets for symbian-sbsv2. - * [QT-4476] Fixed UTF-8 application names in device application menu in Symbian. + * [QTBUG-16691] Remove toolcheck from generic clean targets for + symbian-sbsv2. + * [QT-4476] Fixed UTF-8 application names in device application menu. * [QTBUG-16753] Improved QMAKE_POST_LINK support in symbian-sbsv2. - * [QTBUG-16881] Fix QMAKE_POST_LINK in Symbian for targets with special characters. - * [QTBUG-16888] No longer replace dash and dot in TARGET with underscore in Symbian. + * [QTBUG-16881] Fix QMAKE_POST_LINK for targets with special characters. + * [QTBUG-16888] No longer replace dash and dot in TARGET with underscore. + * [QTBUG-17187] Ensure that package generated against Symbian^3 SDK has no + Symbian^1 platforms as dependencies. * Fix partial upgrade package UID for libinfixed Qt. * Cleaned up sis_targets.prf. - + - QNetworkProxyFactory + * [QTBUG-13857] Added systemProxyForQuery() for Symbian, allowing + network proxies configured on the device to be used by applications. + - QPaintEngine + * [QTBUG-16008] Fixed broken constant alpha blending on ARMV6. + * [QTBUG-16240] Fix blurry text in word-wrapped, center-aligned text items + with OpenVG. + - QSystemSemaphore + * [QTBUG-16615] Fix QSystemSemaphore handle management issues in Symbian. + - qtmain.lib + * [QTBUG-14735] Use qtmain.lib to provide entry point for all applications. + - QtQuick + * [QTBUG-15405] QML Plugins were not loaded when installed on different + drives. + - QtScript + * [QTBUG-14293] Enhanced JavaScript heap allocator. + * [QTBUG-15800] Creating QScriptEngine on the heap caused app crash. + * [QTBUG-15847] Add compiler optimizations. + * [QTBUG-16685] Fix crash in JavaScript stack allocator. + - QWidget + * [QTBUG-16578] In cases where the widget was created from the event loop + instead of main(), the middle three softkeys would not get the right + visibility and would leave a "hole" in the application where one could + see what was beneath it. + * [QT-4416, QTBUG-17288] On devices which lack support for transparency + in EGL surfaces, setting Qt::WA_TranslucentBackground on a widget + whose windowType() is Qt::Window causes that widget to be rendered + using the raster graphics system. - Tool scripts * [QTBUG-13886] Disallow patching capabilities of executables. * [QTBUG-13891] Add Location as self signable capability in patch_capabilities.pl. @@ -225,49 +269,10 @@ Qt for Symbian * Fix epocroot handling in createpackage.pl script. * Unify epocroot usage in createpackage and patch_capabilities scripts. - - qtmain.lib - * [QTBUG-14735] Use qtmain.lib to provide entry point for all Symbian applications. - - - QWidget - * [QT-4416, QTBUG-17288] On devices which lack support for transparency - in EGL surfaces, setting Qt::WA_TranslucentBackground on a widget - whose windowType() is Qt::Window causes that widget to be rendered - using the raster graphics system. - -Qt for Embedded Linux ---------------------- - - - - -DirectFB --------- - - - - -Qt for Windows CE ------------------ - - - - **************************************************************************** * Tools * **************************************************************************** - - Designer - * foo - - - qdoc3 - * bar - - - Linguist - * baz - - qmake * [QTBUG-14357] Make qmake to pass all UTF-8 characters unchanged through parser. -**************************************************************************** -* Important Behavior Changes * -**************************************************************************** - - - - diff --git a/doc/src/declarative/dynamicobjects.qdoc b/doc/src/declarative/dynamicobjects.qdoc index 316fe6b..f2ca0fd 100644 --- a/doc/src/declarative/dynamicobjects.qdoc +++ b/doc/src/declarative/dynamicobjects.qdoc @@ -68,9 +68,11 @@ the component. This function can take one or two arguments: \o The first is the parent for the new item. Since graphical items will not appear on the scene without a parent, it is recommended that you set the parent this way. However, if you wish to set the parent later you can safely pass \c null to this function. -\o The second is optional and is a script which assigns values to the item's properties during creation. This avoids warnings - when certain properties have been bound to before they have been set by the code. Additionally, there are small performance - benefits when instantiating objects in this way. +\o The second is optional and is a map of property-value items that define initial any property values for the item. + Property values specified by this argument are applied to the object before its creation is finalized, avoiding + binding errors that may occur if particular properties must be initialized to enable other property bindings. + when certain properties have been bound to before they have been set by the code. Additionally, there are small + performance benefits when compared to defining property values and bindings after the object is created. \endlist Here is an example. First there is \c Sprite.qml, which defines a simple QML component: diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc index 466b940..e2d9350 100644 --- a/doc/src/declarative/elements.qdoc +++ b/doc/src/declarative/elements.qdoc @@ -76,7 +76,7 @@ To see the QML elements listed by functional area, see the \o \l {FocusScope} - Element that mediate keyboard focus changes \o \l {Flickable} - Provides a surface that can be "flicked" \o \l {Flipable} - Provides a surface that produces "flipping" effects -\o \l {GestureArea} - Enables simple gesture handling +\o \l {PinchArea} - Enables simple pinch gesture handling \endlist \section1 Positioners and Repeater diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc index a287533..80b6e72 100644 --- a/doc/src/declarative/extending.qdoc +++ b/doc/src/declarative/extending.qdoc @@ -51,7 +51,7 @@ to either instantiating an object instance, or assigning a property a value. QML relies heavily on Qt's meta object system and can only instantiate classes that derive from QObject. For visual element types, this will usually mean a subclass of QDeclarativeItem; for models used with the view elements, a subclass of QAbstractItemModel; -and for abitrary objects with properties, a direct subclass of QObject. +and for arbitrary objects with properties, a direct subclass of QObject. The QML engine has no intrinsic knowledge of any class types. Instead the programmer must register the C++ types with their corresponding QML names. @@ -522,7 +522,7 @@ The \c {invite()} method is similarly available if it is declared as a slot. \snippet examples/declarative/cppextensions/referenceexamples/valuesource/example.qml 0 \snippet examples/declarative/cppextensions/referenceexamples/valuesource/example.qml 1 -The QML snippet shown above applies a property value source to the \c announcment property. +The QML snippet shown above applies a property value source to the \c announcement property. A property value source generates a value for a property that changes over time. Property value sources are most commonly used to do animation. Rather than @@ -562,7 +562,7 @@ assignment fails does the engine call the \l {QDeclarativePropertyValueSource::} the type to also be used in contexts other than just as a value source. \l {Extending QML - Property Value Source Example} shows the complete code used -implement the \c HappyBirthdaySong property value source. +to implement the \c HappyBirthdaySong property value source. \section1 Property Binding diff --git a/doc/src/declarative/qmlinuse.qdoc b/doc/src/declarative/qmlinuse.qdoc index 7380ef5..131be1b 100644 --- a/doc/src/declarative/qmlinuse.qdoc +++ b/doc/src/declarative/qmlinuse.qdoc @@ -207,7 +207,7 @@ <li><a href="qml-flipable.html">Flipable Element</a> - The Flipable item provides a surface that can be flipped or reflected.</li> <li><a href="qml-focuspanel.html">FocusPanel Element</a> - The FocusPanel item explicitly creates a focus panel.</li> <li><a href="qml-focusscope.html">FocusScope Element</a> - The FocusScope object explicitly creates a focus scope for focus management.</li> - <li><a href="qml-gesturearea.html">GestureArea Element</a> - The GestureArea item enables simple gesture handling.</li> + <li><a href="qml-pincharea.html">PinchArea Element</a> - The PinchArea item enables simple pinch gesture handling.</li> <li><a href="qml-keynavigation.html">KeyNavigation Element</a> - The KeyNavigation attached property supports key navigation by arrow keys.</li> <li><a href="qml-keys.html">Keys Element</a> - The Keys attached property provides key handling to Items.</li> <li><a href="qml-mousearea.html">MouseArea Element</a> - The MouseArea item enables simple mouse handling.</li> diff --git a/doc/src/declarative/whatsnew.qdoc b/doc/src/declarative/whatsnew.qdoc index f4359f9..e8c2124 100644 --- a/doc/src/declarative/whatsnew.qdoc +++ b/doc/src/declarative/whatsnew.qdoc @@ -41,10 +41,10 @@ PinchArea provides support for the common two finger pinch gesture. Added the following properties: \list -\o lineSpacing -\o lineCount -\o maximumLineCount -\o truncated +\o \l {Text::}{lineHeight} +\o \l {Text::}{lineCount} +\o \l {Text::}{maximumLineCount} +\o \l {Text::}{truncated} \endlist horizontalAlignment now accepts Text.AlignJustify alignment mode. @@ -53,85 +53,88 @@ horizontalAlignment now accepts Text.AlignJustify alignment mode. Added the following properties, methods and signal handlers: \list -\o canPaste -\o lineCount -\o deselect() -\o moveCursorSelection(int pos, SelectionMode mode) to enable selection by word -\o onLinkActivated(string link) +\o \l {TextEdit::}{canPaste} +\o \l {TextEdit::}{lineCount} +\o \l {TextEdit::}{deselect()} +\o \l {TextEdit::}{moveCursorSelection()} to enable selection by word +\o \l {TextEdit::}{onLinkActivated} \endlist \section2 TextInput Added the following properties and methods: \list -\o canPaste -\o deselect() -\o moveCursorSelection(int pos, SelectionMode mode) to enable selection by word +\o \l{TextInput::}{canPaste} +\o \l{TextInput::}{deselect()} +\o \l{TextInput::}{moveCursorSelection()} to enable selection by word \endlist \section2 Image, BorderImage and AnimatedImage Added the following properties: \list -\o cache -\o mirror +\o \l{Image::}{cache} +\o \l{Image::}{mirror} \endlist \section2 Item Added the following properties: \list -\o implicitWidth and implicitHeight +\o \l{Item::}{implicitWidth} and \l{Item::}{implicitHeight} \endlist \section2 Flickable Added the following methods: \list -\o resizeContent(qreal w, qreal h, QPointF center) -\o returnToBounds() +\o \l{Flickable::}{resizeContent()} +\o \l{Flickable::}{returnToBounds()} \endlist \section2 ListView and GridView Added the following methods: \list -\o positionViewAtBeginning() -\o positionViewAtEnd() +\o \l{ListView::}{positionViewAtBeginning()} +\o \l{ListView::}{positionViewAtEnd()} \endlist -\section2 Flow, Grid, Row +\section2 Flow, Grid and Row Added the following properties: \list -\o layoutDirection +\o \l{Flow::}{layoutDirection} \endlist \section2 Repeater Added the following methods and signal handlers: \list -\o onItemAdded() -\o onItemRemoved() -\o itemAt(int index) +\o \l{Repeater::}{onItemAdded} +\o \l{Repeater::}{onItemRemoved} +\o \l{Repeater::}{itemAt()} \endlist \section2 Component -The createObject() method now accepts a map of initial property values for the created object. +\list +\o The \l{Component::}{createObject()} method now accepts a map of initial property values for +the created object. +\endlist \section2 Qt -Added the following properties and methods: \list -\o application.layoutDirection -\o application.active +\o Added the \l {QML:Qt::application}{Qt.application} object to hold generic global application +properties. \endlist \section2 Other changes \list -\o Functions can be assigned to properties from JavaScript to create property bindings +\o Functions can be \l{Binding Properties from JavaScript}{assigned to properties from JavaScript} +to create property bindings. \endlist diff --git a/doc/src/development/qmake-manual.qdoc b/doc/src/development/qmake-manual.qdoc index 373254c..1c5d903 100644 --- a/doc/src/development/qmake-manual.qdoc +++ b/doc/src/development/qmake-manual.qdoc @@ -247,8 +247,7 @@ Normally, variables are used to contain whitespace-separated lists of values. However, it is sometimes necessary to specify values containing - spaces. These must be quoted by using the - \l{qmake Function Reference#quote-string}{quote()} function in the following way: + spaces. These must be quoted by using double quotes: \snippet doc/src/snippets/qmake/quoting.pro 0 @@ -256,9 +255,7 @@ the variable. A similar approach is used to deal with paths that contain spaces, particularly when defining the \l{qmake Variable Reference#INCLUDEPATH}{INCLUDEPATH} and - \l{qmake Variable Reference#LIBS}{LIBS} variables for the Windows platform. - In cases like these, the \l{qmake Function Reference#quote(string)}{quote()} - function can be used in the following way: + \l{qmake Variable Reference#LIBS}{LIBS} variables for the Windows platform: \snippet doc/src/snippets/qmake/spaces.pro quoting include paths with spaces @@ -1650,8 +1647,7 @@ \section1 INCLUDEPATH This variable specifies the #include directories which should be - searched when compiling the project. Use ';' or a space as the - directory separator. + searched when compiling the project. For example: @@ -1659,9 +1655,7 @@ To specify a path containing spaces, quote the path using the technique mentioned in the \l{qmake Project Files#Whitespace}{qmake Project Files} - document. For example, paths with spaces can be specified on Windows - and Unix platforms by using the \l{qmake Function Reference#quote-string}{quote()} - function in the following way: + document. \snippet doc/src/snippets/qmake/spaces.pro quoting include paths with spaces @@ -1723,9 +1717,7 @@ To specify a path containing spaces, quote the path using the technique mentioned in the \l{qmake Project Files#Whitespace}{qmake Project Files} - document. For example, paths with spaces can be specified on Windows - and Unix platforms by using the \l{qmake Function Reference#quote-string}{quote()} - function in the following way: + document. \snippet doc/src/snippets/qmake/spaces.pro quoting library paths with spaces @@ -3614,10 +3606,7 @@ \section1 quote(string) Converts a whole \e string into a single entity and returns the result. - Newlines, carriage returns, and tabs can be specified in the string - with \\n \\r and \\t. The return value does not contain either single - or double quotation marks unless you explicitly include them yourself, - but will be placed into a single entry (for literal expansion). + This is just a fancy way of enclosing the string into double quotes. \section1 replace(string, old_string, new_string) diff --git a/doc/src/getting-started/installation.qdoc b/doc/src/getting-started/installation.qdoc index c906f84..6d0256e 100644 --- a/doc/src/getting-started/installation.qdoc +++ b/doc/src/getting-started/installation.qdoc @@ -874,9 +874,10 @@ If the installation fails, please make sure that there is no previously installed version of Qt on the phone. Qt requires some dependent packages to be installed on the device, -they are shipped in the Symbian SDK and can be installed using the -runonphone tool as well. -The packages can be found in the EPOCROOT at the following locations; +which can be installed using the runonphone tool as well. One is +the \c{sqlite3.sis}, which is included in the Qt distribution, while +the others are shipped with the Symbian SDK. The required packages +can be found from the following locations: \snippet doc/src/snippets/code/doc_src_installation.qdoc 50 @@ -1274,10 +1275,18 @@ We hope you will enjoy using Qt. in this release. \endlist - Running Qt on real device requires the Open C to be installed on the device. - The Open C installation packages are embedded into \c{qt_installer.sis}, which is included in - Qt for Symbian binary package. If you are building Qt from scratch, you can find the - required packages in the Symbian SDK where you installed Open C/C++: + Running Qt on real device requires the Open C and sqlite3 to be installed on the device. + These installation packages are embedded into \c{qt_installer.sis}, which is included in + Qt for Symbian binary package. + + If you are building Qt from scratch, you can find the sqlite3 package from + under your Qt installation: + + \list + \o \c{src\s60installs\sqlite3.sis} + \endlist + + The Open C packages you can find in the Symbian SDK where you installed Open C/C++: \list \o \c{nokia_plugin\openc\s60opencsis\pips_s60_<version>.sis} \o \c{nokia_plugin\openc\s60opencsis\openc_ssl_s60_<version>.sis} diff --git a/doc/src/images/roaming-states.png b/doc/src/images/roaming-states.png Binary files differnew file mode 100644 index 0000000..bc61cac --- /dev/null +++ b/doc/src/images/roaming-states.png diff --git a/doc/src/platforms/platform-notes-rtos.qdoc b/doc/src/platforms/platform-notes-rtos.qdoc index 776f510..be63063 100644 --- a/doc/src/platforms/platform-notes-rtos.qdoc +++ b/doc/src/platforms/platform-notes-rtos.qdoc @@ -245,3 +245,112 @@ some regressions were spotted in QDateTime computation around year 0 and year 1970, which have been tracked back to faulty time zone data on some QNX versions. */ + +/*! + \page platform-notes-integrity.html + \title Platform Notes - INTEGRITY + \contentspage Platform Notes + \target INTEGRITY + + \note INTEGRITY is a community supported platform. See the + \l{Supported Platforms} page for more information. + + This page contains information about the Qt for INTEGRITY port. More + information about the combinations of platforms and compilers supported + by Qt can be found on the \l{Supported Platforms} page. + + Note that Qt for INTEGRITY is currently based on \l{Qt for Embedded Linux}, + which contains its own windowing system. + + Qt for INTEGRITY contains experimental screen and input drivers based on the + gh_FB Framebuffer API for graphics, a Connection-based mouse and keyboard + support. For information about these drivers, please refer to Green Hills + Software standard support. + + \tableofcontents + + \section1 Supported Versions + + Qt has been tested on INTEGRITY 10 on various PowerPC, ARM and x86 targets. + On some platforms a native graphics FrameBuffer driver is available and has + then been used for testing. On all other platforms, the default FrameBuffer + VNC driver is used. + + \section1 Limitations + + Some of Qt's functionality is currently not available on INTEGRITY: + + \table + \header \o Function \o Notes + \row \o QProcess + \o Not implemented. Volunteers welcome. + \row \o QSharedMemory + \o Not available - INTEGRITY doesn't support SYSV style shared memory. + \row \o QSystemSemaphore + \o Not available - INTEGRITY doesn't support SYSV style system semaphores. + \row \o QWS Multi Process + \o QT_NO_QWS_MULTIPROCESS is always on due to missing shared memory support. + \row \o Phonon + \o There is no standard audio backend. + \row \o Qt3Support + \o The Qt3Support library is not available on INTEGRITY. + \row \o QtScript + \o Not available - INTEGRITY's mmap() doesn't support allocating memory. + \endtable + + \section1 Build Instructions + + Qt for INTEGRITY can be built on either a Linux or Windows (with cygwin) host. + In both cases, a standard installation of INTEGRITY is required, with the + addition of the FrameBuffer API. + + Example configure line for cross-compiling Qt for INTEGRITY for an + ARM INTEGRITY target: + + \code + ./configure --hostprefix=$PWD -embedded integrity -xplatform unsupported/qws/integrity-arm-cxarm -static -qt-kbd-integrity -qt-mouse-integrity -no-mouse-linuxtp -no-mouse-pc -no-kbd-tty -qt-gfx-integrityfb -no-qt3support -no-gfx-linuxfb -no-glib -no-openssl -no-largefile -little-endian -arch integrity -prefix / -opensource -no-feature-QWS_MULTIPROCESS -no-feature-SHAREDMEMORY -no-feature-PROCESS -no-feature-SYSTEMSEMAPHORE -no-feature-PRINTER -no-feature-QWS_QPF2 -no-scripttools + \endcode + + \list + \o \c{--hostprefix=$PWD} - specifies the current directory as the base source for Qt + \o \c{-arch integrity} - sets the architecture to INTEGRITY (for atomic operations) + \o \c{-embedded integrity} - builds the embedded version of Qt and sets the architecture to INTEGRITY + \o \c{-xplatform unsupported/qws/integrity-arm-cxarm} - selects the arm-cxarm mkspec for INTEGRITY + \o \c{-static} - specifies a static build of Qt + \o \c{-no-gfx-linuxfb}, \c{-no-mouse-linuxtp}, \c{-no-mouse-pc} and \c{-no-kbd-tty} are Linux specific and won't work on INTEGRITY + \o \c{-no-qt3support} - required since the Qt3 support classes are not supported on INTEGRITY + \o \c{-no-exceptions} - reduces the size of the library by disabling exception support + \o \c{-no-openssl} - disable support for OpenSSL + \o \c{-no-glib} - disable support for unavailable Glib + \o \c{-no-largefile} - disable support for large (> 2TB) files + \o \c{-no-scripttools} - disable support for QtScript tools + \o \c{-qt-gfx-integrity} - enables the experimental gh_FB based display driver + \o \c{-qt-mouse-integrity} - enables the experimental Connection-based mouse driver + \o \c{-qt-kbd-integrity} - enables the experimental Connection-based keyboard driver + \endlist + + The above script will generate MULTI .gpj Project files, not Makefiles. The + main benefit of using these project files is automatic dependency checking, + but this also provides an organization known to INTEGRITY customers. + For Qt libraries, the top-level file is projects.gpj. + + \section1 General Notes + + \list + \o Before you run the above configure line, you may want to modify the values + of INTEGRITY_DIR and INTEGRITY_BSP in unsupported/qws/integrity-arm-cxarm/qmake.conf. + If you do not do this, you will have to modify the resulting generated projects.gpj + + \o GIF support is currently not enabled. + + \o Default .int files are generated. You may want to modify the amount of heap assigned + to each example by modifying the HeapSize declaration in the specific example .int file. + + \o Some of the tools, examples and demos do not compile due to dependencies on QProcess + or other classes that are not available on INTEGRITY. + + \endlist + + \section1 Platform Regressions + +*/ diff --git a/doc/src/platforms/platform-notes.qdoc b/doc/src/platforms/platform-notes.qdoc index aac6bb0..de6eb7f 100644 --- a/doc/src/platforms/platform-notes.qdoc +++ b/doc/src/platforms/platform-notes.qdoc @@ -735,9 +735,9 @@ \row \o QtCore \o \c AllFiles when \l{http://developer.symbian.org/wiki/index.php/Capabilities_%28Symbian_Signed%29/AllFiles_Capability}{accessing specific areas.} \row \o QtDeclarative - \o \c NetworkServices is automatically added for this module. + \o \c NetworkServices is automatically added for this module if no capabilities are explicitly specified. \row \o QtNetwork - \o \c NetworkServices is automatically added for this module. + \o \c NetworkServices is automatically added for this module if no capabilities are explicitly specified. \row \o QtNetwork \o \c ReadUserData is required to include all the phone's SSL certificates in the system's default CA certificate list (for example those added by the user or stored in the SIM card), @@ -745,7 +745,7 @@ \row \o QtMultiMedia \o \c UserEnvironment if QAudioInput is used. \row \o QtWebkit - \o \c NetworkServices is automatically added for this module. + \o \c NetworkServices is automatically added for this module if no capabilities are explicitly specified. \endtable \note Some modules rely on other modules. E.g. QtWebkit and QtDeclarative diff --git a/doc/src/snippets/code/doc_src_installation.qdoc b/doc/src/snippets/code/doc_src_installation.qdoc index cf204b5..5aaa2b0 100644 --- a/doc/src/snippets/code/doc_src_installation.qdoc +++ b/doc/src/snippets/code/doc_src_installation.qdoc @@ -328,9 +328,10 @@ runonphone -s myapp.sis myapp.exe //! [49] //! [50] -nokia_plugin/openc/s60opencsis/openc_ssl_s60_1_6_ss.sis -nokia_plugin/openc/s60opencsis/pips_s60_1_6_ss.sis -nokia_plugin/opencpp/s60opencppsis/stdcpp_s60_1_6_ss.sis +src/s60installs/sqlite3.sis +$EPOCROOT/nokia_plugin/openc/s60opencsis/openc_ssl_s60_1_6_ss.sis +$EPOCROOT/nokia_plugin/openc/s60opencsis/pips_s60_1_6_ss.sis +$EPOCROOT/nokia_plugin/opencpp/s60opencppsis/stdcpp_s60_1_6_ss.sis //! [50] diff --git a/doc/src/snippets/declarative/componentCreation.js b/doc/src/snippets/declarative/componentCreation.js index cf59777..7364139 100644 --- a/doc/src/snippets/declarative/componentCreation.js +++ b/doc/src/snippets/declarative/componentCreation.js @@ -32,13 +32,10 @@ function createSpriteObjects() { //![finishCreation] function finishCreation() { if (component.status == Component.Ready) { - sprite = component.createObject(appWindow); + sprite = component.createObject(appWindow, {"x": 100, "y": 100}); if (sprite == null) { // Error Handling - } else { - sprite.x = 100; - sprite.y = 100; - // ... + console.log("Error creating object"); } } else if (component.status == Component.Error) { // Error Handling diff --git a/doc/src/snippets/qmake/spaces.pro b/doc/src/snippets/qmake/spaces.pro index 544ef05..614d4c5 100644 --- a/doc/src/snippets/qmake/spaces.pro +++ b/doc/src/snippets/qmake/spaces.pro @@ -1,9 +1,9 @@ #! [quoting library paths with spaces] -win32:LIBS += $$quote(C:/mylibs/extra libs/extra.lib) -unix:LIBS += $$quote(-L/home/user/extra libs) -lextra +win32:LIBS += "C:/mylibs/extra libs/extra.lib" +unix:LIBS += "-L/home/user/extra libs" -lextra #! [quoting library paths with spaces] #! [quoting include paths with spaces] -win32:INCLUDEPATH += $$quote(C:/mylibs/extra headers) -unix:INCLUDEPATH += $$quote(/home/user/extra headers) +win32:INCLUDEPATH += "C:/mylibs/extra headers" +unix:INCLUDEPATH += "/home/user/extra headers" #! [quoting include paths with spaces] diff --git a/examples/declarative/keyinteraction/focus/focus.qml b/examples/declarative/keyinteraction/focus/focus.qml index 9cb1fef..935db25 100644 --- a/examples/declarative/keyinteraction/focus/focus.qml +++ b/examples/declarative/keyinteraction/focus/focus.qml @@ -91,7 +91,7 @@ Rectangle { MouseArea { anchors.fill: parent; anchors.margins: -10 - onClicked: window.state = "contextMenuOpen" + onClicked: contextMenu.focus = true } } diff --git a/examples/itemviews/chart/chart.pro b/examples/itemviews/chart/chart.pro index 53601f4..12f08b9 100644 --- a/examples/itemviews/chart/chart.pro +++ b/examples/itemviews/chart/chart.pro @@ -4,7 +4,7 @@ RESOURCES = chart.qrc SOURCES = main.cpp \ mainwindow.cpp \ pieview.cpp -unix:!mac:!symbian:!vxworks:LIBS+= -lm +unix:!mac:!symbian:!vxworks:!integrity:LIBS+= -lm TARGET.EPOCHEAPSIZE = 0x200000 0x800000 diff --git a/examples/painting/painterpaths/painterpaths.pro b/examples/painting/painterpaths/painterpaths.pro index 1f42b41..d096fa6 100644 --- a/examples/painting/painterpaths/painterpaths.pro +++ b/examples/painting/painterpaths/painterpaths.pro @@ -3,7 +3,7 @@ HEADERS = renderarea.h \ SOURCES = main.cpp \ renderarea.cpp \ window.cpp -unix:!mac:!symbian:!vxworks:LIBS += -lm +unix:!mac:!symbian:!vxworks:!integrity:LIBS += -lm # install target.path = $$[QT_INSTALL_EXAMPLES]/painting/painterpaths diff --git a/examples/threads/mandelbrot/mandelbrot.pro b/examples/threads/mandelbrot/mandelbrot.pro index ecbec56..2db886b 100644 --- a/examples/threads/mandelbrot/mandelbrot.pro +++ b/examples/threads/mandelbrot/mandelbrot.pro @@ -4,7 +4,7 @@ SOURCES = main.cpp \ mandelbrotwidget.cpp \ renderthread.cpp -unix:!mac:!symbian:!vxworks:LIBS += -lm +unix:!mac:!symbian:!vxworks:!integrity:LIBS += -lm # install target.path = $$[QT_INSTALL_EXAMPLES]/threads/mandelbrot diff --git a/mkspecs/common/symbian/symbian-makefile.conf b/mkspecs/common/symbian/symbian-makefile.conf index cffc859..b248117 100644 --- a/mkspecs/common/symbian/symbian-makefile.conf +++ b/mkspecs/common/symbian/symbian-makefile.conf @@ -33,7 +33,7 @@ QMAKE_LINK_OBJECT_SCRIPT = objects is_using_gnupoc { DEFINES *= __QT_PRODUCT_INCLUDE_IS_LOWERCASE__ } -QMAKE_SYMBIAN_INCLUDES = $$[QT_INSTALL_DATA]/mkspecs/common/symbian/symbianincludes.h +QMAKE_SYMBIAN_INCLUDES = $$IN_PWD/symbianincludes.h symbian-armcc { QMAKE_CFLAGS += --preinclude $$QMAKE_SYMBIAN_INCLUDES QMAKE_CXXFLAGS += --preinclude $$QMAKE_SYMBIAN_INCLUDES diff --git a/mkspecs/features/default_post.prf b/mkspecs/features/default_post.prf index 9fb9f10..3f93220 100644 --- a/mkspecs/features/default_post.prf +++ b/mkspecs/features/default_post.prf @@ -83,8 +83,8 @@ breakpad { win32:PROJECTPATH ~= s,/,\\, !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$QMAKE_POST_LINK$$escape_expand(\\n\\t) - QMAKE_POST_LINK += $$quote($${QT_BREAKPAD_ROOT_PATH}$${DIR_SEPARATOR}qtbreakpadsymbols \"$$DEBUGFILENAME\" \"$$PROJECTPATH\") - !isEmpty(QMAKE_STRIP):QMAKE_POST_LINK = $$quote($$QMAKE_POST_LINK$$escape_expand(\\n\\t)$$QMAKE_STRIP \"$$DEBUGFILENAME\") + QMAKE_POST_LINK = $$QMAKE_POST_LINK$$quote($${QT_BREAKPAD_ROOT_PATH}$${QMAKE_DIR_SEP}qtbreakpadsymbols \"$$DEBUGFILENAME\" \"$$PROJECTPATH\") + !isEmpty(QMAKE_STRIP):QMAKE_POST_LINK = $$QMAKE_POST_LINK$$escape_expand(\\n\\t)$$quote($$QMAKE_STRIP \"$$DEBUGFILENAME\") unset(TARGET_BASEPATH) unset(SYMBOLFILENAME) diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 1fb6298..5baf7ce 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -58,15 +58,15 @@ defineTest(qtAddLibrary) { # Needed for because relative inclusion problem in toolchain INCLUDEPATH *= $$QMAKE_INCDIR_QT/QtXmlPatterns INCLUDEPATH *= $$QMAKE_INCDIR_QT/QtNetwork - TARGET.CAPABILITY *= NetworkServices + isEmpty(TARGET.CAPABILITY): TARGET.CAPABILITY = NetworkServices isEmpty(TARGET.EPOCHEAPSIZE):TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 } else:isEqual(LIB_NAME, QtXmlPatterns) { # Needed for #include <QtXmlPatterns/QtXmlPatterns> because relative inclusion problem in toolchain INCLUDEPATH *= $$QMAKE_INCDIR_QT/QtNetwork } else:isEqual(LIB_NAME, QtNetwork) { - TARGET.CAPABILITY *= NetworkServices + isEmpty(TARGET.CAPABILITY): TARGET.CAPABILITY = NetworkServices } else:isEqual(LIB_NAME, QtDeclarative) { - TARGET.CAPABILITY *= NetworkServices + isEmpty(TARGET.CAPABILITY): TARGET.CAPABILITY = NetworkServices isEmpty(TARGET.EPOCHEAPSIZE):TARGET.EPOCHEAPSIZE = 0x20000 0x2000000 } export(TARGET.EPOCHEAPSIZE) diff --git a/mkspecs/features/unix/gdb_dwarf_index.prf b/mkspecs/features/unix/gdb_dwarf_index.prf index c647bae..14c4c38 100644 --- a/mkspecs/features/unix/gdb_dwarf_index.prf +++ b/mkspecs/features/unix/gdb_dwarf_index.prf @@ -1,7 +1,7 @@ !CONFIG(separate_debug_info):CONFIG(debug, debug|release):!staticlib:!static:!contains(TEMPLATE, subdirs):!isEmpty(QMAKE_OBJCOPY) { QMAKE_GDB_INDEX = { test -z \"$(DESTDIR)\" || cd \"$(DESTDIR)\"; } && \ - test \$\$(gdb --version | sed -e \'s,[^(]*(GDB).\\([0-9]\\)\\.\\([0-9]\\).*,\\1\\2,;q\') -gt 72 && \ + test \$\$(gdb --version | sed -e \'s,[^(]*(GDB)[^)]\\([0-9]\\)\\.\\([0-9]\\).*,\\1\\2,;q\') -gt 72 && \ gdb --nx --batch --quiet -ex \'set confirm off\' -ex \'save gdb-index .\' -ex quit \'$(TARGET)\' && \ test -f $(TARGET).gdb-index && \ $$QMAKE_OBJCOPY --add-section \'.gdb_index=$(TARGET).gdb-index\' --set-section-flags \'.gdb_index=readonly\' \'$(TARGET)\' \'$(TARGET)\' && \ diff --git a/mkspecs/features/win32/embed_manifest_dll.prf b/mkspecs/features/win32/embed_manifest_dll.prf index 69c9d1d..013668d 100644 --- a/mkspecs/features/win32/embed_manifest_dll.prf +++ b/mkspecs/features/win32/embed_manifest_dll.prf @@ -7,6 +7,6 @@ NOPATH_TARGET ~= s,^(.*/)+,, # Remove all paths QMAKE_LFLAGS += /MANIFEST $$quote(/MANIFESTFILE:\"$${MANIFEST_DIR}\\$${NOPATH_TARGET}.intermediate.manifest\") !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK - QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest \"$$replace(MANIFEST_DIR,/,\\)\\$${NOPATH_TARGET}.intermediate.manifest\" -outputresource:$(DESTDIR_TARGET);2$$escape_expand(\\n\\t))$$QMAKE_POST_LINK + QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest \"$$replace(MANIFEST_DIR,/,\\)\\$${NOPATH_TARGET}.intermediate.manifest\" -outputresource:$(DESTDIR_TARGET);2)$$QMAKE_POST_LINK QMAKE_CLEAN += \"$$replace(MANIFEST_DIR,/,\\)\\$${NOPATH_TARGET}.intermediate.manifest\" } diff --git a/mkspecs/features/win32/embed_manifest_exe.prf b/mkspecs/features/win32/embed_manifest_exe.prf index 44aadfa..872949e 100644 --- a/mkspecs/features/win32/embed_manifest_exe.prf +++ b/mkspecs/features/win32/embed_manifest_exe.prf @@ -7,6 +7,6 @@ if(win32-msvc2005*|win32-msvc2008*|win32-msvc2010*):!equals(TEMPLATE_PREFIX, "vc NOPATH_TARGET ~= s,^(.*/)+,, # Remove all paths QMAKE_LFLAGS += /MANIFEST $$quote(/MANIFESTFILE:\"$${MANIFEST_DIR}\\$${NOPATH_TARGET}.intermediate.manifest\") !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK = $$escape_expand(\\n\\t)$$QMAKE_POST_LINK - QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest \"$$replace(MANIFEST_DIR,/,\\)\\$${NOPATH_TARGET}.intermediate.manifest\" -outputresource:$(DESTDIR_TARGET);1$$escape_expand(\\n\\t))$$QMAKE_POST_LINK + QMAKE_POST_LINK = $$quote(mt.exe -nologo -manifest \"$$replace(MANIFEST_DIR,/,\\)\\$${NOPATH_TARGET}.intermediate.manifest\" -outputresource:$(DESTDIR_TARGET);1)$$QMAKE_POST_LINK QMAKE_CLEAN += \"$$replace(MANIFEST_DIR,/,\\)\\$${NOPATH_TARGET}.intermediate.manifest\" } diff --git a/mkspecs/symbian-gcce/qmake.conf b/mkspecs/symbian-gcce/qmake.conf index 1d1053c..f550751a 100644 --- a/mkspecs/symbian-gcce/qmake.conf +++ b/mkspecs/symbian-gcce/qmake.conf @@ -54,7 +54,7 @@ DEFINES += __GCCE__ \ UNICODE QMAKE_LFLAGS_APP += --entry=_E32Startup -u _E32Startup -QMAKE_LFLAGS_SHLIB += -shared --default-symver --entry _E32Dll -u _E32Dll +QMAKE_LFLAGS_SHLIB += -shared --default-symver --entry=_E32Dll -u _E32Dll QMAKE_LFLAGS_PLUGIN += $$QMAKE_LFLAGS_SHLIB gcceExtraFlags = --include=$${EPOCROOT}epoc32/include/gcce/gcce.h -march=armv5t -mapcs -mthumb-interwork -nostdinc -c -msoft-float -T script diff --git a/mkspecs/symbian-sbsv2/flm/qt/qmake_clean.flm b/mkspecs/symbian-sbsv2/flm/qt/qmake_clean.flm new file mode 100644 index 0000000..fe35e6e --- /dev/null +++ b/mkspecs/symbian-sbsv2/flm/qt/qmake_clean.flm @@ -0,0 +1,18 @@ +# /**************************************************************************** +# ** +# ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +# ** Contact: Nokia Corporation (qt-info@nokia.com) +# ** +# ** This file is part of symbian-sbsv2 mkspec. +# ** +# ****************************************************************************/ + + +SINGLETON:=$(call sanitise,QMAKE_CLEAN_SINGLETON_$(EXTENSION_ROOT)) + +ifeq ($($(SINGLETON)),) +# Prevent duplicate targets from being created +$(SINGLETON):=1 +$(eval $(call GenerateStandardCleanTarget,$(CLEAN_FILES),'')) +endif + diff --git a/mkspecs/symbian-sbsv2/flm/qt/qmake_emulator_deployment.flm b/mkspecs/symbian-sbsv2/flm/qt/qmake_emulator_deployment.flm index 39ab0f0..8791a47 100644 --- a/mkspecs/symbian-sbsv2/flm/qt/qmake_emulator_deployment.flm +++ b/mkspecs/symbian-sbsv2/flm/qt/qmake_emulator_deployment.flm @@ -33,5 +33,6 @@ ifeq ($($(SINGLETON)),) $(eval $(call qmake_emulator_deployment, $(subst $(CHAR_SPACE),\$(CHAR_SPACE),$(DEPLOY_TARGET)), $(subst $(CHAR_SPACE),\$(CHAR_SPACE),$(DEPLOY_SOURCE)))) $(call makepath,$(dir $(DEPLOY_TARGET))) $(eval $(call GenerateStandardCleanTarget,$(CLEAN_TARGET),'')) +$(eval $(call whatmacro,$(CLEAN_TARGET))) endif diff --git a/mkspecs/symbian-sbsv2/flm/qt/qt.xml b/mkspecs/symbian-sbsv2/flm/qt/qt.xml index ddd8d55..f2f32ee 100644 --- a/mkspecs/symbian-sbsv2/flm/qt/qt.xml +++ b/mkspecs/symbian-sbsv2/flm/qt/qt.xml @@ -38,4 +38,9 @@ <interface name="qt.qmake_store_build" extends="Symbian.UserFLM" flm="qmake_store_build.flm"> </interface> + + <interface name="qt.qmake_clean" extends="Symbian.UserFLM" + flm="qmake_clean.flm"> + <param name='CLEAN_FILES' /> + </interface> </build> diff --git a/mkspecs/unsupported/integrity-ghs/qmake.conf b/mkspecs/unsupported/integrity-ghs/qmake.conf new file mode 100644 index 0000000..822d6bb --- /dev/null +++ b/mkspecs/unsupported/integrity-ghs/qmake.conf @@ -0,0 +1,72 @@ +# +# qmake configuration for integrity-ghs +# + +MAKEFILE_GENERATOR = GBUILD +#MAKEFILE_GENERATOR = UNIX +TEMPLATE = app +CONFIG += qt warn_on release integrity unix +QT += core gui network + +QMAKE_CFLAGS = -bsp $$INTEGRITY_BSP -os_dir $__OS_DIR +QMAKE_CFLAGS += --diag_suppress=1,228,236,381,611,997 +QMAKE_CFLAGS_WARN_ON = +QMAKE_CFLAGS_WARN_OFF = -w +QMAKE_CFLAGS_RELEASE = -g -Ospeed -Olink --signed_fields --no_commons +QMAKE_CFLAGS_DEBUG = -g --no_commons --signed_fields +QMAKE_CFLAGS_SHLIB = +QMAKE_CFLAGS_THREAD = -D_REENTRANT + +QMAKE_CXXFLAGS = $$QMAKE_CFLAGS --no_implicit_include --link_once_templates +QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON +QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF +QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE +QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG +QMAKE_CXXFLAGS_SHLIB = $$QMAKE_CFLAGS_SHLIB +QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC +QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD + +QMAKE_INCDIR = +QMAKE_LIBDIR = +QMAKE_INCDIR_X11 = +QMAKE_LIBDIR_X11 = +QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] +QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS] +QMAKE_INCDIR_OPENGL = +QMAKE_LIBDIR_OPENGL = +QMAKE_INCDIR_QTOPIA = $(QPEDIR)/include +QMAKE_LIBDIR_QTOPIA = $(QPEDIR)/lib + +QMAKE_LFLAGS = -lposix -livfs -lnet -lsocket -lfbdev -ldl +QMAKE_LFLAGS_RELEASE = -g -Ospeed -Olink --no_commons -non_shared --link_once_templates +QMAKE_LFLAGS_DEBUG = -g --no_commons +QMAKE_LFLAGS_SHLIB = +QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB +QMAKE_LFLAGS_SONAME = +QMAKE_LFLAGS_THREAD = +QMAKE_LFLAGS_RPATH = + +QMAKE_LIBS = +QMAKE_LIBS_DYNLOAD = -ldl +QMAKE_LIBS_X11 = +QMAKE_LIBS_X11SM = +QMAKE_LIBS_QTOPIA = +QMAKE_LIBS_THREAD = + +QMAKE_MOC = $$[QT_INSTALL_BINS]/moc +QMAKE_UIC = $$[QT_INSTALL_BINS]/uic + +QMAKE_AR = ar cqs +QMAKE_RANLIB = + +QMAKE_TAR = tar -cf +QMAKE_GZIP = gzip -9f + +QMAKE_COPY = cp -f +QMAKE_MOVE = mv -f +QMAKE_DEL_FILE = rm -f +QMAKE_DEL_DIR = rmdir +QMAKE_CHK_DIR_EXISTS = test -d +QMAKE_MKDIR = mkdir -p +load(qt_config) + diff --git a/mkspecs/unsupported/integrity-ghs/qplatformdefs.h b/mkspecs/unsupported/integrity-ghs/qplatformdefs.h new file mode 100644 index 0000000..adfb374 --- /dev/null +++ b/mkspecs/unsupported/integrity-ghs/qplatformdefs.h @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// Get Qt defines/settings + +#include "qglobal.h" + +// Set any POSIX/XOPEN defines at the top of this file to turn on specific APIs + +#include <unistd.h> + +// We are hot - unistd.h should have turned on the specific APIs we requested + +#include <pthread.h> +#include <dirent.h> +#include <fcntl.h> +#include <grp.h> +#include <pwd.h> +#include <signal.h> +#include <dlfcn.h> +#include <limits.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <netinet/in.h> +#ifndef QT_NO_IPV6IFNAME +#include <net/if.h> +#endif + +#ifdef QT_LARGEFILE_SUPPORT +#define QT_STATBUF struct stat64 +#define QT_STATBUF4TSTAT struct stat64 +#define QT_STAT ::stat64 +#define QT_FSTAT ::fstat64 +#define QT_LSTAT ::lstat64 +#define QT_OPEN ::open64 +#define QT_TRUNCATE ::truncate64 +#define QT_FTRUNCATE ::ftruncate64 +#define QT_LSEEK ::lseek64 +#else +#define QT_STATBUF struct stat +#define QT_STATBUF4TSTAT struct stat +#define QT_STAT ::stat +#define QT_FSTAT ::fstat +#define QT_LSTAT ::lstat +#define QT_OPEN ::open +#define QT_TRUNCATE ::truncate +#define QT_FTRUNCATE ::ftruncate +#define QT_LSEEK ::lseek +#endif + +#ifdef QT_LARGEFILE_SUPPORT +#define QT_FOPEN ::fopen64 +#define QT_FSEEK ::fseeko64 +#define QT_FTELL ::ftello64 +#define QT_FGETPOS ::fgetpos64 +#define QT_FSETPOS ::fsetpos64 +#define QT_FPOS_T fpos64_t +#define QT_OFF_T off64_t +#else +#define QT_FOPEN ::fopen +#define QT_FSEEK ::fseek +#define QT_FTELL ::ftell +#define QT_FGETPOS ::fgetpos +#define QT_FSETPOS ::fsetpos +#define QT_FPOS_T fpos_t +#define QT_OFF_T long +#endif + +#define QT_STAT_REG S_IFREG +#define QT_STAT_DIR S_IFDIR +#define QT_STAT_MASK S_IFMT +#define QT_STAT_LNK S_IFLNK +#define QT_SOCKET_CONNECT ::connect +#define QT_SOCKET_BIND ::bind +#define QT_FILENO fileno +#ifndef QT_CLOSE +#define QT_CLOSE ::close +#endif +#ifndef QT_READ +#define QT_READ ::read +#endif +#ifndef QT_WRITE +#define QT_WRITE ::write +#endif +#define QT_ACCESS ::access +#define QT_GETCWD ::getcwd +#define QT_CHDIR ::chdir +#define QT_MKDIR ::mkdir +#define QT_RMDIR ::rmdir +#define QT_OPEN_RDONLY O_RDONLY +#define QT_OPEN_WRONLY O_WRONLY +#define QT_OPEN_RDWR O_RDWR +#define QT_OPEN_CREAT O_CREAT +#define QT_OPEN_TRUNC O_TRUNC +#define QT_OPEN_APPEND O_APPEND + +#define QT_SIGNAL_RETTYPE void +#define QT_SIGNAL_ARGS int +#define QT_SIGNAL_IGNORE SIG_IGN + +#define QT_MMAP ::mmap + +// Directory iteration +#define QT_DIR DIR + +#define QT_OPENDIR ::opendir +#define QT_CLOSEDIR ::closedir + + +#if defined(QT_LARGEFILE_SUPPORT) \ + && defined(QT_USE_XOPEN_LFS_EXTENSIONS) \ + && !defined(QT_NO_READDIR64) +# define QT_DIRENT struct dirent64 +# define QT_READDIR ::readdir64 +# define QT_READDIR_R ::readdir64_r +#else +# define QT_DIRENT struct dirent +# define QT_READDIR ::readdir +# define QT_READDIR_R ::readdir_r +#endif + +#define QT_SOCKLEN_T socklen_t + +#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500) +#define QT_SNPRINTF ::snprintf +#define QT_VSNPRINTF ::vsnprintf +#endif + +#ifndef MAXNAMLEN +# define MAXNAMLEN NAME_MAX +#endif + +#ifndef PATH_MAX +# define PATH_MAX MAXPATHLEN +#endif + +#ifndef NSIG +# define NSIG _SIGMAX +#endif + +#ifndef MAP_ANON +# define MAP_ANON 0 +#endif + +typedef void (*sighandler_t)(int); + +#ifndef QT_NO_MMAP +# define QT_NO_MMAP +#endif + +#ifndef QT_NO_SHAREDMEMORY +# define QT_NO_SHAREDMEMORY +#endif + +#ifndef QT_NO_SYSTEMSEMAPHORE +# define QT_NO_SYSTEMSEMAPHORE +#endif + diff --git a/mkspecs/unsupported/qws/integrity-arm-cxarm/qmake.conf b/mkspecs/unsupported/qws/integrity-arm-cxarm/qmake.conf new file mode 100644 index 0000000..acaf3c2 --- /dev/null +++ b/mkspecs/unsupported/qws/integrity-arm-cxarm/qmake.conf @@ -0,0 +1,12 @@ +# +# qmake configuration for integrity-ghs +# + +INTEGRITY_DIR = /enter/your/path/to/INTEGRITY +INTEGRITY_BSP = enter_your_bsp_name_here +QMAKE_CC = ccintarm +QMAKE_CXX = cxintarm +QMAKE_LINK = cxintarm +QMAKE_LINK_SHLIB = cxintarm +include(../../integrity-ghs/qmake.conf) + diff --git a/mkspecs/unsupported/qws/integrity-arm-cxarm/qplatformdefs.h b/mkspecs/unsupported/qws/integrity-arm-cxarm/qplatformdefs.h new file mode 100644 index 0000000..e19f8dd --- /dev/null +++ b/mkspecs/unsupported/qws/integrity-arm-cxarm/qplatformdefs.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the qmake spec 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 "../../integrity-ghs/qplatformdefs.h" diff --git a/mkspecs/unsupported/qws/integrity-ppc-cxppc/qmake.conf b/mkspecs/unsupported/qws/integrity-ppc-cxppc/qmake.conf new file mode 100644 index 0000000..829e6d3 --- /dev/null +++ b/mkspecs/unsupported/qws/integrity-ppc-cxppc/qmake.conf @@ -0,0 +1,12 @@ +# +# qmake configuration for integrity-ghs +# + +INTEGRITY_DIR = /enter/your/path/to/INTEGRITY +INTEGRITY_BSP = enter_your_bsp_name_here +QMAKE_CC = ccintppc +QMAKE_CXX = cxintppc +QMAKE_LINK = cxintppc +QMAKE_LINK_SHLIB = cxintppc +include(../../integrity-ghs/qmake.conf) + diff --git a/mkspecs/unsupported/qws/integrity-ppc-cxppc/qplatformdefs.h b/mkspecs/unsupported/qws/integrity-ppc-cxppc/qplatformdefs.h new file mode 100644 index 0000000..e19f8dd --- /dev/null +++ b/mkspecs/unsupported/qws/integrity-ppc-cxppc/qplatformdefs.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the qmake spec 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 "../../integrity-ghs/qplatformdefs.h" diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix index a24076e..fd502e0 100644 --- a/qmake/Makefile.unix +++ b/qmake/Makefile.unix @@ -11,7 +11,7 @@ OBJS=project.o property.o main.o makefile.o unixmake2.o unixmake.o \ meta.o makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \ borland_bmake.o msvc_vcproj.o msvc_vcxproj.o msvc_nmake.o msvc_objectmodel.o msbuild_objectmodel.o \ symmake.o initprojectdeploy_symbian.o symmake_abld.o symmake_sbsv2.o \ - symbiancommon.o registry.o epocroot.o + symbiancommon.o registry.o epocroot.o gbuild.o #qt code QOBJS=qtextcodec.o qutfcodec.o qstring.o qtextstream.o qiodevice.o qmalloc.o qglobal.o \ @@ -38,6 +38,7 @@ DEPEND_SRC=project.cpp property.cpp meta.cpp main.cpp generators/makefile.cpp ge $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp \ generators/symbian/symmake_abld.cpp generators/symbian/symmake_sbsv2.cpp \ generaters/symbian/symbiancommon.cpp \ + generators/integrity/gbuild.cpp \ $(SOURCE_PATH)/src/corelib/codecs/qtextcodec.cpp $(SOURCE_PATH)/src/corelib/codecs/qutfcodec.cpp \ $(SOURCE_PATH)/src/corelib/tools/qstring.cpp $(SOURCE_PATH)/src/corelib/io/qfile.cpp \ $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp $(SOURCE_PATH)/src/corelib/io/qiodevice.cpp \ @@ -68,7 +69,8 @@ DEPEND_SRC=project.cpp property.cpp meta.cpp main.cpp generators/makefile.cpp ge $(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp \ $(QTSRCS) -CPPFLAGS = -I. -Igenerators -Igenerators/unix -Igenerators/win32 -Igenerators/mac -Igenerators/symbian \ +CPPFLAGS = -g -I. -Igenerators -Igenerators/unix -Igenerators/win32 \ + -Igenerators/mac -Igenerators/symbian -Igenerators/integrity \ -I$(BUILD_PATH)/include -I$(BUILD_PATH)/include/QtCore \ -I$(BUILD_PATH)/src/corelib/global -I$(BUILD_PATH)/src/corelib/xml \ -I$(SOURCE_PATH)/tools/shared \ @@ -318,6 +320,9 @@ registry.o: $(SOURCE_PATH)/tools/shared/windows/registry.cpp epocroot.o: $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp +gbuild.o: generators/integrity/gbuild.cpp + $(CXX) -c -o $@ $(CXXFLAGS) generators/integrity/gbuild.cpp + projectgenerator.o: generators/projectgenerator.cpp $(CXX) -c -o $@ $(CXXFLAGS) generators/projectgenerator.cpp diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32 index 4d29537..0ab2932 100644 --- a/qmake/Makefile.win32 +++ b/qmake/Makefile.win32 @@ -31,7 +31,7 @@ CFLAGS_EXTRA = /MP CFLAGS_BARE = -c -Fo./ \ -W3 -nologo -O2 \ $(CFLAGS_EXTRA) \ - -I. -Igenerators -Igenerators\unix -Igenerators\win32 -Igenerators\mac -Igenerators\symbian \ + -I. -Igenerators -Igenerators\unix -Igenerators\win32 -Igenerators\mac -Igenerators\symbian -Igenerators\integrity \ -I$(BUILD_PATH)\include -I$(BUILD_PATH)\include\QtCore \ -I$(SOURCE_PATH)\include -I$(SOURCE_PATH)\include\QtCore \ -I$(BUILD_PATH)\src\corelib\global \ @@ -62,7 +62,8 @@ OBJS = project.obj main.obj makefile.obj unixmake.obj unixmake2.obj mingw makefiledeps.obj metamakefile.obj xmloutput.obj pbuilder_pbx.obj \ borland_bmake.obj msvc_nmake.obj msvc_vcproj.obj msvc_vcxproj.obj \ msvc_objectmodel.obj msbuild_objectmodel.obj symmake.obj initprojectdeploy_symbian.obj \ - symmake_abld.obj symmake_sbsv2.obj symbiancommon.obj registry.obj epocroot.obj + symmake_abld.obj symmake_sbsv2.obj symbiancommon.obj registry.obj epocroot.obj \ + gbuild.obj !IFDEF QMAKE_OPENSOURCE_EDITION CFLAGS = $(CFLAGS) -DQMAKE_OPENSOURCE_EDITION @@ -169,6 +170,9 @@ qmake_pch.obj: {$(SOURCE_PATH)\qmake\generators\symbian}.cpp{}.obj:: $(CXX) $(CXXFLAGS) $< +{$(SOURCE_PATH)\qmake\generators\integrity}.cpp{}.obj:: + $(CXX) $(CXXFLAGS) $< + {$(SOURCE_PATH)\qmake\generators\unix}.cpp{}.obj:: $(CXX) $(CXXFLAGS) $< diff --git a/qmake/Makefile.win32-g++ b/qmake/Makefile.win32-g++ index 59ac8c2..0707a3a 100644 --- a/qmake/Makefile.win32-g++ +++ b/qmake/Makefile.win32-g++ @@ -15,7 +15,7 @@ CXX = g++ CFLAGS = -c -o$@ -O \ -I. -Igenerators -Igenerators/unix \ -Igenerators/win32 -Igenerators/mac \ - -Igenerators/symbian \ + -Igenerators/symbian -Igenerators/integrity \ -I$(BUILD_PATH)/include -I$(BUILD_PATH)/include/QtCore \ -I$(SOURCE_PATH)/include -I$(SOURCE_PATH)/include/QtCore \ -I$(BUILD_PATH)/src/corelib/global \ @@ -39,7 +39,7 @@ OBJS = project.o main.o makefile.o unixmake.o unixmake2.o mingw_make.o \ makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \ borland_bmake.o msvc_nmake.o msvc_vcproj.o msvc_vcxproj.o \ msvc_objectmodel.o msbuild_objectmodel.o symmake.o initprojectdeploy_symbian.o \ - symmake_abld.o symmake_sbsv2.o symbiancommon.o registry.o epocroot.o + symmake_abld.o symmake_sbsv2.o symbiancommon.o registry.o epocroot.o gbuild.o ifdef QMAKE_OPENSOURCE_EDITION CFLAGS += -DQMAKE_OPENSOURCE_EDITION @@ -311,6 +311,9 @@ registry.o: $(SOURCE_PATH)/tools/shared/windows/registry.cpp epocroot.o: $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp +gbuild.o: $(SOURCE_PATH)/qmake/generators/integrity/gbuild.cpp + $(CXX) $(CXXFLAGS) generators/integrity/gbuild.cpp + project.o: $(SOURCE_PATH)/qmake/project.cpp $(SOURCE_PATH)/qmake/project.h $(SOURCE_PATH)/qmake/option.h $(CXX) $(CXXFLAGS) project.cpp diff --git a/qmake/Makefile.win32-g++-sh b/qmake/Makefile.win32-g++-sh index a84b3f6..c3537e3 100644 --- a/qmake/Makefile.win32-g++-sh +++ b/qmake/Makefile.win32-g++-sh @@ -15,7 +15,7 @@ CXX = g++ CFLAGS = -c -o$@ -O \ -I. -Igenerators -Igenerators/unix \ -Igenerators/win32 -Igenerators/mac \ - -Igenerators/symbian \ + -Igenerators/symbian -Igenerators/integrity \ -I$(BUILD_PATH)/include -I$(BUILD_PATH)/include/QtCore \ -I$(SOURCE_PATH)/include -I$(SOURCE_PATH)/include/QtCore \ -I$(BUILD_PATH)/src/corelib/global \ @@ -39,7 +39,7 @@ OBJS = project.o main.o makefile.o unixmake.o unixmake2.o mingw_make.o \ makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \ borland_bmake.o msvc_nmake.o msvc_vcproj.o msvc_vcxproj.o \ msvc_objectmodel.o msbuild_objectmodel.o symmake.o initprojectdeploy_symbian.o \ - symmake_abld.o symmake_sbsv2.o symbiancommon.o registry.o epocroot.o + symmake_abld.o symmake_sbsv2.o symbiancommon.o registry.o epocroot.o gbuild.o ifdef QMAKE_OPENSOURCE_EDITION CFLAGS += -DQMAKE_OPENSOURCE_EDITION @@ -310,6 +310,10 @@ registry.o: $(SOURCE_PATH)/tools/shared/windows/registry.cpp epocroot.o: $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp $(CXX) $(CXXFLAGS) $(SOURCE_PATH)/tools/shared/symbian/epocroot.cpp +gbuild.o: $(SOURCE_PATH)/qmake/generators/integrity/gbuild.cpp + $(CXX) $(CXXFLAGS) generators/integrity/gbuild.cpp + + project.o: $(SOURCE_PATH)/qmake/project.cpp $(SOURCE_PATH)/qmake/project.h $(SOURCE_PATH)/qmake/option.h $(CXX) $(CXXFLAGS) project.cpp diff --git a/qmake/generators/integrity/gbuild.cpp b/qmake/generators/integrity/gbuild.cpp new file mode 100644 index 0000000..17bd8f0 --- /dev/null +++ b/qmake/generators/integrity/gbuild.cpp @@ -0,0 +1,442 @@ +/**************************************************************************** +** +** 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 "gbuild.h" +#include "option.h" +#include "meta.h" +#include <qdir.h> +#include <qregexp.h> +#include <qcryptographichash.h> +#include <qdebug.h> +#include <stdlib.h> +#include <time.h> +#ifdef Q_OS_UNIX +# include <sys/types.h> +# include <sys/stat.h> +#endif + +QT_BEGIN_NAMESPACE + +unsigned int dllbase = 0x01000000; +#define DLLOFFSET 0x600000 + +GBuildMakefileGenerator::GBuildMakefileGenerator() : MakefileGenerator() +{ + nativebins << "moc" << "rcc" << "uic" << "bootstrap"; +} + +bool +GBuildMakefileGenerator::write() +{ + QStringList tmp; + QString filename(Option::output.fileName()); + QString pathtoremove(qmake_getpwd()); + QString relpath(pathtoremove); + QString strtarget(project->first("TARGET")); + bool isnativebin = nativebins.contains(strtarget); + relpath.replace(Option::output_dir, ""); + + /* correct output for non-prl, non-recursive case */ + QString outname(qmake_getpwd()); + outname += QDir::separator(); + outname += fileInfo(Option::output.fileName()).baseName(); + outname += projectSuffix(); + Option::output.close(); + Option::output.setFileName(outname); + MakefileGenerator::openOutput(Option::output, QString()); + + if (strtarget != fileInfo(project->projectFile()).baseName()) { + QString gpjname(strtarget); + QString outputName(qmake_getpwd()); + outputName += QDir::separator(); + outputName += fileInfo(project->projectFile()).baseName(); + outputName += projectSuffix(); + QFile f(outputName); + f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate); + QTextStream t(&f); + t << "#!gbuild\n"; + t << "[Project]\n"; + t << gpjname << projectSuffix() << "\n"; + if ((project->first("TEMPLATE") == "lib") + && project->isActiveConfig("shared")) + t << gpjname << "_shared" << projectSuffix() << "\n"; + t.flush(); + gpjname += projectSuffix(); + Option::output.close(); + Option::output.setFileName(gpjname); + MakefileGenerator::openOutput(Option::output, QString()); + } + + if ((project->first("TEMPLATE") == "app") + && (!isnativebin)) { + QTextStream t(&Option::output); + QString intname(strtarget); + intname += ".int"; + /* this is for bulding an INTEGRITY application. + * generate the .int integrate file and the .gpj INTEGRITY Application + * project file, then go on with regular files */ + t << "#!gbuild" << "\n"; + t << "[INTEGRITY Application]" << "\n"; + t << "\t:binDirRelative=.\n"; + t << "\t-o " << strtarget << "\n"; + t << intname << "\n"; + t << strtarget << "_app" << projectSuffix() << "\n"; + t.flush(); + + /* generate integrate file */ + QFile f(intname); + f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate); + QTextStream ti(&f); + ti << "# This is a file automatically generated by qmake" << "\n"; + ti << "# Modifications will be lost next time you run qmake" << "\n"; + ti << "Kernel" << "\n"; + ti << "\tFilename\tDynamicDownload" << "\n"; + ti << "EndKernel" << "\n" << "\n"; + ti << "AddressSpace" << "\n"; + ti << "\tName\t" << strtarget << "\n"; + ti << "\tFilename\t" << strtarget << "_app" << "\n"; + ti << "\tMemoryPoolSize\t0x100000" << "\n"; + ti << "\tLanguage\tC++" << "\n"; + /* FIXME : heap size is huge to be big enough for every example + * it should probably be tailored for each example, btu there is no + * good way to guess that */ + ti << "\tHeapSize\t0x00D00000" << "\n"; + ti << "\tTask\tInitial" << "\n"; + ti << "\t\tStackSize\t0x30000" << "\n"; + ti << "\tEndTask" << "\n"; + ti << "EndAddressSpace" << "\n"; + ti.flush(); + + /* change current project file to <projectname>_app.gpj and continue + * generation */ + filename.insert(filename.lastIndexOf("."), "_app"); + Option::output.close(); + Option::output.setFileName(filename); + MakefileGenerator::openOutput(Option::output, QString()); + } else if ((project->first("TEMPLATE") == "lib") + && project->isActiveConfig("shared")) { + QString gpjname(strtarget); + gpjname += "_shared"; + gpjname += projectSuffix(); + QFile f(gpjname); + f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate); + QTextStream t(&f); + t << "#!gbuild\n" + "[Program]\n" + "\t-A libINTEGRITY.so\n" + "\t-A libc.so\n" + "\t-A libscxx.so\n" + "\t-A libQtCore.so\n" + "\t-e __ghsbegin_text\n" + "\t-startfile=-\n" + "\t:syslibraries=-\n" + "\t-Onolink\n"; + t << "\t-o lib" << strtarget << ".so\n"; + t << "\t-l" << strtarget << "\n"; + t << "\t-extractall=-l" << strtarget << "\n"; + t << "\t:outputDir=work/" << filename.section(QDir::separator(), 0, -1).remove(".gpj") << "\n"; + t << strtarget << "_shared.ld\n"; + t << "$(__OS_DIR)/intlib/sharedobjbssinit.c\n"; + t.flush(); + + QFile fl(strtarget + "_shared.ld"); + fl.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate); + QTextStream tl(&fl); + tl << "CONSTANTS {\n" + " __INTEGRITY_MinPageAlign = 16K\n" + " __INTEGRITY_MaxPageAlign = 16K\n" + " __INTEGRITY_LibCBaseAddress = \n"; + tl << dllbase << "\n"; + tl << "}\n" + "-sec\n" + "{\n" + " .picbase __INTEGRITY_LibCBaseAddress :\n" + " .text :\n" + " .syscall :\n" + " .intercall :\n" + " .interfunc :\n" + " .secinfo :\n" + " .rodata align(16) :\n" + " .fixaddr :\n" + " .fixtype :\n" + " .rombeg :\n" + " .textchecksum :\n" + " // The above sections may be large. Leave a bigger gap for large pages.\n" + " .pidbase align(__INTEGRITY_MaxPageAlign) :\n" + " .sdabase :\n" + " .data :\n" + " .toc :\n" + " .opd :\n" + " .datachecksum :\n" + " .bss align(__INTEGRITY_MinPageAlign) :\n" + " .heap :\n" + "}\n"; + tl.flush(); + dllbase += DLLOFFSET; + } + + warn_msg(WarnParser, Option::output.fileName().toAscii()); + QTextStream t(&Option::output); + QString primaryTarget(project->values("QMAKE_CXX").at(0)); + + pathtoremove += QDir::separator(); + filename.remove(qmake_getpwd()); + + //HEADER + t << "#!gbuild" << "\n"; + + /* find the architecture out of the compiler name */ + if (filename.endsWith("projects.gpj")) { + primaryTarget.remove(0, 5); + t << "macro QT_BUILD_DIR=%expand_path(.)\n"; + t << "macro __OS_DIR=" << project->values("INTEGRITY_DIR").first() << "\n"; + t << "primaryTarget=" << primaryTarget << "_integrity.tgt" << "\n"; + t << "customization=util/integrity/qt.bod\n"; + } + /* project type */ + if (project->first("TEMPLATE") == "app") { + t << "[Program]" << "\n"; + if (isnativebin) { + t << "\t:binDir=bin\n"; + t << "\t-o " << strtarget << "\n"; + } else { + t << "\t:binDirRelative=.\n"; + t << "\t-o " << strtarget << "_app\n"; + } + } else if (project->first("TEMPLATE") == "lib") { + t << "[Library]" << "\n"; + t << "\t:binDir=lib" << "\n"; + t << "\t-o lib" << strtarget << ".a" << "\n"; + } else if (project->first("TEMPLATE") == "subdirs") + t << "[Project]" << "\n"; + else + t << project->first("TEMPLATE") << "\n"; + + /* compilations options */ + t << "\t:sourceDir=." << "\n"; + + t << "\t:outputDir=work" << relpath << "\n"; + if (filename.endsWith("projects.gpj")) { + t << "\t:sourceDir=work\n"; + t << "\t-Iwork\n"; + t << "\t-Llib\n"; + t << "\t"; + QStringList &l = project->values("QMAKE_CXXFLAGS"); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) { + if ((*it).startsWith("-")) + t << "\n" << "\t" << (*it); + else + t << " " << (*it); + } + t << "\n"; + } + t << "\n"; + + t << varGlue("DEFINES", "\t-D", "\n\t-D", "\n"); + + t << "\t-I.\n\t-I" << specdir() << "\n"; + t << varGlue("INCLUDEPATH", "\t-I", "\n\t-I", "\n"); + t << "\t--cxx_include_directory .\n\t--cxx_include_directory " << specdir() << "\n"; + t << varGlue("INCLUDEPATH", "\t--cxx_include_directory ", "\n\t--cxx_include_directory ", "\n"); + + if (project->first("TEMPLATE") == "app") { + /* include linker flags if it's an application */ + QString src[] = { "QMAKE_LFLAGS", "QMAKE_FRAMEWORKPATH_FLAGS", "QMAKE_LIBDIR_FLAGS", "QMAKE_LIBS", "LIBS", QString() }; + for (int i = 0; !src[i].isNull(); i++) { + /* skip target libraries for native tools */ + if (isnativebin && (i == 0)) + continue; + t << "\t"; + QStringList &l = project->values(src[i]); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) { + if ((*it).startsWith("-")) + t << "\n" << "\t" << (*it); + else + t << " " << (*it); + } + t << "\n"; + } + } + + /* first subdirectories/subprojects */ + { + QStringList &l = project->values("SUBDIRS"); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) { + QString gpjname((*it)); + /* avoid native tools */ + if (nativebins.contains(gpjname.section("_", -1))) + continue; + if (!project->first((*it) + ".subdir").isEmpty()) + gpjname = project->first((*it) + ".subdir"); + else + gpjname.replace("_", QDir::separator()); + gpjname += QDir::separator() + gpjname.section(QDir::separator(), -1); + gpjname += projectSuffix(); + /* make relative */ + if (!project->values("QT_SOURCE_TREE").isEmpty()) { + gpjname.replace(project->values("QT_SOURCE_TREE").first() + QDir::separator(), ""); + } + t << gpjname << "\n"; + } + } + + { + QStringList &l = project->values("RESOURCES"); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) { + QString tmpstr((*it).replace(pathtoremove, "")); + t << tmpstr << "\t[Qt Resource]\n"; + tmpstr = tmpstr.section(".", -2, -1).section(QDir::separator(), -1); + tmpstr.remove(".qrc"); + t << "\t-name " << tmpstr << "\n"; + tmpstr.insert(tmpstr.lastIndexOf(QDir::separator()) + 1, "qrc_"); + tmpstr.append(".cpp"); + t << "\t-o work/" << tmpstr << "\n"; + } + } + { + QStringList &l = project->values("FORMS"); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) { + QString tmpstr((*it).replace(pathtoremove, "")); + t << tmpstr << "\t[Qt Dialog]\n"; + tmpstr = tmpstr.section(".", 0, 0).section(QDir::separator(), -1); + tmpstr.insert(tmpstr.lastIndexOf(QDir::separator()) + 1, "ui_"); + tmpstr.remove(".ui"); + tmpstr.append(".h"); + t << "\t-o work/" << tmpstr << "\n"; + } + } + + /* source files for this project */ + QString src[] = { "HEADERS", "SOURCES", QString() }; + for (int i = 0; !src[i].isNull(); i++) { + QStringList &l = project->values(src[i]); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) { + if ((*it).isEmpty()) + continue; + /* native tools aren't preprocessed */ + if (!isnativebin) + t << writeOne((*it), pathtoremove); + else + t << (*it).remove(pathtoremove) << "\n"; + } + } + t << "\n"; + + { + QStringList &l = project->values("GENERATED_SOURCES"); + for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) { + t << "work/" << (*it).section(QDir::separator(), -1) << "\n"; + } + } + + return true; +} + +QString GBuildMakefileGenerator::writeOne(QString filename, QString pathtoremove) +{ + QString s(""); + s += filename.remove(pathtoremove); + if (filename.endsWith(Option::h_ext.first())) { + QString corename(filename.section(QDir::separator(), -1)); + corename.remove(Option::h_ext.first()); + corename.append(Option::cpp_ext.first()); + corename.prepend(Option::h_moc_mod); + s += "\t[MOC/Qt Header]\n"; + s += "\t-o "; + s += "work/"; + s += corename; + s += "\n"; + } else if (filename.section(QDir::separator(), -1).startsWith("qrc_")) { + QString tmpstr(filename.section("/", -1).section(".", 0, -1).remove("qrc_").remove(".cpp")); + s += "\n\t:depends="; + s += tmpstr; + s += ".qrc"; + s += "\n"; + } else if (filename.endsWith(Option::cpp_ext.first())) { + QString tmpstr(filename.section("/", -1)); +// QString moctool(project->values("QMAKE_MOC").first()); + QString filepath(pathtoremove); + if (!project->values("QT_SOURCE_TREE").isEmpty()) { + filepath.remove(project->values("QT_SOURCE_TREE").first()); + filepath.remove(0, 1); + } +// if (!project->values("QT_BUILD_TREE").isEmpty()) { +// moctool.remove(project->values("QT_BUILD_TREE").first()); +// moctool.remove(0, 1); +// } + s += "\n\t:preexecShellSafe='${QT_BUILD_DIR}/bin/moc "; +// s += moctool; +// s += " "; + s += varGlue("DEFINES", "-D", " -D", " "); + s += varGlue("INCLUDEPATH", "-I", " -I", " "); + s += filepath; + s += filename; + s += " -o "; + tmpstr.replace(Option::cpp_ext.first(), Option::cpp_moc_ext); + s += "work/"; + s += tmpstr; + s += "\n"; + } else + s += "\n"; + return s; +} + +bool +GBuildMakefileGenerator::openOutput(QFile &file, const QString &build) const +{ + debug_msg(1, "file is %s", file.fileName().toLatin1().constData()); + QFileInfo fi(file); + if (fi.filePath().isEmpty()) + file.setFileName(qmake_getpwd() + QDir::separator() + file.fileName()); + if (!file.fileName().endsWith(projectSuffix())) { + QString outputName(file.fileName()); + outputName += QDir::separator(); + outputName += fileInfo(project->projectFile()).baseName(); + outputName += projectSuffix(); + warn_msg(WarnParser, outputName.toAscii()); + file.setFileName(outputName); + } + debug_msg(1, "file is %s", file.fileName().toLatin1().constData()); + bool ret = MakefileGenerator::openOutput(file, QString()); + return ret; +} + +QT_END_NAMESPACE diff --git a/qmake/generators/integrity/gbuild.h b/qmake/generators/integrity/gbuild.h new file mode 100644 index 0000000..6b5b1a0 --- /dev/null +++ b/qmake/generators/integrity/gbuild.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 GBUILD_H +#define GBUILD_H + +#include "makefile.h" + +QT_BEGIN_NAMESPACE + +class GBuildMakefileGenerator : public MakefileGenerator +{ + virtual bool write(); + + QString projectSuffix() const { return QString(".gpj"); }; + QString writeOne(QString filename, QString pathtoremove = ""); + +public: + GBuildMakefileGenerator(); + ~GBuildMakefileGenerator(); + + virtual bool supportsMetaBuild() { return false; } + virtual bool openOutput(QFile &, const QString &) const; +protected: + bool doPrecompiledHeaders() const { return false; } + virtual bool doDepends() const { return true; } + QStringList nativebins; + +}; + +inline GBuildMakefileGenerator::~GBuildMakefileGenerator() +{ } + +QT_END_NAMESPACE + +#endif // GBUILD_H diff --git a/qmake/generators/metamakefile.cpp b/qmake/generators/metamakefile.cpp index ae48ddd..a3fba6a 100644 --- a/qmake/generators/metamakefile.cpp +++ b/qmake/generators/metamakefile.cpp @@ -138,12 +138,12 @@ BuildsMetaMakefileGenerator::init() Build *build = new Build; build->name = name; build->makefile = createMakefileGenerator(project, false); - if (build->makefile){ + if (build->makefile){ makefiles += build; - }else { - delete build; - return false; - } + }else { + delete build; + return false; + } } return true; } @@ -179,7 +179,7 @@ BuildsMetaMakefileGenerator::write(const QString &oldpwd) using_stdout = true; } else { if(Option::output.fileName().isEmpty() && - Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE) + Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE) Option::output.setFileName(project->first("QMAKE_MAKEFILE")); Option::output_dir = oldpwd; QString build_name = build->name; @@ -306,7 +306,7 @@ SubdirsMetaMakefileGenerator::init() && project->isRecursive()); if(recurse) { QString old_output_dir = Option::output_dir; - QString old_output = Option::output.fileName(); + QString old_output = Option::output.fileName(); QString oldpwd = qmake_getpwd(); QString thispwd = oldpwd; if(!thispwd.endsWith('/')) @@ -387,7 +387,7 @@ SubdirsMetaMakefileGenerator::init() self->input_dir = qmake_getpwd(); self->output_dir = Option::output_dir; if(!recurse || (!Option::output.fileName().endsWith(Option::dir_sep) && !QFileInfo(Option::output).isDir())) - self->output_file = Option::output.fileName(); + self->output_file = Option::output.fileName(); self->makefile = new BuildsMetaMakefileGenerator(project, name, false); self->makefile->init(); subs.append(self); @@ -420,10 +420,10 @@ SubdirsMetaMakefileGenerator::write(const QString &oldpwd) writepwd = oldpwd; if(!(ret = subs.at(i)->makefile->write(writepwd))) break; - //restore because I'm paranoid + //restore because I'm paranoid qmake_setpwd(pwd); - Option::output.setFileName(output_name); - Option::output_dir = output_dir; + Option::output.setFileName(output_name); + Option::output_dir = output_dir; } return ret; } @@ -448,6 +448,7 @@ QT_BEGIN_INCLUDE_NAMESPACE #include "symmake_abld.h" #include "symmake_sbsv2.h" #include "symbian_makefile.h" +#include "gbuild.h" QT_END_INCLUDE_NAMESPACE MakefileGenerator * @@ -491,6 +492,8 @@ MetaMakefileGenerator::createMakefileGenerator(QMakeProject *proj, bool noIO) mkfile = new SymbianMakefileTemplate<UnixMakefileGenerator>; } else if(gen == "SYMBIAN_MINGW") { mkfile = new SymbianMakefileTemplate<MingwMakefileGenerator>; + } else if(gen == "GBUILD") { + mkfile = new GBuildMakefileGenerator; } else { fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData()); } @@ -556,6 +559,9 @@ MetaMakefileGenerator::modesForGenerator(const QString &gen, *host_mode = Option::HOST_WIN_MODE; #endif *target_mode = Option::TARG_SYMBIAN_MODE; + } else if (gen == "GBUILD") { + *host_mode = Option::HOST_UNIX_MODE; + *target_mode = Option::TARG_INTEGRITY_MODE; } else { fprintf(stderr, "Unknown generator specified: %s\n", gen.toLatin1().constData()); return false; diff --git a/qmake/generators/symbian/symmake_sbsv2.cpp b/qmake/generators/symbian/symmake_sbsv2.cpp index 9eccd46..f94a63f 100644 --- a/qmake/generators/symbian/symmake_sbsv2.cpp +++ b/qmake/generators/symbian/symmake_sbsv2.cpp @@ -721,6 +721,18 @@ void SymbianSbsv2MakefileGenerator::writeBldInfExtensionRulesPart(QTextStream& t t << "END" << endl; t << endl; + // Handle QMAKE_CLEAN + QStringList cleanFiles = project->values("QMAKE_CLEAN"); + if (!cleanFiles.isEmpty()) { + QStringList absoluteCleanFiles; + foreach (QString cleanFile, cleanFiles) { + QFileInfo fi(cleanFile); + absoluteCleanFiles << fi.absoluteFilePath(); + } + t << "START EXTENSION qt/qmake_clean" << endl; + t << "OPTION CLEAN_FILES " << absoluteCleanFiles.join(" ") << endl; + t << "END" << endl; + } t << endl; } diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index d7145b4..5ea13f4 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -536,7 +536,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) t << "\n\t" << "-$(MOVE) $(TARGET) " << destdir; if(!project->isEmpty("QMAKE_POST_LINK")) - t << "\n\t" << var("QMAKE_POST_LINK") << "\n\t"; + t << "\n\t" << var("QMAKE_POST_LINK"); t << endl << endl; } else if(!project->isEmpty("QMAKE_BUNDLE")) { t << "\n\t" diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 603ffb5..c85533b 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -701,10 +701,10 @@ void Win32MakefileGenerator::writeStandardParts(QTextStream &t) if(project->isActiveConfig("shared") && !project->values("DLLDESTDIR").isEmpty()) { QStringList dlldirs = project->values("DLLDESTDIR"); for (QStringList::Iterator dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir) { - t << "\n\t" << "-$(COPY_FILE) \"$(DESTDIR_TARGET)\" " << Option::fixPathToTargetOS(*dlldir, false); + t << "\t" << "-$(COPY_FILE) \"$(DESTDIR_TARGET)\" " << Option::fixPathToTargetOS(*dlldir, false) << endl; } } - t << endl << endl; + t << endl; writeRcFilePart(t); diff --git a/qmake/option.cpp b/qmake/option.cpp index fcbf5fa..1354281 100644 --- a/qmake/option.cpp +++ b/qmake/option.cpp @@ -260,6 +260,8 @@ Option::parseCommandLine(int argc, char **argv, int skip) Option::host_mode = HOST_WIN_MODE; Option::target_mode = TARG_WIN_MODE; Option::target_mode_overridden = true; + } else if(opt == "integrity") { + Option::target_mode = TARG_INTEGRITY_MODE; } else if(opt == "d") { Option::debug_level++; } else if(opt == "version" || opt == "v" || opt == "-version") { diff --git a/qmake/option.h b/qmake/option.h index 23be12f..e3ddc9a 100644 --- a/qmake/option.h +++ b/qmake/option.h @@ -156,7 +156,7 @@ struct Option enum HOST_MODE { HOST_UNKNOWN_MODE, HOST_UNIX_MODE, HOST_WIN_MODE, HOST_MACX_MODE }; static HOST_MODE host_mode; enum TARG_MODE { TARG_UNKNOWN_MODE, TARG_UNIX_MODE, TARG_WIN_MODE, TARG_MACX_MODE, - TARG_SYMBIAN_MODE }; + TARG_SYMBIAN_MODE, TARG_INTEGRITY_MODE }; static TARG_MODE target_mode; static bool target_mode_overridden; static QString user_template, user_template_prefix; diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp index b3c229e..d8027ff 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITStubs.cpp @@ -1168,8 +1168,17 @@ DEFINE_STUB_FUNCTION(int, timeout_check) globalData->exception = createInterruptedExecutionException(globalData); VM_THROW_EXCEPTION_AT_END(); } - - CHECK_FOR_EXCEPTION_AT_END(); +#ifdef QT_BUILD_SCRIPT_LIB + else { + // It's possible that the call to QtScript's implementation of + // TimeoutChecker::didTimeOut() caused an error to be thrown. + // In that case, didTimeOut() should still return false, since + // we don't want the interrupted-exception to override the + // user-thrown error. But we need to check for exception here, + // otherwise JSC would continue normal execution. + CHECK_FOR_EXCEPTION_AT_END(); + } +#endif return timeoutChecker->ticksUntilNextCheck(); } diff --git a/src/3rdparty/webkit/WebCore/WebCore.pro b/src/3rdparty/webkit/WebCore/WebCore.pro index e82ec4c..2de6961 100644 --- a/src/3rdparty/webkit/WebCore/WebCore.pro +++ b/src/3rdparty/webkit/WebCore/WebCore.pro @@ -15,7 +15,7 @@ symbian: { webkitlibs.path = /sys/bin vendorinfo = \ "; Localised Vendor name" \ - "%{\"Nokia, Qt\"}" \ + "%{\"Nokia\"}" \ " " \ "; Unique Vendor name" \ ":\"Nokia, Qt\"" \ diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebkitglobal.h b/src/3rdparty/webkit/WebKit/qt/Api/qwebkitglobal.h index 63d9e55..2c0bf6d 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebkitglobal.h +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebkitglobal.h @@ -22,9 +22,9 @@ #include <QtCore/qglobal.h> -#define QTWEBKIT_VERSION_STR "2.0.1" +#define QTWEBKIT_VERSION_STR "2.0.2" // QTWEBKIT_VERSION is (major << 16) + (minor << 8) + patch. Similar to Qt. -#define QTWEBKIT_VERSION 0x020001 +#define QTWEBKIT_VERSION 0x020002 // Use: #if (QTWEBKIT_VERSION >= QTWEBKIT_VERSION_CHECK(2, 0, 0)). Similar to Qt. #define QTWEBKIT_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) diff --git a/src/3rdparty/zlib/zlib.h b/src/3rdparty/zlib/zlib.h index 9e5b467..bdb9a3d 100644 --- a/src/3rdparty/zlib/zlib.h +++ b/src/3rdparty/zlib/zlib.h @@ -1171,7 +1171,7 @@ ZEXTERN int Q_ZEXPORT gzgetc OF((gzFile file)); or -1 in case of end of file or error. */ -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +ZEXTERN int Q_ZEXPORT gzungetc OF((int c, gzFile file)); /* Push one character back onto the stream to be read again later. Only one character of push-back is allowed. gzungetc() returns the diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 7c16f7e..2d5cfab 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -404,6 +404,8 @@ void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d) The default animation system is driven by a timer that fires at regular intervals. In some scenarios, it is better to drive the animation based on other synchronization mechanisms, such as the vertical refresh rate of the screen. + + \internal */ QAnimationDriver::QAnimationDriver(QObject *parent) @@ -420,6 +422,8 @@ QAnimationDriver::QAnimationDriver(QAnimationDriverPrivate &dd, QObject *parent) /*! Advances the animation based on the current time. This function should be continuously called by the driver while the animation is running. + + \internal */ void QAnimationDriver::advance() { @@ -434,6 +438,8 @@ void QAnimationDriver::advance() /*! Installs this animation driver. The animation driver is thread local and will only apply for the thread its installed in. + + \internal */ void QAnimationDriver::install() { @@ -471,6 +477,8 @@ void QAnimationDriver::stop() This function is called by the animation framework to notify the driver that it should start running. + + \internal */ /*! @@ -478,6 +486,8 @@ void QAnimationDriver::stop() This function is called by the animation framework to notify the driver that it should stop running. + + \internal */ /*! @@ -491,6 +501,7 @@ QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer) void QDefaultAnimationDriver::timerEvent(QTimerEvent *e) { Q_ASSERT(e->timerId() == m_timer.timerId()); + Q_UNUSED(e); // if the assertions are disabled advance(); } diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h index 957b9d5..0900870 100644 --- a/src/corelib/animation/qabstractanimation.h +++ b/src/corelib/animation/qabstractanimation.h @@ -140,7 +140,7 @@ class Q_CORE_EXPORT QAnimationDriver : public QObject Q_DECLARE_PRIVATE(QAnimationDriver) public: - QAnimationDriver(QObject *parent); + QAnimationDriver(QObject *parent = 0); void advance(); void install(); @@ -148,8 +148,8 @@ public: bool isRunning() const; protected: - virtual void started() = 0; - virtual void stopped() = 0; + virtual void started() {}; + virtual void stopped() {}; QAnimationDriver(QAnimationDriverPrivate &dd, QObject *parent = 0); diff --git a/src/corelib/arch/arch.pri b/src/corelib/arch/arch.pri index 971069f..cd23e5e 100644 --- a/src/corelib/arch/arch.pri +++ b/src/corelib/arch/arch.pri @@ -12,6 +12,8 @@ symbian:HEADERS += arch/qatomic_symbian.h \ vxworks:HEADERS += arch/qatomic_vxworks.h +integrity:HEADERS += arch/qatomic_integrity.h + !wince*:!win32:!mac:!symbian:HEADERS += arch/qatomic_alpha.h \ arch/qatomic_avr32.h \ arch/qatomic_ia64.h \ diff --git a/src/corelib/arch/integrity/arch.pri b/src/corelib/arch/integrity/arch.pri new file mode 100644 index 0000000..2c4196e --- /dev/null +++ b/src/corelib/arch/integrity/arch.pri @@ -0,0 +1,3 @@ +# +# INTEGRITY RTOS architecture +# diff --git a/src/corelib/arch/qatomic_arch.h b/src/corelib/arch/qatomic_arch.h index f32aec7..3da833a 100644 --- a/src/corelib/arch/qatomic_arch.h +++ b/src/corelib/arch/qatomic_arch.h @@ -46,7 +46,9 @@ QT_BEGIN_HEADER #include "QtCore/qglobal.h" -#if defined(QT_ARCH_VXWORKS) +#if defined(QT_ARCH_INTEGRITY) +# include "QtCore/qatomic_integrity.h" +#elif defined(QT_ARCH_VXWORKS) # include "QtCore/qatomic_vxworks.h" #elif defined(QT_ARCH_ALPHA) # include "QtCore/qatomic_alpha.h" diff --git a/src/corelib/arch/qatomic_armv5.h b/src/corelib/arch/qatomic_armv5.h index f0f2f9a..820be7b 100644 --- a/src/corelib/arch/qatomic_armv5.h +++ b/src/corelib/arch/qatomic_armv5.h @@ -107,7 +107,7 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree() // kernel places a restartable cmpxchg implementation at a fixed address extern "C" typedef int (qt_atomic_eabi_cmpxchg_int_t)(int oldval, int newval, volatile int *ptr); -extern "C" typedef int (qt_atomic_eabi_cmpxchg_ptr_t)(const void *oldval, void *newval, volatile void *ptr); +extern "C" typedef int (qt_atomic_eabi_cmpxchg_ptr_t)(const void *oldval, const void *newval, volatile void *ptr); #define qt_atomic_eabi_cmpxchg_int (*reinterpret_cast<qt_atomic_eabi_cmpxchg_int_t *>(0xffff0fc0)) #define qt_atomic_eabi_cmpxchg_ptr (*reinterpret_cast<qt_atomic_eabi_cmpxchg_ptr_t *>(0xffff0fc0)) diff --git a/src/corelib/arch/qatomic_integrity.h b/src/corelib/arch/qatomic_integrity.h new file mode 100644 index 0000000..6563903 --- /dev/null +++ b/src/corelib/arch/qatomic_integrity.h @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** 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 QATOMIC_INTEGRITY_H +#define QATOMIC_INTEGRITY_H + +#include <INTEGRITY.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define qt_i2addr(a) reinterpret_cast<Address *>(const_cast<int *>(a)) +#define qt_p2addr(a) reinterpret_cast<Address *>(const_cast<void *>(a)) +#define qt_addr(a) reinterpret_cast<Address>(a) + + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return false; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE + +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetNative() +{ return true; } +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE + +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreNative() +{ return true; } +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE + +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddNative() +{ return true; } +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree() +{ return true; } + +// Reference counting + +inline bool QBasicAtomicInt::ref() +{ + int oldval; + AtomicModify(qt_i2addr(&_q_value), qt_i2addr(&oldval), 0, 1); + return _q_value != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + int oldval; + AtomicModify(qt_i2addr(&_q_value), qt_i2addr(&oldval), 0, -1U); + return _q_value != 0; +} + +// Test and set for integers + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return TestAndSet(qt_i2addr(&_q_value), expectedValue, newValue) == Success; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for integers + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + int old_val; + do { + old_val = _q_value; + } while (TestAndSet(qt_i2addr(&_q_value), old_val, newValue) != Success); + return old_val; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for integers + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + int old_val; + do { + old_val = _q_value; + } while (TestAndSet(qt_i2addr(&_q_value), old_val, old_val + valueToAdd) != Success); + return old_val; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +// Test and set for pointers + +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return TestAndSet((Address*)&_q_value, qt_addr(expectedValue), qt_addr(newValue)) == Success; +} + +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template <typename T> +Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for pointers + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue) +{ + Address old_val; + do { + old_val = *reinterpret_cast<Address *>(const_cast<T *>(newValue)); + } while (TestAndSet(reinterpret_cast<Address *>(const_cast<T **>(&_q_value)), old_val, qt_addr(newValue)) != Success); + return reinterpret_cast<T *>(old_val); +} + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for pointers + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + AtomicModify(qt_p2addr(&_q_value), qt_addr(_q_value), qt_addr(_q_value) + valueToAdd * sizeof(T)); + return _q_value; +} + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template <typename T> +Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_INTEGRITY_H + diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index 93ed5ed..3c3d39e 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -64,7 +64,7 @@ #ifndef QT_NO_CODECS # include "qtsciicodec_p.h" # include "qisciicodec_p.h" -#ifndef Q_OS_SYMBIAN +#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_INTEGRITY) # if defined(QT_NO_ICONV) && !defined(QT_BOOTSTRAPPED) // no iconv(3) support, must build all codecs into the library # include "../../plugins/codecs/cn/qgb18030codec.h" @@ -772,7 +772,7 @@ static void setup() # endif // Q_WS_X11 -#ifndef Q_OS_SYMBIAN +#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_INTEGRITY) # if defined(QT_NO_ICONV) && !defined(QT_BOOTSTRAPPED) // no asian codecs when bootstrapping, sorry (void)new QGb18030Codec; @@ -805,7 +805,7 @@ static void setup() (void)new QLatin1Codec; (void)new QUtf8Codec; -#ifndef Q_OS_SYMBIAN +#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_INTEGRITY) #if defined(Q_OS_UNIX) && !defined(QT_NO_ICONV) && !defined(QT_BOOTSTRAPPED) // QIconvCodec depends on the UTF-16 codec, so it needs to be created last (void) new QIconvCodec(); diff --git a/src/corelib/concurrent/qfutureinterface.cpp b/src/corelib/concurrent/qfutureinterface.cpp index 6256944..627d0c7 100644 --- a/src/corelib/concurrent/qfutureinterface.cpp +++ b/src/corelib/concurrent/qfutureinterface.cpp @@ -421,9 +421,11 @@ bool QFutureInterfaceBase::referenceCountIsOne() const QFutureInterfaceBasePrivate::QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState) : refCount(1), m_progressValue(0), m_progressMinimum(0), m_progressMaximum(0), - state(initialState), progressTimeStarted(false), pendingResults(0), + state(initialState), pendingResults(0), manualProgress(false), m_expectedResultCount(0), runnable(0) -{ } +{ + progressTime.invalidate(); +} int QFutureInterfaceBasePrivate::internal_resultCount() const { @@ -455,12 +457,11 @@ bool QFutureInterfaceBasePrivate::internal_updateProgress(int progress, m_progressValue = progress; m_progressText = progressText; - if (progressTimeStarted == true && m_progressValue != m_progressMaximum) // make sure the first and last steps are emitted. + if (progressTime.isValid() && m_progressValue != m_progressMaximum) // make sure the first and last steps are emitted. if (progressTime.elapsed() < (1000 / MaxProgressEmitsPerSecond)) return false; progressTime.start(); - progressTimeStarted = true; return true; } diff --git a/src/corelib/concurrent/qfutureinterface_p.h b/src/corelib/concurrent/qfutureinterface_p.h index 7f93c75..538947e 100644 --- a/src/corelib/concurrent/qfutureinterface_p.h +++ b/src/corelib/concurrent/qfutureinterface_p.h @@ -53,7 +53,7 @@ // We mean it. // -#include <QtCore/qdatetime.h> +#include <QtCore/qelapsedtimer.h> #include <QtCore/qcoreevent.h> #include <QtCore/qlist.h> #include <QtCore/qwaitcondition.h> @@ -137,8 +137,7 @@ public: int m_progressMinimum; int m_progressMaximum; QFutureInterfaceBase::State state; - QTime progressTime; - bool progressTimeStarted; + QElapsedTimer progressTime; QWaitCondition pausedWaitCondition; int pendingResults; QtConcurrent::ResultStoreBase m_results; diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index fb39ee5..134ef2f 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1738,7 +1738,7 @@ QSysInfo::WinVersion QSysInfo::windowsVersion() if (winver) return winver; winver = QSysInfo::WV_NT; - OSVERSIONINFOW osver; + OSVERSIONINFO osver; osver.dwOSVersionInfoSize = sizeof(osver); GetVersionEx(&osver); #ifdef Q_OS_WINCE diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 960fe6e..9c03dc3 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -369,7 +369,20 @@ namespace QT_NAMESPACE {} */ #if defined(__ghs) -# define Q_OUTOFLINE_TEMPLATE inline +# define Q_OUTOFLINE_TEMPLATE inline + +/* the following are necessary because the GHS C++ name mangling relies on __*/ +# define Q_CONSTRUCTOR_FUNCTION0(AFUNC) \ + static const int AFUNC ## _init_variable_ = AFUNC(); +# define Q_CONSTRUCTOR_FUNCTION(AFUNC) Q_CONSTRUCTOR_FUNCTION0(AFUNC) +# define Q_DESTRUCTOR_FUNCTION0(AFUNC) \ + class AFUNC ## _dest_class_ { \ + public: \ + inline AFUNC ## _dest_class_() { } \ + inline ~ AFUNC ## _dest_class_() { AFUNC(); } \ + } AFUNC ## _dest_instance_; +# define Q_DESTRUCTOR_FUNCTION(AFUNC) Q_DESTRUCTOR_FUNCTION0(AFUNC) + #endif /* Symantec C++ is now Digital Mars */ @@ -460,7 +473,6 @@ namespace QT_NAMESPACE {} # if defined(__INTEL_COMPILER) /* Intel C++ also masquerades as GCC 3.2.0 */ # define Q_CC_INTEL -# define Q_NO_TEMPLATE_FRIENDS # endif # if defined(__clang__) /* Clang also masquerades as GCC 4.2.1 */ @@ -763,6 +775,24 @@ namespace QT_NAMESPACE {} # error "Qt has not been tested with this compiler - talk to qt-bugs@trolltech.com" #endif +#ifdef Q_CC_INTEL +# if __INTEL_COMPILER < 1200 +# define Q_NO_TEMPLATE_FRIENDS +# endif +# if defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) +# if __INTEL_COMPILER >= 1100 +# define Q_COMPILER_RVALUE_REFS +# define Q_COMPILER_EXTERN_TEMPLATES +# elif __INTEL_COMPILER >= 1200 +# define Q_COMPILER_VARIADIC_TEMPLATES +# define Q_COMPILER_AUTO_TYPE +# define Q_COMPILER_DEFAULT_DELETE_MEMBERS +# define Q_COMPILER_CLASS_ENUM +# define Q_COMPILER_LAMBDA +# endif +# endif +#endif + #ifndef Q_PACKED # define Q_PACKED # undef Q_NO_PACKED_REFERENCE @@ -1428,7 +1458,7 @@ class QDataStream; # define Q_AUTOTEST_EXPORT #endif -inline void qt_noop() {} +inline void qt_noop(void) {} /* These wrap try/catch so we can switch off exceptions later. @@ -1798,32 +1828,32 @@ public: inline ~QGlobalStatic() { pointer = 0; } }; -#define Q_GLOBAL_STATIC(TYPE, NAME) \ - static TYPE *NAME() \ - { \ - static TYPE this_##NAME; \ - static QGlobalStatic<TYPE > global_##NAME(&this_##NAME); \ - return global_##NAME.pointer; \ +#define Q_GLOBAL_STATIC(TYPE, NAME) \ + static TYPE *NAME() \ + { \ + static TYPE thisVariable; \ + static QGlobalStatic<TYPE > thisGlobalStatic(&thisVariable); \ + return thisGlobalStatic.pointer; \ } -#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ - static TYPE *NAME() \ - { \ - static TYPE this_##NAME ARGS; \ - static QGlobalStatic<TYPE > global_##NAME(&this_##NAME); \ - return global_##NAME.pointer; \ +#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ + static TYPE *NAME() \ + { \ + static TYPE thisVariable ARGS; \ + static QGlobalStatic<TYPE > thisGlobalStatic(&thisVariable); \ + return thisGlobalStatic.pointer; \ } -#define Q_GLOBAL_STATIC_WITH_INITIALIZER(TYPE, NAME, INITIALIZER) \ - static TYPE *NAME() \ - { \ - static TYPE this_##NAME; \ - static QGlobalStatic<TYPE > global_##NAME(0); \ - if (!global_##NAME.pointer) { \ - TYPE *x = global_##NAME.pointer = &this_##NAME; \ - INITIALIZER; \ - } \ - return global_##NAME.pointer; \ +#define Q_GLOBAL_STATIC_WITH_INITIALIZER(TYPE, NAME, INITIALIZER) \ + static TYPE *NAME() \ + { \ + static TYPE thisVariable; \ + static QGlobalStatic<TYPE > thisGlobalStatic(0); \ + if (!thisGlobalStatic.pointer) { \ + TYPE *x = thisGlobalStatic.pointer = &thisVariable; \ + INITIALIZER; \ + } \ + return thisGlobalStatic.pointer; \ } #else @@ -1858,50 +1888,50 @@ public: } }; -#define Q_GLOBAL_STATIC_INIT(TYPE, NAME) \ - static QGlobalStatic<TYPE > this_##NAME = { Q_BASIC_ATOMIC_INITIALIZER(0), false } - -#define Q_GLOBAL_STATIC(TYPE, NAME) \ - Q_GLOBAL_STATIC_INIT(TYPE, NAME); \ - static TYPE *NAME() \ - { \ - if (!this_##NAME.pointer && !this_##NAME.destroyed) { \ - TYPE *x = new TYPE; \ - if (!this_##NAME.pointer.testAndSetOrdered(0, x)) \ - delete x; \ - else \ - static QGlobalStaticDeleter<TYPE > cleanup(this_##NAME); \ - } \ - return this_##NAME.pointer; \ +#define Q_GLOBAL_STATIC(TYPE, NAME) \ + static TYPE *NAME() \ + { \ + static QGlobalStatic<TYPE > thisGlobalStatic \ + = { Q_BASIC_ATOMIC_INITIALIZER(0), false }; \ + if (!thisGlobalStatic.pointer && !thisGlobalStatic.destroyed) { \ + TYPE *x = new TYPE; \ + if (!thisGlobalStatic.pointer.testAndSetOrdered(0, x)) \ + delete x; \ + else \ + static QGlobalStaticDeleter<TYPE > cleanup(thisGlobalStatic); \ + } \ + return thisGlobalStatic.pointer; \ } -#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ - Q_GLOBAL_STATIC_INIT(TYPE, NAME); \ - static TYPE *NAME() \ - { \ - if (!this_##NAME.pointer && !this_##NAME.destroyed) { \ - TYPE *x = new TYPE ARGS; \ - if (!this_##NAME.pointer.testAndSetOrdered(0, x)) \ - delete x; \ - else \ - static QGlobalStaticDeleter<TYPE > cleanup(this_##NAME); \ - } \ - return this_##NAME.pointer; \ +#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \ + static TYPE *NAME() \ + { \ + static QGlobalStatic<TYPE > thisGlobalStatic \ + = { Q_BASIC_ATOMIC_INITIALIZER(0), false }; \ + if (!thisGlobalStatic.pointer && !thisGlobalStatic.destroyed) { \ + TYPE *x = new TYPE ARGS; \ + if (!thisGlobalStatic.pointer.testAndSetOrdered(0, x)) \ + delete x; \ + else \ + static QGlobalStaticDeleter<TYPE > cleanup(thisGlobalStatic); \ + } \ + return thisGlobalStatic.pointer; \ } -#define Q_GLOBAL_STATIC_WITH_INITIALIZER(TYPE, NAME, INITIALIZER) \ - Q_GLOBAL_STATIC_INIT(TYPE, NAME); \ - static TYPE *NAME() \ - { \ - if (!this_##NAME.pointer && !this_##NAME.destroyed) { \ - QScopedPointer<TYPE > x(new TYPE); \ - INITIALIZER; \ - if (this_##NAME.pointer.testAndSetOrdered(0, x.data())) { \ - static QGlobalStaticDeleter<TYPE > cleanup(this_##NAME); \ - x.take(); \ - } \ - } \ - return this_##NAME.pointer; \ +#define Q_GLOBAL_STATIC_WITH_INITIALIZER(TYPE, NAME, INITIALIZER) \ + static TYPE *NAME() \ + { \ + static QGlobalStatic<TYPE > thisGlobalStatic \ + = { Q_BASIC_ATOMIC_INITIALIZER(0), false }; \ + if (!thisGlobalStatic.pointer && !thisGlobalStatic.destroyed) { \ + QScopedPointer<TYPE > x(new TYPE); \ + INITIALIZER; \ + if (thisGlobalStatic.pointer.testAndSetOrdered(0, x.data())) { \ + static QGlobalStaticDeleter<TYPE > cleanup(thisGlobalStatic); \ + x.take(); \ + } \ + } \ + return thisGlobalStatic.pointer; \ } #endif @@ -2469,9 +2499,14 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); # define QT_SYMBIAN_SUPPORTS_SGIMAGE #endif -#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS +#ifdef SYMBIAN_GRAPHICS_SET_SURFACE_TRANSPARENCY_AVAILABLE # define Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE #endif + +#ifdef SYMBIAN_GRAPHICS_TRANSITION_EFFECTS_SIGNALING_AVAILABLE +# define Q_SYMBIAN_TRANSITION_EFFECTS +#endif + #endif //Symbian does not support data imports from a DLL diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 4d4ae21..2b61192 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -113,3 +113,7 @@ win32 { LIBS += -lplatformenv } } +integrity { + SOURCES += io/qfsfileengine_unix.cpp \ + io/qfsfileengine_iterator_unix.cpp +} diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 62e7c9f..6c03b32 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -1029,7 +1029,11 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla if (openMode & QIODevice::ReadOnly) access |= PROT_READ; if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE; +#if defined(Q_OS_INTEGRITY) + int pageSize = sysconf(_SC_PAGESIZE); +#else int pageSize = getpagesize(); +#endif int extra = offset % pageSize; if (quint64(size + extra) > quint64((size_t)-1)) { @@ -1079,6 +1083,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla bool QFSFileEnginePrivate::unmap(uchar *ptr) { +#if !defined(Q_OS_INTEGRITY) Q_Q(QFSFileEngine); if (!maps.contains(ptr)) { q->setError(QFile::PermissionsError, qt_error_string(EACCES)); @@ -1093,6 +1098,9 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) } maps.remove(ptr); return true; +#else + return false; +#endif } QT_END_NAMESPACE diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp index 235f671..71cf92d 100644 --- a/src/corelib/io/qnoncontiguousbytedevice.cpp +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -153,6 +153,7 @@ void QNonContiguousByteDevice::disableReset() resetDisabled = true; } +// FIXME we should scrap this whole implementation and instead change the ByteArrayImpl to be able to cope with sub-arrays? QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b) : QNonContiguousByteDevice() { buffer = b; @@ -244,7 +245,7 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size() return byteArray->size(); } -QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb) +QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb) : QNonContiguousByteDevice(), currentPosition(0) { ringBuffer = rb; @@ -355,6 +356,11 @@ bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount) // normal advancement currentReadBufferPosition += amount; + if (size() == -1) + emit readProgress(totalAdvancements, totalAdvancements); + else + emit readProgress(totalAdvancements, size()); + // advancing over that what has actually been read before if (currentReadBufferPosition > currentReadBufferAmount) { qint64 i = currentReadBufferPosition - currentReadBufferAmount; @@ -370,10 +376,6 @@ bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount) currentReadBufferAmount = 0; } - if (size() == -1) - emit readProgress(totalAdvancements, totalAdvancements); - else - emit readProgress(totalAdvancements, size()); return true; } @@ -505,7 +507,7 @@ QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *dev \internal */ -QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QRingBuffer *ringBuffer) +QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QSharedPointer<QRingBuffer> ringBuffer) { return new QNonContiguousByteDeviceRingBufferImpl(ringBuffer); } diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h index ff946ed..5e0b1bb 100644 --- a/src/corelib/io/qnoncontiguousbytedevice_p.h +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -57,6 +57,7 @@ #include <QtCore/qbytearray.h> #include <QtCore/qbuffer.h> #include <QtCore/qiodevice.h> +#include <QtCore/QSharedPointer> #include "private/qringbuffer_p.h" QT_BEGIN_NAMESPACE @@ -70,6 +71,7 @@ public: virtual bool atEnd() = 0; virtual bool reset() = 0; void disableReset(); + bool isResetDisabled() { return resetDisabled; } virtual qint64 size() = 0; virtual ~QNonContiguousByteDevice(); @@ -89,7 +91,7 @@ class Q_CORE_EXPORT QNonContiguousByteDeviceFactory public: static QNonContiguousByteDevice* create(QIODevice *device); static QNonContiguousByteDevice* create(QByteArray *byteArray); - static QNonContiguousByteDevice* create(QRingBuffer *ringBuffer); + static QNonContiguousByteDevice* create(QSharedPointer<QRingBuffer> ringBuffer); static QIODevice* wrap(QNonContiguousByteDevice* byteDevice); }; @@ -114,7 +116,7 @@ protected: class QNonContiguousByteDeviceRingBufferImpl : public QNonContiguousByteDevice { public: - QNonContiguousByteDeviceRingBufferImpl(QRingBuffer *rb); + QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb); ~QNonContiguousByteDeviceRingBufferImpl(); const char* readPointer(qint64 maximumLength, qint64 &len); bool advanceReadPointer(qint64 amount); @@ -122,13 +124,14 @@ public: bool reset(); qint64 size(); protected: - QRingBuffer* ringBuffer; + QSharedPointer<QRingBuffer> ringBuffer; qint64 currentPosition; }; class QNonContiguousByteDeviceIoDeviceImpl : public QNonContiguousByteDevice { + Q_OBJECT public: QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d); ~QNonContiguousByteDeviceIoDeviceImpl(); @@ -150,6 +153,7 @@ protected: class QNonContiguousByteDeviceBufferImpl : public QNonContiguousByteDevice { + Q_OBJECT public: QNonContiguousByteDeviceBufferImpl(QBuffer *b); ~QNonContiguousByteDeviceBufferImpl(); diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 2a9d8ee..0435256 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -928,7 +928,7 @@ public: } }; -#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) && ! defined (Q_OS_NACL) +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) && !defined (Q_OS_NACL) && !defined(Q_OS_INTEGRITY) #define QT_USE_MMAP #endif diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 93818d1..c3a6721 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -139,3 +139,19 @@ vxworks { kernel/qfunctions_vxworks.h } + +integrity { + SOURCES += \ + kernel/qcore_unix.cpp \ + kernel/qcrashhandler.cpp \ + kernel/qsharedmemory_unix.cpp \ + kernel/qsystemsemaphore_unix.cpp \ + kernel/qeventdispatcher_unix.cpp + HEADERS += \ + kernel/qcore_unix_p.h \ + kernel/qcrashhandler_p.h \ + kernel/qeventdispatcher_unix_p.h + + contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) +} + diff --git a/src/corelib/kernel/qcrashhandler.cpp b/src/corelib/kernel/qcrashhandler.cpp index 59f3796..fbdbac0 100644 --- a/src/corelib/kernel/qcrashhandler.cpp +++ b/src/corelib/kernel/qcrashhandler.cpp @@ -339,6 +339,9 @@ static void print_backtrace(FILE *outb) "EOF\n", globalProgName, (int)getpid())) return; +#elif defined(Q_OS_INTEGRITY) + /* abort */ + CheckSuccess(Failure); #else /* All other platforms */ /* * TODO: SCO/UnixWare 7 must be something like (not tested) diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 25c02c4..dceb51d 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -116,7 +116,7 @@ QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate() // do nothing. #elif defined(Q_OS_INTEGRITY) // INTEGRITY doesn't like a "select" on pipes, so use socketpair instead - if (socketpair(AF_INET, SOCK_STREAM, PF_INET, thread_pipe) == -1) { + if (socketpair(AF_INET, SOCK_STREAM, 0, thread_pipe) == -1) { perror("QEventDispatcherUNIXPrivate(): Unable to create socket pair"); pipefail = true; } else { @@ -343,7 +343,7 @@ timeval QTimerInfoList::updateCurrentTime() return (currentTime = qt_gettime()); } -#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED) +#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED) template <> timeval qAbs(const timeval &t) diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index d72c1ab..daa5dc6 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -56,7 +56,7 @@ #include "qhash.h" #include "qtranslator_p.h" -#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) && !defined(Q_OS_INTEGRITY) #define QT_USE_MMAP #include "private/qcore_unix_p.h" #endif diff --git a/src/corelib/plugin/plugin.pri b/src/corelib/plugin/plugin.pri index 50b005d..eb7a7f7 100644 --- a/src/corelib/plugin/plugin.pri +++ b/src/corelib/plugin/plugin.pri @@ -28,4 +28,8 @@ unix { SOURCES += plugin/qlibrary_unix.cpp } +integrity { + SOURCES += plugin/qlibrary_unix.cpp +} + LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri index 03f661d..90583bb 100644 --- a/src/corelib/thread/thread.pri +++ b/src/corelib/thread/thread.pri @@ -31,3 +31,7 @@ unix:SOURCES += thread/qmutex_unix.cpp \ win32:SOURCES += thread/qmutex_win.cpp \ thread/qthread_win.cpp \ thread/qwaitcondition_win.cpp + +integrity:SOURCES += thread/qmutex_unix.cpp \ + thread/qthread_unix.cpp \ + thread/qwaitcondition_unix.cpp diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index c003214..a903007 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -677,7 +677,7 @@ bool QChar::isSymbol() const \since 4.7 Returns true if the UCS-4-encoded character specified by \a ucs4 - is the high part of a utf16 surrogate + is the low part of a utf16 surrogate (ie. if its code point is between 0xdc00 and 0xdfff, inclusive). */ @@ -686,7 +686,7 @@ bool QChar::isSymbol() const \since 4.7 Returns true if the UCS-4-encoded character specified by \a ucs4 - can be splited to the high and low parts of a utf16 surrogate + can be split into the high and low parts of a utf16 surrogate (ie. if its code point is greater than or equals to 0x10000). */ diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index 1bdba2c..1494373 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -114,6 +114,7 @@ public: return *this; } #ifdef Q_COMPILER_RVALUE_REFS + QSharedDataPointer(QSharedDataPointer &&o) : d(o.d) { o.d = 0; } inline QSharedDataPointer<T> &operator=(QSharedDataPointer<T> &&other) { qSwap(d, other.d); return *this; } #endif @@ -197,7 +198,8 @@ public: return *this; } #ifdef Q_COMPILER_RVALUE_REFS - inline QSharedDataPointer<T> &operator=(QSharedDataPointer<T> &&other) + inline QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) : d(o.d) { o.d = 0; } + inline QExplicitlySharedDataPointer<T> &operator=(QExplicitlySharedDataPointer<T> &&other) { qSwap(d, other.d); return *this; } #endif diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 9d564a1..fb1b466 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -88,6 +88,7 @@ symbian:SOURCES+=tools/qlocale_symbian.cpp else:symbian:SOURCES += tools/qelapsedtimer_symbian.cpp else:unix:SOURCES += tools/qelapsedtimer_unix.cpp else:win32:SOURCES += tools/qelapsedtimer_win.cpp +else:integrity:SOURCES += tools/qelapsedtimer_unix.cpp else:SOURCES += tools/qelapsedtimer_generic.cpp contains(QT_CONFIG, zlib):include($$PWD/../../3rdparty/zlib.pri) diff --git a/src/dbus/qdbusdemarshaller.cpp b/src/dbus/qdbusdemarshaller.cpp index 3882edb..6638263 100644 --- a/src/dbus/qdbusdemarshaller.cpp +++ b/src/dbus/qdbusdemarshaller.cpp @@ -176,10 +176,10 @@ QDBusArgument::ElementType QDBusDemarshaller::currentType() case DBUS_TYPE_INVALID: return QDBusArgument::UnknownType; - default: - qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'", - q_dbus_message_iter_get_arg_type(&iterator), - q_dbus_message_iter_get_arg_type(&iterator)); +// default: +// qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'", +// q_dbus_message_iter_get_arg_type(&iterator), +// q_dbus_message_iter_get_arg_type(&iterator)); } return QDBusArgument::UnknownType; } @@ -232,10 +232,15 @@ QVariant QDBusDemarshaller::toVariantInternal() return QVariant::fromValue(duplicate()); default: - qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'", - q_dbus_message_iter_get_arg_type(&iterator), - q_dbus_message_iter_get_arg_type(&iterator)); - return QVariant(); +// qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'", +// q_dbus_message_iter_get_arg_type(&iterator), +// q_dbus_message_iter_get_arg_type(&iterator)); + char *ptr = 0; + ptr += q_dbus_message_iter_get_arg_type(&iterator); + q_dbus_message_iter_next(&iterator); + + // I hope you never dereference this pointer! + return QVariant::fromValue<void *>(ptr); break; }; } diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index 6683505..df8bc1d 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -193,14 +193,19 @@ QDBusMetaObjectGenerator::findType(const QByteArray &signature, QByteArray typeName = annotations.value(annotationName).toLatin1(); // verify that it's a valid one - if (typeName.isEmpty()) - return result; // invalid - - type = QVariant::nameToType(typeName); - if (type == QVariant::UserType) - type = QMetaType::type(typeName); - if (type == QVariant::Invalid || signature != QDBusMetaType::typeToSignature(type)) - return result; // unknown type is invalid too + if (!typeName.isEmpty()) { + // type name found + type = QVariant::nameToType(typeName); + if (type == QVariant::UserType) + type = QMetaType::type(typeName); + } + + if (type == QVariant::Invalid || signature != QDBusMetaType::typeToSignature(type)) { + // type is still unknown or doesn't match back to the signature that it + // was expected to, so synthesize a fake type + type = QMetaType::VoidStar; + typeName = "QDBusRawType<0x" + signature.toHex() + ">*"; + } result.name = typeName; } else if (type == QVariant::Invalid) { diff --git a/src/dbus/qdbusxmlparser.cpp b/src/dbus/qdbusxmlparser.cpp index 1b99ced..3feedde 100644 --- a/src/dbus/qdbusxmlparser.cpp +++ b/src/dbus/qdbusxmlparser.cpp @@ -52,6 +52,13 @@ #ifndef QT_NO_DBUS +//#define QDBUS_PARSER_DEBUG +#ifdef QDBUS_PARSER_DEBUG +# define qDBusParserError qWarning +#else +# define qDBusParserError if (true) {} else qDebug +#endif + QT_BEGIN_NAMESPACE static QDBusIntrospection::Annotations @@ -69,8 +76,8 @@ parseAnnotations(const QDomElement& elem) value = ann.attribute(QLatin1String("value")); if (!QDBusUtil::isValidInterfaceName(name)) { - qWarning("Invalid D-BUS annotation '%s' found while parsing introspection", - qPrintable(name)); + qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection", + qPrintable(name)); continue; } @@ -99,9 +106,8 @@ parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEm argData.name = arg.attribute(QLatin1String("name")); // can be empty argData.type = arg.attribute(QLatin1String("type")); if (!QDBusUtil::isValidSingleSignature(argData.type)) { - qWarning("Invalid D-BUS type signature '%s' found while parsing introspection", - qPrintable(argData.type)); - continue; + qDBusParserError("Invalid D-BUS type signature '%s' found while parsing introspection", + qPrintable(argData.type)); } retval << argData; @@ -141,8 +147,8 @@ QDBusXmlParser::interfaces() const if (iface.isNull()) continue; // for whatever reason if (!QDBusUtil::isValidInterfaceName(ifaceName)) { - qWarning("Invalid D-BUS interface name '%s' found while parsing introspection", - qPrintable(ifaceName)); + qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection", + qPrintable(ifaceName)); continue; } @@ -166,8 +172,8 @@ QDBusXmlParser::interfaces() const if (method.isNull()) continue; if (!QDBusUtil::isValidMemberName(methodName)) { - qWarning("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection", - qPrintable(methodName), qPrintable(ifaceName)); + qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection", + qPrintable(methodName), qPrintable(ifaceName)); continue; } @@ -192,8 +198,8 @@ QDBusXmlParser::interfaces() const if (signal.isNull()) continue; if (!QDBusUtil::isValidMemberName(signalName)) { - qWarning("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection", - qPrintable(signalName), qPrintable(ifaceName)); + qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection", + qPrintable(signalName), qPrintable(ifaceName)); continue; } @@ -217,8 +223,8 @@ QDBusXmlParser::interfaces() const if (property.isNull()) continue; if (!QDBusUtil::isValidMemberName(propertyName)) { - qWarning("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection", - qPrintable(propertyName), qPrintable(ifaceName)); + qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection", + qPrintable(propertyName), qPrintable(ifaceName)); continue; } @@ -231,10 +237,9 @@ QDBusXmlParser::interfaces() const if (!QDBusUtil::isValidSingleSignature(propertyData.type)) { // cannot be! - qWarning("Invalid D-BUS type signature '%s' found in property '%s.%s' while parsing introspection", - qPrintable(propertyData.type), qPrintable(ifaceName), - qPrintable(propertyName)); - continue; + qDBusParserError("Invalid D-BUS type signature '%s' found in property '%s.%s' while parsing introspection", + qPrintable(propertyData.type), qPrintable(ifaceName), + qPrintable(propertyName)); } QString access = property.attribute(QLatin1String("access")); @@ -245,9 +250,9 @@ QDBusXmlParser::interfaces() const else if (access == QLatin1String("readwrite")) propertyData.access = QDBusIntrospection::Property::ReadWrite; else { - qWarning("Invalid D-BUS property access '%s' found in property '%s.%s' while parsing introspection", - qPrintable(access), qPrintable(ifaceName), - qPrintable(propertyName)); + qDBusParserError("Invalid D-BUS property access '%s' found in property '%s.%s' while parsing introspection", + qPrintable(access), qPrintable(ifaceName), + qPrintable(propertyName)); continue; // invalid one! } @@ -286,8 +291,8 @@ QDBusXmlParser::object() const if (obj.isNull()) continue; // for whatever reason if (!QDBusUtil::isValidObjectPath(m_path + QLatin1Char('/') + objName)) { - qWarning("Invalid D-BUS object path '%s/%s' found while parsing introspection", - qPrintable(m_path), qPrintable(objName)); + qDBusParserError("Invalid D-BUS object path '%s/%s' found while parsing introspection", + qPrintable(m_path), qPrintable(objName)); continue; } @@ -301,8 +306,8 @@ QDBusXmlParser::object() const if (iface.isNull()) continue; if (!QDBusUtil::isValidInterfaceName(ifaceName)) { - qWarning("Invalid D-BUS interface name '%s' found while parsing introspection", - qPrintable(ifaceName)); + qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection", + qPrintable(ifaceName)); continue; } diff --git a/src/declarative/debugger/qdeclarativedebugservice_p.h b/src/declarative/debugger/qdeclarativedebugservice_p.h index 1730d11..5e30350 100644 --- a/src/declarative/debugger/qdeclarativedebugservice_p.h +++ b/src/declarative/debugger/qdeclarativedebugservice_p.h @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QDeclarativeDebugServicePrivate; -class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeDebugService : public QObject +class Q_DECLARATIVE_EXPORT QDeclarativeDebugService : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(QDeclarativeDebugService) diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index c03c624..8f37e90 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -149,6 +149,20 @@ QT_BEGIN_NAMESPACE \sa Image, AnimatedImage */ +/*! + \qmlproperty bool BorderImage::asynchronous + + Specifies that images on the local filesystem should be loaded + asynchronously in a separate thread. The default value is + false, causing the user interface thread to block while the + image is loaded. Setting \a asynchronous to true is useful where + maintaining a responsive user interface is more desirable + than having images immediately visible. + + Note that this property is only valid for images read from the + local filesystem. Images loaded via a network resource (e.g. HTTP) + are always loaded asynchonously. +*/ QDeclarativeBorderImage::QDeclarativeBorderImage(QDeclarativeItem *parent) : QDeclarativeImageBase(*(new QDeclarativeBorderImagePrivate), parent) { @@ -200,6 +214,15 @@ QDeclarativeBorderImage::~QDeclarativeBorderImage() */ /*! + \qmlproperty bool BorderImage::cache + \since Quick 1.1 + + Specifies whether the image should be cached. The default value is + true. Setting \a cache to false is useful when dealing with large images, + to make sure that they aren't cached at the expense of small 'ui element' images. +*/ + +/*! \qmlproperty bool BorderImage::mirror \since Quick 1.1 diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index 0faa296..1e2b70c 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -143,7 +143,7 @@ QDeclarativeFlickablePrivate::QDeclarativeFlickablePrivate() , stealMouse(false), pressed(false), interactive(true), calcVelocity(false) , deceleration(500), maxVelocity(2000), reportedVelocitySmoothing(100) , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(600) - , vTime(0), visibleArea(0) + , fixupMode(Normal), vTime(0), visibleArea(0) , flickableDirection(QDeclarativeFlickable::AutoFlickDirection) , boundsBehavior(QDeclarativeFlickable::DragAndOvershootBounds) { @@ -219,6 +219,7 @@ void QDeclarativeFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal { Q_Q(QDeclarativeFlickable); qreal maxDistance = -1; + data.fixingUp = false; bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds; // -ve velocity means list is moving up if (velocity > 0) { @@ -288,24 +289,45 @@ void QDeclarativeFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal if (data.move.value() > minExtent || maxExtent > minExtent) { timeline.reset(data.move); if (data.move.value() != minExtent) { - if (fixupDuration) { - qreal dist = minExtent - data.move; - timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4); - timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); - } else { + switch (fixupMode) { + case Immediate: timeline.set(data.move, minExtent); + break; + case ExtentChanged: + // The target has changed. Don't start from the beginning; just complete the + // second half of the animation using the new extent. + timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); + data.fixingUp = true; + break; + default: { + qreal dist = minExtent - data.move; + timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4); + timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); + data.fixingUp = true; + } } } } else if (data.move.value() < maxExtent) { timeline.reset(data.move); - if (fixupDuration) { - qreal dist = maxExtent - data.move; - timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4); - timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); - } else { + switch (fixupMode) { + case Immediate: timeline.set(data.move, maxExtent); + break; + case ExtentChanged: + // The target has changed. Don't start from the beginning; just complete the + // second half of the animation using the new extent. + timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); + data.fixingUp = true; + break; + default: { + qreal dist = maxExtent - data.move; + timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4); + timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4); + data.fixingUp = true; + } } } + fixupMode = Normal; vTime = timeline.time(); } @@ -688,6 +710,12 @@ void QDeclarativeFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEven vData.velocity = 0; hData.dragStartOffset = 0; vData.dragStartOffset = 0; + hData.dragMinBound = q->minXExtent(); + vData.dragMinBound = q->minYExtent(); + hData.dragMaxBound = q->maxXExtent(); + vData.dragMaxBound = q->maxYExtent(); + hData.fixingUp = false; + vData.fixingUp = false; lastPos = QPoint(); QDeclarativeItemPrivate::start(lastPosTime); pressPos = event->pos(); @@ -716,8 +744,8 @@ void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent if (!vMoved) vData.dragStartOffset = dy; qreal newY = dy + vData.pressPos - vData.dragStartOffset; - const qreal minY = q->minYExtent(); - const qreal maxY = q->maxYExtent(); + const qreal minY = vData.dragMinBound; + const qreal maxY = vData.dragMaxBound; if (newY > minY) newY = minY + (newY - minY) / 2; if (newY < maxY && maxY - minY <= 0) @@ -748,8 +776,8 @@ void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent if (!hMoved) hData.dragStartOffset = dx; qreal newX = dx + hData.pressPos - hData.dragStartOffset; - const qreal minX = q->minXExtent(); - const qreal maxX = q->maxXExtent(); + const qreal minX = hData.dragMinBound; + const qreal maxX = hData.dragMaxBound; if (newX > minX) newX = minX + (newX - minX) / 2; if (newX < maxX && maxX - minX <= 0) @@ -845,7 +873,8 @@ void QDeclarativeFlickable::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeFlickable); if (d->interactive) { - d->handleMousePressEvent(event); + if (!d->pressed) + d->handleMousePressEvent(event); event->accept(); } else { QDeclarativeItem::mousePressEvent(event); @@ -910,11 +939,27 @@ void QDeclarativeFlickable::wheelEvent(QGraphicsSceneWheelEvent *event) } } +bool QDeclarativeFlickablePrivate::isOutermostPressDelay() const +{ + Q_Q(const QDeclarativeFlickable); + QDeclarativeItem *item = q->parentItem(); + while (item) { + QDeclarativeFlickable *flick = qobject_cast<QDeclarativeFlickable*>(item); + if (flick && flick->pressDelay() > 0 && flick->isInteractive()) + return false; + item = item->parentItem(); + } + + return true; +} + void QDeclarativeFlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event) { Q_Q(QDeclarativeFlickable); if (!q->scene() || pressDelay <= 0) return; + if (!isOutermostPressDelay()) + return; delayedPressTarget = q->scene()->mouseGrabberItem(); delayedPressEvent = new QGraphicsSceneMouseEvent(event->type()); delayedPressEvent->setAccepted(false); @@ -970,9 +1015,10 @@ void QDeclarativeFlickable::timerEvent(QTimerEvent *event) if (scene()->mouseGrabberItem() == d->delayedPressTarget) d->delayedPressTarget->ungrabMouse(); //Use the event handler that will take care of finding the proper item to propagate the event - QApplication::sendEvent(scene(), d->delayedPressEvent); + QApplication::postEvent(scene(), d->delayedPressEvent); + } else { + delete d->delayedPressEvent; } - delete d->delayedPressEvent; d->delayedPressEvent = 0; } } @@ -1047,10 +1093,8 @@ void QDeclarativeFlickable::geometryChanged(const QRectF &newGeometry, } // Make sure that we're entirely in view. if (!d->pressed && !d->movingHorizontally && !d->movingVertically) { - int oldDuration = d->fixupDuration; - d->fixupDuration = 0; + d->fixupMode = QDeclarativeFlickablePrivate::Immediate; d->fixupX(); - d->fixupDuration = oldDuration; } } if (newGeometry.height() != oldGeometry.height()) { @@ -1062,10 +1106,8 @@ void QDeclarativeFlickable::geometryChanged(const QRectF &newGeometry, } // Make sure that we're entirely in view. if (!d->pressed && !d->movingHorizontally && !d->movingVertically) { - int oldDuration = d->fixupDuration; - d->fixupDuration = 0; + d->fixupMode = QDeclarativeFlickablePrivate::Immediate; d->fixupY(); - d->fixupDuration = oldDuration; } } @@ -1219,10 +1261,11 @@ void QDeclarativeFlickable::setContentWidth(qreal w) d->contentItem->setWidth(w); // Make sure that we're entirely in view. if (!d->pressed && !d->movingHorizontally && !d->movingVertically) { - int oldDuration = d->fixupDuration; - d->fixupDuration = 0; + d->fixupMode = QDeclarativeFlickablePrivate::Immediate; + d->fixupX(); + } else if (!d->pressed && d->hData.fixingUp) { + d->fixupMode = QDeclarativeFlickablePrivate::ExtentChanged; d->fixupX(); - d->fixupDuration = oldDuration; } emit contentWidthChanged(); d->updateBeginningEnd(); @@ -1246,10 +1289,11 @@ void QDeclarativeFlickable::setContentHeight(qreal h) d->contentItem->setHeight(h); // Make sure that we're entirely in view. if (!d->pressed && !d->movingHorizontally && !d->movingVertically) { - int oldDuration = d->fixupDuration; - d->fixupDuration = 0; + d->fixupMode = QDeclarativeFlickablePrivate::Immediate; + d->fixupY(); + } else if (!d->pressed && d->vData.fixingUp) { + d->fixupMode = QDeclarativeFlickablePrivate::ExtentChanged; d->fixupY(); - d->fixupDuration = oldDuration; } emit contentHeightChanged(); d->updateBeginningEnd(); @@ -1258,11 +1302,10 @@ void QDeclarativeFlickable::setContentHeight(qreal h) /*! \qmlmethod Flickable::resizeContent(real width, real height, QPointF center) \preliminary + \since Quick 1.1 Resizes the content to \a width x \a height about \a center. - \bold {This method was added in QtQuick 1.1.} - This does not scale the contents of the Flickable - it only resizes the \l contentWidth and \l contentHeight. @@ -1294,11 +1337,10 @@ void QDeclarativeFlickable::resizeContent(qreal w, qreal h, QPointF center) /*! \qmlmethod Flickable::returnToBounds() \preliminary + \since Quick 1.1 Ensures the content is within legal bounds. - \bold {This method was added in QtQuick 1.1.} - This may be called to ensure that the content is within legal bounds after manually positioning the content. */ @@ -1343,6 +1385,22 @@ bool QDeclarativeFlickable::yflick() const return d->flickableDirection & QDeclarativeFlickable::VerticalFlick; } +bool QDeclarativeFlickable::sceneEvent(QEvent *event) +{ + bool rv = QDeclarativeItem::sceneEvent(event); + if (event->type() == QEvent::UngrabMouse) { + Q_D(QDeclarativeFlickable); + if (d->pressed) { + // if our mouse grab has been removed (probably by another Flickable), + // fix our state + d->pressed = false; + d->stealMouse = false; + setKeepMouseGrab(false); + } + } + return rv; +} + bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeFlickable); @@ -1370,7 +1428,7 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event) d->handleMouseMoveEvent(&mouseEvent); break; case QEvent::GraphicsSceneMousePress: - if (d->delayedPressEvent) + if (d->pressed) // we are already pressed - this is a delayed replay return false; d->handleMousePressEvent(&mouseEvent); @@ -1389,6 +1447,8 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event) // We send the release scene()->sendEvent(s->mouseGrabberItem(), event); // And the event has been consumed + d->stealMouse = false; + d->pressed = false; return true; } d->handleMouseReleaseEvent(&mouseEvent); @@ -1411,6 +1471,7 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event) d->stealMouse = false; d->pressed = false; } + return false; } @@ -1509,6 +1570,9 @@ bool QDeclarativeFlickable::isFlickingVertically() const If the flickable is dragged/flicked before the delay times out the press event will not be delivered. If the button is released within the timeout, both the press and release will be delivered. + + Note that for nested Flickables with pressDelay set, the pressDelay of + inner Flickables is overridden by the outermost Flickable. */ int QDeclarativeFlickable::pressDelay() const { @@ -1601,6 +1665,7 @@ void QDeclarativeFlickable::movementXEnding() emit movementEnded(); } } + d->hData.fixingUp = false; } void QDeclarativeFlickable::movementYEnding() @@ -1623,6 +1688,7 @@ void QDeclarativeFlickable::movementYEnding() emit movementEnded(); } } + d->vData.fixingUp = false; } void QDeclarativeFlickablePrivate::updateVelocity() diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p.h index 4fde1d5..a14cc1c 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable_p.h +++ b/src/declarative/graphicsitems/qdeclarativeflickable_p.h @@ -204,6 +204,7 @@ protected: virtual void viewportMoved(); virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + bool sceneEvent(QEvent *event); bool sendMouseEvent(QGraphicsSceneMouseEvent *event); bool xflick() const; diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h index 5ad6ff6..38a5eb3 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h @@ -94,17 +94,21 @@ public: struct AxisData { AxisData(QDeclarativeFlickablePrivate *fp, void (QDeclarativeFlickablePrivate::*func)(qreal)) : move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true) + , fixingUp(false) {} QDeclarativeTimeLineValueProxy<QDeclarativeFlickablePrivate> move; qreal viewSize; qreal pressPos; qreal dragStartOffset; + qreal dragMinBound; + qreal dragMaxBound; qreal velocity; qreal flickTarget; QDeclarativeFlickablePrivate::Velocity smoothVelocity; bool atEnd : 1; bool atBeginning : 1; + bool fixingUp : 1; }; void flickX(qreal velocity); @@ -118,6 +122,7 @@ public: void updateBeginningEnd(); + bool isOutermostPressDelay() const; void captureDelayedPress(QGraphicsSceneMouseEvent *event); void clearDelayedPress(); @@ -160,6 +165,9 @@ public: int pressDelay; int fixupDuration; + enum FixupMode { Normal, Immediate, ExtentChanged }; + FixupMode fixupMode; + static void fixupY_callback(void *); static void fixupX_callback(void *); diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 694130b..1d2ad1c 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -82,7 +82,7 @@ public: item->setPos(QPointF(row, col)); } } - bool contains(int x, int y) const { + bool contains(qreal x, qreal y) const { return (x >= item->x() && x < item->x() + view->cellWidth() && y >= item->y() && y < item->y() + view->cellHeight()); } @@ -912,8 +912,7 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m || (flow == QDeclarativeGridView::LeftToRight && &data == &hData)) return; - int oldDuration = fixupDuration; - fixupDuration = moveReason == Mouse ? fixupDuration : 0; + fixupMode = moveReason == Mouse ? fixupMode : Immediate; if (snapMode != QDeclarativeGridView::NoSnap) { FxGridItem *topItem = snapItemAt(position()+highlightRangeStart); @@ -932,7 +931,6 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m pos = qMax(qMin(bottomItem->rowPos() - highlightRangeStart, -maxExtent), -minExtent); } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); - fixupDuration = oldDuration; return; } if (currentItem && haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { @@ -947,10 +945,12 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m qreal dist = qAbs(data.move + pos); if (dist > 0) { timeline.reset(data.move); - if (fixupDuration) + if (fixupMode != Immediate) { timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); - else + data.fixingUp = true; + } else { timeline.set(data.move, -pos); + } vTime = timeline.time(); } } else if (haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { @@ -965,23 +965,26 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m timeline.reset(data.move); if (viewPos != position()) { - if (fixupDuration) + if (fixupMode != Immediate) { timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); - else + data.fixingUp = true; + } else { timeline.set(data.move, -viewPos); + } } vTime = timeline.time(); } } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); } - fixupDuration = oldDuration; + fixupMode = Normal; } void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity) { Q_Q(QDeclarativeGridView); + data.fixingUp = false; moveReason = Mouse; if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange) && snapMode == QDeclarativeGridView::NoSnap) { @@ -2250,6 +2253,7 @@ void QDeclarativeGridView::positionViewAtIndex(int index, int mode) /*! \qmlmethod GridView::positionViewAtBeginning() \qmlmethod GridView::positionViewAtEnd() + \since Quick 1.1 Positions the view at the beginning or end, taking into account any header or footer. @@ -2294,7 +2298,7 @@ void QDeclarativeGridView::positionViewAtEnd() \bold Note: methods should only be called after the Component has completed. */ -int QDeclarativeGridView::indexAt(int x, int y) const +int QDeclarativeGridView::indexAt(qreal x, qreal y) const { Q_D(const QDeclarativeGridView); for (int i = 0; i < d->visibleItems.count(); ++i) { diff --git a/src/declarative/graphicsitems/qdeclarativegridview_p.h b/src/declarative/graphicsitems/qdeclarativegridview_p.h index 248b9ef..e68a9ba 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview_p.h +++ b/src/declarative/graphicsitems/qdeclarativegridview_p.h @@ -158,7 +158,7 @@ public: enum PositionMode { Beginning, Center, End, Visible, Contain }; Q_INVOKABLE void positionViewAtIndex(int index, int mode); - Q_INVOKABLE int indexAt(int x, int y) const; + Q_INVOKABLE int indexAt(qreal x, qreal y) const; Q_INVOKABLE Q_REVISION(1) void positionViewAtBeginning(); Q_INVOKABLE Q_REVISION(1) void positionViewAtEnd(); diff --git a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp index bc4a2d0..3c8f64e 100644 --- a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp @@ -180,6 +180,7 @@ void QDeclarativeItemModule::defineModule() qmlRegisterType<QDeclarativePinch>("QtQuick",1,1,"Pinch"); qmlRegisterType<QDeclarativePinchEvent>(); qmlRegisterType<QDeclarativeItem,1>("QtQuick",1,1,"Item"); + qmlRegisterType<QDeclarativeMouseArea,1>("QtQuick",1,1,"MouseArea"); qmlRegisterType<QDeclarativeFlickable,1>("QtQuick",1,1,"Flickable"); qmlRegisterType<QDeclarativeListView,1>("QtQuick",1,1,"ListView"); qmlRegisterType<QDeclarativeGridView,1>("QtQuick",1,1,"GridView"); diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index a60a4aa..e369ba6 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -148,7 +148,7 @@ public: else item->setWidth(size); } - bool contains(int x, int y) const { + bool contains(qreal x, qreal y) const { return (x >= item->x() && x < item->x() + item->width() && y >= item->y() && y < item->y() + item->height()); } @@ -228,6 +228,26 @@ public: return 0; } + // Returns the item before modelIndex, if created. + // May return an item marked for removal. + FxListItem *itemBefore(int modelIndex) const { + if (modelIndex < visibleIndex) + return 0; + int idx = 1; + int lastIndex = -1; + while (idx < visibleItems.count()) { + FxListItem *item = visibleItems.at(idx); + if (item->index != -1) + lastIndex = item->index; + if (item->index == modelIndex) + return visibleItems.at(idx-1); + ++idx; + } + if (lastIndex == modelIndex-1) + return visibleItems.last(); + return 0; + } + qreal position() const { Q_Q(const QDeclarativeListView); return orient == QDeclarativeListView::Vertical ? q->contentY() : q->contentX(); @@ -561,7 +581,7 @@ FxListItem *QDeclarativeListViewPrivate::createItem(int modelIndex) QString propValue = model->stringValue(modelIndex, sectionCriteria->property()); listItem->attached->m_section = sectionCriteria->sectionString(propValue); if (modelIndex > 0) { - if (FxListItem *item = visibleItem(modelIndex-1)) + if (FxListItem *item = itemBefore(modelIndex)) listItem->attached->m_prevSection = item->attached->section(); else listItem->attached->m_prevSection = sectionAt(modelIndex-1); @@ -922,7 +942,7 @@ void QDeclarativeListViewPrivate::createSection(FxListItem *listItem) } else { QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q)); context->setContextProperty(QLatin1String("section"), listItem->attached->m_section); - QObject *nobj = sectionCriteria->delegate()->create(context); + QObject *nobj = sectionCriteria->delegate()->beginCreate(context); if (nobj) { QDeclarative_setParent_noEvent(context, nobj); listItem->section = qobject_cast<QDeclarativeItem *>(nobj); @@ -936,6 +956,7 @@ void QDeclarativeListViewPrivate::createSection(FxListItem *listItem) } else { delete context; } + sectionCriteria->delegate()->completeCreate(); } listItem->setPosition(pos); } else { @@ -969,18 +990,18 @@ void QDeclarativeListViewPrivate::updateSections() QDeclarativeListViewAttached *prevAtt = 0; int idx = -1; for (int i = 0; i < visibleItems.count(); ++i) { + QDeclarativeListViewAttached *attached = visibleItems.at(i)->attached; + attached->setPrevSection(prevSection); if (visibleItems.at(i)->index != -1) { - QDeclarativeListViewAttached *attached = visibleItems.at(i)->attached; - attached->setPrevSection(prevSection); QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property()); attached->setSection(sectionCriteria->sectionString(propValue)); - if (prevAtt) - prevAtt->setNextSection(attached->section()); - createSection(visibleItems.at(i)); - prevSection = attached->section(); - prevAtt = attached; idx = visibleItems.at(i)->index; } + createSection(visibleItems.at(i)); + if (prevAtt) + prevAtt->setNextSection(attached->section()); + prevSection = attached->section(); + prevAtt = attached; } if (prevAtt) { if (idx > 0 && idx < model->count()-1) @@ -1177,8 +1198,7 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m return; correctFlick = false; - int oldDuration = fixupDuration; - fixupDuration = moveReason == Mouse ? fixupDuration : 0; + fixupMode = moveReason == Mouse ? fixupMode : Immediate; if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) { updateHighlight(); @@ -1191,10 +1211,12 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m timeline.reset(data.move); if (viewPos != position()) { - if (fixupDuration) + if (fixupMode != Immediate) { timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); - else + data.fixingUp = true; + } else { timeline.set(data.move, -viewPos); + } } vTime = timeline.time(); } else if (snapMode != QDeclarativeListView::NoSnap) { @@ -1210,23 +1232,24 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m pos = qMax(qMin(bottomItem->position() - highlightRangeStart, -maxExtent), -minExtent); } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); - fixupDuration = oldDuration; return; } qreal dist = qAbs(data.move + pos); if (dist > 0) { timeline.reset(data.move); - if (fixupDuration) + if (fixupMode != Immediate) { timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2); - else + data.fixingUp = true; + } else { timeline.set(data.move, -pos); + } vTime = timeline.time(); } } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); } - fixupDuration = oldDuration; + fixupMode = Normal; } void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, @@ -1234,6 +1257,7 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m { Q_Q(QDeclarativeListView); + data.fixingUp = false; moveReason = Mouse; if ((!haveHighlightRange || highlightRange != QDeclarativeListView::StrictlyEnforceRange) && snapMode == QDeclarativeListView::NoSnap) { correctFlick = true; @@ -2688,6 +2712,7 @@ void QDeclarativeListView::positionViewAtIndex(int index, int mode) /*! \qmlmethod ListView::positionViewAtBeginning() \qmlmethod ListView::positionViewAtEnd() + \since Quick 1.1 Positions the view at the beginning or end, taking into account any header or footer. @@ -2732,7 +2757,7 @@ void QDeclarativeListView::positionViewAtEnd() \bold Note: methods should only be called after the Component has completed. */ -int QDeclarativeListView::indexAt(int x, int y) const +int QDeclarativeListView::indexAt(qreal x, qreal y) const { Q_D(const QDeclarativeListView); for (int i = 0; i < d->visibleItems.count(); ++i) { @@ -2777,6 +2802,8 @@ void QDeclarativeListView::updateSections() roles << d->sectionCriteria->property().toUtf8(); d->model->setWatchedRoles(roles); d->updateSections(); + if (d->itemCount) + d->layout(); } } @@ -3096,6 +3123,7 @@ void QDeclarativeListView::destroyRemoved() } // Correct the positioning of the items + d->updateSections(); d->layout(); } diff --git a/src/declarative/graphicsitems/qdeclarativelistview_p.h b/src/declarative/graphicsitems/qdeclarativelistview_p.h index 10fbf10..265f4bd 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview_p.h +++ b/src/declarative/graphicsitems/qdeclarativelistview_p.h @@ -208,7 +208,7 @@ public: enum PositionMode { Beginning, Center, End, Visible, Contain }; Q_INVOKABLE void positionViewAtIndex(int index, int mode); - Q_INVOKABLE int indexAt(int x, int y) const; + Q_INVOKABLE int indexAt(qreal x, qreal y) const; Q_INVOKABLE Q_REVISION(1) void positionViewAtBeginning(); Q_INVOKABLE Q_REVISION(1) void positionViewAtEnd(); diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp index 5b73a29..da11b00 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp +++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp @@ -416,6 +416,40 @@ void QDeclarativeMouseArea::setEnabled(bool a) emit enabledChanged(); } } + +/*! + \qmlproperty bool MouseArea::preventStealing + \since Quick 1.1 + This property holds whether the mouse events may be stolen from this + MouseArea. + + If a MouseArea is placed within an item that filters child mouse + events, such as Flickable, the mouse + events may be stolen from the MouseArea if a gesture is recognized + by the parent element, e.g. a flick gesture. If preventStealing is + set to true, no element will steal the mouse events. + + Note that setting preventStealing to true once an element has started + stealing events will have no effect until the next press event. + + By default this property is false. +*/ +bool QDeclarativeMouseArea::preventStealing() const +{ + Q_D(const QDeclarativeMouseArea); + return d->preventStealing; +} + +void QDeclarativeMouseArea::setPreventStealing(bool prevent) +{ + Q_D(QDeclarativeMouseArea); + if (prevent != d->preventStealing) { + d->preventStealing = prevent; + setKeepMouseGrab(d->preventStealing && d->absorb); + emit preventStealingChanged(); + } +} + /*! \qmlproperty MouseButtons MouseArea::pressedButtons This property holds the mouse buttons currently pressed. @@ -443,7 +477,7 @@ void QDeclarativeMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeMouseArea); d->moved = false; - d->stealMouse = false; + d->stealMouse = d->preventStealing; if (!d->absorb) QDeclarativeItem::mousePressEvent(event); else { @@ -460,7 +494,7 @@ void QDeclarativeMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event) // we should only start timer if pressAndHold is connected to. if (d->isPressAndHoldConnected()) d->pressAndHoldTimer.start(PressAndHoldDelay, this); - setKeepMouseGrab(false); + setKeepMouseGrab(d->stealMouse); event->setAccepted(setPressed(true)); } } diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p.h index 937ac78..985f27e 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea_p.h +++ b/src/declarative/graphicsitems/qdeclarativemousearea_p.h @@ -129,6 +129,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeMouseArea : public QDeclarativeItem Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged) Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged) Q_PROPERTY(QDeclarativeDrag *drag READ drag CONSTANT) //### add flicking to QDeclarativeDrag or add a QDeclarativeFlick ??? + Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged REVISION 1) public: QDeclarativeMouseArea(QDeclarativeItem *parent=0); @@ -153,6 +154,9 @@ public: QDeclarativeDrag *drag(); + bool preventStealing() const; + void setPreventStealing(bool prevent); + Q_SIGNALS: void hoveredChanged(); void pressedChanged(); @@ -161,6 +165,7 @@ Q_SIGNALS: void hoverEnabledChanged(); void positionChanged(QDeclarativeMouseEvent *mouse); void mousePositionChanged(QDeclarativeMouseEvent *mouse); + Q_REVISION(1) void preventStealingChanged(); void pressed(QDeclarativeMouseEvent *mouse); void pressAndHold(QDeclarativeMouseEvent *mouse); diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h index 2a327af..67694fb 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h @@ -68,7 +68,7 @@ class QDeclarativeMouseAreaPrivate : public QDeclarativeItemPrivate public: QDeclarativeMouseAreaPrivate() : absorb(true), hovered(false), pressed(false), longPress(false), - moved(false), stealMouse(false), doubleClick(false), drag(0) + moved(false), stealMouse(false), doubleClick(false), preventStealing(false), drag(0) { } @@ -110,6 +110,7 @@ public: bool dragY : 1; bool stealMouse : 1; bool doubleClick : 1; + bool preventStealing : 1; QDeclarativeDrag *drag; QPointF startScene; qreal startX; diff --git a/src/declarative/graphicsitems/qdeclarativepositioners.cpp b/src/declarative/graphicsitems/qdeclarativepositioners.cpp index 27a1301..c0be2a2 100644 --- a/src/declarative/graphicsitems/qdeclarativepositioners.cpp +++ b/src/declarative/graphicsitems/qdeclarativepositioners.cpp @@ -584,6 +584,8 @@ QDeclarativeRow::QDeclarativeRow(QDeclarativeItem *parent) /*! \qmlproperty enumeration Row::layoutDirection + \since Quick 1.1 + This property holds the layoutDirection of the row. Possible values: @@ -859,6 +861,8 @@ void QDeclarativeGrid::setFlow(Flow flow) /*! \qmlproperty enumeration Grid::layoutDirection + \since Quick 1.1 + This property holds the layout direction of the layout. Possible values are: @@ -1201,6 +1205,8 @@ void QDeclarativeFlow::setFlow(Flow flow) /*! \qmlproperty enumeration Flow::layoutDirection + \since Quick 1.1 + This property holds the layout direction of the layout. Possible values are: diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp index 559d061..12e1c0f 100644 --- a/src/declarative/graphicsitems/qdeclarativetext.cpp +++ b/src/declarative/graphicsitems/qdeclarativetext.cpp @@ -1145,6 +1145,7 @@ void QDeclarativeText::setWrapMode(WrapMode mode) /*! \qmlproperty int Text::lineCount + \since Quick 1.1 Returns the number of lines visible in the text item. @@ -1160,6 +1161,7 @@ int QDeclarativeText::lineCount() const /*! \qmlproperty bool Text::truncated + \since Quick 1.1 Returns true if the text has been truncated due to \l maximumLineCount or \l elide. @@ -1176,6 +1178,7 @@ bool QDeclarativeText::truncated() const /*! \qmlproperty int Text::maximumLineCount + \since Quick 1.1 Set this property to limit the number of lines that the text item will show. If elide is set to Text.ElideRight, the text will be elided appropriately. @@ -1428,6 +1431,7 @@ qreal QDeclarativeText::paintedHeight() const /*! \qmlproperty real Text::lineHeight + \since Quick 1.1 Sets the line height for the text. The value can be in pixels or a multiplier depending on lineHeightMode. diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index e2f6265..c28d7f4 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -544,6 +544,7 @@ void QDeclarativeTextEdit::setWrapMode(WrapMode mode) /*! \qmlproperty int TextEdit::lineCount + \since Quick 1.1 Returns the total number of lines in the textEdit item. */ @@ -605,6 +606,22 @@ int QDeclarativeTextEdit::positionAt(int x, int y) const { Q_D(const QDeclarativeTextEdit); int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit); + QTextCursor cursor = d->control->textCursor(); + if (r > cursor.position()) { + // The cursor position includes positions within the preedit text, but only positions in the + // same text block are offset so it is possible to get a position that is either part of the + // preedit or the next text block. + QTextLayout *layout = cursor.block().layout(); + const int preeditLength = layout + ? layout->preeditAreaText().length() + : 0; + if (preeditLength > 0 + && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) { + r = r > cursor.position() + preeditLength + ? r - preeditLength + : cursor.position(); + } + } return r; } @@ -977,6 +994,10 @@ void QDeclarativeTextEdit::setSelectByMouse(bool on) if (d->selectByMouse != on) { d->selectByMouse = on; setKeepMouseGrab(on); + if (on) + setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse); + else + setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse); emit selectByMouseChanged(on); } } @@ -1029,11 +1050,10 @@ void QDeclarativeTextEdit::setReadOnly(bool r) setFlag(QGraphicsItem::ItemAcceptsInputMethod, !r); Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse; - if (r) { + if (d->selectByMouse) flags = flags | Qt::TextSelectableByMouse; - } else { - flags = flags | Qt::TextEditorInteraction; - } + if (!r) + flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable; d->control->setTextInteractionFlags(flags); if (!r) d->control->moveCursor(QTextCursor::End); @@ -1125,12 +1145,13 @@ void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event) void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus) { Q_Q(QDeclarativeTextEdit); - q->setCursorVisible(hasFocus); + q->setCursorVisible(hasFocus && scene && scene->hasFocus()); QDeclarativeItemPrivate::focusChanged(hasFocus); } /*! \qmlmethod void TextEdit::deselect() + \since Quick 1.1 Removes active text selection. */ @@ -1251,8 +1272,8 @@ void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) } } } - if (event->type() != QEvent::GraphicsSceneMouseDoubleClick || d->selectByMouse) - d->control->processEvent(event, QPointF(0, -d->yoff)); + + d->control->processEvent(event, QPointF(0, -d->yoff)); if (!event->isAccepted()) QDeclarativePaintedItem::mousePressEvent(event); } @@ -1287,13 +1308,11 @@ Handles the given mouse \a event. void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextEdit); - if (d->selectByMouse) { - d->control->processEvent(event, QPointF(0, -d->yoff)); - if (!event->isAccepted()) - QDeclarativePaintedItem::mouseDoubleClickEvent(event); - } else { + + d->control->processEvent(event, QPointF(0, -d->yoff)); + if (!event->isAccepted()) QDeclarativePaintedItem::mouseDoubleClickEvent(event); - } + } /*! @@ -1303,14 +1322,9 @@ Handles the given mouse \a event. void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextEdit); - if (d->selectByMouse) { - d->control->processEvent(event, QPointF(0, -d->yoff)); - if (!event->isAccepted()) - QDeclarativePaintedItem::mouseMoveEvent(event); - event->setAccepted(true); - } else { + d->control->processEvent(event, QPointF(0, -d->yoff)); + if (!event->isAccepted()) QDeclarativePaintedItem::mouseMoveEvent(event); - } } /*! @@ -1320,7 +1334,10 @@ Handles the given input method \a event. void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event) { Q_D(QDeclarativeTextEdit); + const bool wasComposing = isInputMethodComposing(); d->control->processEvent(event, QPointF(0, -d->yoff)); + if (wasComposing != isInputMethodComposing()) + emit inputMethodComposingChanged(); } /*! @@ -1385,19 +1402,38 @@ void QDeclarativeTextEdit::updateImgCache(const QRectF &rf) /*! \qmlproperty bool TextEdit::canPaste + \since QtQuick 1.1 Returns true if the TextEdit is writable and the content of the clipboard is suitable for pasting into the TextEdit. - - \since QtQuick 1.1 */ - bool QDeclarativeTextEdit::canPaste() const { Q_D(const QDeclarativeTextEdit); return d->canPaste; } +/*! + \qmlproperty bool TextEdit::isInputMethodComposing() + + \since QtQuick 1.1 + + This property holds whether the TextEdit has partial text input from an + input method. + + While it is composing an input method may rely on mouse or key events from + the TextEdit to edit or commit the partial text. This property can be used + to determine when to disable events handlers that may interfere with the + correct operation of an input method. +*/ +bool QDeclarativeTextEdit::isInputMethodComposing() const +{ + Q_D(const QDeclarativeTextEdit); + if (QTextLayout *layout = d->control->textCursor().block().layout()) + return layout->preeditAreaText().length() > 0; + return false; +} + void QDeclarativeTextEditPrivate::init() { Q_Q(QDeclarativeTextEdit); @@ -1409,7 +1445,7 @@ void QDeclarativeTextEditPrivate::init() control = new QTextControl(q); control->setIgnoreUnusedNavigationEvents(true); - control->setTextInteractionFlags(control->textInteractionFlags() | Qt::LinksAccessibleByMouse); + control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable); control->setDragEnabled(false); // QTextControl follows the default text color diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h index 7785a7a..612f9a9 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h @@ -94,6 +94,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextEdit : public QDeclarativeImplicitSizePa Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged) Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged REVISION 1) Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1) + Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged REVISION 1) public: QDeclarativeTextEdit(QDeclarativeItem *parent=0); @@ -215,6 +216,8 @@ public: QRectF boundingRect() const; + bool isInputMethodComposing() const; + Q_SIGNALS: void textChanged(const QString &); void paintedSizeChanged(); @@ -242,6 +245,7 @@ Q_SIGNALS: Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode); Q_REVISION(1) void linkActivated(const QString &link); Q_REVISION(1) void canPasteChanged(); + Q_REVISION(1) void inputMethodComposingChanged(); public Q_SLOTS: void selectAll(); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 3c95ab8..dc44bfe 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -51,6 +51,7 @@ #include <QFontMetrics> #include <QPainter> #include <QTextBoundaryFinder> +#include <QInputContext> #include <qstyle.h> #ifndef QT_NO_LINEEDIT @@ -481,6 +482,7 @@ QRect QDeclarativeTextInput::cursorRectangle() const Q_D(const QDeclarativeTextInput); QRect r = d->control->cursorRect(); r.setHeight(r.height()-1); // Make consistent with TextEdit (QLineControl inexplicably adds 1) + r.moveLeft(r.x() - d->hscroll); return r; } @@ -920,14 +922,22 @@ void QDeclarativeTextInput::moveCursor() QRectF QDeclarativeTextInput::positionToRectangle(int pos) const { Q_D(const QDeclarativeTextInput); + if (pos > d->control->cursorPosition()) + pos += d->control->preeditAreaText().length(); return QRectF(d->control->cursorToX(pos)-d->hscroll, 0.0, d->control->cursorWidth(), cursorRectangle().height()); } +int QDeclarativeTextInput::positionAt(int x) const +{ + return positionAt(x, CursorBetweenCharacters); +} + /*! - \qmlmethod int TextInput::positionAt(int x) + \qmlmethod int TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters) + \since Quick 1.1 This function returns the character position at x pixels from the left of the textInput. Position 0 is before the @@ -936,18 +946,33 @@ QRectF QDeclarativeTextInput::positionToRectangle(int pos) const This means that for all x values before the first character this function returns 0, and for all x values after the last character this function returns text.length. + + The cursor position type specifies how the cursor position should be resolved. + + \list + \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x. + \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x. + \endlist */ -int QDeclarativeTextInput::positionAt(int x) const +int QDeclarativeTextInput::positionAt(int x, CursorPosition position) const { Q_D(const QDeclarativeTextInput); - return d->control->xToPos(x + d->hscroll); + int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position)); + const int cursor = d->control->cursor(); + if (pos > cursor) { + const int preeditLength = d->control->preeditAreaText().length(); + pos = pos > cursor + preeditLength + ? pos - preeditLength + : cursor; + } + return pos; } void QDeclarativeTextInputPrivate::focusChanged(bool hasFocus) { Q_Q(QDeclarativeTextInput); focused = hasFocus; - q->setCursorVisible(hasFocus); + q->setCursorVisible(hasFocus && scene && scene->hasFocus()); if(q->echoMode() == QDeclarativeTextInput::PasswordEchoOnEdit && !hasFocus) control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events if (!hasFocus) @@ -981,18 +1006,22 @@ void QDeclarativeTextInput::inputMethodEvent(QInputMethodEvent *ev) { Q_D(QDeclarativeTextInput); ev->ignore(); + const bool wasComposing = d->control->preeditAreaText().length() > 0; inputMethodPreHandler(ev); - if (ev->isAccepted()) - return; - if (d->control->isReadOnly()) { - ev->ignore(); - } else { - d->control->processInputMethodEvent(ev); - updateSize(); - d->updateHorizontalScroll(); + if (!ev->isAccepted()) { + if (d->control->isReadOnly()) { + ev->ignore(); + } else { + d->control->processInputMethodEvent(ev); + updateSize(); + d->updateHorizontalScroll(); + } } if (!ev->isAccepted()) QDeclarativePaintedItem::inputMethodEvent(ev); + + if (wasComposing != (d->control->preeditAreaText().length() > 0)) + emit inputMethodComposingChanged(); } /*! @@ -1002,6 +1031,8 @@ Handles the given mouse \a event. void QDeclarativeTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextInput); + if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonDblClick)) + return; if (d->selectByMouse) { int cursor = d->xToPos(event->pos().x()); d->control->selectWordAtPos(cursor); @@ -1014,6 +1045,8 @@ void QDeclarativeTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextInput); + if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonPress)) + return; if(d->focusOnPress){ bool hadActiveFocus = hasActiveFocus(); forceActiveFocus(); @@ -1041,6 +1074,8 @@ void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event) void QDeclarativeTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextInput); + if (d->sendMouseEventToInputContext(event, QEvent::MouseMove)) + return; if (d->selectByMouse) { if (qAbs(int(event->pos().x() - d->pressPos.x())) > QApplication::startDragDistance()) setKeepMouseGrab(true); @@ -1058,6 +1093,8 @@ Handles the given mouse \a event. void QDeclarativeTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextInput); + if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonRelease)) + return; if (d->selectByMouse) setKeepMouseGrab(false); if (!d->showInputPanelOnFocus) { // input panel on click @@ -1075,6 +1112,44 @@ void QDeclarativeTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) QDeclarativePaintedItem::mouseReleaseEvent(event); } +bool QDeclarativeTextInputPrivate::sendMouseEventToInputContext( + QGraphicsSceneMouseEvent *event, QEvent::Type eventType) +{ +#if !defined QT_NO_IM + if (event->widget() && control->composeMode()) { + int tmp_cursor = xToPos(event->pos().x()); + int mousePos = tmp_cursor - control->cursor(); + if (mousePos < 0 || mousePos > control->preeditAreaText().length()) { + mousePos = -1; + // don't send move events outside the preedit area + if (eventType == QEvent::MouseMove) + return true; + } + + QInputContext *qic = event->widget()->inputContext(); + if (qic) { + QMouseEvent mouseEvent( + eventType, + event->widget()->mapFromGlobal(event->screenPos()), + event->screenPos(), + event->button(), + event->buttons(), + event->modifiers()); + // may be causing reset() in some input methods + qic->mouseHandler(mousePos, &mouseEvent); + event->setAccepted(mouseEvent.isAccepted()); + } + if (!control->preeditAreaText().isEmpty()) + return true; + } +#else + Q_UNUSED(event); + Q_UNUSED(eventType) +#endif + + return false; +} + bool QDeclarativeTextInput::sceneEvent(QEvent *event) { bool rv = QDeclarativeItem::sceneEvent(event); @@ -1238,6 +1313,7 @@ QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property) /*! \qmlmethod void TextInput::deselect() + \since Quick 1.1 Removes active text selection. */ @@ -1419,6 +1495,13 @@ void QDeclarativeTextInput::setMouseSelectionMode(SelectionMode mode) } } +/*! + \qmlproperty bool TextInput::canPaste + \since QtQuick 1.1 + + Returns true if the TextInput is writable and the content of the clipboard is + suitable for pasting into the TextEdit. +*/ bool QDeclarativeTextInput::canPaste() const { Q_D(const QDeclarativeTextInput); @@ -1637,6 +1720,25 @@ void QDeclarativeTextInput::focusInEvent(QFocusEvent *event) QDeclarativePaintedItem::focusInEvent(event); } +/*! + \qmlproperty bool TextInput::isInputMethodComposing() + + \since QtQuick 1.1 + + This property holds whether the TextInput has partial text input from an + input method. + + While it is composing an input method may rely on mouse or key events from + the TextInput to edit or commit the partial text. This property can be + used to determine when to disable events handlers that may interfere with + the correct operation of an input method. +*/ +bool QDeclarativeTextInput::isInputMethodComposing() const +{ + Q_D(const QDeclarativeTextInput); + return d->control->preeditAreaText().length() > 0; +} + void QDeclarativeTextInputPrivate::init() { Q_Q(QDeclarativeTextInput); @@ -1662,6 +1764,8 @@ void QDeclarativeTextInputPrivate::init() q->connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged())); #endif // QT_NO_CLIPBOARD + q->connect(control, SIGNAL(updateMicroFocus()), + q, SLOT(updateMicroFocus())); q->updateSize(); oldValidity = control->hasAcceptableInput(); lastSelectionStart = 0; diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h index e1e66a9..822d5e2 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h @@ -97,6 +97,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextInput : public QDeclarativeImplicitSizeP Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged) Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged REVISION 1) Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1) + Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged REVISION 1) public: QDeclarativeTextInput(QDeclarativeItem* parent=0); @@ -120,8 +121,14 @@ public: SelectWords }; + enum CursorPosition { + CursorBetweenCharacters, + CursorOnCharacter + }; + //Auxilliary functions needed to control the TextInput from QML Q_INVOKABLE int positionAt(int x) const; + Q_INVOKABLE Q_REVISION(1) int positionAt(int x, CursorPosition position) const; Q_INVOKABLE QRectF positionToRectangle(int pos) const; Q_INVOKABLE void moveCursorSelection(int pos); Q_INVOKABLE Q_REVISION(1) void moveCursorSelection(int pos, SelectionMode mode); @@ -204,6 +211,8 @@ public: QRectF boundingRect() const; bool canPaste() const; + bool isInputMethodComposing() const; + Q_SIGNALS: void textChanged(); void cursorPositionChanged(); @@ -231,6 +240,7 @@ Q_SIGNALS: void selectByMouseChanged(bool selectByMouse); Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode); Q_REVISION(1) void canPasteChanged(); + Q_REVISION(1) void inputMethodComposingChanged(); protected: virtual void geometryChanged(const QRectF &newGeometry, diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h index f7446b4..ab2838b 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h @@ -104,6 +104,7 @@ public: void focusChanged(bool hasFocus); void updateHorizontalScroll(); int calculateTextWidth(); + bool sendMouseEventToInputContext(QGraphicsSceneMouseEvent *event, QEvent::Type eventType); QLineControl* control; diff --git a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp index b24dd2c..31819f5 100644 --- a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp @@ -99,7 +99,6 @@ class DrawTextItemRecorder: public QPaintEngine needFreshCurrentItem = false; last.numChars += ti.num_chars; - last.numGlyphs += ti.glyphs.numGlyphs; } } @@ -111,7 +110,7 @@ class DrawTextItemRecorder: public QPaintEngine currentItem.font = ti.font(); currentItem.charOffset = charOffset; currentItem.numChars = ti.num_chars; - currentItem.numGlyphs = ti.glyphs.numGlyphs; + currentItem.numGlyphs = 0; currentItem.glyphOffset = glyphOffset; currentItem.positionOffset = positionOffset; currentItem.useBackendOptimizations = m_useBackendOptimizations; @@ -121,6 +120,8 @@ class DrawTextItemRecorder: public QPaintEngine m_inertText->items.append(currentItem); } + QStaticTextItem ¤tItem = m_inertText->items.last(); + QTransform matrix = m_untransformedCoordinates ? QTransform() : state->transform(); matrix.translate(position.x(), position.y()); @@ -129,18 +130,18 @@ class DrawTextItemRecorder: public QPaintEngine ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); int size = glyphs.size(); - Q_ASSERT(size == ti.glyphs.numGlyphs); Q_ASSERT(size == positions.size()); + currentItem.numGlyphs += size; m_inertText->glyphs.resize(m_inertText->glyphs.size() + size); m_inertText->positions.resize(m_inertText->glyphs.size()); m_inertText->chars.resize(m_inertText->chars.size() + ti.num_chars); glyph_t *glyphsDestination = m_inertText->glyphs.data() + glyphOffset; - qMemCopy(glyphsDestination, glyphs.constData(), sizeof(glyph_t) * ti.glyphs.numGlyphs); + qMemCopy(glyphsDestination, glyphs.constData(), sizeof(glyph_t) * size); QFixedPoint *positionsDestination = m_inertText->positions.data() + positionOffset; - qMemCopy(positionsDestination, positions.constData(), sizeof(QFixedPoint) * ti.glyphs.numGlyphs); + qMemCopy(positionsDestination, positions.constData(), sizeof(QFixedPoint) * size); QChar *charsDestination = m_inertText->chars.data() + charOffset; qMemCopy(charsDestination, ti.chars, sizeof(QChar) * ti.num_chars); diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 0554897..f57f842 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -608,7 +608,7 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine, out->types << ref; } - Object *root = unit->parser().tree(); + QDeclarativeParser::Object *root = unit->parser().tree(); Q_ASSERT(root); this->engine = engine; @@ -637,7 +637,7 @@ bool QDeclarativeCompiler::compile(QDeclarativeEngine *engine, return !isError(); } -void QDeclarativeCompiler::compileTree(Object *tree) +void QDeclarativeCompiler::compileTree(QDeclarativeParser::Object *tree) { compileState.root = tree; componentStat.lineNumber = tree->location.start.line; @@ -715,14 +715,14 @@ void QDeclarativeCompiler::compileTree(Object *tree) enginePrivate->registerCompositeType(output); } -static bool ValuePtrLessThan(const Value *t1, const Value *t2) +static bool ValuePtrLessThan(const QDeclarativeParser::Value *t1, const QDeclarativeParser::Value *t2) { return t1->location.start.line < t2->location.start.line || (t1->location.start.line == t2->location.start.line && t1->location.start.column < t2->location.start.column); } -bool QDeclarativeCompiler::buildObject(Object *obj, const BindingContext &ctxt) +bool QDeclarativeCompiler::buildObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt) { componentStat.objects++; @@ -799,7 +799,7 @@ bool QDeclarativeCompiler::buildObject(Object *obj, const BindingContext &ctxt) defaultProperty->values = obj->defaultProperty->values; defaultProperty->values += explicitProperty->values; - foreach(Value *value, defaultProperty->values) + foreach(QDeclarativeParser::Value *value, defaultProperty->values) value->addref(); qSort(defaultProperty->values.begin(), defaultProperty->values.end(), ValuePtrLessThan); @@ -1262,7 +1262,7 @@ bool QDeclarativeCompiler::buildComponent(QDeclarativeParser::Object *obj, if (!obj->dynamicSlots.isEmpty()) COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions.")); - Object *root = 0; + QDeclarativeParser::Object *root = 0; if (obj->defaultProperty && obj->defaultProperty->values.count()) root = obj->defaultProperty->values.first()->object; @@ -1302,7 +1302,7 @@ bool QDeclarativeCompiler::buildComponentFromRoot(QDeclarativeParser::Object *ob // Build a sub-object. A sub-object is one that was not created directly by // QML - such as a grouped property object, or an attached object. Sub-object's // can't have an id, involve a custom parser, have attached properties etc. -bool QDeclarativeCompiler::buildSubObject(Object *obj, const BindingContext &ctxt) +bool QDeclarativeCompiler::buildSubObject(QDeclarativeParser::Object *obj, const BindingContext &ctxt) { Q_ASSERT(obj->metatype); Q_ASSERT(!obj->defaultProperty); @@ -1615,7 +1615,7 @@ void QDeclarativeCompiler::genListProperty(QDeclarativeParser::Property *prop, output->bytecode << fetch; for (int ii = 0; ii < prop->values.count(); ++ii) { - Value *v = prop->values.at(ii); + QDeclarativeParser::Value *v = prop->values.at(ii); if (v->type == Value::CreatedObject) { @@ -1903,7 +1903,7 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, if (prop->values.count() > 1) { COMPILE_EXCEPTION(prop, tr("Single property assignment expected")); } else if (prop->values.count()) { - Value *value = prop->values.at(0); + QDeclarativeParser::Value *value = prop->values.at(0); if (value->object) { COMPILE_EXCEPTION(prop, tr("Unexpected object assignment")); @@ -1932,7 +1932,7 @@ bool QDeclarativeCompiler::buildValueTypeProperty(QObject *type, } for (int ii = 0; ii < prop->onValues.count(); ++ii) { - Value *v = prop->onValues.at(ii); + QDeclarativeParser::Value *v = prop->onValues.at(ii); Q_ASSERT(v->object); COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, baseObj, v, ctxt)); @@ -1962,7 +1962,7 @@ bool QDeclarativeCompiler::buildListProperty(QDeclarativeParser::Property *prop, bool assignedBinding = false; for (int ii = 0; ii < prop->values.count(); ++ii) { - Value *v = prop->values.at(ii); + QDeclarativeParser::Value *v = prop->values.at(ii); if (v->object) { v->type = Value::CreatedObject; COMPILE_CHECK(buildObject(v->object, ctxt)); @@ -2017,7 +2017,7 @@ bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property COMPILE_EXCEPTION(prop->values.at(0), tr( "Cannot assign multiple values to a singular property") ); for (int ii = 0; ii < prop->values.count(); ++ii) { - Value *v = prop->values.at(ii); + QDeclarativeParser::Value *v = prop->values.at(ii); if (v->object) { COMPILE_CHECK(buildPropertyObjectAssignment(prop, obj, v, ctxt)); @@ -2030,7 +2030,7 @@ bool QDeclarativeCompiler::buildPropertyAssignment(QDeclarativeParser::Property } for (int ii = 0; ii < prop->onValues.count(); ++ii) { - Value *v = prop->onValues.at(ii); + QDeclarativeParser::Value *v = prop->onValues.at(ii); Q_ASSERT(v->object); COMPILE_CHECK(buildPropertyOnAssignment(prop, obj, obj, v, ctxt)); @@ -2385,7 +2385,7 @@ bool QDeclarativeCompiler::mergeDynamicMetaProperties(QDeclarativeParser::Object COMPILE_EXCEPTION(property, tr("Invalid property nesting")); for (int ii = 0; ii < p.defaultValue->values.count(); ++ii) { - Value *v = p.defaultValue->values.at(ii); + QDeclarativeParser::Value *v = p.defaultValue->values.at(ii); v->addref(); property->values.append(v); } @@ -2678,7 +2678,7 @@ static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node) bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, QByteArray &data, - Object *obj, + QDeclarativeParser::Object *obj, const Object::DynamicProperty &prop) { if (!prop.defaultValue) @@ -2701,7 +2701,7 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, if (!compileState.ids.contains(alias.at(0))) COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); - Object *idObject = compileState.ids[alias.at(0)]; + QDeclarativeParser::Object *idObject = compileState.ids[alias.at(0)]; QByteArray typeName; @@ -2884,7 +2884,7 @@ bool QDeclarativeCompiler::completeComponentBuild() componentStat.ids = compileState.ids.count(); for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { - Object *aliasObject = compileState.aliasingObjects.at(ii); + QDeclarativeParser::Object *aliasObject = compileState.aliasingObjects.at(ii); COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); } diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index 5840f70..fc393d1 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -615,10 +615,11 @@ QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, Q } /*! - \qmlmethod object Component::createObject(Item parent, Script valuemap = null) + \qmlmethod object Component::createObject(Item parent, object properties) - Creates and returns an object instance of this component that will have the given - \a parent. Returns null if object creation fails. + Creates and returns an object instance of this component that will have + the given \a parent and \a properties. The \a properties argument is optional. + Returns null if object creation fails. The object will be created in the same context as the one in which the component was created. This function will always return null when called on components @@ -630,14 +631,23 @@ QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, Q property, or else the object will not be visible. If a \a parent is not provided to createObject(), a reference to the returned object must be held so that - it is not destroyed by the garbage collector. This is regardless of Item.parent being set afterwards, + it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards, since setting the Item parent does not change object ownership; only the graphical parent is changed. - Since QtQuick 1.1, a map of property values can be optionally passed to the method that applies values to the object's properties - before its creation is finalised. This will avoid binding issues that can occur when the object is - instantiated before property bindings have been set. For example: + As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a + map of initial property values for the created object. These values are applied before object + creation is finalized. (This is more efficient than setting property values after object creation, + particularly where large sets of property values are defined, and also allows property bindings + to be set up before the object is created.) - \code component.createObject(parent, {"x": 100, "y": 100, "specialProperty": someObject}); \endcode + The \a properties argument is specified as a map of property-value items. For example, the code + below creates an object with initial \c x and \c y values of 100 and 200, respectively: + + \qml + var component = Qt.createComponent("Button.qml"); + if (component.status == Component.Ready) + component.createObject(parent, {"x": 100, "y": 100}); + \endqml Dynamically created instances can be deleted with the \c destroy() method. See \l {Dynamic Object Management in QML} for more information. @@ -870,7 +880,6 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon state->bindValues = enginePriv->bindValues; state->parserStatus = enginePriv->parserStatus; - state->finalizedParserStatus = enginePriv->finalizedParserStatus; state->componentAttached = enginePriv->componentAttached; if (state->componentAttached) state->componentAttached->prev = &state->componentAttached; @@ -878,7 +887,6 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon enginePriv->componentAttached = 0; enginePriv->bindValues.clear(); enginePriv->parserStatus.clear(); - enginePriv->finalizedParserStatus.clear(); state->completePending = true; enginePriv->inProgressCreations++; } @@ -909,7 +917,6 @@ void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *engi state->bindValues = enginePriv->bindValues; state->parserStatus = enginePriv->parserStatus; - state->finalizedParserStatus = enginePriv->finalizedParserStatus; state->componentAttached = enginePriv->componentAttached; if (state->componentAttached) state->componentAttached->prev = &state->componentAttached; @@ -917,7 +924,6 @@ void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *engi enginePriv->componentAttached = 0; enginePriv->bindValues.clear(); enginePriv->parserStatus.clear(); - enginePriv->finalizedParserStatus.clear(); state->completePending = true; enginePriv->inProgressCreations++; } @@ -955,14 +961,17 @@ void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePri QDeclarativeEnginePrivate::clear(ps); } - for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) { - QPair<QDeclarativeGuard<QObject>, int> status = state->finalizedParserStatus.at(ii); - QObject *obj = status.first; - if (obj) { - void *args[] = { 0 }; - QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, - status.second, args); + if (1 == enginePriv->inProgressCreations) { + for (int ii = 0; ii < enginePriv->finalizedParserStatus.count(); ++ii) { + QPair<QDeclarativeGuard<QObject>, int> status = enginePriv->finalizedParserStatus.at(ii); + QObject *obj = status.first; + if (obj) { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, + status.second, args); + } } + enginePriv->finalizedParserStatus.clear(); } while (state->componentAttached) { @@ -977,7 +986,6 @@ void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePri state->bindValues.clear(); state->parserStatus.clear(); - state->finalizedParserStatus.clear(); state->completePending = false; enginePriv->inProgressCreations--; @@ -987,7 +995,6 @@ void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePri enginePriv->erroredBindings->removeError(); } } - } } diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h index f8bec2b..020c5e0 100644 --- a/src/declarative/qml/qdeclarativecomponent_p.h +++ b/src/declarative/qml/qdeclarativecomponent_p.h @@ -101,7 +101,6 @@ public: ConstructionState() : componentAttached(0), completePending(false) {} QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> > bindValues; QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> > parserStatus; - QList<QPair<QDeclarativeGuard<QObject>, int> > finalizedParserStatus; QDeclarativeComponentAttached *componentAttached; QList<QDeclarativeError> errors; bool completePending; diff --git a/src/declarative/qml/qdeclarativecustomparser.cpp b/src/declarative/qml/qdeclarativecustomparser.cpp index 8dd6824..856108c 100644 --- a/src/declarative/qml/qdeclarativecustomparser.cpp +++ b/src/declarative/qml/qdeclarativecustomparser.cpp @@ -131,7 +131,7 @@ QDeclarativeCustomParserNodePrivate::fromProperty(QDeclarativeParser::Property * prop.d->values << QVariant::fromValue(props.at(ii)); } else { for(int ii = 0; ii < p->values.count(); ++ii) { - Value *v = p->values.at(ii); + QDeclarativeParser::Value *v = p->values.at(ii); v->type = QDeclarativeParser::Value::Literal; if(v->object) { diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp index 8c7f3ad..31fd516 100644 --- a/src/declarative/qml/qdeclarativeenginedebug.cpp +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp @@ -167,17 +167,19 @@ QDeclarativeEngineDebugServer::propertyData(QObject *obj, int propIdx) QVariant QDeclarativeEngineDebugServer::valueContents(const QVariant &value) const { int userType = value.userType(); - if (QDeclarativeValueTypeFactory::isValueType(userType)) - return value; - /* - if (QDeclarativeMetaType::isList(userType)) { - int count = QDeclarativeMetaType::listCount(value); + if (value.type() == QVariant::List) { QVariantList contents; - for (int i=0; i<count; i++) - contents << valueContents(QDeclarativeMetaType::listAt(value, i)); + QVariantList list = value.toList(); + int count = list.size(); + for (int i = 0; i < count; i++) + contents << valueContents(list.at(i)); return contents; - } else */ + } + + if (QDeclarativeValueTypeFactory::isValueType(userType)) + return value; + if (QDeclarativeMetaType::isQObject(userType)) { QObject *o = QDeclarativeMetaType::toQObject(value); if (o) { diff --git a/src/declarative/qml/qdeclarativelist.cpp b/src/declarative/qml/qdeclarativelist.cpp index 9598d98..346fee5 100644 --- a/src/declarative/qml/qdeclarativelist.cpp +++ b/src/declarative/qml/qdeclarativelist.cpp @@ -88,6 +88,7 @@ void QDeclarativeListReferencePrivate::release() /*! \class QDeclarativeListReference \since 4.7 +\module QtDeclarative \brief The QDeclarativeListReference class allows the manipulation of QDeclarativeListProperty properties. QDeclarativeListReference allows C++ programs to read from, and assign values to a QML list property in a diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index 2aa2059..dc3ecca 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -368,7 +368,7 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj, newBinding = new QDeclarativeBinding(value, obj, evalContext); newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber()); newBinding->setTarget(QDeclarativePropertyPrivate::restore(*lastData, valueTypeData, obj, evalContext)); - if (newBinding->expression().contains("this")) + if (newBinding->expression().contains(QLatin1String("this"))) newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject); } diff --git a/src/declarative/qml/qdeclarativeparser.cpp b/src/declarative/qml/qdeclarativeparser.cpp index 35bb0f1..d5b9424 100644 --- a/src/declarative/qml/qdeclarativeparser.cpp +++ b/src/declarative/qml/qdeclarativeparser.cpp @@ -225,9 +225,9 @@ QDeclarativeParser::Property::~Property() if (value) value->release(); } -Object *QDeclarativeParser::Property::getValue(const LocationSpan &l) +QDeclarativeParser::Object *QDeclarativeParser::Property::getValue(const LocationSpan &l) { - if (!value) { value = new Object; value->location = l; } + if (!value) { value = new QDeclarativeParser::Object; value->location = l; } return value; } diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index 61e3002..0dd0edb 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -427,7 +427,7 @@ bool QDeclarativeProperty::operator==(const QDeclarativeProperty &other) const */ int QDeclarativeProperty::propertyType() const { - return d ? d->propertyType() : QVariant::Invalid; + return d ? d->propertyType() : int(QVariant::Invalid); } bool QDeclarativePropertyPrivate::isValueType() const diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp index 996920a..e8f6b0d 100644 --- a/src/declarative/qml/qdeclarativescriptparser.cpp +++ b/src/declarative/qml/qdeclarativescriptparser.cpp @@ -65,16 +65,16 @@ class ProcessAST: protected AST::Visitor { struct State { State() : object(0), property(0) {} - State(Object *o) : object(o), property(0) {} - State(Object *o, Property *p) : object(o), property(p) {} + State(QDeclarativeParser::Object *o) : object(o), property(0) {} + State(QDeclarativeParser::Object *o, Property *p) : object(o), property(p) {} - Object *object; + QDeclarativeParser::Object *object; Property *property; }; struct StateStack : public QStack<State> { - void pushObject(Object *obj) + void pushObject(QDeclarativeParser::Object *obj) { push(State(obj)); } @@ -105,7 +105,7 @@ public: protected: - Object *defineObjectBinding(AST::UiQualifiedId *propertyName, bool onAssignment, + QDeclarativeParser::Object *defineObjectBinding(AST::UiQualifiedId *propertyName, bool onAssignment, const QString &objectType, AST::SourceLocation typeLocation, LocationSpan location, @@ -134,7 +134,7 @@ protected: QString asString(AST::UiQualifiedId *node) const; const State state() const; - Object *currentObject() const; + QDeclarativeParser::Object *currentObject() const; Property *currentProperty() const; QString qualifiedNameId() const; @@ -200,7 +200,7 @@ const ProcessAST::State ProcessAST::state() const return _stateStack.back(); } -Object *ProcessAST::currentObject() const +QDeclarativeParser::Object *ProcessAST::currentObject() const { return state().object; } @@ -229,7 +229,7 @@ QString ProcessAST::asString(AST::UiQualifiedId *node) const return s; } -Object * +QDeclarativeParser::Object * ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName, bool onAssignment, const QString &objectType, @@ -286,7 +286,7 @@ ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName, if (lastTypeDot >= 0) resolvableObjectType.replace(QLatin1Char('.'),QLatin1Char('/')); - Object *obj = new Object; + QDeclarativeParser::Object *obj = new QDeclarativeParser::Object; QDeclarativeScriptParser::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType); obj->type = typeRef->id; @@ -302,7 +302,7 @@ ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName, if (propertyCount) { Property *prop = currentProperty(); - Value *v = new Value; + QDeclarativeParser::Value *v = new QDeclarativeParser::Value; v->object = obj; v->location = obj->location; if (onAssignment) @@ -319,7 +319,7 @@ ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName, _parser->setTree(obj); } else { const State state = _stateStack.top(); - Value *v = new Value; + QDeclarativeParser::Value *v = new QDeclarativeParser::Value; v->object = obj; v->location = obj->location; if (state.property) { @@ -594,7 +594,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node) property.defaultValue->location = location(node->expression->firstSourceLocation(), node->expression->lastSourceLocation()); - Value *value = new Value; + QDeclarativeParser::Value *value = new QDeclarativeParser::Value; value->location = location(node->expression->firstSourceLocation(), node->expression->lastSourceLocation()); value->value = getVariant(node->expression); @@ -698,7 +698,7 @@ bool ProcessAST::visit(AST::UiScriptBinding *node) prop->location.range.length = prop->location.range.offset + prop->location.range.length - node->qualifiedId->identifierToken.offset; prop->location.range.offset = node->qualifiedId->identifierToken.offset; - Value *v = new Value; + QDeclarativeParser::Value *v = new QDeclarativeParser::Value; v->value = primitive; v->location = location(node->statement->firstSourceLocation(), node->statement->lastSourceLocation()); @@ -870,7 +870,7 @@ QList<QDeclarativeScriptParser::TypeReference*> QDeclarativeScriptParser::refere return _refTypes; } -Object *QDeclarativeScriptParser::tree() const +QDeclarativeParser::Object *QDeclarativeScriptParser::tree() const { return root; } @@ -1193,7 +1193,7 @@ QDeclarativeScriptParser::TypeReference *QDeclarativeScriptParser::findOrCreateT return type; } -void QDeclarativeScriptParser::setTree(Object *tree) +void QDeclarativeScriptParser::setTree(QDeclarativeParser::Object *tree) { Q_ASSERT(! root); diff --git a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp index 200cc1c..4c312b5 100644 --- a/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp +++ b/src/declarative/qml/qdeclarativevaluetypescriptclass.cpp @@ -184,7 +184,7 @@ void QDeclarativeValueTypeScriptClass::setProperty(Object *obj, const Identifier newBinding->setSourceLocation(ctxtInfo.fileName(), ctxtInfo.functionStartLineNumber()); QDeclarativeProperty prop = QDeclarativePropertyPrivate::restore(cacheData, valueTypeData, ref->object, ctxt); newBinding->setTarget(prop); - if (newBinding->expression().contains("this")) + if (newBinding->expression().contains(QLatin1String("this"))) newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject); } diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 366c64b..2d551f2 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -938,7 +938,6 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, QDeclarativeEnginePrivate::clear(bindValues); QDeclarativeEnginePrivate::clear(parserStatus); - ep->finalizedParserStatus.clear(); return 0; } diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp index eaf0cfa..dc6d524 100644 --- a/src/declarative/util/qdeclarativeanimation.cpp +++ b/src/declarative/util/qdeclarativeanimation.cpp @@ -182,12 +182,11 @@ void QDeclarativeAbstractAnimation::setRunning(bool r) { Q_D(QDeclarativeAbstractAnimation); if (!d->componentComplete) { - if (d->running && r == d->running) //don't re-register - return; d->running = r; if (r == false) d->avoidPropertyValueSourceStart = true; - else { + else if (!d->registered) { + d->registered = true; QDeclarativeEnginePrivate *engPriv = QDeclarativeEnginePrivate::get(qmlEngine(this)); engPriv->registerFinalizedParserStatusObject(this, this->metaObject()->indexOfSlot("componentFinalized()")); } @@ -204,6 +203,7 @@ void QDeclarativeAbstractAnimation::setRunning(bool r) d->running = r; if (d->running) { + bool supressStart = false; if (d->alwaysRunToEnd && d->loopCount != 1 && qtAnimation()->state() == QAbstractAnimation::Running) { //we've restarted before the final loop finished; restore proper loop count @@ -211,6 +211,7 @@ void QDeclarativeAbstractAnimation::setRunning(bool r) qtAnimation()->setLoopCount(d->loopCount); else qtAnimation()->setLoopCount(qtAnimation()->currentLoop() + d->loopCount); + supressStart = true; //we want the animation to continue, rather than restart } if (!d->connectedTimeLine) { @@ -218,7 +219,8 @@ void QDeclarativeAbstractAnimation::setRunning(bool r) this, SLOT(timelineComplete())); d->connectedTimeLine = true; } - d->commence(); + if (!supressStart) + d->commence(); emit started(); } else { if (d->alwaysRunToEnd) { diff --git a/src/declarative/util/qdeclarativeanimation_p_p.h b/src/declarative/util/qdeclarativeanimation_p_p.h index 15bda3c..048ecb1 100644 --- a/src/declarative/util/qdeclarativeanimation_p_p.h +++ b/src/declarative/util/qdeclarativeanimation_p_p.h @@ -210,7 +210,7 @@ public: : running(false), paused(false), alwaysRunToEnd(false), connectedTimeLine(false), componentComplete(true), avoidPropertyValueSourceStart(false), disableUserControl(false), - loopCount(1), group(0) {} + registered(false), loopCount(1), group(0) {} bool running:1; bool paused:1; @@ -219,6 +219,7 @@ public: bool componentComplete:1; bool avoidPropertyValueSourceStart:1; bool disableUserControl:1; + bool registered:1; int loopCount; diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index ccd122e..9bcb263 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -281,7 +281,7 @@ QDeclarativePropertyChangesParser::compile(const QList<QDeclarativeCustomParserP QDeclarativeParser::Variant v = qvariant_cast<QDeclarativeParser::Variant>(data.at(ii).second); QVariant var; bool isScript = v.isScript(); - QDeclarativeBinding::Identifier id; + QDeclarativeBinding::Identifier id = 0; switch(v.type()) { case QDeclarativeParser::Variant::Boolean: var = QVariant(v.asBoolean()); diff --git a/src/declarative/util/qdeclarativespringanimation.cpp b/src/declarative/util/qdeclarativespringanimation.cpp index ec2b083..1212a1c 100644 --- a/src/declarative/util/qdeclarativespringanimation.cpp +++ b/src/declarative/util/qdeclarativespringanimation.cpp @@ -236,7 +236,7 @@ void QDeclarativeSpringAnimationPrivate::updateMode() /*! \qmlclass SpringAnimation QDeclarativeSpringAnimation \ingroup qml-animation-transition - \inherits Animation + \inherits NumberAnimation \since 4.7 \brief The SpringAnimation element allows a property to track a value in a spring-like motion. diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp index d691f94..d5c7d1b 100644 --- a/src/declarative/util/qdeclarativexmllistmodel.cpp +++ b/src/declarative/util/qdeclarativexmllistmodel.cpp @@ -46,11 +46,9 @@ #include <QDebug> #include <QStringList> -#include <QQueue> +#include <QMap> #include <QApplication> #include <QThread> -#include <QMutex> -#include <QWaitCondition> #include <QXmlQuery> #include <QXmlResultItems> #include <QXmlNodeModelIndex> @@ -58,6 +56,7 @@ #include <QNetworkRequest> #include <QNetworkReply> #include <QTimer> +#include <QMutex> #include <private/qobject_p.h> @@ -147,39 +146,32 @@ struct XmlQueryJob QStringList keyRoleResultsCache; }; -class QDeclarativeXmlQuery : public QThread +class QDeclarativeXmlQuery : public QObject { Q_OBJECT public: QDeclarativeXmlQuery(QObject *parent=0) - : QThread(parent), m_quit(false), m_abortQueryId(-1), m_queryIds(XMLLISTMODEL_CLEAR_ID + 1) { + : QObject(parent), m_queryIds(XMLLISTMODEL_CLEAR_ID + 1) { qRegisterMetaType<QDeclarativeXmlQueryResult>("QDeclarativeXmlQueryResult"); - m_currentJob.queryId = -1; + moveToThread(&m_thread); + m_thread.start(QThread::IdlePriority); } ~QDeclarativeXmlQuery() { - m_mutex.lock(); - m_quit = true; - m_condition.wakeOne(); - m_mutex.unlock(); - - wait(); + if(m_thread.isRunning()) { + m_thread.quit(); + m_thread.wait(); + } } void abort(int id) { - QMutexLocker locker(&m_mutex); - QQueue<XmlQueryJob>::iterator it; - for (it = m_jobs.begin(); it != m_jobs.end(); ++it) { - if ((*it).queryId == id) { - m_jobs.erase(it); - return; - } + QMutexLocker ml(&m_mutex); + if (id != -1) { + m_jobs.remove(id); } - m_abortQueryId = id; } - int doQuery(QString query, QString namespaces, QByteArray data, QList<QDeclarativeXmlListModelRole *> *roleObjects, QStringList keyRoleResultsCache) { - QMutexLocker locker(&m_mutex); + int doQuery(QString query, QString namespaces, QByteArray data, QList<QDeclarativeXmlListModelRole *>* roleObjects, QStringList keyRoleResultsCache) { XmlQueryJob job; job.queryId = m_queryIds; @@ -198,69 +190,69 @@ public: if (roleObjects->at(i)->isKey()) job.keyRoleQueries << job.roleQueries.last(); } - m_jobs.enqueue(job); - m_queryIds++; - if (!isRunning()) - start(QThread::IdlePriority); - else - m_condition.wakeOne(); + { + QMutexLocker ml(&m_mutex); + m_jobs.insert(m_queryIds, job); + m_queryIds++; + if (m_queryIds <= 0) + m_queryIds = 1; + } + + QMetaObject::invokeMethod(this, "processQuery", Qt::QueuedConnection, Q_ARG(int, job.queryId)); return job.queryId; } +private slots: + void processQuery(int queryId) { + XmlQueryJob job; + + { + QMutexLocker ml(&m_mutex); + if (!m_jobs.contains(queryId)) + return; + job = m_jobs.value(queryId); + } + + QDeclarativeXmlQueryResult r; + doQueryJob(&job); + doSubQueryJob(&job); + r.queryId = job.queryId; + r.size = m_size; + r.data = m_modelData; + r.inserted = m_insertedItemRanges; + r.removed = m_removedItemRanges; + r.keyRoleResultsCache = job.keyRoleResultsCache; + + { + QMutexLocker ml(&m_mutex); + if (m_jobs.contains(queryId)) { + emit queryCompleted(r); + m_jobs.remove(queryId); + } + } + } + Q_SIGNALS: void queryCompleted(const QDeclarativeXmlQueryResult &); void error(void*, const QString&); protected: - void run() { - m_mutex.lock(); - - while (!m_quit) { - if (!m_jobs.isEmpty()) - m_currentJob = m_jobs.dequeue(); - m_mutex.unlock(); - - QDeclarativeXmlQueryResult r; - if (m_currentJob.queryId != -1) { - doQueryJob(); - doSubQueryJob(); - r.queryId = m_currentJob.queryId; - r.size = m_size; - r.data = m_modelData; - r.inserted = m_insertedItemRanges; - r.removed = m_removedItemRanges; - r.keyRoleResultsCache = m_currentJob.keyRoleResultsCache; - } - m_mutex.lock(); - if (m_currentJob.queryId != -1 && m_abortQueryId != m_currentJob.queryId) - emit queryCompleted(r); - if (m_jobs.isEmpty() && !m_quit) - m_condition.wait(&m_mutex); - m_currentJob.queryId = -1; - m_abortQueryId = -1; - } - - m_mutex.unlock(); - } private: - void doQueryJob(); - void doSubQueryJob(); - void getValuesOfKeyRoles(QStringList *values, QXmlQuery *query) const; + void doQueryJob(XmlQueryJob* job); + void doSubQueryJob(XmlQueryJob* job); + void getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const; void addIndexToRangeList(QList<QDeclarativeXmlListRange> *ranges, int index) const; private: QMutex m_mutex; - QWaitCondition m_condition; - QQueue<XmlQueryJob> m_jobs; - XmlQueryJob m_currentJob; - bool m_quit; - int m_abortQueryId; + QThread m_thread; + QMap<int, XmlQueryJob> m_jobs; + int m_queryIds; QString m_prefix; int m_size; - int m_queryIds; QList<QList<QVariant> > m_modelData; QList<QDeclarativeXmlListRange> m_insertedItemRanges; QList<QDeclarativeXmlListRange> m_removedItemRanges; @@ -268,16 +260,16 @@ private: Q_GLOBAL_STATIC(QDeclarativeXmlQuery, globalXmlQuery) -void QDeclarativeXmlQuery::doQueryJob() +void QDeclarativeXmlQuery::doQueryJob(XmlQueryJob* currentJob) { - Q_ASSERT(m_currentJob.queryId != -1); + Q_ASSERT(currentJob->queryId != -1); QString r; QXmlQuery query; - QBuffer buffer(&m_currentJob.data); + QBuffer buffer(¤tJob->data); buffer.open(QIODevice::ReadOnly); query.bindVariable(QLatin1String("src"), &buffer); - query.setQuery(m_currentJob.namespaces + m_currentJob.query); + query.setQuery(currentJob->namespaces + currentJob->query); query.evaluateTo(&r); //always need a single root element @@ -285,9 +277,9 @@ void QDeclarativeXmlQuery::doQueryJob() QBuffer b(&xml); b.open(QIODevice::ReadOnly); - QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + m_currentJob.namespaces; + QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + currentJob->namespaces; QString prefix = QLatin1String("doc($inputDocument)/dummy:items") + - m_currentJob.query.mid(m_currentJob.query.lastIndexOf(QLatin1Char('/'))); + currentJob->query.mid(currentJob->query.lastIndexOf(QLatin1Char('/'))); //figure out how many items we are dealing with int count = -1; @@ -302,18 +294,16 @@ void QDeclarativeXmlQuery::doQueryJob() count = item.toAtomicValue().toInt(); } - m_currentJob.data = xml; + currentJob->data = xml; m_prefix = namespaces + prefix + QLatin1Char('/'); m_size = 0; if (count > 0) m_size = count; } -void QDeclarativeXmlQuery::getValuesOfKeyRoles(QStringList *values, QXmlQuery *query) const +void QDeclarativeXmlQuery::getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const { - Q_ASSERT(m_currentJob.queryId != -1); - - const QStringList &keysQueries = m_currentJob.keyRoleQueries; + const QStringList &keysQueries = currentJob.keyRoleQueries; QString keysQuery; if (keysQueries.count() == 1) keysQuery = m_prefix + keysQueries[0]; @@ -341,34 +331,34 @@ void QDeclarativeXmlQuery::addIndexToRangeList(QList<QDeclarativeXmlListRange> * ranges->append(qMakePair(index, 1)); } -void QDeclarativeXmlQuery::doSubQueryJob() +void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) { - Q_ASSERT(m_currentJob.queryId != -1); + Q_ASSERT(currentJob->queryId != -1); m_modelData.clear(); - QBuffer b(&m_currentJob.data); + QBuffer b(¤tJob->data); b.open(QIODevice::ReadOnly); QXmlQuery subquery; subquery.bindVariable(QLatin1String("inputDocument"), &b); QStringList keyRoleResults; - getValuesOfKeyRoles(&keyRoleResults, &subquery); + getValuesOfKeyRoles(*currentJob, &keyRoleResults, &subquery); // See if any values of key roles have been inserted or removed. m_insertedItemRanges.clear(); m_removedItemRanges.clear(); - if (m_currentJob.keyRoleResultsCache.isEmpty()) { + if (currentJob->keyRoleResultsCache.isEmpty()) { m_insertedItemRanges << qMakePair(0, m_size); } else { - if (keyRoleResults != m_currentJob.keyRoleResultsCache) { + if (keyRoleResults != currentJob->keyRoleResultsCache) { QStringList temp; - for (int i=0; i<m_currentJob.keyRoleResultsCache.count(); i++) { - if (!keyRoleResults.contains(m_currentJob.keyRoleResultsCache[i])) + for (int i=0; i<currentJob->keyRoleResultsCache.count(); i++) { + if (!keyRoleResults.contains(currentJob->keyRoleResultsCache[i])) addIndexToRangeList(&m_removedItemRanges, i); else - temp << m_currentJob.keyRoleResultsCache[i]; + temp << currentJob->keyRoleResultsCache[i]; } for (int i=0; i<keyRoleResults.count(); i++) { @@ -379,11 +369,11 @@ void QDeclarativeXmlQuery::doSubQueryJob() } } } - m_currentJob.keyRoleResultsCache = keyRoleResults; + currentJob->keyRoleResultsCache = keyRoleResults; // Get the new values for each role. //### we might be able to condense even further (query for everything in one go) - const QStringList &queries = m_currentJob.roleQueries; + const QStringList &queries = currentJob->roleQueries; for (int i = 0; i < queries.size(); ++i) { QList<QVariant> resultList; if (!queries[i].isEmpty()) { @@ -397,7 +387,7 @@ void QDeclarativeXmlQuery::doSubQueryJob() item = resultItems.next(); } } else { - emit error(m_currentJob.roleQueryErrorId.at(i), queries[i]); + emit error(currentJob->roleQueryErrorId.at(i), queries[i]); } } //### should warn here if things have gone wrong. diff --git a/src/gui/dialogs/qfileinfogatherer.cpp b/src/gui/dialogs/qfileinfogatherer.cpp index 12e77b1..b36b21e 100644 --- a/src/gui/dialogs/qfileinfogatherer.cpp +++ b/src/gui/dialogs/qfileinfogatherer.cpp @@ -78,11 +78,11 @@ QFileInfoGatherer::QFileInfoGatherer(QObject *parent) #endif m_resolveSymlinks(false), m_iconProvider(&defaultProvider) { -#ifndef Q_OS_WIN +#ifdef Q_OS_WIN + m_resolveSymlinks = true; +#elif !defined(Q_OS_INTEGRITY) userId = getuid(); groupId = getgid(); -#else - m_resolveSymlinks = true; #endif #ifndef QT_NO_FILESYSTEMWATCHER watcher = new QFileSystemWatcher(this); diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index dd27aff..cb8eb6a 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -1458,7 +1458,6 @@ void QFileSystemModel::setIconProvider(QFileIconProvider *provider) { Q_D(QFileSystemModel); d->fileInfoGatherer.setIconProvider(provider); - QApplication::processEvents(); d->root.updateIcon(provider, QString()); } diff --git a/src/gui/embedded/embedded.pri b/src/gui/embedded/embedded.pri index eb13d8d..31f0bc6 100644 --- a/src/gui/embedded/embedded.pri +++ b/src/gui/embedded/embedded.pri @@ -120,6 +120,12 @@ embedded { LIBS += -lgf } + contains( gfx-drivers, integrityfb ) { + HEADERS += embedded/qscreenintegrityfb_qws.h + SOURCES += embedded/qscreenintegrityfb_qws.cpp + LIBS += -lfbdev + } + contains( gfx-drivers, qvfb ) { HEADERS += embedded/qscreenvfb_qws.h SOURCES += embedded/qscreenvfb_qws.cpp @@ -174,6 +180,11 @@ embedded { SOURCES += embedded/qkbdqnx_qws.cpp } + contains( kbd-drivers, integrity ) { + HEADERS += embedded/qkbdintegrity_qws.h + SOURCES += embedded/qkbdintegrity_qws.cpp + } + # # Mouse drivers # @@ -207,4 +218,9 @@ embedded { HEADERS += embedded/qmouseqnx_qws.h SOURCES += embedded/qmouseqnx_qws.cpp } + + contains( mouse-drivers, integrity ) { + HEADERS += embedded/qmouseintegrity_qws.h + SOURCES += embedded/qmouseintegrity_qws.cpp + } } diff --git a/src/gui/embedded/qkbddriverfactory_qws.cpp b/src/gui/embedded/qkbddriverfactory_qws.cpp index 661b073..45825e5 100644 --- a/src/gui/embedded/qkbddriverfactory_qws.cpp +++ b/src/gui/embedded/qkbddriverfactory_qws.cpp @@ -49,6 +49,7 @@ #include "qkbdum_qws.h" #include "qkbdvfb_qws.h" #include "qkbdqnx_qws.h" +#include "qkbdintegrity_qws.h" #include <stdlib.h> #include "private/qfactoryloader_p.h" #include "qkbddriverplugin_qws.h" @@ -106,6 +107,10 @@ QWSKeyboardHandler *QKbdDriverFactory::create(const QString& key, const QString& if (driver == QLatin1String("qnx") || driver.isEmpty()) return new QWSQnxKeyboardHandler(device); #endif +#if defined(Q_OS_INTEGRITY) + if (driver == QLatin1String("integrity") || driver.isEmpty()) + return new QWSIntKeyboardHandler(device); +#endif #ifndef QT_NO_QWS_KEYBOARD # ifndef QT_NO_QWS_KBD_TTY if (driver == QLatin1String("tty") || driver.isEmpty()) @@ -151,6 +156,9 @@ QStringList QKbdDriverFactory::keys() #if defined(Q_OS_QNX) && !defined(QT_NO_QWS_KBD_QNX) list << QLatin1String("QNX"); #endif +#if defined(Q_OS_INTEGRITY) && !defined(QT_NO_QWS_KBD_INTEGRITY) + list << QLatin1String("INTEGRITY"); +#endif #ifndef QT_NO_QWS_KBD_TTY list << QLatin1String("TTY"); #endif diff --git a/src/gui/embedded/qkbdintegrity_qws.cpp b/src/gui/embedded/qkbdintegrity_qws.cpp new file mode 100644 index 0000000..b2df422 --- /dev/null +++ b/src/gui/embedded/qkbdintegrity_qws.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#if !defined(QT_NO_QWS_KEYBOARD) && !defined(QT_NO_QWS_KBD_INTEGRITY) + +#include "qkbdintegrity_qws.h" +#include <qwindowsystem_qws.h> +#include <qapplication.h> +#include <qtimer.h> +#include <qthread.h> + +#include <INTEGRITY.h> + + +//=========================================================================== + +QT_BEGIN_NAMESPACE + +// +// INTEGRITY keyboard +// + +class QIntKeyboardListenThread; + +class QWSIntKbPrivate : public QObject +{ + Q_OBJECT + friend class QIntKeyboardListenThread; +public: + QWSIntKbPrivate(QWSKeyboardHandler *, const QString &device); + ~QWSIntKbPrivate(); + void dataReady(int amount) { emit kbdDataAvailable(amount); } + uint8_t scancodebuf[32 /* USB_SCANCODE_BUF_LEN */ ]; + uint8_t rxpost; + uint8_t rxack; + +Q_SIGNALS: + void kbdDataAvailable(int amount); + +private Q_SLOTS: + void readKeyboardData(int amount); + +private: + QWSKeyboardHandler *handler; + QIntKeyboardListenThread *kbdthread; +}; +class QIntKeyboardListenThread : public QThread +{ +protected: + QWSIntKbPrivate *imp; + bool loop; +public: + QIntKeyboardListenThread(QWSIntKbPrivate *im) : QThread(), imp(im) {}; + ~QIntKeyboardListenThread() {}; + void run(); + void stoploop() { loop = false; }; +}; + + +QWSIntKeyboardHandler::QWSIntKeyboardHandler(const QString &device) + : QWSKeyboardHandler(device) +{ + d = new QWSIntKbPrivate(this, device); +} + +QWSIntKeyboardHandler::~QWSIntKeyboardHandler() +{ + delete d; +} + +//void QWSIntKeyboardHandler::processKeyEvent(int keycode, bool isPress, +// bool autoRepeat) +//{ +// QWSKeyboardHandler::processKeyEvent(keycode, isPress, autoRepeat); +//} + +void QIntKeyboardListenThread::run(void) +{ + Error E; + Buffer b; + Connection kbdc; + bool waitforresource = true; + do { + E = RequestResource((Object*)&kbdc, + "USBKeyboardClient", "!systempassword"); + if (E == Success) { + loop = false; + } else { + E = RequestResource((Object*)&kbdc, + "KeyboardClient", "!systempassword"); + if (E == Success) { + waitforresource = false; + } + } + if (waitforresource) + ::sleep(1); + } while (loop && waitforresource); + if (!loop) + return; + b.BufferType = DataBuffer | LastBuffer; + b.Length = sizeof(imp->scancodebuf); + b.TheAddress = (Address)imp->scancodebuf; + do { + b.Transferred = 0; + b.TheAddress = (Address)imp->scancodebuf + imp->rxpost; + CheckSuccess(SynchronousReceive(kbdc, &b)); + imp->rxpost += b.Transferred; + if (imp->rxpost >= 32 /* USB_SCANCODE_BUF_LEN */) + imp->rxpost = 0; + if (imp->rxpost == (imp->rxack + b.Transferred) % 32 /* USB_SCANCODE_BUF_LEN */) { + imp->kbdDataAvailable(b.Transferred); + } + } while (loop); +} + +void QWSIntKbPrivate::readKeyboardData(int amount) +{ + uint16_t keycode; + do { + if (scancodebuf[rxack] == 0xe0) { + keycode = scancodebuf[rxack] << 8; + rxack++; + if (rxack >= 32 /* USB_SCANCODE_BUF_LEN */) + rxack = 0; + } else { + keycode = 0; + } + + handler->processKeycode(keycode + (scancodebuf[rxack] & 0x7f), + (scancodebuf[rxack] & 0x80) == 0, + scancodebuf[rxack] == 2); + rxack++; + if (rxack >= 32 /* USB_SCANCODE_BUF_LEN */) + rxack = 0; + } while (rxack != rxpost); +} + +QWSIntKbPrivate::QWSIntKbPrivate(QWSKeyboardHandler *h, const QString &device) : handler(h) +{ + connect(this, SIGNAL(kbdDataAvailable(int)), this, SLOT(readKeyboardData(int))); + this->handler = handler; + rxack = rxpost = 0; + kbdthread = new QIntKeyboardListenThread(this); + kbdthread->start(); +} + +QWSIntKbPrivate::~QWSIntKbPrivate() +{ + kbdthread->stoploop(); + kbdthread->wait(); + delete kbdthread; +} + + +QT_END_NAMESPACE + +#include "qkbdintegrity_qws.moc" + +#endif // QT_NO_QWS_KEYBOARD || QT_NO_QWS_KBD_TTY diff --git a/src/gui/embedded/qkbdintegrity_qws.h b/src/gui/embedded/qkbdintegrity_qws.h new file mode 100644 index 0000000..f9ae4e3 --- /dev/null +++ b/src/gui/embedded/qkbdintegrity_qws.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 QKBDINTEGRITY_QWS_H +#define QKBDINTEGRITY_QWS_H + +#include <QtGui/qkbd_qws.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_QWS_KEYBOARD + +#ifndef QT_NO_QWS_KBD_INTEGRITY + +class QSocketNotifier; +class QWSIntKbPrivate; + +class QWSIntKeyboardHandler : public QWSKeyboardHandler +{ +public: + explicit QWSIntKeyboardHandler(const QString&); + virtual ~QWSIntKeyboardHandler(); + +//protected: +// virtual void processKeyEvent(int keycode, bool isPress, bool autoRepeat); + +private: + QWSIntKbPrivate *d; +}; + +#endif // QT_NO_QWS_KBD_INTEGRITY + +#endif // QT_NO_QWS_KEYBOARD + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QKBDINTEGRITY_QWS_H diff --git a/src/gui/embedded/qmousedriverfactory_qws.cpp b/src/gui/embedded/qmousedriverfactory_qws.cpp index 81e6552..f67284d 100644 --- a/src/gui/embedded/qmousedriverfactory_qws.cpp +++ b/src/gui/embedded/qmousedriverfactory_qws.cpp @@ -48,6 +48,7 @@ #include "qmousevfb_qws.h" #include "qmousetslib_qws.h" #include "qmouseqnx_qws.h" +#include "qmouseintegrity_qws.h" #include <stdlib.h> #include "private/qfactoryloader_p.h" #include "qmousedriverplugin_qws.h" @@ -107,6 +108,10 @@ QWSMouseHandler *QMouseDriverFactory::create(const QString& key, const QString & if (driver == QLatin1String("qnx") || driver.isEmpty()) return new QQnxMouseHandler(key, device); #endif +#if defined(Q_OS_INTEGRITY) && !defined(QT_NO_MOUSE_INTEGRITY) + if (driver == QLatin1String("integrity") || driver.isEmpty()) + return new QIntMouseHandler(key, device); +#endif #ifndef QT_NO_QWS_MOUSE_LINUXTP if (driver == QLatin1String("linuxtp") || driver.isEmpty()) return new QWSLinuxTPMouseHandler(key, device); @@ -157,6 +162,9 @@ QStringList QMouseDriverFactory::keys() #if defined(Q_OS_QNX) && !defined(QT_NO_QWS_MOUSE_QNX) list << QLatin1String("QNX"); #endif +#if defined(Q_OS_INTEGRITY) && !defined(QT_NO_QWS_MOUSE_INTEGRITY) + list << QLatin1String("INTEGRITY"); +#endif #ifndef QT_NO_QWS_MOUSE_LINUXTP list << QLatin1String("LinuxTP"); #endif diff --git a/src/gui/embedded/qmouseintegrity_qws.cpp b/src/gui/embedded/qmouseintegrity_qws.cpp new file mode 100644 index 0000000..78a8c1b --- /dev/null +++ b/src/gui/embedded/qmouseintegrity_qws.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** 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 QT_NO_QWS_MOUSE_INTEGRITY + +#include "qmouseintegrity_qws.h" +#include <qwindowsystem_qws.h> +#include <qapplication.h> +#include <qtimer.h> +#include <qthread.h> + +#include <INTEGRITY.h> + + +typedef Address MOUSEHandler; +typedef struct MOUSEMessageStruct +{ + Value x; + Value y; + Value z; + Value buttons; +} MOUSEMessage; + +static Error MOUSE_Init(MOUSEHandler *handler, Boolean *isabsolute); +static Error MOUSE_SynchronousGetPosition(MOUSEHandler handler, MOUSEMessage *msg, + Boolean absolute); +static Error MOUSE_ShouldFilter(MOUSEHandler handler, Boolean *filter); + +QT_BEGIN_NAMESPACE + +class QIntMouseListenThread; + +class QIntMousePrivate : public QObject +{ + Q_OBJECT + friend class QIntMouseListenTaskThread; +Q_SIGNALS: + void mouseDataAvailable(int x, int y, int buttons); +public: + QIntMousePrivate(QIntMouseHandler *handler); + ~QIntMousePrivate(); + void dataReady(int x, int y, int buttons) { emit mouseDataAvailable(x, y, buttons); } + bool calibrated; + bool waitforread; + bool suspended; + QIntMouseListenThread *mousethread; + +private: + QIntMouseHandler *handler; +}; + +class QIntMouseListenThread : public QThread +{ +protected: + QIntMousePrivate *imp; + bool loop; +public: + QIntMouseListenThread(QIntMousePrivate *im) : QThread(), imp(im) {}; + ~QIntMouseListenThread() {}; + void run(); + void stoploop() { loop = false; }; +}; + + +QIntMouseHandler::QIntMouseHandler(const QString &driver, const QString &device) + : QObject(), QWSCalibratedMouseHandler(driver, device) +{ + QPoint test(1,1); + d = new QIntMousePrivate(this); + connect(d, SIGNAL(mouseDataAvailable(int, int, int)), this, SLOT(readMouseData(int, int, int))); + + d->calibrated = (test != transform(test)); + + d->mousethread->start(); +} + +QIntMouseHandler::~QIntMouseHandler() +{ + disconnect(d, SIGNAL(mouseDataAvailable(int, int, int)), this, SLOT(readMouseData(int, int, int))); + delete d; +} + +void QIntMouseHandler::resume() +{ + d->suspended = true; +} + +void QIntMouseHandler::suspend() +{ + d->suspended = false; +} + +void QIntMouseHandler::readMouseData(int x, int y, int buttons) +{ + d->waitforread = false; + if (d->suspended) + return; + if (d->calibrated) { + sendFiltered(QPoint(x, y), buttons); + } else { + QPoint pos; + pos = transform(QPoint(x, y)); + limitToScreen(pos); + mouseChanged(pos, buttons, 0); + } +} + +void QIntMouseHandler::clearCalibration() +{ + QWSCalibratedMouseHandler::clearCalibration(); +} + +void QIntMouseHandler::calibrate(const QWSPointerCalibrationData *data) +{ + QWSCalibratedMouseHandler::calibrate(data); +} + +void QIntMouseListenThread::run(void) +{ + MOUSEHandler handler; + MOUSEMessage msg; + Boolean filter; + Boolean isabsolute; + loop = true; + CheckSuccess(MOUSE_Init(&handler, &isabsolute)); + CheckSuccess(MOUSE_ShouldFilter(handler, &filter)); + if (!filter) + imp->calibrated = false; + imp->waitforread = false; + do { + MOUSE_SynchronousGetPosition(handler, &msg, isabsolute); + imp->dataReady(msg.x, msg.y, msg.buttons); + } while (loop); + QThread::exit(0); +} + +QIntMousePrivate::QIntMousePrivate(QIntMouseHandler *handler) + : QObject() +{ + this->handler = handler; + suspended = false; + mousethread = new QIntMouseListenThread(this); +} + +QIntMousePrivate::~QIntMousePrivate() +{ + mousethread->stoploop(); + mousethread->wait(); + delete mousethread; +} + +QT_END_NAMESPACE + +#include "qmouseintegrity_qws.moc" + +typedef struct USBMouseStruct +{ + Connection mouseconn; + Buffer mousemsg[2]; + Value x; + Value y; +} USBMouse; + +USBMouse mousedev; + +Error MOUSE_Init(MOUSEHandler *handler, Boolean *isabsolute) +{ + Error E; + bool loop = true; + memset((void*)&mousedev, 0, sizeof(USBMouse)); + mousedev.mousemsg[0].BufferType = DataImmediate; + mousedev.mousemsg[1].BufferType = DataImmediate | LastBuffer; + do { + E = RequestResource((Object*)&mousedev.mouseconn, + "MouseClient", "!systempassword"); + if (E == Success) { + *isabsolute = true; + loop = false; + } else { + E = RequestResource((Object*)&mousedev.mouseconn, + "USBMouseClient", "!systempassword"); + if (E == Success) { + *isabsolute = false; + loop = false; + } + } + if (loop) + sleep(1); + } while (loop); + *handler = (MOUSEHandler)&mousedev; + return Success; +} + +Error MOUSE_SynchronousGetPosition(MOUSEHandler handler, MOUSEMessage *msg, + Boolean isabsolute) +{ + signed long x; + signed long y; + USBMouse *mdev = (USBMouse *)handler; + mdev->mousemsg[0].Transferred = 0; + mdev->mousemsg[1].Transferred = 0; + SynchronousReceive(mdev->mouseconn, mdev->mousemsg); + if (isabsolute) { + x = (signed long)mdev->mousemsg[0].Length; + y = (signed long)mdev->mousemsg[1].TheAddress; + } else { + x = mdev->x + (signed long)mdev->mousemsg[0].Length; + y = mdev->y + (signed long)mdev->mousemsg[1].TheAddress; + } + if (x < 0) + mdev->x = 0; + else + mdev->x = x; + if (y < 0) + mdev->y = 0; + else + mdev->y = y; + msg->x = mdev->x; + msg->y = mdev->y; + msg->buttons = mdev->mousemsg[0].TheAddress; + return Success; +} + +Error MOUSE_ShouldFilter(MOUSEHandler handler, Boolean *filter) +{ + if (filter == NULL) + return Failure; + *filter = false; + return Success; +} + +#endif // QT_NO_QWS_MOUSE_INTEGRITY + diff --git a/src/gui/embedded/qmouseintegrity_qws.h b/src/gui/embedded/qmouseintegrity_qws.h new file mode 100644 index 0000000..46d27a3 --- /dev/null +++ b/src/gui/embedded/qmouseintegrity_qws.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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 QMOUSEINTEGRITY_QWS_H +#define QMOUSEINTEGRITY_QWS_H + +#include <QtGui/qmouse_qws.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_QWS_MOUSE_INTEGRITY + +class QSocketNotifier; +class QIntMousePrivate; + +class QIntMouseHandler : public QObject, public QWSCalibratedMouseHandler { + Q_OBJECT +public: + QIntMouseHandler(const QString &driver = QString(), + const QString &device = QString()); + ~QIntMouseHandler(); + + void resume(); + void suspend(); + + void calibrate(const QWSPointerCalibrationData *data); + void clearCalibration(); + +private: + QIntMousePrivate *d; +private Q_SLOTS: + void readMouseData(int x, int y, int buttons); +}; +#endif // QT_NO_QWS_MOUSE_INTEGRITY + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMOUSEINTEGRITY_QWS_H diff --git a/src/gui/embedded/qscreen_qws.h b/src/gui/embedded/qscreen_qws.h index d237dd8..17ffbbb 100644 --- a/src/gui/embedded/qscreen_qws.h +++ b/src/gui/embedded/qscreen_qws.h @@ -193,7 +193,7 @@ class Q_GUI_EXPORT QScreen { public: enum ClassId { LinuxFBClass, TransformedClass, VNCClass, MultiClass, VFbClass, DirectFBClass, SvgalibClass, ProxyClass, - GLClass, CustomClass = 1024 }; + GLClass, IntfbClass, CustomClass = 1024 }; QScreen(int display_id, ClassId classId); explicit QScreen(int display_id); @@ -358,6 +358,7 @@ private: friend class QLinuxFbScreen; friend class QVFbScreen; friend class QProxyScreen; + friend class QIntfbScreen; #endif friend void qt_solidFill_setup(QScreen*, const QColor&, const QRegion&); friend void qt_blit_setup(QScreen *screen, const QImage &image, diff --git a/src/gui/embedded/qscreendriverfactory_qws.cpp b/src/gui/embedded/qscreendriverfactory_qws.cpp index c0ae214..ea194e5 100644 --- a/src/gui/embedded/qscreendriverfactory_qws.cpp +++ b/src/gui/embedded/qscreendriverfactory_qws.cpp @@ -48,6 +48,7 @@ #include "qscreenvfb_qws.h" #include "qscreenmulti_qws_p.h" #include "qscreenqnx_qws.h" +#include "qscreenintegrityfb_qws.h" #include <stdlib.h> #include "private/qfactoryloader_p.h" #include "qscreendriverplugin_qws.h" @@ -112,6 +113,10 @@ QScreen *QScreenDriverFactory::create(const QString& key, int displayId) if (driver == QLatin1String("qnx") || driver.isEmpty()) return new QQnxScreen(displayId); #endif +#if defined(Q_OS_INTEGRITY) && !defined(QT_NO_QWS_INTEGRITY) + if (driver == QLatin1String("integrityfb") || driver.isEmpty()) + return new QIntfbScreen(displayId); +#endif #ifndef QT_NO_QWS_QVFB if (driver == QLatin1String("qvfb") || driver.isEmpty()) return new QVFbScreen(displayId); @@ -159,6 +164,9 @@ QStringList QScreenDriverFactory::keys() #if defined(Q_OS_QNX) && !defined(QT_NO_QWS_QNX) list << QLatin1String("QNX"); #endif +#if defined(Q_OS_INTEGRITY) && !defined(QT_NO_QWS_INTEGRITY) + list << QLatin1String("INTEGRITYFB"); +#endif #ifndef QT_NO_QWS_QVFB list << QLatin1String("QVFb"); #endif diff --git a/src/gui/embedded/qscreenintegrityfb_qws.cpp b/src/gui/embedded/qscreenintegrityfb_qws.cpp new file mode 100644 index 0000000..7b24490 --- /dev/null +++ b/src/gui/embedded/qscreenintegrityfb_qws.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** 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 QT_NO_QWS_INTEGRITYFB + +#include <qscreenintegrityfb_qws.h> +#include <qwindowsystem_qws.h> +#include <qsocketnotifier.h> +#include <qapplication.h> +#include <qscreen_qws.h> +#include "qmouseintegrity_qws.h" +#include "qkbdintegrity_qws.h" +#include <qmousedriverfactory_qws.h> +#include <qkbddriverfactory_qws.h> +#include <qdebug.h> + +#include <INTEGRITY.h> +#include <device/fbdriver.h> + +QT_BEGIN_NAMESPACE + +class QIntfbScreenPrivate +{ +public: + QIntfbScreenPrivate(); + ~QIntfbScreenPrivate(); + + FBHandle handle; + struct FBInfoStruct fbinfo; + + QWSMouseHandler *mouse; +#ifndef QT_NO_QWS_KEYBOARD + QWSKeyboardHandler *keyboard; +#endif +}; + +QIntfbScreenPrivate::QIntfbScreenPrivate() + : mouse(0) + +{ +#ifndef QT_NO_QWS_KEYBOARD + keyboard = 0; +#endif +} + +QIntfbScreenPrivate::~QIntfbScreenPrivate() +{ + delete mouse; +#ifndef QT_NO_QWS_KEYBOARD + delete keyboard; +#endif +} + +/*! + \internal + + \class QIntfbScreen + \ingroup qws + + \brief The QIntfbScreen class implements a screen driver for the + INTEGRITY framebuffer drivers. + + Note that this class is only available in \l{Qt for INTEGRITY}. + Custom screen drivers can be added by subclassing the + QScreenDriverPlugin class, using the QScreenDriverFactory class to + dynamically load the driver into the application, but there should + only be one screen object per application. + + \sa QScreen, QScreenDriverPlugin, {Running Applications} +*/ + +/*! + \fn bool QIntfbScreen::connect(const QString & displaySpec) + \reimp +*/ + +/*! + \fn void QIntfbScreen::disconnect() + \reimp +*/ + +/*! + \fn bool QIntfbScreen::initDevice() + \reimp +*/ + +/*! + \fn void QIntfbScreen::restore() + \reimp +*/ + +/*! + \fn void QIntfbScreen::save() + \reimp +*/ + +/*! + \fn void QIntfbScreen::setDirty(const QRect & r) + \reimp +*/ + +/*! + \fn void QIntfbScreen::setMode(int nw, int nh, int nd) + \reimp +*/ + +/*! + \fn void QIntfbScreen::shutdownDevice() + \reimp +*/ + +/*! + \fn QIntfbScreen::QIntfbScreen(int displayId) + + Constructs a QVNCScreen object. The \a displayId argument + identifies the Qt for Embedded Linux server to connect to. +*/ +QIntfbScreen::QIntfbScreen(int display_id) + : QScreen(display_id, IntfbClass), d_ptr(new QIntfbScreenPrivate) +{ + d_ptr->handle = 0; + data = 0; +} + +/*! + Destroys this QIntfbScreen object. +*/ +QIntfbScreen::~QIntfbScreen() +{ + delete d_ptr; +} + +static QIntfbScreen *connected = 0; + +bool QIntfbScreen::connect(const QString &displaySpec) +{ + FBDriver *fbdev; + + CheckSuccess(gh_FB_get_driver(0, &fbdev)); + CheckSuccess(gh_FB_init_device(fbdev, 0, &d_ptr->handle)); + CheckSuccess(gh_FB_get_info(d_ptr->handle, &d_ptr->fbinfo)); + + data = (uchar *)d_ptr->fbinfo.start; + + d = d_ptr->fbinfo.bitsperpixel; + switch (d) { + case 1: + setPixelFormat(QImage::Format_Mono); + break; + case 8: + setPixelFormat(QImage::Format_Indexed8); + break; + case 12: + setPixelFormat(QImage::Format_RGB444); + break; + case 15: + setPixelFormat(QImage::Format_RGB555); + break; + case 16: + setPixelFormat(QImage::Format_RGB16); + break; + case 18: + setPixelFormat(QImage::Format_RGB666); + break; + case 24: + setPixelFormat(QImage::Format_RGB888); +#ifdef QT_QWS_DEPTH_GENERIC +#if Q_BYTE_ORDER != Q_BIG_ENDIAN + qt_set_generic_blit(this, 24, + d_ptr->fbinfo.redbits, + d_ptr->fbinfo.greenbits, + d_ptr->fbinfo.bluebits, + d_ptr->fbinfo.alphabits, + d_ptr->fbinfo.redoffset, + d_ptr->fbinfo.greenoffset, + d_ptr->fbinfo.blueoffset, + d_ptr->fbinfo.alphaoffset); +#else + qt_set_generic_blit(this, 24, + d_ptr->fbinfo.redbits, + d_ptr->fbinfo.greenbits, + d_ptr->fbinfo.bluebits, + d_ptr->fbinfo.alphabits, + 16 - d_ptr->fbinfo.redoffset, + 16 - d_ptr->fbinfo.greenoffset, + 16 - d_ptr->fbinfo.blueoffset, + d_ptr->fbinfo.alphaoffset); +#endif +#endif + break; + case 32: + setPixelFormat(QImage::Format_ARGB32_Premultiplied); +#ifdef QT_QWS_DEPTH_GENERIC +#if Q_BYTE_ORDER != Q_BIG_ENDIAN + qt_set_generic_blit(this, 32, + d_ptr->fbinfo.redbits, + d_ptr->fbinfo.greenbits, + d_ptr->fbinfo.bluebits, + d_ptr->fbinfo.alphabits, + d_ptr->fbinfo.redoffset, + d_ptr->fbinfo.greenoffset, + d_ptr->fbinfo.blueoffset, + d_ptr->fbinfo.alphaoffset); +#else + qt_set_generic_blit(this, 32, + d_ptr->fbinfo.redbits, + d_ptr->fbinfo.greenbits, + d_ptr->fbinfo.bluebits, + d_ptr->fbinfo.alphabits, + 24 - d_ptr->fbinfo.redoffset, + 24 - d_ptr->fbinfo.greenoffset, + 24 - d_ptr->fbinfo.blueoffset, + d_ptr->fbinfo.alphaoffset ? 24 - d_ptr->fbinfo.alphaoffset : 0); +#endif +#endif + break; + } + + dw = w = d_ptr->fbinfo.width; + dh = h = d_ptr->fbinfo.height; + + /* assumes no padding */ + lstep = w * ((d + 7) >> 3); + + mapsize = size = h * lstep; + + /* default values */ + int dpi = 72; + physWidth = qRound(dw * 25.4 / dpi); + physHeight = qRound(dh * 25.4 / dpi); + + qDebug("Connected to INTEGRITYfb server: %d x %d x %d %dx%dmm (%dx%ddpi)", + w, h, d, physWidth, physHeight, qRound(dw*25.4/physWidth), qRound(dh*25.4/physHeight) ); + + + QWSServer::setDefaultMouse("integrity"); + QWSServer::setDefaultKeyboard("integrity"); + + connected = this; + + return true; +} + +void QIntfbScreen::disconnect() +{ + connected = 0; +} + +bool QIntfbScreen::initDevice() +{ + + CheckSuccess(gh_FB_set_info(d_ptr->handle, &d_ptr->fbinfo, false)); + CheckSuccess(gh_FB_get_info(d_ptr->handle, &d_ptr->fbinfo)); + data = (uchar *)d_ptr->fbinfo.start; + d = d_ptr->fbinfo.bitsperpixel; + dw = w = d_ptr->fbinfo.width; + dh = h = d_ptr->fbinfo.height; + mapsize = d_ptr->fbinfo.length; + /* assumes no padding */ + lstep = w * ((d + 7) >> 3); + + mapsize = size = h * lstep; + + data = (uchar *)d_ptr->fbinfo.start; + + d = d_ptr->fbinfo.bitsperpixel; + switch (d) { + case 1: + setPixelFormat(QImage::Format_Mono); + break; + case 8: + setPixelFormat(QImage::Format_Indexed8); + break; + case 12: + setPixelFormat(QImage::Format_RGB444); + break; + case 15: + setPixelFormat(QImage::Format_RGB555); + break; + case 16: + setPixelFormat(QImage::Format_RGB16); + break; + case 18: + setPixelFormat(QImage::Format_RGB666); + break; + case 24: + setPixelFormat(QImage::Format_RGB888); + break; + case 32: + setPixelFormat(QImage::Format_ARGB32_Premultiplied); + break; + } +#ifdef QT_QWS_DEPTH_GENERIC +#if defined(__BIG_ENDIAN__) + qt_set_generic_blit(this, d, + d_ptr->fbinfo.redbits, + d_ptr->fbinfo.greenbits, + d_ptr->fbinfo.bluebits, + d_ptr->fbinfo.alphabits, + 24 - d_ptr->fbinfo.redoffset, + 24 - d_ptr->fbinfo.greenoffset, + 24 - d_ptr->fbinfo.blueoffset, + d_ptr->fbinfo.alphaoffset ? 24 - d_ptr->fbinfo.alphaoffset : 0); +#else + qt_set_generic_blit(this, d, + d_ptr->fbinfo.redbits, + d_ptr->fbinfo.greenbits, + d_ptr->fbinfo.bluebits, + d_ptr->fbinfo.alphabits, + d_ptr->fbinfo.redoffset, + d_ptr->fbinfo.greenoffset, + d_ptr->fbinfo.blueoffset, + d_ptr->fbinfo.alphaoffset); +#endif +#endif + +#ifndef QT_NO_QWS_CURSOR + QScreenCursor::initSoftwareCursor(); +#endif + return true; +} + +void QIntfbScreen::shutdownDevice() +{ + gh_FB_close(d_ptr->handle); +} + +void QIntfbScreen::setMode(int ,int ,int) +{ +} + +// save the state of the graphics card +// This is needed so that e.g. we can restore the palette when switching +// between linux virtual consoles. +void QIntfbScreen::save() +{ + // nothing to do. +} + +// restore the state of the graphics card. +void QIntfbScreen::restore() +{ +} +void QIntfbScreen::setDirty(const QRect& rect) +{ + FBRect fbrect; + fbrect.dx = rect.x(); + fbrect.dy = rect.y(); + fbrect.width = rect.width(); + fbrect.height = rect.height(); + gh_FB_expose(d_ptr->handle, &fbrect); +} + +void QIntfbScreen::setBrightness(int b) +{ + if (connected) { + } +} + +void QIntfbScreen::blank(bool on) +{ +} + +#endif // QT_NO_QWS_INTEGRITYFB + +QT_END_NAMESPACE + diff --git a/src/gui/embedded/qscreenintegrityfb_qws.h b/src/gui/embedded/qscreenintegrityfb_qws.h new file mode 100644 index 0000000..06b3967 --- /dev/null +++ b/src/gui/embedded/qscreenintegrityfb_qws.h @@ -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 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 QSCREENINTEGRITYFB_QWS_H +#define QSCREENINTEGRITYFB_QWS_H + +#include <QtGui/qscreen_qws.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_QWS_INTEGRITYFB + +class QIntfbScreenPrivate; + +class Q_GUI_EXPORT QIntfbScreen : public QScreen +{ +public: + explicit QIntfbScreen(int display_id); + virtual ~QIntfbScreen(); + virtual bool initDevice(); + virtual bool connect(const QString &displaySpec); + virtual void disconnect(); + virtual void shutdownDevice(); + virtual void save(); + virtual void restore(); + virtual void setMode(int nw,int nh,int nd); + virtual void setDirty(const QRect& r); + virtual void blank(bool); + static void setBrightness(int b); + +private: + QIntfbScreenPrivate *d_ptr; +}; + +#endif // QT_NO_QWS_INTEGRITYFB + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSCREENINTEGRITYFB_QWS_H diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index 92ea397..a5e37f3 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -29,7 +29,9 @@ HEADERS += \ image/qpixmapdata_p.h \ image/qpixmapdatafactory_p.h \ image/qpixmapfilter_p.h \ - image/qimagepixmapcleanuphooks_p.h + image/qimagepixmapcleanuphooks_p.h \ + image/qvolatileimage_p.h \ + image/qvolatileimagedata_p.h SOURCES += \ image/qbitmap.cpp \ @@ -53,7 +55,8 @@ SOURCES += \ image/qpixmap_raster.cpp \ image/qpixmap_blitter.cpp \ image/qnativeimage.cpp \ - image/qimagepixmapcleanuphooks.cpp + image/qimagepixmapcleanuphooks.cpp \ + image/qvolatileimage.cpp win32 { SOURCES += image/qpixmap_win.cpp @@ -77,6 +80,13 @@ else:symbian { SOURCES += image/qpixmap_s60.cpp } +!symbian|contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2) { + SOURCES += image/qvolatileimagedata.cpp +} +else { + SOURCES += image/qvolatileimagedata_symbian.cpp +} + # Built-in image format support HEADERS += \ image/qbmphandler_p.h \ diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h index 5c05c28..db5ff4a 100644 --- a/src/gui/image/qpixmapdata_p.h +++ b/src/gui/image/qpixmapdata_p.h @@ -71,7 +71,8 @@ public: #if defined(Q_OS_SYMBIAN) enum NativeType { FbsBitmap, - SgImage + SgImage, + VolatileImage }; #endif enum ClassId { RasterClass, X11Class, MacClass, DirectFBClass, diff --git a/src/gui/image/qvolatileimage.cpp b/src/gui/image/qvolatileimage.cpp new file mode 100644 index 0000000..098e9a1 --- /dev/null +++ b/src/gui/image/qvolatileimage.cpp @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvolatileimage_p.h" +#include "qvolatileimagedata_p.h" +#include <QtGui/private/qpaintengine_raster_p.h> +#include <QtGui/private/qpixmapdata_p.h> + +QT_BEGIN_NAMESPACE + +class QVolatileImagePaintEnginePrivate : public QRasterPaintEnginePrivate +{ +public: + QVolatileImagePaintEnginePrivate() { } + QVolatileImage *img; +}; + +class QVolatileImagePaintEngine : public QRasterPaintEngine +{ + Q_DECLARE_PRIVATE(QVolatileImagePaintEngine) + +public: + QVolatileImagePaintEngine(QPaintDevice *device, QVolatileImage *img); + bool begin(QPaintDevice *device); + bool end(); + void drawPixmap(const QPointF &p, const QPixmap &pm); + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); +}; + +QVolatileImage::QVolatileImage() + : d(new QVolatileImageData) +{ +} + +QVolatileImage::QVolatileImage(int w, int h, QImage::Format format) + : d(new QVolatileImageData(w, h, format)) +{ +} + +QVolatileImage::QVolatileImage(const QImage &sourceImage) + : d(new QVolatileImageData(sourceImage)) +{ +} + +QVolatileImage::QVolatileImage(void *nativeImage, void *nativeMask) + : d(new QVolatileImageData(nativeImage, nativeMask)) +{ +} + +// Need non-inline, non-autogenerated copy ctor, dtor, op= to keep the +// fwd declared QSharedData working. + +QVolatileImage::QVolatileImage(const QVolatileImage &other) + : d(other.d) +{ +} + +QVolatileImage::~QVolatileImage() +{ +} + +QVolatileImage &QVolatileImage::operator=(const QVolatileImage &rhs) +{ + d = rhs.d; + return *this; +} + +bool QVolatileImage::isNull() const +{ + return d->image.isNull(); +} + +QImage::Format QVolatileImage::format() const +{ + return d->image.format(); +} + +int QVolatileImage::width() const +{ + return d->image.width(); +} + +int QVolatileImage::height() const +{ + return d->image.height(); +} + +int QVolatileImage::bytesPerLine() const +{ + return d->image.bytesPerLine(); +} + +int QVolatileImage::byteCount() const +{ + return d->image.byteCount(); +} + +int QVolatileImage::depth() const +{ + return d->image.depth(); +} + +bool QVolatileImage::hasAlphaChannel() const +{ + return d->image.hasAlphaChannel(); +} + +void QVolatileImage::beginDataAccess() const +{ + d->beginDataAccess(); +} + +void QVolatileImage::endDataAccess(bool readOnly) const +{ + d->endDataAccess(readOnly); +} + +/*! + Access to pixel data via bits() or constBits() should be guarded by + begin/endDataAccess(). + */ +uchar *QVolatileImage::bits() +{ + return d->image.bits(); +} + +const uchar *QVolatileImage::constBits() const +{ + return d->image.constBits(); +} + +bool QVolatileImage::ensureFormat(QImage::Format format) +{ + return d->ensureFormat(format); +} + +/*! + This will always perform a copy of the pixel data. + */ +QImage QVolatileImage::toImage() const +{ + d->beginDataAccess(); + QImage newImage = d->image.copy(); // no sharing allowed + d->endDataAccess(true); + return newImage; +} + +/*! + Returns a reference to the image that is potentially using some native + buffer internally. Access to the image's pixel data should be guarded by + begin/endDataAccess(). Use it when there is a need for QImage APIs not provided + by this class. The returned QImage must never be shared or assigned to. + */ +QImage &QVolatileImage::imageRef() // non-const, in order to cause a detach +{ + d->ensureImage(); + return d->image; +} + +void *QVolatileImage::duplicateNativeImage() const +{ + return d->duplicateNativeImage(); +} + +void QVolatileImage::setAlphaChannel(const QPixmap &alphaChannel) +{ + ensureFormat(QImage::Format_ARGB32_Premultiplied); + beginDataAccess(); + imageRef().setAlphaChannel(alphaChannel.toImage()); + endDataAccess(); + d->ensureImage(); +} + +void QVolatileImage::fill(uint pixelValue) +{ + beginDataAccess(); + imageRef().fill(pixelValue); + endDataAccess(); + d->ensureImage(); +} + +void QVolatileImage::copyFrom(QVolatileImage *source, const QRect &rect) +{ + if (source->isNull()) { + return; + } + QRect r = rect; + if (rect.isNull()) { + r = QRect(0, 0, source->width(), source->height()); + } + source->beginDataAccess(); + QImage &srcImgRef(source->imageRef()); + int srcbpl = srcImgRef.bytesPerLine(); + int srcbpp = srcImgRef.depth() / 8; + const uchar *sptr = srcImgRef.constBits() + r.y() * srcbpl; + beginDataAccess(); + QImage &dstImgRef(imageRef()); + int dstbpl = dstImgRef.bytesPerLine(); + uchar *dptr = dstImgRef.bits(); + for (int y = 0; y < r.height(); ++y) { + qMemCopy(dptr, sptr + r.x() * srcbpp, r.width() * srcbpp); + sptr += srcbpl; + dptr += dstbpl; + } + endDataAccess(); + source->endDataAccess(true); +} + +/*! + To be called from the PixmapData's paintEngine(). + */ +QPaintEngine *QVolatileImage::paintEngine() +{ + if (!d->pengine) { + d->pengine = new QVolatileImagePaintEngine(&imageRef(), this); + } + return d->pengine; +} + +QVolatileImagePaintEngine::QVolatileImagePaintEngine(QPaintDevice *device, + QVolatileImage *img) + : QRasterPaintEngine(*(new QVolatileImagePaintEnginePrivate), device) +{ + Q_D(QVolatileImagePaintEngine); + d->img = img; +} + +bool QVolatileImagePaintEngine::begin(QPaintDevice *device) +{ + Q_D(QVolatileImagePaintEngine); + d->img->beginDataAccess(); + return QRasterPaintEngine::begin(device); +} + +bool QVolatileImagePaintEngine::end() +{ + Q_D(QVolatileImagePaintEngine); + bool ret = QRasterPaintEngine::end(); + d->img->endDataAccess(); + return ret; +} + +// For non-RasterClass pixmaps drawPixmap() would call toImage() which is slow in +// our case. Therefore drawPixmap() is rerouted to drawImage(). + +void QVolatileImagePaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm) +{ +#ifdef Q_OS_SYMBIAN + void *nativeData = pm.pixmapData()->toNativeType(QPixmapData::VolatileImage); + if (nativeData) { + QVolatileImage *img = static_cast<QVolatileImage *>(nativeData); + img->beginDataAccess(); + QRasterPaintEngine::drawImage(p, img->imageRef()); + img->endDataAccess(true); + } else { + QRasterPaintEngine::drawPixmap(p, pm); + } +#else + QRasterPaintEngine::drawPixmap(p, pm); +#endif +} + +void QVolatileImagePaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) +{ +#ifdef Q_OS_SYMBIAN + void *nativeData = pm.pixmapData()->toNativeType(QPixmapData::VolatileImage); + if (nativeData) { + QVolatileImage *img = static_cast<QVolatileImage *>(nativeData); + img->beginDataAccess(); + QRasterPaintEngine::drawImage(r, img->imageRef(), sr); + img->endDataAccess(true); + } else { + QRasterPaintEngine::drawPixmap(r, pm, sr); + } +#else + QRasterPaintEngine::drawPixmap(r, pm, sr); +#endif +} + +QT_END_NAMESPACE diff --git a/src/gui/image/qvolatileimage_p.h b/src/gui/image/qvolatileimage_p.h new file mode 100644 index 0000000..fc5d6b1 --- /dev/null +++ b/src/gui/image/qvolatileimage_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVOLATILEIMAGE_P_H +#define QVOLATILEIMAGE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/qimage.h> +#include <QtCore/qshareddata.h> + +QT_BEGIN_NAMESPACE + +class QVolatileImageData; + +class Q_GUI_EXPORT QVolatileImage +{ +public: + QVolatileImage(); + QVolatileImage(int w, int h, QImage::Format format); + explicit QVolatileImage(const QImage &sourceImage); + explicit QVolatileImage(void *nativeImage, void *nativeMask = 0); + QVolatileImage(const QVolatileImage &other); + ~QVolatileImage(); + QVolatileImage &operator=(const QVolatileImage &rhs); + + bool isNull() const; + QImage::Format format() const; + int width() const; + int height() const; + int bytesPerLine() const; + int byteCount() const; + int depth() const; + bool hasAlphaChannel() const; + void beginDataAccess() const; + void endDataAccess(bool readOnly = false) const; + uchar *bits(); + const uchar *constBits() const; + bool ensureFormat(QImage::Format format); + QImage toImage() const; + QImage &imageRef(); + QPaintEngine *paintEngine(); + void setAlphaChannel(const QPixmap &alphaChannel); + void fill(uint pixelValue); + void *duplicateNativeImage() const; + void copyFrom(QVolatileImage *source, const QRect &rect); + +private: + QSharedDataPointer<QVolatileImageData> d; +}; + +QT_END_NAMESPACE + +#endif // QVOLATILEIMAGE_P_H diff --git a/src/gui/image/qvolatileimagedata.cpp b/src/gui/image/qvolatileimagedata.cpp new file mode 100644 index 0000000..51b5995 --- /dev/null +++ b/src/gui/image/qvolatileimagedata.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvolatileimagedata_p.h" +#include <QtGui/qpaintengine.h> + +QT_BEGIN_NAMESPACE + +QVolatileImageData::QVolatileImageData() + : pengine(0) +{ +} + +QVolatileImageData::QVolatileImageData(int w, int h, QImage::Format format) + : pengine(0) +{ + image = QImage(w, h, format); +} + +QVolatileImageData::QVolatileImageData(const QImage &sourceImage) + : pengine(0) +{ + image = sourceImage; +} + +QVolatileImageData::QVolatileImageData(void *, void *) + : pengine(0) +{ + // Not supported. +} + +QVolatileImageData::QVolatileImageData(const QVolatileImageData &other) +{ + image = other.image; + // The detach is not mandatory here but we do it nonetheless in order to + // keep the behavior consistent with other platforms. + image.detach(); + pengine = 0; +} + +QVolatileImageData::~QVolatileImageData() +{ + delete pengine; +} + +void QVolatileImageData::beginDataAccess() const +{ + // nothing to do here +} + +void QVolatileImageData::endDataAccess(bool readOnly) const +{ + Q_UNUSED(readOnly); + // nothing to do here +} + +bool QVolatileImageData::ensureFormat(QImage::Format format) +{ + if (image.format() != format) { + image = image.convertToFormat(format); + } + return true; +} + +void *QVolatileImageData::duplicateNativeImage() const +{ + return 0; +} + +void QVolatileImageData::ensureImage() +{ + // nothing to do here +} + +QT_END_NAMESPACE diff --git a/src/gui/image/qvolatileimagedata_p.h b/src/gui/image/qvolatileimagedata_p.h new file mode 100644 index 0000000..dab1685 --- /dev/null +++ b/src/gui/image/qvolatileimagedata_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVOLATILEIMAGEDATA_P_H +#define QVOLATILEIMAGEDATA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/qimage.h> +#include <QtCore/qshareddata.h> + +#ifdef Q_OS_SYMBIAN +class CFbsBitmap; +#endif + +QT_BEGIN_NAMESPACE + +class QVolatileImageData : public QSharedData +{ +public: + QVolatileImageData(); + QVolatileImageData(int w, int h, QImage::Format format); + QVolatileImageData(const QImage &sourceImage); + QVolatileImageData(void *nativeImage, void *nativeMask); + QVolatileImageData(const QVolatileImageData &other); + ~QVolatileImageData(); + + void beginDataAccess() const; + void endDataAccess(bool readOnly = false) const; + bool ensureFormat(QImage::Format format); + void *duplicateNativeImage() const; + void ensureImage(); + +#ifdef Q_OS_SYMBIAN + void updateImage(); + void initWithBitmap(CFbsBitmap *source); + void applyMask(CFbsBitmap *mask); + void ensureBitmap(); + void release(); + QVolatileImageData *next; + QVolatileImageData *prev; + CFbsBitmap *bitmap; +#endif + QImage image; + QPaintEngine *pengine; +}; + +QT_END_NAMESPACE + +#endif // QVOLATILEIMAGEDATA_P_H diff --git a/src/gui/image/qvolatileimagedata_symbian.cpp b/src/gui/image/qvolatileimagedata_symbian.cpp new file mode 100644 index 0000000..474d0ef --- /dev/null +++ b/src/gui/image/qvolatileimagedata_symbian.cpp @@ -0,0 +1,471 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvolatileimagedata_p.h" +#include <fbs.h> +#include <QtGui/private/qt_s60_p.h> +#include <QtGui/qpaintengine.h> +#include <QtGui/private/qimage_p.h> + +QT_BEGIN_NAMESPACE + +static CFbsBitmap *rasterizeBitmap(CFbsBitmap *bitmap, TDisplayMode newMode) +{ + if (!bitmap) { + return 0; + } + QScopedPointer<CFbsBitmap> newBitmap(new CFbsBitmap); + if (newBitmap->Create(bitmap->SizeInPixels(), newMode) != KErrNone) { + qWarning("QVolatileImage: Failed to create new bitmap"); + return 0; + } + CFbsBitmapDevice *bitmapDevice = 0; + CFbsBitGc *bitmapGc = 0; + QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(newBitmap.data())); + QScopedPointer<CFbsBitmapDevice> bitmapDevicePtr(bitmapDevice); + QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); + bitmapGc->Activate(bitmapDevice); + bitmapGc->BitBlt(TPoint(), bitmap); + delete bitmapGc; + return newBitmap.take(); +} + +static inline TDisplayMode format2TDisplayMode(QImage::Format format) +{ + TDisplayMode mode; + switch (format) { + case QImage::Format_MonoLSB: + mode = EGray2; + break; + case QImage::Format_Indexed8: + mode = EColor256; + break; + case QImage::Format_RGB444: + mode = EColor4K; + break; + case QImage::Format_RGB16: + mode = EColor64K; + break; + case QImage::Format_RGB888: + mode = EColor16M; + break; + case QImage::Format_RGB32: + mode = EColor16MU; + break; + case QImage::Format_ARGB32: + mode = EColor16MA; + break; + case QImage::Format_ARGB32_Premultiplied: + mode = Q_SYMBIAN_ECOLOR16MAP; + break; + default: + mode = ENone; + break; + } + return mode; +} + +static CFbsBitmap *imageToBitmap(const QImage &image) +{ + if (image.isNull()) { + return 0; + } + CFbsBitmap *bitmap = new CFbsBitmap; + if (bitmap->Create(TSize(image.width(), image.height()), + format2TDisplayMode(image.format())) == KErrNone) { + bitmap->BeginDataAccess(); + uchar *dptr = reinterpret_cast<uchar *>(bitmap->DataAddress()); + int bmpLineLen = bitmap->DataStride(); + int imgLineLen = image.bytesPerLine(); + if (bmpLineLen == imgLineLen) { + qMemCopy(dptr, image.constBits(), image.byteCount()); + } else { + int len = qMin(bmpLineLen, imgLineLen); + const uchar *sptr = image.constBits(); + for (int y = 0; y < image.height(); ++y) { + qMemCopy(dptr, sptr, len); + dptr += bmpLineLen; + sptr += imgLineLen; + } + } + bitmap->EndDataAccess(); + } else { + qWarning("QVolatileImage: Failed to create source bitmap"); + delete bitmap; + bitmap = 0; + } + return bitmap; +} + +static CFbsBitmap *copyData(const QVolatileImageData &source) +{ + source.beginDataAccess(); + CFbsBitmap *bmp = imageToBitmap(source.image); + source.endDataAccess(); + return bmp; +} + +static CFbsBitmap *convertData(const QVolatileImageData &source, QImage::Format newFormat) +{ + source.beginDataAccess(); + QImage img = source.image.convertToFormat(newFormat); + CFbsBitmap *bmp = imageToBitmap(img); + source.endDataAccess(); + return bmp; +} + +static CFbsBitmap *duplicateBitmap(const CFbsBitmap &sourceBitmap) +{ + CFbsBitmap *bitmap = new CFbsBitmap; + if (bitmap->Duplicate(sourceBitmap.Handle()) != KErrNone) { + qWarning("QVolatileImage: Failed to duplicate source bitmap"); + delete bitmap; + bitmap = 0; + } + return bitmap; +} + +static CFbsBitmap *createBitmap(int w, int h, QImage::Format format) +{ + CFbsBitmap *bitmap = new CFbsBitmap; + if (bitmap->Create(TSize(w, h), format2TDisplayMode(format)) != KErrNone) { + qWarning("QVolatileImage: Failed to create source bitmap %d,%d (%d)", w, h, format); + delete bitmap; + bitmap = 0; + } + return bitmap; +} + +static inline bool bitmapNeedsCopy(CFbsBitmap *bitmap) +{ + bool needsCopy = bitmap->IsCompressedInRAM(); +#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE + needsCopy |= (bitmap->ExtendedBitmapType() != KNullUid); +#endif + return needsCopy; +} + +static bool cleanup_function_registered = false; +static QVolatileImageData *firstImageData = 0; + +static void cleanup() +{ + if (RFbsSession::GetSession()) { + QVolatileImageData *imageData = firstImageData; + while (imageData) { + imageData->release(); + imageData = imageData->next; + } + } +} + +static void ensureCleanup() +{ + // Destroy all underlying bitmaps in a post routine to prevent panics. + // This is a must because CFbsBitmap destructor needs the fbs session, + // that was used to create the bitmap, to be open still. + if (!cleanup_function_registered) { + qAddPostRoutine(cleanup); + cleanup_function_registered = true; + } +} + +static void registerImageData(QVolatileImageData *imageData) +{ + ensureCleanup(); + imageData->next = firstImageData; + if (firstImageData) { + firstImageData->prev = imageData; + } + firstImageData = imageData; +} + +static void unregisterImageData(QVolatileImageData *imageData) +{ + if (imageData->prev) { + imageData->prev->next = imageData->next; + } else { + firstImageData = imageData->next; + } + if (imageData->next) { + imageData->next->prev = imageData->prev; + } +} + +QVolatileImageData::QVolatileImageData() + : next(0), prev(0), bitmap(0), pengine(0) +{ + registerImageData(this); +} + +QVolatileImageData::QVolatileImageData(int w, int h, QImage::Format format) + : next(0), prev(0), bitmap(0), pengine(0) +{ + registerImageData(this); + bitmap = createBitmap(w, h, format); + updateImage(); +} + +QVolatileImageData::QVolatileImageData(const QImage &sourceImage) + : next(0), prev(0), bitmap(0), pengine(0) +{ + registerImageData(this); + image = sourceImage; + // The following is not mandatory, but we do it here to have a bitmap + // created always in order to reduce local heap usage. + ensureBitmap(); +} + +QVolatileImageData::QVolatileImageData(void *nativeImage, void *nativeMask) + : next(0), prev(0), bitmap(0), pengine(0) +{ + registerImageData(this); + if (nativeImage) { + CFbsBitmap *source = static_cast<CFbsBitmap *>(nativeImage); + CFbsBitmap *mask = static_cast<CFbsBitmap *>(nativeMask); + initWithBitmap(source); + if (mask) { + applyMask(mask); + } + } +} + +QVolatileImageData::QVolatileImageData(const QVolatileImageData &other) +{ + bitmap = 0; + pengine = 0; + next = prev = 0; + registerImageData(this); + if (!other.image.isNull()) { + bitmap = copyData(other); + updateImage(); + } +} + +QVolatileImageData::~QVolatileImageData() +{ + release(); + unregisterImageData(this); +} + +void QVolatileImageData::release() +{ + delete bitmap; + bitmap = 0; + delete pengine; + pengine = 0; +} + +void QVolatileImageData::beginDataAccess() const +{ + if (bitmap) { + bitmap->BeginDataAccess(); + } +} + +void QVolatileImageData::endDataAccess(bool readOnly) const +{ + if (bitmap) { + bitmap->EndDataAccess(readOnly); + } +} + +bool QVolatileImageData::ensureFormat(QImage::Format format) +{ + if (image.isNull()) { + return false; + } + if (image.format() != format) { + CFbsBitmap *newBitmap = convertData(*this, format); + if (newBitmap && newBitmap != bitmap) { + delete bitmap; + bitmap = newBitmap; + updateImage(); + } else { + return false; + } + } + return true; +} + +void *QVolatileImageData::duplicateNativeImage() const +{ + const_cast<QVolatileImageData *>(this)->ensureBitmap(); + if (bitmap) { + if (bitmap->DisplayMode() == EColor16M) { + // slow path: needs rgb swapping + beginDataAccess(); + QImage tmp = image.rgbSwapped(); + endDataAccess(true); + return imageToBitmap(tmp); + } else if (bitmap->DisplayMode() == EGray2) { + // slow path: needs inverting pixels + beginDataAccess(); + QImage tmp = image.copy(); + endDataAccess(true); + tmp.invertPixels(); + return imageToBitmap(tmp); + } else { + // fast path: just duplicate the bitmap + return duplicateBitmap(*bitmap); + } + } + return 0; +} + +void QVolatileImageData::updateImage() +{ + if (bitmap) { + TSize size = bitmap->SizeInPixels(); + beginDataAccess(); + // Use existing buffer, no copy. The data address never changes so it + // is enough to do this whenever we have a new CFbsBitmap. N.B. never + // use const uchar* here, that would create a read-only image data which + // would make a copy in detach() even when refcount is 1. + image = QImage(reinterpret_cast<uchar *>(bitmap->DataAddress()), + size.iWidth, size.iHeight, bitmap->DataStride(), + qt_TDisplayMode2Format(bitmap->DisplayMode())); + endDataAccess(true); + } else { + image = QImage(); + } +} + +void QVolatileImageData::initWithBitmap(CFbsBitmap *source) +{ + bool needsCopy = bitmapNeedsCopy(source); + if (source->DisplayMode() == EColor16M) { + // EColor16M is BGR + CFbsBitmap *unswappedBmp = source; + if (needsCopy) { + unswappedBmp = rasterizeBitmap(source, source->DisplayMode()); + } + unswappedBmp->BeginDataAccess(); + TSize sourceSize = unswappedBmp->SizeInPixels(); + QImage img((uchar *) unswappedBmp->DataAddress(), + sourceSize.iWidth, sourceSize.iHeight, unswappedBmp->DataStride(), + qt_TDisplayMode2Format(unswappedBmp->DisplayMode())); + img = img.rgbSwapped(); + unswappedBmp->EndDataAccess(true); + bitmap = imageToBitmap(img); + if (needsCopy) { + delete unswappedBmp; + } + } else if (needsCopy) { + // Rasterize extended and compressed bitmaps. + bitmap = rasterizeBitmap(source, EColor16MAP); + } else { + // Efficient path: no pixel data copying. Just duplicate. This of course + // means the original bitmap's data may get modified, but that's fine + // and is in accordance with the QPixmap::fromSymbianCFbsBitmap() docs. + bitmap = duplicateBitmap(*source); + } + updateImage(); + if (bitmap && bitmap->DisplayMode() == EGray2) { + // Symbian thinks set pixels are white/transparent, Qt thinks they are + // foreground/solid. Invert mono bitmaps so that masks work correctly. + beginDataAccess(); + image.invertPixels(); + endDataAccess(); + } +} + +void QVolatileImageData::applyMask(CFbsBitmap *mask) +{ + ensureFormat(QImage::Format_ARGB32_Premultiplied); + bool destroyMask = false; + if (bitmapNeedsCopy(mask)) { + mask = rasterizeBitmap(mask, EColor16MU); + if (!mask) { + return; + } + destroyMask = true; + } + mask->BeginDataAccess(); + TSize maskSize = mask->SizeInPixels(); + QImage maskImg((const uchar *) mask->DataAddress(), maskSize.iWidth, maskSize.iHeight, + mask->DataStride(), qt_TDisplayMode2Format(mask->DisplayMode())); + if (mask->DisplayMode() == EGray2) { + maskImg = maskImg.copy(); + maskImg.invertPixels(); + } + beginDataAccess(); + image.setAlphaChannel(maskImg); + endDataAccess(); + mask->EndDataAccess(true); + ensureImage(); + if (destroyMask) { + delete mask; + } +} + +void QVolatileImageData::ensureImage() +{ + if (bitmap && !image.isNull()) { + QImageData *imaged = image.data_ptr(); + if (imaged->ref != 1 || imaged->ro_data) { + // This is bad, the imagedata got shared somehow. Detach, in order to + // have the next check fail and thus have 'image' recreated. + beginDataAccess(); + image.detach(); + endDataAccess(true); + } + } + if (bitmap && image.constBits() != reinterpret_cast<const uchar *>(bitmap->DataAddress())) { + // Should not ever get here. If we do it means that either 'image' has + // been replaced with a copy (e.g. because some QImage API assigned a + // new, regular QImage to *this) or the bitmap's data address changed + // unexpectedly. + qWarning("QVolatileImageData: Ptr mismatch"); + // Recover by recreating the image so that it uses the bitmap as its buffer. + updateImage(); + } +} + +void QVolatileImageData::ensureBitmap() +{ + if (!bitmap && !image.isNull()) { + bitmap = imageToBitmap(image); + updateImage(); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index ffad75b..075d5da 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -864,7 +864,7 @@ static bool read_xpm_body( QByteArray buf(200, 0); int i; - if (cpp > 15) + if (cpp < 0 || cpp > 15) return false; // For > 256 colors, we delay creation of the image until diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index 3196ba5..eb56f56 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -227,7 +227,7 @@ public: void _q_sourceColumnsRemoved(const QModelIndex &source_parent, int start, int end); - void clear_mapping(); + void _q_clearMapping(); void sort(); bool update_source_sort_column(); @@ -281,7 +281,7 @@ typedef QHash<QModelIndex, QSortFilterProxyModelPrivate::Mapping *> IndexMap; void QSortFilterProxyModelPrivate::_q_sourceModelDestroyed() { QAbstractProxyModelPrivate::_q_sourceModelDestroyed(); - clear_mapping(); + _q_clearMapping(); } void QSortFilterProxyModelPrivate::remove_from_mapping(const QModelIndex &source_parent) @@ -293,7 +293,7 @@ void QSortFilterProxyModelPrivate::remove_from_mapping(const QModelIndex &source } } -void QSortFilterProxyModelPrivate::clear_mapping() +void QSortFilterProxyModelPrivate::_q_clearMapping() { // store the persistent indexes QModelIndexPairList source_indexes = store_persistent_indexes(); @@ -1225,7 +1225,7 @@ void QSortFilterProxyModelPrivate::_q_sourceReset() { Q_Q(QSortFilterProxyModel); invalidatePersistentIndexes(); - clear_mapping(); + _q_clearMapping(); // All internal structures are deleted in clear() q->endResetModel(); update_source_sort_column(); @@ -1521,6 +1521,7 @@ QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent) d->filter_column = 0; d->filter_role = Qt::DisplayRole; d->dynamic_sortfilter = false; + connect(this, SIGNAL(modelReset()), this, SLOT(_q_clearMapping())); } /*! @@ -1622,7 +1623,7 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset())); connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); - d->clear_mapping(); + d->_q_clearMapping(); endResetModel(); if (d->update_source_sort_column() && d->dynamic_sortfilter) d->sort(); @@ -2313,7 +2314,7 @@ void QSortFilterProxyModel::clear() { Q_D(QSortFilterProxyModel); emit layoutAboutToBeChanged(); - d->clear_mapping(); + d->_q_clearMapping(); emit layoutChanged(); } @@ -2328,7 +2329,7 @@ void QSortFilterProxyModel::invalidate() { Q_D(QSortFilterProxyModel); emit layoutAboutToBeChanged(); - d->clear_mapping(); + d->_q_clearMapping(); emit layoutChanged(); } diff --git a/src/gui/itemviews/qsortfilterproxymodel.h b/src/gui/itemviews/qsortfilterproxymodel.h index 09fd20f..afeaa69 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.h +++ b/src/gui/itemviews/qsortfilterproxymodel.h @@ -189,6 +189,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsInserted(const QModelIndex &source_parent, int start, int end)) Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end)) Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsRemoved(const QModelIndex &source_parent, int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_clearMapping()) }; QT_END_NAMESPACE diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index d03babb..21c9d3b 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -2744,6 +2744,7 @@ int QTreeView::indexRowSizeHint(const QModelIndex &index) const int start = -1; int end = -1; + int indexRow = index.row(); int count = d->header->count(); bool emptyHeader = (count == 0); QModelIndex parent = index.parent(); @@ -2780,7 +2781,7 @@ int QTreeView::indexRowSizeHint(const QModelIndex &index) const int logicalColumn = emptyHeader ? column : d->header->logicalIndex(column); if (d->header->isSectionHidden(logicalColumn)) continue; - QModelIndex idx = d->model->index(index.row(), logicalColumn, parent); + QModelIndex idx = d->model->index(indexRow, logicalColumn, parent); if (idx.isValid()) { QWidget *editor = d->editorForIndex(idx).widget.data(); if (editor && d->persistent.contains(editor)) { @@ -3215,14 +3216,14 @@ int QTreeViewPrivate::itemHeight(int item) const if (viewItems.isEmpty()) return 0; const QModelIndex &index = viewItems.at(item).index; + if (!index.isValid()) + return 0; int height = viewItems.at(item).height; - if (height <= 0 && index.isValid()) { + if (height <= 0) { height = q_func()->indexRowSizeHint(index); viewItems[item].height = height; } - if (!index.isValid() || height < 0) - return 0; - return height; + return qMax(height, 0); } diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp index f0801e3..642d3e6 100644 --- a/src/gui/kernel/qapplication_qws.cpp +++ b/src/gui/kernel/qapplication_qws.cpp @@ -204,6 +204,11 @@ QString qws_dataDir() result = QT_VFB_DATADIR(qws_display_id); QByteArray dataDir = result.toLocal8Bit(); +#if defined(Q_OS_INTEGRITY) + /* ensure filesystem is ready before starting requests */ + WaitForFileSystemInitialization(); +#endif + if (QT_MKDIR(dataDir, 0700)) { if (errno != EEXIST) { qFatal("Cannot create Qt for Embedded Linux data directory: %s", dataDir.constData()); diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 6e7b9a7..586869a 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -87,7 +87,7 @@ #include <hal.h> #include <hal_data.h> -#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS +#ifdef Q_SYMBIAN_TRANSITION_EFFECTS #include <graphics/wstfxconst.h> #endif @@ -432,7 +432,7 @@ void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop) DrawableWindow()->SetPointerGrab(ETrue); } -#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS +#ifdef Q_SYMBIAN_TRANSITION_EFFECTS if (OwnsWindow()) { TTfxWindowPurpose windowPurpose(ETfxPurposeNone); switch (qwidget->windowType()) { @@ -1588,7 +1588,7 @@ void qt_init(QApplicationPrivate * /* priv */, int) systemFont.setFamily(systemFont.defaultFamily()); QApplicationPrivate::setSystemFont(systemFont); -#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS +#ifdef Q_SYMBIAN_TRANSITION_EFFECTS QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit())); #endif @@ -1695,7 +1695,7 @@ bool QApplicationPrivate::modalState() void QApplicationPrivate::enterModal_sys(QWidget *widget) { -#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS +#ifdef Q_SYMBIAN_TRANSITION_EFFECTS S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeEnter); #endif if (widget) { @@ -1713,7 +1713,7 @@ void QApplicationPrivate::enterModal_sys(QWidget *widget) void QApplicationPrivate::leaveModal_sys(QWidget *widget) { -#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS +#ifdef Q_SYMBIAN_TRANSITION_EFFECTS S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeExit); #endif if (widget) { @@ -2401,7 +2401,7 @@ void QApplication::restoreOverrideCursor() void QApplicationPrivate::_q_aboutToQuit() { -#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS +#ifdef Q_SYMBIAN_TRANSITION_EFFECTS // Send the shutdown tfx command S60->wsSession().SendEffectCommand(ETfxCmdAppShutDown); #endif diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h index 1c9258a..c4b74c6 100644 --- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h +++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h @@ -88,6 +88,8 @@ QT_END_NAMESPACE QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)]; if (!widget) return NO; // This should happen only for qt_root_win + if (QApplicationPrivate::isBlockedByModal(widget)) + return NO; bool isToolTip = (widget->windowType() == Qt::ToolTip); bool isPopup = (widget->windowType() == Qt::Popup); @@ -99,6 +101,8 @@ QT_END_NAMESPACE QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)]; if (!widget) return NO; // This should happen only for qt_root_win + if ([self isSheet]) + return NO; bool isToolTip = (widget->windowType() == Qt::ToolTip); bool isPopup = (widget->windowType() == Qt::Popup); diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 3d87a9e..ff2dfe7 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -797,7 +797,7 @@ static int qCocoaViewCount = 0; - (BOOL)resignFirstResponder { if (!qwidget) - return NO; + return YES; // Seems like the following test only triggers if this // view is inside a QMacNativeWidget: diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index c8132e8..98f62ca 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -1627,6 +1627,7 @@ void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayI #ifdef QT_MAC_USE_COCOA void qt_mac_menu_collapseSeparators(void */*NSMenu **/ theMenu, bool collapse) { + QMacCocoaAutoReleasePool pool; OSMenuRef menu = static_cast<OSMenuRef>(theMenu); if (collapse) { bool previousIsSeparator = true; // setting to true kills all the separators placed at the top. diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index b378b78..4bff5ac 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -1496,7 +1496,7 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset) || !QX11Info::appDefaultColormap(xinfo.screen())) { // unknown DE or non-default visual/colormap, use 1bpp bitmap if (!forceReset || !topData->iconPixmap) - topData->iconPixmap = new QBitmap(qt_toX11Pixmap(icon.pixmap(QSize(64,64)))); + topData->iconPixmap = new QPixmap(qt_toX11Pixmap(QBitmap(icon.pixmap(QSize(64,64))))); pixmap_handle = topData->iconPixmap->handle(); } else { // default depth, use a normal pixmap (even though this diff --git a/src/gui/math3d/qgenericmatrix.h b/src/gui/math3d/qgenericmatrix.h index d9aef20..181eda8 100644 --- a/src/gui/math3d/qgenericmatrix.h +++ b/src/gui/math3d/qgenericmatrix.h @@ -79,9 +79,9 @@ public: void copyDataTo(T *values) const; - T *data() { return m[0]; } - const T *data() const { return m[0]; } - const T *constData() const { return m[0]; } + T *data() { return *m; } + const T *data() const { return *m; } + const T *constData() const { return *m; } #if !defined(Q_NO_TEMPLATE_FRIENDS) template<int NN, int MM, typename TT> diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h index 706450a..ad05116 100644 --- a/src/gui/math3d/qmatrix4x4.h +++ b/src/gui/math3d/qmatrix4x4.h @@ -173,8 +173,8 @@ public: QGenericMatrix<N, M, qreal> toGenericMatrix() const; inline qreal *data(); - inline const qreal *data() const { return m[0]; } - inline const qreal *constData() const { return m[0]; } + inline const qreal *data() const { return *m; } + inline const qreal *constData() const { return *m; } void optimize(); @@ -974,7 +974,7 @@ inline qreal *QMatrix4x4::data() // We have to assume that the caller will modify the matrix elements, // so we flip it over to "General" mode. flagBits = General; - return m[0]; + return *m; } #ifndef QT_NO_DEBUG_STREAM diff --git a/src/gui/painting/qbackingstore_p.h b/src/gui/painting/qbackingstore_p.h index e2b21c3..47387ab 100644 --- a/src/gui/painting/qbackingstore_p.h +++ b/src/gui/painting/qbackingstore_p.h @@ -209,8 +209,9 @@ private: { #ifdef Q_WS_QWS return tlw->frameGeometry(); -#endif +#else return tlw->data->crect; +#endif } inline void appendDirtyOnScreenWidget(QWidget *widget) diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index dc90003..10674f8 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -309,7 +309,7 @@ template <typename T> void qt_blend_argb24_on_rgb16(uchar *destPixels, int dbpl, const uchar *src = srcPixels + y * sbpl; const uchar *srcEnd = src + srcOffset; while (src < srcEnd) { -#if defined(QT_ARCH_ARMV5) || defined(QT_ARCH_POWERPC) || defined(QT_ARCH_SH) || defined(QT_ARCH_AVR32) || (defined(QT_ARCH_WINDOWSCE) && !defined(_X86_)) || (defined(QT_ARCH_SPARC) && defined(Q_CC_GNU)) +#if defined(QT_ARCH_ARMV5) || defined(QT_ARCH_POWERPC) || defined(QT_ARCH_SH) || defined(QT_ARCH_AVR32) || (defined(QT_ARCH_WINDOWSCE) && !defined(_X86_)) || (defined(QT_ARCH_SPARC) && defined(Q_CC_GNU)) || (defined(QT_ARCH_INTEGRITY) && !defined(_X86_)) // non-16-bit aligned memory access is not possible on PowerPC, // ARM <v6 (QT_ARCH_ARMV5) & SH & AVR32 & SPARC w/GCC quint16 spix = (quint16(src[2])<<8) + src[1]; diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp index 8d39b59..171ef46 100644 --- a/src/gui/painting/qgraphicssystem.cpp +++ b/src/gui/painting/qgraphicssystem.cpp @@ -89,4 +89,9 @@ QPixmapData *QGraphicsSystem::createPixmapData(QPixmapData *origin) return createPixmapData(origin->pixelType()); } +void QGraphicsSystem::releaseCachedResources() +{ + // Do nothing here +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qgraphicssystem_p.h b/src/gui/painting/qgraphicssystem_p.h index 1aa3aa0..0f99a31 100644 --- a/src/gui/painting/qgraphicssystem_p.h +++ b/src/gui/painting/qgraphicssystem_p.h @@ -76,6 +76,8 @@ public: //### Remove this & change qpixmap.cpp & qbitmap.cpp once every platform is gaurenteed // to have a graphics system. static QPixmapData *createDefaultPixmapData(QPixmapData::PixelType type); + + virtual void releaseCachedResources(); }; QT_END_NAMESPACE diff --git a/src/gui/painting/qgraphicssystem_runtime.cpp b/src/gui/painting/qgraphicssystem_runtime.cpp index 0294c4b..5841d40 100644 --- a/src/gui/painting/qgraphicssystem_runtime.cpp +++ b/src/gui/painting/qgraphicssystem_runtime.cpp @@ -285,6 +285,7 @@ void QRuntimeWindowSurface::flush(QWidget *widget, const QRegion ®ion, void QRuntimeWindowSurface::setGeometry(const QRect &rect) { + QWindowSurface::setGeometry(rect); m_windowSurface->setGeometry(rect); } diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 47caa9f..9242fb6 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -662,19 +662,19 @@ QRasterPaintEngineState::QRasterPaintEngineState() QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s) : QPainterState(s) + , lastPen(s.lastPen) + , penData(s.penData) , stroker(s.stroker) + , strokeFlags(s.strokeFlags) , lastBrush(s.lastBrush) , brushData(s.brushData) - , lastPen(s.lastPen) - , penData(s.penData) , fillFlags(s.fillFlags) - , strokeFlags(s.strokeFlags) , pixmapFlags(s.pixmapFlags) , intOpacity(s.intOpacity) , txscale(s.txscale) - , flag_bits(s.flag_bits) , clip(s.clip) , dirty(s.dirty) + , flag_bits(s.flag_bits) { brushData.tempImage = 0; penData.tempImage = 0; @@ -3716,6 +3716,13 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line, const bool squareCap = (pen.capStyle() == Qt::SquareCap); const QVector<qreal> pattern = pen.dashPattern(); + qreal patternLength = 0; + for (int i = 0; i < pattern.size(); ++i) + patternLength += pattern.at(i); + + if (patternLength <= 0) + return; + qreal length = line.length(); Q_ASSERT(length > 0); while (length > 0) { diff --git a/src/gui/painting/qpaintengine_s60.cpp b/src/gui/painting/qpaintengine_s60.cpp index 1bc7799..ca303be 100644 --- a/src/gui/painting/qpaintengine_s60.cpp +++ b/src/gui/painting/qpaintengine_s60.cpp @@ -41,6 +41,7 @@ #include <private/qpaintengine_s60_p.h> #include <private/qpixmap_s60_p.h> #include <private/qt_s60_p.h> +#include <private/qvolatileimage_p.h> QT_BEGIN_NAMESPACE @@ -90,7 +91,15 @@ void QS60PaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm) QRasterPaintEngine::drawPixmap(p, pm); srcData->endDataAccess(); } else { - QRasterPaintEngine::drawPixmap(p, pm); + void *nativeData = pm.pixmapData()->toNativeType(QPixmapData::VolatileImage); + if (nativeData) { + QVolatileImage *img = static_cast<QVolatileImage *>(nativeData); + img->beginDataAccess(); + QRasterPaintEngine::drawImage(p, img->imageRef()); + img->endDataAccess(true); + } else { + QRasterPaintEngine::drawPixmap(p, pm); + } } } @@ -102,7 +111,15 @@ void QS60PaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRect QRasterPaintEngine::drawPixmap(r, pm, sr); srcData->endDataAccess(); } else { - QRasterPaintEngine::drawPixmap(r, pm, sr); + void *nativeData = pm.pixmapData()->toNativeType(QPixmapData::VolatileImage); + if (nativeData) { + QVolatileImage *img = static_cast<QVolatileImage *>(nativeData); + img->beginDataAccess(); + QRasterPaintEngine::drawImage(r, img->imageRef(), sr); + img->endDataAccess(true); + } else { + QRasterPaintEngine::drawPixmap(r, pm, sr); + } } } diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 81ca40f..8bff021 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -874,7 +874,7 @@ void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength); #endif - if (!qt_is_finite(rect.x()) && !qt_is_finite(rect.y()) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height()) + if ((!qt_is_finite(rect.x()) && !qt_is_finite(rect.y())) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height()) || !qt_is_finite(startAngle) || !qt_is_finite(sweepLength)) { #ifndef QT_NO_DEBUG qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN or Inf, ignoring call"); diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index 80353bc..fca46b4 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -668,26 +668,28 @@ template <class Iterator> bool qt_stroke_side(Iterator *it, #endif QLineF line(qt_fixed_to_real(prev.x), qt_fixed_to_real(prev.y), qt_fixed_to_real(e.x), qt_fixed_to_real(e.y)); - QLineF normal = line.normalVector(); - normal.setLength(offset); - line.translate(normal.dx(), normal.dy()); - - // If we are starting a new subpath, move to correct starting point. - if (first) { - if (capFirst) - stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode()); - else - stroker->emitMoveTo(qt_real_to_fixed(line.x1()), qt_real_to_fixed(line.y1())); - *startTangent = line; - first = false; - } else { - stroker->joinPoints(prev.x, prev.y, line, stroker->joinStyleMode()); - } + if (line.p1() != line.p2()) { + QLineF normal = line.normalVector(); + normal.setLength(offset); + line.translate(normal.dx(), normal.dy()); + + // If we are starting a new subpath, move to correct starting point. + if (first) { + if (capFirst) + stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode()); + else + stroker->emitMoveTo(qt_real_to_fixed(line.x1()), qt_real_to_fixed(line.y1())); + *startTangent = line; + first = false; + } else { + stroker->joinPoints(prev.x, prev.y, line, stroker->joinStyleMode()); + } - // Add the stroke for this line. - stroker->emitLineTo(qt_real_to_fixed(line.x2()), - qt_real_to_fixed(line.y2())); - prev = e; + // Add the stroke for this line. + stroker->emitLineTo(qt_real_to_fixed(line.x2()), + qt_real_to_fixed(line.y2())); + prev = e; + } // CurveToElement } else if (e.isCurveTo()) { diff --git a/src/gui/statemachine/qguistatemachine.cpp b/src/gui/statemachine/qguistatemachine.cpp index eadb8ff..2a0de3c 100644 --- a/src/gui/statemachine/qguistatemachine.cpp +++ b/src/gui/statemachine/qguistatemachine.cpp @@ -404,6 +404,7 @@ static QEvent *cloneEvent(QEvent *e) we2->setButtons(we->buttons()); we2->setModifiers(we->modifiers()); we2->setOrientation(we->orientation()); + we2->setDelta(we->delta()); return we2; } #endif diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index 605872e..600c631 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -47,6 +47,7 @@ #include "private/qt_s60_p.h" #include "private/qpixmap_s60_p.h" #include "private/qcore_symbian_p.h" +#include "private/qvolatileimage_p.h" #include "qapplication.h" #include "qsettings.h" @@ -637,9 +638,22 @@ QPixmap QS60StyleModeSpecifics::fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask if (error) return QPixmap(); - QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(icon); - if (mask) - pixmap.setAlphaChannel(QPixmap::fromSymbianCFbsBitmap(mask)); + QPixmap pixmap; + QScopedPointer<QPixmapData> pd(QPixmapData::create(0, 0, QPixmapData::PixmapType)); + bool nativeMaskSupported = (pd->toNativeType(QPixmapData::VolatileImage) != 0); + if (mask && nativeMaskSupported) { + // Efficient path, less copying and conversion. + QVolatileImage img(icon, mask); + pd->fromNativeType(&img, QPixmapData::VolatileImage); + pixmap = QPixmap(pd.take()); + } else { + // Potentially more expensive path. + pd->fromNativeType(icon, QPixmapData::FbsBitmap); + pixmap = QPixmap(pd.take()); + if (mask) { + pixmap.setAlphaChannel(QPixmap::fromSymbianCFbsBitmap(mask)); + } + } if ((flags & QS60StylePrivate::SF_PointEast) || (flags & QS60StylePrivate::SF_PointSouth) || @@ -795,6 +809,8 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX( rotatedBy90or270 ? TSize(size.height(), size.width()) : qt_QSize2TSize(size); MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance(); + static const TDisplayMode displayMode = S60->supportsPremultipliedAlpha ? Q_SYMBIAN_ECOLOR16MAP : EColor16MA; + static const TInt drawParam = S60->supportsPremultipliedAlpha ? KAknsDrawParamDefault : KAknsDrawParamRGBOnly; QPixmap result; @@ -833,7 +849,7 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX( // QS60WindowSurface::unlockBitmapHeap(); CFbsBitmap *background = new (ELeave) CFbsBitmap(); //offscreen CleanupStack::PushL(background); - User::LeaveIfError(background->Create(targetSize, EColor16MA)); + User::LeaveIfError(background->Create(targetSize, displayMode)); CFbsBitmapDevice *dev = CFbsBitmapDevice::NewL(background); CleanupStack::PushL(dev); @@ -854,7 +870,7 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX( *gc, TPoint(), targetSize, - KAknsDrawParamDefault | KAknsDrawParamRGBOnly); + drawParam); if (drawn) result = fromFbsBitmap(background, NULL, flags, targetSize); diff --git a/src/gui/styles/qstylesheetstyle_default.cpp b/src/gui/styles/qstylesheetstyle_default.cpp index 002dcff..76ffac8 100644 --- a/src/gui/styles/qstylesheetstyle_default.cpp +++ b/src/gui/styles/qstylesheetstyle_default.cpp @@ -151,7 +151,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const BasicSelector bSelector; Selector selector; Declaration decl; - Value value; + QCss::Value value; Pseudo pseudo; AttributeSelector attr; diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index 54ca7cc..052dc72 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -649,7 +649,7 @@ bool ValueExtractor::extractOutline(int *borders, QBrush *colors, BorderStyle *s return hit; } -static Qt::Alignment parseAlignment(const Value *values, int count) +static Qt::Alignment parseAlignment(const QCss::Value *values, int count) { Qt::Alignment a[2] = { 0, 0 }; for (int i = 0; i < qMin(2, count); i++) { @@ -672,7 +672,7 @@ static Qt::Alignment parseAlignment(const Value *values, int count) return a[0] | a[1]; } -static ColorData parseColorValue(Value v) +static ColorData parseColorValue(QCss::Value v) { if (v.type == Value::Identifier || v.type == Value::String) { v.variant.convert(QVariant::Color); @@ -706,7 +706,7 @@ static ColorData parseColorValue(Value v) if (!p.testExpr()) return ColorData(); - QVector<Value> colorDigits; + QVector<QCss::Value> colorDigits; if (!p.parseExpr(&colorDigits)) return ColorData(); @@ -738,7 +738,7 @@ static QColor colorFromData(const ColorData& c, const QPalette &pal) return QColor(); } -static BrushData parseBrushValue(const Value &v, const QPalette &pal) +static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal) { ColorData c = parseColorValue(v); if (c.type == ColorData::Color) { @@ -780,7 +780,7 @@ static BrushData parseBrushValue(const Value &v, const QPalette &pal) return BrushData(); parser.skipSpace(); if (attr.compare(QLatin1String("stop"), Qt::CaseInsensitive) == 0) { - Value stop, color; + QCss::Value stop, color; parser.next(); if (!parser.parseTerm(&stop)) return BrushData(); parser.skipSpace(); @@ -792,7 +792,7 @@ static BrushData parseBrushValue(const Value &v, const QPalette &pal) stops.append(QGradientStop(stop.variant.toReal(), colorFromData(cd, pal))); } else { parser.next(); - Value value; + QCss::Value value; (void)parser.parseTerm(&value); if (attr.compare(QLatin1String("spread"), Qt::CaseInsensitive) == 0) { spread = spreads.indexOf(value.variant.toString()); @@ -856,7 +856,7 @@ static QBrush brushFromData(const BrushData& c, const QPalette &pal) } } -static BorderStyle parseStyleValue(Value v) +static BorderStyle parseStyleValue(QCss::Value v) { if (v.type == Value::KnownIdentifier) { switch (v.variant.toInt()) { @@ -941,7 +941,7 @@ void ValueExtractor::borderValue(const Declaration &decl, int *width, QCss::Bord decl.d->parsed = QVariant::fromValue<BorderData>(data); } -static void parseShorthandBackgroundProperty(const QVector<Value> &values, BrushData *brush, QString *image, Repeat *repeat, Qt::Alignment *alignment, const QPalette &pal) +static void parseShorthandBackgroundProperty(const QVector<QCss::Value> &values, BrushData *brush, QString *image, Repeat *repeat, Qt::Alignment *alignment, const QPalette &pal) { *brush = BrushData(); *image = QString(); @@ -949,7 +949,7 @@ static void parseShorthandBackgroundProperty(const QVector<Value> &values, Brush *alignment = Qt::AlignTop | Qt::AlignLeft; for (int i = 0; i < values.count(); ++i) { - const Value &v = values.at(i); + const QCss::Value &v = values.at(i); if (v.type == Value::Uri) { *image = v.variant.toString(); continue; @@ -996,7 +996,7 @@ bool ValueExtractor::extractBackground(QBrush *brush, QString *image, Repeat *re const Declaration &decl = declarations.at(i); if (decl.d->values.isEmpty()) continue; - const Value &val = decl.d->values.at(0); + const QCss::Value &val = decl.d->values.at(0); switch (decl.d->propertyId) { case BackgroundColor: *brush = decl.brushValue(); @@ -1050,7 +1050,7 @@ bool ValueExtractor::extractBackground(QBrush *brush, QString *image, Repeat *re return hit; } -static bool setFontSizeFromValue(Value value, QFont *font, int *fontSizeAdjustment) +static bool setFontSizeFromValue(QCss::Value value, QFont *font, int *fontSizeAdjustment) { if (value.type == Value::KnownIdentifier) { bool valid = true; @@ -1087,7 +1087,7 @@ static bool setFontSizeFromValue(Value value, QFont *font, int *fontSizeAdjustme return valid; } -static bool setFontStyleFromValue(const Value &value, QFont *font) +static bool setFontStyleFromValue(const QCss::Value &value, QFont *font) { if (value.type != Value::KnownIdentifier) return false ; @@ -1100,7 +1100,7 @@ static bool setFontStyleFromValue(const Value &value, QFont *font) return false; } -static bool setFontWeightFromValue(const Value &value, QFont *font) +static bool setFontWeightFromValue(const QCss::Value &value, QFont *font) { if (value.type == Value::KnownIdentifier) { switch (value.variant.toInt()) { @@ -1121,12 +1121,12 @@ static bool setFontWeightFromValue(const Value &value, QFont *font) * and set it the \a font * \returns true if a family was extracted. */ -static bool setFontFamilyFromValues(const QVector<Value> &values, QFont *font, int start = 0) +static bool setFontFamilyFromValues(const QVector<QCss::Value> &values, QFont *font, int start = 0) { QString family; bool shouldAddSpace = false; for (int i = start; i < values.count(); ++i) { - const Value &v = values.at(i); + const QCss::Value &v = values.at(i); if (v.type == Value::TermOperatorComma) { family += QLatin1Char(','); shouldAddSpace = false; @@ -1146,7 +1146,7 @@ static bool setFontFamilyFromValues(const QVector<Value> &values, QFont *font, i return true; } -static void setTextDecorationFromValues(const QVector<Value> &values, QFont *font) +static void setTextDecorationFromValues(const QVector<QCss::Value> &values, QFont *font) { for (int i = 0; i < values.count(); ++i) { if (values.at(i).type != Value::KnownIdentifier) @@ -1165,7 +1165,7 @@ static void setTextDecorationFromValues(const QVector<Value> &values, QFont *fon } } -static void parseShorthandFontProperty(const QVector<Value> &values, QFont *font, int *fontSizeAdjustment) +static void parseShorthandFontProperty(const QVector<QCss::Value> &values, QFont *font, int *fontSizeAdjustment) { font->setStyle(QFont::StyleNormal); font->setWeight(QFont::Normal); @@ -1190,7 +1190,7 @@ static void parseShorthandFontProperty(const QVector<Value> &values, QFont *font } } -static void setFontVariantFromValue(const Value &value, QFont *font) +static void setFontVariantFromValue(const QCss::Value &value, QFont *font) { if (value.type == Value::KnownIdentifier) { switch (value.variant.toInt()) { @@ -1201,7 +1201,7 @@ static void setFontVariantFromValue(const Value &value, QFont *font) } } -static void setTextTransformFromValue(const Value &value, QFont *font) +static void setTextTransformFromValue(const QCss::Value &value, QFont *font) { if (value.type == Value::KnownIdentifier) { switch (value.variant.toInt()) { @@ -1226,7 +1226,7 @@ bool ValueExtractor::extractFont(QFont *font, int *fontSizeAdjustment) const Declaration &decl = declarations.at(i); if (decl.d->values.isEmpty()) continue; - const Value &val = decl.d->values.at(0); + const QCss::Value &val = decl.d->values.at(0); switch (decl.d->propertyId) { case FontSize: setFontSizeFromValue(val, font, fontSizeAdjustment); break; case FontStyle: setFontStyleFromValue(val, font); break; @@ -1411,7 +1411,7 @@ bool Declaration::realValue(qreal *real, const char *unit) const return ok; } -static bool intValueHelper(const Value &v, int *i, const char *unit) +static bool intValueHelper(const QCss::Value &v, int *i, const char *unit) { if (unit && v.type != Value::Length) return false; @@ -1460,7 +1460,7 @@ QRect Declaration::rectValue() const if (d->parsed.isValid()) return qvariant_cast<QRect>(d->parsed); - const Value &v = d->values.at(0); + const QCss::Value &v = d->values.at(0); if (v.type != Value::Function) return QRect(); QStringList func = v.variant.toStringList(); diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index 79c46b3..86bafc9 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -71,6 +71,9 @@ #if defined(Q_OS_VXWORKS) && defined(NONE) # undef NONE #endif +#if defined(Q_OS_INTEGRITY) +# undef Value +#endif QT_BEGIN_NAMESPACE diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 084b7ac..64eb27a 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -139,6 +139,9 @@ bool QFontDef::exactMatch(const QFontDef &other) const QFontDatabase::parseFontName(family, this_foundry, this_family); QFontDatabase::parseFontName(other.family, other_foundry, other_family); + this_family = QFontDatabase::resolveFontFamilyAlias(this_family); + other_family = QFontDatabase::resolveFontFamilyAlias(other_family); + return (styleHint == other.styleHint && styleStrategy == other.styleStrategy && weight == other.weight diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 8e92b1a..1e94bf5 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -1087,6 +1087,12 @@ QT_BEGIN_INCLUDE_NAMESPACE #elif defined(Q_OS_SYMBIAN) # include "qfontdatabase_s60.cpp" #endif +#if !defined(Q_WS_X11) +QString QFontDatabase::resolveFontFamilyAlias(const QString &family) +{ + return family; +} +#endif QT_END_INCLUDE_NAMESPACE static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey) diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 3e9483b..ae1130e 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -152,6 +152,7 @@ public: private: static void createDatabase(); static void parseFontName(const QString &name, QString &foundry, QString &family); + static QString resolveFontFamilyAlias(const QString &family); #if defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_SYMBIAN) static QFontEngine *findFont(int script, const QFontPrivate *fp, const QFontDef &request); #endif diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp index 2186058..02b0148 100644 --- a/src/gui/text/qfontdatabase_x11.cpp +++ b/src/gui/text/qfontdatabase_x11.cpp @@ -1972,17 +1972,6 @@ void QFontDatabase::load(const QFontPrivate *d, int script) #ifndef QT_NO_FONTCONFIG } else if (X11->has_fontconfig) { fe = loadFc(d, script, req); - if (fe != 0 && fe->fontDef.pixelSize != req.pixelSize && mainThread && qt_is_gui_used) { - QFontEngine *xlfdFontEngine = loadXlfd(d->screen, script, req); - if (xlfdFontEngine->fontDef.family == fe->fontDef.family) { - delete fe; - fe = xlfdFontEngine; - } else { - delete xlfdFontEngine; - } - } - - #endif } else if (mainThread && qt_is_gui_used) { fe = loadXlfd(d->screen, script, req); @@ -2131,4 +2120,26 @@ bool QFontDatabase::supportsThreadedFontRendering() #endif } +QString QFontDatabase::resolveFontFamilyAlias(const QString &family) +{ +#if defined(QT_NO_FONTCONFIG) + return family; +#else + FcPattern *pattern = FcPatternCreate(); + if (!pattern) + return family; + + FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) family.toUtf8().data()); + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcChar8 *familyAfterSubstitution; + FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution); + QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution); + FcPatternDestroy(pattern); + + return resolved; +#endif +} + QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine_qws.cpp b/src/gui/text/qfontengine_qws.cpp index 4802b94..b71c4a7 100644 --- a/src/gui/text/qfontengine_qws.cpp +++ b/src/gui/text/qfontengine_qws.cpp @@ -288,13 +288,16 @@ private: #else void readNode(QIODevice& f) { - uchar rw = f.getch(); - uchar cl = f.getch(); + char rw; + char cl; + f.getChar(&rw); + f.getChar(&cl); min = (rw << 8) | cl; - rw = f.getch(); - cl = f.getch(); + f.getChar(&rw); + f.getChar(&cl); max = (rw << 8) | cl; - int flags = f.getch(); + char flags; + f.getChar(&flags); if ( flags & 1 ) less = new QPFGlyphTree; else @@ -332,7 +335,7 @@ private: int n = max-min+1; for (int i=0; i<n; i++) { glyph[i].metrics = new QPFGlyphMetrics; - f.readBlock((char*)glyph[i].metrics, sizeof(QPFGlyphMetrics)); + f.read((char*)glyph[i].metrics, sizeof(QPFGlyphMetrics)); } if ( less ) less->readMetrics(f); @@ -365,7 +368,7 @@ private: //############### s = qt_screen->mapToDevice( s ); uint datasize = glyph[i].metrics->linestep * s.height(); glyph[i].data = new uchar[datasize]; // ### deleted? - f.readBlock((char*)glyph[i].data, datasize); + f.read((char*)glyph[i].data, datasize); } if ( less ) less->readData(f); @@ -385,6 +388,32 @@ public: size_t mmapLength; }; +#if defined(Q_OS_INTEGRITY) +static void *qt_mmap(void *start, size_t length, int /*prot*/, int /*flags*/, int fd, off_t offset) +{ + // INTEGRITY cannot mmap local files - load it into a local buffer + if (::lseek(fd, offset, SEEK_SET) == -1) { +# if defined(DEBUG_FONTENGINE) + perror("lseek failed"); +# endif + } + void *buf = malloc(length); + if (::read(fd, buf, length) != (ssize_t)length) { +# if defined(DEBUG_FONTENGINE) + perror("read failed"); +# endif + } + + return buf; +} +#else +static inline void *qt_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) +{ + return mmap(start, length, prot, flags, fd, offset); +} +#endif + + QFontEngineQPF1::QFontEngineQPF1(const QFontDef&, const QString &fn) { @@ -395,16 +424,18 @@ QFontEngineQPF1::QFontEngineQPF1(const QFontDef&, const QString &fn) QT_STATBUF st; if ( QT_FSTAT( f, &st ) ) qFatal("Failed to stat %s",QFile::encodeName(fn).data()); - uchar* data = (uchar*)mmap( 0, // any address + uchar* data = (uchar*)qt_mmap( 0, // any address st.st_size, // whole file PROT_READ, // read-only memory -#if !defined(Q_OS_SOLARIS) && !defined(Q_OS_QNX4) && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_VXWORKS) +#if defined(Q_OS_INTEGRITY) + 0, +#elif !defined(Q_OS_SOLARIS) && !defined(Q_OS_QNX4) && !defined(Q_OS_VXWORKS) MAP_FILE | MAP_PRIVATE, // swap-backed map from file #else MAP_PRIVATE, #endif f, 0 ); // from offset 0 of f -#if defined(Q_OS_QNX4) && !defined(MAP_FAILED) +#if !defined(MAP_FAILED) && (defined(Q_OS_QNX4) || defined(Q_OS_INTEGRITY)) #define MAP_FAILED ((void *)-1) #endif if ( !data || data == (uchar*)MAP_FAILED ) diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index e15c06d..46f1d62 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -933,15 +933,18 @@ void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *conte break; } case QEvent::MouseMove: { QMouseEvent *ev = static_cast<QMouseEvent *>(e); - d->mouseMoveEvent(ev->buttons(), matrix.map(ev->pos())); + d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), + ev->buttons(), ev->globalPos()); break; } case QEvent::MouseButtonRelease: { QMouseEvent *ev = static_cast<QMouseEvent *>(e); - d->mouseReleaseEvent(ev->button(), matrix.map(ev->pos())); + d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), + ev->buttons(), ev->globalPos()); break; } case QEvent::MouseButtonDblClick: { QMouseEvent *ev = static_cast<QMouseEvent *>(e); - d->mouseDoubleClickEvent(e, ev->button(), matrix.map(ev->pos())); + d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), + ev->buttons(), ev->globalPos()); break; } case QEvent::InputMethod: d->inputMethodEvent(static_cast<QInputMethodEvent *>(e)); @@ -1001,15 +1004,18 @@ void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *conte break; } case QEvent::GraphicsSceneMouseMove: { QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e); - d->mouseMoveEvent(ev->buttons(), matrix.map(ev->pos())); + d->mouseMoveEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(), + ev->screenPos()); break; } case QEvent::GraphicsSceneMouseRelease: { QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e); - d->mouseReleaseEvent(ev->button(), matrix.map(ev->pos())); + d->mouseReleaseEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(), + ev->screenPos()); break; } case QEvent::GraphicsSceneMouseDoubleClick: { QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e); - d->mouseDoubleClickEvent(e, ev->button(), matrix.map(ev->pos())); + d->mouseDoubleClickEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(), + ev->screenPos()); break; } case QEvent::GraphicsSceneContextMenu: { QGraphicsSceneContextMenuEvent *ev = static_cast<QGraphicsSceneContextMenuEvent *>(e); @@ -1018,7 +1024,8 @@ void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *conte case QEvent::GraphicsSceneHoverMove: { QGraphicsSceneHoverEvent *ev = static_cast<QGraphicsSceneHoverEvent *>(e); - d->mouseMoveEvent(Qt::NoButton, matrix.map(ev->pos())); + d->mouseMoveEvent(ev, Qt::NoButton, matrix.map(ev->pos()), ev->modifiers(),Qt::NoButton, + ev->screenPos()); break; } case QEvent::GraphicsSceneDragEnter: { @@ -1488,6 +1495,11 @@ void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, con { Q_Q(QTextControl); + if (sendMouseEventToInputContext( + e, QEvent::MouseButtonPress, button, pos, modifiers, buttons, globalPos)) { + return; + } + if (interactionFlags & Qt::LinksAccessibleByMouse) { anchorOnMousePress = q->anchorAt(pos); @@ -1530,22 +1542,7 @@ void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, con return; } -#if !defined(QT_NO_IM) - QTextLayout *layout = cursor.block().layout(); - if (contextWidget && layout && !layout->preeditAreaText().isEmpty()) { - QInputContext *ctx = inputContext(); - if (ctx) { - QMouseEvent ev(QEvent::MouseButtonPress, contextWidget->mapFromGlobal(globalPos), globalPos, - button, buttons, modifiers); - ctx->mouseHandler(cursorPos - cursor.position(), &ev); - } - if (!layout->preeditAreaText().isEmpty()) { - e->ignore(); - return; - } - } -#endif - if (modifiers == Qt::ShiftModifier) { + if (modifiers == Qt::ShiftModifier && (interactionFlags & Qt::TextSelectableByMouse)) { if (wordSelectionEnabled && !selectedWordOnDoubleClick.hasSelection()) { selectedWordOnDoubleClick = cursor; selectedWordOnDoubleClick.select(QTextCursor::WordUnderCursor); @@ -1590,10 +1587,16 @@ void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, con hadSelectionOnMousePress = cursor.hasSelection(); } -void QTextControlPrivate::mouseMoveEvent(Qt::MouseButtons buttons, const QPointF &mousePos) +void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, const QPointF &mousePos, Qt::KeyboardModifiers modifiers, + Qt::MouseButtons buttons, const QPoint &globalPos) { Q_Q(QTextControl); + if (sendMouseEventToInputContext( + e, QEvent::MouseMove, button, mousePos, modifiers, buttons, globalPos)) { + return; + } + if (interactionFlags & Qt::LinksAccessibleByMouse) { QString anchor = q->anchorAt(mousePos); if (anchor != highlightedAnchor) { @@ -1623,12 +1626,6 @@ void QTextControlPrivate::mouseMoveEvent(Qt::MouseButtons buttons, const QPointF } const qreal mouseX = qreal(mousePos.x()); -#if !defined(QT_NO_IM) - QTextLayout *layout = cursor.block().layout(); - if (layout && !layout->preeditAreaText().isEmpty()) - return; -#endif - int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit); if (newCursorPos == -1) return; @@ -1642,7 +1639,7 @@ void QTextControlPrivate::mouseMoveEvent(Qt::MouseButtons buttons, const QPointF extendBlockwiseSelection(newCursorPos); else if (selectedWordOnDoubleClick.hasSelection()) extendWordwiseSelection(newCursorPos, mouseX); - else + else if (interactionFlags & Qt::TextSelectableByMouse) setCursorPosition(newCursorPos, QTextCursor::KeepAnchor); if (interactionFlags & Qt::TextEditable) { @@ -1666,10 +1663,16 @@ void QTextControlPrivate::mouseMoveEvent(Qt::MouseButtons buttons, const QPointF repaintOldAndNewSelection(oldSelection); } -void QTextControlPrivate::mouseReleaseEvent(Qt::MouseButton button, const QPointF &pos) +void QTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, + Qt::MouseButtons buttons, const QPoint &globalPos) { Q_Q(QTextControl); + if (sendMouseEventToInputContext( + e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) { + return; + } + const QTextCursor oldSelection = cursor; const int oldCursorPos = cursor.position(); @@ -1727,19 +1730,21 @@ void QTextControlPrivate::mouseReleaseEvent(Qt::MouseButton button, const QPoint } } -void QTextControlPrivate::mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos) +void QTextControlPrivate::mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, + Qt::MouseButtons buttons, const QPoint &globalPos) { Q_Q(QTextControl); + + if (sendMouseEventToInputContext( + e, QEvent::MouseButtonDblClick, button, pos, modifiers, buttons, globalPos)) { + return; + } + if (button != Qt::LeftButton || !(interactionFlags & Qt::TextSelectableByMouse)) { e->ignore(); return; } -#if !defined(QT_NO_IM) - QTextLayout *layout = cursor.block().layout(); - if (layout && !layout->preeditAreaText().isEmpty()) - return; -#endif #ifndef QT_NO_DRAGANDDROP mightStartDrag = false; @@ -1768,6 +1773,45 @@ void QTextControlPrivate::mouseDoubleClickEvent(QEvent *e, Qt::MouseButton butto } } +bool QTextControlPrivate::sendMouseEventToInputContext( + QEvent *e, QEvent::Type eventType, Qt::MouseButton button, const QPointF &pos, + Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos) +{ +#if !defined(QT_NO_IM) + Q_Q(QTextControl); + + QTextLayout *layout = cursor.block().layout(); + if (contextWidget && layout && !layout->preeditAreaText().isEmpty()) { + QInputContext *ctx = inputContext(); + int cursorPos = q->hitTest(pos, Qt::FuzzyHit) - cursor.position(); + + if (cursorPos < 0 || cursorPos > layout->preeditAreaText().length()) { + cursorPos = -1; + // don't send move events outside the preedit area + if (eventType == QEvent::MouseMove) + return true; + } + if (ctx) { + QMouseEvent ev(eventType, contextWidget->mapFromGlobal(globalPos), globalPos, + button, buttons, modifiers); + ctx->mouseHandler(cursorPos, &ev); + e->setAccepted(ev.isAccepted()); + } + if (!layout->preeditAreaText().isEmpty()) + return true; + } +#else + Q_UNUSED(e); + Q_UNUSED(eventType); + Q_UNUSED(button); + Q_UNUSED(pos); + Q_UNUSED(modifiers); + Q_UNUSED(buttons); + Q_UNUSED(globalPos); +#endif + return false; +} + void QTextControlPrivate::contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget) { #ifdef QT_NO_CONTEXTMENU diff --git a/src/gui/text/qtextcontrol_p_p.h b/src/gui/text/qtextcontrol_p_p.h index ecd13ea..94670e2 100644 --- a/src/gui/text/qtextcontrol_p_p.h +++ b/src/gui/text/qtextcontrol_p_p.h @@ -135,9 +135,23 @@ public: Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos); - void mouseMoveEvent(Qt::MouseButtons buttons, const QPointF &pos); - void mouseReleaseEvent(Qt::MouseButton button, const QPointF &pos); - void mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos); + void mouseMoveEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, + Qt::KeyboardModifiers modifiers, + Qt::MouseButtons buttons, + const QPoint &globalPos); + void mouseReleaseEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, + Qt::KeyboardModifiers modifiers, + Qt::MouseButtons buttons, + const QPoint &globalPos); + void mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, + Qt::KeyboardModifiers modifiers, + Qt::MouseButtons buttons, + const QPoint &globalPos); + bool sendMouseEventToInputContext(QEvent *e, QEvent::Type eventType, Qt::MouseButton button, + const QPointF &pos, + Qt::KeyboardModifiers modifiers, + Qt::MouseButtons buttons, + const QPoint &globalPos); void contextMenuEvent(const QPoint &screenPos, const QPointF &docPos, QWidget *contextWidget); void focusEvent(QFocusEvent *e); #ifdef QT_KEYPAD_NAVIGATION diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 415fa4b..a63fdbf 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1385,6 +1385,15 @@ void QTextEngine::shape(int item) const } } +static inline void releaseCachedFontEngine(QFontEngine *fontEngine) +{ + if (fontEngine) { + fontEngine->ref.deref(); + if (fontEngine->cache_count == 0 && fontEngine->ref == 0) + delete fontEngine; + } +} + void QTextEngine::invalidate() { freeMemory(); @@ -1392,6 +1401,9 @@ void QTextEngine::invalidate() maxWidth = 0; if (specialData) specialData->resolvedFormatIndices.clear(); + + releaseCachedFontEngine(feCache.prevFontEngine); + releaseCachedFontEngine(feCache.prevScaledFontEngine); feCache.reset(); } @@ -1824,7 +1836,11 @@ QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFix scaledEngine = font.d->engineForScript(script); } feCache.prevFontEngine = engine; + if (engine) + engine->ref.ref(); feCache.prevScaledFontEngine = scaledEngine; + if (scaledEngine) + scaledEngine->ref.ref(); feCache.prevScript = script; feCache.prevPosition = si.position; feCache.prevLength = length(&si); @@ -1835,6 +1851,8 @@ QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFix else { engine = font.d->engineForScript(script); feCache.prevFontEngine = engine; + if (engine) + engine->ref.ref(); feCache.prevScript = script; feCache.prevPosition = -1; feCache.prevLength = -1; diff --git a/src/gui/text/qtextengine_mac.cpp b/src/gui/text/qtextengine_mac.cpp index c0a1e64..97e8c5b 100644 --- a/src/gui/text/qtextengine_mac.cpp +++ b/src/gui/text/qtextengine_mac.cpp @@ -607,8 +607,9 @@ void QTextEngine::shapeTextMac(int item) const bool stringToCMapFailed = false; if (!fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters, attributes())) { ensureSpace(num_glyphs); - stringToCMapFailed = fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters, - attributes()); + g = availableGlyphs(&si); + stringToCMapFailed = !fe->stringToCMap(str, len, &g, &num_glyphs, flags, log_clusters, + attributes()); } if (!stringToCMapFailed) { diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 4b95000..f20e018 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -420,7 +420,7 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) int c = m_cursor; // cursor position after insertion of commit string if (event->replacementStart() <= 0) - c += event->commitString().length() + qMin(-event->replacementStart(), event->replacementLength()); + c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength()); m_cursor += event->replacementStart(); @@ -456,6 +456,7 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) #ifndef QT_NO_IM setPreeditArea(m_cursor, event->preeditString()); #endif //QT_NO_IM + const int oldPreeditCursor = m_preeditCursor; m_preeditCursor = event->preeditString().length(); m_hideCursor = false; QList<QTextLayout::FormatRange> formats; @@ -479,6 +480,8 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) updateDisplayText(/*force*/ true); if (cursorPositionChanged) emitCursorPositionChanged(); + else if (m_preeditCursor != oldPreeditCursor) + emit updateMicroFocus(); if (isGettingInput) finishChange(priorState); } diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index bfe50fe..3c505c8 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -425,6 +425,7 @@ Q_SIGNALS: void textEdited(const QString &); void resetInputContext(); + void updateMicroFocus(); void accepted(); void editingFinished(); diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index d3af9e1..7435691 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -967,7 +967,7 @@ void QPlainTextEditPrivate::_q_adjustScrollbars() ++lineNumber; } if (lineNumber < layoutLineCount) - visibleFromBottom += (layoutLineCount - lineNumber - 1); + visibleFromBottom += (layoutLineCount - lineNumber); break; } diff --git a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp index d5726c1..9fe01bf 100644 --- a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp +++ b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp @@ -365,7 +365,7 @@ void QDeclarativeFolderListModel::refresh() { d->folderIndex = QModelIndex(); if (d->count) { - emit beginRemoveRows(QModelIndex(), 0, d->count); + emit beginRemoveRows(QModelIndex(), 0, d->count-1); d->count = 0; emit endRemoveRows(); } diff --git a/src/imports/gestures/qdeclarativegesturearea.cpp b/src/imports/gestures/qdeclarativegesturearea.cpp index 1b6e723..c2a2e98 100644 --- a/src/imports/gestures/qdeclarativegesturearea.cpp +++ b/src/imports/gestures/qdeclarativegesturearea.cpp @@ -89,6 +89,10 @@ public: \warning Elements in the Qt.labs module are not guaranteed to remain compatible in future versions. + \warning GestureArea is an experimental element whose development has + been discontinued. PinchArea is available in QtQuick 1.1 and handles + two finger gesture input. + \note This element is only functional on devices with touch input. \qml diff --git a/src/network/access/access.pri b/src/network/access/access.pri index 7497c1a..57a79b3 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -33,7 +33,8 @@ HEADERS += \ access/qabstractnetworkcache_p.h \ access/qabstractnetworkcache.h \ access/qnetworkdiskcache_p.h \ - access/qnetworkdiskcache.h + access/qnetworkdiskcache.h \ + access/qhttpthreaddelegate_p.h SOURCES += \ access/qftp.cpp \ @@ -60,6 +61,7 @@ SOURCES += \ access/qnetworkreplydataimpl.cpp \ access/qnetworkreplyfileimpl.cpp \ access/qabstractnetworkcache.cpp \ - access/qnetworkdiskcache.cpp + access/qnetworkdiskcache.cpp \ + access/qhttpthreaddelegate.cpp include($$PWD/../../3rdparty/zlib_dependency.pri) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index e94b099..3502113 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -286,7 +286,13 @@ void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket, int i = indexOf(socket); // remove the corrupt data if any reply->d_func()->eraseData(); + + // Clean the channel channels[i].close(); + channels[i].reply = 0; + channels[i].request = QHttpNetworkRequest(); + channels[i].requeueCurrentlyPipelinedRequests(); + // send the next request QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); } diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 079f608..41bc64a 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -253,7 +253,7 @@ bool QHttpNetworkConnectionChannel::sendRequest() #endif { // get pointer to upload data - qint64 currentReadSize; + qint64 currentReadSize = 0; qint64 desiredReadSize = qMin(socketWriteMaxSize, bytesTotal - written); const char *readPointer = uploadByteDevice->readPointer(desiredReadSize, currentReadSize); @@ -476,7 +476,8 @@ void QHttpNetworkConnectionChannel::_q_receiveReply() } #ifndef QT_NO_COMPRESS else if (!expand(false)) { // expand a chunk if possible - return; // ### expand failed + // If expand() failed we can just return, it had already called connection->emitReplyError() + return; } #endif } @@ -645,28 +646,38 @@ void QHttpNetworkConnectionChannel::allDone() { #ifndef QT_NO_COMPRESS // expand the whole data. - if (reply->d_func()->expectContent() && reply->d_func()->autoDecompress && !reply->d_func()->streamEnd) - expand(true); // ### if expand returns false, its an error + if (reply->d_func()->expectContent() && reply->d_func()->autoDecompress && !reply->d_func()->streamEnd) { + bool expandResult = expand(true); + // If expand() failed we can just return, it had already called connection->emitReplyError() + if (!expandResult) + return; + } #endif + + if (!reply) { + qWarning() << "QHttpNetworkConnectionChannel::allDone() called without reply. Please report at http://bugreports.qt.nokia.com/"; + return; + } + // while handling 401 & 407, we might reset the status code, so save this. bool emitFinished = reply->d_func()->shouldEmitSignals(); - handleStatus(); - // ### at this point there should be no more data on the socket - // close if server requested bool connectionCloseEnabled = reply->d_func()->isConnectionCloseEnabled(); - if (connectionCloseEnabled) - close(); + detectPipeliningSupport(); + + handleStatus(); + // handleStatus() might have removed the reply because it already called connection->emitReplyError() + // queue the finished signal, this is required since we might send new requests from // slot connected to it. The socket will not fire readyRead signal, if we are already // in the slot connected to readyRead - if (emitFinished) + if (reply && emitFinished) QMetaObject::invokeMethod(reply, "finished", Qt::QueuedConnection); + + // reset the reconnection attempts after we receive a complete reply. // in case of failures, each channel will attempt two reconnects before emitting error. reconnectAttempts = 2; - detectPipeliningSupport(); - // now the channel can be seen as free/idle again, all signal emissions for the reply have been done this->state = QHttpNetworkConnectionChannel::IdleState; @@ -717,6 +728,8 @@ void QHttpNetworkConnectionChannel::allDone() // leading whitespace. QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } else if (alreadyPipelinedRequests.isEmpty()) { + if (connectionCloseEnabled) + close(); if (qobject_cast<QHttpNetworkConnection*>(connection)) QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 7f6b71f..704cf3a 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -177,6 +177,12 @@ qint64 QHttpNetworkReply::bytesAvailableNextBlock() const return -1; } +bool QHttpNetworkReply::readAnyAvailable() const +{ + Q_D(const QHttpNetworkReply); + return (d->responseData.bufferCount() > 0); +} + QByteArray QHttpNetworkReply::readAny() { Q_D(QHttpNetworkReply); diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 1856d7a..cc0f671 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -125,6 +125,7 @@ public: qint64 bytesAvailable() const; qint64 bytesAvailableNextBlock() const; + bool readAnyAvailable() const; QByteArray readAny(); QByteArray readAll(); void setDownstreamLimited(bool t); diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp new file mode 100644 index 0000000..b5cf00a --- /dev/null +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -0,0 +1,518 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork 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 "qhttpthreaddelegate_p.h" + +#include <QThread> +#include <QTimer> +#include <QAuthenticator> +#include <QEventLoop> + +#include "private/qhttpnetworkreply_p.h" +#include "private/qnetworkaccesscache_p.h" +#include "private/qnoncontiguousbytedevice_p.h" + + +QT_BEGIN_NAMESPACE + +static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url) +{ + QNetworkReply::NetworkError code; + // we've got an error + switch (httpStatusCode) { + case 401: // Authorization required + code = QNetworkReply::AuthenticationRequiredError; + break; + + case 403: // Access denied + code = QNetworkReply::ContentOperationNotPermittedError; + break; + + case 404: // Not Found + code = QNetworkReply::ContentNotFoundError; + break; + + case 405: // Method Not Allowed + code = QNetworkReply::ContentOperationNotPermittedError; + break; + + case 407: + code = QNetworkReply::ProxyAuthenticationRequiredError; + break; + + default: + if (httpStatusCode > 500) { + // some kind of server error + code = QNetworkReply::ProtocolUnknownError; + } else if (httpStatusCode >= 400) { + // content error we did not handle above + code = QNetworkReply::UnknownContentError; + } else { + qWarning("QNetworkAccess: got HTTP status code %d which is not expected from url: \"%s\"", + httpStatusCode, qPrintable(url.toString())); + code = QNetworkReply::ProtocolFailure; + } + } + + return code; +} + + +static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy) +{ + QByteArray result; + QUrl copy = url; + bool isEncrypted = copy.scheme().toLower() == QLatin1String("https"); + copy.setPort(copy.port(isEncrypted ? 443 : 80)); + result = copy.toEncoded(QUrl::RemoveUserInfo | QUrl::RemovePath | + QUrl::RemoveQuery | QUrl::RemoveFragment); + +#ifndef QT_NO_NETWORKPROXY + if (proxy && proxy->type() != QNetworkProxy::NoProxy) { + QUrl key; + + switch (proxy->type()) { + case QNetworkProxy::Socks5Proxy: + key.setScheme(QLatin1String("proxy-socks5")); + break; + + case QNetworkProxy::HttpProxy: + case QNetworkProxy::HttpCachingProxy: + key.setScheme(QLatin1String("proxy-http")); + break; + + default: + break; + } + + if (!key.scheme().isEmpty()) { + key.setUserName(proxy->user()); + key.setHost(proxy->hostName()); + key.setPort(proxy->port()); + key.setEncodedQuery(result); + result = key.toEncoded(); + } + } +#endif + + return "http-connection:" + result; +} + +class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection, + public QNetworkAccessCache::CacheableObject +{ + // Q_OBJECT +public: + QNetworkAccessCachedHttpConnection(const QString &hostName, quint16 port, bool encrypt) + : QHttpNetworkConnection(hostName, port, encrypt) + { + setExpires(true); + setShareable(true); + } + + virtual void dispose() + { +#if 0 // sample code; do this right with the API + Q_ASSERT(!isWorking()); +#endif + delete this; + } +}; + + +QThreadStorage<QNetworkAccessCache *> QHttpThreadDelegate::connections; + + +QHttpThreadDelegate::~QHttpThreadDelegate() +{ + // It could be that the main thread has asked us to shut down, so we need to delete the HTTP reply + if (httpReply) { + delete httpReply; + } + + // Get the object cache that stores our QHttpNetworkConnection objects + // and release the entry for this QHttpNetworkConnection + if (connections.hasLocalData() && !cacheKey.isEmpty()) { + connections.localData()->releaseEntry(cacheKey); + } +} + + +QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) : + QObject(parent) + , ssl(false) + , downloadBufferMaximumSize(0) + , pendingDownloadData(0) + , pendingDownloadProgress(0) + , synchronous(false) + , incomingStatusCode(0) + , isPipeliningUsed(false) + , incomingContentLength(-1) + , incomingErrorCode(QNetworkReply::NoError) + , downloadBuffer(0) + , httpConnection(0) + , httpReply(0) +{ +} + +// This is invoked as BlockingQueuedConnection from QNetworkAccessHttpBackend in the user thread +void QHttpThreadDelegate::startRequestSynchronously() +{ + synchronous = true; + + QEventLoop synchronousRequestLoop; + this->synchronousRequestLoop = &synchronousRequestLoop; + + // Worst case timeout + QTimer::singleShot(30*1000, this, SLOT(abortRequest())); + + QMetaObject::invokeMethod(this, "startRequest", Qt::QueuedConnection); + synchronousRequestLoop.exec(); + + connections.localData()->releaseEntry(cacheKey); + connections.setLocalData(0); + +} + + +// This is invoked as QueuedConnection from QNetworkAccessHttpBackend in the user thread +void QHttpThreadDelegate::startRequest() +{ + // Check QThreadStorage for the QNetworkAccessCache + // If not there, create this connection cache + if (!connections.hasLocalData()) { + connections.setLocalData(new QNetworkAccessCache()); + } + + // check if we have an open connection to this host + QUrl urlCopy = httpRequest.url(); + urlCopy.setPort(urlCopy.port(ssl ? 443 : 80)); + + if (transparentProxy.type() != QNetworkProxy::NoProxy) + cacheKey = makeCacheKey(urlCopy, &transparentProxy); + else if (cacheProxy.type() != QNetworkProxy::NoProxy) + cacheKey = makeCacheKey(urlCopy, &cacheProxy); + else + cacheKey = makeCacheKey(urlCopy, 0); + + + // the http object is actually a QHttpNetworkConnection + httpConnection = static_cast<QNetworkAccessCachedHttpConnection *>(connections.localData()->requestEntryNow(cacheKey)); + if (httpConnection == 0) { + // no entry in cache; create an object + // the http object is actually a QHttpNetworkConnection + httpConnection = new QNetworkAccessCachedHttpConnection(urlCopy.host(), urlCopy.port(), ssl); +#ifndef QT_NO_OPENSSL + // Set the QSslConfiguration from this QNetworkRequest. + if (ssl) { + httpConnection->setSslConfiguration(incomingSslConfiguration); + } +#endif + +#ifndef QT_NO_NETWORKPROXY + httpConnection->setTransparentProxy(transparentProxy); + httpConnection->setCacheProxy(cacheProxy); +#endif + + // cache the QHttpNetworkConnection corresponding to this cache key + connections.localData()->addEntry(cacheKey, httpConnection); + } + + + // Send the request to the connection + httpReply = httpConnection->sendRequest(httpRequest); + httpReply->setParent(this); + + // Connect the reply signals that we need to handle and then forward + if (synchronous) { + connect(httpReply,SIGNAL(headerChanged()), this, SLOT(synchronousHeaderChangedSlot())); + connect(httpReply,SIGNAL(finished()), this, SLOT(synchronousFinishedSlot())); + connect(httpReply,SIGNAL(finishedWithError(QNetworkReply::NetworkError, const QString)), + this, SLOT(synchronousFinishedWithErrorSlot(QNetworkReply::NetworkError,QString))); + + connect(httpReply, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)), + this, SLOT(synchronousAuthenticationRequiredSlot(QHttpNetworkRequest,QAuthenticator*))); + connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(synchronousProxyAuthenticationRequiredSlot(QNetworkProxy,QAuthenticator*))); + + // Don't care about ignored SSL errors for now in the synchronous HTTP case. + } else if (!synchronous) { + connect(httpReply,SIGNAL(headerChanged()), this, SLOT(headerChangedSlot())); + connect(httpReply,SIGNAL(finished()), this, SLOT(finishedSlot())); + connect(httpReply,SIGNAL(finishedWithError(QNetworkReply::NetworkError, const QString)), + this, SLOT(finishedWithErrorSlot(QNetworkReply::NetworkError,QString))); + // some signals are only interesting when normal asynchronous style is used + connect(httpReply,SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + connect(httpReply,SIGNAL(dataReadProgress(int, int)), this, SLOT(dataReadProgressSlot(int,int))); + connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)), + this, SLOT(cacheCredentialsSlot(QHttpNetworkRequest,QAuthenticator*))); +#ifndef QT_NO_OPENSSL + connect(httpReply,SIGNAL(sslErrors(const QList<QSslError>)), this, SLOT(sslErrorsSlot(QList<QSslError>))); +#endif + + // In the asynchronous HTTP case we can just forward those signals + // Connect the reply signals that we can directly forward + connect(httpReply, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)), + this, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*))); + connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + } +} + +// This gets called from the user thread or by the synchronous HTTP timeout timer +void QHttpThreadDelegate::abortRequest() +{ + if (httpReply) { + delete httpReply; + httpReply = 0; + this->deleteLater(); + } + + // Got aborted by the timeout timer + if (synchronous) + incomingErrorCode = QNetworkReply::TimeoutError; +} + +void QHttpThreadDelegate::readyReadSlot() +{ + // Don't do in zerocopy case + if (!downloadBuffer.isNull()) + return; + + while (httpReply->readAnyAvailable()) { + pendingDownloadData->fetchAndAddRelease(1); + emit downloadData(httpReply->readAny()); + } +} + +void QHttpThreadDelegate::finishedSlot() +{ + if (!httpReply) { + qWarning() << "QHttpThreadDelegate::finishedSlot: HTTP reply had already been deleted, internal problem. Please report."; + return; + } + + // If there is still some data left emit that now + while (httpReply->readAnyAvailable()) { + pendingDownloadData->fetchAndAddRelease(1); + emit downloadData(httpReply->readAny()); + } + +#ifndef QT_NO_OPENSSL + if (ssl) + emit sslConfigurationChanged(httpReply->sslConfiguration()); +#endif + + if (httpReply->statusCode() >= 400) { + // it's an error reply + QString msg = QLatin1String(QT_TRANSLATE_NOOP("QNetworkReply", + "Error downloading %1 - server replied: %2")); + msg = msg.arg(QString::fromAscii(httpRequest.url().toEncoded()), httpReply->reasonPhrase()); + emit error(statusCodeFromHttp(httpReply->statusCode(), httpRequest.url()), msg); + } + + emit downloadFinished(); + + QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection); + QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); + httpReply = 0; +} + +void QHttpThreadDelegate::synchronousFinishedSlot() +{ + if (httpReply->statusCode() >= 400) { + // it's an error reply + QString msg = QLatin1String(QT_TRANSLATE_NOOP("QNetworkReply", + "Error downloading %1 - server replied: %2")); + incomingErrorDetail = msg.arg(QString::fromAscii(httpRequest.url().toEncoded()), httpReply->reasonPhrase()); + incomingErrorCode = statusCodeFromHttp(httpReply->statusCode(), httpRequest.url()); + } + + synchronousDownloadData = httpReply->readAll(); + + QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection); + QMetaObject::invokeMethod(synchronousRequestLoop, "quit", Qt::QueuedConnection); + httpReply = 0; +} + +void QHttpThreadDelegate::finishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail) +{ + if (!httpReply) { + qWarning() << "QHttpThreadDelegate::finishedWithErrorSlot: HTTP reply had already been deleted, internal problem. Please report."; + return; + } + +#ifndef QT_NO_OPENSSL + if (ssl) + emit sslConfigurationChanged(httpReply->sslConfiguration()); +#endif + emit error(errorCode,detail); + emit downloadFinished(); + + + QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection); + QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); + httpReply = 0; +} + + +void QHttpThreadDelegate::synchronousFinishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail) +{ + incomingErrorCode = errorCode; + incomingErrorDetail = detail; + + QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection); + QMetaObject::invokeMethod(synchronousRequestLoop, "quit", Qt::QueuedConnection); + httpReply = 0; +} + +static void downloadBufferDeleter(char *ptr) +{ + delete[] ptr; +} + +void QHttpThreadDelegate::headerChangedSlot() +{ +#ifndef QT_NO_OPENSSL + if (ssl) + emit sslConfigurationChanged(httpReply->sslConfiguration()); +#endif + + // Is using a zerocopy buffer allowed by user and possible with this reply? + if (httpReply->supportsUserProvidedDownloadBuffer() + && downloadBufferMaximumSize > 0) { + char *buf = new char[httpReply->contentLength()]; // throws if allocation fails + if (buf) { + downloadBuffer = QSharedPointer<char>(buf, downloadBufferDeleter); + httpReply->setUserProvidedDownloadBuffer(buf); + } + } + + // We fetch this into our own + incomingHeaders = httpReply->header(); + incomingStatusCode = httpReply->statusCode(); + incomingReasonPhrase = httpReply->reasonPhrase(); + isPipeliningUsed = httpReply->isPipeliningUsed(); + incomingContentLength = httpReply->contentLength(); + + emit downloadMetaData(incomingHeaders, + incomingStatusCode, + incomingReasonPhrase, + isPipeliningUsed, + downloadBuffer, + incomingContentLength); +} + +void QHttpThreadDelegate::synchronousHeaderChangedSlot() +{ + // Store the information we need in this object, the QNetworkAccessHttpBackend will later read it + incomingHeaders = httpReply->header(); + incomingStatusCode = httpReply->statusCode(); + incomingReasonPhrase = httpReply->reasonPhrase(); + isPipeliningUsed = httpReply->isPipeliningUsed(); + incomingContentLength = httpReply->contentLength(); +} + + +void QHttpThreadDelegate::dataReadProgressSlot(int done, int total) +{ + // If we don't have a download buffer don't attempt to go this codepath + // It is not used by QNetworkAccessHttpBackend + if (downloadBuffer.isNull()) + return; + + pendingDownloadProgress->fetchAndAddRelease(1); + emit downloadProgress(done, total); +} + +void QHttpThreadDelegate::cacheCredentialsSlot(const QHttpNetworkRequest &request, QAuthenticator *authenticator) +{ + authenticationManager->cacheCredentials(request.url(), authenticator); +} + + +#ifndef QT_NO_OPENSSL +void QHttpThreadDelegate::sslErrorsSlot(const QList<QSslError> &errors) +{ + emit sslConfigurationChanged(httpReply->sslConfiguration()); + + bool ignoreAll = false; + QList<QSslError> specificErrors; + emit sslErrors(errors, &ignoreAll, &specificErrors); + if (ignoreAll) + httpReply->ignoreSslErrors(); + if (!specificErrors.isEmpty()) + httpReply->ignoreSslErrors(specificErrors); +} +#endif + +void QHttpThreadDelegate::synchronousAuthenticationRequiredSlot(const QHttpNetworkRequest &request, QAuthenticator *a) +{ + Q_UNUSED(request); + + // Ask the credential cache + QNetworkAuthenticationCredential credential = authenticationManager->fetchCachedCredentials(httpRequest.url(), a); + if (!credential.isNull()) { + a->setUser(credential.user); + a->setPassword(credential.password); + } + + // Disconnect this connection now since we only want to ask the authentication cache once. + QObject::disconnect(this, SLOT(synchronousAuthenticationRequiredSlot(QHttpNetworkRequest,QAuthenticator*))); +} + +#ifndef QT_NO_NETWORKPROXY +void QHttpThreadDelegate::synchronousProxyAuthenticationRequiredSlot(const QNetworkProxy &p, QAuthenticator *a) +{ + // Ask the credential cache + QNetworkAuthenticationCredential credential = authenticationManager->fetchCachedProxyCredentials(p, a); + if (!credential.isNull()) { + a->setUser(credential.user); + a->setPassword(credential.password); + } + + // Disconnect this connection now since we only want to ask the authentication cache once. + QObject::disconnect(this, SLOT(synchronousProxyAuthenticationRequiredSlot(QNetworkProxy,QAuthenticator*))); +} + +#endif + +QT_END_NAMESPACE diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h new file mode 100644 index 0000000..086a35d --- /dev/null +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtNetwork 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 QHTTPTHREADDELEGATE_H +#define QHTTPTHREADDELEGATE_H + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the Network Access API. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QObject> +#include <QThreadStorage> +#include <QNetworkProxy> +#include <QSslConfiguration> +#include <QSslError> +#include <QList> +#include <QNetworkReply> +#include "qhttpnetworkrequest_p.h" +#include "qhttpnetworkconnection_p.h" +#include <QSharedPointer> +#include "qsslconfiguration.h" +#include "private/qnoncontiguousbytedevice_p.h" +#include "qnetworkaccessauthenticationmanager_p.h" + +QT_BEGIN_NAMESPACE + +class QAuthenticator; +class QHttpNetworkReply; +class QEventLoop; +class QNetworkAccessCache; +class QNetworkAccessCachedHttpConnection; + +class QHttpThreadDelegate : public QObject +{ + Q_OBJECT +public: + explicit QHttpThreadDelegate(QObject *parent = 0); + + ~QHttpThreadDelegate(); + + // incoming + bool ssl; +#ifndef QT_NO_OPENSSL + QSslConfiguration incomingSslConfiguration; +#endif + QHttpNetworkRequest httpRequest; + qint64 downloadBufferMaximumSize; + // From backend, modified by us for signal compression + QSharedPointer<QAtomicInt> pendingDownloadData; + QSharedPointer<QAtomicInt> pendingDownloadProgress; +#ifndef QT_NO_NETWORKPROXY + QNetworkProxy cacheProxy; + QNetworkProxy transparentProxy; +#endif + QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager; + bool synchronous; + + // outgoing, Retrieved in the synchronous HTTP case + QByteArray synchronousDownloadData; + QList<QPair<QByteArray,QByteArray> > incomingHeaders; + int incomingStatusCode; + QString incomingReasonPhrase; + bool isPipeliningUsed; + qint64 incomingContentLength; + QNetworkReply::NetworkError incomingErrorCode; + QString incomingErrorDetail; + +protected: + // The zerocopy download buffer, if used: + QSharedPointer<char> downloadBuffer; + // The QHttpNetworkConnection that is used + QNetworkAccessCachedHttpConnection *httpConnection; + QByteArray cacheKey; + QHttpNetworkReply *httpReply; + + // Used for implementing the synchronous HTTP, see startRequestSynchronously() + QEventLoop *synchronousRequestLoop; + +signals: + void authenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *); +#ifndef QT_NO_NETWORKPROXY + void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *); +#endif +#ifndef QT_NO_OPENSSL + void sslErrors(const QList<QSslError> &, bool *, QList<QSslError> *); + void sslConfigurationChanged(const QSslConfiguration); +#endif + void downloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64); + void downloadProgress(qint64, qint64); + void downloadData(QByteArray); + void error(QNetworkReply::NetworkError, const QString); + void downloadFinished(); +public slots: + // This are called via QueuedConnection from user thread + void startRequest(); + void abortRequest(); + // This is called with a BlockingQueuedConnection from user thread + void startRequestSynchronously(); +protected slots: + // From QHttp* + void readyReadSlot(); + void finishedSlot(); + void finishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail = QString()); + void synchronousFinishedSlot(); + void synchronousFinishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail = QString()); + void headerChangedSlot(); + void synchronousHeaderChangedSlot(); + void dataReadProgressSlot(int done, int total); + void cacheCredentialsSlot(const QHttpNetworkRequest &request, QAuthenticator *authenticator); +#ifndef QT_NO_OPENSSL + void sslErrorsSlot(const QList<QSslError> &errors); +#endif + + void synchronousAuthenticationRequiredSlot(const QHttpNetworkRequest &request, QAuthenticator *); +#ifndef QT_NO_NETWORKPROXY + void synchronousProxyAuthenticationRequiredSlot(const QNetworkProxy &, QAuthenticator *); +#endif + +protected: + // Cache for all the QHttpNetworkConnection objects. + // This is per thread. + static QThreadStorage<QNetworkAccessCache *> connections; + +}; + +// This QNonContiguousByteDevice is connected to the QNetworkAccessHttpBackend +// and represents the PUT/POST data. +class QNonContiguousByteDeviceThreadForwardImpl : public QNonContiguousByteDevice +{ + Q_OBJECT +protected: + bool wantDataPending; + qint64 m_amount; + char *m_data; + QByteArray m_dataArray; + bool m_atEnd; + qint64 m_size; +public: + QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s) + : QNonContiguousByteDevice(), + wantDataPending(false), + m_amount(0), + m_data(0), + m_atEnd(aE), + m_size(s) + { + } + + ~QNonContiguousByteDeviceThreadForwardImpl() + { + } + + const char* readPointer(qint64 maximumLength, qint64 &len) + { + if (m_amount == 0 && wantDataPending == false) { + len = 0; + wantDataPending = true; + emit wantData(maximumLength); + } else if (m_amount == 0 && wantDataPending == true) { + // Do nothing, we already sent a wantData signal and wait for results + len = 0; + } else if (m_amount > 0) { + len = m_amount; + return m_data; + } + // cannot happen + return 0; + } + + bool advanceReadPointer(qint64 a) + { + if (m_data == 0) + return false; + + m_amount -= a; + m_data += a; + + // To main thread to inform about our state + emit processedData(a); + + // FIXME possible optimization, already ask user thread for some data + + return true; + } + + bool atEnd() + { + if (m_amount > 0) + return false; + else + return m_atEnd; + } + + bool reset() + { + m_amount = 0; + m_data = 0; + + // Communicate as BlockingQueuedConnection + bool b = false; + emit resetData(&b); + return b; + } + + qint64 size() + { + return m_size; + } + +public slots: + // From user thread: + void haveDataSlot(QByteArray dataArray, bool dataAtEnd, qint64 dataSize) + { + wantDataPending = false; + + m_dataArray = dataArray; + m_data = const_cast<char*>(m_dataArray.constData()); + m_amount = dataArray.size(); + + m_atEnd = dataAtEnd; + m_size = dataSize; + + // This will tell the HTTP code (QHttpNetworkConnectionChannel) that we have data available now + emit readyRead(); + } + +signals: + // void readyRead(); in parent class + // void readProgress(qint64 current, qint64 total); happens in the main thread with the real bytedevice + + // to main thread: + void wantData(qint64); + void processedData(qint64); + void resetData(bool *b); +}; + +QT_END_NAMESPACE + +#endif // QHTTPTHREADDELEGATE_H diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index 53ae29e..5aedac9 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -106,12 +106,10 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice() { - QNonContiguousByteDevice* device = 0; - if (reply->outgoingDataBuffer) - device = QNonContiguousByteDeviceFactory::create(reply->outgoingDataBuffer); + uploadByteDevice = QSharedPointer<QNonContiguousByteDevice>(QNonContiguousByteDeviceFactory::create(reply->outgoingDataBuffer)); else if (reply->outgoingData) { - device = QNonContiguousByteDeviceFactory::create(reply->outgoingData); + uploadByteDevice = QSharedPointer<QNonContiguousByteDevice>(QNonContiguousByteDeviceFactory::create(reply->outgoingData)); } else { return 0; } @@ -120,14 +118,13 @@ QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice() reply->request.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute, QVariant(false)) == QVariant(true); if (bufferDisallowed) - device->disableReset(); - - // make sure we delete this later - device->setParent(this); + uploadByteDevice->disableReset(); - connect(device, SIGNAL(readProgress(qint64,qint64)), this, SLOT(emitReplyUploadProgress(qint64,qint64))); + // We want signal emissions only for normal asynchronous uploads + if (!isSynchronous()) + connect(uploadByteDevice.data(), SIGNAL(readProgress(qint64,qint64)), this, SLOT(emitReplyUploadProgress(qint64,qint64))); - return device; + return uploadByteDevice.data(); } // need to have this function since the reply is a private member variable @@ -327,11 +324,6 @@ void QNetworkAccessBackend::authenticationRequired(QAuthenticator *authenticator manager->authenticationRequired(this, authenticator); } -void QNetworkAccessBackend::cacheCredentials(QAuthenticator *authenticator) -{ - manager->authenticationManager->cacheCredentials(this->reply->url, authenticator); -} - void QNetworkAccessBackend::metaDataChanged() { reply->metaDataChanged(); diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h index 26ee61a..644ae2d 100644 --- a/src/network/access/qnetworkaccessbackend_p.h +++ b/src/network/access/qnetworkaccessbackend_p.h @@ -70,7 +70,6 @@ class QNetworkAccessManagerPrivate; class QNetworkReplyImplPrivate; class QAbstractNetworkCache; class QNetworkCacheMetaData; -class QNetworkAccessBackendUploadIODevice; class QNonContiguousByteDevice; // Should support direct file upload from disk or download to disk. @@ -175,7 +174,6 @@ protected: // Create the device used for reading the upload data QNonContiguousByteDevice* createUploadByteDevice(); - // these functions control the downstream mechanism // that is, data that has come via the connection and is going out the backend qint64 nextDownstreamBlockSize() const; @@ -185,6 +183,8 @@ protected: void writeDownstreamDataDownloadBuffer(qint64, qint64); char* getDownloadBuffer(qint64); + QSharedPointer<QNonContiguousByteDevice> uploadByteDevice; + public slots: // for task 251801, needs to be a slot to be called asynchronously void writeDownstreamData(QIODevice *data); @@ -196,19 +196,22 @@ protected slots: void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); #endif void authenticationRequired(QAuthenticator *auth); - void cacheCredentials(QAuthenticator *auth); void metaDataChanged(); void redirectionRequested(const QUrl &destination); void sslErrors(const QList<QSslError> &errors); void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal); +protected: + // FIXME In the long run we should get rid of our QNAM architecture + // and scrap this ReplyImpl/Backend distinction. + QNetworkAccessManagerPrivate *manager; + QNetworkReplyImplPrivate *reply; + private: friend class QNetworkAccessManager; friend class QNetworkAccessManagerPrivate; - friend class QNetworkAccessBackendUploadIODevice; friend class QNetworkReplyImplPrivate; - QNetworkAccessManagerPrivate *manager; - QNetworkReplyImplPrivate *reply; + bool synchronous; }; diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp index 6da0722..7ebf626 100644 --- a/src/network/access/qnetworkaccessfilebackend.cpp +++ b/src/network/access/qnetworkaccessfilebackend.cpp @@ -75,6 +75,8 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op, // // this construct here must match the one below in open() QFileInfo fi(url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery)); + if ((url.scheme().length()==1) && fi.exists()) + qWarning("QNetworkAccessFileBackendFactory: URL has no schema set, use file:// for files"); if (fi.exists() || (op == QNetworkAccessManager::PutOperation && fi.dir().exists())) return new QNetworkAccessFileBackend; } diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index 79c43fa..4908e0a 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -52,60 +52,19 @@ #include "QtCore/qdatetime.h" #include "QtCore/qelapsedtimer.h" #include "QtNetwork/qsslconfiguration.h" +#include "qhttpthreaddelegate_p.h" +#include "qthread.h" #ifndef QT_NO_HTTP #include <string.h> // for strchr -QT_BEGIN_NAMESPACE +Q_DECLARE_METATYPE(QSharedPointer<char>) -enum { - DefaultHttpPort = 80, - DefaultHttpsPort = 443 -}; +QT_BEGIN_NAMESPACE class QNetworkProxy; -static QByteArray makeCacheKey(QNetworkAccessHttpBackend *backend, QNetworkProxy *proxy) -{ - QByteArray result; - QUrl copy = backend->url(); - bool isEncrypted = copy.scheme().toLower() == QLatin1String("https"); - copy.setPort(copy.port(isEncrypted ? DefaultHttpsPort : DefaultHttpPort)); - result = copy.toEncoded(QUrl::RemoveUserInfo | QUrl::RemovePath | - QUrl::RemoveQuery | QUrl::RemoveFragment); - -#ifndef QT_NO_NETWORKPROXY - if (proxy->type() != QNetworkProxy::NoProxy) { - QUrl key; - - switch (proxy->type()) { - case QNetworkProxy::Socks5Proxy: - key.setScheme(QLatin1String("proxy-socks5")); - break; - - case QNetworkProxy::HttpProxy: - case QNetworkProxy::HttpCachingProxy: - key.setScheme(QLatin1String("proxy-http")); - break; - - default: - break; - } - - if (!key.scheme().isEmpty()) { - key.setUserName(proxy->user()); - key.setHost(proxy->hostName()); - key.setPort(proxy->port()); - key.setEncodedQuery(result); - result = key.toEncoded(); - } - } -#endif - - return "http-connection:" + result; -} - static inline bool isSeparator(register char c) { static const char separators[] = "()<>@,;:\\\"/[]?={}"; @@ -230,71 +189,13 @@ QNetworkAccessHttpBackendFactory::create(QNetworkAccessManager::Operation op, return 0; } -static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const QUrl &url) -{ - QNetworkReply::NetworkError code; - // we've got an error - switch (httpStatusCode) { - case 401: // Authorization required - code = QNetworkReply::AuthenticationRequiredError; - break; - - case 403: // Access denied - code = QNetworkReply::ContentOperationNotPermittedError; - break; - - case 404: // Not Found - code = QNetworkReply::ContentNotFoundError; - break; - - case 405: // Method Not Allowed - code = QNetworkReply::ContentOperationNotPermittedError; - break; - - case 407: - code = QNetworkReply::ProxyAuthenticationRequiredError; - break; - - default: - if (httpStatusCode > 500) { - // some kind of server error - code = QNetworkReply::ProtocolUnknownError; - } else if (httpStatusCode >= 400) { - // content error we did not handle above - code = QNetworkReply::UnknownContentError; - } else { - qWarning("QNetworkAccess: got HTTP status code %d which is not expected from url: \"%s\"", - httpStatusCode, qPrintable(url.toString())); - code = QNetworkReply::ProtocolFailure; - } - } - - return code; -} - -class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection, - public QNetworkAccessCache::CacheableObject -{ - // Q_OBJECT -public: - QNetworkAccessCachedHttpConnection(const QString &hostName, quint16 port, bool encrypt) - : QHttpNetworkConnection(hostName, port, encrypt) - { - setExpires(true); - setShareable(true); - } - - virtual void dispose() - { -#if 0 // sample code; do this right with the API - Q_ASSERT(!isWorking()); -#endif - delete this; - } -}; - QNetworkAccessHttpBackend::QNetworkAccessHttpBackend() - : QNetworkAccessBackend(), httpReply(0), http(0), uploadDevice(0) + : QNetworkAccessBackend() + , statusCode(0) + , pendingDownloadDataEmissions(new QAtomicInt()) + , pendingDownloadProgressEmissions(new QAtomicInt()) + , loadingFromCache(false) + , usingZerocopyDownloadBuffer(false) #ifndef QT_NO_OPENSSL , pendingSslConfiguration(0), pendingIgnoreAllSslErrors(false) #endif @@ -304,44 +205,14 @@ QNetworkAccessHttpBackend::QNetworkAccessHttpBackend() QNetworkAccessHttpBackend::~QNetworkAccessHttpBackend() { - if (http) - disconnectFromHttp(); + // This will do nothing if the request was already finished or aborted + emit abortHttpRequest(); + #ifndef QT_NO_OPENSSL delete pendingSslConfiguration; #endif } -void QNetworkAccessHttpBackend::disconnectFromHttp() -{ - if (http) { - // This is abut disconnecting signals, not about disconnecting TCP connections - disconnect(http, 0, this, 0); - - // Get the object cache that stores our QHttpNetworkConnection objects - QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getObjectCache(this); - - // synchronous calls are not put into the cache, so for them the key is empty - if (!cacheKey.isEmpty()) - cache->releaseEntry(cacheKey); - } - - // This is abut disconnecting signals, not about disconnecting TCP connections - if (httpReply) - disconnect(httpReply, 0, this, 0); - - http = 0; - httpReply = 0; - cacheKey.clear(); -} - -void QNetworkAccessHttpBackend::finished() -{ - if (http) - disconnectFromHttp(); - // call parent - QNetworkAccessBackend::finished(); -} - /* For a given httpRequest 1) If AlwaysNetwork, return @@ -487,9 +358,82 @@ static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& pr void QNetworkAccessHttpBackend::postRequest() { + QThread *thread = 0; + if (isSynchronous()) { + // A synchronous HTTP request uses its own thread + thread = new QThread(); + QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + thread->start(); + } else if (!manager->httpThread) { + // We use the manager-global thread. + // At some point we could switch to having multiple threads if it makes sense. + manager->httpThread = new QThread(); + QObject::connect(manager->httpThread, SIGNAL(finished()), manager->httpThread, SLOT(deleteLater())); + manager->httpThread->start(); +#ifndef QT_NO_NETWORKPROXY + qRegisterMetaType<QNetworkProxy>("QNetworkProxy"); +#endif +#ifndef QT_NO_OPENSSL + qRegisterMetaType<QList<QSslError> >("QList<QSslError>"); + qRegisterMetaType<QSslConfiguration>("QSslConfiguration"); +#endif + qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >("QList<QPair<QByteArray,QByteArray> >"); + qRegisterMetaType<QHttpNetworkRequest>("QHttpNetworkRequest"); + qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError"); + qRegisterMetaType<QSharedPointer<char> >("QSharedPointer<char>"); + + thread = manager->httpThread; + } else { + // Asynchronous request, thread already exists + thread = manager->httpThread; + } + + QUrl url = request().url(); + httpRequest.setUrl(url); + + bool ssl = url.scheme().toLower() == QLatin1String("https"); + setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl); + httpRequest.setSsl(ssl); + + +#ifndef QT_NO_NETWORKPROXY + QNetworkProxy transparentProxy, cacheProxy; + + foreach (const QNetworkProxy &p, proxyList()) { + // use the first proxy that works + // for non-encrypted connections, any transparent or HTTP proxy + // for encrypted, only transparent proxies + if (!ssl + && (p.capabilities() & QNetworkProxy::CachingCapability) + && (p.type() == QNetworkProxy::HttpProxy || + p.type() == QNetworkProxy::HttpCachingProxy)) { + cacheProxy = p; + transparentProxy = QNetworkProxy::NoProxy; + break; + } + if (p.isTransparentProxy()) { + transparentProxy = p; + cacheProxy = QNetworkProxy::NoProxy; + break; + } + } + + // check if at least one of the proxies + if (transparentProxy.type() == QNetworkProxy::DefaultProxy && + cacheProxy.type() == QNetworkProxy::DefaultProxy) { + // unsuitable proxies + QMetaObject::invokeMethod(this, "error", isSynchronous() ? Qt::DirectConnection : Qt::QueuedConnection, + Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError), + Q_ARG(QString, tr("No suitable proxy found"))); + QMetaObject::invokeMethod(this, "finished", isSynchronous() ? Qt::DirectConnection : Qt::QueuedConnection); + return; + } +#endif + + bool loadedFromCache = false; - QHttpNetworkRequest httpRequest; httpRequest.setPriority(convert(request().priority())); + switch (operation()) { case QNetworkAccessManager::GetOperation: httpRequest.setOperation(QHttpNetworkRequest::Get); @@ -504,13 +448,13 @@ void QNetworkAccessHttpBackend::postRequest() case QNetworkAccessManager::PostOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Post); - httpRequest.setUploadByteDevice(createUploadByteDevice()); + createUploadByteDevice(); break; case QNetworkAccessManager::PutOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Put); - httpRequest.setUploadByteDevice(createUploadByteDevice()); + createUploadByteDevice(); break; case QNetworkAccessManager::DeleteOperation: @@ -521,7 +465,7 @@ void QNetworkAccessHttpBackend::postRequest() case QNetworkAccessManager::CustomOperation: invalidateCache(); // for safety reasons, we don't know what the operation does httpRequest.setOperation(QHttpNetworkRequest::Custom); - httpRequest.setUploadByteDevice(createUploadByteDevice()); + createUploadByteDevice(); httpRequest.setCustomVerb(request().attribute( QNetworkRequest::CustomVerbAttribute).toByteArray()); break; @@ -530,11 +474,6 @@ void QNetworkAccessHttpBackend::postRequest() break; // can't happen } - bool encrypt = (url().scheme().toLower() == QLatin1String("https")); - httpRequest.setSsl(encrypt); - - httpRequest.setUrl(url()); - QList<QByteArray> headers = request().rawHeaderList(); if (resumeOffset != 0) { if (headers.contains("Range")) { @@ -558,6 +497,7 @@ void QNetworkAccessHttpBackend::postRequest() httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-'); } } + foreach (const QByteArray &header, headers) httpRequest.setHeaderField(header, request().rawHeader(header)); @@ -576,30 +516,155 @@ void QNetworkAccessHttpBackend::postRequest() QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual) httpRequest.setWithCredentials(false); - httpReply = http->sendRequest(httpRequest); - httpReply->setParent(this); + + // Create the HTTP thread delegate + QHttpThreadDelegate *delegate = new QHttpThreadDelegate; + + // For the synchronous HTTP, this is the normal way the delegate gets deleted + // For the asynchronous HTTP this is a safety measure, the delegate deletes itself when HTTP is finished + connect(thread, SIGNAL(finished()), delegate, SLOT(deleteLater())); + + // Set the properties it needs + delegate->httpRequest = httpRequest; +#ifndef QT_NO_NETWORKPROXY + delegate->cacheProxy = cacheProxy; + delegate->transparentProxy = transparentProxy; +#endif + delegate->ssl = ssl; #ifndef QT_NO_OPENSSL - if (pendingSslConfiguration) - httpReply->setSslConfiguration(*pendingSslConfiguration); - if (pendingIgnoreAllSslErrors) - httpReply->ignoreSslErrors(); - httpReply->ignoreSslErrors(pendingIgnoreSslErrorsList); - connect(httpReply, SIGNAL(sslErrors(QList<QSslError>)), - SLOT(sslErrors(QList<QSslError>))); + if (ssl) + delegate->incomingSslConfiguration = request().sslConfiguration(); #endif - connect(httpReply, SIGNAL(finished()), SLOT(replyFinished())); - connect(httpReply, SIGNAL(finishedWithError(QNetworkReply::NetworkError,QString)), - SLOT(httpError(QNetworkReply::NetworkError,QString))); - connect(httpReply, SIGNAL(headerChanged()), SLOT(replyHeaderChanged())); - connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)), - SLOT(httpCacheCredentials(QHttpNetworkRequest,QAuthenticator*))); + // Do we use synchronous HTTP? + delegate->synchronous = isSynchronous(); + + // The authentication manager is used to avoid the BlockingQueuedConnection communication + // from HTTP thread to user thread in some cases. + delegate->authenticationManager = manager->authenticationManager; + + if (!isSynchronous()) { + // Tell our zerocopy policy to the delegate + delegate->downloadBufferMaximumSize = + request().attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute).toLongLong(); + + // These atomic integers are used for signal compression + delegate->pendingDownloadData = pendingDownloadDataEmissions; + delegate->pendingDownloadProgress = pendingDownloadProgressEmissions; + + // Connect the signals of the delegate to us + connect(delegate, SIGNAL(downloadData(QByteArray)), + this, SLOT(replyDownloadData(QByteArray)), + Qt::QueuedConnection); + connect(delegate, SIGNAL(downloadFinished()), + this, SLOT(replyFinished()), + Qt::QueuedConnection); + connect(delegate, SIGNAL(downloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)), + this, SLOT(replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64)), + Qt::QueuedConnection); + connect(delegate, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(replyDownloadProgressSlot(qint64,qint64)), + Qt::QueuedConnection); + connect(delegate, SIGNAL(error(QNetworkReply::NetworkError,QString)), + this, SLOT(httpError(QNetworkReply::NetworkError, const QString)), + Qt::QueuedConnection); +#ifndef QT_NO_OPENSSL + connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)), + this, SLOT(replySslConfigurationChanged(QSslConfiguration)), + Qt::QueuedConnection); +#endif + // Those need to report back, therefire BlockingQueuedConnection + connect(delegate, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)), + this, SLOT(httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)), + Qt::BlockingQueuedConnection); #ifndef QT_NO_NETWORKPROXY - connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), - SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect (delegate, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + Qt::BlockingQueuedConnection); #endif - connect(httpReply, SIGNAL(authenticationRequired(const QHttpNetworkRequest,QAuthenticator*)), - SLOT(httpAuthenticationRequired(const QHttpNetworkRequest,QAuthenticator*))); +#ifndef QT_NO_OPENSSL + connect(delegate, SIGNAL(sslErrors(QList<QSslError>,bool*,QList<QSslError>*)), + this, SLOT(replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *)), + Qt::BlockingQueuedConnection); +#endif + // This signal we will use to start the request. + connect(this, SIGNAL(startHttpRequest()), delegate, SLOT(startRequest())); + connect(this, SIGNAL(abortHttpRequest()), delegate, SLOT(abortRequest())); + + if (uploadByteDevice) { + QNonContiguousByteDeviceThreadForwardImpl *forwardUploadDevice = + new QNonContiguousByteDeviceThreadForwardImpl(uploadByteDevice->atEnd(), uploadByteDevice->size()); + if (uploadByteDevice->isResetDisabled()) + forwardUploadDevice->disableReset(); + forwardUploadDevice->setParent(delegate); // needed to make sure it is moved on moveToThread() + delegate->httpRequest.setUploadByteDevice(forwardUploadDevice); + + // From main thread to user thread: + QObject::connect(this, SIGNAL(haveUploadData(QByteArray, bool, qint64)), + forwardUploadDevice, SLOT(haveDataSlot(QByteArray, bool, qint64)), Qt::QueuedConnection); + QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()), + forwardUploadDevice, SIGNAL(readyRead()), + Qt::QueuedConnection); + + // From http thread to user thread: + QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)), + this, SLOT(wantUploadDataSlot(qint64))); + QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)), + this, SLOT(sentUploadDataSlot(qint64))); + connect(forwardUploadDevice, SIGNAL(resetData(bool*)), + this, SLOT(resetUploadDataSlot(bool*)), + Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued! + } + } else if (isSynchronous()) { + connect(this, SIGNAL(startHttpRequestSynchronously()), delegate, SLOT(startRequestSynchronously()), Qt::BlockingQueuedConnection); + + if (uploadByteDevice) { + // For the synchronous HTTP use case the use thread (this one here) is blocked + // so we cannot use the asynchronous upload architecture. + // We therefore won't use the QNonContiguousByteDeviceThreadForwardImpl but directly + // use the uploadByteDevice provided to us by the QNetworkReplyImpl. + // The code that is in QNetworkReplyImplPrivate::setup() makes sure it is safe to use from a thread + // since it only wraps a QRingBuffer + delegate->httpRequest.setUploadByteDevice(uploadByteDevice.data()); + } + } + + + // Move the delegate to the http thread + delegate->moveToThread(thread); + // This call automatically moves the uploadDevice too for the asynchronous case. + + // Send an signal to the delegate so it starts working in the other thread + if (isSynchronous()) { + emit startHttpRequestSynchronously(); // This one is BlockingQueuedConnection, so it will return when all work is done + + if (delegate->incomingErrorCode != QNetworkReply::NoError) { + replyDownloadMetaData + (delegate->incomingHeaders, + delegate->incomingStatusCode, + delegate->incomingReasonPhrase, + delegate->isPipeliningUsed, + QSharedPointer<char>(), + delegate->incomingContentLength); + httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail); + } else { + replyDownloadMetaData + (delegate->incomingHeaders, + delegate->incomingStatusCode, + delegate->incomingReasonPhrase, + delegate->isPipeliningUsed, + QSharedPointer<char>(), + delegate->incomingContentLength); + replyDownloadData(delegate->synchronousDownloadData); + } + + // End the thread. It will delete itself from the finished() signal + thread->quit(); + + finished(); + } else { + emit startHttpRequest(); // Signal to the HTTP thread and go back to user. + } } void QNetworkAccessHttpBackend::invalidateCache() @@ -611,159 +676,52 @@ void QNetworkAccessHttpBackend::invalidateCache() void QNetworkAccessHttpBackend::open() { - QUrl url = request().url(); - bool encrypt = url.scheme().toLower() == QLatin1String("https"); - setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, encrypt); - - // set the port number in the reply if it wasn't set - url.setPort(url.port(encrypt ? DefaultHttpsPort : DefaultHttpPort)); - - QNetworkProxy *theProxy = 0; -#ifndef QT_NO_NETWORKPROXY - QNetworkProxy transparentProxy, cacheProxy; - - foreach (const QNetworkProxy &p, proxyList()) { - // use the first proxy that works - // for non-encrypted connections, any transparent or HTTP proxy - // for encrypted, only transparent proxies - if (!encrypt - && (p.capabilities() & QNetworkProxy::CachingCapability) - && (p.type() == QNetworkProxy::HttpProxy || - p.type() == QNetworkProxy::HttpCachingProxy)) { - cacheProxy = p; - transparentProxy = QNetworkProxy::NoProxy; - theProxy = &cacheProxy; - break; - } - if (p.isTransparentProxy()) { - transparentProxy = p; - cacheProxy = QNetworkProxy::NoProxy; - theProxy = &transparentProxy; - break; - } - } - - // check if at least one of the proxies - if (transparentProxy.type() == QNetworkProxy::DefaultProxy && - cacheProxy.type() == QNetworkProxy::DefaultProxy) { - // unsuitable proxies - if (isSynchronous()) { - error(QNetworkReply::ProxyNotFoundError, tr("No suitable proxy found")); - finished(); - } else { - QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, - Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError), - Q_ARG(QString, tr("No suitable proxy found"))); - QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); - } - return; - } -#endif - - if (isSynchronous()) { - // for synchronous requests, we just create a new connection - http = new QHttpNetworkConnection(1, url.host(), url.port(), encrypt, this); -#ifndef QT_NO_NETWORKPROXY - http->setTransparentProxy(transparentProxy); - http->setCacheProxy(cacheProxy); -#endif - postRequest(); - processRequestSynchronously(); - } else { - // check if we have an open connection to this host - cacheKey = makeCacheKey(this, theProxy); - QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getObjectCache(this); - // the http object is actually a QHttpNetworkConnection - http = static_cast<QNetworkAccessCachedHttpConnection *>(cache->requestEntryNow(cacheKey)); - if (http == 0) { - // no entry in cache; create an object - // the http object is actually a QHttpNetworkConnection - http = new QNetworkAccessCachedHttpConnection(url.host(), url.port(), encrypt); - -#ifndef QT_NO_NETWORKPROXY - http->setTransparentProxy(transparentProxy); - http->setCacheProxy(cacheProxy); -#endif - - // cache the QHttpNetworkConnection corresponding to this cache key - cache->addEntry(cacheKey, static_cast<QNetworkAccessCachedHttpConnection *>(http.data())); - } - postRequest(); - } + postRequest(); } void QNetworkAccessHttpBackend::closeDownstreamChannel() { - // this indicates that the user closed the stream while the reply isn't finished yet + // FIXME Maybe we can get rid of this whole architecture part } void QNetworkAccessHttpBackend::downstreamReadyWrite() { - readFromHttp(); - if (httpReply && httpReply->bytesAvailable() == 0 && httpReply->isFinished()) - replyFinished(); + // FIXME Maybe we can get rid of this whole architecture part } void QNetworkAccessHttpBackend::setDownstreamLimited(bool b) { - if (httpReply) - httpReply->setDownstreamLimited(b); -} - -void QNetworkAccessHttpBackend::replyReadyRead() -{ - readFromHttp(); + Q_UNUSED(b); + // We know that readBuffer maximum size limiting is broken since quite a while. + // The task to fix this is QTBUG-15065 } -void QNetworkAccessHttpBackend::readFromHttp() +void QNetworkAccessHttpBackend::replyDownloadData(QByteArray d) { - if (!httpReply) + int pendingSignals = (int)pendingDownloadDataEmissions->fetchAndAddAcquire(-1) - 1; + + if (pendingSignals > 0) { + // Some more signal emissions to this slot are pending. + // Instead of writing the downstream data, we wait + // and do it in the next call we get + // (signal comppression) + pendingDownloadData.append(d); return; - - // We read possibly more than nextDownstreamBlockSize(), but - // this is not a critical thing since it is already in the - // memory anyway - - QByteDataBuffer list; - - while (httpReply->bytesAvailable() != 0 && nextDownstreamBlockSize() != 0 && nextDownstreamBlockSize() > list.byteAmount()) { - list.append(httpReply->readAny()); } - if (!list.isEmpty()) - writeDownstreamData(list); + pendingDownloadData.append(d); + d.clear(); + writeDownstreamData(pendingDownloadData); + pendingDownloadData.clear(); } void QNetworkAccessHttpBackend::replyFinished() { - if (httpReply->bytesAvailable()) - // we haven't read everything yet. Wait some more. + // We are already loading from cache, we still however + // got this signal because it was posted already + if (loadingFromCache) return; - int statusCode = httpReply->statusCode(); - if (statusCode >= 400) { - // it's an error reply - QString msg = QLatin1String(QT_TRANSLATE_NOOP("QNetworkReply", - "Error downloading %1 - server replied: %2")); - msg = msg.arg(url().toString(), httpReply->reasonPhrase()); - error(statusCodeFromHttp(httpReply->statusCode(), httpReply->url()), msg); - } - -#ifndef QT_NO_OPENSSL - // store the SSL configuration now - // once we call finished(), we won't have access to httpReply anymore - QSslConfiguration sslConfig = httpReply->sslConfiguration(); - if (pendingSslConfiguration) { - *pendingSslConfiguration = sslConfig; - } else if (!sslConfig.isNull()) { - QT_TRY { - pendingSslConfiguration = new QSslConfiguration(sslConfig); - } QT_CATCH(...) { - qWarning("QNetworkAccess: could not allocate a QSslConfiguration object for a SSL connection."); - } - } -#endif - finished(); } @@ -785,12 +743,27 @@ void QNetworkAccessHttpBackend::checkForRedirect(const int statusCode) } } -void QNetworkAccessHttpBackend::replyHeaderChanged() +void QNetworkAccessHttpBackend::replyDownloadMetaData + (QList<QPair<QByteArray,QByteArray> > hm, + int sc,QString rp,bool pu, + QSharedPointer<char> db, + qint64 contentLength) { - setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, httpReply->isPipeliningUsed()); + statusCode = sc; + reasonPhrase = rp; + + // Download buffer + if (!db.isNull()) { + reply->setDownloadBuffer(db, contentLength); + usingZerocopyDownloadBuffer = true; + } else { + usingZerocopyDownloadBuffer = false; + } + + setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu); // reconstruct the HTTP header - QList<QPair<QByteArray, QByteArray> > headerMap = httpReply->header(); + QList<QPair<QByteArray, QByteArray> > headerMap = hm; QList<QPair<QByteArray, QByteArray> >::ConstIterator it = headerMap.constBegin(), end = headerMap.constEnd(); QByteArray header; @@ -807,11 +780,10 @@ void QNetworkAccessHttpBackend::replyHeaderChanged() setRawHeader(it->first, value); } - setAttribute(QNetworkRequest::HttpStatusCodeAttribute, httpReply->statusCode()); - setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, httpReply->reasonPhrase()); + setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode); + setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase); // is it a redirection? - const int statusCode = httpReply->statusCode(); checkForRedirect(statusCode); if (statusCode >= 500 && statusCode < 600) { @@ -854,29 +826,21 @@ void QNetworkAccessHttpBackend::replyHeaderChanged() setCachingEnabled(true); } - // Check if a download buffer is supported from the HTTP reply - char *buf = 0; - if (httpReply->supportsUserProvidedDownloadBuffer()) { - // Check if a download buffer is supported by the user - buf = getDownloadBuffer(httpReply->contentLength()); - if (buf) { - httpReply->setUserProvidedDownloadBuffer(buf); - // If there is a download buffer we react on the progress signal - connect(httpReply, SIGNAL(dataReadProgress(int,int)), SLOT(replyDownloadProgressSlot(int,int))); - } - } - - // If there is no buffer, we react on the readyRead signal - if (!buf) { - connect(httpReply, SIGNAL(readyRead()), SLOT(replyReadyRead())); - } - metaDataChanged(); } -void QNetworkAccessHttpBackend::replyDownloadProgressSlot(int received, int total) +void QNetworkAccessHttpBackend::replyDownloadProgressSlot(qint64 received, qint64 total) { // we can be sure here that there is a download buffer + + int pendingSignals = (int)pendingDownloadProgressEmissions->fetchAndAddAcquire(-1) - 1; + if (pendingSignals > 0) { + // Let's ignore this signal and look at the next one coming in + // (signal comppression) + return; + } + + // Now do the actual notification of new bytes writeDownstreamDataDownloadBuffer(received, total); } @@ -886,20 +850,62 @@ void QNetworkAccessHttpBackend::httpAuthenticationRequired(const QHttpNetworkReq authenticationRequired(auth); } -void QNetworkAccessHttpBackend::httpCacheCredentials(const QHttpNetworkRequest &, - QAuthenticator *auth) -{ - cacheCredentials(auth); -} - void QNetworkAccessHttpBackend::httpError(QNetworkReply::NetworkError errorCode, const QString &errorString) { #if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) qDebug() << "http error!" << errorCode << errorString; #endif + error(errorCode, errorString); - finished(); +} + +#ifndef QT_NO_OPENSSL +void QNetworkAccessHttpBackend::replySslErrors( + const QList<QSslError> &list, bool *ignoreAll, QList<QSslError> *toBeIgnored) +{ + // Go to generic backend + sslErrors(list); + // Check if the callback set any ignore and return this here to http thread + if (pendingIgnoreAllSslErrors) + *ignoreAll = true; + if (!pendingIgnoreSslErrorsList.isEmpty()) + *toBeIgnored = pendingIgnoreSslErrorsList; +} + +void QNetworkAccessHttpBackend::replySslConfigurationChanged(const QSslConfiguration &c) +{ + // Receiving the used SSL configuration from the HTTP thread + if (pendingSslConfiguration) + *pendingSslConfiguration = c; + else if (!c.isNull()) + pendingSslConfiguration = new QSslConfiguration(c); +} +#endif + +// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread +void QNetworkAccessHttpBackend::resetUploadDataSlot(bool *r) +{ + *r = uploadByteDevice->reset(); +} + +// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread +void QNetworkAccessHttpBackend::sentUploadDataSlot(qint64 amount) +{ + uploadByteDevice->advanceReadPointer(amount); +} + +// Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread +void QNetworkAccessHttpBackend::wantUploadDataSlot(qint64 maxSize) +{ + // call readPointer + qint64 currentUploadDataLength = 0; + char *data = const_cast<char*>(uploadByteDevice->readPointer(maxSize, currentUploadDataLength)); + // Let's make a copy of this data + QByteArray dataArray(data, currentUploadDataLength); + + // Communicate back to HTTP thread + emit haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size()); } /* @@ -950,8 +956,10 @@ bool QNetworkAccessHttpBackend::sendCacheContents(const QNetworkCacheMetaData &m #if defined(QNETWORKACCESSHTTPBACKEND_DEBUG) qDebug() << "Successfully sent cache:" << url() << contents->size() << "bytes"; #endif - if (httpReply) - disconnect(httpReply, SIGNAL(finished()), this, SLOT(replyFinished())); + + // Set the following flag so we can ignore some signals from HTTP thread + // that would still come + loadingFromCache = true; return true; } @@ -964,39 +972,29 @@ void QNetworkAccessHttpBackend::copyFinished(QIODevice *dev) #ifndef QT_NO_OPENSSL void QNetworkAccessHttpBackend::ignoreSslErrors() { - if (httpReply) - httpReply->ignoreSslErrors(); - else - pendingIgnoreAllSslErrors = true; + pendingIgnoreAllSslErrors = true; } void QNetworkAccessHttpBackend::ignoreSslErrors(const QList<QSslError> &errors) { - if (httpReply) { - httpReply->ignoreSslErrors(errors); - } else { - // the pending list is set if QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) - // is called before QNetworkAccessManager::get() (or post(), etc.) - pendingIgnoreSslErrorsList = errors; - } + // the pending list is set if QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors) + // is called before QNetworkAccessManager::get() (or post(), etc.) + pendingIgnoreSslErrorsList = errors; } void QNetworkAccessHttpBackend::fetchSslConfiguration(QSslConfiguration &config) const { - if (httpReply) - config = httpReply->sslConfiguration(); - else if (pendingSslConfiguration) + if (pendingSslConfiguration) config = *pendingSslConfiguration; + else + config = request().sslConfiguration(); } void QNetworkAccessHttpBackend::setSslConfiguration(const QSslConfiguration &newconfig) { - if (httpReply) - httpReply->setSslConfiguration(newconfig); - else if (pendingSslConfiguration) - *pendingSslConfiguration = newconfig; - else - pendingSslConfiguration = new QSslConfiguration(newconfig); + // Setting a SSL configuration on a reply is not supported. The user needs to set + // her/his QSslConfiguration on the QNetworkRequest. + Q_UNUSED(newconfig); } #endif @@ -1101,7 +1099,7 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo bool canDiskCache; // only cache GET replies by default, all other replies (POST, PUT, DELETE) // are not cacheable by default (according to RFC 2616 section 9) - if (httpReply->request().operation() == QHttpNetworkRequest::Get) { + if (httpRequest.operation() == QHttpNetworkRequest::Get) { canDiskCache = true; // 14.32 @@ -1119,7 +1117,7 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo canDiskCache = false; // responses to POST might be cacheable - } else if (httpReply->request().operation() == QHttpNetworkRequest::Post) { + } else if (httpRequest.operation() == QHttpNetworkRequest::Post) { canDiskCache = false; // some pages contain "expires:" and "cache-control: no-cache" field, @@ -1133,12 +1131,11 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo } metaData.setSaveToDisk(canDiskCache); - int statusCode = httpReply->statusCode(); QNetworkCacheMetaData::AttributesMap attributes; if (statusCode != 304) { // update the status code attributes.insert(QNetworkRequest::HttpStatusCodeAttribute, statusCode); - attributes.insert(QNetworkRequest::HttpReasonPhraseAttribute, httpReply->reasonPhrase()); + attributes.insert(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase); } else { // this is a redirection, keep the attributes intact attributes = oldMetaData.attributes(); @@ -1154,7 +1151,8 @@ bool QNetworkAccessHttpBackend::canResume() const return false; // Can only resume if server/resource supports Range header. - if (httpReply->headerField("Accept-Ranges", "none") == "none") + QByteArray acceptRangesheaderName("Accept-Ranges"); + if (!hasRawHeader(acceptRangesheaderName) || rawHeader(acceptRangesheaderName) == "none") return false; // We only support resuming for byte ranges. @@ -1166,7 +1164,7 @@ bool QNetworkAccessHttpBackend::canResume() const // If we're using a download buffer then we don't support resuming/migration // right now. Too much trouble. - if (httpReply->userProvidedDownloadBuffer()) + if (usingZerocopyDownloadBuffer) return false; return true; @@ -1177,87 +1175,6 @@ void QNetworkAccessHttpBackend::setResumeOffset(quint64 offset) resumeOffset = offset; } -bool QNetworkAccessHttpBackend::processRequestSynchronously() -{ - QHttpNetworkConnectionChannel *channel = &http->channels()[0]; - - // Disconnect all socket signals. They will only confuse us when using waitFor* - QObject::disconnect(channel->socket, 0, 0, 0); - - qint64 timeout = 20*1000; // 20 sec - QElapsedTimer timeoutTimer; - - bool waitResult = channel->socket->waitForConnected(timeout); - timeoutTimer.start(); - - if (!waitResult || channel->socket->state() != QAbstractSocket::ConnectedState) { - error(QNetworkReply::UnknownNetworkError, QLatin1String("could not connect")); - return false; - } - channel->_q_connected(); // this will send the request (via sendRequest()) - -#ifndef QT_NO_OPENSSL - if (http->isSsl()) { - qint64 remainingTimeEncrypted = timeout - timeoutTimer.elapsed(); - if (!static_cast<QSslSocket *>(channel->socket)->waitForEncrypted(remainingTimeEncrypted)) { - error(QNetworkReply::SslHandshakeFailedError, - QLatin1String("could not encrypt or timeout while encrypting")); - return false; - } - channel->_q_encrypted(); - } -#endif - - // if we get a 401 or 407, we might need to send the request twice, see below - bool authenticating = false; - - do { - channel->sendRequest(); - - qint64 remainingTimeBytesWritten; - while(channel->socket->bytesToWrite() > 0 || - channel->state == QHttpNetworkConnectionChannel::WritingState) { - remainingTimeBytesWritten = timeout - timeoutTimer.elapsed(); - channel->sendRequest(); // triggers channel->socket->write() - if (!channel->socket->waitForBytesWritten(remainingTimeBytesWritten)) { - error(QNetworkReply::TimeoutError, - QLatin1String("could not write bytes to socket or timeout while writing")); - return false; - } - } - - qint64 remainingTimeBytesRead = timeout - timeoutTimer.elapsed(); - // Loop for at most remainingTime until either the socket disconnects - // or the reply is finished - do { - waitResult = channel->socket->waitForReadyRead(remainingTimeBytesRead); - remainingTimeBytesRead = timeout - timeoutTimer.elapsed(); - if (!waitResult || remainingTimeBytesRead <= 0 - || channel->socket->state() != QAbstractSocket::ConnectedState) { - error(QNetworkReply::TimeoutError, - QLatin1String("could not read from socket or timeout while reading")); - return false; - } - - if (channel->socket->bytesAvailable()) - channel->_q_readyRead(); - - if (!httpReply) - return false; // we got a 401 or 407 and cannot handle it (it might happen that - // disconnectFromHttp() was called, in that case the reply is zero) - // ### I am quite sure this does not work for NTLM - // ### how about uploading to an auth / proxyAuth site? - - authenticating = (httpReply->statusCode() == 401 || httpReply->statusCode() == 407); - - if (httpReply->isFinished()) - break; - } while (remainingTimeBytesRead > 0); - } while (authenticating); - - return true; -} - QT_END_NAMESPACE #endif // QT_NO_HTTP diff --git a/src/network/access/qnetworkaccesshttpbackend_p.h b/src/network/access/qnetworkaccesshttpbackend_p.h index 7064d4a..712dd2f 100644 --- a/src/network/access/qnetworkaccesshttpbackend_p.h +++ b/src/network/access/qnetworkaccesshttpbackend_p.h @@ -61,6 +61,8 @@ #include "QtCore/qpointer.h" #include "QtCore/qdatetime.h" +#include "QtCore/qsharedpointer.h" +#include "qatomic.h" #ifndef QT_NO_HTTP @@ -99,24 +101,44 @@ public: bool canResume() const; void setResumeOffset(quint64 offset); - virtual bool processRequestSynchronously(); +signals: + // To HTTP thread: + void startHttpRequest(); + void abortHttpRequest(); + void startHttpRequestSynchronously(); + + void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize); private slots: - void replyReadyRead(); + // From HTTP thread: + void replyDownloadData(QByteArray); void replyFinished(); - void replyHeaderChanged(); - void replyDownloadProgressSlot(int,int); + void replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64); + void replyDownloadProgressSlot(qint64,qint64); void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth); - void httpCacheCredentials(const QHttpNetworkRequest &request, QAuthenticator *auth); void httpError(QNetworkReply::NetworkError error, const QString &errorString); +#ifndef QT_NO_OPENSSL + void replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *); + void replySslConfigurationChanged(const QSslConfiguration&); +#endif + + // From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread: + void resetUploadDataSlot(bool *r); + void wantUploadDataSlot(qint64); + void sentUploadDataSlot(qint64); + bool sendCacheContents(const QNetworkCacheMetaData &metaData); - void finished(); // override private: - QHttpNetworkReply *httpReply; - QPointer<QHttpNetworkConnection> http; - QByteArray cacheKey; - QNetworkAccessBackendUploadIODevice *uploadDevice; + QHttpNetworkRequest httpRequest; // There is also a copy in the HTTP thread + int statusCode; + QString reasonPhrase; + // Will be increased by HTTP thread: + QSharedPointer<QAtomicInt> pendingDownloadDataEmissions; + QSharedPointer<QAtomicInt> pendingDownloadProgressEmissions; + bool loadingFromCache; + QByteDataBuffer pendingDownloadData; + bool usingZerocopyDownloadBuffer; #ifndef QT_NO_OPENSSL QSslConfiguration *pendingSslConfiguration; @@ -126,7 +148,6 @@ private: quint64 resumeOffset; - void disconnectFromHttp(); void validateCache(QHttpNetworkRequest &httpRequest, bool &loadedFromCache); void invalidateCache(); void postRequest(); diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 22f62cb..7e75045 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -65,6 +65,8 @@ #include "QtNetwork/qsslconfiguration.h" #include "QtNetwork/qnetworkconfigmanager.h" +#include "qthread.h" + QT_BEGIN_NAMESPACE #ifndef QT_NO_HTTP @@ -1099,10 +1101,21 @@ void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager) { manager->d_func()->objectCache.clear(); manager->d_func()->authenticationManager->clearCache(); + + if (manager->d_func()->httpThread) { + // The thread will deleteLater() itself from its finished() signal + manager->d_func()->httpThread->quit(); + manager->d_func()->httpThread = 0; + } } QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate() { + if (httpThread) { + // The thread will deleteLater() itself from its finished() signal + httpThread->quit(); + httpThread = 0; + } } #ifndef QT_NO_BEARERMANAGEMENT diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 7ef009f..d67b8ac 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -156,6 +156,8 @@ protected: private: friend class QNetworkReplyImplPrivate; + friend class QNetworkAccessHttpBackend; + Q_DECLARE_PRIVATE(QNetworkAccessManager) Q_PRIVATE_SLOT(d_func(), void _q_replyFinished()) Q_PRIVATE_SLOT(d_func(), void _q_replySslErrors(QList<QSslError>)) diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index dba1fd2..ee6ad70 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -73,6 +73,7 @@ class QNetworkAccessManagerPrivate: public QObjectPrivate public: QNetworkAccessManagerPrivate() : networkCache(0), cookieJar(0), + httpThread(0), #ifndef QT_NO_NETWORKPROXY proxyFactory(0), #endif @@ -123,6 +124,8 @@ public: QNetworkCookieJar *cookieJar; + QThread *httpThread; + #ifndef QT_NO_NETWORKPROXY QNetworkProxy proxy; @@ -140,7 +143,7 @@ public: bool cookieJarCreated; // The cache with authorization data: - QNetworkAccessAuthenticationManager* authenticationManager; + QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager; // this cache can be used by individual backends to cache e.g. their TCP connections to a server // and use the connections for multiple requests. diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp index d35f0ce..2040b01 100644 --- a/src/network/access/qnetworkdiskcache.cpp +++ b/src/network/access/qnetworkdiskcache.cpp @@ -404,7 +404,7 @@ QIODevice *QNetworkDiskCache::data(const QUrl &url) // ### verify that QFile uses the fd size and not the file name qint64 size = file->size() - file->pos(); const uchar *p = 0; -#ifndef Q_OS_WINCE +#if !defined(Q_OS_WINCE) && !defined(Q_OS_INTEGRITY) p = file->map(file->pos(), size); #endif if (p) { diff --git a/src/network/access/qnetworkreplyfileimpl.cpp b/src/network/access/qnetworkreplyfileimpl.cpp index 686eb5f..babee32 100644 --- a/src/network/access/qnetworkreplyfileimpl.cpp +++ b/src/network/access/qnetworkreplyfileimpl.cpp @@ -49,15 +49,10 @@ QT_BEGIN_NAMESPACE QNetworkReplyFileImplPrivate::QNetworkReplyFileImplPrivate() - : QNetworkReplyPrivate(), fileEngine(0), fileSize(0), filePos(0) + : QNetworkReplyPrivate(), realFileSize(0) { } -QNetworkReplyFileImplPrivate::~QNetworkReplyFileImplPrivate() -{ - delete fileEngine; -} - QNetworkReplyFileImpl::~QNetworkReplyFileImpl() { } @@ -112,15 +107,15 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequ return; } - d->fileEngine = QAbstractFileEngine::create(fileName); - bool opened = d->fileEngine->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + d->realFile.setFileName(fileName); + bool opened = d->realFile.open(QIODevice::ReadOnly | QIODevice::Unbuffered); // could we open the file? if (!opened) { QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Error opening %1: %2") - .arg(fileName, d->fileEngine->errorString()); + .arg(d->realFile.fileName(), d->realFile.errorString()); - if (fi.exists()) { + if (d->realFile.exists()) { setError(QNetworkReply::ContentAccessDenied, msg); QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ContentAccessDenied)); @@ -133,13 +128,13 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QObject *parent, const QNetworkRequ return; } - d->fileSize = fi.size(); setHeader(QNetworkRequest::LastModifiedHeader, fi.lastModified()); - setHeader(QNetworkRequest::ContentLengthHeader, d->fileSize); + d->realFileSize = fi.size(); + setHeader(QNetworkRequest::ContentLengthHeader, d->realFileSize); QMetaObject::invokeMethod(this, "metaDataChanged", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "downloadProgress", Qt::QueuedConnection, - Q_ARG(qint64, d->fileSize), Q_ARG(qint64, d->fileSize)); + Q_ARG(qint64, d->realFileSize), Q_ARG(qint64, d->realFileSize)); QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); } @@ -147,25 +142,20 @@ void QNetworkReplyFileImpl::close() { Q_D(QNetworkReplyFileImpl); QNetworkReply::close(); - if (d->fileEngine) - d->fileEngine->close(); + d->realFile.close(); } void QNetworkReplyFileImpl::abort() { Q_D(QNetworkReplyFileImpl); QNetworkReply::close(); - if (d->fileEngine) - d->fileEngine->close(); + d->realFile.close(); } qint64 QNetworkReplyFileImpl::bytesAvailable() const { Q_D(const QNetworkReplyFileImpl); - if (!d->fileEngine) - return 0; - - return QNetworkReply::bytesAvailable() + d->fileSize - d->filePos; + return QNetworkReply::bytesAvailable() + d->realFile.bytesAvailable(); } bool QNetworkReplyFileImpl::isSequential () const @@ -176,7 +166,7 @@ bool QNetworkReplyFileImpl::isSequential () const qint64 QNetworkReplyFileImpl::size() const { Q_D(const QNetworkReplyFileImpl); - return d->fileSize; + return d->realFileSize; } /*! @@ -185,17 +175,11 @@ qint64 QNetworkReplyFileImpl::size() const qint64 QNetworkReplyFileImpl::readData(char *data, qint64 maxlen) { Q_D(QNetworkReplyFileImpl); - if (!d->fileEngine) + qint64 ret = d->realFile.read(data, maxlen); + if (ret == 0 && bytesAvailable() == 0) return -1; - - qint64 ret = d->fileEngine->read(data, maxlen); - if (ret == 0 && bytesAvailable() == 0) { - return -1; // everything had been read - } else if (ret > 0) { - d->filePos += ret; - } - - return ret; + else + return ret; } diff --git a/src/network/access/qnetworkreplyfileimpl_p.h b/src/network/access/qnetworkreplyfileimpl_p.h index 627363f..393e3cd 100644 --- a/src/network/access/qnetworkreplyfileimpl_p.h +++ b/src/network/access/qnetworkreplyfileimpl_p.h @@ -86,11 +86,9 @@ class QNetworkReplyFileImplPrivate: public QNetworkReplyPrivate { public: QNetworkReplyFileImplPrivate(); - ~QNetworkReplyFileImplPrivate(); - QAbstractFileEngine *fileEngine; - qint64 fileSize; - qint64 filePos; + QFile realFile; + qint64 realFileSize; Q_DECLARE_PUBLIC(QNetworkReplyFileImpl) }; diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 41a6c62..485f449 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -57,7 +57,7 @@ Q_DECLARE_METATYPE(QSharedPointer<char>) QT_BEGIN_NAMESPACE inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate() - : backend(0), outgoingData(0), outgoingDataBuffer(0), + : backend(0), outgoingData(0), copyDevice(0), cacheEnabled(false), cacheSaveDevice(0), notificationHandlingPaused(false), @@ -212,7 +212,7 @@ void QNetworkReplyImplPrivate::_q_bufferOutgoingData() if (!outgoingDataBuffer) { // first call, create our buffer - outgoingDataBuffer = new QRingBuffer(); + outgoingDataBuffer = QSharedPointer<QRingBuffer>(new QRingBuffer()); QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData())); QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished())); @@ -306,20 +306,22 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const // Internal code that does a HTTP reply for the synchronous Ajax // in QtWebKit. QVariant synchronousHttpAttribute = req.attribute( - static_cast<QNetworkRequest::Attribute>(QNetworkRequest::DownloadBufferAttribute + 1)); - if (backend && synchronousHttpAttribute.toBool()) { - backend->setSynchronous(true); - if (outgoingData && outgoingData->isSequential()) { - outgoingDataBuffer = new QRingBuffer(); - QByteArray data; - do { - data = outgoingData->readAll(); - if (data.isEmpty()) - break; - outgoingDataBuffer->append(data); - } while (1); - } + static_cast<QNetworkRequest::Attribute>(QNetworkRequest::SynchronousRequestAttribute)); + // The synchronous HTTP is a corner case, we will put all upload data in one big QByteArray in the outgoingDataBuffer. + // Yes, this is not the most efficient thing to do, but on the other hand synchronous XHR needs to die anyway. + if (synchronousHttpAttribute.toBool() && outgoingData) { + outgoingDataBuffer = QSharedPointer<QRingBuffer>(new QRingBuffer()); + qint64 previousDataSize = 0; + do { + previousDataSize = outgoingDataBuffer->size(); + outgoingDataBuffer->append(outgoingData->readAll()); + } while (outgoingDataBuffer->size() != previousDataSize); } + + if (backend) + backend->setSynchronous(synchronousHttpAttribute.toBool()); + + if (outgoingData && backend && !backend->isSynchronous()) { // there is data to be uploaded, e.g. HTTP POST. @@ -349,10 +351,6 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const } } } else { - // No outgoing data (e.g. HTTP GET request) - // or no backend - // if no backend, _q_startOperation will handle the error of this - // for HTTP, we want to send out the request as fast as possible to the network, without // invoking methods in a QueuedConnection #ifndef QT_NO_HTTP @@ -634,8 +632,9 @@ char* QNetworkReplyImplPrivate::getDownloadBuffer(qint64 size) { Q_Q(QNetworkReplyImpl); - // Check attribute() if allocating a buffer of that size can be allowed if (!downloadBuffer) { + // We are requested to create it + // Check attribute() if allocating a buffer of that size can be allowed QVariant bufferAllocationPolicy = request.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute); if (bufferAllocationPolicy.isValid() && bufferAllocationPolicy.toLongLong() >= size) { downloadBufferCurrentSize = 0; @@ -650,6 +649,18 @@ char* QNetworkReplyImplPrivate::getDownloadBuffer(qint64 size) return downloadBuffer; } +void QNetworkReplyImplPrivate::setDownloadBuffer(QSharedPointer<char> sp, qint64 size) +{ + Q_Q(QNetworkReplyImpl); + + downloadBufferPointer = sp; + downloadBuffer = downloadBufferPointer.data(); + downloadBufferCurrentSize = 0; + downloadBufferMaximumSize = size; + q->setAttribute(QNetworkRequest::DownloadBufferAttribute, qVariantFromValue<QSharedPointer<char> > (downloadBufferPointer)); +} + + void QNetworkReplyImplPrivate::appendDownstreamDataDownloadBuffer(qint64 bytesReceived, qint64 bytesTotal) { Q_Q(QNetworkReplyImpl); @@ -746,6 +757,11 @@ void QNetworkReplyImplPrivate::finished() void QNetworkReplyImplPrivate::error(QNetworkReplyImpl::NetworkError code, const QString &errorMessage) { Q_Q(QNetworkReplyImpl); + // Can't set and emit multiple errors. + if (errorCode != QNetworkReply::NoError) { + qWarning() << "QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once."; + return; + } errorCode = code; q->setErrorString(errorMessage); @@ -803,9 +819,6 @@ QNetworkReplyImpl::~QNetworkReplyImpl() // save had been properly finished. So if it is still enabled it means we got deleted/aborted. if (d->isCachingEnabled()) d->networkCache()->remove(url()); - - if (d->outgoingDataBuffer) - delete d->outgoingDataBuffer; } void QNetworkReplyImpl::abort() diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index 238bee5..1a9ab7e 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -164,6 +164,7 @@ public: void appendDownstreamData(QIODevice *data); void appendDownstreamData(const QByteArray &data); + void setDownloadBuffer(QSharedPointer<char> sp, qint64 size); char* getDownloadBuffer(qint64 size); void appendDownstreamDataDownloadBuffer(qint64, qint64); @@ -175,7 +176,7 @@ public: QNetworkAccessBackend *backend; QIODevice *outgoingData; - QRingBuffer *outgoingDataBuffer; + QSharedPointer<QRingBuffer> outgoingDataBuffer; QIODevice *copyDevice; QAbstractNetworkCache *networkCache() const; diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index fc33e8d..a48a26f 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -226,6 +226,8 @@ QT_BEGIN_NAMESPACE \omitvalue DownloadBufferAttribute + \omitvalue SynchronousRequestAttribute + \value User Special type. Additional information can be passed in QVariants with types ranging from User to UserMax. The default @@ -529,8 +531,9 @@ QSslConfiguration QNetworkRequest::sslConfiguration() const /*! Sets this network request's SSL configuration to be \a config. The settings that apply are the private key, the local certificate, - the SSL protocol (SSLv2, SSLv3, TLSv1 where applicable) and the - ciphers that the SSL backend is allowed to use. + the SSL protocol (SSLv2, SSLv3, TLSv1 where applicable), the CA + certificates and the ciphers that the SSL backend is allowed to + use. By default, no SSL configuration is set, which allows the backends to choose freely what configuration is best for them. diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 586e6ff..b5ef109 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -84,9 +84,7 @@ public: CookieSaveControlAttribute, MaximumDownloadBufferSizeAttribute, // internal DownloadBufferAttribute, // internal - - // (DownloadBufferAttribute + 1) is reserved internal for QSynchronousHttpNetworkReply - // add the enum in 4.8 + SynchronousRequestAttribute, // internal User = 1000, UserMax = 32767 diff --git a/src/network/bearer/qnetworkconfigmanager.cpp b/src/network/bearer/qnetworkconfigmanager.cpp index 9927f29..9e1eaea 100644 --- a/src/network/bearer/qnetworkconfigmanager.cpp +++ b/src/network/bearer/qnetworkconfigmanager.cpp @@ -52,21 +52,23 @@ QT_BEGIN_NAMESPACE #define Q_GLOBAL_STATIC_QAPP_DESTRUCTION(TYPE, NAME) \ - Q_GLOBAL_STATIC_INIT(TYPE, NAME); \ + static QGlobalStatic<TYPE > this_##NAME \ + = { Q_BASIC_ATOMIC_INITIALIZER(0), false }; \ static void NAME##_cleanup() \ { \ delete this_##NAME.pointer; \ this_##NAME.pointer = 0; \ - this_##NAME.destroyed = true; \ } \ static TYPE *NAME() \ { \ - if (!this_##NAME.pointer && !this_##NAME.destroyed) { \ + if (!this_##NAME.pointer) { \ TYPE *x = new TYPE; \ if (!this_##NAME.pointer.testAndSetOrdered(0, x)) \ delete x; \ - else \ + else { \ qAddPostRoutine(NAME##_cleanup); \ + this_##NAME.pointer->updateConfigurations(); \ + } \ } \ return this_##NAME.pointer; \ } @@ -75,15 +77,7 @@ Q_GLOBAL_STATIC_QAPP_DESTRUCTION(QNetworkConfigurationManagerPrivate, connManage QNetworkConfigurationManagerPrivate *qNetworkConfigurationManagerPrivate() { - static bool initialized = false; - - QNetworkConfigurationManagerPrivate *m = connManager(); - if (!initialized) { - initialized = true; - m->updateConfigurations(); - } - - return m; + return connManager(); } /*! diff --git a/src/network/bearer/qnetworksession.cpp b/src/network/bearer/qnetworksession.cpp index 553410e..af60a43 100644 --- a/src/network/bearer/qnetworksession.cpp +++ b/src/network/bearer/qnetworksession.cpp @@ -680,7 +680,7 @@ void QNetworkSession::connectNotify(const char *signal) //check for preferredConfigurationChanged() signal connect notification //This is not required on all platforms - if (QLatin1String(signal) == SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool))) + if (qstrcmp(signal, SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool))) == 0) d->setALREnabled(true); } @@ -701,7 +701,7 @@ void QNetworkSession::disconnectNotify(const char *signal) //check for preferredConfigurationChanged() signal disconnect notification //This is not required on all platforms - if (QLatin1String(signal) == SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool))) + if (qstrcmp(signal, SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool))) == 0) d->setALREnabled(false); } diff --git a/src/network/bearer/qnetworksession.h b/src/network/bearer/qnetworksession.h index 59d048a..688f37e 100644 --- a/src/network/bearer/qnetworksession.h +++ b/src/network/bearer/qnetworksession.h @@ -142,13 +142,12 @@ private: #ifndef QT_MOBILITY_BEARER QT_END_NAMESPACE +Q_DECLARE_METATYPE(QNetworkSession::State) +Q_DECLARE_METATYPE(QNetworkSession::SessionError) #else QTM_END_NAMESPACE #endif -Q_DECLARE_METATYPE(QNetworkSession::State) -Q_DECLARE_METATYPE(QNetworkSession::SessionError) - QT_END_HEADER #endif // QT_NO_BEARERMANAGEMENT diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 66e87c9..bd3e6ec 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -23,6 +23,7 @@ SOURCES += kernel/qauthenticator.cpp \ symbian: SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_symbian.cpp unix:!symbian:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp +integrity:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation mac:SOURCES += kernel/qnetworkproxy_mac.cpp diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index ead9897..2a942cc 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -2136,7 +2136,7 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize) qDebug("QAbstractSocket::readData(%p '%c (0x%.2x)', 1) == 1 [char buffer]", data, isprint(int(uchar(*data))) ? *data : '?', *data); #endif - if (d->readBuffer.isEmpty() && d->socketEngine) + if (d->readBuffer.isEmpty() && d->socketEngine && d->socketEngine->isValid()) d->socketEngine->setReadNotificationEnabled(true); return 1; } @@ -2148,7 +2148,8 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize) && d->readBuffer.size() < maxSize && d->readBufferMaxSize > 0 && maxSize < d->readBufferMaxSize - && d->socketEngine) { + && d->socketEngine + && d->socketEngine->isValid()) { // Our buffer is empty and a read() was requested for a byte amount that is smaller // than the readBufferMaxSize. This means that we should fill our buffer since we want // such small reads come from the buffer and not always go to the costly socket engine read() @@ -2198,6 +2199,10 @@ qint64 QAbstractSocket::readData(char *data, qint64 maxSize) if (!d->isBuffered) { if (!d->socketEngine) return -1; // no socket engine is probably EOF + if (!d->socketEngine->isValid()) + return -1; // This is for unbuffered TCP when we already had been disconnected + if (d->state != QAbstractSocket::ConnectedState) + return -1; // This is for unbuffered TCP if we're not connected yet qint64 readBytes = d->socketEngine->read(data, maxSize); if (readBytes == -2) { // -2 from the engine means no bytes available (EAGAIN) so read more later @@ -2624,7 +2629,7 @@ void QAbstractSocket::setReadBufferSize(qint64 size) // ensure that the read notification is enabled if we've now got // room in the read buffer // but only if we're not inside canReadNotification -- that will take care on its own - if (size == 0 || d->readBuffer.size() < size) + if ((size == 0 || d->readBuffer.size() < size) && d->state == QAbstractSocket::ConnectedState) // Do not change the notifier unless we are connected. d->socketEngine->setReadNotificationEnabled(true); } } diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 4e628f3..6a025f2 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -743,7 +743,10 @@ void QHttpSocketEngine::emitReadNotification() { Q_D(QHttpSocketEngine); d->readNotificationActivated = true; - if (d->readNotificationEnabled && !d->readNotificationPending) { + // if there is a connection notification pending we have to emit the readNotification + // incase there is connection error. This is only needed for Windows, but it does not + // hurt in other cases. + if ((d->readNotificationEnabled && !d->readNotificationPending) || d->connectionNotificationPending) { d->readNotificationPending = true; QMetaObject::invokeMethod(this, "emitPendingReadNotification", Qt::QueuedConnection); } diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index 8fa4b92..9a2b0ba 100644 --- a/src/network/socket/qlocalsocket.cpp +++ b/src/network/socket/qlocalsocket.cpp @@ -346,7 +346,7 @@ QLocalSocket::QLocalSocket(QObject * parent) QLocalSocket::~QLocalSocket() { close(); -#ifndef Q_OS_WIN +#if !defined(Q_OS_WIN) && !defined(QT_LOCALSOCKET_TCP) Q_D(QLocalSocket); d->unixSocket.setParent(0); #endif diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index 76c9158..940569a 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -337,15 +337,17 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc } #if !defined(Q_OS_WINCE) - // enable new behavior using - // SIO_UDP_CONNRESET - DWORD dwBytesReturned = 0; - int bNewBehavior = 1; - if (::WSAIoctl(socket, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior), - NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) { - // not to worry isBogusUdpReadNotification() should handle this otherwise - int err = WSAGetLastError(); - WS_ERROR_DEBUG(err); + if (socketType == QAbstractSocket::UdpSocket) { + // enable new behavior using + // SIO_UDP_CONNRESET + DWORD dwBytesReturned = 0; + int bNewBehavior = 1; + if (::WSAIoctl(socket, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior), + NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR) { + // not to worry isBogusUdpReadNotification() should handle this otherwise + int err = WSAGetLastError(); + WS_ERROR_DEBUG(err); + } } #endif @@ -639,6 +641,11 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &address, quin socketState = QAbstractSocket::UnconnectedState; break; } + if (value == WSAEADDRNOTAVAIL) { + setError(QAbstractSocket::NetworkError, AddressNotAvailableErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + } } // fall through } diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index 2bafe13..3ccc8e0 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -43,3 +43,13 @@ wince*: { DEFINES += QT_LOCALSOCKET_TCP } + +integrity: { + SOURCES -= socket/qlocalsocket_unix.cpp \ + socket/qlocalserver_unix.cpp + SOURCES += socket/qlocalsocket_tcp.cpp \ + socket/qlocalserver_tcp.cpp \ + socket/qnativesocketengine_unix.cpp + + DEFINES += QT_LOCALSOCKET_TCP +} diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 4252123..61f27fe 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -143,6 +143,15 @@ setDefaultCaCertificates(). \endlist + \note If available, root certificates on Unix (excluding Mac OS X) will be + loaded on demand from the standard certificate directories. If + you do not want to load root certificates on demand, you need to call either + the static function setDefaultCaCertificates() before the first SSL handshake + is made in your application, (e.g. via + "QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates());"), + or call setCaCertificates() on your QSslSocket instance prior to the SSL + handshake. + For more information about ciphers and certificates, refer to QSslCipher and QSslCertificate. @@ -1249,6 +1258,7 @@ void QSslSocket::setCaCertificates(const QList<QSslCertificate> &certificates) { Q_D(QSslSocket); d->configuration.caCertificates = certificates; + d->allowRootCertOnDemandLoading = false; } /*! @@ -1258,6 +1268,9 @@ void QSslSocket::setCaCertificates(const QList<QSslCertificate> &certificates) handshake with addCaCertificate(), addCaCertificates(), and setCaCertificates(). + \note On Unix, this method may return an empty list if the root + certificates are loaded on demand. + \sa addCaCertificate(), addCaCertificates(), setCaCertificates() */ QList<QSslCertificate> QSslSocket::caCertificates() const @@ -1311,10 +1324,9 @@ void QSslSocket::addDefaultCaCertificates(const QList<QSslCertificate> &certific /*! Sets the default CA certificate database to \a certificates. The default CA certificate database is originally set to your system's - default CA certificate database. If no system default database is - found, Qt will provide its own default database. You can override - the default CA certificate database with your own CA certificate - database using this function. + default CA certificate database. You can override the default CA + certificate database with your own CA certificate database using + this function. Each SSL socket's CA certificate database is initialized to the default CA certificate database. @@ -1336,6 +1348,9 @@ void QSslSocket::setDefaultCaCertificates(const QList<QSslCertificate> &certific Each SSL socket's CA certificate database is initialized to the default CA certificate database. + \note On Unix, this method may return an empty list if the root + certificates are loaded on demand. + \sa caCertificates() */ QList<QSslCertificate> QSslSocket::defaultCaCertificates() @@ -1803,6 +1818,7 @@ QSslSocketPrivate::QSslSocketPrivate() , connectionEncrypted(false) , ignoreAllSslErrors(false) , readyReadEmittedPointer(0) + , allowRootCertOnDemandLoading(true) , plainSocket(0) { QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration); @@ -1879,6 +1895,7 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph */ QList<QSslCertificate> QSslSocketPrivate::defaultCaCertificates() { + // ### Qt5: rename everything containing "caCertificates" to "rootCertificates" or similar QSslSocketPrivate::ensureInitialized(); QMutexLocker locker(&globalData()->mutex); return globalData()->config->caCertificates; @@ -1893,6 +1910,9 @@ void QSslSocketPrivate::setDefaultCaCertificates(const QList<QSslCertificate> &c QMutexLocker locker(&globalData()->mutex); globalData()->config.detach(); globalData()->config->caCertificates = certs; + // when the certificates are set explicitly, we do not want to + // load the system certificates on demand + s_loadRootCertsOnDemand = false; } /*! @@ -2192,6 +2212,20 @@ void QSslSocketPrivate::_q_flushReadBuffer() transmit(); } +/*! + \internal +*/ +QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories() +{ + return QList<QByteArray>() << "/etc/ssl/certs/" // (K)ubuntu, OpenSUSE, Mandriva, MeeGo ... + << "/usr/lib/ssl/certs/" // Gentoo, Mandrake + << "/usr/share/ssl/" // Centos, Redhat, SuSE + << "/usr/local/ssl/" // Normal OpenSSL Tarball + << "/var/ssl/certs/" // AIX + << "/usr/local/ssl/certs/" // Solaris + << "/opt/openssl/certs/"; // HP-UX +} + QT_END_NAMESPACE // For private slots diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 7d21bd3..83714ed 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -80,6 +80,7 @@ QT_BEGIN_NAMESPACE bool QSslSocketPrivate::s_libraryLoaded = false; bool QSslSocketPrivate::s_loadedCiphersAndCerts = false; +bool QSslSocketPrivate::s_loadRootCertsOnDemand = false; /* \internal @@ -317,6 +318,13 @@ init_context: q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle()); } + if (s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) { + // tell OpenSSL the directories where to look up the root certs on demand + QList<QByteArray> unixDirs = unixRootCertDirectories(); + for (int a = 0; a < unixDirs.count(); ++a) + q_SSL_CTX_load_verify_locations(ctx, 0, unixDirs.at(a).constData()); + } + // Register a custom callback to get all verification errors. X509_STORE_set_verify_cb_func(ctx->cert_store, q_X509Callback); @@ -517,8 +525,22 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() } else { qWarning("could not load crypt32 library"); // should never happen } +#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) && !defined(Q_OS_MAC) + // check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there) + QList<QByteArray> dirs = unixRootCertDirectories(); + QStringList symLinkFilter; + symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]"); + for (int a = 0; a < dirs.count(); ++a) { + QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files); + if (iterator.hasNext()) { + s_loadRootCertsOnDemand = true; + break; + } + } #endif - setDefaultCaCertificates(systemCaCertificates()); + // if on-demand loading was not enabled, load the certs now + if (!s_loadRootCertsOnDemand) + setDefaultCaCertificates(systemCaCertificates()); } /*! @@ -780,6 +802,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() systemCerts.append(QSslCertificate::fromData(rawCert, QSsl::Der)); } } + CFRelease(cfCerts); } else { // no detailed error handling here @@ -813,15 +836,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() } #elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) QSet<QString> certFiles; - QList<QByteArray> directories; - directories << "/etc/ssl/certs/"; // (K)ubuntu, OpenSUSE, Mandriva, MeeGo ... - directories << "/usr/lib/ssl/certs/"; // Gentoo, Mandrake - directories << "/usr/share/ssl/"; // Centos, Redhat, SuSE - directories << "/usr/local/ssl/"; // Normal OpenSSL Tarball - directories << "/var/ssl/certs/"; // AIX - directories << "/usr/local/ssl/certs/"; // Solaris - directories << "/opt/openssl/certs/"; // HP-UX - + QList<QByteArray> directories = unixRootCertDirectories(); QDir currentDir; QStringList nameFilters; nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt"); diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index 38598b6..b9a05f3 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -262,6 +262,7 @@ DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c, #endif DEFINEFUNC(void, OPENSSL_add_all_algorithms_noconf, void, DUMMYARG, return, DUMMYARG) DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG) +DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return) #ifdef Q_OS_SYMBIAN #define RESOLVEFUNC(func, ordinal, lib) \ @@ -630,6 +631,7 @@ bool q_resolveOpenSslSymbols() #endif RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf, 1153, libs.second ) RESOLVEFUNC(OPENSSL_add_all_algorithms_conf, 1152, libs.second ) + RESOLVEFUNC(SSL_CTX_load_verify_locations, 34, libs.second ) #else // Q_OS_SYMBIAN #ifdef SSLEAY_MACROS RESOLVEFUNC(ASN1_dup) @@ -754,6 +756,7 @@ bool q_resolveOpenSslSymbols() #endif RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf) RESOLVEFUNC(OPENSSL_add_all_algorithms_conf) + RESOLVEFUNC(SSL_CTX_load_verify_locations) #endif // Q_OS_SYMBIAN symbolsResolved = true; delete libs.first; diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index 954ffba..c05dfe11 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -412,6 +412,7 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length); #endif void q_OPENSSL_add_all_algorithms_noconf(); void q_OPENSSL_add_all_algorithms_conf(); +int q_SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath); // Helper function class QDateTime; diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 3a14488..7b92f95 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -112,6 +112,8 @@ public: // that was used for connecting to. QString verificationPeerName; + bool allowRootCertOnDemandLoading; + static bool supportsSsl(); static void ensureInitialized(); static void deinitialize(); @@ -168,6 +170,9 @@ private: static bool s_libraryLoaded; static bool s_loadedCiphersAndCerts; +protected: + static bool s_loadRootCertsOnDemand; + static QList<QByteArray> unixRootCertDirectories(); }; QT_END_NAMESPACE diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 0ec3a15..76621e9 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1791,7 +1791,7 @@ static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, boo QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) { - QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32 + QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32); int w = size.width(); int h = size.height(); diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index 04de1bd..db9f8c8 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE -extern const QGLContext* qt_gl_share_context(); +Q_OPENGL_EXPORT extern const QGLContext* qt_gl_share_context(); /*! \class QGLFramebufferObjectPool diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index cdd3eb9..21b2f09 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -825,11 +825,7 @@ void QGLWindowSurface::updateGeometry() { ctx->updatePaintDevice(); #endif -#ifdef Q_WS_QPA - QSize surfSize = size(); -#else QSize surfSize = geometry().size(); -#endif if (surfSize.width() <= 0 || surfSize.height() <= 0) return; diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 22cbbf5..f0f198f 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -3134,9 +3134,13 @@ void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF if (pm.size().width() <= screenSize.width() && pm.size().height() <= screenSize.height()) vgpd->failedToAlloc = false; - } - drawImage(r, *(pd->buffer()), sr, Qt::AutoColor); + vgpd->source.beginDataAccess(); + drawImage(r, vgpd->source.imageRef(), sr, Qt::AutoColor); + vgpd->source.endDataAccess(true); + } else { + drawImage(r, *(pd->buffer()), sr, Qt::AutoColor); + } } void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) @@ -3162,9 +3166,13 @@ void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) if (pm.size().width() <= screenSize.width() && pm.size().height() <= screenSize.height()) vgpd->failedToAlloc = false; - } - drawImage(pos, *(pd->buffer())); + vgpd->source.beginDataAccess(); + drawImage(pos, vgpd->source.imageRef()); + vgpd->source.endDataAccess(); + } else { + drawImage(pos, *(pd->buffer())); + } } void QVGPaintEngine::drawImage diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index 732b484..c5da115 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -70,7 +70,7 @@ QVGPixmapData::QVGPixmapData(PixelType type) context = 0; qt_vg_register_pixmap(this); #endif - setSerialNumber(++qt_vg_pixmap_serial); + updateSerial(); } QVGPixmapData::~QVGPixmapData() @@ -138,25 +138,31 @@ bool QVGPixmapData::isValid() const return (w > 0 && h > 0); } +void QVGPixmapData::updateSerial() +{ + setSerialNumber(++qt_vg_pixmap_serial); +} + void QVGPixmapData::resize(int wid, int ht) { - if (w == wid && h == ht) + if (w == wid && h == ht) { + updateSerial(); return; + } w = wid; h = ht; d = 32; // We always use ARGB_Premultiplied for VG pixmaps. is_null = (w <= 0 || h <= 0); - source = QImage(); + source = QVolatileImage(); recreate = true; - setSerialNumber(++qt_vg_pixmap_serial); + updateSerial(); } -void QVGPixmapData::fromImage - (const QImage &image, Qt::ImageConversionFlags flags) +void QVGPixmapData::fromImage(const QImage &image, Qt::ImageConversionFlags flags) { - if(image.isNull()) + if (image.isNull()) return; QImage img = image; @@ -200,33 +206,34 @@ bool QVGPixmapData::fromData(const uchar *buffer, uint len, const char *format, return !isNull(); } -/*! - out-of-place conversion (inPlace == false) will always detach() - */ -void QVGPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) +QImage::Format QVGPixmapData::idealFormat(QImage *image, Qt::ImageConversionFlags flags) const { - if (image.size() == QSize(w, h)) - setSerialNumber(++qt_vg_pixmap_serial); - else - resize(image.width(), image.height()); - QImage::Format format = sourceFormat(); - int d = image.depth(); - if (d == 1 || d == 16 || d == 24 || (d == 32 && !image.hasAlphaChannel())) + int d = image->depth(); + if (d == 1 || d == 16 || d == 24 || (d == 32 && !image->hasAlphaChannel())) format = QImage::Format_RGB32; - else if (!(flags & Qt::NoOpaqueDetection) && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels()) + else if (!(flags & Qt::NoOpaqueDetection) && image->data_ptr()->checkForAlphaPixels()) format = sourceFormat(); else - format = image.hasAlphaChannel() ? sourceFormat() : QImage::Format_RGB32; + format = image->hasAlphaChannel() ? sourceFormat() : QImage::Format_RGB32; + return format; +} + +void QVGPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) +{ + resize(image.width(), image.height()); + + QImage::Format format = idealFormat(&image, flags); if (inPlace && image.data_ptr()->convertInPlace(format, flags)) { - source = image; + source = QVolatileImage(image); } else { - source = image.convertToFormat(format); - - // convertToFormat won't detach the image if format stays the same. - if (image.format() == format) - source.detach(); + QImage convertedImage = image.convertToFormat(format); + // convertToFormat won't detach the image if format stays the + // same. Detaching is needed to prevent issues with painting + // onto this QPixmap later on. + convertedImage.detach(); + source = QVolatileImage(convertedImage); } recreate = true; @@ -238,12 +245,13 @@ void QVGPixmapData::fill(const QColor &color) return; if (source.isNull()) - source = QImage(w, h, sourceFormat()); + source = QVolatileImage(w, h, sourceFormat()); if (source.depth() == 1) { // Pick the best approximate color in the image's colortable. int gray = qGray(color.rgba()); - if (qAbs(qGray(source.color(0)) - gray) < qAbs(qGray(source.color(1)) - gray)) + if (qAbs(qGray(source.imageRef().color(0)) - gray) + < qAbs(qGray(source.imageRef().color(1)) - gray)) source.fill(0); else source.fill(1); @@ -266,7 +274,7 @@ bool QVGPixmapData::hasAlphaChannel() const void QVGPixmapData::setAlphaChannel(const QPixmap &alphaChannel) { forceToImage(); - source.setAlphaChannel(alphaChannel.toImage()); + source.setAlphaChannel(alphaChannel); } QImage QVGPixmapData::toImage() const @@ -275,17 +283,41 @@ QImage QVGPixmapData::toImage() const return QImage(); if (source.isNull()) { - source = QImage(w, h, sourceFormat()); + source = QVolatileImage(w, h, sourceFormat()); recreate = true; } - return source; + return source.toImage(); +} + +void QVGPixmapData::copy(const QPixmapData *data, const QRect &rect) +{ + // toImage() is potentially expensive with QVolatileImage so provide a + // more efficient implementation of copy() that does not rely on it. + if (!data) { + return; + } + if (data->classId() != OpenVGClass) { + fromImage(data->toImage(rect), Qt::NoOpaqueDetection); + return; + } + const QVGPixmapData *pd = static_cast<const QVGPixmapData *>(data); + QRect r = rect; + if (r.isNull() || r.contains(QRect(0, 0, pd->w, pd->h))) { + r = QRect(0, 0, pd->w, pd->h); + } + resize(r.width(), r.height()); + recreate = true; + if (!pd->source.isNull()) { + source = QVolatileImage(r.width(), r.height(), pd->source.format()); + source.copyFrom(&pd->source, r); + } } QImage *QVGPixmapData::buffer() { - forceToImage(); - return &source; + // Cannot be safely implemented and QVGPixmapData is not (must not be) RasterClass anyway. + return 0; } QPaintEngine* QVGPixmapData::paintEngine() const @@ -329,10 +361,12 @@ VGImage QVGPixmapData::toVGImage() } if (!source.isNull() && recreate) { + source.beginDataAccess(); vgImageSubData (vgImage, source.constBits(), source.bytesPerLine(), qt_vg_image_to_vg_format(source.format()), 0, 0, w, h); + source.endDataAccess(true); } recreate = false; @@ -442,14 +476,14 @@ int QVGPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const } } -// Force the pixmap data to be in QImage format. +// Force the pixmap data to be backed by some valid data. void QVGPixmapData::forceToImage() { if (!isValid()) return; if (source.isNull()) - source = QImage(w, h, sourceFormat()); + source = QVolatileImage(w, h, sourceFormat()); recreate = true; } diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index 58e69db..c4fd47f 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -54,6 +54,7 @@ // #include <QtGui/private/qpixmap_raster_p.h> +#include <QtGui/private/qvolatileimage_p.h> #include <private/qvg_p.h> #if defined(Q_OS_SYMBIAN) @@ -99,6 +100,7 @@ public: bool hasAlphaChannel() const; void setAlphaChannel(const QPixmap &alphaChannel); QImage toImage() const; + void copy(const QPixmapData *data, const QRect &rect); QImage *buffer(); QPaintEngine* paintEngine() const; @@ -161,7 +163,7 @@ protected: VGImage vgImage; VGImage vgImageOpacity; qreal cachedOpacity; - mutable QImage source; + mutable QVolatileImage source; mutable bool recreate; bool inImagePool; #if !defined(QT_NO_EGL) @@ -170,6 +172,8 @@ protected: void forceToImage(); QImage::Format sourceFormat() const; + QImage::Format idealFormat(QImage *image, Qt::ImageConversionFlags flags) const; + void updateSerial(); void destroyImageAndContext(); void destroyImages(); diff --git a/src/openvg/qvg_symbian.cpp b/src/openvg/qvg_symbian.cpp index ff0ab13..22cbb3c 100644 --- a/src/openvg/qvg_symbian.cpp +++ b/src/openvg/qvg_symbian.cpp @@ -44,7 +44,6 @@ #include <private/qt_s60_p.h> #include <fbs.h> -#include <bitdev.h> #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE # include <sgresource/sgimage.h> @@ -75,34 +74,6 @@ VGImage QVG::vgCreateEGLImageTargetKHR(VGeglImageKHR eglImage) extern int qt_vg_pixmap_serial; -static CFbsBitmap* createBlitCopy(CFbsBitmap* bitmap) -{ - CFbsBitmap *copy = new CFbsBitmap; - Q_CHECK_PTR(copy); - if(!copy) - return 0; - - if (copy->Create(bitmap->SizeInPixels(), bitmap->DisplayMode()) != KErrNone) { - delete copy; - copy = 0; - - return 0; - } - - CFbsBitmapDevice* bitmapDevice = 0; - CFbsBitGc *bitmapGc = 0; - QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(copy)); - QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); - bitmapGc->Activate(bitmapDevice); - - bitmapGc->BitBlt(TPoint(), bitmap); - - delete bitmapGc; - delete bitmapDevice; - - return copy; -} - #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE static VGImage sgImageToVGImage(QEglContext *context, const RSgImage &sgImage) { @@ -137,7 +108,7 @@ void QVGPixmapData::cleanup() { is_null = w = h = 0; recreate = false; - source = QImage(); + source = QVolatileImage(); } void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) @@ -156,55 +127,28 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) } is_null = (w <= 0 || h <= 0); - source = QImage(); // vgGetImageSubData() some day? + source = QVolatileImage(); // vgGetImageSubData() some day? recreate = false; prevSize = QSize(w, h); - //setSerialNumber(++qt_vg_pixmap_serial); + updateSerial(); #endif - } else if (type == QPixmapData::FbsBitmap) { - CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap); - - bool deleteSourceBitmap = false; -#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE - - // Rasterize extended bitmaps - - TUid extendedBitmapType = bitmap->ExtendedBitmapType(); - if (extendedBitmapType != KNullUid) { - bitmap = createBlitCopy(bitmap); - deleteSourceBitmap = true; - } -#endif - - if (bitmap->IsCompressedInRAM()) { - bitmap = createBlitCopy(bitmap); - deleteSourceBitmap = true; - } - - TDisplayMode displayMode = bitmap->DisplayMode(); - QImage::Format format = qt_TDisplayMode2Format(displayMode); - - TSize size = bitmap->SizeInPixels(); - int bytesPerLine = bitmap->ScanLineLength(size.iWidth, displayMode); - - bitmap->BeginDataAccess(); - uchar *bytes = (uchar*)bitmap->DataAddress(); - QImage img = QImage(bytes, size.iWidth, size.iHeight, bytesPerLine, format); - img = img.copy(); - bitmap->EndDataAccess(); - - if(displayMode == EGray2) { - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - img.invertPixels(); - } else if(displayMode == EColor16M) { - img = img.rgbSwapped(); // EColor16M is BGR - } - - fromImage(img, Qt::AutoColor); - - if(deleteSourceBitmap) - delete bitmap; + } else if (type == QPixmapData::FbsBitmap && pixmap) { + CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap *>(pixmap); + QSize size(bitmap->SizeInPixels().iWidth, bitmap->SizeInPixels().iHeight); + resize(size.width(), size.height()); + source = QVolatileImage(bitmap); // duplicates only, if possible + if (source.isNull()) + return; + // Here we may need to copy if the formats do not match. + // (e.g. for display modes other than EColor16MAP and EColor16MU) + source.ensureFormat(idealFormat(&source.imageRef(), Qt::AutoColor)); + recreate = true; + } else if (type == QPixmapData::VolatileImage && pixmap) { + QVolatileImage *img = static_cast<QVolatileImage *>(pixmap); + resize(img->width(), img->height()); + source = *img; + source.ensureFormat(idealFormat(&source.imageRef(), Qt::AutoColor)); + recreate = true; } } @@ -271,27 +215,14 @@ void* QVGPixmapData::toNativeType(NativeType type) driver.Close(); return reinterpret_cast<void*>(sgImage.take()); #endif - } else if (type == QPixmapData::FbsBitmap) { - CFbsBitmap *bitmap = new CFbsBitmap; - Q_CHECK_PTR(bitmap); - - if (bitmap) { - if (bitmap->Create(TSize(source.width(), source.height()), - EColor16MAP) == KErrNone) { - const uchar *sptr = const_cast<const QImage&>(source).bits(); - bitmap->BeginDataAccess(); - - uchar *dptr = (uchar*)bitmap->DataAddress(); - Mem::Copy(dptr, sptr, source.byteCount()); - - bitmap->EndDataAccess(); - } else { - delete bitmap; - bitmap = 0; - } + } else if (type == QPixmapData::FbsBitmap && isValid()) { + if (source.isNull()) { + source = QVolatileImage(w, h, sourceFormat()); } - - return reinterpret_cast<void*>(bitmap); + // Just duplicate the bitmap handle, no data copying happens. + return source.duplicateNativeImage(); + } else if (type == QPixmapData::VolatileImage) { + return &source; } return 0; } diff --git a/src/openvg/qvgfontglyphcache_p.h b/src/openvg/qvgfontglyphcache_p.h index 9a105ec..ce12301 100644 --- a/src/openvg/qvgfontglyphcache_p.h +++ b/src/openvg/qvgfontglyphcache_p.h @@ -56,7 +56,7 @@ #include <QtCore/qvarlengtharray.h> #include <QtGui/private/qfontengine_p.h> -#include <qvg_p.h> +#include "qvg_p.h" QT_BEGIN_NAMESPACE diff --git a/src/openvg/qvgimagepool.cpp b/src/openvg/qvgimagepool.cpp index a2b1c4e..7a7ec78 100644 --- a/src/openvg/qvgimagepool.cpp +++ b/src/openvg/qvgimagepool.cpp @@ -175,8 +175,19 @@ bool QVGImagePool::reclaimSpace(VGImageFormat format, void QVGImagePool::hibernate() { - // Nothing to do here at the moment since the pool does not - // retain VGImage's after they have been released. + Q_D(QVGImagePool); + QVGPixmapData *pd = d->lruLast; + while (pd) { + QVGPixmapData *prevLRU = pd->prevLRU; + pd->inImagePool = false; + pd->inLRU = false; + pd->nextLRU = 0; + pd->prevLRU = 0; + pd->hibernate(); + pd = prevLRU; + } + d->lruFirst = 0; + d->lruLast = 0; } void QVGImagePool::moveToHeadOfLRU(QVGPixmapData *data) diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index 30d6b50..6b37b38 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -213,6 +213,11 @@ void QNetworkManagerEngine::connectToId(const QString &id) dbusDevicePath = devicePath.path(); break; } + else if (device.deviceType() == DEVICE_TYPE_GSM && + connectionType == QLatin1String("gsm")) { + dbusDevicePath = devicePath.path(); + break; + } } const QString service = connection->connectionInterface()->service(); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index 50e0f5f..eaff74a 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -245,10 +245,9 @@ bool QDirectFBPixmapData::fromDataBufferDescription(const DFBDataBufferDescripti QDirectFBPointer<IDirectFBDataBuffer> dataBuffer(dataBufferPtr); IDirectFBImageProvider *providerPtr; - if ((result = dataBuffer->CreateImageProvider(dataBuffer.data(), &providerPtr)) != DFB_OK) { - DirectFBError("QDirectFBPixmapData::fromDataBufferDescription(): Can't create image provider", result); + if ((result = dataBuffer->CreateImageProvider(dataBuffer.data(), &providerPtr)) != DFB_OK) return false; - } + QDirectFBPointer<IDirectFBImageProvider> provider(providerPtr); DFBImageDescription imageDescription; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp index 09cc465..ff15078 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -1285,7 +1285,7 @@ bool QDirectFBScreen::connect(const QString &displaySpec) result = d_ptr->primarySurface->GetSize(d_ptr->primarySurface, &w, &h); #elif (Q_DIRECTFB_VERSION >= 0x010000) IDirectFBSurface *layerSurface; - if (d_ptr->dfbLayer->GetSurface(d_ptr->dfbLayer, &layerSurface) != DFB_OK) { + if (d_ptr->dfbLayer->GetSurface(d_ptr->dfbLayer, &layerSurface) == DFB_OK) { result = layerSurface->GetSize(layerSurface, &w, &h); layerSurface->Release(layerSurface); } diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index d0056a7..3d8cf50 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -55,7 +55,6 @@ QT_BEGIN_NAMESPACE QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr) : QDirectFBPaintDevice(scr) - , sibling(0) #ifndef QT_NO_DIRECTFB_WM , dfbWindow(0) #endif @@ -75,7 +74,6 @@ QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirect QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr, QWidget *widget) : QWSWindowSurface(widget), QDirectFBPaintDevice(scr) - , sibling(0) #ifndef QT_NO_DIRECTFB_WM , dfbWindow(0) #endif @@ -123,7 +121,7 @@ void QDirectFBWindowSurface::raise() IDirectFBWindow *QDirectFBWindowSurface::directFBWindow() const { - return (dfbWindow ? dfbWindow : (sibling ? sibling->dfbWindow : 0)); + return dfbWindow; } void QDirectFBWindowSurface::createWindow(const QRect &rect) @@ -287,17 +285,40 @@ void QDirectFBWindowSurface::setGeometry(const QRect &rect) QByteArray QDirectFBWindowSurface::permanentState() const { - QByteArray state(sizeof(this), 0); - *reinterpret_cast<const QDirectFBWindowSurface**>(state.data()) = this; + QByteArray state(sizeof(SurfaceFlags) + sizeof(DFBWindowID), 0); + char *ptr = state.data(); + SurfaceFlags flags = surfaceFlags(); + memcpy(ptr, &flags, sizeof(SurfaceFlags)); + ptr += sizeof(SurfaceFlags); + DFBWindowID did = (DFBWindowID)(-1); + if (dfbWindow) + dfbWindow->GetID(dfbWindow, &did); + memcpy(ptr, &did, sizeof(DFBWindowID)); return state; } void QDirectFBWindowSurface::setPermanentState(const QByteArray &state) { - if (state.size() == sizeof(this)) { - sibling = *reinterpret_cast<QDirectFBWindowSurface *const*>(state.constData()); - Q_ASSERT(sibling); - setSurfaceFlags(sibling->surfaceFlags()); + const char *ptr = state.constData(); + IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer(); + SurfaceFlags flags; + memcpy(&flags, ptr, sizeof(SurfaceFlags)); + + setSurfaceFlags(flags); + ptr += sizeof(SurfaceFlags); + DFBWindowID id; + memcpy(&id, ptr, sizeof(DFBWindowID)); + if (dfbSurface) + dfbSurface->Release(dfbSurface); + if (id != (DFBWindowID)-1) { + IDirectFBWindow *dw; + layer->GetWindow(layer, id, &dw); + if (dw->GetSurface(dw, &dfbSurface) != DFB_OK) + dfbSurface = 0; + dw->Release(dw); + } + else { + dfbSurface = 0; } } @@ -406,8 +427,6 @@ void QDirectFBWindowSurface::endPaint(const QRegion &) IDirectFBSurface *QDirectFBWindowSurface::directFBSurface() const { - if (!dfbSurface && sibling && sibling->dfbSurface) - return sibling->dfbSurface; return dfbSurface; } @@ -415,11 +434,8 @@ IDirectFBSurface *QDirectFBWindowSurface::directFBSurface() const IDirectFBSurface *QDirectFBWindowSurface::surfaceForWidget(const QWidget *widget, QRect *rect) const { Q_ASSERT(widget); - if (!dfbSurface) { - if (sibling && (!sibling->sibling || sibling->dfbSurface)) - return sibling->surfaceForWidget(widget, rect); + if (!dfbSurface) return 0; - } QWidget *win = window(); Q_ASSERT(win); if (rect) { diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h index f683fc8..75d462b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h @@ -100,7 +100,6 @@ private: void updateIsOpaque(); void setOpaque(bool opaque); void releaseSurface(); - QDirectFBWindowSurface *sibling; #ifdef QT_DIRECTFB_WM void createWindow(const QRect &rect); diff --git a/src/plugins/graphicssystems/meego/dithering.cpp b/src/plugins/graphicssystems/meego/dithering.cpp index 91e3337..2561c22 100644 --- a/src/plugins/graphicssystems/meego/dithering.cpp +++ b/src/plugins/graphicssystems/meego/dithering.cpp @@ -39,15 +39,22 @@ ** ****************************************************************************/ -// This is an implementation of the 32bit => 16bit Floyd-Steinberg dithering. +// Implements two dithering methods: +// +// * convertRGBA32_to_RGB565 +// +// This is implemented using Ordered Bayer Dithering. The code has been adapted +// from QX11PixmapData::fromImage. This method was originally implemented using +// Floyd-Steinberg dithering but was later changed to Ordered Dithering because +// of the better quality of the results. +// +// * convertRGBA32_to_RGBA4444 +// +// This is implemented using Floyd-Steinberg dithering. +// // The alghorithm used here is not the fastest possible but it's prolly fast enough: // uses look-up tables, integer-only arthmetics and works in one pass on two lines // at a time. It's a high-quality dithering using 1/8 diffusion precission. -// Two functions here to look at: -// -// * convertRGBA32_to_RGB565 -// * convertRGBA32_to_RGBA4444 -// // Each channel (RGBA) is diffused independently and alpha is dithered too. #include <string.h> @@ -76,113 +83,63 @@ // Converts incoming RGB32 (QImage::Format_RGB32) to RGB565. Returns the newly allocated data. unsigned short* convertRGB32_to_RGB565(const unsigned char *in, int width, int height, int stride) { + static bool thresholdMapInitialized = false; + static int thresholdMap[16][16]; + + if (!thresholdMapInitialized) { + int i; + int j; + int n; + + thresholdMap[0][0] = 0; + thresholdMap[1][0] = 2; + thresholdMap[0][1] = 3; + thresholdMap[1][1] = 1; + + for (n=2; n<16; n*=2) { + for (i=0; i<n; i++) { + for (j=0; j<n; j++) { + thresholdMap[i][j] *= 4; + thresholdMap[i+n][j] = thresholdMap[i][j] + 2; + thresholdMap[i][j+n] = thresholdMap[i][j] + 3; + thresholdMap[i+n][j+n] = thresholdMap[i][j] + 1; + } + } + } + + thresholdMapInitialized = true; + } + // Output line stride. Aligned to 4 bytes. int alignedWidth = width; if (alignedWidth % 2 > 0) alignedWidth++; // Will store output - unsigned short *out = (unsigned short *) malloc(alignedWidth * height * 2); - - // Lookup tables for the 8bit => 6bit and 8bit => 5bit conversion - unsigned char lookup_8bit_to_5bit[256]; - short lookup_8bit_to_5bit_diff[256]; - unsigned char lookup_8bit_to_6bit[256]; - short lookup_8bit_to_6bit_diff[256]; - - // Macros for the conversion using the lookup table. - #define CONVERT_8BIT_TO_5BIT(v) (lookup_8bit_to_5bit[v]) - #define DIFF_8BIT_TO_5BIT(v) (lookup_8bit_to_5bit_diff[v]) - - #define CONVERT_8BIT_TO_6BIT(v) (lookup_8bit_to_6bit[v]) - #define DIFF_8BIT_TO_6BIT(v) (lookup_8bit_to_6bit_diff[v]) - - int i; - int x, y, c; // Pixel we're processing. c is component number (0, 1, 2 for r, b, b) - short component[3]; // Stores the new components (r, g, b) for pixel produced during conversion - short diff; // The difference between the converted value and the original one. To be accumulated. - QVarLengthArray <short> accumulatorData(3 * width * 2); // Data for three acumulators for r, g, b. Each accumulator is two lines. - short *accumulator[3]; // Helper for accessing the accumulator on a per-channel basis more easily. - accumulator[0] = accumulatorData.data(); - accumulator[1] = accumulatorData.data() + width; - accumulator[2] = accumulatorData.data() + (width * 2); - - // Produce the conversion lookup tables. - for (i = 0; i < 256; i++) { - lookup_8bit_to_5bit[i] = round(i / 8.0); - - // Before bitshifts: (i * 8) - (... * 8 * 8) - lookup_8bit_to_5bit_diff[i] = (i << 3) - (lookup_8bit_to_5bit[i] << 6); - if (lookup_8bit_to_5bit[i] > 31) - lookup_8bit_to_5bit[i] -= 1; - - lookup_8bit_to_6bit[i] = round(i / 4.0); - - // Before bitshifts: (i * 8) - (... * 4 * 8) - lookup_8bit_to_6bit_diff[i] = (i << 3) - (lookup_8bit_to_6bit[i] << 5); - if (lookup_8bit_to_6bit[i] > 63) - lookup_8bit_to_6bit[i] -= 1; - } + unsigned short *out = (unsigned short *)malloc (alignedWidth * height * 2); - // Clear the accumulators - memset(accumulator[0], 0, width * 4); - memset(accumulator[1], 0, width * 4); - memset(accumulator[2], 0, width * 4); + int x; + int y; + int threshold; // For each line... for (y = 0; y < height; y++) { - // For each accumulator, move the second line (index 1) to replace the first line (index 0). - // Clear the second line (index 1) - memcpy(accumulator[0], accumulator[0] + width, width * 2); - memset(accumulator[0] + width, 0, width * 2); - - memcpy(accumulator[1], accumulator[1] + width, width * 2); - memset(accumulator[1] + width, 0, width * 2); - - memcpy(accumulator[2], accumulator[2] + width, width * 2); - memset(accumulator[2] + width, 0, width * 2); - // For each column.... for (x = 0; x < width; x++) { - // For each component (r, g, b)... - for (c = 0; c < 3; c++) { + int r = GET_RGBA_COMPONENT(in, x, y, stride, 0); + int g = GET_RGBA_COMPONENT(in, x, y, stride, 1); + int b = GET_RGBA_COMPONENT(in, x, y, stride, 2); - // Get the 8bit value from the original image - component[c] = GET_RGBA_COMPONENT(in, x, y, stride, c); - - // Add the diffusion for this pixel we stored in the accumulator. - // >> 7 because the values in accumulator are stored * 128 - if (x != 0 && x != (width - 1)) { - if (accumulator[c][x] >> 7 != 0) - component[c] += rand() % accumulator[c][x] >> 7; - } - - // Make sure we're not over the boundaries. - CLAMP_256(component[c]); - - // For green component we use 6 bits. Otherwise 5 bits. - // Store the difference from converting 8bit => 6 bit and the orig pixel. - // Convert 8bit => 6(5) bit. - if (c == 1) { - diff = DIFF_8BIT_TO_6BIT(component[c]); - component[c] = CONVERT_8BIT_TO_6BIT(component[c]); - } else { - diff = DIFF_8BIT_TO_5BIT(component[c]); - component[c] = CONVERT_8BIT_TO_5BIT(component[c]); - } + threshold = thresholdMap[x%16][y%16]; - // Distribute the difference according to the matrix in the - // accumulation bufffer. - ACCUMULATE(accumulator[c], x + 1, 0, width, diff * 3); - ACCUMULATE(accumulator[c], x - 1, 1, width, diff * 5); - ACCUMULATE(accumulator[c], x, 1, width, diff * 5); - ACCUMULATE(accumulator[c], x + 1, 1, width, diff * 3); - } + if (r <= (255-(1<<3)) && ((r<<5) & 255) > threshold) r += (1<<3); + if (g <= (255-(1<<2)) && ((g<<6) & 255) > threshold) g += (1<<2); + if (b <= (255-(1<<3)) && ((b<<5) & 255) > threshold) b += (1<<3); // Write the newly produced pixel - PUT_565(out, x, y, alignedWidth, component[2], component[1], component[0]); + PUT_565(out, x, y, alignedWidth, ((b >> 3) & 0x1f), ((g >> 2) & 0x3f), ((r >> 3) & 0x1f)); } } diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp index 0c107b5..1da58e1 100644 --- a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp +++ b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp @@ -42,6 +42,7 @@ #include "qgraphicssystem_vg_p.h" #include <QtOpenVG/private/qpixmapdata_vg_p.h> #include <QtOpenVG/private/qwindowsurface_vg_p.h> +#include <QtOpenVG/private/qvgimagepool_p.h> #if defined(Q_OS_SYMBIAN) && !defined(Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE) #include <QtGui/private/qwidget_p.h> #endif @@ -77,4 +78,9 @@ QWindowSurface *QVGGraphicsSystem::createWindowSurface(QWidget *widget) const return new QVGWindowSurface(widget); } +void QVGGraphicsSystem::releaseCachedResources() +{ + QVGImagePool::instance()->hibernate(); +} + QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h index d1bce28..9c9b3e2 100644 --- a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h +++ b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h @@ -64,6 +64,8 @@ public: QPixmapData *createPixmapData(QPixmapData::PixelType type) const; QWindowSurface *createWindowSurface(QWidget *widget) const; + + void releaseCachedResources(); }; QT_END_NAMESPACE diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index 5aa26d3..701207d 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -559,6 +559,8 @@ QImage ICOReader::iconAt(int index) icoAttrib.ncolors = 0; else // # colors used icoAttrib.ncolors = header.biClrUsed ? header.biClrUsed : 1 << icoAttrib.nbits; + if (icoAttrib.ncolors > 256) //color table can't be more than 256 + return img; icoAttrib.w = iconEntry.bWidth; if (icoAttrib.w == 0) icoAttrib.w = header.biWidth; diff --git a/src/qbase.pri b/src/qbase.pri index 4d835bd..ce69757 100644 --- a/src/qbase.pri +++ b/src/qbase.pri @@ -197,7 +197,7 @@ symbian { # Partial upgrade SIS file vendorinfo = \ "; Localised Vendor name" \ - "%{\"Nokia, Qt\"}" \ + "%{\"Nokia\"}" \ " " \ "; Unique Vendor name" \ ":\"Nokia, Qt\"" \ diff --git a/src/s60installs/bwins/QtDeclarativeu.def b/src/s60installs/bwins/QtDeclarativeu.def index 7d0a83e..8b23b63 100644 --- a/src/s60installs/bwins/QtDeclarativeu.def +++ b/src/s60installs/bwins/QtDeclarativeu.def @@ -3,7 +3,7 @@ EXPORTS ?setStored@QMetaPropertyBuilder@@QAEX_N@Z @ 2 NONAME ABSENT ; void QMetaPropertyBuilder::setStored(bool) ?trUtf8@QDeclarativeExpression@@SA?AVQString@@PBD0H@Z @ 3 NONAME ; class QString QDeclarativeExpression::trUtf8(char const *, char const *, int) ?qt_metacast@QDeclarativeComponent@@UAEPAXPBD@Z @ 4 NONAME ; void * QDeclarativeComponent::qt_metacast(char const *) - ?name@QDeclarativeDebugService@@QBE?AVQString@@XZ @ 5 NONAME ABSENT ; class QString QDeclarativeDebugService::name(void) const + ?name@QDeclarativeDebugService@@QBE?AVQString@@XZ @ 5 NONAME ; class QString QDeclarativeDebugService::name(void) const ?debugId@QDeclarativeDebugObjectReference@@QBEHXZ @ 6 NONAME ABSENT ; int QDeclarativeDebugObjectReference::debugId(void) const ?addPluginPath@QDeclarativeEngine@@QAEXABVQString@@@Z @ 7 NONAME ; void QDeclarativeEngine::addPluginPath(class QString const &) ?name@QMetaPropertyBuilder@@QBE?AVQByteArray@@XZ @ 8 NONAME ABSENT ; class QByteArray QMetaPropertyBuilder::name(void) const @@ -11,7 +11,7 @@ EXPORTS ?propertyOffset@QDeclarativeOpenMetaObjectType@@QBEHXZ @ 10 NONAME ABSENT ; int QDeclarativeOpenMetaObjectType::propertyOffset(void) const ??0QDeclarativeText@@QAE@PAVQDeclarativeItem@@@Z @ 11 NONAME ABSENT ; QDeclarativeText::QDeclarativeText(class QDeclarativeItem *) ?propertyTypeName@QDeclarativeProperty@@QBEPBDXZ @ 12 NONAME ; char const * QDeclarativeProperty::propertyTypeName(void) const - ?getStaticMetaObject@QDeclarativeDebugService@@SAABUQMetaObject@@XZ @ 13 NONAME ABSENT ; struct QMetaObject const & QDeclarativeDebugService::getStaticMetaObject(void) + ?getStaticMetaObject@QDeclarativeDebugService@@SAABUQMetaObject@@XZ @ 13 NONAME ; struct QMetaObject const & QDeclarativeDebugService::getStaticMetaObject(void) ?setLeft@QDeclarativeAnchors@@QAEXABVQDeclarativeAnchorLine@@@Z @ 14 NONAME ABSENT ; void QDeclarativeAnchors::setLeft(class QDeclarativeAnchorLine const &) ?qt_metacall@QDeclarativeExpression@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 15 NONAME ; int QDeclarativeExpression::qt_metacall(enum QMetaObject::Call, int, void * *) ?staticMetaObject@QDeclarativePen@@2UQMetaObject@@B @ 16 NONAME ABSENT ; struct QMetaObject const QDeclarativePen::staticMetaObject @@ -145,7 +145,7 @@ EXPORTS ?isConnected@QDeclarativeDebugClient@@QBE_NXZ @ 144 NONAME ABSENT ; bool QDeclarativeDebugClient::isConnected(void) const ?enabled@QDeclarativeBinding@@QBE_NXZ @ 145 NONAME ABSENT ; bool QDeclarativeBinding::enabled(void) const ?setSource@QDeclarativeView@@QAEXABVQUrl@@@Z @ 146 NONAME ; void QDeclarativeView::setSource(class QUrl const &) - ??_EQDeclarativeDebugService@@UAE@I@Z @ 147 NONAME ABSENT ; QDeclarativeDebugService::~QDeclarativeDebugService(unsigned int) + ??_EQDeclarativeDebugService@@UAE@I@Z @ 147 NONAME ; QDeclarativeDebugService::~QDeclarativeDebugService(unsigned int) ??0QDeclarativeDomDynamicProperty@@QAE@ABV0@@Z @ 148 NONAME ABSENT ; QDeclarativeDomDynamicProperty::QDeclarativeDomDynamicProperty(class QDeclarativeDomDynamicProperty const &) ?className@QDeclarativeDebugObjectReference@@QBE?AVQString@@XZ @ 149 NONAME ABSENT ; class QString QDeclarativeDebugObjectReference::className(void) const ?indexOfSlot@QMetaObjectBuilder@@QAEHABVQByteArray@@@Z @ 150 NONAME ABSENT ; int QMetaObjectBuilder::indexOfSlot(class QByteArray const &) @@ -294,7 +294,7 @@ EXPORTS ?attachedPropertiesType@QDeclarativeType@@QBEPBUQMetaObject@@XZ @ 293 NONAME ABSENT ; struct QMetaObject const * QDeclarativeType::attachedPropertiesType(void) const ?setName@QDeclarativeState@@QAEXABVQString@@@Z @ 294 NONAME ; void QDeclarativeState::setName(class QString const &) ?setReversed@QDeclarativeTransition@@QAEX_N@Z @ 295 NONAME ; void QDeclarativeTransition::setReversed(bool) - ?idForObject@QDeclarativeDebugService@@SAHPAVQObject@@@Z @ 296 NONAME ABSENT ; int QDeclarativeDebugService::idForObject(class QObject *) + ?idForObject@QDeclarativeDebugService@@SAHPAVQObject@@@Z @ 296 NONAME ; int QDeclarativeDebugService::idForObject(class QObject *) ?qt_metacall@QDeclarativeDebugWatch@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 297 NONAME ABSENT ; int QDeclarativeDebugWatch::qt_metacall(enum QMetaObject::Call, int, void * *) ?fromState@QDeclarativeTransition@@QBE?AVQString@@XZ @ 298 NONAME ; class QString QDeclarativeTransition::fromState(void) const ??1QDeclarativeExpression@@UAE@XZ @ 299 NONAME ; QDeclarativeExpression::~QDeclarativeExpression(void) @@ -332,7 +332,7 @@ EXPORTS ??0QDeclarativeCustomParserNode@@QAE@ABV0@@Z @ 331 NONAME ; QDeclarativeCustomParserNode::QDeclarativeCustomParserNode(class QDeclarativeCustomParserNode const &) ??1QDeclarativeImageProvider@@UAE@XZ @ 332 NONAME ; QDeclarativeImageProvider::~QDeclarativeImageProvider(void) ?sync@QDeclarativeListModel@@QAEXXZ @ 333 NONAME ABSENT ; void QDeclarativeListModel::sync(void) - ?objectForId@QDeclarativeDebugService@@SAPAVQObject@@H@Z @ 334 NONAME ABSENT ; class QObject * QDeclarativeDebugService::objectForId(int) + ?objectForId@QDeclarativeDebugService@@SAPAVQObject@@H@Z @ 334 NONAME ; class QObject * QDeclarativeDebugService::objectForId(int) ?hasFocus@QDeclarativeItem@@QBE_NXZ @ 335 NONAME ; bool QDeclarativeItem::hasFocus(void) const ??1QDeclarativeExtensionPlugin@@UAE@XZ @ 336 NONAME ; QDeclarativeExtensionPlugin::~QDeclarativeExtensionPlugin(void) ?qt_metacall@QDeclarativeBehavior@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 337 NONAME ABSENT ; int QDeclarativeBehavior::qt_metacall(enum QMetaObject::Call, int, void * *) @@ -482,7 +482,7 @@ EXPORTS ?pluginPathList@QDeclarativeEngine@@QBE?AVQStringList@@XZ @ 481 NONAME ; class QStringList QDeclarativeEngine::pluginPathList(void) const ?parentContext@QDeclarativeContext@@QBEPAV1@XZ @ 482 NONAME ; class QDeclarativeContext * QDeclarativeContext::parentContext(void) const ?leftMarginChanged@QDeclarativeAnchors@@IAEXXZ @ 483 NONAME ABSENT ; void QDeclarativeAnchors::leftMarginChanged(void) - ?staticMetaObject@QDeclarativeDebugService@@2UQMetaObject@@B @ 484 NONAME ABSENT ; struct QMetaObject const QDeclarativeDebugService::staticMetaObject + ?staticMetaObject@QDeclarativeDebugService@@2UQMetaObject@@B @ 484 NONAME ; struct QMetaObject const QDeclarativeDebugService::staticMetaObject ?topMargin@QDeclarativeAnchors@@QBEMXZ @ 485 NONAME ABSENT ; float QDeclarativeAnchors::topMargin(void) const ??0QDeclarativeDebugExpressionQuery@@AAE@PAVQObject@@@Z @ 486 NONAME ABSENT ; QDeclarativeDebugExpressionQuery::QDeclarativeDebugExpressionQuery(class QObject *) ??0QPacket@@IAE@ABVQByteArray@@@Z @ 487 NONAME ; QPacket::QPacket(class QByteArray const &) @@ -559,7 +559,7 @@ EXPORTS ?metaObject@QDeclarativeEngine@@UBEPBUQMetaObject@@XZ @ 558 NONAME ; struct QMetaObject const * QDeclarativeEngine::metaObject(void) const ??_EQDeclarativeDebugContextReference@@QAE@I@Z @ 559 NONAME ABSENT ; QDeclarativeDebugContextReference::~QDeclarativeDebugContextReference(unsigned int) ?propertyWrite@QDeclarativeOpenMetaObject@@MAEXH@Z @ 560 NONAME ABSENT ; void QDeclarativeOpenMetaObject::propertyWrite(int) - ?qt_metacall@QDeclarativeDebugService@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 561 NONAME ABSENT ; int QDeclarativeDebugService::qt_metacall(enum QMetaObject::Call, int, void * *) + ?qt_metacall@QDeclarativeDebugService@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 561 NONAME ; int QDeclarativeDebugService::qt_metacall(enum QMetaObject::Call, int, void * *) ?setVerticalCenterOffset@QDeclarativeAnchors@@QAEXM@Z @ 562 NONAME ABSENT ; void QDeclarativeAnchors::setVerticalCenterOffset(float) ??1QDeclarativeDebugWatch@@UAE@XZ @ 563 NONAME ABSENT ; QDeclarativeDebugWatch::~QDeclarativeDebugWatch(void) ??1QPacketAutoSend@@UAE@XZ @ 564 NONAME ABSENT ; QPacketAutoSend::~QPacketAutoSend(void) @@ -641,7 +641,7 @@ EXPORTS ?d_func@QDeclarativeItem@@AAEPAVQDeclarativeItemPrivate@@XZ @ 640 NONAME ; class QDeclarativeItemPrivate * QDeclarativeItem::d_func(void) ?binding@QDeclarativeDomValueBinding@@QBE?AVQString@@XZ @ 641 NONAME ABSENT ; class QString QDeclarativeDomValueBinding::binding(void) const ?updateAutoState@QDeclarativeStateGroup@@AAE_NXZ @ 642 NONAME ; bool QDeclarativeStateGroup::updateAutoState(void) - ?tr@QDeclarativeDebugService@@SA?AVQString@@PBD0@Z @ 643 NONAME ABSENT ; class QString QDeclarativeDebugService::tr(char const *, char const *) + ?tr@QDeclarativeDebugService@@SA?AVQString@@PBD0@Z @ 643 NONAME ; class QString QDeclarativeDebugService::tr(char const *, char const *) ?tr@QDeclarativeComponent@@SA?AVQString@@PBD0H@Z @ 644 NONAME ; class QString QDeclarativeComponent::tr(char const *, char const *, int) ??1QDeclarativeProperty@@QAE@XZ @ 645 NONAME ; QDeclarativeProperty::~QDeclarativeProperty(void) ?fontChanged@QDeclarativeText@@IAEXABVQFont@@@Z @ 646 NONAME ABSENT ; void QDeclarativeText::fontChanged(class QFont const &) @@ -667,14 +667,14 @@ EXPORTS ?getStaticMetaObject@QDeclarativeListModel@@SAABUQMetaObject@@XZ @ 666 NONAME ABSENT ; struct QMetaObject const & QDeclarativeListModel::getStaticMetaObject(void) ?setStdCppSet@QMetaPropertyBuilder@@QAEX_N@Z @ 667 NONAME ABSENT ; void QMetaPropertyBuilder::setStdCppSet(bool) ??0QDeclarativeItemPrivate@@QAE@XZ @ 668 NONAME ; QDeclarativeItemPrivate::QDeclarativeItemPrivate(void) - ??0QDeclarativeDebugService@@QAE@ABVQString@@PAVQObject@@@Z @ 669 NONAME ABSENT ; QDeclarativeDebugService::QDeclarativeDebugService(class QString const &, class QObject *) + ??0QDeclarativeDebugService@@QAE@ABVQString@@PAVQObject@@@Z @ 669 NONAME ; QDeclarativeDebugService::QDeclarativeDebugService(class QString const &, class QObject *) ?load@QDeclarativePixmap@@QAEXPAVQDeclarativeEngine@@ABVQUrl@@_N@Z @ 670 NONAME ABSENT ; void QDeclarativePixmap::load(class QDeclarativeEngine *, class QUrl const &, bool) ??_EQPacketAutoSend@@UAE@I@Z @ 671 NONAME ABSENT ; QPacketAutoSend::~QPacketAutoSend(unsigned int) ?saveValueType@QDeclarativePropertyPrivate@@SA?AVQByteArray@@PBUQMetaObject@@H0H@Z @ 672 NONAME ABSENT ; class QByteArray QDeclarativePropertyPrivate::saveValueType(struct QMetaObject const *, int, struct QMetaObject const *, int) ?resetHeight@QDeclarativeItem@@QAEXXZ @ 673 NONAME ; void QDeclarativeItem::resetHeight(void) ?setVAlign@QDeclarativeText@@QAEXW4VAlignment@1@@Z @ 674 NONAME ABSENT ; void QDeclarativeText::setVAlign(enum QDeclarativeText::VAlignment) - ??1QDeclarativeDebugService@@UAE@XZ @ 675 NONAME ABSENT ; QDeclarativeDebugService::~QDeclarativeDebugService(void) - ?trUtf8@QDeclarativeDebugService@@SA?AVQString@@PBD0H@Z @ 676 NONAME ABSENT ; class QString QDeclarativeDebugService::trUtf8(char const *, char const *, int) + ??1QDeclarativeDebugService@@UAE@XZ @ 675 NONAME ; QDeclarativeDebugService::~QDeclarativeDebugService(void) + ?trUtf8@QDeclarativeDebugService@@SA?AVQString@@PBD0H@Z @ 676 NONAME ; class QString QDeclarativeDebugService::trUtf8(char const *, char const *, int) ?elideMode@QDeclarativeText@@QBE?AW4TextElideMode@1@XZ @ 677 NONAME ABSENT ; enum QDeclarativeText::TextElideMode QDeclarativeText::elideMode(void) const ?baseUrl@QDeclarativeContext@@QBE?AVQUrl@@XZ @ 678 NONAME ; class QUrl QDeclarativeContext::baseUrl(void) const ?qt_metacall@QDeclarativeDebugRootContextQuery@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 679 NONAME ABSENT ; int QDeclarativeDebugRootContextQuery::qt_metacall(enum QMetaObject::Call, int, void * *) @@ -849,7 +849,7 @@ EXPORTS ??1QDeclarativeBehavior@@UAE@XZ @ 848 NONAME ABSENT ; QDeclarativeBehavior::~QDeclarativeBehavior(void) ?qmlInfo@@YA?AVQDeclarativeInfo@@PBVQObject@@@Z @ 849 NONAME ; class QDeclarativeInfo qmlInfo(class QObject const *) ?qt_metacall@QDeclarativeDebugClient@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 850 NONAME ABSENT ; int QDeclarativeDebugClient::qt_metacall(enum QMetaObject::Call, int, void * *) - ?d_func@QDeclarativeDebugService@@ABEPBVQDeclarativeDebugServicePrivate@@XZ @ 851 NONAME ABSENT ; class QDeclarativeDebugServicePrivate const * QDeclarativeDebugService::d_func(void) const + ?d_func@QDeclarativeDebugService@@ABEPBVQDeclarativeDebugServicePrivate@@XZ @ 851 NONAME ; class QDeclarativeDebugServicePrivate const * QDeclarativeDebugService::d_func(void) const ??1QDeclarativeDebugQuery@@UAE@XZ @ 852 NONAME ABSENT ; QDeclarativeDebugQuery::~QDeclarativeDebugQuery(void) ?data_append@QDeclarativeItemPrivate@@SAXPAV?$QDeclarativeListProperty@VQObject@@@@PAVQObject@@@Z @ 853 NONAME ; void QDeclarativeItemPrivate::data_append(class QDeclarativeListProperty<class QObject> *, class QObject *) ?tr@QDeclarativeState@@SA?AVQString@@PBD0@Z @ 854 NONAME ; class QString QDeclarativeState::tr(char const *, char const *) @@ -1120,7 +1120,7 @@ EXPORTS ?expression@QDeclarativeDebugExpressionQuery@@QBE?AVQVariant@@XZ @ 1119 NONAME ABSENT ; class QVariant QDeclarativeDebugExpressionQuery::expression(void) const ??4QDeclarativeDomList@@QAEAAV0@ABV0@@Z @ 1120 NONAME ABSENT ; class QDeclarativeDomList & QDeclarativeDomList::operator=(class QDeclarativeDomList const &) ?qt_metacall@QDeclarativeComponent@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1121 NONAME ; int QDeclarativeComponent::qt_metacall(enum QMetaObject::Call, int, void * *) - ?tr@QDeclarativeDebugService@@SA?AVQString@@PBD0H@Z @ 1122 NONAME ABSENT ; class QString QDeclarativeDebugService::tr(char const *, char const *, int) + ?tr@QDeclarativeDebugService@@SA?AVQString@@PBD0H@Z @ 1122 NONAME ; class QString QDeclarativeDebugService::tr(char const *, char const *, int) ?staticMetaObject@QDeclarativeEngine@@2UQMetaObject@@B @ 1123 NONAME ; struct QMetaObject const QDeclarativeEngine::staticMetaObject ?staticMetaObject@QDeclarativeStateOperation@@2UQMetaObject@@B @ 1124 NONAME ; struct QMetaObject const QDeclarativeStateOperation::staticMetaObject ?actions@QDeclarativeStateOperation@@UAE?AV?$QList@VQDeclarativeAction@@@@XZ @ 1125 NONAME ; class QList<class QDeclarativeAction> QDeclarativeStateOperation::actions(void) @@ -1145,7 +1145,7 @@ EXPORTS ?sourceFile@QDeclarativeExpression@@QBE?AVQString@@XZ @ 1144 NONAME ; class QString QDeclarativeExpression::sourceFile(void) const ??_EQDeclarativeAnchors@@UAE@I@Z @ 1145 NONAME ABSENT ; QDeclarativeAnchors::~QDeclarativeAnchors(unsigned int) ?removeNotifySignal@QMetaPropertyBuilder@@QAEXXZ @ 1146 NONAME ABSENT ; void QMetaPropertyBuilder::removeNotifySignal(void) - ?trUtf8@QDeclarativeDebugService@@SA?AVQString@@PBD0@Z @ 1147 NONAME ABSENT ; class QString QDeclarativeDebugService::trUtf8(char const *, char const *) + ?trUtf8@QDeclarativeDebugService@@SA?AVQString@@PBD0@Z @ 1147 NONAME ; class QString QDeclarativeDebugService::trUtf8(char const *, char const *) ?setImportPathList@QDeclarativeEngine@@QAEXABVQStringList@@@Z @ 1148 NONAME ; void QDeclarativeEngine::setImportPathList(class QStringList const &) ?enabledChanged@QDeclarativeDebugService@@MAEX_N@Z @ 1149 NONAME ABSENT ; void QDeclarativeDebugService::enabledChanged(bool) ?addWatch@QDeclarativeEngineDebug@@QAEPAVQDeclarativeDebugWatch@@ABVQDeclarativeDebugObjectReference@@PAVQObject@@@Z @ 1150 NONAME ABSENT ; class QDeclarativeDebugWatch * QDeclarativeEngineDebug::addWatch(class QDeclarativeDebugObjectReference const &, class QObject *) @@ -1176,7 +1176,7 @@ EXPORTS ?paint@QDeclarativeRectangle@@UAEXPAVQPainter@@PBVQStyleOptionGraphicsItem@@PAVQWidget@@@Z @ 1175 NONAME ABSENT ; void QDeclarativeRectangle::paint(class QPainter *, class QStyleOptionGraphicsItem const *, class QWidget *) ??6QDeclarativeState@@QAEAAV0@PAVQDeclarativeStateOperation@@@Z @ 1176 NONAME ; class QDeclarativeState & QDeclarativeState::operator<<(class QDeclarativeStateOperation *) ?destroy@QDeclarativeAbstractBinding@@UAEXXZ @ 1177 NONAME ABSENT ; void QDeclarativeAbstractBinding::destroy(void) - ?qt_metacast@QDeclarativeDebugService@@UAEPAXPBD@Z @ 1178 NONAME ABSENT ; void * QDeclarativeDebugService::qt_metacast(char const *) + ?qt_metacast@QDeclarativeDebugService@@UAEPAXPBD@Z @ 1178 NONAME ; void * QDeclarativeDebugService::qt_metacast(char const *) ?qt_metacast@QDeclarativeValueType@@UAEPAXPBD@Z @ 1179 NONAME ABSENT ; void * QDeclarativeValueType::qt_metacast(char const *) ?childAt@QDeclarativeItem@@QBEPAV1@MM@Z @ 1180 NONAME ; class QDeclarativeItem * QDeclarativeItem::childAt(float, float) const ?paintedWidth@QDeclarativeText@@QBEMXZ @ 1181 NONAME ABSENT ; float QDeclarativeText::paintedWidth(void) const @@ -1297,7 +1297,7 @@ EXPORTS ?value@QDeclarativeOpenMetaObject@@QBE?AVQVariant@@H@Z @ 1296 NONAME ABSENT ; class QVariant QDeclarativeOpenMetaObject::value(int) const ?tr@QDeclarativeDebugRootContextQuery@@SA?AVQString@@PBD0H@Z @ 1297 NONAME ABSENT ; class QString QDeclarativeDebugRootContextQuery::tr(char const *, char const *, int) ?setFromState@QDeclarativeTransition@@QAEXABVQString@@@Z @ 1298 NONAME ; void QDeclarativeTransition::setFromState(class QString const &) - ?metaObject@QDeclarativeDebugService@@UBEPBUQMetaObject@@XZ @ 1299 NONAME ABSENT ; struct QMetaObject const * QDeclarativeDebugService::metaObject(void) const + ?metaObject@QDeclarativeDebugService@@UBEPBUQMetaObject@@XZ @ 1299 NONAME ; struct QMetaObject const * QDeclarativeDebugService::metaObject(void) const ?state@QDeclarativeDebugQuery@@QBE?AW4State@1@XZ @ 1300 NONAME ABSENT ; enum QDeclarativeDebugQuery::State QDeclarativeDebugQuery::state(void) const ?setBottom@QDeclarativeScaleGrid@@QAEXH@Z @ 1301 NONAME ABSENT ; void QDeclarativeScaleGrid::setBottom(int) ?topMarginChanged@QDeclarativeAnchors@@IAEXXZ @ 1302 NONAME ABSENT ; void QDeclarativeAnchors::topMarginChanged(void) @@ -1305,7 +1305,7 @@ EXPORTS ?position@QDeclarativeDomObject@@QBEHXZ @ 1304 NONAME ABSENT ; int QDeclarativeDomObject::position(void) const ?update@QDeclarativeBinding@@UAEXV?$QFlags@W4WriteFlag@QDeclarativePropertyPrivate@@@@@Z @ 1305 NONAME ABSENT ; void QDeclarativeBinding::update(class QFlags<enum QDeclarativePropertyPrivate::WriteFlag>) ?tr@QDeclarativeBehavior@@SA?AVQString@@PBD0@Z @ 1306 NONAME ABSENT ; class QString QDeclarativeBehavior::tr(char const *, char const *) - ?isDebuggingEnabled@QDeclarativeDebugService@@SA_NXZ @ 1307 NONAME ABSENT ; bool QDeclarativeDebugService::isDebuggingEnabled(void) + ?isDebuggingEnabled@QDeclarativeDebugService@@SA_NXZ @ 1307 NONAME ; bool QDeclarativeDebugService::isDebuggingEnabled(void) ?tr@QDeclarativeText@@SA?AVQString@@PBD0H@Z @ 1308 NONAME ABSENT ; class QString QDeclarativeText::tr(char const *, char const *, int) ?reset@QDeclarativeProperty@@QBE_NXZ @ 1309 NONAME ; bool QDeclarativeProperty::reset(void) const ?objectDebugId@QDeclarativeDebugWatch@@QBEHXZ @ 1310 NONAME ABSENT ; int QDeclarativeDebugWatch::objectDebugId(void) const @@ -1344,7 +1344,7 @@ EXPORTS ?maximumPacketSize@QPacketProtocol@@QBEHXZ @ 1343 NONAME ; int QPacketProtocol::maximumPacketSize(void) const ??_EQDeclarativeDebuggerStatus@@UAE@I@Z @ 1344 NONAME ABSENT ; QDeclarativeDebuggerStatus::~QDeclarativeDebuggerStatus(unsigned int) ?error@QDeclarativeCustomParser@@IAEXABVQString@@@Z @ 1345 NONAME ; void QDeclarativeCustomParser::error(class QString const &) - ?messageReceived@QDeclarativeDebugService@@MAEXABVQByteArray@@@Z @ 1346 NONAME ABSENT ; void QDeclarativeDebugService::messageReceived(class QByteArray const &) + ?messageReceived@QDeclarativeDebugService@@MAEXABVQByteArray@@@Z @ 1346 NONAME ; void QDeclarativeDebugService::messageReceived(class QByteArray const &) ??0QDeclarativeParserStatus@@QAE@XZ @ 1347 NONAME ; QDeclarativeParserStatus::QDeclarativeParserStatus(void) ?isNumber@Variant@QDeclarativeParser@@QBE_NXZ @ 1348 NONAME ; bool QDeclarativeParser::Variant::isNumber(void) const ?getStaticMetaObject@QDeclarativeEngineDebug@@SAABUQMetaObject@@XZ @ 1349 NONAME ABSENT ; struct QMetaObject const & QDeclarativeEngineDebug::getStaticMetaObject(void) @@ -1475,7 +1475,7 @@ EXPORTS ?packetWritten@QPacketProtocol@@IAEXXZ @ 1474 NONAME ; void QPacketProtocol::packetWritten(void) ?getStaticMetaObject@QDeclarativeDebugObjectQuery@@SAABUQMetaObject@@XZ @ 1475 NONAME ABSENT ; struct QMetaObject const & QDeclarativeDebugObjectQuery::getStaticMetaObject(void) ?isSignalProperty@QDeclarativeProperty@@QBE_NXZ @ 1476 NONAME ; bool QDeclarativeProperty::isSignalProperty(void) const - ?d_func@QDeclarativeDebugService@@AAEPAVQDeclarativeDebugServicePrivate@@XZ @ 1477 NONAME ABSENT ; class QDeclarativeDebugServicePrivate * QDeclarativeDebugService::d_func(void) + ?d_func@QDeclarativeDebugService@@AAEPAVQDeclarativeDebugServicePrivate@@XZ @ 1477 NONAME ; class QDeclarativeDebugServicePrivate * QDeclarativeDebugService::d_func(void) ?qmlTypeNames@QDeclarativeMetaType@@SA?AV?$QList@VQByteArray@@@@XZ @ 1478 NONAME ABSENT ; class QList<class QByteArray> QDeclarativeMetaType::qmlTypeNames(void) ?componentComplete@QDeclarativeItem@@MAEXXZ @ 1479 NONAME ; void QDeclarativeItem::componentComplete(void) ?creationContext@QDeclarativeComponent@@QBEPAVQDeclarativeContext@@XZ @ 1480 NONAME ; class QDeclarativeContext * QDeclarativeComponent::creationContext(void) const @@ -1575,7 +1575,7 @@ EXPORTS ?keyCount@QMetaEnumBuilder@@QBEHXZ @ 1574 NONAME ABSENT ; int QMetaEnumBuilder::keyCount(void) const ??1QDeclarativeDomProperty@@QAE@XZ @ 1575 NONAME ABSENT ; QDeclarativeDomProperty::~QDeclarativeDomProperty(void) ?url@QDeclarativePixmap@@QBEABVQUrl@@XZ @ 1576 NONAME ; class QUrl const & QDeclarativePixmap::url(void) const - ?sendMessage@QDeclarativeDebugService@@QAEXABVQByteArray@@@Z @ 1577 NONAME ABSENT ; void QDeclarativeDebugService::sendMessage(class QByteArray const &) + ?sendMessage@QDeclarativeDebugService@@QAEXABVQByteArray@@@Z @ 1577 NONAME ; void QDeclarativeDebugService::sendMessage(class QByteArray const &) ?context@QDeclarativeScriptString@@QBEPAVQDeclarativeContext@@XZ @ 1578 NONAME ; class QDeclarativeContext * QDeclarativeScriptString::context(void) const ?queryObject@QDeclarativeEngineDebug@@QAEPAVQDeclarativeDebugObjectQuery@@ABVQDeclarativeDebugObjectReference@@PAVQObject@@@Z @ 1579 NONAME ABSENT ; class QDeclarativeDebugObjectQuery * QDeclarativeEngineDebug::queryObject(class QDeclarativeDebugObjectReference const &, class QObject *) ?tr@QDeclarativePropertyMap@@SA?AVQString@@PBD0H@Z @ 1580 NONAME ; class QString QDeclarativePropertyMap::tr(char const *, char const *, int) @@ -1608,7 +1608,7 @@ EXPORTS ??_EQDeclarativeComponent@@UAE@I@Z @ 1607 NONAME ; QDeclarativeComponent::~QDeclarativeComponent(unsigned int) ?get@QDeclarativeItemPrivate@@SAPAV1@PAVQDeclarativeItem@@@Z @ 1608 NONAME ; class QDeclarativeItemPrivate * QDeclarativeItemPrivate::get(class QDeclarativeItem *) ?staticMetaObject@QDeclarativeView@@2UQMetaObject@@B @ 1609 NONAME ; struct QMetaObject const QDeclarativeView::staticMetaObject - ?objectToString@QDeclarativeDebugService@@SA?AVQString@@PAVQObject@@@Z @ 1610 NONAME ABSENT ; class QString QDeclarativeDebugService::objectToString(class QObject *) + ?objectToString@QDeclarativeDebugService@@SA?AVQString@@PAVQObject@@@Z @ 1610 NONAME ; class QString QDeclarativeDebugService::objectToString(class QObject *) ?defaultValue@QDeclarativeDomDynamicProperty@@QBE?AVQDeclarativeDomProperty@@XZ @ 1611 NONAME ABSENT ; class QDeclarativeDomProperty QDeclarativeDomDynamicProperty::defaultValue(void) const ?relatedMetaObject@QMetaObjectBuilder@@QBEPBUQMetaObject@@H@Z @ 1612 NONAME ABSENT ; struct QMetaObject const * QMetaObjectBuilder::relatedMetaObject(int) const ?addKey@QMetaEnumBuilder@@QAEHABVQByteArray@@H@Z @ 1613 NONAME ABSENT ; int QMetaEnumBuilder::addKey(class QByteArray const &, int) @@ -1633,7 +1633,7 @@ EXPORTS ?tr@QDeclarativeView@@SA?AVQString@@PBD0@Z @ 1632 NONAME ; class QString QDeclarativeView::tr(char const *, char const *) ?qt_metacall@QPacketProtocol@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1633 NONAME ; int QPacketProtocol::qt_metacall(enum QMetaObject::Call, int, void * *) ??0QDeclarativeItem@@QAE@PAV0@@Z @ 1634 NONAME ; QDeclarativeItem::QDeclarativeItem(class QDeclarativeItem *) - ?hasDebuggingClient@QDeclarativeDebugService@@SA_NXZ @ 1635 NONAME ABSENT ; bool QDeclarativeDebugService::hasDebuggingClient(void) + ?hasDebuggingClient@QDeclarativeDebugService@@SA_NXZ @ 1635 NONAME ; bool QDeclarativeDebugService::hasDebuggingClient(void) ?staticMetaObject@QDeclarativeContext@@2UQMetaObject@@B @ 1636 NONAME ; struct QMetaObject const QDeclarativeContext::staticMetaObject ?setContextForObject@QDeclarativeEngine@@SAXPAVQObject@@PAVQDeclarativeContext@@@Z @ 1637 NONAME ; void QDeclarativeEngine::setContextForObject(class QObject *, class QDeclarativeContext *) ?baselineOffsetChanged@QDeclarativeItem@@IAEXM@Z @ 1638 NONAME ; void QDeclarativeItem::baselineOffsetChanged(float) @@ -1733,7 +1733,7 @@ EXPORTS ?start@QDeclarativeTimer@@QAEXXZ @ 1732 NONAME ABSENT ; void QDeclarativeTimer::start(void) ?transition@QDeclarativeAbstractAnimation@@UAEXAAV?$QList@VQDeclarativeAction@@@@AAV?$QList@VQDeclarativeProperty@@@@W4TransitionDirection@1@@Z @ 1733 NONAME ABSENT ; void QDeclarativeAbstractAnimation::transition(class QList<class QDeclarativeAction> &, class QList<class QDeclarativeProperty> &, enum QDeclarativeAbstractAnimation::TransitionDirection) ?componentComplete@QDeclarativeAbstractAnimation@@UAEXXZ @ 1734 NONAME ABSENT ; void QDeclarativeAbstractAnimation::componentComplete(void) - ?statusChanged@QDeclarativeDebugService@@MAEXW4Status@1@@Z @ 1735 NONAME ABSENT ; void QDeclarativeDebugService::statusChanged(enum QDeclarativeDebugService::Status) + ?statusChanged@QDeclarativeDebugService@@MAEXW4Status@1@@Z @ 1735 NONAME ; void QDeclarativeDebugService::statusChanged(enum QDeclarativeDebugService::Status) ?runningChanged@QDeclarativeAbstractAnimation@@IAEX_N@Z @ 1736 NONAME ABSENT ; void QDeclarativeAbstractAnimation::runningChanged(bool) ?trUtf8@QDeclarativeAbstractAnimation@@SA?AVQString@@PBD0H@Z @ 1737 NONAME ABSENT ; class QString QDeclarativeAbstractAnimation::trUtf8(char const *, char const *, int) ??_EQDeclarativeBasePositioner@@UAE@I@Z @ 1738 NONAME ABSENT ; QDeclarativeBasePositioner::~QDeclarativeBasePositioner(unsigned int) @@ -1813,7 +1813,7 @@ EXPORTS ?setTarget@QDeclarativeAbstractAnimation@@EAEXABVQDeclarativeProperty@@@Z @ 1812 NONAME ABSENT ; void QDeclarativeAbstractAnimation::setTarget(class QDeclarativeProperty const &) ?alwaysRunToEnd@QDeclarativeAbstractAnimation@@QBE_NXZ @ 1813 NONAME ABSENT ; bool QDeclarativeAbstractAnimation::alwaysRunToEnd(void) const ?tr@QDeclarativeTimer@@SA?AVQString@@PBD0H@Z @ 1814 NONAME ABSENT ; class QString QDeclarativeTimer::tr(char const *, char const *, int) - ?status@QDeclarativeDebugService@@QBE?AW4Status@1@XZ @ 1815 NONAME ABSENT ; enum QDeclarativeDebugService::Status QDeclarativeDebugService::status(void) const + ?status@QDeclarativeDebugService@@QBE?AW4Status@1@XZ @ 1815 NONAME ; enum QDeclarativeDebugService::Status QDeclarativeDebugService::status(void) const ?intervalChanged@QDeclarativeTimer@@IAEXXZ @ 1816 NONAME ABSENT ; void QDeclarativeTimer::intervalChanged(void) ?isPaused@QDeclarativeAbstractAnimation@@QBE_NXZ @ 1817 NONAME ABSENT ; bool QDeclarativeAbstractAnimation::isPaused(void) const ?getStaticMetaObject@QDeclarativeAbstractAnimation@@SAABUQMetaObject@@XZ @ 1818 NONAME ABSENT ; struct QMetaObject const & QDeclarativeAbstractAnimation::getStaticMetaObject(void) diff --git a/src/s60installs/bwins/QtOpenVGu.def b/src/s60installs/bwins/QtOpenVGu.def index 87b9c7f..4767d93 100644 --- a/src/s60installs/bwins/QtOpenVGu.def +++ b/src/s60installs/bwins/QtOpenVGu.def @@ -176,4 +176,7 @@ EXPORTS ?fromData@QVGPixmapData@@UAE_NPBEIPBDV?$QFlags@W4ImageConversionFlag@Qt@@@@@Z @ 175 NONAME ; bool QVGPixmapData::fromData(unsigned char const *, unsigned int, char const *, class QFlags<enum Qt::ImageConversionFlag>) ?fromImageReader@QVGPixmapData@@UAEXPAVQImageReader@@V?$QFlags@W4ImageConversionFlag@Qt@@@@@Z @ 176 NONAME ; void QVGPixmapData::fromImageReader(class QImageReader *, class QFlags<enum Qt::ImageConversionFlag>) ?canVgWritePixels@QVGPaintEngine@@ABE_NABVQImage@@@Z @ 177 NONAME ; bool QVGPaintEngine::canVgWritePixels(class QImage const &) const + ?updateSerial@QVGPixmapData@@IAEXXZ @ 178 NONAME ; void QVGPixmapData::updateSerial(void) + ?copy@QVGPixmapData@@UAEXPBVQPixmapData@@ABVQRect@@@Z @ 179 NONAME ; void QVGPixmapData::copy(class QPixmapData const *, class QRect const &) + ?idealFormat@QVGPixmapData@@IBE?AW4Format@QImage@@PAV3@V?$QFlags@W4ImageConversionFlag@Qt@@@@@Z @ 180 NONAME ; enum QImage::Format QVGPixmapData::idealFormat(class QImage *, class QFlags<enum Qt::ImageConversionFlag>) const diff --git a/src/s60installs/eabi/QtDeclarativeu.def b/src/s60installs/eabi/QtDeclarativeu.def index 95180d4..130e2d5 100644 --- a/src/s60installs/eabi/QtDeclarativeu.def +++ b/src/s60installs/eabi/QtDeclarativeu.def @@ -761,20 +761,20 @@ EXPORTS _ZN24QDeclarativeCustomParser5errorERK28QDeclarativeCustomParserNodeRK7QString @ 760 NONAME _ZN24QDeclarativeCustomParser5errorERK32QDeclarativeCustomParserPropertyRK7QString @ 761 NONAME _ZN24QDeclarativeCustomParser5errorERK7QString @ 762 NONAME - _ZN24QDeclarativeDebugService11idForObjectEP7QObject @ 763 NONAME ABSENT - _ZN24QDeclarativeDebugService11objectForIdEi @ 764 NONAME ABSENT - _ZN24QDeclarativeDebugService11qt_metacallEN11QMetaObject4CallEiPPv @ 765 NONAME ABSENT - _ZN24QDeclarativeDebugService11qt_metacastEPKc @ 766 NONAME ABSENT - _ZN24QDeclarativeDebugService11sendMessageERK10QByteArray @ 767 NONAME ABSENT + _ZN24QDeclarativeDebugService11idForObjectEP7QObject @ 763 NONAME + _ZN24QDeclarativeDebugService11objectForIdEi @ 764 NONAME + _ZN24QDeclarativeDebugService11qt_metacallEN11QMetaObject4CallEiPPv @ 765 NONAME + _ZN24QDeclarativeDebugService11qt_metacastEPKc @ 766 NONAME + _ZN24QDeclarativeDebugService11sendMessageERK10QByteArray @ 767 NONAME _ZN24QDeclarativeDebugService14enabledChangedEb @ 768 NONAME ABSENT - _ZN24QDeclarativeDebugService14objectToStringEP7QObject @ 769 NONAME ABSENT - _ZN24QDeclarativeDebugService15messageReceivedERK10QByteArray @ 770 NONAME ABSENT - _ZN24QDeclarativeDebugService16staticMetaObjectE @ 771 NONAME DATA 16 ABSENT - _ZN24QDeclarativeDebugService18hasDebuggingClientEv @ 772 NONAME ABSENT - _ZN24QDeclarativeDebugService18isDebuggingEnabledEv @ 773 NONAME ABSENT - _ZN24QDeclarativeDebugService19getStaticMetaObjectEv @ 774 NONAME ABSENT - _ZN24QDeclarativeDebugServiceC1ERK7QStringP7QObject @ 775 NONAME ABSENT - _ZN24QDeclarativeDebugServiceC2ERK7QStringP7QObject @ 776 NONAME ABSENT + _ZN24QDeclarativeDebugService14objectToStringEP7QObject @ 769 NONAME + _ZN24QDeclarativeDebugService15messageReceivedERK10QByteArray @ 770 NONAME + _ZN24QDeclarativeDebugService16staticMetaObjectE @ 771 NONAME DATA 16 + _ZN24QDeclarativeDebugService18hasDebuggingClientEv @ 772 NONAME + _ZN24QDeclarativeDebugService18isDebuggingEnabledEv @ 773 NONAME + _ZN24QDeclarativeDebugService19getStaticMetaObjectEv @ 774 NONAME + _ZN24QDeclarativeDebugServiceC1ERK7QStringP7QObject @ 775 NONAME + _ZN24QDeclarativeDebugServiceC2ERK7QStringP7QObject @ 776 NONAME _ZN24QDeclarativeDomComponentC1ERKS_ @ 777 NONAME ABSENT _ZN24QDeclarativeDomComponentC1Ev @ 778 NONAME ABSENT _ZN24QDeclarativeDomComponentC2ERKS_ @ 779 NONAME ABSENT @@ -1425,8 +1425,8 @@ EXPORTS _ZNK23QDeclarativePropertyMapixERK7QString @ 1424 NONAME _ZNK24QDeclarativeCustomParser11resolveTypeERK10QByteArray @ 1425 NONAME _ZNK24QDeclarativeCustomParser12evaluateEnumERK10QByteArray @ 1426 NONAME - _ZNK24QDeclarativeDebugService10metaObjectEv @ 1427 NONAME ABSENT - _ZNK24QDeclarativeDebugService4nameEv @ 1428 NONAME ABSENT + _ZNK24QDeclarativeDebugService10metaObjectEv @ 1427 NONAME + _ZNK24QDeclarativeDebugService4nameEv @ 1428 NONAME _ZNK24QDeclarativeDebugService9isEnabledEv @ 1429 NONAME ABSENT _ZNK24QDeclarativeDomComponent13componentRootEv @ 1430 NONAME ABSENT _ZNK24QDeclarativeScriptString11scopeObjectEv @ 1431 NONAME @@ -1554,7 +1554,7 @@ EXPORTS _ZTI23QDeclarativeItemPrivate @ 1553 NONAME _ZTI23QDeclarativePropertyMap @ 1554 NONAME _ZTI24QDeclarativeCustomParser @ 1555 NONAME - _ZTI24QDeclarativeDebugService @ 1556 NONAME ABSENT + _ZTI24QDeclarativeDebugService @ 1556 NONAME _ZTI24QDeclarativeParserStatus @ 1557 NONAME _ZTI25QDeclarativeImageProvider @ 1558 NONAME _ZTI26QDeclarativeDebuggerStatus @ 1559 NONAME ABSENT @@ -1604,7 +1604,7 @@ EXPORTS _ZTV23QDeclarativeItemPrivate @ 1603 NONAME _ZTV23QDeclarativePropertyMap @ 1604 NONAME _ZTV24QDeclarativeCustomParser @ 1605 NONAME - _ZTV24QDeclarativeDebugService @ 1606 NONAME ABSENT + _ZTV24QDeclarativeDebugService @ 1606 NONAME _ZTV24QDeclarativeParserStatus @ 1607 NONAME _ZTV25QDeclarativeImageProvider @ 1608 NONAME _ZTV26QDeclarativeDebuggerStatus @ 1609 NONAME ABSENT @@ -1777,10 +1777,10 @@ EXPORTS _ZN23QDeclarativeDebugClientD1Ev @ 1776 NONAME ABSENT _ZN23QDeclarativeDebugClientD2Ev @ 1777 NONAME ABSENT _ZN23QDeclarativeEngineDebug13statusChangedENS_6StatusE @ 1778 NONAME ABSENT - _ZN24QDeclarativeDebugService13statusChangedENS_6StatusE @ 1779 NONAME ABSENT - _ZN24QDeclarativeDebugServiceD0Ev @ 1780 NONAME ABSENT - _ZN24QDeclarativeDebugServiceD1Ev @ 1781 NONAME ABSENT - _ZN24QDeclarativeDebugServiceD2Ev @ 1782 NONAME ABSENT + _ZN24QDeclarativeDebugService13statusChangedENS_6StatusE @ 1779 NONAME + _ZN24QDeclarativeDebugServiceD0Ev @ 1780 NONAME + _ZN24QDeclarativeDebugServiceD1Ev @ 1781 NONAME + _ZN24QDeclarativeDebugServiceD2Ev @ 1782 NONAME _ZN26QDeclarativeBasePositioner10addChangedEv @ 1783 NONAME ABSENT _ZN26QDeclarativeBasePositioner10itemChangeEN13QGraphicsItem18GraphicsItemChangeERK8QVariant @ 1784 NONAME ABSENT _ZN26QDeclarativeBasePositioner10setSpacingEi @ 1785 NONAME ABSENT @@ -1851,7 +1851,7 @@ EXPORTS _ZNK17QDeclarativeTimer9isRunningEv @ 1850 NONAME ABSENT _ZNK23QDeclarativeDebugClient6statusEv @ 1851 NONAME ABSENT _ZNK23QDeclarativeEngineDebug6statusEv @ 1852 NONAME ABSENT - _ZNK24QDeclarativeDebugService6statusEv @ 1853 NONAME ABSENT + _ZNK24QDeclarativeDebugService6statusEv @ 1853 NONAME _ZNK26QDeclarativeBasePositioner10metaObjectEv @ 1854 NONAME ABSENT _ZNK26QDeclarativeBasePositioner3addEv @ 1855 NONAME ABSENT _ZNK26QDeclarativeBasePositioner4moveEv @ 1856 NONAME ABSENT diff --git a/src/s60installs/eabi/QtOpenVGu.def b/src/s60installs/eabi/QtOpenVGu.def index e1828c1..40aac8a 100644 --- a/src/s60installs/eabi/QtOpenVGu.def +++ b/src/s60installs/eabi/QtOpenVGu.def @@ -206,4 +206,7 @@ EXPORTS _ZN13QVGPixmapData8fromDataEPKhjPKc6QFlagsIN2Qt19ImageConversionFlagEE @ 205 NONAME _ZN13QVGPixmapData8fromFileERK7QStringPKc6QFlagsIN2Qt19ImageConversionFlagEE @ 206 NONAME _ZNK14QVGPaintEngine16canVgWritePixelsERK6QImage @ 207 NONAME + _ZN13QVGPixmapData12updateSerialEv @ 208 NONAME + _ZN13QVGPixmapData4copyEPK11QPixmapDataRK5QRect @ 209 NONAME + _ZNK13QVGPixmapData11idealFormatEP6QImage6QFlagsIN2Qt19ImageConversionFlagEE @ 210 NONAME diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro index 0a2f614..1c91422 100644 --- a/src/s60installs/s60installs.pro +++ b/src/s60installs/s60installs.pro @@ -11,23 +11,6 @@ symbian: { isEmpty(QT_LIBINFIX) { TARGET.UID3 = 0x2001E61C - - # Sqlite3 is expected to be already found on phone if infixed configuration is built. - # It is also expected that devices newer than those based on S60 5.0 all have sqlite3.dll. - contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2)|contains(S60_VERSION, 5.0) { - BLD_INF_RULES.prj_exports += \ - "sqlite3.sis /epoc32/data/qt/sis/sqlite3.sis" - symbian-abld|symbian-sbsv2 { - sqlitedeployment = \ - "; Deploy sqlite onto phone that does not have it already" \ - "@\"$${EPOCROOT}epoc32/data/qt/sis/sqlite3.sis\", (0x2002af5f)" - } else { - sqlitedeployment = \ - "; Deploy sqlite onto phone that does not have it already" \ - "@\"$${PWD}/sqlite3.sis\", (0x2002af5f)" - } - qtlibraries.pkg_postrules += sqlitedeployment - } } else { # Always use experimental UID for infixed configuration to avoid UID clash TARGET.UID3 = 0xE001E61C @@ -92,7 +75,7 @@ symbian: { vendorinfo = \ "; Localised Vendor name" \ - "%{\"Nokia, Qt\"}" \ + "%{\"Nokia\"}" \ " " \ "; Unique Vendor name" \ ":\"Nokia, Qt\"" \ diff --git a/src/script/api/qscriptcontext.cpp b/src/script/api/qscriptcontext.cpp index 2468a46..5454df5 100644 --- a/src/script/api/qscriptcontext.cpp +++ b/src/script/api/qscriptcontext.cpp @@ -268,8 +268,14 @@ QScriptValue QScriptContext::argument(int index) const QScriptValue QScriptContext::callee() const { const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this); - QScript::APIShim shim(QScript::scriptEngineFromExec(frame)); - return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->callee()); + QScriptEnginePrivate *eng = QScript::scriptEngineFromExec(frame); + QScript::APIShim shim(eng); + if (frame->callee() == eng->originalGlobalObject()) { + // This is a pushContext()-created context; the callee is a lie. + Q_ASSERT(QScriptEnginePrivate::contextFlags(const_cast<JSC::CallFrame*>(frame)) & QScriptEnginePrivate::NativeContext); + return QScriptValue(); + } + return eng->scriptValueFromJSCValue(frame->callee()); } /*! diff --git a/src/script/api/qscriptcontextinfo.cpp b/src/script/api/qscriptcontextinfo.cpp index 0f9de1d..182bc4a 100644 --- a/src/script/api/qscriptcontextinfo.cpp +++ b/src/script/api/qscriptcontextinfo.cpp @@ -159,12 +159,20 @@ QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *conte JSC::CodeBlock *codeBlock = frame->codeBlock(); if (returnPC && codeBlock && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { #if ENABLE(JIT) - unsigned bytecodeOffset = codeBlock->getBytecodeIndex(frame, JSC::ReturnAddressPtr(returnPC)); + JSC::JITCode code = codeBlock->getJITCode(); + unsigned jitOffset = code.offsetOf(JSC::ReturnAddressPtr(returnPC).value()); + // We can only use the JIT code offset if it's smaller than the JIT size; + // otherwise calling getBytecodeIndex() is meaningless. + if (jitOffset < code.size()) { + unsigned bytecodeOffset = codeBlock->getBytecodeIndex(frame, JSC::ReturnAddressPtr(returnPC)); #else unsigned bytecodeOffset = returnPC - codeBlock->instructions().begin(); #endif bytecodeOffset--; //because returnPC is on the next instruction. We want the current one lineNumber = codeBlock->lineNumberForBytecodeOffset(const_cast<JSC::ExecState *>(frame), bytecodeOffset); +#if ENABLE(JIT) + } +#endif } } } diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 14ab2eb..ceb1b03 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -955,8 +955,11 @@ static QScriptValue __setupPackage__(QScriptContext *ctx, QScriptEngine *eng) } // namespace QScript QScriptEnginePrivate::QScriptEnginePrivate() - : registeredScriptValues(0), freeScriptValues(0), freeScriptValuesCount(0), - registeredScriptStrings(0), inEval(false) + : originalGlobalObjectProxy(0), currentFrame(0), + qobjectPrototype(0), qmetaobjectPrototype(0), variantPrototype(0), + activeAgent(0), agentLineNumber(-1), + registeredScriptValues(0), freeScriptValues(0), freeScriptValuesCount(0), + registeredScriptStrings(0), processEventsInterval(-1), inEval(false) { qMetaTypeId<QScriptValue>(); qMetaTypeId<QList<int> >(); @@ -1002,10 +1005,6 @@ QScriptEnginePrivate::QScriptEnginePrivate() currentFrame = exec; - originalGlobalObjectProxy = 0; - activeAgent = 0; - agentLineNumber = -1; - processEventsInterval = -1; cachedTranslationUrl = JSC::UString(); cachedTranslationContext = JSC::UString(); JSC::setCurrentIdentifierTable(oldTable); @@ -1253,10 +1252,12 @@ void QScriptEnginePrivate::mark(JSC::MarkStack& markStack) { Q_Q(QScriptEngine); - markStack.append(originalGlobalObject()); - markStack.append(globalObject()); - if (originalGlobalObjectProxy) - markStack.append(originalGlobalObjectProxy); + if (originalGlobalObject()) { + markStack.append(originalGlobalObject()); + markStack.append(globalObject()); + if (originalGlobalObjectProxy) + markStack.append(originalGlobalObjectProxy); + } if (qobjectPrototype) markStack.append(qobjectPrototype); @@ -1281,7 +1282,7 @@ void QScriptEnginePrivate::mark(JSC::MarkStack& markStack) } } - { + if (q) { QScriptContext *context = q->currentContext(); while (context) { @@ -2728,6 +2729,14 @@ JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSV bool clearScopeChain) { JSC::JSValue thisObject = _thisObject; + if (!callee) { + // callee can't be zero, as this can cause JSC to crash during GC + // marking phase if the context's Arguments object has been created. + // Fake it by using the global object. Note that this is also handled + // in QScriptContext::callee(), as that function should still return + // an invalid value. + callee = originalGlobalObject(); + } if (calledAsConstructor) { //JSC doesn't create default created object for native functions. so we do it JSC::JSValue prototype = callee->get(exec, exec->propertyNames().prototype); diff --git a/src/script/api/qscriptprogram.cpp b/src/script/api/qscriptprogram.cpp index 31af9a0..c0e2656 100644 --- a/src/script/api/qscriptprogram.cpp +++ b/src/script/api/qscriptprogram.cpp @@ -27,6 +27,7 @@ #include "qscriptengine.h" #include "qscriptengine_p.h" +#include "SamplingTool.h" #include "Executable.h" QT_BEGIN_NAMESPACE diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index e0dc385..079cf92 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -254,6 +254,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, int val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsNumber(exec, val)); } else @@ -271,6 +272,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, uint val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsNumber(exec, val)); } else @@ -288,6 +290,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, qsreal val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsNumber(exec, val)); } else @@ -305,6 +308,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, const QString &val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsString(exec, val)); } else { @@ -325,6 +329,7 @@ QScriptValue::QScriptValue(QScriptEngine *engine, const char *val) : d_ptr(new (QScriptEnginePrivate::get(engine))QScriptValuePrivate(QScriptEnginePrivate::get(engine))) { if (engine) { + QScript::APIShim shim(d_ptr->engine); JSC::ExecState *exec = d_ptr->engine->currentFrame; d_ptr->initFrom(JSC::jsString(exec, val)); } else { @@ -531,7 +536,12 @@ void QScriptValue::setPrototype(const QScriptValue &prototype) Q_D(QScriptValue); if (!d || !d->isObject()) return; - if (prototype.isValid() && QScriptValuePrivate::getEngine(prototype) + + JSC::JSValue other = d->engine->scriptValueToJSCValue(prototype); + if (!other || !(other.isObject() || other.isNull())) + return; + + if (QScriptValuePrivate::getEngine(prototype) && (QScriptValuePrivate::getEngine(prototype) != d->engine)) { qWarning("QScriptValue::setPrototype() failed: " "cannot set a prototype created in " @@ -539,7 +549,6 @@ void QScriptValue::setPrototype(const QScriptValue &prototype) return; } JSC::JSObject *thisObject = JSC::asObject(d->jscValue); - JSC::JSValue other = d->engine->scriptValueToJSCValue(prototype); // check for cycle JSC::JSValue nextPrototypeValue = other; diff --git a/src/script/script.pro b/src/script/script.pro index 162eb9c..c558ba8 100644 --- a/src/script/script.pro +++ b/src/script/script.pro @@ -73,7 +73,7 @@ INCLUDEPATH += $$WEBKITDIR/JavaScriptCore/generated # This line copied from WebCore.pro DEFINES += WTF_USE_JAVASCRIPTCORE_BINDINGS=1 WTF_CHANGES=1 -DEFINES += NDEBUG +CONFIG(release, debug|release):DEFINES += NDEBUG solaris-g++:isEqual(QT_ARCH,sparc) { CONFIG -= separate_debug_info @@ -101,5 +101,9 @@ symbian { QMAKE_CXXFLAGS.ARMCC += -OTime -O3 } +integrity { + CFLAGS += --diag_remark=236,82 +} + # WebKit doesn't compile in C++0x mode *-g++*:QMAKE_CXXFLAGS -= -std=c++0x -std=gnu++0x diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index 4df1d63..bf7c0aa 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -657,7 +657,7 @@ bool QSqlTableModel::insertRowIntoTable(const QSqlRecord &values) return false; } - return d->exec(stmt, prepStatement, rec); + return d->exec(stmt, prepStatement, rec, QSqlRecord() /* no where values */); } /*! @@ -695,7 +695,7 @@ bool QSqlTableModel::deleteRowFromTable(int row) } stmt.append(QLatin1Char(' ')).append(where); - return d->exec(stmt, prepStatement, whereValues); + return d->exec(stmt, prepStatement, QSqlRecord() /* no new values */, whereValues); } /*! diff --git a/src/sql/models/qsqltablemodel_p.h b/src/sql/models/qsqltablemodel_p.h index d2b96e6..f4f3811 100644 --- a/src/sql/models/qsqltablemodel_p.h +++ b/src/sql/models/qsqltablemodel_p.h @@ -75,7 +75,7 @@ public: QSqlRecord record(const QVector<QVariant> &values) const; bool exec(const QString &stmt, bool prepStatement, - const QSqlRecord &rec, const QSqlRecord &whereValues = QSqlRecord()); + const QSqlRecord &rec, const QSqlRecord &whereValues); virtual void revertCachedRow(int row); void revertInsertedRow(); bool setRecord(int row, const QSqlRecord &record); diff --git a/src/testlib/qbenchmark_p.h b/src/testlib/qbenchmark_p.h index 9a83a1a..ace17db 100644 --- a/src/testlib/qbenchmark_p.h +++ b/src/testlib/qbenchmark_p.h @@ -130,7 +130,7 @@ public: QBenchmarkGlobalData:current is created at the beginning of qExec() and cleared at the end. */ -class QBenchmarkGlobalData +class Q_TESTLIB_EXPORT QBenchmarkGlobalData { public: static QBenchmarkGlobalData *current; @@ -161,7 +161,7 @@ private: created at the beginning of qInvokeTestMethod() and cleared at the end. */ -class QBenchmarkTestMethodData +class Q_TESTLIB_EXPORT QBenchmarkTestMethodData { public: static QBenchmarkTestMethodData *current; diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 55f5fbe..287d8e6 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1014,6 +1014,10 @@ static bool isValidSlot(const QMetaMethod &sl) return true; } +Q_TESTLIB_EXPORT bool printAvailableFunctions = false; +Q_TESTLIB_EXPORT QStringList testFunctions; +Q_TESTLIB_EXPORT QStringList testTags; + static void qPrintTestSlots() { for (int i = 0; i < QTest::currentTestObject->metaObject()->methodCount(); ++i) { @@ -1034,7 +1038,7 @@ static int qToInt(char *str) return l; } -static void qParseArgs(int argc, char *argv[]) +Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) { const char *testOptions = " options:\n" @@ -1084,8 +1088,12 @@ static void qParseArgs(int argc, char *argv[]) "%s", argv[0], testOptions); exit(0); } else if (strcmp(argv[i], "-functions") == 0) { - qPrintTestSlots(); - exit(0); + if (qml) { + QTest::printAvailableFunctions = true; + } else { + qPrintTestSlots(); + exit(0); + } } else if(strcmp(argv[i], "-xunitxml") == 0){ QTestLog::setLogMode(QTestLog::XunitXML); } else if (strcmp(argv[i], "-xml") == 0) { @@ -1221,6 +1229,32 @@ static void qParseArgs(int argc, char *argv[]) } else if (argv[i][0] == '-') { printf("Unknown option: '%s'\n\n%s", argv[i], testOptions); exit(1); + } else if (qml) { + // We can't check the availability of test functions until + // we load the QML files. So just store the data for now. + int colon = -1; + int offset; + for(offset = 0; *(argv[i]+offset); ++offset) { + if (*(argv[i]+offset) == ':') { + if (*(argv[i]+offset+1) == ':') { + // "::" is used as a test name separator. + // e.g. "ClickTests::test_click:row1". + ++offset; + } else { + colon = offset; + break; + } + } + } + if (colon == -1) { + QTest::testFunctions += QString::fromLatin1(argv[i]); + QTest::testTags += QString(); + } else { + QTest::testFunctions += + QString::fromLatin1(argv[i], colon); + QTest::testTags += + QString::fromLatin1(argv[i] + colon + 1); + } } else { if (!QTest::testFuncs) { QTest::testFuncs = new QTest::TestFunction[512]; @@ -1625,6 +1659,14 @@ private: void FatalSignalHandler::signal(int signum) { qFatal("Received signal %d", signum); +#if defined(Q_OS_INTEGRITY) + { + struct sigaction act; + memset(&act, 0, sizeof(struct sigaction)); + act.sa_handler = SIG_DFL; + sigaction(signum, &act, NULL); + } +#endif } FatalSignalHandler::FatalSignalHandler() @@ -1639,8 +1681,9 @@ FatalSignalHandler::FatalSignalHandler() act.sa_handler = FatalSignalHandler::signal; // Remove the handler after it is invoked. +#if !defined(Q_OS_INTEGRITY) act.sa_flags = SA_RESETHAND; - +#endif // Block all fatal signals in our signal handler so we don't try to close // the testlog twice. sigemptyset(&act.sa_mask); @@ -1785,7 +1828,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) QTEST_ASSERT(metaObject); QTestResult::setCurrentTestObject(metaObject->className()); - qParseArgs(argc, argv); + qtest_qParseArgs(argc, argv, false); if (QTest::randomOrder) { seedRandom(); } diff --git a/src/testlib/qtestlog_p.h b/src/testlib/qtestlog_p.h index 59282fd..a892d3d 100644 --- a/src/testlib/qtestlog_p.h +++ b/src/testlib/qtestlog_p.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE class QBenchmarkResult; -class QTestLog +class Q_TESTLIB_EXPORT QTestLog { public: enum LogMode { Plain = 0, XML, LightXML, XunitXML }; diff --git a/src/testlib/qtestresult_p.h b/src/testlib/qtestresult_p.h index 15523f5..7ff120a 100644 --- a/src/testlib/qtestresult_p.h +++ b/src/testlib/qtestresult_p.h @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE class QTestResultPrivate; class QTestData; -class QTestResult +class Q_TESTLIB_EXPORT QTestResult { public: enum TestLocation { NoWhere = 0, DataFunc = 1, InitFunc = 2, Func = 3, CleanupFunc = 4 }; diff --git a/src/testlib/qtesttable_p.h b/src/testlib/qtesttable_p.h index d085b57..f835506 100644 --- a/src/testlib/qtesttable_p.h +++ b/src/testlib/qtesttable_p.h @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE class QTestData; class QTestTablePrivate; -class QTestTable +class Q_TESTLIB_EXPORT QTestTable { public: QTestTable(); diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp index 1ecb7e5..ecff105 100644 --- a/src/tools/moc/main.cpp +++ b/src/tools/moc/main.cpp @@ -111,6 +111,7 @@ void error(const char *msg = "Invalid argument") " -i do not generate an #include statement\n" " -p<path> path prefix for included file\n" " -f[<file>] force #include, optional file name\n" + " -nn do not display notes\n" " -nw do not display warnings\n" " @<file> read additional options from file\n" " -v display version of moc\n"); @@ -333,9 +334,12 @@ int runMoc(int _argc, char **_argv) case 'n': // don't display warnings if (ignoreConflictingOptions) break; - if (opt != "nw") + if (opt == "nw") + moc.displayWarnings = moc.displayNotes = false; + else if (opt == "nn") + moc.displayNotes = false; + else error(); - moc.displayWarnings = false; break; case 'h': // help if (more && opt != "help") @@ -425,7 +429,7 @@ int runMoc(int _argc, char **_argv) fprintf(out, "%s\n", composePreprocessorOutput(moc.symbols).constData()); } else { if (moc.classList.isEmpty()) - moc.warning("No relevant classes found. No output generated."); + moc.note("No relevant classes found. No output generated."); else moc.generate(out); } diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 2cf2412..74b1ace 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -685,10 +685,13 @@ void Moc::parse() if (parseEnum(&enumDef)) def.enumList += enumDef; } break; + case SEMIC: + case COLON: + break; default: FunctionDef funcDef; funcDef.access = access; - int rewind = index; + int rewind = index--; if (parseMaybeFunction(&def, &funcDef)) { if (funcDef.isConstructor) { if ((access == FunctionDef::Public) && funcDef.isInvokable) { diff --git a/src/tools/moc/parser.cpp b/src/tools/moc/parser.cpp index 1fa1401..b6f0837 100644 --- a/src/tools/moc/parser.cpp +++ b/src/tools/moc/parser.cpp @@ -78,4 +78,10 @@ void Parser::warning(const char *msg) { currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), msg); } +void Parser::note(const char *msg) { + if (displayNotes && msg) + fprintf(stderr, ErrorFormatString "Note: %s\n", + currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), msg); +} + QT_END_NAMESPACE diff --git a/src/tools/moc/parser.h b/src/tools/moc/parser.h index 8356449..a874248 100644 --- a/src/tools/moc/parser.h +++ b/src/tools/moc/parser.h @@ -50,10 +50,11 @@ QT_BEGIN_NAMESPACE class Parser { public: - Parser():index(0), displayWarnings(true){} + Parser():index(0), displayWarnings(true), displayNotes(true) {} Symbols symbols; int index; bool displayWarnings; + bool displayNotes; QStack<QByteArray> currentFilenames; @@ -73,6 +74,7 @@ public: void error(int rollback); void error(const char *msg = 0); void warning(const char * = 0); + void note(const char * = 0); }; diff --git a/tests/auto/declarative/qdeclarativeanimations/data/Double.qml b/tests/auto/declarative/qdeclarativeanimations/data/Double.qml new file mode 100644 index 0000000..b247fce --- /dev/null +++ b/tests/auto/declarative/qdeclarativeanimations/data/Double.qml @@ -0,0 +1,14 @@ +import QtQuick 1.0 + +Rectangle { + id: container + property bool on: false + border.color: "#ffffff" + color: "green" + width: 50 + height: 50 + NumberAnimation on x { + objectName: "animation" + running: container.on; from: 0; to: 600; loops: Animation.Infinite; duration: 2000 + } +} diff --git a/tests/auto/declarative/qdeclarativeanimations/data/doubleRegistrationBug.qml b/tests/auto/declarative/qdeclarativeanimations/data/doubleRegistrationBug.qml new file mode 100644 index 0000000..f0fdf9c --- /dev/null +++ b/tests/auto/declarative/qdeclarativeanimations/data/doubleRegistrationBug.qml @@ -0,0 +1,8 @@ +import QtQuick 1.0 + +Rectangle { + width: 400; height: 400 + + Double { id: dub; on: parent.width < 800 } + Component.onCompleted: dub.on = false +} diff --git a/tests/auto/declarative/qdeclarativeanimations/data/registrationBug.qml b/tests/auto/declarative/qdeclarativeanimations/data/registrationBug.qml new file mode 100644 index 0000000..7dc29f9 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeanimations/data/registrationBug.qml @@ -0,0 +1,18 @@ +import QtQuick 1.0 + +Rectangle { + id: rect + width: 200 + height: 200 + + property bool animating: true + property int value: 0 + + NumberAnimation { + target: rect + property: "value" + running: rect.animating + to: 100 + duration: 50 + } +} diff --git a/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp b/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp index 6f71dec..e2a54c0 100644 --- a/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp +++ b/tests/auto/declarative/qdeclarativeanimations/tst_qdeclarativeanimations.cpp @@ -85,6 +85,9 @@ private slots: void rotation(); void runningTrueBug(); void nonTransitionBug(); + void registrationBug(); + void doubleRegistrationBug(); + void alwaysRunToEndRestartBug(); }; #define QTIMED_COMPARE(lhs, rhs) do { \ @@ -793,6 +796,54 @@ void tst_qdeclarativeanimations::nonTransitionBug() QCOMPARE(mover->x(), qreal(100)); } +//QTBUG-14042 +void tst_qdeclarativeanimations::registrationBug() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, SRCDIR "/data/registrationBug.qml"); + QDeclarativeRectangle *rect = qobject_cast<QDeclarativeRectangle*>(c.create()); + QVERIFY(rect != 0); + QTRY_COMPARE(rect->property("value"), QVariant(int(100))); +} + +void tst_qdeclarativeanimations::doubleRegistrationBug() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, SRCDIR "/data/doubleRegistrationBug.qml"); + QDeclarativeRectangle *rect = qobject_cast<QDeclarativeRectangle*>(c.create()); + QVERIFY(rect != 0); + + QDeclarativeAbstractAnimation *anim = rect->findChild<QDeclarativeAbstractAnimation*>("animation"); + QVERIFY(anim != 0); + QTRY_COMPARE(anim->qtAnimation()->state(), QAbstractAnimation::Stopped); +} + +//QTBUG-16736 +void tst_qdeclarativeanimations::alwaysRunToEndRestartBug() +{ + QDeclarativeRectangle rect; + QDeclarativePropertyAnimation animation; + animation.setTarget(&rect); + animation.setProperty("x"); + animation.setTo(200); + animation.setDuration(1000); + animation.setLoops(-1); + animation.setAlwaysRunToEnd(true); + QVERIFY(animation.loops() == -1); + QVERIFY(animation.alwaysRunToEnd() == true); + animation.start(); + animation.stop(); + animation.start(); + animation.stop(); + QTest::qWait(500); + QVERIFY(rect.x() != qreal(200)); + QTest::qWait(800); + QTIMED_COMPARE(rect.x(), qreal(200)); + QCOMPARE(static_cast<QDeclarativeAbstractAnimation*>(&animation)->qtAnimation()->state(), QAbstractAnimation::Stopped); +} + QTEST_MAIN(tst_qdeclarativeanimations) #include "tst_qdeclarativeanimations.moc" diff --git a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp index 9a15575..6bcb4eb 100644 --- a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp +++ b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp @@ -167,8 +167,8 @@ void tst_QDeclarativeDebug::recursiveObjectTest(QObject *o, const QDeclarativeDe { const QMetaObject *meta = o->metaObject(); - QDeclarativeType *type = QDeclarativeMetaType::qmlType(o->metaObject()); - QString className = type ? type->qmlTypeName() : QString(); + QDeclarativeType *type = QDeclarativeMetaType::qmlType(meta); + QString className = type ? QString(type->qmlTypeName()) : QString(meta->className()); className = className.mid(className.lastIndexOf(QLatin1Char('/'))+1); QCOMPARE(oref.debugId(), QDeclarativeDebugService::idForObject(o)); @@ -293,12 +293,21 @@ void tst_QDeclarativeDebug::initTestCase() QList<QByteArray> qml; qml << "import QtQuick 1.0\n" "Item {" + "id: root\n" "width: 10; height: 20; scale: blueRect.scale;" "Rectangle { id: blueRect; width: 500; height: 600; color: \"blue\"; }" "Text { color: blueRect.color; }" "MouseArea {" "onEntered: { console.log('hello') }" "}" + "property variant varObj\n" + "property variant varObjList: []\n" + "Component.onCompleted: {\n" + "varObj = blueRect;\n" + "var list = varObjList;\n" + "list[0] = blueRect;\n" + "varObjList = list;\n" + "}\n" "}"; // add second component to test multiple root contexts @@ -742,7 +751,6 @@ void tst_QDeclarativeDebug::queryObject() QCOMPARE(findProperty(rect.properties(), "color").value(), qVariantFromValue(QColor("blue"))); QCOMPARE(findProperty(text.properties(), "color").value(), qVariantFromValue(QColor("blue"))); - } else { foreach(const QDeclarativeDebugObjectReference &child, obj.children()) QCOMPARE(child.properties().count(), 0); @@ -799,6 +807,8 @@ void tst_QDeclarativeDebug::queryExpressionResult_data() QTest::newRow("width + 50") << "width + 50" << qVariantFromValue(60); QTest::newRow("blueRect.width") << "blueRect.width" << qVariantFromValue(500); QTest::newRow("bad expr") << "aeaef" << qVariantFromValue(QString("<undefined>")); + QTest::newRow("QObject*") << "varObj" << qVariantFromValue(QString("<unnamed object>")); + QTest::newRow("list of QObject*") << "varObjList" << qVariantFromValue(QString("<unknown value>")); } void tst_QDeclarativeDebug::tst_QDeclarativeDebugFileReference() diff --git a/tests/auto/declarative/qdeclarativeflickable/data/nestedPressDelay.qml b/tests/auto/declarative/qdeclarativeflickable/data/nestedPressDelay.qml new file mode 100644 index 0000000..d0ee545 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeflickable/data/nestedPressDelay.qml @@ -0,0 +1,33 @@ +import QtQuick 1.0 + +Flickable { + property bool pressed: ma.pressed + width: 240 + height: 320 + contentWidth: 480 + contentHeight: 320 + flickableDirection: Flickable.HorizontalFlick + pressDelay: 50 + Flickable { + objectName: "innerFlickable" + flickableDirection: Flickable.VerticalFlick + width: 480 + height: 320 + contentWidth: 480 + contentHeight: 400 + pressDelay: 10000 + Rectangle { + y: 100 + anchors.horizontalCenter: parent.horizontalCenter + width: 240 + height: 100 + color: ma.pressed ? 'blue' : 'green' + MouseArea { + id: ma + objectName: "mouseArea" + anchors.fill: parent + } + } + } +} + diff --git a/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp b/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp index f4bec8f..736f8f4 100644 --- a/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp +++ b/tests/auto/declarative/qdeclarativeflickable/tst_qdeclarativeflickable.cpp @@ -69,6 +69,7 @@ private slots: void maximumFlickVelocity(); void flickDeceleration(); void pressDelay(); + void nestedPressDelay(); void flickableDirection(); void qgraphicswidget(); void resizeContent(); @@ -246,6 +247,34 @@ void tst_qdeclarativeflickable::pressDelay() QCOMPARE(spy.count(),1); } +// QTBUG-17361 +void tst_qdeclarativeflickable::nestedPressDelay() +{ + QDeclarativeView *canvas = new QDeclarativeView; + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/nestedPressDelay.qml")); + canvas->show(); + canvas->setFocus(); + QVERIFY(canvas->rootObject() != 0); + + QDeclarativeFlickable *outer = qobject_cast<QDeclarativeFlickable*>(canvas->rootObject()); + QVERIFY(outer != 0); + + QDeclarativeFlickable *inner = canvas->rootObject()->findChild<QDeclarativeFlickable*>("innerFlickable"); + QVERIFY(inner != 0); + + QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(150, 150))); + // the MouseArea is not pressed immediately + QVERIFY(outer->property("pressed").toBool() == false); + + // The outer pressDelay will prevail (50ms, vs. 10sec) + QTest::qWait(300); + QVERIFY(outer->property("pressed").toBool() == true); + + QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(150, 150))); + + delete canvas; +} + void tst_qdeclarativeflickable::flickableDirection() { QDeclarativeComponent component(&engine); diff --git a/tests/auto/declarative/qdeclarativefolderlistmodel/tst_qdeclarativefolderlistmodel.cpp b/tests/auto/declarative/qdeclarativefolderlistmodel/tst_qdeclarativefolderlistmodel.cpp index a62ea31..ffd5d38 100644 --- a/tests/auto/declarative/qdeclarativefolderlistmodel/tst_qdeclarativefolderlistmodel.cpp +++ b/tests/auto/declarative/qdeclarativefolderlistmodel/tst_qdeclarativefolderlistmodel.cpp @@ -62,14 +62,24 @@ class tst_qdeclarativefolderlistmodel : public QObject { Q_OBJECT public: - tst_qdeclarativefolderlistmodel() {} + tst_qdeclarativefolderlistmodel() : removeStart(0), removeEnd(0) {} + +public slots: + void removed(const QModelIndex &, int start, int end) { + removeStart = start; + removeEnd = end; + } private slots: void basicProperties(); + void refresh(); private: void checkNoErrors(const QDeclarativeComponent& component); QDeclarativeEngine engine; + + int removeStart; + int removeEnd; }; void tst_qdeclarativefolderlistmodel::checkNoErrors(const QDeclarativeComponent& component) @@ -115,6 +125,28 @@ void tst_qdeclarativefolderlistmodel::basicProperties() QCOMPARE(flm->property("folder").toUrl(), QUrl::fromLocalFile("")); } +void tst_qdeclarativefolderlistmodel::refresh() +{ + QDeclarativeComponent component(&engine, QUrl::fromLocalFile(SRCDIR "/data/basic.qml")); + checkNoErrors(component); + + QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create()); + QVERIFY(flm != 0); + + flm->setProperty("folder",QUrl::fromLocalFile(SRCDIR "/data")); + QTRY_COMPARE(flm->property("count").toInt(),2); // wait for refresh + + int count = flm->rowCount(); + + connect(flm, SIGNAL(rowsRemoved(const QModelIndex&,int,int)), + this, SLOT(removed(const QModelIndex&,int,int))); + + flm->setProperty("sortReversed", true); + + QCOMPARE(removeStart, 0); + QCOMPARE(removeEnd, count-1); +} + QTEST_MAIN(tst_qdeclarativefolderlistmodel) #include "tst_qdeclarativefolderlistmodel.moc" diff --git a/tests/auto/declarative/qdeclarativelistview/data/listview-sections_delegate.qml b/tests/auto/declarative/qdeclarativelistview/data/listview-sections_delegate.qml index 35a398b..b2d9213 100644 --- a/tests/auto/declarative/qdeclarativelistview/data/listview-sections_delegate.qml +++ b/tests/auto/declarative/qdeclarativelistview/data/listview-sections_delegate.qml @@ -1,6 +1,7 @@ import QtQuick 1.0 Rectangle { + property string sectionProperty: "number" width: 240 height: 320 color: "#ffffff" @@ -41,6 +42,11 @@ Rectangle { text: wrapper.y } } + ListView.onRemove: SequentialAnimation { + PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true } + NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 100; easing.type: Easing.InOutQuad } + PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false } + } } } ] @@ -51,7 +57,7 @@ Rectangle { height: 320 model: testModel delegate: myDelegate - section.property: "number" + section.property: sectionProperty section.delegate: Rectangle { objectName: "sect_" + section color: "#99bb99" diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index f358625..e326136 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -1078,6 +1078,65 @@ void tst_QDeclarativeListView::sectionsDelegate() QTRY_COMPARE(item->y(), qreal(i*20*6)); } + // remove section boundary + model.removeItem(5); + qApp->processEvents(); + for (int i = 0; i < 3; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, + "sect_" + (i == 0 ? QString("aaa") : QString::number(i))); + QVERIFY(item); + } + + // QTBUG-17606 + QList<QDeclarativeItem*> items = findItems<QDeclarativeItem>(contentItem, "sect_1"); + QCOMPARE(items.count(), 1); + + // QTBUG-17759 + model.modifyItem(0, "One", "aaa"); + model.modifyItem(1, "One", "aaa"); + model.modifyItem(2, "One", "aaa"); + model.modifyItem(3, "Four", "aaa"); + model.modifyItem(4, "Four", "aaa"); + model.modifyItem(5, "Four", "aaa"); + model.modifyItem(6, "Five", "aaa"); + model.modifyItem(7, "Five", "aaa"); + model.modifyItem(8, "Five", "aaa"); + model.modifyItem(9, "Two", "aaa"); + model.modifyItem(10, "Two", "aaa"); + model.modifyItem(11, "Two", "aaa"); + QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "sect_aaa").count(), 1); + canvas->rootObject()->setProperty("sectionProperty", "name"); + // ensure view has settled. + QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "sect_Four").count(), 1); + for (int i = 0; i < 4; ++i) { + QDeclarativeItem *item = findItem<QDeclarativeItem>(contentItem, + "sect_" + model.name(i*3)); + QVERIFY(item); + QTRY_COMPARE(item->y(), qreal(i*20*4)); + } + + // QTBUG-17769 + model.removeItems(10, 20); + // ensure view has settled. + QTRY_COMPARE(findItems<QDeclarativeItem>(contentItem, "wrapper").count(), 10); + // Drag view up beyond bounds + QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(20,20))); + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,0)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,-50)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + { + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(20,-200)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(canvas->viewport(), &mv); + } + QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(20,-200))); + // view should settle back at 0 + QTRY_COMPARE(listview->contentY(), 0.0); + delete canvas; } @@ -2408,7 +2467,7 @@ QList<T*> tst_QDeclarativeListView::findItems(QGraphicsObject *parent, const QSt //qDebug() << parent->childItems().count() << "children"; for (int i = 0; i < parent->childItems().count(); ++i) { QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent->childItems().at(i)); - if(!item) + if(!item || !item->isVisible()) continue; //qDebug() << "try" << item; if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) diff --git a/tests/auto/declarative/qdeclarativemousearea/data/preventstealing.qml b/tests/auto/declarative/qdeclarativemousearea/data/preventstealing.qml new file mode 100644 index 0000000..11553fa --- /dev/null +++ b/tests/auto/declarative/qdeclarativemousearea/data/preventstealing.qml @@ -0,0 +1,24 @@ +import QtQuick 1.1 + +Flickable { + property bool stealing: true + width: 200 + height: 200 + contentWidth: 400 + contentHeight: 400 + Rectangle { + color: "black" + width: 400 + height: 400 + Rectangle { + x: 50; y: 50 + width: 100; height: 100 + color: "steelblue" + MouseArea { + objectName: "mousearea" + anchors.fill: parent + preventStealing: stealing + } + } + } +} diff --git a/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp b/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp index 845d6bb..e1c34fc 100644 --- a/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp +++ b/tests/auto/declarative/qdeclarativemousearea/tst_qdeclarativemousearea.cpp @@ -43,8 +43,10 @@ #include <QtTest/QSignalSpy> #include <private/qdeclarativemousearea_p.h> #include <private/qdeclarativerectangle_p.h> +#include <private/qdeclarativeflickable_p.h> #include <QtDeclarative/qdeclarativeview.h> #include <QtDeclarative/qdeclarativecontext.h> +#include <QtDeclarative/qdeclarativeengine.h> #ifdef Q_OS_SYMBIAN // In Symbian OS test data is located in applications private dir @@ -65,6 +67,9 @@ private slots: void doubleClick(); void clickTwice(); void pressedOrdering(); + void preventStealing(); + void testQtQuick11Attributes(); + void testQtQuick11Attributes_data(); private: QDeclarativeView *createView(); @@ -356,6 +361,8 @@ void tst_QDeclarativeMouseArea::noOnClickedWithPressAndHold() QVERIFY(!canvas->rootObject()->property("clicked").toBool()); QVERIFY(canvas->rootObject()->property("held").toBool()); + + delete canvas; } void tst_QDeclarativeMouseArea::onMousePressRejected() @@ -399,6 +406,8 @@ void tst_QDeclarativeMouseArea::onMousePressRejected() QVERIFY(canvas->rootObject()->property("mr1_released").toBool()); QVERIFY(!canvas->rootObject()->property("mr1_canceled").toBool()); QVERIFY(!canvas->rootObject()->property("mr2_released").toBool()); + + delete canvas; } void tst_QDeclarativeMouseArea::doubleClick() @@ -436,6 +445,7 @@ void tst_QDeclarativeMouseArea::doubleClick() QCOMPARE(canvas->rootObject()->property("doubleClicked").toInt(), 1); QCOMPARE(canvas->rootObject()->property("released").toInt(), 2); + delete canvas; } // QTBUG-14832 @@ -476,6 +486,8 @@ void tst_QDeclarativeMouseArea::clickTwice() QCOMPARE(canvas->rootObject()->property("pressed").toInt(), 2); QCOMPARE(canvas->rootObject()->property("released").toInt(), 2); QCOMPARE(canvas->rootObject()->property("clicked").toInt(), 2); + + delete canvas; } void tst_QDeclarativeMouseArea::pressedOrdering() @@ -512,6 +524,119 @@ void tst_QDeclarativeMouseArea::pressedOrdering() delete canvas; } +void tst_QDeclarativeMouseArea::preventStealing() +{ + QDeclarativeView *canvas = createView(); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/preventstealing.qml")); + canvas->show(); + canvas->setFocus(); + QVERIFY(canvas->rootObject() != 0); + + QDeclarativeFlickable *flickable = qobject_cast<QDeclarativeFlickable*>(canvas->rootObject()); + QVERIFY(flickable != 0); + + QDeclarativeMouseArea *mouseArea = canvas->rootObject()->findChild<QDeclarativeMouseArea*>("mousearea"); + QVERIFY(mouseArea != 0); + + QSignalSpy mousePositionSpy(mouseArea, SIGNAL(positionChanged(QDeclarativeMouseEvent*))); + + QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(80, 80))); + + // Without preventStealing, mouse movement over MouseArea would + // cause the Flickable to steal mouse and trigger content movement. + QGraphicsScene *scene = canvas->scene(); + QGraphicsSceneMouseEvent moveEvent(QEvent::GraphicsSceneMouseMove); + moveEvent.setScenePos(QPointF(70, 70)); + moveEvent.setButton(Qt::LeftButton); + moveEvent.setButtons(Qt::LeftButton); + QApplication::sendEvent(scene, &moveEvent); + + moveEvent.setScenePos(QPointF(60, 60)); + moveEvent.setButton(Qt::LeftButton); + moveEvent.setButtons(Qt::LeftButton); + QApplication::sendEvent(scene, &moveEvent); + + moveEvent.setScenePos(QPointF(50, 50)); + moveEvent.setButton(Qt::LeftButton); + moveEvent.setButtons(Qt::LeftButton); + QApplication::sendEvent(scene, &moveEvent); + + // We should have received all three move events + QCOMPARE(mousePositionSpy.count(), 3); + QVERIFY(mouseArea->pressed()); + + // Flickable content should not have moved. + QCOMPARE(flickable->contentX(), 0.); + QCOMPARE(flickable->contentY(), 0.); + + QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 50))); + + // Now allow stealing and confirm Flickable does its thing. + canvas->rootObject()->setProperty("stealing", false); + + QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(80, 80))); + + // Without preventStealing, mouse movement over MouseArea would + // cause the Flickable to steal mouse and trigger content movement. + moveEvent.setScenePos(QPointF(70, 70)); + QApplication::sendEvent(scene, &moveEvent); + + moveEvent.setScenePos(QPointF(60, 60)); + QApplication::sendEvent(scene, &moveEvent); + + moveEvent.setScenePos(QPointF(50, 50)); + QApplication::sendEvent(scene, &moveEvent); + + // We should only have received the first move event + QCOMPARE(mousePositionSpy.count(), 4); + // Our press should be taken away + QVERIFY(!mouseArea->pressed()); + + // Flickable content should have moved. + QCOMPARE(flickable->contentX(), 10.); + QCOMPARE(flickable->contentY(), 10.); + + QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(50, 50))); + + delete canvas; +} + +void tst_QDeclarativeMouseArea::testQtQuick11Attributes() +{ + QFETCH(QString, code); + QFETCH(QString, warning); + QFETCH(QString, error); + + QDeclarativeEngine engine; + QObject *obj; + + QDeclarativeComponent valid(&engine); + valid.setData("import QtQuick 1.1; MouseArea { " + code.toUtf8() + " }", QUrl("")); + obj = valid.create(); + QVERIFY(obj); + QVERIFY(valid.errorString().isEmpty()); + delete obj; + + QDeclarativeComponent invalid(&engine); + invalid.setData("import QtQuick 1.0; MouseArea { " + code.toUtf8() + " }", QUrl("")); + QTest::ignoreMessage(QtWarningMsg, warning.toUtf8()); + obj = invalid.create(); + QCOMPARE(invalid.errorString(), error); + delete obj; +} + +void tst_QDeclarativeMouseArea::testQtQuick11Attributes_data() +{ + QTest::addColumn<QString>("code"); + QTest::addColumn<QString>("warning"); + QTest::addColumn<QString>("error"); + + QTest::newRow("preventStealing") << "preventStealing: true" + << "QDeclarativeComponent: Component is not ready" + << ":1 \"MouseArea.preventStealing\" is not available in QtQuick 1.0.\n"; +} + QTEST_MAIN(tst_QDeclarativeMouseArea) #include "tst_qdeclarativemousearea.moc" diff --git a/tests/auto/declarative/qdeclarativetext/data/qtbug_14734.qml b/tests/auto/declarative/qdeclarativetext/data/qtbug_14734.qml new file mode 100644 index 0000000..bd07d66 --- /dev/null +++ b/tests/auto/declarative/qdeclarativetext/data/qtbug_14734.qml @@ -0,0 +1,10 @@ +import QtQuick 1.0 + +Rectangle { + width: 640 + height: 480 + + Text { + text: "Ã " + } +} diff --git a/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp b/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp index a3bba3b..dbb822b 100644 --- a/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp +++ b/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp @@ -109,6 +109,7 @@ private slots: void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); + void qtbug_14734(); private: QStringList standard; QStringList richText; @@ -1204,6 +1205,19 @@ void tst_qdeclarativetext::testQtQuick11Attributes_data() << ""; } +void tst_qdeclarativetext::qtbug_14734() +{ + QDeclarativeView *canvas = createView(SRCDIR "/data/qtbug_14734.qml"); + QVERIFY(canvas); + + canvas->show(); + QApplication::setActiveWindow(canvas); + QTest::qWaitForWindowShown(canvas); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas)); + + delete canvas; +} + QTEST_MAIN(tst_qdeclarativetext) #include "tst_qdeclarativetext.moc" diff --git a/tests/auto/declarative/qdeclarativetextedit/data/positionAt.qml b/tests/auto/declarative/qdeclarativetextedit/data/positionAt.qml new file mode 100644 index 0000000..e010135 --- /dev/null +++ b/tests/auto/declarative/qdeclarativetextedit/data/positionAt.qml @@ -0,0 +1,9 @@ +import QtQuick 1.0 + +TextEdit { + focus: true + objectName: "myInput" + width: 50 + height: 25 + text: "This is\n a long piece of text" +} diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 7d5101c..dc1063f 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -121,7 +121,10 @@ private slots: void dragMouseSelection(); void inputMethodHints(); + void positionAt(); + void cursorDelegate(); + void cursorVisible(); void delegateLoading_data(); void delegateLoading(); void navigation(); @@ -137,6 +140,10 @@ private slots: void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); + void preeditMicroFocus(); + void inputContextMouseHandler(); + void inputMethodComposing(); + private: void simulateKey(QDeclarativeView *, int key); QDeclarativeView *createView(const QString &filename); @@ -1177,6 +1184,8 @@ void tst_qdeclarativetextedit::dragMouseSelection() QVERIFY(str2.length() > 3); QVERIFY(str1 != str2); // Verify the second press and drag is a new selection and doesn't not the first moved. + + delete canvas; } void tst_qdeclarativetextedit::mouseSelectionMode_data() @@ -1244,6 +1253,56 @@ void tst_qdeclarativetextedit::inputMethodHints() delete canvas; } +void tst_qdeclarativetextedit::positionAt() +{ + QDeclarativeView *canvas = createView(SRCDIR "/data/positionAt.qml"); + QVERIFY(canvas->rootObject() != 0); + canvas->show(); + canvas->setFocus(); + QApplication::setActiveWindow(canvas); + QTest::qWaitForWindowShown(canvas); + + QDeclarativeTextEdit *texteditObject = qobject_cast<QDeclarativeTextEdit *>(canvas->rootObject()); + QVERIFY(texteditObject != 0); + + QFontMetrics fm(texteditObject->font()); + const int y0 = fm.height() / 2; + const int y1 = fm.height() * 3 / 2; + + int pos = texteditObject->positionAt(texteditObject->width()/2, y0); + int diff = abs(int(fm.width(texteditObject->text().left(pos))-texteditObject->width()/2)); + + // some tollerance for different fonts. +#ifdef Q_OS_LINUX + QVERIFY(diff < 2); +#else + QVERIFY(diff < 5); +#endif + + const qreal x0 = texteditObject->positionToRectangle(pos).x(); + const qreal x1 = texteditObject->positionToRectangle(pos + 1).x(); + + QString preeditText = texteditObject->text().mid(0, pos); + texteditObject->setText(texteditObject->text().mid(pos)); + texteditObject->setCursorPosition(0); + + QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>()); + QApplication::sendEvent(canvas, &inputEvent); + + // Check all points within the preedit text return the same position. + QCOMPARE(texteditObject->positionAt(0, y0), 0); + QCOMPARE(texteditObject->positionAt(x0 / 2, y0), 0); + QCOMPARE(texteditObject->positionAt(x0, y0), 0); + + // Verify positioning returns to normal after the preedit text. + QCOMPARE(texteditObject->positionAt(x1, y0), 1); + QCOMPARE(texteditObject->positionToRectangle(1).x(), x1); + + QVERIFY(texteditObject->positionAt(x0 / 2, y1) > 0); + + delete canvas; +} + void tst_qdeclarativetextedit::cursorDelegate() { QDeclarativeView* view = createView(SRCDIR "/data/cursorTest.qml"); @@ -1272,6 +1331,76 @@ void tst_qdeclarativetextedit::cursorDelegate() delete view; } +void tst_qdeclarativetextedit::cursorVisible() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + view.setFocus(); + + QDeclarativeTextEdit edit; + QSignalSpy spy(&edit, SIGNAL(cursorVisibleChanged(bool))); + + QCOMPARE(edit.isCursorVisible(), false); + + edit.setCursorVisible(true); + QCOMPARE(edit.isCursorVisible(), true); + QCOMPARE(spy.count(), 1); + + edit.setCursorVisible(false); + QCOMPARE(edit.isCursorVisible(), false); + QCOMPARE(spy.count(), 2); + + edit.setFocus(true); + QCOMPARE(edit.isCursorVisible(), false); + QCOMPARE(spy.count(), 2); + + scene.addItem(&edit); + QCOMPARE(edit.isCursorVisible(), true); + QCOMPARE(spy.count(), 3); + + edit.setFocus(false); + QCOMPARE(edit.isCursorVisible(), false); + QCOMPARE(spy.count(), 4); + + edit.setFocus(true); + QCOMPARE(edit.isCursorVisible(), true); + QCOMPARE(spy.count(), 5); + + scene.clearFocus(); + QCOMPARE(edit.isCursorVisible(), false); + QCOMPARE(spy.count(), 6); + + scene.setFocus(); + QCOMPARE(edit.isCursorVisible(), true); + QCOMPARE(spy.count(), 7); + + view.clearFocus(); + QCOMPARE(edit.isCursorVisible(), false); + QCOMPARE(spy.count(), 8); + + view.setFocus(); + QCOMPARE(edit.isCursorVisible(), true); + QCOMPARE(spy.count(), 9); + + // on mac, setActiveWindow(0) on mac does not deactivate the current application + // (you have to switch to a different app or hide the current app to trigger this) +#if !defined(Q_WS_MAC) + QApplication::setActiveWindow(0); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(0)); + QCOMPARE(edit.isCursorVisible(), false); + QCOMPARE(spy.count(), 10); + + QApplication::setActiveWindow(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + QCOMPARE(edit.isCursorVisible(), true); + QCOMPARE(spy.count(), 11); +#endif +} + void tst_qdeclarativetextedit::delegateLoading_data() { QTest::addColumn<QString>("qmlfile"); @@ -1460,7 +1589,7 @@ QDeclarativeView *tst_qdeclarativetextedit::createView(const QString &filename) class MyInputContext : public QInputContext { public: - MyInputContext() : openInputPanelReceived(false), closeInputPanelReceived(false) {} + MyInputContext() : openInputPanelReceived(false), closeInputPanelReceived(false), updateReceived(false), eventType(QEvent::None) {} ~MyInputContext() {} QString identifierName() { return QString(); } @@ -1478,8 +1607,40 @@ public: closeInputPanelReceived = true; return QInputContext::filterEvent(event); } + + void update() { updateReceived = true; } + + void sendPreeditText(const QString &text, int cursor) + { + QList<QInputMethodEvent::Attribute> attributes; + attributes.append(QInputMethodEvent::Attribute( + QInputMethodEvent::Cursor, cursor, text.length(), QVariant())); + + QInputMethodEvent event(text, attributes); + sendEvent(event); + } + + void mouseHandler(int x, QMouseEvent *event) + { + cursor = x; + eventType = event->type(); + eventPosition = event->pos(); + eventGlobalPosition = event->globalPos(); + eventButton = event->button(); + eventButtons = event->buttons(); + eventModifiers = event->modifiers(); + } + bool openInputPanelReceived; bool closeInputPanelReceived; + bool updateReceived; + int cursor; + QEvent::Type eventType; + QPoint eventPosition; + QPoint eventGlobalPosition; + Qt::MouseButton eventButton; + Qt::MouseButtons eventButtons; + Qt::KeyboardModifiers eventModifiers; }; void tst_qdeclarativetextedit::textInput() @@ -1797,6 +1958,217 @@ void tst_qdeclarativetextedit::testQtQuick11Attributes_data() << ":1 \"TextEdit.onLinkActivated\" is not available in QtQuick 1.0.\n"; } +void tst_qdeclarativetextedit::preeditMicroFocus() +{ + QString preeditText = "super"; + + QGraphicsScene scene; + QGraphicsView view(&scene); + MyInputContext ic; + view.setInputContext(&ic); + QDeclarativeTextEdit edit; + edit.setFocus(true); + scene.addItem(&edit); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + + QRect currentRect; + QRect previousRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect(); + + // Verify that the micro focus rect is positioned the same for position 0 as + // it would be if there was no preedit text. + ic.updateReceived = false; + ic.sendPreeditText(preeditText, 0); + currentRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect(); + QCOMPARE(currentRect, previousRect); +#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) + QCOMPARE(ic.updateReceived, true); +#endif + + // Verify that the micro focus rect moves to the left as the cursor position + // is incremented. + for (int i = 1; i <= 5; ++i) { + ic.updateReceived = false; + ic.sendPreeditText(preeditText, i); + currentRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect(); + QVERIFY(previousRect.left() < currentRect.left()); +#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) + QCOMPARE(ic.updateReceived, true); +#endif + previousRect = currentRect; + } + + // Verify that if there is no preedit cursor then the micro focus rect is the + // same as it would be if it were positioned at the end of the preedit text. + ic.sendPreeditText(preeditText, 0); + ic.updateReceived = false; + ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>())); + currentRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect(); + QCOMPARE(currentRect, previousRect); +#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) + QCOMPARE(ic.updateReceived, true); +#endif +} + +void tst_qdeclarativetextedit::inputContextMouseHandler() +{ + QString text = "supercalifragisiticexpialidocious!"; + + QGraphicsScene scene; + QGraphicsView view(&scene); + MyInputContext ic; + view.setInputContext(&ic); + QDeclarativeTextEdit edit; + edit.setPos(0, 0); + edit.setWidth(200); + edit.setText(text.mid(0, 12)); + edit.setPos(0, 0); + edit.setCursorPosition(12); + edit.setFocus(true); + scene.addItem(&edit); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + view.setFocus(); + + QFontMetricsF fm(edit.font()); + const qreal y = fm.height() / 2; + + QPoint position2 = view.mapFromScene(edit.mapToScene(QPointF(fm.width(text.mid(0, 2)), y))); + QPoint position8 = view.mapFromScene(edit.mapToScene(QPointF(fm.width(text.mid(0, 8)), y))); + QPoint position20 = view.mapFromScene(edit.mapToScene(QPointF(fm.width(text.mid(0, 20)), y))); + QPoint position27 = view.mapFromScene(edit.mapToScene(QPointF(fm.width(text.mid(0, 27)), y))); + QPoint globalPosition2 = view.viewport()->mapToGlobal(position2); + QPoint globalposition8 = view.viewport()->mapToGlobal(position8); + QPoint globalposition20 = view.viewport()->mapToGlobal(position20); + QPoint globalposition27 = view.viewport()->mapToGlobal(position27); + + ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); + + QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2); + QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); + QCOMPARE(ic.eventPosition, position2); + QCOMPARE(ic.eventGlobalPosition, globalPosition2); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::NoModifier); + QVERIFY(ic.cursor < 0); + ic.eventType = QEvent::None; + + QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2); + QCOMPARE(ic.eventType, QEvent::MouseButtonPress); + QCOMPARE(ic.eventPosition, position2); + QCOMPARE(ic.eventGlobalPosition, globalPosition2); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::NoModifier); + QVERIFY(ic.cursor < 0); + ic.eventType = QEvent::None; + + { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(view.viewport(), &mv); } + QCOMPARE(ic.eventType, QEvent::None); + + { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(view.viewport(), &mv); } + QCOMPARE(ic.eventType, QEvent::MouseMove); + QCOMPARE(ic.eventPosition, position27); + QCOMPARE(ic.eventGlobalPosition, globalposition27); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::NoModifier); + QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one. + ic.eventType = QEvent::None; + + QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, position27); + QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); + QCOMPARE(ic.eventPosition, position27); + QCOMPARE(ic.eventGlobalPosition, globalposition27); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::NoModifier); + QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); + ic.eventType = QEvent::None; + + // And in the other direction. + QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, position27); + QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); + QCOMPARE(ic.eventPosition, position27); + QCOMPARE(ic.eventGlobalPosition, globalposition27); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::ControlModifier); + QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); + ic.eventType = QEvent::None; + + QTest::mousePress(view.viewport(), Qt::RightButton, Qt::ControlModifier, position27); + QCOMPARE(ic.eventType, QEvent::MouseButtonPress); + QCOMPARE(ic.eventPosition, position27); + QCOMPARE(ic.eventGlobalPosition, globalposition27); + QCOMPARE(ic.eventButton, Qt::RightButton); + QCOMPARE(ic.eventModifiers, Qt::ControlModifier); + QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); + ic.eventType = QEvent::None; + + { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); + QApplication::sendEvent(view.viewport(), &mv); } + QCOMPARE(ic.eventType, QEvent::MouseMove); + QCOMPARE(ic.eventPosition, position20); + QCOMPARE(ic.eventGlobalPosition, globalposition20); + QCOMPARE(ic.eventButton, Qt::RightButton); + QCOMPARE(ic.eventModifiers, Qt::ControlModifier); + QVERIFY(ic.cursor >= 7 && ic.cursor <= 9); + ic.eventType = QEvent::None; + + { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); + QApplication::sendEvent(view.viewport(), &mv); } + QCOMPARE(ic.eventType, QEvent::None); + + QTest::mouseRelease(view.viewport(), Qt::RightButton, Qt::ControlModifier, position2); + QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); + QCOMPARE(ic.eventPosition, position2); + QCOMPARE(ic.eventGlobalPosition, globalPosition2); + QCOMPARE(ic.eventButton, Qt::RightButton); + QCOMPARE(ic.eventModifiers, Qt::ControlModifier); + QVERIFY(ic.cursor < 0); + ic.eventType = QEvent::None; +} + +void tst_qdeclarativetextedit::inputMethodComposing() +{ + QString text = "supercalifragisiticexpialidocious!"; + + QGraphicsScene scene; + QGraphicsView view(&scene); + MyInputContext ic; + view.setInputContext(&ic); + QDeclarativeTextEdit edit; + edit.setWidth(200); + edit.setText(text.mid(0, 12)); + edit.setCursorPosition(12); + edit.setPos(0, 0); + edit.setFocus(true); + scene.addItem(&edit); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + + QSignalSpy spy(&edit, SIGNAL(inputMethodComposingChanged())); + + QCOMPARE(edit.isInputMethodComposing(), false); + + ic.sendEvent(QInputMethodEvent(text.mid(3), QList<QInputMethodEvent::Attribute>())); + QCOMPARE(edit.isInputMethodComposing(), true); + QCOMPARE(spy.count(), 1); + + ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); + QCOMPARE(edit.isInputMethodComposing(), true); + QCOMPARE(spy.count(), 1); + + ic.sendEvent(QInputMethodEvent()); + QCOMPARE(edit.isInputMethodComposing(), false); + QCOMPARE(spy.count(), 2); +} + QTEST_MAIN(tst_qdeclarativetextedit) #include "tst_qdeclarativetextedit.moc" diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index a6d30a5..24ce0e4 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -110,6 +110,8 @@ private slots: void passwordCharacter(); void cursorDelegate(); + void cursorVisible(); + void cursorRectangle(); void navigation(); void copyAndPaste(); void readOnly(); @@ -125,6 +127,9 @@ private slots: void testQtQuick11Attributes_data(); void preeditAutoScroll(); + void preeditMicroFocus(); + void inputContextMouseHandler(); + void inputMethodComposing(); private: void simulateKey(QDeclarativeView *, int key); @@ -952,6 +957,10 @@ void tst_qdeclarativetextinput::positionAt() QVERIFY(diff < 5); #endif + int x = textinputObject->positionToRectangle(pos + 1).x() - 1; + QCOMPARE(textinputObject->positionAt(x, QDeclarativeTextInput::CursorBetweenCharacters), pos + 1); + QCOMPARE(textinputObject->positionAt(x, QDeclarativeTextInput::CursorOnCharacter), pos); + // Check without autoscroll... textinputObject->setAutoScroll(false); pos = textinputObject->positionAt(textinputObject->width()/2); @@ -964,6 +973,29 @@ void tst_qdeclarativetextinput::positionAt() QVERIFY(diff < 5); #endif + x = textinputObject->positionToRectangle(pos + 1).x() - 1; + QCOMPARE(textinputObject->positionAt(x, QDeclarativeTextInput::CursorBetweenCharacters), pos + 1); + QCOMPARE(textinputObject->positionAt(x, QDeclarativeTextInput::CursorOnCharacter), pos); + + const qreal x0 = textinputObject->positionToRectangle(pos).x(); + const qreal x1 = textinputObject->positionToRectangle(pos + 1).x(); + + QString preeditText = textinputObject->text().mid(0, pos); + textinputObject->setText(textinputObject->text().mid(pos)); + textinputObject->setCursorPosition(0); + + QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>()); + QApplication::sendEvent(canvas, &inputEvent); + + // Check all points within the preedit text return the same position. + QCOMPARE(textinputObject->positionAt(0), 0); + QCOMPARE(textinputObject->positionAt(x0 / 2), 0); + QCOMPARE(textinputObject->positionAt(x0), 0); + + // Verify positioning returns to normal after the preedit text. + QCOMPARE(textinputObject->positionAt(x1), 1); + QCOMPARE(textinputObject->positionToRectangle(1).x(), x1); + delete canvas; } @@ -1142,6 +1174,24 @@ void tst_qdeclarativetextinput::inputMethods() QApplication::sendEvent(canvas, &event); QCOMPARE(input->text(), QString("My Hello world!")); + input->setCursorPosition(2); + event.setCommitString("Your", -2, 2); + QApplication::sendEvent(canvas, &event); + QCOMPARE(input->text(), QString("Your Hello world!")); + QCOMPARE(input->cursorPosition(), 4); + + input->setCursorPosition(7); + event.setCommitString("Goodbye", -2, 5); + QApplication::sendEvent(canvas, &event); + QCOMPARE(input->text(), QString("Your Goodbye world!")); + QCOMPARE(input->cursorPosition(), 12); + + input->setCursorPosition(8); + event.setCommitString("Our", -8, 4); + QApplication::sendEvent(canvas, &event); + QCOMPARE(input->text(), QString("Our Goodbye world!")); + QCOMPARE(input->cursorPosition(), 7); + delete canvas; } @@ -1314,6 +1364,110 @@ void tst_qdeclarativetextinput::cursorDelegate() delete view; } +void tst_qdeclarativetextinput::cursorVisible() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + + QDeclarativeTextInput input; + QSignalSpy spy(&input, SIGNAL(cursorVisibleChanged(bool))); + + QCOMPARE(input.isCursorVisible(), false); + + input.setCursorVisible(true); + QCOMPARE(input.isCursorVisible(), true); + QCOMPARE(spy.count(), 1); + + input.setCursorVisible(false); + QCOMPARE(input.isCursorVisible(), false); + QCOMPARE(spy.count(), 2); + + input.setFocus(true); + QCOMPARE(input.isCursorVisible(), false); + QCOMPARE(spy.count(), 2); + + scene.addItem(&input); + QCOMPARE(input.isCursorVisible(), true); + QCOMPARE(spy.count(), 3); + + input.setFocus(false); + QCOMPARE(input.isCursorVisible(), false); + QCOMPARE(spy.count(), 4); + + input.setFocus(true); + QCOMPARE(input.isCursorVisible(), true); + QCOMPARE(spy.count(), 5); + + scene.clearFocus(); + QCOMPARE(input.isCursorVisible(), false); + QCOMPARE(spy.count(), 6); + + scene.setFocus(); + QCOMPARE(input.isCursorVisible(), true); + QCOMPARE(spy.count(), 7); + + view.clearFocus(); + QCOMPARE(input.isCursorVisible(), false); + QCOMPARE(spy.count(), 8); + + view.setFocus(); + QCOMPARE(input.isCursorVisible(), true); + QCOMPARE(spy.count(), 9); + + // on mac, setActiveWindow(0) on mac does not deactivate the current application + // (you have to switch to a different app or hide the current app to trigger this) +#if !defined(Q_WS_MAC) + QApplication::setActiveWindow(0); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(0)); + QCOMPARE(input.isCursorVisible(), false); + QCOMPARE(spy.count(), 10); + + QApplication::setActiveWindow(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + QCOMPARE(input.isCursorVisible(), true); + QCOMPARE(spy.count(), 11); +#endif +} + +void tst_qdeclarativetextinput::cursorRectangle() +{ + QString text = "Hello World!"; + + QDeclarativeTextInput input; + input.setText(text); + QFontMetricsF fm(input.font()); + input.setWidth(fm.width(text.mid(0, 5))); + + QRect r; + + for (int i = 0; i <= 5; ++i) { + input.setCursorPosition(i); + r = input.cursorRectangle(); + int textWidth = fm.width(text.mid(0, i)); + + QVERIFY(r.left() < textWidth); + QVERIFY(r.right() > textWidth); + } + + // Check the cursor rectangle remains within the input bounding rect when auto scrolling. + QVERIFY(r.left() < input.boundingRect().width()); + QVERIFY(r.right() >= input.width()); + + for (int i = 6; i < text.length(); ++i) { + input.setCursorPosition(i); + QCOMPARE(r, input.cursorRectangle()); + } + + for (int i = text.length() - 2; i >= 0; --i) { + input.setCursorPosition(i); + QVERIFY(r.right() >= 0); + } +} + void tst_qdeclarativetextinput::readOnly() { QDeclarativeView *canvas = createView(SRCDIR "/data/readOnly.qml"); @@ -1419,7 +1573,7 @@ QDeclarativeView *tst_qdeclarativetextinput::createView(const QString &filename) class MyInputContext : public QInputContext { public: - MyInputContext() : openInputPanelReceived(false), closeInputPanelReceived(false) {} + MyInputContext() : openInputPanelReceived(false), closeInputPanelReceived(false), updateReceived(false), eventType(QEvent::None) {} ~MyInputContext() {} QString identifierName() { return QString(); } @@ -1438,6 +1592,19 @@ public: return QInputContext::filterEvent(event); } + void update() { updateReceived = true; } + + void mouseHandler(int x, QMouseEvent *event) + { + cursor = x; + eventType = event->type(); + eventPosition = event->pos(); + eventGlobalPosition = event->globalPos(); + eventButton = event->button(); + eventButtons = event->buttons(); + eventModifiers = event->modifiers(); + } + void sendPreeditText(const QString &text, int cursor) { QList<QInputMethodEvent::Attribute> attributes; @@ -1450,6 +1617,14 @@ public: bool openInputPanelReceived; bool closeInputPanelReceived; + bool updateReceived; + int cursor; + QEvent::Type eventType; + QPoint eventPosition; + QPoint eventGlobalPosition; + Qt::MouseButton eventButton; + Qt::MouseButtons eventButtons; + Qt::KeyboardModifiers eventModifiers; }; void tst_qdeclarativetextinput::openInputPanelOnClick() @@ -1747,7 +1922,8 @@ void tst_qdeclarativetextinput::preeditAutoScroll() MyInputContext ic; view.setInputContext(&ic); QDeclarativeTextInput input; - input.setWidth(QFontMetricsF(input.font()).width(committedText)); + QFontMetricsF fm(input.font()); + input.setWidth(fm.width(committedText)); input.setText(committedText); input.setPos(0, 0); input.setFocus(true); @@ -1760,7 +1936,7 @@ void tst_qdeclarativetextinput::preeditAutoScroll() // test the text is scrolled so the preedit is visible. ic.sendPreeditText(preeditText.mid(0, 3), 1); QVERIFY(input.positionAt(0) != 0); - QCOMPARE(input.positionAt(input.width()), 8); + QVERIFY(input.cursorRectangle().left() < input.boundingRect().width()); // test the text is scrolled back when the preedit is removed. ic.sendEvent(QInputMethodEvent()); @@ -1769,26 +1945,31 @@ void tst_qdeclarativetextinput::preeditAutoScroll() // test if the preedit is larger than the text input that the // character preceding the cursor is still visible. + qreal x = input.positionToRectangle(0).x(); for (int i = 0; i < 3; ++i) { ic.sendPreeditText(preeditText, i + 1); - QCOMPARE(input.positionAt(0), 5 + i); + QVERIFY(input.cursorRectangle().right() >= fm.width(preeditText.at(i))); + QVERIFY(input.positionToRectangle(0).x() < x); + x = input.positionToRectangle(0).x(); } for (int i = 1; i >= 0; --i) { ic.sendPreeditText(preeditText, i + 1); - QCOMPARE(input.positionAt(0), 5 + i); + QVERIFY(input.cursorRectangle().right() >= fm.width(preeditText.at(i))); + QVERIFY(input.positionToRectangle(0).x() > x); + x = input.positionToRectangle(0).x(); } // Test incrementing the preedit cursor doesn't cause further // scrolling when right most text is visible. ic.sendPreeditText(preeditText, preeditText.length() - 3); - int position = input.positionAt(0); + x = input.positionToRectangle(0).x(); for (int i = 2; i >= 0; --i) { ic.sendPreeditText(preeditText, preeditText.length() - i); - QCOMPARE(input.positionAt(0), position); + QCOMPARE(input.positionToRectangle(0).x(), x); } for (int i = 1; i < 3; ++i) { ic.sendPreeditText(preeditText, preeditText.length() - i); - QCOMPARE(input.positionAt(0), position); + QCOMPARE(input.positionToRectangle(0).x(), x); } // Test disabling auto scroll. @@ -1800,6 +1981,216 @@ void tst_qdeclarativetextinput::preeditAutoScroll() QCOMPARE(input.positionAt(input.width()), 5); } +void tst_qdeclarativetextinput::preeditMicroFocus() +{ + QString preeditText = "super"; + + QGraphicsScene scene; + QGraphicsView view(&scene); + MyInputContext ic; + view.setInputContext(&ic); + QDeclarativeTextInput input; + input.setPos(0, 0); + input.setFocus(true); + scene.addItem(&input); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + + QRect currentRect; + QRect previousRect = input.inputMethodQuery(Qt::ImMicroFocus).toRect(); + + // Verify that the micro focus rect is positioned the same for position 0 as + // it would be if there was no preedit text. + ic.updateReceived = false; + ic.sendPreeditText(preeditText, 0); + currentRect = input.inputMethodQuery(Qt::ImMicroFocus).toRect(); + QCOMPARE(currentRect, previousRect); +#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) + QCOMPARE(ic.updateReceived, true); +#endif + + // Verify that the micro focus rect moves to the left as the cursor position + // is incremented. + for (int i = 1; i <= 5; ++i) { + ic.updateReceived = false; + ic.sendPreeditText(preeditText, i); + currentRect = input.inputMethodQuery(Qt::ImMicroFocus).toRect(); + QVERIFY(previousRect.left() < currentRect.left()); +#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) + QCOMPARE(ic.updateReceived, true); +#endif + previousRect = currentRect; + } + + // Verify that if there is no preedit cursor then the micro focus rect is the + // same as it would be if it were positioned at the end of the preedit text. + ic.sendPreeditText(preeditText, 0); + ic.updateReceived = false; + ic.sendEvent(QInputMethodEvent(preeditText, QList<QInputMethodEvent::Attribute>())); + currentRect = input.inputMethodQuery(Qt::ImMicroFocus).toRect(); + QCOMPARE(currentRect, previousRect); +#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) + QCOMPARE(ic.updateReceived, true); +#endif +} + +void tst_qdeclarativetextinput::inputContextMouseHandler() +{ + QString text = "supercalifragisiticexpialidocious!"; + + QGraphicsScene scene; + QGraphicsView view(&scene); + MyInputContext ic; + view.setInputContext(&ic); + QDeclarativeTextInput input; + input.setWidth(200); + input.setText(text.mid(0, 12)); + input.setCursorPosition(12); + input.setPos(0, 0); + input.setFocus(true); + scene.addItem(&input); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + + QFontMetricsF fm(input.font()); + const qreal y = fm.height() / 2; + + QPoint position2 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 2)), y))); + QPoint position8 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 8)), y))); + QPoint position20 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 20)), y))); + QPoint position27 = view.mapFromScene(input.mapToScene(QPointF(fm.width(text.mid(0, 27)), y))); + QPoint globalPosition2 = view.viewport()->mapToGlobal(position2); + QPoint globalposition8 = view.viewport()->mapToGlobal(position8); + QPoint globalposition20 = view.viewport()->mapToGlobal(position20); + QPoint globalposition27 = view.viewport()->mapToGlobal(position27); + + ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); + + QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2); + QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); + QCOMPARE(ic.eventPosition, position2); + QCOMPARE(ic.eventGlobalPosition, globalPosition2); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::NoModifier); + QVERIFY(ic.cursor < 0); + ic.eventType = QEvent::None; + + QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, position2); + QCOMPARE(ic.eventType, QEvent::MouseButtonPress); + QCOMPARE(ic.eventPosition, position2); + QCOMPARE(ic.eventGlobalPosition, globalPosition2); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::NoModifier); + QVERIFY(ic.cursor < 0); + ic.eventType = QEvent::None; + + { QMouseEvent mv(QEvent::MouseMove, position8, globalposition8, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(view.viewport(), &mv); } + QCOMPARE(ic.eventType, QEvent::None); + + { QMouseEvent mv(QEvent::MouseMove, position27, globalposition27, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QApplication::sendEvent(view.viewport(), &mv); } + QCOMPARE(ic.eventType, QEvent::MouseMove); + QCOMPARE(ic.eventPosition, position27); + QCOMPARE(ic.eventGlobalPosition, globalposition27); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::NoModifier); + QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); // 15 is expected but some platforms may be off by one. + ic.eventType = QEvent::None; + + QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, position27); + QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); + QCOMPARE(ic.eventPosition, position27); + QCOMPARE(ic.eventGlobalPosition, globalposition27); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::NoModifier); + QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); + ic.eventType = QEvent::None; + + // And in the other direction. + QTest::mouseDClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, position27); + QCOMPARE(ic.eventType, QEvent::MouseButtonDblClick); + QCOMPARE(ic.eventPosition, position27); + QCOMPARE(ic.eventGlobalPosition, globalposition27); + QCOMPARE(ic.eventButton, Qt::LeftButton); + QCOMPARE(ic.eventModifiers, Qt::ControlModifier); + QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); + ic.eventType = QEvent::None; + + QTest::mousePress(view.viewport(), Qt::RightButton, Qt::ControlModifier, position27); + QCOMPARE(ic.eventType, QEvent::MouseButtonPress); + QCOMPARE(ic.eventPosition, position27); + QCOMPARE(ic.eventGlobalPosition, globalposition27); + QCOMPARE(ic.eventButton, Qt::RightButton); + QCOMPARE(ic.eventModifiers, Qt::ControlModifier); + QVERIFY(ic.cursor >= 14 && ic.cursor <= 16); + ic.eventType = QEvent::None; + + { QMouseEvent mv(QEvent::MouseMove, position20, globalposition20, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); + QApplication::sendEvent(view.viewport(), &mv); } + QCOMPARE(ic.eventType, QEvent::MouseMove); + QCOMPARE(ic.eventPosition, position20); + QCOMPARE(ic.eventGlobalPosition, globalposition20); + QCOMPARE(ic.eventButton, Qt::RightButton); + QCOMPARE(ic.eventModifiers, Qt::ControlModifier); + QVERIFY(ic.cursor >= 7 && ic.cursor <= 9); + ic.eventType = QEvent::None; + + { QMouseEvent mv(QEvent::MouseMove, position2, globalPosition2, Qt::RightButton, Qt::RightButton,Qt::ControlModifier); + QApplication::sendEvent(view.viewport(), &mv); } + QCOMPARE(ic.eventType, QEvent::None); + + QTest::mouseRelease(view.viewport(), Qt::RightButton, Qt::ControlModifier, position2); + QCOMPARE(ic.eventType, QEvent::MouseButtonRelease); + QCOMPARE(ic.eventPosition, position2); + QCOMPARE(ic.eventGlobalPosition, globalPosition2); + QCOMPARE(ic.eventButton, Qt::RightButton); + QCOMPARE(ic.eventModifiers, Qt::ControlModifier); + QVERIFY(ic.cursor < 0); + ic.eventType = QEvent::None; +} + +void tst_qdeclarativetextinput::inputMethodComposing() +{ + QString text = "supercalifragisiticexpialidocious!"; + + QGraphicsScene scene; + QGraphicsView view(&scene); + MyInputContext ic; + view.setInputContext(&ic); + QDeclarativeTextInput input; + input.setWidth(200); + input.setText(text.mid(0, 12)); + input.setCursorPosition(12); + input.setPos(0, 0); + input.setFocus(true); + scene.addItem(&input); + view.show(); + QApplication::setActiveWindow(&view); + QTest::qWaitForWindowShown(&view); + QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); + + QSignalSpy spy(&input, SIGNAL(inputMethodComposingChanged())); + + QCOMPARE(input.isInputMethodComposing(), false); + + ic.sendEvent(QInputMethodEvent(text.mid(3), QList<QInputMethodEvent::Attribute>())); + QCOMPARE(input.isInputMethodComposing(), true); + QCOMPARE(spy.count(), 1); + + ic.sendEvent(QInputMethodEvent(text.mid(12), QList<QInputMethodEvent::Attribute>())); + QCOMPARE(input.isInputMethodComposing(), true); + QCOMPARE(spy.count(), 1); + + ic.sendEvent(QInputMethodEvent()); + QCOMPARE(input.isInputMethodComposing(), false); + QCOMPARE(spy.count(), 2); +} + QTEST_MAIN(tst_qdeclarativetextinput) #include "tst_qdeclarativetextinput.moc" diff --git a/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp b/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp index 19d7967..af54008 100644 --- a/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp +++ b/tests/auto/declarative/qdeclarativexmllistmodel/tst_qdeclarativexmllistmodel.cpp @@ -569,6 +569,11 @@ void tst_qdeclarativexmllistmodel::reload() QSignalSpy spyRemove(model, SIGNAL(itemsRemoved(int,int))); QSignalSpy spyCount(model, SIGNAL(countChanged())); + //reload multiple times to test the xml query aborting + model->reload(); + model->reload(); + QCoreApplication::processEvents(); + model->reload(); model->reload(); QTRY_COMPARE(spyCount.count(), 1); QTRY_COMPARE(spyInsert.count(), 1); @@ -839,9 +844,27 @@ void tst_qdeclarativexmllistmodel::threading() data3 += "name=C" + QString::number(i) + ",age=3" + QString::number(i) + ",sport=Curling;"; } + //Set the xml data multiple times with randomized order and mixed with multiple event loops + //to test the xml query reloading/aborting, the result should be stable. + m1->setXml(makeItemXmlAndData(data1)); + m2->setXml(makeItemXmlAndData(data2)); + m3->setXml(makeItemXmlAndData(data3)); + QCoreApplication::processEvents(); + m2->setXml(makeItemXmlAndData(data2)); m1->setXml(makeItemXmlAndData(data1)); m2->setXml(makeItemXmlAndData(data2)); + QCoreApplication::processEvents(); + m3->setXml(makeItemXmlAndData(data3)); + QCoreApplication::processEvents(); + m2->setXml(makeItemXmlAndData(data2)); + m1->setXml(makeItemXmlAndData(data1)); + m2->setXml(makeItemXmlAndData(data2)); + m3->setXml(makeItemXmlAndData(data3)); + QCoreApplication::processEvents(); + m2->setXml(makeItemXmlAndData(data2)); + m3->setXml(makeItemXmlAndData(data3)); m3->setXml(makeItemXmlAndData(data3)); + QCoreApplication::processEvents(); QTRY_VERIFY(m1->count() == dataCount && m2->count() == dataCount && m3->count() == dataCount); diff --git a/tests/auto/gui.pro b/tests/auto/gui.pro index 07dc5ef..186f00c 100644 --- a/tests/auto/gui.pro +++ b/tests/auto/gui.pro @@ -112,6 +112,7 @@ SUBDIRS=\ qmimedata \ qmouseevent_modal \ qmovie \ + qvolatileimage \ qnetworkaccessmanager_and_qprogressdialog \ qnetworkcachemetadata \ qnetworkdiskcache \ diff --git a/tests/auto/moc/tst_moc.cpp b/tests/auto/moc/tst_moc.cpp index 20fade1..203f0ae 100644 --- a/tests/auto/moc/tst_moc.cpp +++ b/tests/auto/moc/tst_moc.cpp @@ -493,7 +493,12 @@ private slots: void QTBUG5590_dummyProperty(); void QTBUG12260_defaultTemplate(); void notifyError(); + void QTBUG17635_invokableAndProperty(); void revisions(); + void warnings_data(); + void warnings(); + + signals: void sigWithUnsignedArg(unsigned foo); void sigWithSignedArg(signed foo); @@ -1386,6 +1391,31 @@ void tst_Moc::notifyError() #endif } +class QTBUG_17635_InvokableAndProperty : public QObject +{ + Q_OBJECT +public: + Q_PROPERTY(int numberOfEggs READ numberOfEggs) + Q_PROPERTY(int numberOfChickens READ numberOfChickens) + Q_INVOKABLE QString getEgg(int index) { return QString::fromLatin1("Egg"); } + Q_INVOKABLE QString getChicken(int index) { return QString::fromLatin1("Chicken"); } + int numberOfEggs() { return 2; } + int numberOfChickens() { return 4; } +}; + +void tst_Moc::QTBUG17635_invokableAndProperty() +{ + //Moc used to fail parsing Q_INVOKABLE if they were dirrectly following a Q_PROPERTY; + QTBUG_17635_InvokableAndProperty mc; + QString val; + QMetaObject::invokeMethod(&mc, "getEgg", Q_RETURN_ARG(QString, val), Q_ARG(int, 10)); + QCOMPARE(val, QString::fromLatin1("Egg")); + QMetaObject::invokeMethod(&mc, "getChicken", Q_RETURN_ARG(QString, val), Q_ARG(int, 10)); + QCOMPARE(val, QString::fromLatin1("Chicken")); + QVERIFY(mc.metaObject()->indexOfProperty("numberOfEggs") != -1); + QVERIFY(mc.metaObject()->indexOfProperty("numberOfChickens") != -1); +} + // If changed, update VersionTestNotify below class VersionTest : public QObject { @@ -1498,8 +1528,126 @@ void tst_Moc::revisions() revisions_T<VersionTestNotify>(); } -QTEST_APPLESS_MAIN(tst_Moc) -#include "tst_moc.moc" +void tst_Moc::warnings_data() +{ + QTest::addColumn<QByteArray>("input"); + QTest::addColumn<QStringList>("args"); + QTest::addColumn<int>("exitCode"); + QTest::addColumn<QString>("expectedStdOut"); + QTest::addColumn<QString>("expectedStdErr"); + + // empty input should result in "no relevant classes" note + QTest::newRow("No relevant classes") + << QByteArray(" ") + << QStringList() + << 0 + << QString() + << QString("standard input:0: Note: No relevant classes found. No output generated."); + + // passing "-nn" should suppress "no relevant classes" note + QTest::newRow("-nn") + << QByteArray(" ") + << (QStringList() << "-nn") + << 0 + << QString() + << QString(); + + // passing "-nw" should also suppress "no relevant classes" note + QTest::newRow("-nw") + << QByteArray(" ") + << (QStringList() << "-nw") + << 0 + << QString() + << QString(); + + // This should output a warning + QTest::newRow("Invalid property warning") + << QByteArray("class X : public QObject { Q_OBJECT Q_PROPERTY(int x) };") + << QStringList() + << 0 + << QString("IGNORE_ALL_STDOUT") + << QString("standard input:1: Warning: Property declaration x has no READ accessor function. The property will be invalid."); + + // Passing "-nn" should NOT suppress the warning + QTest::newRow("Invalid property warning") + << QByteArray("class X : public QObject { Q_OBJECT Q_PROPERTY(int x) };") + << (QStringList() << "-nn") + << 0 + << QString("IGNORE_ALL_STDOUT") + << QString("standard input:1: Warning: Property declaration x has no READ accessor function. The property will be invalid."); + + // Passing "-nw" should suppress the warning + QTest::newRow("Invalid property warning") + << QByteArray("class X : public QObject { Q_OBJECT Q_PROPERTY(int x) };") + << (QStringList() << "-nw") + << 0 + << QString("IGNORE_ALL_STDOUT") + << QString(); + + // This should output an error + QTest::newRow("Does not inherit QObject") + << QByteArray("class X { Q_OBJECT };") + << QStringList() + << 1 + << QString() + << QString("standard input:1: Error: Class contains Q_OBJECT macro but does not inherit from QObject"); + + // "-nn" should not suppress the error + QTest::newRow("Does not inherit QObject with -nn") + << QByteArray("class X { Q_OBJECT };") + << (QStringList() << "-nn") + << 1 + << QString() + << QString("standard input:1: Error: Class contains Q_OBJECT macro but does not inherit from QObject"); + + // "-nw" should not suppress the error + QTest::newRow("Does not inherit QObject with -nn") + << QByteArray("class X { Q_OBJECT };") + << (QStringList() << "-nw") + << 1 + << QString() + << QString("standard input:1: Error: Class contains Q_OBJECT macro but does not inherit from QObject"); +} + +void tst_Moc::warnings() +{ +#ifdef MOC_CROSS_COMPILED + QSKIP("Not tested when cross-compiled", SkipAll); +#endif + QFETCH(QByteArray, input); + QFETCH(QStringList, args); + QFETCH(int, exitCode); + QFETCH(QString, expectedStdOut); + QFETCH(QString, expectedStdErr); + +#ifdef Q_CC_MSVC + // for some reasons, moc compiled with MSVC uses a different output format + QRegExp lineNumberRe(":(\\d+):"); + lineNumberRe.setMinimal(true); + expectedStdErr.replace(lineNumberRe, "(\\1):"); +#endif + + QProcess proc; + proc.start("moc", args); + QVERIFY(proc.waitForStarted()); + QCOMPARE(proc.write(input), qint64(input.size())); + + proc.closeWriteChannel(); + + QVERIFY(proc.waitForFinished()); + + QCOMPARE(proc.exitCode(), exitCode); + QCOMPARE(proc.exitStatus(), QProcess::NormalExit); + + // magic value "IGNORE_ALL_STDOUT" ignores stdout + if (expectedStdOut != "IGNORE_ALL_STDOUT") + QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardOutput()).trimmed(), expectedStdOut); + QCOMPARE(QString::fromLocal8Bit(proc.readAllStandardError()).trimmed(), expectedStdErr); + + } + +QTEST_APPLESS_MAIN(tst_Moc) +#include "tst_moc.moc" diff --git a/tests/auto/network.pro b/tests/auto/network.pro index 7d83054..b427f1c 100644 --- a/tests/auto/network.pro +++ b/tests/auto/network.pro @@ -35,6 +35,8 @@ SUBDIRS=\ qsslerror \ qsslkey \ qsslsocket \ + qsslsocket_onDemandCertificates_member \ + qsslsocket_onDemandCertificates_static \ # qnetworkproxyfactory \ # Uses a hardcoded proxy configuration !contains(QT_CONFIG, private_tests): SUBDIRS -= \ diff --git a/tests/auto/networkselftest/tst_networkselftest.cpp b/tests/auto/networkselftest/tst_networkselftest.cpp index cfcafc0..64de64a 100644 --- a/tests/auto/networkselftest/tst_networkselftest.cpp +++ b/tests/auto/networkselftest/tst_networkselftest.cpp @@ -967,7 +967,7 @@ void tst_NetworkSelfTest::smbServer() QVERIFY2(f, qt_error_string().toLocal8Bit()); char buf[128]; - size_t ret = fread(buf, sizeof buf, 1, f); + size_t ret = fread(buf, 1, sizeof buf, f); fclose(f); QCOMPARE(ret, strlen(contents)); diff --git a/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp b/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp index 6331db7..db0d0a7 100644 --- a/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp +++ b/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp @@ -331,7 +331,7 @@ void tst_QAbstractNetworkCache::checkSynchronous() QNetworkRequest request(realUrl); request.setAttribute( - static_cast<QNetworkRequest::Attribute>(QNetworkRequest::DownloadBufferAttribute + 1), + QNetworkRequest::SynchronousRequestAttribute, true); // prime the cache diff --git a/tests/auto/qclipboard/tst_qclipboard.cpp b/tests/auto/qclipboard/tst_qclipboard.cpp index c05bbac..7840974 100644 --- a/tests/auto/qclipboard/tst_qclipboard.cpp +++ b/tests/auto/qclipboard/tst_qclipboard.cpp @@ -205,7 +205,7 @@ void tst_QClipboard::testSignals() void tst_QClipboard::copy_exit_paste() { #ifndef QT_NO_PROCESS -#if defined Q_WS_X11 || defined Q_WS_QWS +#if defined Q_WS_X11 || defined Q_WS_QWS || defined (Q_WS_QPA) QSKIP("This test does not make sense on X11 and embedded, copied data disappears from the clipboard when the application exits ", SkipAll); // ### It's still possible to test copy/paste - just keep the apps running #elif defined (Q_OS_SYMBIAN) && defined (Q_CC_NOKIAX86) diff --git a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp index c1938b1..39f0677 100644 --- a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp +++ b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp @@ -169,6 +169,25 @@ public slots: int MyObject::callCount = 0; QVariantList MyObject::callArgs; +class MyObjectUnknownType: public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.MyObject") + Q_CLASSINFO("D-Bus Introspection", "" +" <interface name=\"com.trolltech.QtDBus.MyObjectUnknownTypes\" >\n" +" <property access=\"readwrite\" type=\"~\" name=\"prop1\" />\n" +" <signal name=\"somethingHappened\" >\n" +" <arg direction=\"out\" type=\"~\" />\n" +" </signal>\n" +" <method name=\"ping\" >\n" +" <arg direction=\"in\" type=\"~\" name=\"ping\" />\n" +" <arg direction=\"out\" type=\"~\" name=\"ping\" />\n" +" </method>\n" +" <method name=\"regularMethod\" />\n" +" </interface>\n" + "") +}; + class Spy: public QObject { Q_OBJECT @@ -228,6 +247,7 @@ private slots: void notValidDerived(); void invalidAfterServiceOwnerChanged(); void introspect(); + void introspectUnknownTypes(); void callMethod(); void invokeMethod(); void invokeMethodWithReturn(); @@ -250,8 +270,7 @@ void tst_QDBusInterface::initTestCase() con.registerObject("/", &obj, QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSlots - | QDBusConnection::ExportAllInvokables - | QDBusConnection::ExportChildObjects); + | QDBusConnection::ExportAllInvokables); } void tst_QDBusInterface::notConnected() @@ -322,6 +341,27 @@ void tst_QDBusInterface::introspect() QVERIFY(mo->indexOfProperty("complexProp") != -1); } +void tst_QDBusInterface::introspectUnknownTypes() +{ + QDBusConnection con = QDBusConnection::sessionBus(); + MyObjectUnknownType obj; + con.registerObject("/unknownTypes", &obj, QDBusConnection::ExportAllContents); + QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/unknownTypes"), + "com.trolltech.QtDBus.MyObjectUnknownTypes"); + + const QMetaObject *mo = iface.metaObject(); + QVERIFY(mo->indexOfMethod("regularMethod()") != -1); // this is the control + QVERIFY(mo->indexOfMethod("somethingHappened(QDBusRawType<0x7e>*)") != -1); + + QVERIFY(mo->indexOfMethod("ping(QDBusRawType<0x7e>*)") != -1); + int midx = mo->indexOfMethod("ping(QDBusRawType<0x7e>*)"); + QCOMPARE(mo->method(midx).typeName(), "QDBusRawType<0x7e>*"); + + QVERIFY(mo->indexOfProperty("prop1") != -1); + int pidx = mo->indexOfProperty("prop1"); + QCOMPARE(mo->property(pidx).typeName(), "QDBusRawType<0x7e>*"); +} + void tst_QDBusInterface::callMethod() { QDBusConnection con = QDBusConnection::sessionBus(); diff --git a/tests/auto/qdbusmarshall/test/test.pro b/tests/auto/qdbusmarshall/test/test.pro index 8901999..71fc656 100644 --- a/tests/auto/qdbusmarshall/test/test.pro +++ b/tests/auto/qdbusmarshall/test/test.pro @@ -5,4 +5,5 @@ TARGET = ../tst_qdbusmarshall QT = core QT += dbus - +LIBS += $$QT_LIBS_DBUS +QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS diff --git a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp index c05e49c..9bae6af 100644 --- a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp +++ b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp @@ -38,7 +38,6 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#define DBUS_API_SUBJECT_TO_CHANGE #include <QtCore/QtCore> #include <QtTest/QtTest> #include <QtDBus/QtDBus> @@ -47,6 +46,8 @@ #include "common.h" #include <limits> +#include <dbus/dbus.h> + static const char serviceName[] = "com.trolltech.autotests.qpong"; static const char objectPath[] = "/com/trolltech/qpong"; static const char *interfaceName = serviceName; @@ -88,66 +89,59 @@ private slots: void sendCallErrors_data(); void sendCallErrors(); + void receiveUnknownType_data(); + void receiveUnknownType(); + private: QProcess proc; }; -struct UnregisteredType { }; -Q_DECLARE_METATYPE(UnregisteredType) - -class WaitForQPong: public QObject +class QDBusMessageSpy: public QObject { Q_OBJECT -public: - WaitForQPong(); - bool ok(); -public Q_SLOTS: - void ownerChange(const QString &name) +public slots: + Q_SCRIPTABLE int theSlot(const QDBusMessage &msg) { - if (name == serviceName) - loop.quit(); + list << msg; + return 42; } - -private: - QEventLoop loop; +public: + QList<QDBusMessage> list; }; -WaitForQPong::WaitForQPong() -{ - QDBusConnection con = QDBusConnection::sessionBus(); - if (!ok()) { - connect(con.interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)), - SLOT(ownerChange(QString))); - QTimer::singleShot(2000, &loop, SLOT(quit())); - loop.exec(); - } -} - -bool WaitForQPong::ok() -{ - return QDBusConnection::sessionBus().isConnected() && - QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName); -} +struct UnregisteredType { }; +Q_DECLARE_METATYPE(UnregisteredType) void tst_QDBusMarshall::initTestCase() { commonInit(); + QDBusConnection con = QDBusConnection::sessionBus(); #ifdef Q_OS_WIN proc.start("qpong"); #else proc.start("./qpong/qpong"); #endif - QVERIFY(proc.waitForStarted()); - - WaitForQPong w; - QVERIFY(w.ok()); - //QTest::qWait(2000); + if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName)) { + QVERIFY(proc.waitForStarted()); + + QVERIFY(con.isConnected()); + con.connect("org.freedesktop.DBus", QString(), "org.freedesktop.DBus", "NameOwnerChanged", + QStringList() << serviceName << QString(""), QString(), + &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName)); + con.disconnect("org.freedesktop.DBus", QString(), "org.freedesktop.DBus", "NameOwnerChanged", + QStringList() << serviceName << QString(""), QString(), + &QTestEventLoop::instance(), SLOT(exitLoop())); + } } void tst_QDBusMarshall::cleanupTestCase() { proc.close(); - proc.kill(); + proc.terminate(); + proc.waitForFinished(200); } void tst_QDBusMarshall::sendBasic_data() @@ -700,6 +694,8 @@ void tst_QDBusMarshall::sendBasic() msg << value; QDBusMessage reply = con.call(msg); + QVERIFY2(reply.type() == QDBusMessage::ReplyMessage, + qPrintable(reply.errorName() + ": " + reply.errorMessage())); //qDebug() << reply; QCOMPARE(reply.arguments().count(), msg.arguments().count()); @@ -938,5 +934,145 @@ void tst_QDBusMarshall::sendCallErrors() QCOMPARE(reply.errorMessage(), errorMsg); } +void tst_QDBusMarshall::receiveUnknownType_data() +{ + QTest::addColumn<int>("receivedTypeId"); + QTest::newRow("in-call") << qMetaTypeId<void*>(); + QTest::newRow("type-variant") << qMetaTypeId<QDBusVariant>(); + QTest::newRow("type-array") << qMetaTypeId<QDBusArgument>(); + QTest::newRow("type-struct") << qMetaTypeId<QDBusArgument>(); + QTest::newRow("type-naked") << qMetaTypeId<void *>(); +} + +struct DisconnectRawDBus { + static void cleanup(DBusConnection *connection) + { + if (!connection) + return; + dbus_connection_close(connection); + dbus_connection_unref(connection); + } +}; +template <typename T, void (*unref)(T *)> struct GenericUnref +{ + static void cleanup(T *type) + { + if (!type) return; + unref(type); + } +}; + +// use these scoped types to avoid memory leaks if QVERIFY or QCOMPARE fails +typedef QScopedPointer<DBusConnection, DisconnectRawDBus> ScopedDBusConnection; +typedef QScopedPointer<DBusMessage, GenericUnref<DBusMessage, dbus_message_unref> > ScopedDBusMessage; +typedef QScopedPointer<DBusPendingCall, GenericUnref<DBusPendingCall, dbus_pending_call_unref> > ScopedDBusPendingCall; + +void tst_QDBusMarshall::receiveUnknownType() +{ +#ifndef DBUS_TYPE_UNIX_FD + QSKIP("Your system's D-Bus library is too old for this test", SkipAll); +#else + QDBusConnection con = QDBusConnection::sessionBus(); + QVERIFY(con.isConnected()); + + // this needs to be implemented in raw + // open a new connection to the bus daemon + DBusError error; + dbus_error_init(&error); + ScopedDBusConnection rawcon(dbus_bus_get_private(DBUS_BUS_SESSION, &error)); + QVERIFY2(rawcon.data(), error.name); + + // check if this bus supports passing file descriptors + if (!dbus_connection_can_send_type(rawcon.data(), DBUS_TYPE_UNIX_FD)) + QSKIP("Your session bus does not allow sending Unix file descriptors", SkipAll); + + if (qstrcmp(QTest::currentDataTag(), "in-call") == 0) { + // create a call back to us containing a file descriptor + QDBusMessageSpy spy; + con.registerObject("/spyObject", &spy, QDBusConnection::ExportAllSlots); + ScopedDBusMessage msg(dbus_message_new_method_call(con.baseService().toLatin1(), "/spyObject", NULL, "theSlot")); + + int fd = fileno(stdout); + dbus_message_append_args(msg.data(), DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_INVALID); + + // try to send to us + DBusPendingCall *pending_ptr; + dbus_connection_send_with_reply(rawcon.data(), msg.data(), &pending_ptr, 1000); + ScopedDBusPendingCall pending(pending_ptr); + + // check that it got sent + while (dbus_connection_dispatch(rawcon.data()) == DBUS_DISPATCH_DATA_REMAINS) + ; + + // now spin our event loop. We don't catch this call, so let's get the reply + QEventLoop loop; + QTimer::singleShot(200, &loop, SLOT(quit())); + loop.exec(); + + // now try to receive the reply + dbus_pending_call_block(pending.data()); + + // check that the spy received what it was supposed to receive + QCOMPARE(spy.list.size(), 1); + QCOMPARE(spy.list.at(0).arguments().size(), 1); + QFETCH(int, receivedTypeId); + QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId); + + msg.reset(dbus_pending_call_steal_reply(pending.data())); + QVERIFY(msg); + QCOMPARE(dbus_message_get_type(msg.data()), DBUS_MESSAGE_TYPE_METHOD_RETURN); + QCOMPARE(dbus_message_get_signature(msg.data()), DBUS_TYPE_INT32_AS_STRING); + + int retval; + QVERIFY(dbus_message_get_args(msg.data(), &error, DBUS_TYPE_INT32, &retval, DBUS_TYPE_INVALID)); + QCOMPARE(retval, 42); + } else { + // create a signal that we'll emit + static const char signalName[] = "signalName"; + static const char interfaceName[] = "local.interface.name"; + ScopedDBusMessage msg(dbus_message_new_signal("/", interfaceName, signalName)); + con.connect(dbus_bus_get_unique_name(rawcon.data()), QString(), interfaceName, signalName, &QTestEventLoop::instance(), SLOT(exitLoop())); + + QDBusMessageSpy spy; + con.connect(dbus_bus_get_unique_name(rawcon.data()), QString(), interfaceName, signalName, &spy, SLOT(theSlot(QDBusMessage))); + + DBusMessageIter iter; + dbus_message_iter_init_append(msg.data(), &iter); + int fd = fileno(stdout); + + if (qstrcmp(QTest::currentDataTag(), "type-naked") == 0) { + // send naked + dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd); + } else { + DBusMessageIter subiter; + if (qstrcmp(QTest::currentDataTag(), "type-variant") == 0) + dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, DBUS_TYPE_UNIX_FD_AS_STRING, &subiter); + else if (qstrcmp(QTest::currentDataTag(), "type-array") == 0) + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_UNIX_FD_AS_STRING, &subiter); + else if (qstrcmp(QTest::currentDataTag(), "type-struct") == 0) + dbus_message_iter_open_container(&iter, DBUS_TYPE_STRUCT, 0, &subiter); + dbus_message_iter_append_basic(&subiter, DBUS_TYPE_UNIX_FD, &fd); + dbus_message_iter_close_container(&iter, &subiter); + } + + // send it + dbus_connection_send(rawcon.data(), msg.data(), 0); + + // check that it got sent + while (dbus_connection_dispatch(rawcon.data()) == DBUS_DISPATCH_DATA_REMAINS) + ; + + // now let's see what happens + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(spy.list.size(), 1); + QCOMPARE(spy.list.at(0).arguments().count(), 1); + QFETCH(int, receivedTypeId); + //qDebug() << spy.list.at(0).arguments().at(0).typeName(); + QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId); + } +#endif +} + QTEST_MAIN(tst_QDBusMarshall) #include "tst_qdbusmarshall.moc" diff --git a/tests/auto/qdbusxmlparser/tst_qdbusxmlparser.cpp b/tests/auto/qdbusxmlparser/tst_qdbusxmlparser.cpp index 25595c5..f83795c 100644 --- a/tests/auto/qdbusxmlparser/tst_qdbusxmlparser.cpp +++ b/tests/auto/qdbusxmlparser/tst_qdbusxmlparser.cpp @@ -287,11 +287,14 @@ void tst_QDBusXmlParser::methods_data() "</method>" << map; // one invalid arg + method.inputArgs << arg("~", "invalid"); + map.clear(); + map << method; QTest::newRow("two-in-one-invalid") << "<method name=\"Method\">" "<arg type=\"s\" direction=\"in\"/>" - "<arg type=\"~\" name=\"invalid\" direction=\"in\"/>" // this line should be ignored "<arg type=\"v\" direction=\"in\"/>" + "<arg type=\"~\" name=\"invalid\" direction=\"in\"/>" "</method>" << map; // one out argument @@ -380,8 +383,6 @@ void tst_QDBusXmlParser::methods() QFETCH(QString, xmlDataFragment); - if (strcmp(QTest::currentDataTag(), "two-in-one-invalid") == 0) - QTest::ignoreMessage(QtWarningMsg, "Invalid D-BUS type signature '~' found while parsing introspection"); QDBusIntrospection::Interface iface = QDBusIntrospection::parseInterface(xmlHeader + xmlDataFragment + xmlFooter); @@ -390,9 +391,9 @@ void tst_QDBusXmlParser::methods() QFETCH(MethodMap, methodMap); MethodMap parsedMap = iface.methods; - QCOMPARE(methodMap.count(), parsedMap.count()); - QCOMPARE(methodMap, parsedMap); -} + QCOMPARE(parsedMap.count(), methodMap.count()); + QCOMPARE(parsedMap, methodMap); +} void tst_QDBusXmlParser::signals__data() { diff --git a/tests/auto/qfont/tst_qfont.cpp b/tests/auto/qfont/tst_qfont.cpp index 82c8f65..dabe3fa 100644 --- a/tests/auto/qfont/tst_qfont.cpp +++ b/tests/auto/qfont/tst_qfont.cpp @@ -150,6 +150,13 @@ void tst_QFont::exactMatch() return; #endif +#ifdef Q_WS_X11 + QVERIFY(QFont("sans").exactMatch()); + QVERIFY(QFont("sans-serif").exactMatch()); + QVERIFY(QFont("serif").exactMatch()); + QVERIFY(QFont("monospace").exactMatch()); +#endif + QSKIP("This test is bogus on Unix with support for font aliases in fontconfig", SkipAll); return; diff --git a/tests/auto/qfuturewatcher/tst_qfuturewatcher.cpp b/tests/auto/qfuturewatcher/tst_qfuturewatcher.cpp index eb8677a..a4598dc 100644 --- a/tests/auto/qfuturewatcher/tst_qfuturewatcher.cpp +++ b/tests/auto/qfuturewatcher/tst_qfuturewatcher.cpp @@ -486,8 +486,6 @@ class ProgressTextTask : public RunFunctionTask<T> public: void runFunctor() { - while (this->isProgressUpdateNeeded() == false) - QTest::qSleep(1); this->setProgressValueAndText(1, QLatin1String("Foo 1")); while (this->isProgressUpdateNeeded() == false) @@ -497,6 +495,10 @@ public: while (this->isProgressUpdateNeeded() == false) QTest::qSleep(1); this->setProgressValueAndText(3, QLatin1String("Foo 3")); + + while (this->isProgressUpdateNeeded() == false) + QTest::qSleep(1); + this->setProgressValueAndText(4, QLatin1String("Foo 4")); } }; @@ -524,14 +526,16 @@ void tst_QFutureWatcher::progressText() QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(f.progressText(), QLatin1String("Foo 3")); - QCOMPARE(f.progressValue(), 3); + QCOMPARE(f.progressText(), QLatin1String("Foo 4")); + QCOMPARE(f.progressValue(), 4); QVERIFY(progressValues.contains(1)); QVERIFY(progressValues.contains(2)); QVERIFY(progressValues.contains(3)); + QVERIFY(progressValues.contains(4)); QVERIFY(progressTexts.contains(QLatin1String("Foo 1"))); QVERIFY(progressTexts.contains(QLatin1String("Foo 2"))); QVERIFY(progressTexts.contains(QLatin1String("Foo 3"))); + QVERIFY(progressTexts.contains(QLatin1String("Foo 4"))); } } diff --git a/tests/auto/qimagereader/images/corrupt-pixel-count.xpm b/tests/auto/qimagereader/images/corrupt-pixel-count.xpm new file mode 100644 index 0000000..3a736ff --- /dev/null +++ b/tests/auto/qimagereader/images/corrupt-pixel-count.xpm @@ -0,0 +1,11 @@ +/* XPM */ +static const char *marble_xpm[] = { +/* width height num_colors chars_per_pixel */ +"2 2 2 -2", +/* colors */ +"a c #adadad", +"b c #dedede", +/* pixels */ +"ab", +"ba" +}; diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index 7c2aee8..f02fd6a 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -1410,6 +1410,9 @@ void tst_QImageReader::readFromResources_data() QTest::newRow("corrupt-pixels.xpm") << QString("corrupt-pixels.xpm") << QByteArray("xpm") << QSize(0, 0) << QString("QImage: XPM pixels missing on image line 3"); + QTest::newRow("corrupt-pixel-count.xpm") << QString("corrupt-pixel-count.xpm") + << QByteArray("xpm") << QSize(0, 0) + << QString(""); QTest::newRow("marble.xpm") << QString("marble.xpm") << QByteArray("xpm") << QSize(240, 240) << QString(""); diff --git a/tests/auto/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp b/tests/auto/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp index 10fa7c6..41da16e 100644 --- a/tests/auto/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp +++ b/tests/auto/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp @@ -60,8 +60,8 @@ QString tst_QNetworkProxyFactory::formatProxyName(const QNetworkProxy & proxy) c QString proxyName; if (!proxy.user().isNull()) proxyName.append("%1:%2@").arg(proxy.user(), proxy.password()); - proxyName.append("%1:%2").arg(proxy.hostName(), proxy.port()); - proxyName.append(" (type=%1, capabilities=%2)").arg(proxy.type(), proxy.capabilities()); + proxyName.append(QString("%1:%2").arg(proxy.hostName()).arg(proxy.port())); + proxyName.append(QString(" (type=%1, capabilities=%2)").arg(proxy.type()).arg(proxy.capabilities())); return proxyName; } diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 3715162..93e3051 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -84,8 +84,6 @@ Q_DECLARE_METATYPE(QList<QNetworkProxy>) Q_DECLARE_METATYPE(QNetworkReply::NetworkError) Q_DECLARE_METATYPE(QBuffer*) -const int SynchronousRequestAttribute = QNetworkRequest::DownloadBufferAttribute + 1; - class QNetworkReplyPtr: public QSharedPointer<QNetworkReply> { public: @@ -327,6 +325,7 @@ private Q_SLOTS: void ioGetFromHttpBrokenChunkedEncoding(); void qtbug12908compressedHttpReply(); + void compressedHttpReplyBrokenGzip(); void getFromUnreachableIp(); @@ -340,7 +339,9 @@ private Q_SLOTS: void synchronousRequest_data(); void synchronousRequest(); +#ifndef QT_NO_OPENSSL void synchronousRequestSslFailure(); +#endif void httpAbort(); @@ -457,6 +458,7 @@ private: { //qDebug() << "connectSocketSignals" << client; connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot())); connect(client, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotError(QAbstractSocket::SocketError))); } @@ -484,15 +486,19 @@ public slots: if (multiple) receivedData.remove(0, doubleEndlPos+4); - client->write(dataToTransmit); - while (client->bytesToWrite() > 0) - client->waitForBytesWritten(); + // we need to emulate the bytesWrittenSlot call if the data is empty. + if (dataToTransmit.size() == 0) + QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection); + else + client->write(dataToTransmit); + } + } - if (doClose) { - client->disconnectFromHost(); - disconnect(client, 0, this, 0); - client = 0; - } + void bytesWrittenSlot() { + if (doClose && client->bytesToWrite() == 0) { + client->disconnectFromHost(); + disconnect(client, 0, this, 0); + client = 0; } } }; @@ -961,7 +967,9 @@ tst_QNetworkReply::tst_QNetworkReply() qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy qRegisterMetaType<QAuthenticator *>(); qRegisterMetaType<QNetworkProxy>(); +#ifndef QT_NO_OPENSSL qRegisterMetaType<QList<QSslError> >(); +#endif Q_SET_DEFAULT_IAP @@ -1057,7 +1065,7 @@ QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op, returnCode = Timeout; int code = Success; - if (request.attribute(static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute)).toBool()) { + if (request.attribute(QNetworkRequest::SynchronousRequestAttribute).toBool()) { if (reply->isFinished()) code = reply->error() != QNetworkReply::NoError ? Failure : Success; else @@ -1494,6 +1502,12 @@ void tst_QNetworkReply::getErrors() { QFETCH(QString, url); QNetworkRequest request(url); + +#if defined(Q_OS_WIN) || defined (Q_OS_SYMBIAN) + if (qstrcmp(QTest::currentDataTag(), "empty-scheme-host") == 0) + QTest::ignoreMessage(QtWarningMsg, "QNetworkAccessFileBackendFactory: URL has no schema set, use file:// for files"); +#endif + QNetworkReplyPtr reply = manager.get(request); reply->setParent(this); // we have expect-fails @@ -1508,6 +1522,9 @@ void tst_QNetworkReply::getErrors() //qDebug() << reply->errorString(); QFETCH(int, error); +#if defined(Q_OS_WIN) || defined (Q_OS_SYMBIAN) + QEXPECT_FAIL("empty-scheme-host", "this is expected to fail on Windows and Symbian, QTBUG-17731", Abort); +#endif QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort); // the line below is not necessary QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort); @@ -1680,7 +1697,7 @@ void tst_QNetworkReply::putToHttpSynchronous() QFETCH(QByteArray, data); request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, request, reply, data)); @@ -1740,7 +1757,7 @@ void tst_QNetworkReply::postToHttpSynchronous() QNetworkRequest request(url); request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QNetworkReplyPtr reply; @@ -2255,7 +2272,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth() // now check with synchronous calls: { request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); @@ -2279,7 +2296,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuthSynchronous() QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt")); request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QSignalSpy authspy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); @@ -2364,7 +2381,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuth() reference.seek(0); { request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); @@ -2390,7 +2407,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuthSynchronous() QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt")); manager.setProxy(proxy); request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); @@ -3503,7 +3520,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous() QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); QNetworkRequest request(url); request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]); @@ -3695,12 +3712,12 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() incomingSocket->setReadBufferSize(1*1024); QTestEventLoop::instance().enterLoop(2); // some progress should have been made + QVERIFY(!spy.isEmpty()); QList<QVariant> args = spy.last(); qDebug() << "tst_QNetworkReply::ioPostToHttpsUploadProgress" << args.at(0).toLongLong() << sourceFile.size() << spy.size(); - QVERIFY(!args.isEmpty()); QVERIFY(args.at(0).toLongLong() > 0); // FIXME this is where it messes up @@ -3711,16 +3728,16 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() incomingSocket->read(16*1024); QTestEventLoop::instance().enterLoop(2); // some more progress than before + QVERIFY(!spy.isEmpty()); QList<QVariant> args2 = spy.last(); - QVERIFY(!args2.isEmpty()); QVERIFY(args2.at(0).toLongLong() > args.at(0).toLongLong()); // set the read buffer to unlimited incomingSocket->setReadBufferSize(0); QTestEventLoop::instance().enterLoop(10); // progress should be finished + QVERIFY(!spy.isEmpty()); QList<QVariant> args3 = spy.last(); - QVERIFY(!args3.isEmpty()); QVERIFY(args3.at(0).toLongLong() > args2.at(0).toLongLong()); QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong()); QCOMPARE(args3.at(0).toLongLong(), sourceFile.size()); @@ -3810,6 +3827,8 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp() if (reader.data.size() < testData.size()) { // oops? QCOMPARE(reader.data, testData.mid(0, reader.data.size())); qDebug() << "The data is incomplete, the last" << testData.size() - reader.data.size() << "bytes are missing"; + QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Abort); + QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Abort); } QCOMPARE(reader.data.size(), testData.size()); QCOMPARE(reader.data, testData); @@ -3822,8 +3841,8 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp() const int maxRate = rate * 1024 * (100+allowedDeviation) / 100; qDebug() << minRate << "<="<< server.transferRate << "<=" << maxRate << "?"; QVERIFY(server.transferRate >= minRate); - QEXPECT_FAIL("http+limited", "Limiting is broken right now", Continue); - QEXPECT_FAIL("https+limited", "Limiting is broken right now", Continue); + QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Continue); + QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Continue); QVERIFY(server.transferRate <= maxRate); } } @@ -4274,7 +4293,7 @@ void tst_QNetworkReply::receiveCookiesFromHttpSynchronous() QNetworkRequest request(url); request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QNetworkReplyPtr reply; @@ -4366,7 +4385,7 @@ void tst_QNetworkReply::sendCookiesSynchronous() QNetworkRequest request(url); request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QNetworkReplyPtr reply; @@ -4508,7 +4527,7 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous() // send synchronous request request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QNetworkReplyPtr reply = manager.get(request); @@ -5234,6 +5253,7 @@ void tst_QNetworkReply::qtbug12908compressedHttpReply() // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA"); QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii()); + QCOMPARE(decodedFile.size(), 63); MiniHttpServer server(header.toAscii() + decodedFile); server.doClose = true; @@ -5246,6 +5266,31 @@ void tst_QNetworkReply::qtbug12908compressedHttpReply() QVERIFY(!QTestEventLoop::instance().timeout()); QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->size(), qint64(16384)); + QCOMPARE(reply->readAll(), QByteArray(16384, '\0')); +} + +void tst_QNetworkReply::compressedHttpReplyBrokenGzip() +{ + QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: 63\r\n\r\n"); + + // dd if=/dev/zero of=qtbug-12908 bs=16384 count=1 && gzip qtbug-12908 && base64 -w 0 qtbug-12908.gz + // Then change "BMQ" to "BMX" + QString encodedFile("H4sICDdDaUwAA3F0YnVnLTEyOTA4AO3BMXEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA"); + QByteArray decodedFile = QByteArray::fromBase64(encodedFile.toAscii()); + QCOMPARE(decodedFile.size(), 63); + + MiniHttpServer server(header.toAscii() + decodedFile); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->error(), QNetworkReply::ProtocolFailure); } // TODO add similar test for FTP @@ -5454,7 +5499,7 @@ void tst_QNetworkReply::synchronousRequest() #endif request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QNetworkReplyPtr reply; @@ -5485,6 +5530,7 @@ void tst_QNetworkReply::synchronousRequest() reply->deleteLater(); } +#ifndef QT_NO_OPENSSL void tst_QNetworkReply::synchronousRequestSslFailure() { // test that SSL won't be accepted with self-signed certificate, @@ -5494,7 +5540,7 @@ void tst_QNetworkReply::synchronousRequestSslFailure() QUrl url("https://" + QtNetworkSettings::serverName() + "/qtest/rfc3252.txt"); QNetworkRequest request(url); request.setAttribute( - static_cast<QNetworkRequest::Attribute>(SynchronousRequestAttribute), + QNetworkRequest::SynchronousRequestAttribute, true); QNetworkReplyPtr reply; QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &))); @@ -5503,6 +5549,7 @@ void tst_QNetworkReply::synchronousRequestSslFailure() QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError); QCOMPARE(sslErrorsSpy.count(), 0); } +#endif void tst_QNetworkReply::httpAbort() { diff --git a/tests/auto/qpainter/tst_qpainter.cpp b/tests/auto/qpainter/tst_qpainter.cpp index ce1ff77..c21514b 100644 --- a/tests/auto/qpainter/tst_qpainter.cpp +++ b/tests/auto/qpainter/tst_qpainter.cpp @@ -262,6 +262,8 @@ private slots: void QTBUG14614_gradientCacheRaceCondition(); void drawTextOpacity(); + void QTBUG17053_zeroDashPattern(); + private: void fillData(); void setPenColor(QPainter& p); @@ -4684,6 +4686,26 @@ void tst_QPainter::drawTextOpacity() QCOMPARE(image, copy); } +void tst_QPainter::QTBUG17053_zeroDashPattern() +{ + QImage image(32, 32, QImage::Format_RGB32); + image.fill(0xffffffff); + + QImage original = image; + + QVector<qreal> pattern; + pattern << qreal(0) << qreal(0); + + QPainter p(&image); + QPen pen(Qt::black, 2.0); + pen.setDashPattern(pattern); + + p.setPen(pen); + p.drawLine(0, 0, image.width(), image.height()); + + QCOMPARE(image, original); +} + QTEST_MAIN(tst_QPainter) #include "tst_qpainter.moc" diff --git a/tests/auto/qscriptclass/tst_qscriptclass.cpp b/tests/auto/qscriptclass/tst_qscriptclass.cpp index 5286a5a..9ab8318 100644 --- a/tests/auto/qscriptclass/tst_qscriptclass.cpp +++ b/tests/auto/qscriptclass/tst_qscriptclass.cpp @@ -617,7 +617,7 @@ void tst_QScriptClass::newInstance() QScriptValue obj1 = eng.newObject(&cls); QVERIFY(!obj1.data().isValid()); QVERIFY(obj1.prototype().strictlyEquals(cls.prototype())); - QEXPECT_FAIL("", "classname is not implemented", Continue); + QEXPECT_FAIL("", "QTBUG-17599: classname is not implemented", Continue); QCOMPARE(obj1.toString(), QString::fromLatin1("[object TestClass]")); QCOMPARE(obj1.scriptClass(), (QScriptClass*)&cls); @@ -741,7 +741,7 @@ void tst_QScriptClass::getAndSetPropertyFromCpp() QCOMPARE(obj1.propertyFlags(foo2), foo2Pflags); QVERIFY(cls.lastQueryPropertyObject().strictlyEquals(obj1)); QVERIFY(cls.lastQueryPropertyName() == foo2); - QEXPECT_FAIL("", "classObject.getOwnPropertyDescriptor() reads the property value", Continue); + QEXPECT_FAIL("", "QTBUG-17601: classObject.getOwnPropertyDescriptor() reads the property value", Continue); QVERIFY(!cls.lastPropertyObject().isValid()); QVERIFY(cls.lastPropertyFlagsObject().strictlyEquals(obj1)); QVERIFY(cls.lastPropertyFlagsName() == foo2); diff --git a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp index 9d7e896..457188c 100644 --- a/tests/auto/qscriptcontext/tst_qscriptcontext.cpp +++ b/tests/auto/qscriptcontext/tst_qscriptcontext.cpp @@ -725,10 +725,7 @@ void tst_QScriptContext::backtrace_data() expected << "<native>('hey') at -1" << "<eval>() at 3" - << QString::fromLatin1("foo(arg1 = 'hello', arg2 = 456) at testfile:%0") - // interpreter unfortunately doesn't provide line number for eval() - .arg(qt_script_isJITEnabled() ? 2 : -1); - expected + << "foo(arg1 = 'hello', arg2 = 456) at testfile:2" << "<global>() at testfile:4"; QTest::newRow("eval") << source << expected; @@ -787,10 +784,7 @@ void tst_QScriptContext::backtrace_data() expected << "<native>('hey') at -1" << "<eval>() at 3" - << QString::fromLatin1("plop('hello', 456) at testfile:%0") - // interpreter unfortunately doesn't provide line number for eval() - .arg(qt_script_isJITEnabled() ? 3 : -1); - expected + << "plop('hello', 456) at testfile:3" << "<global>() at testfile:5"; QTest::newRow("eval in member") << source << expected; @@ -987,6 +981,8 @@ void tst_QScriptContext::backtrace() QVERIFY(!eng.hasUncaughtException()); QVERIFY(ret.isArray()); QStringList slist = qscriptvalue_cast<QStringList>(ret); + QEXPECT_FAIL("eval", "QTBUG-17842: Missing line number in backtrace when function calls eval()", Continue); + QEXPECT_FAIL("eval in member", "QTBUG-17842: Missing line number in backtrace when function calls eval()", Continue); QCOMPARE(slist, expectedbacktrace); } diff --git a/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp b/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp index 89c5330..62f899c 100644 --- a/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp +++ b/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp @@ -151,7 +151,7 @@ void tst_QScriptContextInfo::nativeFunction() QVERIFY(info.scriptId() != -1); QCOMPARE(info.fileName(), fileName); QCOMPARE(info.lineNumber(), lineNumber); - QEXPECT_FAIL("", "columnNumber doesn't work", Continue); + QEXPECT_FAIL("", "QTBUG-17602: columnNumber doesn't work", Continue); QCOMPARE(info.columnNumber(), 1); QCOMPARE(info.functionName(), QString()); QCOMPARE(info.functionEndLineNumber(), -1); @@ -183,7 +183,7 @@ void tst_QScriptContextInfo::scriptFunction() QVERIFY(info.scriptId() != -1); QCOMPARE(info.fileName(), fileName); QCOMPARE(info.lineNumber(), lineNumber + 1); - QEXPECT_FAIL("", "columnNumber doesn't work", Continue); + QEXPECT_FAIL("", "QTBUG-17602: columnNumber doesn't work", Continue); QCOMPARE(info.columnNumber(), 2); QCOMPARE(info.functionName(), QString::fromLatin1("bar")); QCOMPARE(info.functionStartLineNumber(), lineNumber); @@ -202,7 +202,7 @@ void tst_QScriptContextInfo::scriptFunction() QVERIFY(info.scriptId() != -1); QCOMPARE(info.fileName(), fileName); QCOMPARE(info.lineNumber(), lineNumber + 3); - QEXPECT_FAIL("", "columnNumber doesn't work", Continue); + QEXPECT_FAIL("", "QTBUG-17602: columnNumber doesn't work", Continue); QCOMPARE(info.columnNumber(), 1); QCOMPARE(info.functionName(), QString()); QCOMPARE(info.functionEndLineNumber(), -1); diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index 589b3b1..bc4091d 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -157,6 +157,7 @@ private slots: void reportAdditionalMemoryCost(); void gcWithNestedDataStructure(); void processEventsWhileRunning(); + void throwErrorFromProcessEvents_data(); void throwErrorFromProcessEvents(); void disableProcessEventsInterval(); void stacktrace(); @@ -164,6 +165,7 @@ private slots: void numberParsing(); void automaticSemicolonInsertion(); void abortEvaluation_notEvaluating(); + void abortEvaluation_data(); void abortEvaluation(); void abortEvaluation_tryCatch(); void abortEvaluation_fromNative(); @@ -235,6 +237,7 @@ private slots: void evaluateProgram_multipleEngines(); void evaluateProgram_empty(); void collectGarbageAfterConnect(); + void collectGarbageAfterNativeArguments(); void promoteThisObjectToQObjectInConstructor(); void scriptValueFromQMetaObject(); @@ -470,10 +473,10 @@ void tst_QScriptEngine::newArray_HooliganTask233836() { QScriptEngine eng; { + // According to ECMA-262, this should cause a RangeError. QScriptValue ret = eng.evaluate("a = new Array(4294967295); a.push('foo')"); - QVERIFY(ret.isNumber()); - QCOMPARE(ret.toInt32(), 0); - QCOMPARE(eng.evaluate("a[4294967295]").toString(), QString::fromLatin1("foo")); + QEXPECT_FAIL("", "ECMA compliance bug in Array.prototype.push: https://bugs.webkit.org/show_bug.cgi?id=55033", Continue); + QVERIFY(ret.isError() && ret.toString().contains(QLatin1String("RangeError"))); } { QScriptValue ret = eng.newArray(0xFFFFFFFF); @@ -672,7 +675,8 @@ void tst_QScriptEngine::jsRegExp() QCOMPARE(r5.toString(), QString::fromLatin1("/foo/gim")); // In JSC, constructing a RegExp from another produces the same identical object. // This is different from SpiderMonkey and old back-end. - QVERIFY(r5.strictlyEquals(r)); + QEXPECT_FAIL("", "RegExp copy-constructor should return a new object: https://bugs.webkit.org/show_bug.cgi?id=55040", Continue); + QVERIFY(!r5.strictlyEquals(r)); QScriptValue r6 = rxCtor.construct(QScriptValueList() << "foo" << "bar"); QVERIFY(r6.isError()); @@ -1316,7 +1320,7 @@ void tst_QScriptEngine::globalObjectProperties() QCOMPARE(global.propertyFlags("URIError"), QScriptValue::SkipInEnumeration); QVERIFY(global.property("Math").isObject()); QVERIFY(!global.property("Math").isFunction()); - QEXPECT_FAIL("", "[ECMA compliance] JSC sets DontDelete flag for Math object", Continue); + QEXPECT_FAIL("", "[ECMA compliance] JSC sets DontDelete flag for Math object: https://bugs.webkit.org/show_bug.cgi?id=55034", Continue); QCOMPARE(global.propertyFlags("Math"), QScriptValue::SkipInEnumeration); } @@ -2960,17 +2964,42 @@ public: QScriptEngine *engine; }; +void tst_QScriptEngine::throwErrorFromProcessEvents_data() +{ + QTest::addColumn<QString>("script"); + QTest::addColumn<QString>("error"); + + QTest::newRow("while (1)") + << QString::fromLatin1("while (1) { }") + << QString::fromLatin1("Error: Killed"); + QTest::newRow("while (1) i++") + << QString::fromLatin1("i = 0; while (1) { i++; }") + << QString::fromLatin1("Error: Killed"); + // Unlike abortEvaluation(), scripts should be able to catch the + // exception. + QTest::newRow("try catch") + << QString::fromLatin1("try {" + " while (1) { }" + "} catch(e) {" + " throw new Error('Caught');" + "}") + << QString::fromLatin1("Error: Caught"); +} + void tst_QScriptEngine::throwErrorFromProcessEvents() { + QFETCH(QString, script); + QFETCH(QString, error); + QScriptEngine eng; EventReceiver2 receiver(&eng); QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); eng.setProcessEventsInterval(100); - QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }")); + QScriptValue ret = eng.evaluate(script); QVERIFY(ret.isError()); - QCOMPARE(ret.toString(), QString::fromLatin1("Error: Killed")); + QCOMPARE(ret.toString(), error); } void tst_QScriptEngine::disableProcessEventsInterval() @@ -3385,8 +3414,26 @@ void tst_QScriptEngine::abortEvaluation_notEvaluating() } } +void tst_QScriptEngine::abortEvaluation_data() +{ + QTest::addColumn<QString>("script"); + + QTest::newRow("while (1)") + << QString::fromLatin1("while (1) { }"); + QTest::newRow("while (1) i++") + << QString::fromLatin1("i = 0; while (1) { i++; }"); + QTest::newRow("try catch") + << QString::fromLatin1("try {" + " while (1) { }" + "} catch(e) {" + " throw new Error('Caught');" + "}"); +} + void tst_QScriptEngine::abortEvaluation() { + QFETCH(QString, script); + QScriptEngine eng; EventReceiver3 receiver(&eng); @@ -3394,7 +3441,7 @@ void tst_QScriptEngine::abortEvaluation() for (int x = 0; x < 4; ++x) { QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); receiver.resultType = EventReceiver3::AbortionResult(x); - QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }")); + QScriptValue ret = eng.evaluate(script); switch (receiver.resultType) { case EventReceiver3::None: QVERIFY(!eng.hasUncaughtException()); @@ -4201,7 +4248,8 @@ void tst_QScriptEngine::getterSetterThisObject_activation() // read eng.evaluate("act.__defineGetter__('x', function() { return this; })"); QVERIFY(eng.evaluate("x === act").toBoolean()); - QEXPECT_FAIL("", "Exotic overload (don't care for now)", Continue); + QEXPECT_FAIL("", "QTBUG-17605: Not possible to implement local variables as getter/setter properties", Abort); + QVERIFY(!eng.hasUncaughtException()); QVERIFY(eng.evaluate("with (act) x").equals("foo")); QVERIFY(eng.evaluate("(function() { with (act) return x; })() === act").toBoolean()); eng.evaluate("q = {}; with (act) with (q) x").equals(eng.evaluate("act")); @@ -5332,7 +5380,7 @@ void tst_QScriptEngine::functionScopes() // top-level functions have only the global object in their scope QScriptValue fun = eng.evaluate("(function() {})"); QVERIFY(fun.isFunction()); - QEXPECT_FAIL("", "Function scope proxying is not implemented", Abort); + QEXPECT_FAIL("", "QScriptValue::scope() is internal, not implemented", Abort); QVERIFY(fun.scope().isObject()); QVERIFY(fun.scope().strictlyEquals(eng.globalObject())); QVERIFY(!eng.globalObject().scope().isValid()); @@ -5641,6 +5689,16 @@ void tst_QScriptEngine::collectGarbageAfterConnect() QVERIFY(widget == 0); } +void tst_QScriptEngine::collectGarbageAfterNativeArguments() +{ + // QTBUG-17788 + QScriptEngine eng; + QScriptContext *ctx = eng.pushContext(); + QScriptValue arguments = ctx->argumentsObject(); + // Shouldn't crash when marking the arguments object. + collectGarbage_helper(eng); +} + static QScriptValue constructQObjectFromThisObject(QScriptContext *ctx, QScriptEngine *eng) { Q_ASSERT(ctx->isCalledAsConstructor()); diff --git a/tests/auto/qscriptengineagent/tst_qscriptengineagent.cpp b/tests/auto/qscriptengineagent/tst_qscriptengineagent.cpp index d89f9f1..065f099 100644 --- a/tests/auto/qscriptengineagent/tst_qscriptengineagent.cpp +++ b/tests/auto/qscriptengineagent/tst_qscriptengineagent.cpp @@ -1291,7 +1291,7 @@ void tst_QScriptEngineAgent::positionChange_1() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, lineNumber); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 8); // 5 + 6 @@ -1326,7 +1326,7 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QVERIFY(spy->at(1).scriptId != spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, lineNumber); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 18); } @@ -1345,7 +1345,7 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 11); } @@ -1376,14 +1376,14 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 31); // void(i) QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(2).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(2).columnNumber, 31); } @@ -1402,21 +1402,21 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 12); // ++i QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(2).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(2).columnNumber, 28); // ++i QCOMPARE(spy->at(3).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(3).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(3).columnNumber, 28); } @@ -1435,28 +1435,28 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 12); // ++i QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(2).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(2).columnNumber, 17); // do QCOMPARE(spy->at(3).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(3).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(3).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(3).columnNumber, 12); // ++i QCOMPARE(spy->at(4).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(4).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(4).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(4).columnNumber, 17); } @@ -1487,7 +1487,7 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 15); } @@ -1506,14 +1506,14 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 32); // continue QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(2).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(2).columnNumber, 32); } @@ -1556,7 +1556,7 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 31); } @@ -1575,14 +1575,14 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 38); // break QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(2).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(2).columnNumber, 45); } @@ -1607,21 +1607,21 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange); QVERIFY(spy->at(0).scriptId != -1); QCOMPARE(spy->at(0).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(0).columnNumber, 7); // i = e QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 29); // i = 2 QCOMPARE(spy->at(2).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(2).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(2).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(2).columnNumber, 48); } @@ -1634,14 +1634,14 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(0).type, ScriptEngineEvent::PositionChange); QVERIFY(spy->at(0).scriptId != -1); QCOMPARE(spy->at(0).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(0).columnNumber, 7); // i = 3 QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 46); } @@ -1663,7 +1663,7 @@ void tst_QScriptEngineAgent::positionChange_2() QCOMPARE(spy->at(1).type, ScriptEngineEvent::PositionChange); QCOMPARE(spy->at(1).scriptId, spy->at(0).scriptId); QCOMPARE(spy->at(1).lineNumber, 1); - QEXPECT_FAIL("", "With JSC-based back-end, column number is always reported as 1", Continue); + QEXPECT_FAIL("", "QTBUG-17609: With JSC-based back-end, column number is always reported as 1", Continue); QCOMPARE(spy->at(1).columnNumber, 20); } delete spy; @@ -2247,8 +2247,7 @@ void tst_QScriptEngineAgent::syntaxError() QCOMPARE(spy->at(i).scriptId, spy->at(0).scriptId); QVERIFY(!spy->at(i).hasExceptionHandler); QVERIFY(spy->at(i).value.isError()); - QEXPECT_FAIL("","QTBUG-6137 There are other messages in JSC",Continue); - QCOMPARE(spy->at(i).value.toString(), QString("SyntaxError: Expected `}'")); + QVERIFY(spy->at(i).value.toString().contains(QLatin1String("SyntaxError"))); QCOMPARE(spy->at(i).scriptId, spy->at(0).scriptId); i = 7; //exit script diff --git a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp index 1607bed..c53abcb 100644 --- a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp +++ b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp @@ -1008,8 +1008,9 @@ void tst_QScriptExtQObject::getSetStaticProperty_methodPersistence() QVERIFY(slot.isFunction()); QScriptValue sameSlot = m_engine->evaluate("myObject.mySlot"); QVERIFY(sameSlot.strictlyEquals(slot)); - sameSlot = m_engine->evaluate("myObject[mySlot()]"); - QEXPECT_FAIL("", "Signature-based method lookup creates new function wrapper object", Continue); + sameSlot = m_engine->evaluate("myObject['mySlot()']"); + QVERIFY(sameSlot.isFunction()); + QEXPECT_FAIL("", "QTBUG-17611: Signature-based method lookup creates new function wrapper object", Continue); QVERIFY(sameSlot.strictlyEquals(slot)); } } @@ -1103,7 +1104,7 @@ void tst_QScriptExtQObject::getSetDynamicProperty_doNotHideJSProperty() val.setProperty("x", 42); m_myObject->setProperty("x", 2222); - QEXPECT_FAIL("", "", Continue); + QEXPECT_FAIL("", "QTBUG-17612: Dynamic C++ property overrides JS property", Continue); // JS should see the original JS value QVERIFY(val.property("x").strictlyEquals(QScriptValue(m_engine, 42))); diff --git a/tests/auto/qscriptjstestsuite/expect_fail.txt b/tests/auto/qscriptjstestsuite/expect_fail.txt new file mode 100644 index 0000000..7f93378 --- /dev/null +++ b/tests/auto/qscriptjstestsuite/expect_fail.txt @@ -0,0 +1,198 @@ +ecma/Array/15.4.3.1-2.js | var props = ''; for ( p in Array ) { props += p } props + +ecma/Boolean/15.6.3.1-1.js | var str='';for ( p in Boolean ) { str += p } str; + +ecma/Expressions/11.4.1.js | var abc; delete(abc) + +ecma/FunctionObjects/15.3.3.1-2.js | var str='';for (prop in Function ) str += prop; str; + +ecma/ObjectObjects/15.2.3.1-1.js | var str = '';for ( p in Object ) { str += p; }; str + +ecma/Statements/12.6.3-11.js | result = ""; for ( p in Number ) { result += String(p) }; +ecma/Statements/12.6.3-2.js | Boolean.prototype.foo = 34; for ( j in Boolean ) Boolean[j] + +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4256) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4257) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4258) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4259) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4260) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4261) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4262) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4263) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4264) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4265) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4266) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4267) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4268) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4269) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4270) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4271) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4272) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4273) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4274) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4275) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4276) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4277) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4278) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4279) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4280) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4281) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4282) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4283) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4284) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4285) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4286) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4287) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4288) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4289) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4290) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4291) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4292) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-2.js | var s = new String( String.fromCharCode(4293) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-5.js | var s = new String( String.fromCharCode(1024) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.11-5.js | var s = new String( String.fromCharCode(1037) ); s.toLowerCase().charCodeAt(0) +ecma/String/15.5.4.12-1.js | var s = new String( String.fromCharCode(181) ); s.toUpperCase().charCodeAt(0) +ecma/String/15.5.4.12-1.js | var s = new String( String.fromCharCode(329) ); s.toUpperCase().charCodeAt(0) +ecma/String/15.5.4.12-4.js | var s = new String( String.fromCharCode(1104) ); s.toUpperCase().charCodeAt(0) +ecma/String/15.5.4.12-4.js | var s = new String( String.fromCharCode(1117) ); s.toUpperCase().charCodeAt(0) +ecma/String/15.5.4.12-5.js | var s = new String( String.fromCharCode(1415) ); s.toUpperCase().charCodeAt(0) + +ecma/TypeConversion/9.3.1-3.js | -"\u20001234\u2001" +ecma/TypeConversion/9.3.1-3.js | - "-0x123456789abcde8" + +ecma/extensions/15.1.2.1-1.js | var PROPS = ''; for ( p in eval ) { PROPS += p }; PROPS + +ecma/GlobalObject/15.1.2.2-1.js | var PROPS=''; for ( var p in parseInt ) { PROPS += p; }; PROPS +ecma/GlobalObject/15.1.2.3-1.js | var MYPROPS=''; for ( var p in parseFloat ) { MYPROPS += p }; MYPROPS +ecma/GlobalObject/15.1.2.4.js | var MYPROPS=''; for ( var p in escape ) { MYPROPS+= p}; MYPROPS +ecma/GlobalObject/15.1.2.5-1.js | var MYPROPS=''; for ( var p in unescape ) { MYPROPS+= p }; MYPROPS +ecma/GlobalObject/15.1.2.6.js | var MYPROPS=''; for ( var p in isNaN ) { MYPROPS+= p }; MYPROPS +ecma/GlobalObject/15.1.2.7.js | var MYPROPS=''; for ( p in isFinite ) { MYPROPS+= p }; MYPROPS + +ecma_3/Array/15.4.5.1-01.js | 15.4.5.1 - array.length coverage + +ecma_3/extensions/regress-274152.js | Do not ignore unicode format-control characters: 0 +ecma_3/extensions/regress-274152.js | Do not ignore unicode format-control characters: 1 +ecma_3/extensions/regress-274152.js | Do not ignore unicode format-control characters: 2 +ecma_3/extensions/regress-274152.js | Do not ignore unicode format-control characters: 3 +ecma_3/extensions/regress-274152.js | Do not ignore unicode format-control characters: 4 +ecma_3/extensions/regress-274152.js | Do not ignore unicode format-control characters: 5 +ecma_3/extensions/regress-274152.js | Do not ignore unicode format-control characters: 6 +ecma_3/extensions/regress-274152.js | Do not ignore unicode format-control characters: 7 +ecma_3/extensions/regress-274152.js | Do not ignore unicode format-control characters: 8 +ecma_3/extensions/regress-368516.js | Treat unicode BOM characters as whitespace: 0 +ecma_3/extensions/regress-368516.js | Treat unicode BOM characters as whitespace: 1 + +ecma_3/Date/15.9.4.3.js | 15.9.4.3 - Date.UTC edge-case arguments.: date Infinity +ecma_3/Date/15.9.4.3.js | 15.9.4.3 - Date.UTC edge-case arguments.: hours Infinity +ecma_3/Date/15.9.4.3.js | 15.9.4.3 - Date.UTC edge-case arguments.: minutes Infinity +ecma_3/Date/15.9.4.3.js | 15.9.4.3 - Date.UTC edge-case arguments.: seconds Infinity +ecma_3/Function/regress-131964.js | Section 1 of test - +ecma_3/Function/regress-313570.js | length of objects whose prototype chain includes a function: immutable +ecma_3/FunExpr/fe-001.js | Both functions were defined. + +ecma_3/LexicalConventions/7.9.1.js | Automatic Semicolon insertion in postfix expressions: expr\n++ +ecma_3/LexicalConventions/7.9.1.js | Automatic Semicolon insertion in postfix expressions: expr\n-- +ecma_3/LexicalConventions/7.9.1.js | Automatic Semicolon insertion in postfix expressions: (x\n)-- y +ecma_3/LexicalConventions/7.9.1.js | Automatic Semicolon insertion in postfix expressions: (x)-- y + +ecma_3/Object/8.6.1-01.js | In strict mode, setting a read-only property should generate a warning: Throw if STRICT and WERROR is enabled + +ecma_3/Operators/order-01.js | operator evaluation order: 11.8.2 > +ecma_3/Operators/order-01.js | operator evaluation order: 11.8.4 >= + +ecma_3/RegExp/15.10.2-1.js | Section 7 of test - \nregexp = /(z)((a+)?(b+)?(c))*/\nstring = 'zaacbbbcac'\nERROR !!! regexp failed to give expected match array:\nExpect: ["zaacbbbcac", "z", "ac", "a", , "c"]\nActual: ["zaacbbbcac", "z", "ac", "a", "bbb", "c"]\n +ecma_3/RegExp/15.10.2-1.js | Section 8 of test - \nregexp = /(a*)*/\nstring = 'b'\nERROR !!! regexp failed to give expected match array:\nExpect: ["", , ]\nActual: ["", ""]\n +ecma_3/RegExp/15.10.2-1.js | Section 12 of test - \nregexp = /(.*?)a(?!(a+)b\2c)\2(.*)/\nstring = 'baaabaac'\nERROR !!! regexp failed to give expected match array:\nExpect: ["baaabaac", "ba", , "abaac"]\nActual: ["baaabaac", "ba", "aa", "abaac"]\n +ecma_3/RegExp/perlstress-001.js | Section 218 of test - \nregexp = /((foo)|(bar))*/\nstring = 'foobar'\nERROR !!! regexp failed to give expected match array:\nExpect: ["foobar", "bar", , "bar"]\nActual: ["foobar", "bar", "foo", "bar"]\n +ecma_3/RegExp/perlstress-001.js | Section 234 of test - \nregexp = /(?:(f)(o)(o)|(b)(a)(r))*/\nstring = 'foobar'\nERROR !!! regexp failed to give expected match array:\nExpect: ["foobar", , , , "b", "a", "r"]\nActual: ["foobar", "f", "o", "o", "b", "a", "r"]\n +ecma_3/RegExp/perlstress-001.js | Section 241 of test - \nregexp = /^(?:b|a(?=(.)))*\1/\nstring = 'abc'\nERROR !!! regexp failed to give expected match array:\nExpect: ["ab", , ]\nActual: ["ab", "b"]\n +ecma_3/RegExp/perlstress-001.js | Section 412 of test - \nregexp = /^(a(b)?)+$/\nstring = 'aba'\nERROR !!! regexp failed to give expected match array:\nExpect: ["aba", "a", , ]\nActual: ["aba", "a", "b"]\n +ecma_3/RegExp/perlstress-001.js | Section 413 of test - \nregexp = /^(aa(bb)?)+$/\nstring = 'aabbaa'\nERROR !!! regexp failed to give expected match array:\nExpect: ["aabbaa", "aa", , ]\nActual: ["aabbaa", "aa", "bb"]\n + +ecma_3/RegExp/regress-209919.js | Section 1 of test - \nregexp = /(a|b*)*/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: ["a", "a"]\nActual: ["a", ""]\n +ecma_3/RegExp/regress-209919.js | Section 3 of test - \nregexp = /(b*)*/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: ["", , ]\nActual: ["", ""]\n +ecma_3/RegExp/regress-209919.js | Section 5 of test - \nregexp = /^\-?(\d{1,}|\.{0,})*(\,\d{1,})?$/\nstring = '100.00'\nERROR !!! regexp failed to give expected match array:\nExpect: ["100.00", "00", , ]\nActual: ["100.00", "", , ]\n +ecma_3/RegExp/regress-209919.js | Section 6 of test - \nregexp = /^\-?(\d{1,}|\.{0,})*(\,\d{1,})?$/\nstring = '100,00'\nERROR !!! regexp failed to give expected match array:\nExpect: ["100,00", "100", ",00"]\nActual: ["100,00", "", ",00"]\n +ecma_3/RegExp/regress-209919.js | Section 7 of test - \nregexp = /^\-?(\d{1,}|\.{0,})*(\,\d{1,})?$/\nstring = '1.000,00'\nERROR !!! regexp failed to give expected match array:\nExpect: ["1.000,00", "000", ",00"]\nActual: ["1.000,00", "", ",00"]\n + +ecma_3/String/15.5.4.11.js | Section 7 +ecma_3/String/15.5.4.11.js | Section 24 +ecma_3/String/15.5.4.11.js | Section 26 +ecma_3/String/15.5.4.11.js | Section 28 +ecma_3/String/15.5.4.11.js | Section 30 +ecma_3/String/15.5.4.14.js | 15.5.4.14 - String.prototype.split(/()/) + +ecma_3/Unicode/regress-352044-01.js | issues with Unicode escape sequences in JavaScript source code +ecma_3/Unicode/uc-001.js | Unicode format-control character test (Category Cf.) + +ecma_2/RegExp/exec-001.js | NO TESTS EXIST +ecma_2/String/replace-001.js | NO TESTS EXIST + +[Q_CC_MSVC] +ecma_3/Expressions/11.7.3-01.js | 11.7.3 - >>> should evaluate operands in order: order | QTBUG-8056 +ecma_3/Operators/order-01.js | operator evaluation order: 11.7.3 >>> | QTBUG-8056 +ecma_3/Operators/order-01.js | operator evaluation order: 11.13.2 >>>= | QTBUG-8056 + +[Q_CC_MINGW] +ecma/Math/15.8.2.13.js | Math.pow(NaN,0) +ecma/Math/15.8.2.13.js | Math.pow(NaN,-0) +ecma/Math/15.8.2.5.js | Math.atan2(Infinity, Infinity) +ecma/Math/15.8.2.5.js | Math.atan2(Infinity, -Infinity) +ecma/Math/15.8.2.5.js | Math.atan2(-Infinity, Infinity) +ecma/Math/15.8.2.5.js | Math.atan2(-Infinity, -Infinity) + +[Q_OS_SOLARIS] +ecma/Expressions/11.13.2-2.js | VAR1 = -0; VAR2= Infinity; VAR2 /= VAR1 +ecma/Expressions/11.13.2-2.js | VAR1 = -0; VAR2= -Infinity; VAR2 /= VAR1 +ecma/Expressions/11.13.2-2.js | VAR1 = 1; VAR2= -0; VAR1 /= VAR2 +ecma/Expressions/11.13.2-2.js | VAR1 = -1; VAR2= -0; VAR1 /= VAR2 +ecma/Expressions/11.5.2.js | Number.POSITIVE_INFINITY / -0 +ecma/Expressions/11.5.2.js | Number.NEGATIVE_INFINITY / -0 +ecma/Expressions/11.5.2.js | 1 / -0 +ecma/Expressions/11.5.2.js | -1 / -0 +ecma/Math/15.8.2.10.js | Math.log(-0.0000001) +ecma/Math/15.8.2.10.js | Math.log(-1) +ecma/Math/15.8.2.11.js | Infinity/Math.max(-0,-0) +ecma/Math/15.8.2.12.js | Infinity/Math.min(0,-0) +ecma/Math/15.8.2.12.js | Infinity/Math.min(-0,-0) +ecma/Math/15.8.2.13.js | Math.pow(NaN,0) +ecma/Math/15.8.2.13.js | Math.pow(NaN,-0) +ecma/Math/15.8.2.13.js | Infinity/Math.pow(-Infinity, -1) +ecma/Math/15.8.2.13.js | Math.pow(0, -1) +ecma/Math/15.8.2.13.js | Math.pow(0, -0.5) +ecma/Math/15.8.2.13.js | Math.pow(0, -1000) +ecma/Math/15.8.2.13.js | Infinity/Math.pow(-0, 1) +ecma/Math/15.8.2.13.js | Infinity/Math.pow(-0, 3) +ecma/Math/15.8.2.13.js | Math.pow(-0, -2) +ecma/Math/15.8.2.15.js | Infinity/Math.round(-0) +ecma/Math/15.8.2.15.js | Infinity/Math.round(-0.49) +ecma/Math/15.8.2.15.js | Infinity/Math.round(-0.5) +ecma/Math/15.8.2.17.js | Infinity/Math.sqrt(-0) +ecma/Math/15.8.2.18.js | Infinity/Math.tan(-0) +ecma/Math/15.8.2.2.js | Math.acos(1.00000001) +ecma/Math/15.8.2.2.js | Math.acos(11.00000001) +ecma/Math/15.8.2.3.js | Math.asin(1.000001) +ecma/Math/15.8.2.3.js | Math.asin(-1.000001) +ecma/Math/15.8.2.3.js | Infinity/Math.asin(-0) +ecma/Math/15.8.2.4.js | Infinity/Math.atan(-0) +ecma/Math/15.8.2.5.js | Math.atan2(0, -0) +ecma/Math/15.8.2.5.js | Infinity/Math.atan2(-0, 1) +ecma/Math/15.8.2.5.js | Math.atan2(-0,\t-0) +ecma/Math/15.8.2.5.js | Math.atan2(-0,\t-1) +ecma/Math/15.8.2.6.js | Infinity/Math.ceil('-0') +ecma/Math/15.8.2.6.js | Infinity/Math.ceil(-0) +ecma/Math/15.8.2.6.js | Infinity/Math.ceil(-Number.MIN_VALUE) +ecma/Math/15.8.2.6.js | Infinity/Math.ceil(-0.9) +ecma/Math/15.8.2.9.js | Infinity/Math.floor(-0) +ecma/TypeConversion/9.3.1-3.js | var z = 0; print(1/-z) +ecma/TypeConversion/9.3.1-3.js | 1/-1e-2000 + +[Q_OS_SYMBIAN] +ecma/Math/15.8.2.13.js | Math.pow(-1, 0.5) +ecma/Math/15.8.2.13.js | Math.pow(-1, -0.5) +ecma_3/Operators/order-01.js | operator evaluation order: 11.5.1 * +ecma_3/Operators/order-01.js | operator evaluation order: 11.5.2 / +ecma_3/Operators/order-01.js | operator evaluation order: 11.6.2 - +ecma_3/Operators/order-01.js | operator evaluation order: 11.13.2 *= +ecma_3/Operators/order-01.js | operator evaluation order: 11.13.2 /= diff --git a/tests/auto/qscriptjstestsuite/qscriptjstestsuite.pro b/tests/auto/qscriptjstestsuite/qscriptjstestsuite.pro index b1ddd64..471aa02 100644 --- a/tests/auto/qscriptjstestsuite/qscriptjstestsuite.pro +++ b/tests/auto/qscriptjstestsuite/qscriptjstestsuite.pro @@ -1,6 +1,8 @@ load(qttest_p4) QT = core script SOURCES += tst_qscriptjstestsuite.cpp +RESOURCES += qscriptjstestsuite.qrc +include(../qscriptv8testsuite/abstracttestsuite.pri) !symbian: DEFINES += SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/qscriptjstestsuite/qscriptjstestsuite.qrc b/tests/auto/qscriptjstestsuite/qscriptjstestsuite.qrc new file mode 100644 index 0000000..4a4eb60 --- /dev/null +++ b/tests/auto/qscriptjstestsuite/qscriptjstestsuite.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>expect_fail.txt</file> + <file>skip.txt</file> +</qresource> +</RCC> diff --git a/tests/auto/qscriptjstestsuite/skip.txt b/tests/auto/qscriptjstestsuite/skip.txt new file mode 100644 index 0000000..2dc0ccb --- /dev/null +++ b/tests/auto/qscriptjstestsuite/skip.txt @@ -0,0 +1,9 @@ +.+/15\.9\.2\..+ | unstable on slow machines +.+/15\.9\.5\..+ | too slooow +regress-130451.js | asserts +regress-322135-01.js | asserts +regress-322135-02.js | asserts +regress-322135-03.js | takes forever +regress-322135-04.js | takes forever +ecma_3/RegExp/regress-375715-04.js | bug +ecma_3/RegExp/regress-289669.js | Can fail due to relying on wall-clock time diff --git a/tests/auto/qscriptjstestsuite/tst_qscriptjstestsuite.cpp b/tests/auto/qscriptjstestsuite/tst_qscriptjstestsuite.cpp index 43a6dba..e042dfe 100644 --- a/tests/auto/qscriptjstestsuite/tst_qscriptjstestsuite.cpp +++ b/tests/auto/qscriptjstestsuite/tst_qscriptjstestsuite.cpp @@ -40,44 +40,18 @@ ****************************************************************************/ +#include "abstracttestsuite.h" #include <QtTest/QtTest> #include <QtScript> #if defined(Q_OS_SYMBIAN) -# define SRCDIR "" +# define SRCDIR "." #endif //TESTED_CLASS= //TESTED_FILES= -// Uncomment the following define to have the autotest generate -// addExpectedFailure() code for all the tests that fail. -// This is useful when a whole new test (sub)suite is added. -// The code is stored in addexpectedfailures.cpp. -// Paste the contents into this file after the existing -// addExpectedFailure() calls. - -//#define GENERATE_ADDEXPECTEDFAILURE_CODE - -static QString readFile(const QString &filename) -{ - QFile file(filename); - if (!file.open(QFile::ReadOnly)) - return QString(); - QTextStream stream(&file); - return stream.readAll(); -} - -static void appendCString(QVector<char> *v, const char *s) -{ - char c; - do { - c = *(s++); - *v << c; - } while (c != '\0'); -} - struct TestRecord { TestRecord() : lineNumber(-1) { } @@ -120,17 +94,18 @@ struct FailureItem QString message; }; -class tst_Suite : public QObject +class tst_QScriptJSTestSuite : public AbstractTestSuite { public: - tst_Suite(); - virtual ~tst_Suite(); + tst_QScriptJSTestSuite(); + virtual ~tst_QScriptJSTestSuite(); - static QMetaObject staticMetaObject; - virtual const QMetaObject *metaObject() const; - virtual void *qt_metacast(const char *); - virtual int qt_metacall(QMetaObject::Call, int, void **argv); +protected: + virtual void configData(TestConfig::Mode mode, const QStringList &parts); + virtual void writeSkipConfigFile(QTextStream &); + virtual void writeExpectFailConfigFile(QTextStream &); + virtual void runTestFunction(int testIndex); private: void addExpectedFailure(const QString &fileName, const QString &description, const QString &message); @@ -143,33 +118,11 @@ private: void addFileExclusion(const QRegExp &rx, const QString &message); bool isExcludedFile(const QString &fileName, QString *message) const; - QDir testsDir; QList<QString> subSuitePaths; QList<FailureItem> expectedFailures; QList<QPair<QRegExp, QString> > fileExclusions; -#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE - QString generatedAddExpectedFailureCode; -#endif }; -QMetaObject tst_Suite::staticMetaObject; - -Q_GLOBAL_STATIC(QVector<uint>, qt_meta_data_tst_Suite) -Q_GLOBAL_STATIC(QVector<char>, qt_meta_stringdata_tst_Suite) - -const QMetaObject *tst_Suite::metaObject() const -{ - return &staticMetaObject; -} - -void *tst_Suite::qt_metacast(const char *_clname) -{ - if (!_clname) return 0; - if (!strcmp(_clname, qt_meta_stringdata_tst_Suite()->constData())) - return static_cast<void*>(const_cast<tst_Suite*>(this)); - return QObject::qt_metacast(_clname); -} - static QScriptValue qscript_void(QScriptContext *, QScriptEngine *eng) { return eng->undefinedValue(); @@ -222,625 +175,245 @@ static QScriptValue qscript_TestCase(QScriptContext *ctx, QScriptEngine *eng) return ret; } -int tst_Suite::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +void tst_QScriptJSTestSuite::runTestFunction(int testIndex) { - _id = QObject::qt_metacall(_c, _id, _a); - if (_id < 0) - return _id; - if (_c == QMetaObject::InvokeMetaMethod) { - if (!(_id & 1)) { - // data - QTest::addColumn<TestRecord>("record"); - bool hasData = false; - - QString testsShellPath = testsDir.absoluteFilePath("shell.js"); - QString testsShellContents = readFile(testsShellPath); - - QDir subSuiteDir(subSuitePaths.at(_id / 2)); - QString subSuiteShellPath = subSuiteDir.absoluteFilePath("shell.js"); - QString subSuiteShellContents = readFile(subSuiteShellPath); - - QDir testSuiteDir(subSuiteDir); - testSuiteDir.cdUp(); - QString suiteJsrefPath = testSuiteDir.absoluteFilePath("jsref.js"); - QString suiteJsrefContents = readFile(suiteJsrefPath); - QString suiteShellPath = testSuiteDir.absoluteFilePath("shell.js"); - QString suiteShellContents = readFile(suiteShellPath); - - QFileInfoList testFileInfos = subSuiteDir.entryInfoList(QStringList() << "*.js", QDir::Files); - foreach (QFileInfo tfi, testFileInfos) { - if ((tfi.fileName() == "shell.js") || (tfi.fileName() == "browser.js")) - continue; - - QString abspath = tfi.absoluteFilePath(); - QString relpath = testsDir.relativeFilePath(abspath); - QString excludeMessage; - if (isExcludedFile(relpath, &excludeMessage)) { - QTest::newRow(relpath.toLatin1()) << TestRecord(excludeMessage, relpath); - continue; - } + if (!(testIndex & 1)) { + // data + QTest::addColumn<TestRecord>("record"); + bool hasData = false; + + QString testsShellPath = testsDir.absoluteFilePath("shell.js"); + QString testsShellContents = readFile(testsShellPath); + + QDir subSuiteDir(subSuitePaths.at(testIndex / 2)); + QString subSuiteShellPath = subSuiteDir.absoluteFilePath("shell.js"); + QString subSuiteShellContents = readFile(subSuiteShellPath); + + QDir testSuiteDir(subSuiteDir); + testSuiteDir.cdUp(); + QString suiteJsrefPath = testSuiteDir.absoluteFilePath("jsref.js"); + QString suiteJsrefContents = readFile(suiteJsrefPath); + QString suiteShellPath = testSuiteDir.absoluteFilePath("shell.js"); + QString suiteShellContents = readFile(suiteShellPath); + + QFileInfoList testFileInfos = subSuiteDir.entryInfoList(QStringList() << "*.js", QDir::Files); + foreach (QFileInfo tfi, testFileInfos) { + if ((tfi.fileName() == "shell.js") || (tfi.fileName() == "browser.js")) + continue; + + QString abspath = tfi.absoluteFilePath(); + QString relpath = testsDir.relativeFilePath(abspath); + QString excludeMessage; + if (isExcludedFile(relpath, &excludeMessage)) { + QTest::newRow(relpath.toLatin1()) << TestRecord(excludeMessage, relpath); + continue; + } - QScriptEngine eng; - QScriptValue global = eng.globalObject(); - global.setProperty("print", eng.newFunction(qscript_void)); - global.setProperty("quit", eng.newFunction(qscript_quit)); - global.setProperty("options", eng.newFunction(qscript_options)); - - eng.evaluate(testsShellContents, testsShellPath); - if (eng.hasUncaughtException()) { - QStringList bt = eng.uncaughtExceptionBacktrace(); - QString err = eng.uncaughtException().toString(); - qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); - break; - } + QScriptEngine eng; + QScriptValue global = eng.globalObject(); + global.setProperty("print", eng.newFunction(qscript_void)); + global.setProperty("quit", eng.newFunction(qscript_quit)); + global.setProperty("options", eng.newFunction(qscript_options)); + + eng.evaluate(testsShellContents, testsShellPath); + if (eng.hasUncaughtException()) { + QStringList bt = eng.uncaughtExceptionBacktrace(); + QString err = eng.uncaughtException().toString(); + qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); + break; + } - eng.evaluate(suiteJsrefContents, suiteJsrefPath); - if (eng.hasUncaughtException()) { - QStringList bt = eng.uncaughtExceptionBacktrace(); - QString err = eng.uncaughtException().toString(); - qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); - break; - } + eng.evaluate(suiteJsrefContents, suiteJsrefPath); + if (eng.hasUncaughtException()) { + QStringList bt = eng.uncaughtExceptionBacktrace(); + QString err = eng.uncaughtException().toString(); + qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); + break; + } - eng.evaluate(suiteShellContents, suiteShellPath); - if (eng.hasUncaughtException()) { - QStringList bt = eng.uncaughtExceptionBacktrace(); - QString err = eng.uncaughtException().toString(); - qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); - break; - } + eng.evaluate(suiteShellContents, suiteShellPath); + if (eng.hasUncaughtException()) { + QStringList bt = eng.uncaughtExceptionBacktrace(); + QString err = eng.uncaughtException().toString(); + qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); + break; + } - eng.evaluate(subSuiteShellContents, subSuiteShellPath); - if (eng.hasUncaughtException()) { - QStringList bt = eng.uncaughtExceptionBacktrace(); - QString err = eng.uncaughtException().toString(); - qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); - break; - } + eng.evaluate(subSuiteShellContents, subSuiteShellPath); + if (eng.hasUncaughtException()) { + QStringList bt = eng.uncaughtExceptionBacktrace(); + QString err = eng.uncaughtException().toString(); + qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); + break; + } - QScriptValue origTestCaseCtor = global.property("TestCase"); - QScriptValue myTestCaseCtor = eng.newFunction(qscript_TestCase); - myTestCaseCtor.setData(origTestCaseCtor); - global.setProperty("TestCase", myTestCaseCtor); + QScriptValue origTestCaseCtor = global.property("TestCase"); + QScriptValue myTestCaseCtor = eng.newFunction(qscript_TestCase); + myTestCaseCtor.setData(origTestCaseCtor); + global.setProperty("TestCase", myTestCaseCtor); - global.setProperty("gTestfile", tfi.fileName()); - global.setProperty("gTestsuite", testSuiteDir.dirName()); - global.setProperty("gTestsubsuite", subSuiteDir.dirName()); - QString testFileContents = readFile(abspath); + global.setProperty("gTestfile", tfi.fileName()); + global.setProperty("gTestsuite", testSuiteDir.dirName()); + global.setProperty("gTestsubsuite", subSuiteDir.dirName()); + QString testFileContents = readFile(abspath); // qDebug() << relpath; - eng.evaluate(testFileContents, abspath); - if (eng.hasUncaughtException() && !relpath.endsWith("-n.js")) { - QStringList bt = eng.uncaughtExceptionBacktrace(); - QString err = eng.uncaughtException().toString(); - qWarning("%s\n%s\n", qPrintable(err), qPrintable(bt.join("\n"))); - continue; - } + eng.evaluate(testFileContents, abspath); + if (eng.hasUncaughtException() && !relpath.endsWith("-n.js")) { + QStringList bt = eng.uncaughtExceptionBacktrace(); + QString err = eng.uncaughtException().toString(); + qWarning("%s\n%s\n", qPrintable(err), qPrintable(bt.join("\n"))); + continue; + } - QScriptValue testcases = global.property("testcases"); - if (!testcases.isArray()) - testcases = global.property("gTestcases"); - int count = testcases.property("length").toInt32(); - if (count == 0) - continue; - - hasData = true; - QString title = global.property("TITLE").toString(); - for (int i = 0; i < count; ++i) { - QScriptValue kase = testcases.property(i); - QString description = kase.property("description").toString(); - QScriptValue expect = kase.property("expect"); - QScriptValue actual = kase.property("actual"); - bool passed = kase.property("passed").toBoolean(); - int lineNumber = kase.property("__lineNumber__").toInt32(); - - TestRecord rec(description, passed, - actual.toString(), expect.toString(), - relpath, lineNumber); - - QTest::newRow(description.toLatin1()) << rec; - } + QScriptValue testcases = global.property("testcases"); + if (!testcases.isArray()) + testcases = global.property("gTestcases"); + int count = testcases.property("length").toInt32(); + if (count == 0) + continue; + + hasData = true; + QString title = global.property("TITLE").toString(); + for (int i = 0; i < count; ++i) { + QScriptValue kase = testcases.property(i); + QString description = kase.property("description").toString(); + QScriptValue expect = kase.property("expect"); + QScriptValue actual = kase.property("actual"); + bool passed = kase.property("passed").toBoolean(); + int lineNumber = kase.property("__lineNumber__").toInt32(); + + TestRecord rec(description, passed, + actual.toString(), expect.toString(), + relpath, lineNumber); + + QTest::newRow(description.toLatin1()) << rec; } - if (!hasData) - QTest::newRow("") << TestRecord(); // dummy + } + if (!hasData) + QTest::newRow("") << TestRecord(); // dummy + } else { + QFETCH(TestRecord, record); + if ((record.lineNumber == -1) && (record.actual == "QSKIP")) { + QTest::qSkip(record.description.toLatin1(), QTest::SkipAll, record.fileName.toLatin1(), -1); } else { - QFETCH(TestRecord, record); - if ((record.lineNumber == -1) && (record.actual == "QSKIP")) { - QTest::qSkip(record.description.toLatin1(), QTest::SkipAll, record.fileName.toLatin1(), -1); - } else { - QString msg; - FailureItem::Action failAct; - bool expectFail = isExpectedFailure(record.fileName, record.description, &msg, &failAct); - if (expectFail) { - switch (failAct) { - case FailureItem::ExpectFail: - QTest::qExpectFail("", msg.toLatin1(), - QTest::Continue, record.fileName.toLatin1(), - record.lineNumber); - break; - case FailureItem::Skip: - QTest::qSkip(msg.toLatin1(), QTest::SkipSingle, - record.fileName.toLatin1(), record.lineNumber); - break; - } + QString msg; + FailureItem::Action failAct; + bool expectFail = isExpectedFailure(record.fileName, record.description, &msg, &failAct); + if (expectFail) { + switch (failAct) { + case FailureItem::ExpectFail: + QTest::qExpectFail("", msg.toLatin1(), + QTest::Continue, record.fileName.toLatin1(), + record.lineNumber); + break; + case FailureItem::Skip: + QTest::qSkip(msg.toLatin1(), QTest::SkipSingle, + record.fileName.toLatin1(), record.lineNumber); + break; } - if (!expectFail || (failAct == FailureItem::ExpectFail)) { - if (!record.passed) { -#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE - if (!expectFail) { - QString escapedDescription = record.description; - escapedDescription.replace("\\", "\\\\"); - escapedDescription.replace("\n", "\\n"); - escapedDescription.replace("\"", "\\\""); - generatedAddExpectedFailureCode.append( - " addExpectedFailure(\"" + record.fileName - + "\", \"" + escapedDescription + - "\", willFixInNextReleaseMessage);\n"); - } -#endif - QTest::qCompare(record.actual, record.expected, "actual", "expect", - record.fileName.toLatin1(), record.lineNumber); - } else { - QTest::qCompare(record.actual, record.actual, "actual", "expect", - record.fileName.toLatin1(), record.lineNumber); + } + if (!expectFail || (failAct == FailureItem::ExpectFail)) { + if (!record.passed) { + if (!expectFail && shouldGenerateExpectedFailures) { + addExpectedFailure(record.fileName, + record.description, + QString()); } + QTest::qCompare(record.actual, record.expected, "actual", "expect", + record.fileName.toLatin1(), record.lineNumber); + } else { + QTest::qCompare(record.actual, record.actual, "actual", "expect", + record.fileName.toLatin1(), record.lineNumber); } } } - _id -= subSuitePaths.size()*2; } - return _id; } -tst_Suite::tst_Suite() +tst_QScriptJSTestSuite::tst_QScriptJSTestSuite() + : AbstractTestSuite("tst_QScriptJsTestSuite", + QString::fromLatin1("%0/tests").arg(SRCDIR), + ":/") { - testsDir = QDir(SRCDIR); - bool testsFound = testsDir.cd("tests"); - if (!testsFound) { - qWarning("*** no tests/ dir!"); - } - - QString willFixInNextReleaseMessage = QString::fromLatin1("Will fix in next release"); - QString fromCharCodeMessage = QString::fromLatin1("Test is wrong?"); - for (int i = 4256; i < 4294; ++i) { - addExpectedFailure("ecma/String/15.5.4.11-2.js", QString::fromLatin1("var s = new String( String.fromCharCode(%0) ); s.toLowerCase().charCodeAt(0)").arg(i), fromCharCodeMessage); - } - addExpectedFailure("ecma/String/15.5.4.11-5.js", "var s = new String( String.fromCharCode(1024) ); s.toLowerCase().charCodeAt(0)", fromCharCodeMessage); - addExpectedFailure("ecma/String/15.5.4.11-5.js", "var s = new String( String.fromCharCode(1037) ); s.toLowerCase().charCodeAt(0)", fromCharCodeMessage); - addExpectedFailure("ecma/String/15.5.4.12-1.js", "var s = new String( String.fromCharCode(181) ); s.toUpperCase().charCodeAt(0)", fromCharCodeMessage); - addExpectedFailure("ecma/String/15.5.4.12-1.js", "var s = new String( String.fromCharCode(329) ); s.toUpperCase().charCodeAt(0)", fromCharCodeMessage); - addExpectedFailure("ecma/String/15.5.4.12-4.js", "var s = new String( String.fromCharCode(1104) ); s.toUpperCase().charCodeAt(0)", fromCharCodeMessage); - addExpectedFailure("ecma/String/15.5.4.12-4.js", "var s = new String( String.fromCharCode(1117) ); s.toUpperCase().charCodeAt(0)", fromCharCodeMessage); - addExpectedFailure("ecma/String/15.5.4.12-5.js", "var s = new String( String.fromCharCode(1415) ); s.toUpperCase().charCodeAt(0)", fromCharCodeMessage); - - addExpectedFailure("ecma/TypeConversion/9.3.1-3.js", "- \"-0x123456789abcde8\"", willFixInNextReleaseMessage); - - addExpectedFailure("ecma/extensions/15.1.2.1-1.js", "var PROPS = ''; for ( p in eval ) { PROPS += p }; PROPS", willFixInNextReleaseMessage); - addExpectedFailure("ecma/GlobalObject/15.1.2.2-1.js", "var PROPS=''; for ( var p in parseInt ) { PROPS += p; }; PROPS", willFixInNextReleaseMessage); - - addExpectedFailure("ecma/GlobalObject/15.1.2.3-1.js", "var MYPROPS=''; for ( var p in parseFloat ) { MYPROPS += p }; MYPROPS", willFixInNextReleaseMessage); - addExpectedFailure("ecma/GlobalObject/15.1.2.4.js", "var MYPROPS=''; for ( var p in escape ) { MYPROPS+= p}; MYPROPS", willFixInNextReleaseMessage); - addExpectedFailure("ecma/GlobalObject/15.1.2.5-1.js", "var MYPROPS=''; for ( var p in unescape ) { MYPROPS+= p }; MYPROPS", willFixInNextReleaseMessage); - addExpectedFailure("ecma/GlobalObject/15.1.2.6.js", "var MYPROPS=''; for ( var p in isNaN ) { MYPROPS+= p }; MYPROPS", willFixInNextReleaseMessage); - addExpectedFailure("ecma/GlobalObject/15.1.2.7.js", "var MYPROPS=''; for ( p in isFinite ) { MYPROPS+= p }; MYPROPS", willFixInNextReleaseMessage); - - addExpectedFailure(QRegExp(), "NO TESTS EXIST", willFixInNextReleaseMessage); - - addExpectedFailure("ecma_3/Array/15.4.5.1-01.js", "15.4.5.1 - array.length coverage", willFixInNextReleaseMessage); - - addExpectedFailure("ecma_3/extensions/regress-228087-002.js", - "Section 1 of test - \nregexp = /{1.*}/g\n" - "string = 'foo {1} foo {2} foo'\n" - "ERROR !!! match arrays have different lengths:\n" - "Expect: [\"{1} foo {2}\"]\n" - "Actual: []", willFixInNextReleaseMessage); - - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", - "Section 1 of test - \n" - "regexp = /a|ab/\n" - "string = 'abc'\n" - "ERROR !!! regexp failed to give expected match array:\n" - "Expect: [\"a\"]\n" - "Actual: [\"ab\"]\n", willFixInNextReleaseMessage); - - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", - "Section 2 of test - \n" - "regexp = /((a)|(ab))((c)|(bc))/\n" - "string = 'abc'\n" - "ERROR !!! regexp failed to give expected match array:\n" - "Expect: [\"abc\", \"a\", \"a\", , \"bc\", , \"bc\"]\n" - "Actual: [\"abc\", \"ab\", \"\", \"ab\", \"c\", \"c\", \"\"]\n", willFixInNextReleaseMessage); - - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", - "Section 4 of test - \n" - "regexp = /a[a-z]{2,4}?/\n" - "string = 'abcdefghi'\n" - "ERROR !!! regexp FAILED to match anything !!!\n" - "Expect: abc\n" - "Actual: null\n", willFixInNextReleaseMessage); - - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js(317)", - "Section 5 of test - \n" - "regexp = /(aa|aabaac|ba|b|c)*/\n" - "string = 'aabaac'\n" - "ERROR !!! regexp failed to give expected match array:\n" - "Expect: [\"aaba\", \"ba\"]\n" - "Actual: [\"aabaac\", \"aabaac\"]\n", willFixInNextReleaseMessage); - - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 1 of test - \nregexp = /{1.*}/g\nstring = 'foo {1} foo {2} foo'\nERROR !!! match arrays have different lengths:\nExpect: [\"{1} foo {2}\"]\nActual: []\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 2 of test - \nregexp = /{1.*}/g\nstring = 'foo {1} foo {2} foo'\nERROR !!! match arrays have different lengths:\nExpect: [\"{1} foo {2}\"]\nActual: []\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 3 of test - \nregexp = /{1[.!}]*}/g\nstring = 'foo {1} foo {2} foo'\nERROR !!! match arrays have different lengths:\nExpect: [\"{1}\"]\nActual: []\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 4 of test - \nregexp = /{1[.!}]*}/g\nstring = 'foo {1} foo {2} foo'\nERROR !!! match arrays have different lengths:\nExpect: [\"{1}\"]\nActual: []\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 6 of test - \nregexp = /c{3 }/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{3 }\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 7 of test - \nregexp = /c{3.}/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{3 }\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 8 of test - \nregexp = /c{3\\s}/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{3 }\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 9 of test - \nregexp = /c{3[ ]}/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{3 }\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 10 of test - \nregexp = /c{ 3}/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{ 3}\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 12 of test - \nregexp = /c{3, }/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{3, }\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 13 of test - \nregexp = /c{3 ,}/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{3 ,}\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 15 of test - \nregexp = /c{3 ,4}/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{3 ,4}\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 16 of test - \nregexp = /c{3, 4}/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{3, 4}\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-228087.js", "Section 17 of test - \nregexp = /c{3,4 }/\nstring = 'abccccc{3 }c{ 3}c{3, }c{3 ,}c{3 ,4}c{3, 4}c{3,4 }de'\nERROR !!! regexp FAILED to match anything !!!\nExpect: c{3,4 }\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-274152.js", "Do not ignore unicode format-control characters: 0", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-274152.js", "Do not ignore unicode format-control characters: 1", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-274152.js", "Do not ignore unicode format-control characters: 2", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-274152.js", "Do not ignore unicode format-control characters: 3", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-274152.js", "Do not ignore unicode format-control characters: 4", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-274152.js", "Do not ignore unicode format-control characters: 5", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-274152.js", "Do not ignore unicode format-control characters: 6", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-274152.js", "Do not ignore unicode format-control characters: 7", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-274152.js", "Do not ignore unicode format-control characters: 8", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-368516.js", "Treat unicode BOM characters as whitespace: 0", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/extensions/regress-368516.js", "Treat unicode BOM characters as whitespace: 1", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/FunExpr/fe-001-n.js", "Previous statement should have thrown a ReferenceError", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/LexicalConventions/7.9.1.js", "Automatic Semicolon insertion in postfix expressions: expr\n++", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/LexicalConventions/7.9.1.js", "Automatic Semicolon insertion in postfix expressions: expr\n--", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/LexicalConventions/7.9.1.js", "Automatic Semicolon insertion in postfix expressions: (x\n)-- y", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/LexicalConventions/7.9.1.js", "Automatic Semicolon insertion in postfix expressions: (x)-- y", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Object/8.6.1-01.js", "In strict mode, setting a read-only property should generate a warning: Throw if STRICT and WERROR is enabled", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Operators/order-01.js", "operator evaluation order: 11.8.2 >", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Operators/order-01.js", "operator evaluation order: 11.8.4 >=", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 5 of test - \nregexp = /(aa|aabaac|ba|b|c)*/\nstring = 'aabaac'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"aaba\", \"ba\"]\nActual: [\"aabaac\", \"aabaac\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 6 of test - \nregexp = /^(a+)\\1*,\\1+$/\nstring = 'aaaaaaaaaa,aaaaaaaaaaaaaaa'\nERROR !!! regexp FAILED to match anything !!!\nExpect: aaaaaaaaaa,aaaaaaaaaaaaaaa,aaaaa\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 7 of test - \nregexp = /(z)((a+)?(b+)?(c))*/\nstring = 'zaacbbbcac'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"zaacbbbcac\", \"z\", \"ac\", \"a\", , \"c\"]\nActual: [\"zaacbbbcac\", \"z\", \"ac\", \"a\", \"\", \"c\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 8 of test - \nregexp = /(a*)*/\nstring = 'b'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"\", , ]\nActual: [\"\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 10 of test - \nregexp = /(?=(a+))/\nstring = 'baaabac'\nERROR !!! match arrays have different lengths:\nExpect: [\"\", \"aaa\"]\nActual: [\"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 11 of test - \nregexp = /(?=(a+))a*b\\1/\nstring = 'baaabac'\nERROR !!! match arrays have different lengths:\nExpect: [\"aba\", \"a\"]\nActual: [\"aaab\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 12 of test - \nregexp = /(.*?)a(?!(a+)b\\2c)\\2(.*)/\nstring = 'baaabaac'\nERROR !!! regexp FAILED to match anything !!!\nExpect: baaabaac,ba,,abaac\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 13 of test - \nregexp = /(?=(a+))/\nstring = 'baaabac'\nERROR !!! match arrays have different lengths:\nExpect: [\"\", \"aaa\"]\nActual: [\"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 34 of test - \nregexp = /a]/\nstring = 'a]'\nERROR !!! regexp FAILED to match anything !!!\nExpect: a]\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 66 of test - \nregexp = /a.+?c/\nstring = 'abcabc'\nERROR !!! regexp FAILED to match anything !!!\nExpect: abc\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 94 of test - \nregexp = /^a(bc+|b[eh])g|.h$/\nstring = 'abh'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"bh\", , ]\nActual: [\"bh\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 95 of test - \nregexp = /(bc+d$|ef*g.|h?i(j|k))/\nstring = 'effgz'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"effgz\", \"effgz\", , ]\nActual: [\"effgz\", \"effgz\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 97 of test - \nregexp = /(bc+d$|ef*g.|h?i(j|k))/\nstring = 'reffgz'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"effgz\", \"effgz\", , ]\nActual: [\"effgz\", \"effgz\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 109 of test - \nregexp = /(([a-c])b*?\\2)*/\nstring = 'ababbbcbc'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ababb,bb,b\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 110 of test - \nregexp = /(([a-c])b*?\\2){3}/\nstring = 'ababbbcbc'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ababbbcbc,cbc,c\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 119 of test - \nregexp = /ab*?bc/i\nstring = 'ABBBBC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABBBBC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 120 of test - \nregexp = /ab{0,}?bc/i\nstring = 'ABBBBC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABBBBC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 121 of test - \nregexp = /ab+?bc/i\nstring = 'ABBC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABBC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 123 of test - \nregexp = /ab{1,}?bc/i\nstring = 'ABBBBC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABBBBC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 124 of test - \nregexp = /ab{1,3}?bc/i\nstring = 'ABBBBC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABBBBC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 125 of test - \nregexp = /ab{3,4}?bc/i\nstring = 'ABBBBC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABBBBC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 126 of test - \nregexp = /ab??bc/i\nstring = 'ABBC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABBC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 127 of test - \nregexp = /ab??bc/i\nstring = 'ABC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 128 of test - \nregexp = /ab{0,1}?bc/i\nstring = 'ABC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 129 of test - \nregexp = /ab??c/i\nstring = 'ABC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 130 of test - \nregexp = /ab{0,1}?c/i\nstring = 'ABC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 138 of test - \nregexp = /a.*?c/i\nstring = 'AXYZC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: AXYZC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 144 of test - \nregexp = /a]/i\nstring = 'A]'\nERROR !!! regexp FAILED to match anything !!!\nExpect: A]\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 160 of test - \nregexp = /a.+?c/i\nstring = 'ABCABC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 161 of test - \nregexp = /a.*?c/i\nstring = 'ABCABC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 162 of test - \nregexp = /a.{0,5}?c/i\nstring = 'ABCABC'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ABC\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 169 of test - \nregexp = /(a+|b){0,1}?/i\nstring = 'AB'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ,\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 191 of test - \nregexp = /^a(bc+|b[eh])g|.h$/i\nstring = 'ABH'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"BH\", , ]\nActual: [\"BH\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 192 of test - \nregexp = /(bc+d$|ef*g.|h?i(j|k))/i\nstring = 'EFFGZ'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"EFFGZ\", \"EFFGZ\", , ]\nActual: [\"EFFGZ\", \"EFFGZ\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 194 of test - \nregexp = /(bc+d$|ef*g.|h?i(j|k))/i\nstring = 'REFFGZ'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"EFFGZ\", \"EFFGZ\", , ]\nActual: [\"EFFGZ\", \"EFFGZ\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 212 of test - \nregexp = /a(?:b|c|d)+?(.)/\nstring = 'ace'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ace,e\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 213 of test - \nregexp = /a(?:b|c|d)+?(.)/\nstring = 'acdbcdbe'\nERROR !!! regexp FAILED to match anything !!!\nExpect: acd,d\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 217 of test - \nregexp = /a(?:b|c|d){4,5}?(.)/\nstring = 'acdbcdbe'\nERROR !!! regexp FAILED to match anything !!!\nExpect: acdbcd,d\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 218 of test - \nregexp = /((foo)|(bar))*/\nstring = 'foobar'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"foobar\", \"bar\", , \"bar\"]\nActual: [\"foobar\", \"bar\", \"\", \"bar\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 220 of test - \nregexp = /a(?:b|c|d){6,7}?(.)/\nstring = 'acdbcdbe'\nERROR !!! regexp FAILED to match anything !!!\nExpect: acdbcdbe,e\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 222 of test - \nregexp = /a(?:b|c|d){5,6}?(.)/\nstring = 'acdbcdbe'\nERROR !!! regexp FAILED to match anything !!!\nExpect: acdbcdb,b\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 224 of test - \nregexp = /a(?:b|c|d){5,7}?(.)/\nstring = 'acdbcdbe'\nERROR !!! regexp FAILED to match anything !!!\nExpect: acdbcdb,b\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 225 of test - \nregexp = /a(?:b|(c|e){1,2}?|d)+?(.)/\nstring = 'ace'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ace,c,e\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 227 of test - \nregexp = /^([^a-z])|(\\^)$/\nstring = '.'\nERROR !!! regexp failed to give expected match array:\nExpect: [\".\", \".\", , ]\nActual: [\".\", \".\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 234 of test - \nregexp = /(?:(f)(o)(o)|(b)(a)(r))*/\nstring = 'foobar'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"foobar\", , , , \"b\", \"a\", \"r\"]\nActual: [\"foobar\", \"\", \"\", \"\", \"b\", \"a\", \"r\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 240 of test - \nregexp = /(?:..)*?a/\nstring = 'aba'\nERROR !!! regexp FAILED to match anything !!!\nExpect: a\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 241 of test - \nregexp = /^(?:b|a(?=(.)))*\\1/\nstring = 'abc'\nERROR !!! match arrays have different lengths:\nExpect: [\"ab\", , ]\nActual: [\"ab\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 246 of test - \nregexp = /(a|x)*ab/\nstring = 'cab'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"ab\", , ]\nActual: [\"ab\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 247 of test - \nregexp = /(a)*ab/\nstring = 'cab'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"ab\", , ]\nActual: [\"ab\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 300 of test - \nregexp = /(?=(a+?))(\\1ab)/\nstring = 'aaab'\nERROR !!! regexp FAILED to match anything !!!\nExpect: aab,a,aab\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 303 of test - \nregexp = /(?=(a+?))(\\1ab)/\nstring = 'aaab'\nERROR !!! regexp FAILED to match anything !!!\nExpect: aab,a,aab\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 304 of test - \nregexp = /([\\w:]+::)?(\\w+)$/\nstring = 'abcd'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"abcd\", , \"abcd\"]\nActual: [\"abcd\", \"\", \"abcd\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 308 of test - \nregexp = /([\\w:]+::)?(\\w+)$/\nstring = 'abcd'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"abcd\", , \"abcd\"]\nActual: [\"abcd\", \"\", \"abcd\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 342 of test - \nregexp = /a$/m\nstring = 'a\\nb\\n'\nERROR !!! regexp FAILED to match anything !!!\nExpect: a\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 344 of test - \nregexp = /a$/m\nstring = 'b\\na\\n'\nERROR !!! regexp FAILED to match anything !!!\nExpect: a\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 353 of test - \nregexp = /aa$/m\nstring = 'aa\\nb\\n'\nERROR !!! regexp FAILED to match anything !!!\nExpect: aa\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 355 of test - \nregexp = /aa$/m\nstring = 'b\\naa\\n'\nERROR !!! regexp FAILED to match anything !!!\nExpect: aa\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 364 of test - \nregexp = /ab$/m\nstring = 'ab\\nb\\n'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ab\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 366 of test - \nregexp = /ab$/m\nstring = 'b\\nab\\n'\nERROR !!! regexp FAILED to match anything !!!\nExpect: ab\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 375 of test - \nregexp = /abb$/m\nstring = 'abb\\nb\\n'\nERROR !!! regexp FAILED to match anything !!!\nExpect: abb\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 377 of test - \nregexp = /abb$/m\nstring = 'b\\nabb\\n'\nERROR !!! regexp FAILED to match anything !!!\nExpect: abb\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 383 of test - \nregexp = /^d[x][x][x]/m\nstring = 'abcd\\ndxxx'\nERROR !!! regexp FAILED to match anything !!!\nExpect: dxxx\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 391 of test - \nregexp = /\\.c(pp|xx|c)?$/i\nstring = 'IO.c'\nERROR !!! regexp failed to give expected match array:\nExpect: [\".c\", , ]\nActual: [\".c\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 392 of test - \nregexp = /(\\.c(pp|xx|c)?$)/i\nstring = 'IO.c'\nERROR !!! regexp failed to give expected match array:\nExpect: [\".c\", \".c\", , ]\nActual: [\".c\", \".c\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 394 of test - \nregexp = /^([ab]*?)(b)?(c)$/\nstring = 'abac'\nERROR !!! regexp FAILED to match anything !!!\nExpect: abac,aba,,c\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 412 of test - \nregexp = /^(a(b)?)+$/\nstring = 'aba'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"aba\", \"a\", , ]\nActual: [\"aba\", \"a\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 413 of test - \nregexp = /^(aa(bb)?)+$/\nstring = 'aabbaa'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"aabbaa\", \"aa\", , ]\nActual: [\"aabbaa\", \"aa\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 414 of test - \nregexp = /^.{9}abc.*\\n/m\nstring = '123\\nabcabcabcabc\\n'\nERROR !!! regexp FAILED to match anything !!!\nExpect: abcabcabcabc\n\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 415 of test - \nregexp = /^(a)?a$/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"a\", , ]\nActual: [\"a\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 416 of test - \nregexp = /^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$/\nstring = 'aaaaaa'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"aaaaaa\", \"a\", \"aa\", \"a\", \"aa\"]\nActual: [\"aaaaaa\", \"aa\", \"a\", \"aa\", \"a\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 418 of test - \nregexp = /^(0+)?(?:x(1))?/\nstring = 'x1'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"x1\", , \"1\"]\nActual: [\"x1\", \"\", \"1\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 419 of test - \nregexp = /^([0-9a-fA-F]+)(?:x([0-9a-fA-F]+)?)(?:x([0-9a-fA-F]+))?/\nstring = '012cxx0190'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"012cxx0190\", \"012c\", , \"0190\"]\nActual: [\"012cxx0190\", \"012c\", \"\", \"0190\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 420 of test - \nregexp = /^(b+?|a){1,2}c/\nstring = 'bbbac'\nERROR !!! regexp FAILED to match anything !!!\nExpect: bbbac,a\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 421 of test - \nregexp = /^(b+?|a){1,2}c/\nstring = 'bbbbac'\nERROR !!! regexp FAILED to match anything !!!\nExpect: bbbbac,a\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-002.js", "Section 40 of test - \nregexp = /(a)|\\1/\nstring = 'x'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"\", , ]\nActual: [\"\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-105972.js", "Section 1 of test - \nregexp = /^.*?$/\nstring = 'Hello World'\nERROR !!! regexp FAILED to match anything !!!\nExpect: Hello World\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-105972.js", "Section 2 of test - \nregexp = /^.*?/\nstring = 'Hello World'\nERROR !!! regexp FAILED to match anything !!!\nExpect: \nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-105972.js", "Section 3 of test - \nregexp = /^.*?(:|$)/\nstring = 'Hello: World'\nERROR !!! regexp FAILED to match anything !!!\nExpect: Hello:,:\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-123437.js", "Section 1 of test - \nregexp = /(a)?a/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"a\", , ]\nActual: [\"a\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-123437.js", "Section 2 of test - \nregexp = /a|(b)/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"a\", , ]\nActual: [\"a\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-123437.js", "Section 3 of test - \nregexp = /(a)?(a)/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"a\", , \"a\"]\nActual: [\"a\", \"\", \"a\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-165353.js", "Section 1 of test - \nregexp = /^([a-z]+)*[a-z]$/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"a\", , ]\nActual: [\"a\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-169497.js", "Section 1 of test - \nregexp = /<body.*>((.*\\n?)*?)<\\/body>/i\nstring = '<html>\\n<body onXXX=\"alert(event.type);\">\\n<p>Kibology for all</p>\\n<p>All for Kibology</p>\\n</body>\\n</html>'\nERROR !!! regexp FAILED to match anything !!!\nExpect: <body onXXX=\"alert(event.type);\">\n<p>Kibology for all</p>\n<p>All for Kibology</p>\n</body>,\n<p>Kibology for all</p>\n<p>All for Kibology</p>\n,<p>All for Kibology</p>\n\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-187133.js", "Section 5 of test - \nregexp = /(?!a|b)|c/\nstring = 'bc'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"\"]\nActual: [\"c\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-191479.js", "Section 1 of test - \nregexp = /(\\d|\\d\\s){2,}/\nstring = '12 3 45'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"12\", \"2\"]\nActual: [\"12 3 45\", \"5\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-191479.js", "Section 3 of test - \nregexp = /(\\d|\\d\\s)+/\nstring = '12 3 45'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"12\", \"2\"]\nActual: [\"12 3 45\", \"5\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-191479.js", "Section 8 of test - \nregexp = /(\\d|\\d\\s){2,}?/\nstring = '12 3 45'\nERROR !!! regexp FAILED to match anything !!!\nExpect: 12,2\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-191479.js", "Section 9 of test - \nregexp = /(\\d|\\d\\s){4,}?/\nstring = '12 3 45'\nERROR !!! regexp FAILED to match anything !!!\nExpect: 12 3 4,4\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-191479.js", "Section 10 of test - \nregexp = /(\\d|\\d\\s)+?/\nstring = '12 3 45'\nERROR !!! regexp FAILED to match anything !!!\nExpect: 1,1\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-191479.js", "Section 11 of test - \nregexp = /(\\d\\s?){4,}?/\nstring = '12 3 45'\nERROR !!! regexp FAILED to match anything !!!\nExpect: 12 3 4,4\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-191479.js", "Section 12 of test - \nregexp = /(\\d\\s|\\d){2,}?/\nstring = '12 3 45'\nERROR !!! regexp FAILED to match anything !!!\nExpect: 12 ,2 \nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-191479.js", "Section 13 of test - \nregexp = /(\\d\\s|\\d){4,}?/\nstring = '12 3 45'\nERROR !!! regexp FAILED to match anything !!!\nExpect: 12 3 4,4\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-191479.js", "Section 14 of test - \nregexp = /(\\d\\s|\\d)+?/\nstring = '12 3 45'\nERROR !!! regexp FAILED to match anything !!!\nExpect: 1,1\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-202564.js", "Section 1 of test - \nregexp = /(?:(.+), )?(.+), (..) to (?:(.+), )?(.+), (..)/\nstring = 'Seattle, WA to Buckley, WA'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"Seattle, WA to Buckley, WA\", , \"Seattle\", \"WA\", , \"Buckley\", \"WA\"]\nActual: [\"Seattle, WA to Buckley, WA\", \"\", \"Seattle\", \"WA\", \"\", \"Buckley\", \"WA\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-209919.js", "Section 2 of test - \nregexp = /(a|b*){5,}/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"a\", \"\"]\nActual: [\"a\", \"a\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-209919.js", "Section 3 of test - \nregexp = /(b*)*/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"\", , ]\nActual: [\"\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-209919.js", "Section 5 of test - \nregexp = /^\\-?(\\d{1,}|\\.{0,})*(\\,\\d{1,})?$/\nstring = '100.00'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"100.00\", \"00\", , ]\nActual: [\"100.00\", \"00\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-216591.js", "Section 1 of test - \nregexp = /\\{(([a-z0-9\\-_]+?\\.)+?)([a-z0-9\\-_]+?)\\}/i\nstring = 'a {result.data.DATA} b'\nERROR !!! regexp FAILED to match anything !!!\nExpect: {result.data.DATA},result.data.,data.,DATA\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-216591.js", "Section 2 of test - \nregexp = /\\{(([a-z0-9\\-_]+?\\.)+?)([a-z0-9\\-_]+?)\\}/gi\nstring = 'a {result.data.DATA} b'\nERROR !!! match arrays have different lengths:\nExpect: [\"{result.data.DATA}\"]\nActual: []\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-220367-001.js", "Section 1 of test - \nregexp = /(a)|(b)/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"a\", \"a\", , ]\nActual: [\"a\", \"a\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-220367-001.js", "Section 2 of test - \nregexp = /(a)|(b)/\nstring = 'b'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"b\", , \"b\"]\nActual: [\"b\", \"\", \"b\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-223535.js", "Section 2 of test - \nregexp = /|a/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"\"]\nActual: [\"a\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-223535.js", "Section 6 of test - \nregexp = /(|a)/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"\", \"\"]\nActual: [\"a\", \"a\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-223535.js", "Section 7 of test - \nregexp = /(|a|)/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"\", \"\"]\nActual: [\"a\", \"a\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-224676.js", "Section 17 of test - \nregexp = /[x]b|(a)/\nstring = 'ZZZxbZZZ'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"xb\", , ]\nActual: [\"xb\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-224676.js", "Section 18 of test - \nregexp = /[x]b|()a/\nstring = 'ZZZxbZZZ'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"xb\", , ]\nActual: [\"xb\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-225289.js", "Section 7 of test - \nregexp = /(a)|([^a])/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"a\", \"a\", , ]\nActual: [\"a\", \"a\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-225289.js", "Section 9 of test - \nregexp = /(a)|([^a])/\nstring = '()'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"(\", , \"(\"]\nActual: [\"(\", \"\", \"(\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-225289.js", "Section 10 of test - \nregexp = /((?:a|[^a])*)/g\nstring = 'a'\nERROR !!! match arrays have different lengths:\nExpect: [\"a\", \"\"]\nActual: [\"a\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-225289.js", "Section 11 of test - \nregexp = /((?:a|[^a])*)/g\nstring = ''\nERROR !!! match arrays have different lengths:\nExpect: [\"\"]\nActual: []\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-225289.js", "Section 12 of test - \nregexp = /((?:a|[^a])*)/g\nstring = '()'\nERROR !!! match arrays have different lengths:\nExpect: [\"()\", \"\"]\nActual: [\"()\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-31316.js", "Section 1 of test - \nregexp = /<([^\\/<>][^<>]*[^\\/])>|<([^\\/<>])>/\nstring = '<p>Some<br />test</p>'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"<p>\", , \"p\"]\nActual: [\"<p>\", \"\", \"p\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-330684.js", "Do not hang on RegExp", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-375711.js", "Do not assert with /[Q-b]/i.exec(\"\"): /[q-b]/.exec(\"\")", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-375711.js", "Do not assert with /[Q-b]/i.exec(\"\"): /[q-b]/i.exec(\"\")", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '(?)'and flag 'i'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '(?)'and flag 'g'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '(?)'and flag 'm'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '(?)'and flag 'undefined'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '(a'and flag 'i'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '(a'and flag 'g'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '(a'and flag 'm'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '(a'and flag 'undefined'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '( ]'and flag 'i'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '( ]'and flag 'g'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '( ]'and flag 'm'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-57631.js", "Testing for error creating illegal RegExp object on pattern '( ]'and flag 'undefined'", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-78156.js", "Section 1 of test - \nregexp = /^\\d/gm\nstring = 'aaa\\n789\\r\\nccc\\r\\n345'\nERROR !!! match arrays have different lengths:\nExpect: [\"7\", \"3\"]\nActual: []\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-78156.js", "Section 2 of test - \nregexp = /\\d$/gm\nstring = 'aaa\\n789\\r\\nccc\\r\\n345'\nERROR !!! match arrays have different lengths:\nExpect: [\"9\", \"5\"]\nActual: [\"5\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-78156.js", "Section 3 of test - \nregexp = /^\\d/gm\nstring = 'aaa\\n789\\r\\nccc\\r\\nddd'\nERROR !!! match arrays have different lengths:\nExpect: [\"7\"]\nActual: []\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-78156.js", "Section 4 of test - \nregexp = /\\d$/gm\nstring = 'aaa\\n789\\r\\nccc\\r\\nddd'\nERROR !!! match arrays have different lengths:\nExpect: [\"9\"]\nActual: []\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-85721.js", "Section 2 of test - \nregexp = /<sql:connection id=\"([^\\r\\n]*?)\">\\s*<sql:url>\\s*([^\\r\\n]*?)\\s*<\\/sql:url>\\s*<sql:driver>\\s*([^\\r\\n]*?)\\s*<\\/sql:driver>\\s*(\\s*<sql:userId>\\s*([^\\r\\n]*?)\\s*<\\/sql:userId>\\s*)?\\s*(\\s*<sql:password>\\s*([^\\r\\n]*?)\\s*<\\/sql:password>\\s*)?\\s*<\\/sql:connection>/\nstring = '<sql:connection id=\"conn1\"> <sql:url>www.m.com</sql:url> <sql:driver>drive.class</sql:driver>\\n<sql:userId>foo</sql:userId> <sql:password>goo</sql:password> </sql:connection>'\nERROR !!! regexp FAILED to match anything !!!\nExpect: <sql:connection id=\"conn1\"> <sql:url>www.m.com</sql:url> <sql:driver>drive.class</sql:driver>\n<sql:userId>foo</sql:userId> <sql:password>goo</sql:password> </sql:connection>,conn1,www.m.com,drive.class,<sql:userId>foo</sql:userId> ,foo,<sql:password>goo</sql:password> ,goo\nActual: null\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-87231.js", "Section 3 of test - \nregexp = /^(A)?(A.*)$/\nstring = 'A'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"A\", , \"A\"]\nActual: [\"A\", \"\", \"A\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-87231.js", "Section 6 of test - \nregexp = /(A)?(A.*)/\nstring = 'zxcasd;fl\\ ^AaaAAaaaf;lrlrzs'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"AaaAAaaaf;lrlrzs\", , \"AaaAAaaaf;lrlrzs\"]\nActual: [\"AaaAAaaaf;lrlrzs\", \"\", \"AaaAAaaaf;lrlrzs\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/String/15.5.4.11.js", "Section 24", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/String/15.5.4.11.js", "Section 28", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/String/15.5.4.11.js", "Section 30", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/String/15.5.4.14.js", "15.5.4.14 - String.prototype.split(/()/)", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Unicode/regress-352044-01.js", "issues with Unicode escape sequences in JavaScript source code", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Unicode/uc-001.js", "Unicode format-control character test (Category Cf.)", willFixInNextReleaseMessage); - - addFileExclusion(".+/15\\.9\\.2\\..+", "unstable on slow machines"); - addFileExclusion(".+/15\\.9\\.5\\..+", "too slooow"); - addFileExclusion("regress-130451.js", "asserts"); - addFileExclusion("regress-322135-01.js", "asserts"); - addFileExclusion("regress-322135-02.js", "asserts"); - addFileExclusion("regress-322135-03.js", "takes forever"); - addFileExclusion("regress-322135-04.js", "takes forever"); - addFileExclusion("ecma_3/RegExp/regress-375715-04.js", "bug"); - - addFileExclusion("ecma_3/RegExp/regress-289669.js", "Can fail due to relying on wall-clock time"); - - // Failures due to switch to JSC as back-end - addExpectedFailure("ecma/Array/15.4.3.1-2.js", "var props = ''; for ( p in Array ) { props += p } props", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Boolean/15.6.3.1-1.js", "var str='';for ( p in Boolean ) { str += p } str;", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Expressions/11.4.1.js", "var abc; delete(abc)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/FunctionObjects/15.3.3.1-2.js", "var str='';for (prop in Function ) str += prop; str;", willFixInNextReleaseMessage); - addExpectedFailure("ecma/ObjectObjects/15.2.3.1-1.js", "var str = '';for ( p in Object ) { str += p; }; str", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Statements/12.6.3-11.js", "result = \"\"; for ( p in Number ) { result += String(p) };", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Statements/12.6.3-2.js", "Boolean.prototype.foo = 34; for ( j in Boolean ) Boolean[j]", willFixInNextReleaseMessage); - addExpectedFailure("ecma/TypeConversion/9.3.1-3.js", "-\"\\u20001234\\u2001\"", willFixInNextReleaseMessage); - addExpectedFailure("ecma_2/RegExp/properties-001.js", "//.toString()", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Date/15.9.4.3.js", "15.9.4.3 - Date.UTC edge-case arguments.: date Infinity", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Date/15.9.4.3.js", "15.9.4.3 - Date.UTC edge-case arguments.: hours Infinity", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Date/15.9.4.3.js", "15.9.4.3 - Date.UTC edge-case arguments.: minutes Infinity", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Date/15.9.4.3.js", "15.9.4.3 - Date.UTC edge-case arguments.: seconds Infinity", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Function/regress-131964.js", "Section 1 of test - ", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Function/regress-313570.js", "length of objects whose prototype chain includes a function: immutable", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/FunExpr/fe-001.js", "Both functions were defined.", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 7 of test - \nregexp = /(z)((a+)?(b+)?(c))*/\nstring = 'zaacbbbcac'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"zaacbbbcac\", \"z\", \"ac\", \"a\", , \"c\"]\nActual: [\"zaacbbbcac\", \"z\", \"ac\", \"a\", \"bbb\", \"c\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/15.10.2-1.js", "Section 12 of test - \nregexp = /(.*?)a(?!(a+)b\\2c)\\2(.*)/\nstring = 'baaabaac'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"baaabaac\", \"ba\", , \"abaac\"]\nActual: [\"baaabaac\", \"ba\", \"aa\", \"abaac\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 218 of test - \nregexp = /((foo)|(bar))*/\nstring = 'foobar'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"foobar\", \"bar\", , \"bar\"]\nActual: [\"foobar\", \"bar\", \"foo\", \"bar\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 234 of test - \nregexp = /(?:(f)(o)(o)|(b)(a)(r))*/\nstring = 'foobar'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"foobar\", , , , \"b\", \"a\", \"r\"]\nActual: [\"foobar\", \"f\", \"o\", \"o\", \"b\", \"a\", \"r\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 241 of test - \nregexp = /^(?:b|a(?=(.)))*\\1/\nstring = 'abc'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"ab\", , ]\nActual: [\"ab\", \"b\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 412 of test - \nregexp = /^(a(b)?)+$/\nstring = 'aba'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"aba\", \"a\", , ]\nActual: [\"aba\", \"a\", \"b\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/perlstress-001.js", "Section 413 of test - \nregexp = /^(aa(bb)?)+$/\nstring = 'aabbaa'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"aabbaa\", \"aa\", , ]\nActual: [\"aabbaa\", \"aa\", \"bb\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-209919.js", "Section 1 of test - \nregexp = /(a|b*)*/\nstring = 'a'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"a\", \"a\"]\nActual: [\"a\", \"\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-209919.js", "Section 5 of test - \nregexp = /^\\-?(\\d{1,}|\\.{0,})*(\\,\\d{1,})?$/\nstring = '100.00'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"100.00\", \"00\", , ]\nActual: [\"100.00\", \"\", , ]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-209919.js", "Section 6 of test - \nregexp = /^\\-?(\\d{1,}|\\.{0,})*(\\,\\d{1,})?$/\nstring = '100,00'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"100,00\", \"100\", \",00\"]\nActual: [\"100,00\", \"\", \",00\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-209919.js", "Section 7 of test - \nregexp = /^\\-?(\\d{1,}|\\.{0,})*(\\,\\d{1,})?$/\nstring = '1.000,00'\nERROR !!! regexp failed to give expected match array:\nExpect: [\"1.000,00\", \"000\", \",00\"]\nActual: [\"1.000,00\", \"\", \",00\"]\n", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/RegExp/regress-311414.js", "RegExp captured tail match should be O(N) BigO 2 < 2", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/String/15.5.4.11.js", "Section 7", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/String/15.5.4.11.js", "Section 26", willFixInNextReleaseMessage); - -#ifdef Q_CC_MSVC - addExpectedFailure("ecma_3/Expressions/11.7.3-01.js", "11.7.3 - >>> should evaluate operands in order: order", "QTBUG-8056"); - addExpectedFailure("ecma_3/Operators/order-01.js", "operator evaluation order: 11.7.3 >>>", "QTBUG-8056"); - addExpectedFailure("ecma_3/Operators/order-01.js", "operator evaluation order: 11.13.2 >>>=", "QTBUG-8056"); -#endif - -#ifdef Q_CC_MINGW - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(NaN,0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(NaN,-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.5.js", "Math.atan2(Infinity, Infinity)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.5.js", "Math.atan2(Infinity, -Infinity)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.5.js", "Math.atan2(-Infinity, Infinity)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.5.js", "Math.atan2(-Infinity, -Infinity)", willFixInNextReleaseMessage); -#endif - -#ifdef Q_OS_SOLARIS - addExpectedFailure("ecma/Expressions/11.13.2-2.js", "VAR1 = -0; VAR2= Infinity; VAR2 /= VAR1", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Expressions/11.13.2-2.js", "VAR1 = -0; VAR2= -Infinity; VAR2 /= VAR1", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Expressions/11.13.2-2.js", "VAR1 = 1; VAR2= -0; VAR1 /= VAR2", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Expressions/11.13.2-2.js", "VAR1 = -1; VAR2= -0; VAR1 /= VAR2", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Expressions/11.5.2.js", "Number.POSITIVE_INFINITY / -0", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Expressions/11.5.2.js", "Number.NEGATIVE_INFINITY / -0", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Expressions/11.5.2.js", "1 / -0", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Expressions/11.5.2.js", "-1 / -0", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.10.js", "Math.log(-0.0000001)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.10.js", "Math.log(-1)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.11.js", "Infinity/Math.max(-0,-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.12.js", "Infinity/Math.min(0,-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.12.js", "Infinity/Math.min(-0,-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(NaN,0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(NaN,-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Infinity/Math.pow(-Infinity, -1)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(0, -1)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(0, -0.5)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(0, -1000)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Infinity/Math.pow(-0, 1)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Infinity/Math.pow(-0, 3)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(-0, -2)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.15.js", "Infinity/Math.round(-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.15.js", "Infinity/Math.round(-0.49)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.15.js", "Infinity/Math.round(-0.5)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.17.js", "Infinity/Math.sqrt(-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.18.js", "Infinity/Math.tan(-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.2.js", "Math.acos(1.00000001)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.2.js", "Math.acos(11.00000001)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.3.js", "Math.asin(1.000001)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.3.js", "Math.asin(-1.000001)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.3.js", "Infinity/Math.asin(-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.4.js", "Infinity/Math.atan(-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.5.js", "Math.atan2(0, -0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.5.js", "Infinity/Math.atan2(-0, 1)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.5.js", "Math.atan2(-0,\t-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.5.js", "Math.atan2(-0,\t-1)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.6.js", "Infinity/Math.ceil('-0')", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.6.js", "Infinity/Math.ceil(-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.6.js", "Infinity/Math.ceil(-Number.MIN_VALUE)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.6.js", "Infinity/Math.ceil(-0.9)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.9.js", "Infinity/Math.floor(-0)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/TypeConversion/9.3.1-3.js", "var z = 0; print(1/-z)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/TypeConversion/9.3.1-3.js", "1/-1e-2000", willFixInNextReleaseMessage); -#endif - -#ifdef Q_OS_SYMBIAN - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(-1, 0.5)", willFixInNextReleaseMessage); - addExpectedFailure("ecma/Math/15.8.2.13.js", "Math.pow(-1, -0.5)", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Operators/order-01.js", "operator evaluation order: 11.5.1 *", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Operators/order-01.js", "operator evaluation order: 11.5.2 /", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Operators/order-01.js", "operator evaluation order: 11.6.2 -", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Operators/order-01.js", "operator evaluation order: 11.13.2 *=", willFixInNextReleaseMessage); - addExpectedFailure("ecma_3/Operators/order-01.js", "operator evaluation order: 11.13.2 /=", willFixInNextReleaseMessage); -#endif - - static const char klass[] = "tst_QScriptJsTestSuite"; - - QVector<uint> *data = qt_meta_data_tst_Suite(); - // content: - *data << 1 // revision - << 0 // classname - << 0 << 0 // classinfo - << 0 << 10 // methods (backpatched later) - << 0 << 0 // properties - << 0 << 0 // enums/sets - ; - - QVector<char> *stringdata = qt_meta_stringdata_tst_Suite(); - appendCString(stringdata, klass); - appendCString(stringdata, ""); - // don't execute any tests on slow machines #if !defined(Q_OS_IRIX) // do all the test suites - QFileInfoList testSuiteDirInfos; - if (testsFound) - testSuiteDirInfos = testsDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); + QFileInfoList testSuiteDirInfos = testsDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); foreach (QFileInfo tsdi, testSuiteDirInfos) { QDir testSuiteDir(tsdi.absoluteFilePath()); // do all the dirs in the test suite QFileInfoList subSuiteDirInfos = testSuiteDir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); foreach (QFileInfo ssdi, subSuiteDirInfos) { subSuitePaths.append(ssdi.absoluteFilePath()); - // slot: signature, parameters, type, tag, flags - QString data_slot = QString::fromLatin1("%0/%1_data()") - .arg(testSuiteDir.dirName()).arg(ssdi.fileName()); - static const int nullbyte = sizeof(klass); - *data << stringdata->size() << nullbyte << nullbyte << nullbyte << 0x08; - appendCString(stringdata, data_slot.toLatin1()); - QString slot = QString::fromLatin1("%0/%1()") - .arg(testSuiteDir.dirName()).arg(ssdi.fileName()); - *data << stringdata->size() << nullbyte << nullbyte << nullbyte << 0x08; - appendCString(stringdata, slot.toLatin1()); + QString function = QString::fromLatin1("%0/%1") + .arg(testSuiteDir.dirName()).arg(ssdi.fileName()); + addTestFunction(function, CreateDataFunction); } } #endif - (*data)[4] = subSuitePaths.size() * 2; + finalizeMetaObject(); +} + +tst_QScriptJSTestSuite::~tst_QScriptJSTestSuite() +{ +} - *data << 0; // eod +void tst_QScriptJSTestSuite::configData(TestConfig::Mode mode, const QStringList &parts) +{ + switch (mode) { + case TestConfig::Skip: + addFileExclusion(parts.at(0), parts.value(1)); + break; + + case TestConfig::ExpectFail: + addExpectedFailure(parts.at(0), parts.value(1), parts.value(2)); + break; + } +} - // initialize staticMetaObject - staticMetaObject.d.superdata = &QObject::staticMetaObject; - staticMetaObject.d.stringdata = stringdata->constData(); - staticMetaObject.d.data = data->constData(); - staticMetaObject.d.extradata = 0; +void tst_QScriptJSTestSuite::writeSkipConfigFile(QTextStream &stream) +{ + stream << QString::fromLatin1("# testcase | message") << endl; } -tst_Suite::~tst_Suite() +void tst_QScriptJSTestSuite::writeExpectFailConfigFile(QTextStream &stream) { -#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE - if (!generatedAddExpectedFailureCode.isEmpty()) { - QFile file("addexpectedfailures.cpp"); - file.open(QFile::WriteOnly); - QTextStream ts(&file); - ts << generatedAddExpectedFailureCode; + stream << QString::fromLatin1("# testcase | description | message") << endl; + for (int i = 0; i < expectedFailures.size(); ++i) { + const FailureItem &fail = expectedFailures.at(i); + if (fail.pathRegExp.pattern().isEmpty()) + continue; + stream << QString::fromLatin1("%0 | %1") + .arg(fail.pathRegExp.pattern()) + .arg(escape(fail.description)); + if (!fail.message.isEmpty()) + stream << QString::fromLatin1(" | %0").arg(escape(fail.message)); + stream << endl; } -#endif } -void tst_Suite::addExpectedFailure(const QRegExp &path, const QString &description, const QString &message) +void tst_QScriptJSTestSuite::addExpectedFailure(const QRegExp &path, const QString &description, const QString &message) { expectedFailures.append(FailureItem(FailureItem::ExpectFail, path, description, message)); } -void tst_Suite::addExpectedFailure(const QString &fileName, const QString &description, const QString &message) +void tst_QScriptJSTestSuite::addExpectedFailure(const QString &fileName, const QString &description, const QString &message) { expectedFailures.append(FailureItem(FailureItem::ExpectFail, QRegExp(fileName), description, message)); } -void tst_Suite::addSkip(const QRegExp &path, const QString &description, const QString &message) +void tst_QScriptJSTestSuite::addSkip(const QRegExp &path, const QString &description, const QString &message) { expectedFailures.append(FailureItem(FailureItem::Skip, path, description, message)); } -void tst_Suite::addSkip(const QString &fileName, const QString &description, const QString &message) +void tst_QScriptJSTestSuite::addSkip(const QString &fileName, const QString &description, const QString &message) { expectedFailures.append(FailureItem(FailureItem::Skip, QRegExp(fileName), description, message)); } -bool tst_Suite::isExpectedFailure(const QString &fileName, const QString &description, +bool tst_QScriptJSTestSuite::isExpectedFailure(const QString &fileName, const QString &description, QString *message, FailureItem::Action *action) const { for (int i = 0; i < expectedFailures.size(); ++i) { @@ -857,17 +430,17 @@ bool tst_Suite::isExpectedFailure(const QString &fileName, const QString &descri return false; } -void tst_Suite::addFileExclusion(const QString &fileName, const QString &message) +void tst_QScriptJSTestSuite::addFileExclusion(const QString &fileName, const QString &message) { fileExclusions.append(qMakePair(QRegExp(fileName), message)); } -void tst_Suite::addFileExclusion(const QRegExp &rx, const QString &message) +void tst_QScriptJSTestSuite::addFileExclusion(const QRegExp &rx, const QString &message) { fileExclusions.append(qMakePair(rx, message)); } -bool tst_Suite::isExcludedFile(const QString &fileName, QString *message) const +bool tst_QScriptJSTestSuite::isExcludedFile(const QString &fileName, QString *message) const { for (int i = 0; i < fileExclusions.size(); ++i) { if (fileExclusions.at(i).first.indexIn(fileName) != -1) { @@ -879,4 +452,4 @@ bool tst_Suite::isExcludedFile(const QString &fileName, QString *message) const return false; } -QTEST_MAIN(tst_Suite) +QTEST_MAIN(tst_QScriptJSTestSuite) diff --git a/tests/auto/qscriptv8testsuite/abstracttestsuite.cpp b/tests/auto/qscriptv8testsuite/abstracttestsuite.cpp new file mode 100644 index 0000000..d47eb24 --- /dev/null +++ b/tests/auto/qscriptv8testsuite/abstracttestsuite.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** +** +** 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 "abstracttestsuite.h" +#include <QtTest/QtTest> +#include <QtCore/qset.h> +#include <QtCore/qtextstream.h> + +/*! + AbstractTestSuite provides a way of building QtTest test objects + dynamically. The use case is integration of JavaScript test suites + into QtTest autotests. + + Subclasses add their tests functions with addTestFunction() in the + constructor, and must reimplement runTestFunction(). Additionally, + subclasses can reimplement initTestCase() and cleanupTestCase() + (but make sure to call the base implementation). + + AbstractTestSuite uses configuration files for getting information + about skipped tests (skip.txt) and expected test failures + (expect_fail.txt). Subclasses must reimplement + createSkipConfigFile() and createExpectFailConfigFile() for + creating these files, and configData() for processing an entry of + such a file. + + The config file format is as follows: + - Lines starting with '#' are skipped. + - Lines of the form [SYMBOL] means that the upcoming data + should only be processed if the given SYMBOL is defined on + this platform. + - Any other line is split on ' | ' and handed off to the client. + + Subclasses must provide a default tests directory (where the + subclass expects to find the script files to run as tests), and a + default config file directory. Some environment variables can be + used to affect where AbstractTestSuite will look for files: + + - QTSCRIPT_TEST_CONFIG_DIR: Overrides the default test config path. + + - QTSCRIPT_TEST_CONFIG_SUFFIX: Is appended to "skip" and + "expect_fail" to create the test config name. This makes it easy to + maintain skip- and expect_fail-files corresponding to different + revisions of a test suite, and switch between them. + + - QTSCRIPT_TEST_DIR: Overrides the default test dir. + + AbstractTestSuite does _not_ define how the test dir itself is + processed or how tests are run; this is left up to the subclass. + + If no config files are found, AbstractTestSuite will ask the + subclass to create a default skip file. Also, the + shouldGenerateExpectedFailures variable will be set to true. The + subclass should check for this when a test fails, and add an entry + to its set of expected failures. When all tests have been run, + AbstractTestSuite will ask the subclass to create the expect_fail + file based on the tests that failed. The next time the autotest is + run, the created config files will be used. + + The reason for skipping a test is usually that it takes a very long + time to complete (or even hangs completely), or it crashes. It's + not possible for the test runner to know in advance which tests are + problematic, which is why the entries to the skip file are + typically added manually. When running tests for the first time, it + can be useful to run the autotest with the -v1 command line option, + so you can see the name of each test before it's run, and can add a + skip entry if appropriate. +*/ + +// Helper class for constructing the test class's QMetaObject contents +// at runtime. +class TestMetaObjectBuilder +{ +public: + TestMetaObjectBuilder(const QByteArray &className, + const QMetaObject *superClass); + + void appendPrivateVoidSlot(const char *signature); + void appendPrivateVoidSlot(const QString &signature) + { appendPrivateVoidSlot(signature.toLatin1().constData()); } + + void assignContents(QMetaObject &); + +private: + void appendString(const char *); + void finalize(); + + const QByteArray m_className; + const QMetaObject *m_superClass; + QVector<uint> m_data; + QVector<char> m_stringdata; + int m_emptyStringOffset; + bool m_finalized; +}; + +TestMetaObjectBuilder::TestMetaObjectBuilder( + const QByteArray &className, + const QMetaObject *superClass) + : m_className(className), m_superClass(superClass), + m_finalized(false) +{ + // header + m_data << 1 // revision + << 0 // classname + << 0 << 0 // classinfo + << 0 << 10 // methods (backpatched later) + << 0 << 0 // properties + << 0 << 0 // enums/sets + ; + + appendString(className.constData()); + m_emptyStringOffset = m_stringdata.size(); + appendString(""); +} + +void TestMetaObjectBuilder::appendString(const char *s) +{ + char c; + do { + c = *(s++); + m_stringdata << c; + } while (c != '\0'); +} + +void TestMetaObjectBuilder::appendPrivateVoidSlot(const char *signature) +{ + static const int methodCountOffset = 4; + // signature, parameters, type, tag, flags + m_data << m_stringdata.size() + << m_emptyStringOffset + << m_emptyStringOffset + << m_emptyStringOffset + << 0x08; + appendString(signature); + ++m_data[methodCountOffset]; +} + +void TestMetaObjectBuilder::finalize() +{ + if (m_finalized) + return; + m_data << 0; // eod + m_finalized = true; +} + +/** + Assigns this builder's contents to the meta-object \a mo. It's up + to the caller to ensure that this builder (and hence, its data) + stays alive as long as needed. +*/ +void TestMetaObjectBuilder::assignContents(QMetaObject &mo) +{ + finalize(); + mo.d.superdata = m_superClass; + mo.d.stringdata = m_stringdata.constData(); + mo.d.data = m_data.constData(); + mo.d.extradata = 0; +} + + +class TestConfigClientInterface; +// For parsing information about skipped tests and expected failures. +class TestConfigParser +{ +public: + static void parse(const QString &path, + TestConfig::Mode mode, + TestConfigClientInterface *client); + +private: + static QString unescape(const QString &); + static bool isKnownSymbol(const QString &); + static bool isDefined(const QString &); + + static QSet<QString> knownSymbols; + static QSet<QString> definedSymbols; +}; + +QSet<QString> TestConfigParser::knownSymbols; +QSet<QString> TestConfigParser::definedSymbols; + +/** + Parses the config file at the given \a path in the given \a mode. + Handling of errors and data is delegated to the given \a client. +*/ +void TestConfigParser::parse(const QString &path, + TestConfig::Mode mode, + TestConfigClientInterface *client) +{ + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) + return; + QTextStream stream(&file); + int lineNumber = 0; + QString predicate; + const QString separator = QString::fromLatin1(" | "); + while (!stream.atEnd()) { + ++lineNumber; + QString line = stream.readLine(); + if (line.isEmpty()) + continue; + if (line.startsWith('#')) // Comment + continue; + if (line.startsWith('[')) { // Predicate + if (!line.endsWith(']')) { + client->configError(path, "malformed predicate", lineNumber); + return; + } + QString symbol = line.mid(1, line.size()-2); + if (isKnownSymbol(symbol)) { + predicate = symbol; + } else { + qWarning("symbol %s is not known -- add it to TestConfigParser!", qPrintable(symbol)); + predicate = QString(); + } + } else { + if (predicate.isEmpty() || isDefined(predicate)) { + QStringList parts = line.split(separator, QString::KeepEmptyParts); + for (int i = 0; i < parts.size(); ++i) + parts[i] = unescape(parts[i]); + client->configData(mode, parts); + } + } + } +} + +QString TestConfigParser::unescape(const QString &str) +{ + return QString(str).replace("\\n", "\n"); +} + +bool TestConfigParser::isKnownSymbol(const QString &symbol) +{ + if (knownSymbols.isEmpty()) { + knownSymbols + // If you add a symbol here, add a case for it in + // isDefined() as well. + << "Q_OS_LINUX" + << "Q_OS_SOLARIS" + << "Q_OS_WINCE" + << "Q_OS_SYMBIAN" + << "Q_CC_MSVC" + << "Q_CC_MINGW" + ; + } + return knownSymbols.contains(symbol); +} + +bool TestConfigParser::isDefined(const QString &symbol) +{ + if (definedSymbols.isEmpty()) { + definedSymbols +#ifdef Q_OS_LINUX + << "Q_OS_LINUX" +#endif +#ifdef Q_OS_SOLARIS + << "Q_OS_SOLARIS" +#endif +#ifdef Q_OS_WINCE + << "Q_OS_WINCE" +#endif +#ifdef Q_OS_SYMBIAN + << "Q_OS_SYMBIAN" +#endif +#ifdef Q_CC_MSVC + << "Q_CC_MSVC" +#endif +#ifdef Q_CC_MINGW + << "Q_CC_MINGW" +#endif + ; + } + return definedSymbols.contains(symbol); +} + + +QMetaObject AbstractTestSuite::staticMetaObject; + +const QMetaObject *AbstractTestSuite::metaObject() const +{ + return &staticMetaObject; +} + +void *AbstractTestSuite::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, staticMetaObject.d.stringdata)) + return static_cast<void*>(const_cast<AbstractTestSuite*>(this)); + return QObject::qt_metacast(_clname); +} + +int AbstractTestSuite::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + switch (_id) { + case 0: + initTestCase(); + break; + case 1: + cleanupTestCase(); + break; + default: + // If another method is added above, this offset must be adjusted. + runTestFunction(_id - 2); + } + _id -= staticMetaObject.methodCount() - staticMetaObject.methodOffset(); + } + return _id; +} + +AbstractTestSuite::AbstractTestSuite(const QByteArray &className, + const QString &defaultTestsPath, + const QString &defaultConfigPath) + : shouldGenerateExpectedFailures(false), + metaBuilder(new TestMetaObjectBuilder(className, &QObject::staticMetaObject)) +{ + QString testConfigPath = qgetenv("QTSCRIPT_TEST_CONFIG_DIR"); + if (testConfigPath.isEmpty()) + testConfigPath = defaultConfigPath; + QString configSuffix = qgetenv("QTSCRIPT_TEST_CONFIG_SUFFIX"); + skipConfigPath = QString::fromLatin1("%0/skip%1.txt") + .arg(testConfigPath).arg(configSuffix); + expectFailConfigPath = QString::fromLatin1("%0/expect_fail%1.txt") + .arg(testConfigPath).arg(configSuffix); + + QString testsPath = qgetenv("QTSCRIPT_TEST_DIR"); + if (testsPath.isEmpty()) + testsPath = defaultTestsPath; + testsDir = QDir(testsPath); + + addTestFunction("initTestCase"); + addTestFunction("cleanupTestCase"); + + // Subclass constructors should add their custom test functions to + // the meta-object and call finalizeMetaObject(). +} + +AbstractTestSuite::~AbstractTestSuite() +{ + delete metaBuilder; +} + +void AbstractTestSuite::addTestFunction(const QString &name, + DataFunctionCreation dfc) +{ + if (dfc == CreateDataFunction) { + QString dataSignature = QString::fromLatin1("%0_data()").arg(name); + metaBuilder->appendPrivateVoidSlot(dataSignature); + } + QString signature = QString::fromLatin1("%0()").arg(name); + metaBuilder->appendPrivateVoidSlot(signature); +} + +void AbstractTestSuite::finalizeMetaObject() +{ + metaBuilder->assignContents(staticMetaObject); +} + +void AbstractTestSuite::initTestCase() +{ + if (!testsDir.exists()) { + QString message = QString::fromLatin1("tests directory (%0) doesn't exist.") + .arg(testsDir.path()); + QFAIL(qPrintable(message)); + return; + } + + if (QFileInfo(skipConfigPath).exists()) + TestConfigParser::parse(skipConfigPath, TestConfig::Skip, this); + else + createSkipConfigFile(); + + if (QFileInfo(expectFailConfigPath).exists()) + TestConfigParser::parse(expectFailConfigPath, TestConfig::ExpectFail, this); + else + shouldGenerateExpectedFailures = true; +} + +void AbstractTestSuite::cleanupTestCase() +{ + if (shouldGenerateExpectedFailures) + createExpectFailConfigFile(); +} + +void AbstractTestSuite::configError(const QString &path, const QString &message, int lineNumber) +{ + QString output; + output.append(path); + if (lineNumber != -1) + output.append(":").append(QString::number(lineNumber)); + output.append(": ").append(message); + QFAIL(qPrintable(output)); +} + +void AbstractTestSuite::createSkipConfigFile() +{ + QFile file(skipConfigPath); + if (!file.open(QIODevice::WriteOnly)) + return; + QWARN(qPrintable(QString::fromLatin1("creating %0").arg(skipConfigPath))); + QTextStream stream(&file); + + writeSkipConfigFile(stream); + + file.close(); +} + +void AbstractTestSuite::createExpectFailConfigFile() +{ + QFile file(expectFailConfigPath); + if (!file.open(QFile::WriteOnly)) + return; + QWARN(qPrintable(QString::fromLatin1("creating %0").arg(expectFailConfigPath))); + QTextStream stream(&file); + + writeExpectFailConfigFile(stream); + + file.close(); +} + +/*! + Convenience function for reading all contents of a file. + */ +QString AbstractTestSuite::readFile(const QString &filename) +{ + QFile file(filename); + if (!file.open(QFile::ReadOnly)) + return QString(); + QTextStream stream(&file); + stream.setCodec("UTF-8"); + return stream.readAll(); +} + +/*! + Escapes characters in the string \a str so it's suitable for writing + to a config file. + */ +QString AbstractTestSuite::escape(const QString &str) +{ + return QString(str).replace("\n", "\\n"); +} diff --git a/tests/auto/qscriptv8testsuite/abstracttestsuite.h b/tests/auto/qscriptv8testsuite/abstracttestsuite.h new file mode 100644 index 0000000..b13c61a --- /dev/null +++ b/tests/auto/qscriptv8testsuite/abstracttestsuite.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef ABSTRACTTESTSUITE_H +#define ABSTRACTTESTSUITE_H + +#include <QtCore/qobject.h> + +#include <QtCore/qbytearray.h> +#include <QtCore/qdir.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qvector.h> +#include <QtCore/qtextstream.h> + +class TestMetaObjectBuilder; + +namespace TestConfig { +enum Mode { + Skip, + ExpectFail +}; +} + +// For receiving callbacks from the config parser. +class TestConfigClientInterface +{ +public: + virtual ~TestConfigClientInterface() {} + virtual void configData(TestConfig::Mode mode, + const QStringList &parts) = 0; + virtual void configError(const QString &path, + const QString &message, + int lineNumber) = 0; +}; + +class AbstractTestSuite : public QObject, + public TestConfigClientInterface +{ +// No Q_OBJECT macro, we implement the meta-object ourselves. +public: + AbstractTestSuite(const QByteArray &className, + const QString &defaultTestsPath, + const QString &defaultConfigPath); + virtual ~AbstractTestSuite(); + + static QMetaObject staticMetaObject; + virtual const QMetaObject *metaObject() const; + virtual void *qt_metacast(const char *); + virtual int qt_metacall(QMetaObject::Call, int, void **argv); + + static QString readFile(const QString &); + static QString escape(const QString &); + +protected: + enum DataFunctionCreation { + DontCreateDataFunction, + CreateDataFunction + }; + + void addTestFunction(const QString &, + DataFunctionCreation = DontCreateDataFunction); + void finalizeMetaObject(); + + virtual void initTestCase(); + virtual void cleanupTestCase(); + + virtual void writeSkipConfigFile(QTextStream &) = 0; + virtual void writeExpectFailConfigFile(QTextStream &) = 0; + + virtual void runTestFunction(int index) = 0; + + virtual void configError(const QString &path, const QString &message, int lineNumber); + + QDir testsDir; + bool shouldGenerateExpectedFailures; + +private: + TestMetaObjectBuilder *metaBuilder; + QString skipConfigPath, expectFailConfigPath; + +private: + void createSkipConfigFile(); + void createExpectFailConfigFile(); +}; + +#endif diff --git a/tests/auto/qscriptv8testsuite/abstracttestsuite.pri b/tests/auto/qscriptv8testsuite/abstracttestsuite.pri new file mode 100644 index 0000000..1de5b93 --- /dev/null +++ b/tests/auto/qscriptv8testsuite/abstracttestsuite.pri @@ -0,0 +1,4 @@ +SOURCES += $$PWD/abstracttestsuite.cpp +HEADERS += $$PWD/abstracttestsuite.h +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD diff --git a/tests/auto/qscriptv8testsuite/expect_fail.txt b/tests/auto/qscriptv8testsuite/expect_fail.txt new file mode 100644 index 0000000..a4eee73 --- /dev/null +++ b/tests/auto/qscriptv8testsuite/expect_fail.txt @@ -0,0 +1,16 @@ +# testcase | actual | expected | message +arguments-enum | 2 | 0 +const-redecl | undefined | TypeError | local:'const x; var x' +date-parse | NaN | 946713600000 | Sat, 01-Jan-2000 08:00:00 GMT+00:00 +delete-global-properties | true | false +delete | false | true | delete 100 +function-arguments-null | false | true +function-caller | null | function eval() {\n [native code]\n} +function-prototype | prototype | disconnectconnect +global-const-var-conflicts | false | true +number-tostring | 0 | 0.0000a7c5ac471b4788 +parse-int-float | 1e+21 | 1 +regexp | false | true +string-lastindexof | 0 | -1 +string-split | 4 | 3 | 19 - array length +substr | abcdefghijklmn | diff --git a/tests/auto/qscriptv8testsuite/qscriptv8testsuite.pro b/tests/auto/qscriptv8testsuite/qscriptv8testsuite.pro index 00e2e01..e1c6234 100644 --- a/tests/auto/qscriptv8testsuite/qscriptv8testsuite.pro +++ b/tests/auto/qscriptv8testsuite/qscriptv8testsuite.pro @@ -2,3 +2,4 @@ load(qttest_p4) QT = core script SOURCES += tst_qscriptv8testsuite.cpp RESOURCES += qscriptv8testsuite.qrc +include(abstracttestsuite.pri) diff --git a/tests/auto/qscriptv8testsuite/qscriptv8testsuite.qrc b/tests/auto/qscriptv8testsuite/qscriptv8testsuite.qrc index a894ee5..150ccf0 100644 --- a/tests/auto/qscriptv8testsuite/qscriptv8testsuite.qrc +++ b/tests/auto/qscriptv8testsuite/qscriptv8testsuite.qrc @@ -1,5 +1,7 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>tests</file> + <file>expect_fail.txt</file> + <file>skip.txt</file> </qresource> </RCC> diff --git a/tests/auto/qscriptv8testsuite/skip.txt b/tests/auto/qscriptv8testsuite/skip.txt new file mode 100644 index 0000000..3c2cc53 --- /dev/null +++ b/tests/auto/qscriptv8testsuite/skip.txt @@ -0,0 +1,17 @@ +# testcase | message +debug-* | not applicable +mirror-* | not applicable +array-concat | Hangs on JSC backend +array-splice | Hangs on JSC backend +sparse-array-reverse | Hangs on JSC backend +string-case | V8-specific behavior? (Doesn't pass on SpiderMonkey either) + +[Q_OS_WINCE] +deep-recursion | Demands too much memory on WinCE +nested-repetition-count-overflow | Demands too much memory on WinCE +unicode-test | Demands too much memory on WinCE +mul-exhaustive | Demands too much memory on WinCE + +[Q_OS_SYMBIAN] +nested-repetition-count-overflow | Demands too much memory on Symbian +unicode-test | Demands too much memory on Symbian diff --git a/tests/auto/qscriptv8testsuite/tst_qscriptv8testsuite.cpp b/tests/auto/qscriptv8testsuite/tst_qscriptv8testsuite.cpp index 7d0858e..b35fd06 100644 --- a/tests/auto/qscriptv8testsuite/tst_qscriptv8testsuite.cpp +++ b/tests/auto/qscriptv8testsuite/tst_qscriptv8testsuite.cpp @@ -40,68 +40,33 @@ ****************************************************************************/ +#include "abstracttestsuite.h" #include <QtTest/QtTest> -#include <QByteArray> - #include <QtScript> //TESTED_CLASS= //TESTED_FILES= -// Uncomment the following define to have the autotest generate -// addExpectedFailure() code for all the tests that fail. -// This is useful when a whole new test (sub)suite is added. -// The code is stored in addexpectedfailures.cpp. -// Paste the contents into this file after the existing -// addExpectedFailure() calls. - -//#define GENERATE_ADDEXPECTEDFAILURE_CODE - -static QString readFile(const QString &filename) -{ - QFile file(filename); - if (!file.open(QFile::ReadOnly)) - return QString(); - QTextStream stream(&file); - stream.setCodec("UTF-8"); - return stream.readAll(); -} - -static void appendCString(QVector<char> *v, const char *s) -{ - char c; - do { - c = *(s++); - *v << c; - } while (c != '\0'); -} - -struct ExpectedFailure +class tst_QScriptV8TestSuite : public AbstractTestSuite { - ExpectedFailure(const QString &name, const QString &act, - const QString &exp, const QString &msg) - : testName(name), actual(act), expected(exp), message(msg) - { } - - QString testName; - QString actual; - QString expected; - QString message; -}; - -class tst_Suite : public QObject -{ - public: - tst_Suite(); - virtual ~tst_Suite(); + tst_QScriptV8TestSuite(); + virtual ~tst_QScriptV8TestSuite(); + +protected: + struct ExpectedFailure + { + ExpectedFailure(const QString &name, const QString &act, + const QString &exp, const QString &msg) + : testName(name), actual(act), expected(exp), message(msg) + { } + + QString testName; + QString actual; + QString expected; + QString message; + }; - static QMetaObject staticMetaObject; - virtual const QMetaObject *metaObject() const; - virtual void *qt_metacast(const char *); - virtual int qt_metacall(QMetaObject::Call, int, void **argv); - -private: void addExpectedFailure(const QString &testName, const QString &actual, const QString &expected, const QString &message); bool isExpectedFailure(const QString &testName, const QString &actual, @@ -110,34 +75,23 @@ private: void addTestExclusion(const QRegExp &rx, const QString &message); bool isExcludedTest(const QString &testName, QString *message) const; - QDir testsDir; + virtual void initTestCase(); + virtual void configData(TestConfig::Mode mode, const QStringList &parts); + virtual void writeSkipConfigFile(QTextStream &); + virtual void writeExpectFailConfigFile(QTextStream &); + virtual void runTestFunction(int testIndex); + QStringList testNames; QList<ExpectedFailure> expectedFailures; QList<QPair<QRegExp, QString> > testExclusions; QString mjsunitContents; -#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE - QString generatedAddExpectedFailureCode; -#endif }; -QMetaObject tst_Suite::staticMetaObject; - -Q_GLOBAL_STATIC(QVector<uint>, qt_meta_data_tst_Suite) -Q_GLOBAL_STATIC(QVector<char>, qt_meta_stringdata_tst_Suite) - -const QMetaObject *tst_Suite::metaObject() const -{ - return &staticMetaObject; -} - -void *tst_Suite::qt_metacast(const char *_clname) -{ - if (!_clname) return 0; - if (!strcmp(_clname, qt_meta_stringdata_tst_Suite()->constData())) - return static_cast<void*>(const_cast<tst_Suite*>(this)); - return QObject::qt_metacast(_clname); -} - +// We expect failing tests to call the fail() function (defined in +// mjsunit.js) with arguments expected, actual, message_opt. This +// function intercepts the call, calls the real fail() function (which +// will throw an exception), and sets the original arguments on the +// exception object so that we can process them later. static QScriptValue qscript_fail(QScriptContext *ctx, QScriptEngine *eng) { QScriptValue realFail = ctx->callee().data(); @@ -146,193 +100,141 @@ static QScriptValue qscript_fail(QScriptContext *ctx, QScriptEngine *eng) Q_ASSERT(eng->hasUncaughtException()); ret.setProperty("expected", ctx->argument(0)); ret.setProperty("actual", ctx->argument(1)); + ret.setProperty("message", ctx->argument(2)); QScriptContextInfo info(ctx->parentContext()->parentContext()); ret.setProperty("lineNumber", info.lineNumber()); return ret; } -int tst_Suite::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +void tst_QScriptV8TestSuite::writeSkipConfigFile(QTextStream &stream) { - _id = QObject::qt_metacall(_c, _id, _a); - if (_id < 0) - return _id; - if (_c == QMetaObject::InvokeMetaMethod) { - QString name = testNames.at(_id); - QString path = testsDir.absoluteFilePath(name + ".js"); - QString excludeMessage; - if (isExcludedTest(name, &excludeMessage)) { - QTest::qSkip(excludeMessage.toLatin1(), QTest::SkipAll, path.toLatin1(), -1); - } else { - QScriptEngine engine; - engine.evaluate(mjsunitContents).toString(); - if (engine.hasUncaughtException()) { - QStringList bt = engine.uncaughtExceptionBacktrace(); - QString err = engine.uncaughtException().toString(); - qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); - } else { - QScriptValue fakeFail = engine.newFunction(qscript_fail); - fakeFail.setData(engine.globalObject().property("fail")); - engine.globalObject().setProperty("fail", fakeFail); - QString contents = readFile(path); - QScriptValue ret = engine.evaluate(contents); - if (engine.hasUncaughtException()) { - if (!ret.isError()) { - Q_ASSERT(ret.instanceOf(engine.globalObject().property("MjsUnitAssertionError"))); - QString actual = ret.property("actual").toString(); - QString expected = ret.property("expected").toString(); - int lineNumber = ret.property("lineNumber").toInt32(); - QString failMessage; - if (isExpectedFailure(name, actual, expected, &failMessage)) { - QTest::qExpectFail("", failMessage.toLatin1(), - QTest::Continue, path.toLatin1(), - lineNumber); - } -#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE - else { - generatedAddExpectedFailureCode.append( - " addExpectedFailure(\"" + name - + "\", \"" + actual + "\", \"" + expected - + "\", willFixInNextReleaseMessage);\n"); - } -#endif - QTest::qCompare(actual, expected, "actual", "expect", - path.toLatin1(), lineNumber); - } else { - int lineNumber = ret.property("lineNumber").toInt32(); - QTest::qExpectFail("", ret.toString().toLatin1(), - QTest::Continue, path.toLatin1(), lineNumber); - QTest::qVerify(false, ret.toString().toLatin1(), "", path.toLatin1(), lineNumber); - } - } - } - } - _id -= testNames.size(); - } - return _id; + stream << QString::fromLatin1("# testcase | message") << endl; } -tst_Suite::tst_Suite() +void tst_QScriptV8TestSuite::writeExpectFailConfigFile(QTextStream &stream) { - testsDir = QDir(":/tests"); - if (!testsDir.exists()) { - qWarning("*** no tests/ dir!"); - } else { - if (!testsDir.exists("mjsunit.js")) - qWarning("*** no tests/mjsunit.js file!"); - else { - mjsunitContents = readFile(testsDir.absoluteFilePath("mjsunit.js")); - if (mjsunitContents.isEmpty()) - qWarning("*** tests/mjsunit.js is empty!"); - } + stream << QString::fromLatin1("# testcase | actual | expected | message") << endl; + for (int i = 0; i < expectedFailures.size(); ++i) { + const ExpectedFailure &fail = expectedFailures.at(i); + stream << QString::fromLatin1("%0 | %1 | %2") + .arg(fail.testName) + .arg(escape(fail.actual)) + .arg(escape(fail.expected)); + if (!fail.message.isEmpty()) + stream << QString::fromLatin1(" | %0").arg(escape(fail.message)); + stream << endl; } - QString willFixInNextReleaseMessage = QString::fromLatin1("Will fix in next release"); - addExpectedFailure("arguments-enum", "2", "0", willFixInNextReleaseMessage); - addExpectedFailure("const-redecl", "undefined", "TypeError", willFixInNextReleaseMessage); - addExpectedFailure("global-const-var-conflicts", "false", "true", willFixInNextReleaseMessage); - addExpectedFailure("string-lastindexof", "0", "-1", "test is wrong?"); - -#ifndef Q_OS_LINUX - addExpectedFailure("to-precision", "1.235e+27", "1.234e+27", "QTBUG-8053: toPrecision(4) gives wrong result on Mac"); -#endif - -#ifdef Q_OS_SOLARIS - addExpectedFailure("math-min-max", "Infinity", "-Infinity", willFixInNextReleaseMessage); - addExpectedFailure("negate-zero", "false", "true", willFixInNextReleaseMessage); - addExpectedFailure("str-to-num", "Infinity", "-Infinity", willFixInNextReleaseMessage); -#endif - - addTestExclusion("debug-*", "not applicable"); - addTestExclusion("mirror-*", "not applicable"); - - addTestExclusion("array-concat", "Hangs on JSC backend"); - addTestExclusion("array-splice", "Hangs on JSC backend"); - addTestExclusion("sparse-array-reverse", "Hangs on JSC backend"); - - addTestExclusion("string-case", "V8-specific behavior? (Doesn't pass on SpiderMonkey either)"); - -#ifdef Q_OS_WINCE - addTestExclusion("deep-recursion", "Demands too much memory on WinCE"); - addTestExclusion("nested-repetition-count-overflow", "Demands too much memory on WinCE"); - addTestExclusion("unicode-test", "Demands too much memory on WinCE"); - addTestExclusion("mul-exhaustive", "Demands too much memory on WinCE"); -#endif - -#ifdef Q_OS_SYMBIAN - addTestExclusion("nested-repetition-count-overflow", "Demands too much memory on Symbian"); - addTestExclusion("unicode-test", "Demands too much memory on Symbian"); -#endif - // Failures due to switch to JSC as back-end - addExpectedFailure("date-parse", "NaN", "946713600000", willFixInNextReleaseMessage); - addExpectedFailure("delete-global-properties", "true", "false", willFixInNextReleaseMessage); - addExpectedFailure("delete", "false", "true", willFixInNextReleaseMessage); - addExpectedFailure("function-arguments-null", "false", "true", willFixInNextReleaseMessage); - addExpectedFailure("function-caller", "null", "function eval() {\n [native code]\n}", willFixInNextReleaseMessage); - addExpectedFailure("function-prototype", "prototype", "disconnectconnect", willFixInNextReleaseMessage); - addExpectedFailure("number-tostring", "0", "0.0000a7c5ac471b4788", willFixInNextReleaseMessage); - addExpectedFailure("parse-int-float", "1e+21", "1", willFixInNextReleaseMessage); - addExpectedFailure("regexp", "false", "true", willFixInNextReleaseMessage); - addExpectedFailure("smi-negative-zero", "-Infinity", "Infinity", willFixInNextReleaseMessage); - addExpectedFailure("string-split", "4", "3", willFixInNextReleaseMessage); - addExpectedFailure("substr", "abcdefghijklmn", "", willFixInNextReleaseMessage); +} - static const char klass[] = "tst_QScriptV8TestSuite"; +void tst_QScriptV8TestSuite::runTestFunction(int testIndex) +{ + QString name = testNames.at(testIndex); + QString path = testsDir.absoluteFilePath(name + ".js"); - QVector<uint> *data = qt_meta_data_tst_Suite(); - // content: - *data << 1 // revision - << 0 // classname - << 0 << 0 // classinfo - << 0 << 10 // methods (backpatched later) - << 0 << 0 // properties - << 0 << 0 // enums/sets - ; + QString excludeMessage; + if (isExcludedTest(name, &excludeMessage)) { + QTest::qSkip(excludeMessage.toLatin1(), QTest::SkipAll, path.toLatin1(), -1); + return; + } - QVector<char> *stringdata = qt_meta_stringdata_tst_Suite(); - appendCString(stringdata, klass); - appendCString(stringdata, ""); + QScriptEngine engine; + engine.evaluate(mjsunitContents); + if (engine.hasUncaughtException()) { + QStringList bt = engine.uncaughtExceptionBacktrace(); + QString err = engine.uncaughtException().toString(); + qWarning("%s\n%s", qPrintable(err), qPrintable(bt.join("\n"))); + } else { + // Prepare to intercept calls to mjsunit's fail() function. + QScriptValue fakeFail = engine.newFunction(qscript_fail); + fakeFail.setData(engine.globalObject().property("fail")); + engine.globalObject().setProperty("fail", fakeFail); + + QString contents = readFile(path); + QScriptValue ret = engine.evaluate(contents); + if (engine.hasUncaughtException()) { + if (!ret.isError()) { + Q_ASSERT(ret.instanceOf(engine.globalObject().property("MjsUnitAssertionError"))); + QString actual = ret.property("actual").toString(); + QString expected = ret.property("expected").toString(); + int lineNumber = ret.property("lineNumber").toInt32(); + QString failMessage; + if (shouldGenerateExpectedFailures) { + if (ret.property("message").isString()) + failMessage = ret.property("message").toString(); + addExpectedFailure(name, actual, expected, failMessage); + } else if (isExpectedFailure(name, actual, expected, &failMessage)) { + QTest::qExpectFail("", failMessage.toLatin1(), + QTest::Continue, path.toLatin1(), + lineNumber); + } + QTest::qCompare(actual, expected, "actual", "expect", + path.toLatin1(), lineNumber); + } else { + int lineNumber = ret.property("lineNumber").toInt32(); + QTest::qExpectFail("", ret.toString().toLatin1(), + QTest::Continue, path.toLatin1(), lineNumber); + QTest::qVerify(false, ret.toString().toLatin1(), "", path.toLatin1(), lineNumber); + } + } + } +} +tst_QScriptV8TestSuite::tst_QScriptV8TestSuite() + : AbstractTestSuite("tst_QScriptV8TestSuite", + ":/tests", ":/") +{ + // One test function per test file. QFileInfoList testFileInfos; testFileInfos = testsDir.entryInfoList(QStringList() << "*.js", QDir::Files); foreach (QFileInfo tfi, testFileInfos) { QString name = tfi.baseName(); - // slot: signature, parameters, type, tag, flags - QString slot = QString::fromLatin1("%0()").arg(name); - static const int nullbyte = sizeof(klass); - *data << stringdata->size() << nullbyte << nullbyte << nullbyte << 0x08; - appendCString(stringdata, slot.toLatin1()); + addTestFunction(name); testNames.append(name); } - (*data)[4] = testFileInfos.size(); + finalizeMetaObject(); +} - *data << 0; // eod +tst_QScriptV8TestSuite::~tst_QScriptV8TestSuite() +{ +} - // initialize staticMetaObject - staticMetaObject.d.superdata = &QObject::staticMetaObject; - staticMetaObject.d.stringdata = stringdata->constData(); - staticMetaObject.d.data = data->constData(); - staticMetaObject.d.extradata = 0; +void tst_QScriptV8TestSuite::initTestCase() +{ + AbstractTestSuite::initTestCase(); + + // FIXME: These warnings should be QFAIL, but that would make the + // test fail right now. + if (!testsDir.exists("mjsunit.js")) + qWarning("*** no tests/mjsunit.js file!"); + else { + mjsunitContents = readFile(testsDir.absoluteFilePath("mjsunit.js")); + if (mjsunitContents.isEmpty()) + qWarning("*** tests/mjsunit.js is empty!"); + } } -tst_Suite::~tst_Suite() +void tst_QScriptV8TestSuite::configData(TestConfig::Mode mode, const QStringList &parts) { -#ifdef GENERATE_ADDEXPECTEDFAILURE_CODE - if (!generatedAddExpectedFailureCode.isEmpty()) { - QFile file("addexpectedfailures.cpp"); - file.open(QFile::WriteOnly); - QTextStream ts(&file); - ts << generatedAddExpectedFailureCode; + switch (mode) { + case TestConfig::Skip: + addTestExclusion(parts.at(0), parts.value(1)); + break; + + case TestConfig::ExpectFail: + addExpectedFailure(parts.at(0), parts.value(1), + parts.value(2), parts.value(3)); + break; } -#endif } -void tst_Suite::addExpectedFailure(const QString &testName, const QString &actual, +void tst_QScriptV8TestSuite::addExpectedFailure(const QString &testName, const QString &actual, const QString &expected, const QString &message) { expectedFailures.append(ExpectedFailure(testName, actual, expected, message)); } -bool tst_Suite::isExpectedFailure(const QString &testName, const QString &actual, +bool tst_QScriptV8TestSuite::isExpectedFailure(const QString &testName, const QString &actual, const QString &expected, QString *message) const { for (int i = 0; i < expectedFailures.size(); ++i) { @@ -346,17 +248,17 @@ bool tst_Suite::isExpectedFailure(const QString &testName, const QString &actual return false; } -void tst_Suite::addTestExclusion(const QString &testName, const QString &message) +void tst_QScriptV8TestSuite::addTestExclusion(const QString &testName, const QString &message) { testExclusions.append(qMakePair(QRegExp(testName), message)); } -void tst_Suite::addTestExclusion(const QRegExp &rx, const QString &message) +void tst_QScriptV8TestSuite::addTestExclusion(const QRegExp &rx, const QString &message) { testExclusions.append(qMakePair(rx, message)); } -bool tst_Suite::isExcludedTest(const QString &testName, QString *message) const +bool tst_QScriptV8TestSuite::isExcludedTest(const QString &testName, QString *message) const { for (int i = 0; i < testExclusions.size(); ++i) { if (testExclusions.at(i).first.indexIn(testName) != -1) { @@ -368,4 +270,4 @@ bool tst_Suite::isExcludedTest(const QString &testName, QString *message) const return false; } -QTEST_MAIN(tst_Suite) +QTEST_MAIN(tst_QScriptV8TestSuite) diff --git a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp index b302eba..6686e2d 100644 --- a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp +++ b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp @@ -1889,7 +1889,7 @@ void tst_QScriptValue::getSetProperty_gettersAndSetters() QCOMPARE(object.propertyFlags("foo") & ~QScriptValue::UserRange, QScriptValue::PropertyGetter ); - QEXPECT_FAIL("", "User-range flags are not retained for getter/setter properties", Continue); + QEXPECT_FAIL("", "QTBUG-17615: User-range flags are not retained for getter/setter properties", Continue); QCOMPARE(object.propertyFlags("foo"), QScriptValue::PropertyGetter | QScriptValue::UserRange); object.setProperty("x", num); @@ -2004,10 +2004,10 @@ void tst_QScriptValue::getSetProperty_gettersAndSettersThrowErrorJS() QScriptValue object = eng.evaluate("o"); QVERIFY(!eng.hasUncaughtException()); QScriptValue ret = object.property("foo"); - QEXPECT_FAIL("", "Exception thrown from js function are not returned by the JSC port", Continue); + QEXPECT_FAIL("", "QTBUG-17616: Exception thrown from js function are not returned by the JSC port", Continue); QVERIFY(ret.isError()); QVERIFY(eng.hasUncaughtException()); - QEXPECT_FAIL("", "Exception thrown from js function are not returned by the JSC port", Continue); + QEXPECT_FAIL("", "QTBUG-17616: Exception thrown from js function are not returned by the JSC port", Continue); QVERIFY(ret.strictlyEquals(eng.uncaughtException())); QCOMPARE(eng.uncaughtException().toString(), QLatin1String("Error: get foo")); eng.evaluate("Object"); // clear exception state... @@ -2185,9 +2185,9 @@ void tst_QScriptValue::getSetProperty() } // should still be deletable from C++ object.setProperty("undeletableProperty", QScriptValue()); - QEXPECT_FAIL("", "With JSC-based back-end, undeletable properties can't be deleted from C++", Continue); + QEXPECT_FAIL("", "QTBUG-17617: With JSC-based back-end, undeletable properties can't be deleted from C++", Continue); QVERIFY(!object.property("undeletableProperty").isValid()); - QEXPECT_FAIL("", "With JSC-based back-end, undeletable properties can't be deleted from C++", Continue); + QEXPECT_FAIL("", "QTBUG-17617: With JSC-based back-end, undeletable properties can't be deleted from C++", Continue); QCOMPARE(object.propertyFlags("undeletableProperty"), 0); // SkipInEnumeration @@ -2328,8 +2328,7 @@ void tst_QScriptValue::getSetPrototype_invalidPrototype() inv.setPrototype(object); QCOMPARE(inv.prototype().isValid(), false); object.setPrototype(inv); - // FIXME should it be invalid or proto? - QVERIFY(object.prototype().strictlyEquals(inv)); + QVERIFY(object.prototype().strictlyEquals(proto)); } void tst_QScriptValue::getSetPrototype_twoEngines() @@ -2367,8 +2366,6 @@ void tst_QScriptValue::getSetPrototype_notObjectOrNull() QScriptValue object = eng.newObject(); QScriptValue originalProto = object.prototype(); - QEXPECT_FAIL("", "QTBUG-15154: QScriptValue::setPrototype() allows a non-Object value to be set as prototype", Abort); - // bool object.setPrototype(true); QVERIFY(object.prototype().equals(originalProto)); diff --git a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 6bb971d..d26f0cd 100644 --- a/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -144,6 +144,8 @@ private slots: void taskQTBUG_7537_appearsAndSort(); void taskQTBUG_7716_unnecessaryDynamicSorting(); void taskQTBUG_10287_unnecessaryMapCreation(); + void taskQTBUG_17812_resetInvalidate_data(); + void taskQTBUG_17812_resetInvalidate(); void testMultipleProxiesWithSelection(); void mapSelectionFromSource(); @@ -3351,5 +3353,60 @@ void tst_QSortFilterProxyModel::filteredColumns() insertCommand->doCommand(); } +void tst_QSortFilterProxyModel::taskQTBUG_17812_resetInvalidate_data() +{ + QTest::addColumn<int>("test"); + QTest::addColumn<bool>("works"); + + QTest::newRow("nothing") << 0 << false; + QTest::newRow("reset") << 1 << true; + QTest::newRow("invalidate") << 2 << true; + QTest::newRow("invalidate_filter") << 3 << true; +} + +void tst_QSortFilterProxyModel::taskQTBUG_17812_resetInvalidate() +{ + QFETCH(int, test); + QFETCH(bool, works); + + struct Proxy : QSortFilterProxyModel { + QString pattern; + virtual bool filterAcceptsRow(int source_row, const QModelIndex&) const { + return sourceModel()->data(sourceModel()->index(source_row, 0)).toString().contains(pattern); + } + void notifyChange(int test) { + switch (test) { + case 0: break; + case 1: reset(); break; + case 2: invalidate(); break; + case 3: invalidateFilter(); break; + } + } + }; + + QStringListModel sourceModel(QStringList() << "Poisson" << "Vache" << "Brebis" + << "Elephant" << "Cochon" << "Serpent" + << "Mouton" << "Ecureuil" << "Mouche"); + Proxy proxy; + proxy.pattern = QString::fromLatin1("n"); + proxy.setSourceModel(&sourceModel); + + QCOMPARE(proxy.rowCount(), 5); + for (int i = 0; i < proxy.rowCount(); i++) { + QVERIFY(proxy.data(proxy.index(i,0)).toString().contains('n')); + } + + proxy.pattern = QString::fromLatin1("o"); + proxy.notifyChange(test); + + QCOMPARE(proxy.rowCount(), works ? 4 : 5); + bool ok = true; + for (int i = 0; i < proxy.rowCount(); i++) { + if (!proxy.data(proxy.index(i,0)).toString().contains('o')) + ok = false; + } + QCOMPARE(ok, works); +} + QTEST_MAIN(tst_QSortFilterProxyModel) #include "tst_qsortfilterproxymodel.moc" diff --git a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp index f7d2180..bf68375 100644 --- a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp @@ -773,6 +773,27 @@ void tst_QSqlTableModel::removeInsertedRow() QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); + + // Now insert a row with a null, and check that removing it also works (QTBUG-15979 etc) + model.insertRow(1); + model.setData(model.index(1,0), 55); + model.setData(model.index(1,1), QString("null columns")); + model.setData(model.index(1,2), QVariant()); + + model.submitAll(); + + QCOMPARE(model.rowCount(), 4); + QCOMPARE(model.data(model.index(3, 0)).toInt(), 55); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("null columns")); + QCOMPARE(model.data(model.index(3, 2)).isNull(), true); + + QVERIFY(model.removeRow(3)); + model.submitAll(); + QCOMPARE(model.rowCount(), 3); + + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("trond")); + QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi")); } void tst_QSqlTableModel::removeInsertedRows() diff --git a/tests/auto/qsslsocket/tst_qsslsocket.cpp b/tests/auto/qsslsocket/tst_qsslsocket.cpp index 8177d29..739f902 100644 --- a/tests/auto/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/qsslsocket/tst_qsslsocket.cpp @@ -390,6 +390,9 @@ void tst_QSslSocket::constructing() QSslConfiguration savedDefault = QSslConfiguration::defaultConfiguration(); // verify that changing the default config doesn't affect this socket + // (on Unix, the ca certs might be empty, depending on whether we load + // them on demand or not, so set them explicitly) + socket.setCaCertificates(QSslSocket::systemCaCertificates()); QSslSocket::setDefaultCaCertificates(QList<QSslCertificate>()); QSslSocket::setDefaultCiphers(QList<QSslCipher>()); QVERIFY(!socket.caCertificates().isEmpty()); @@ -518,11 +521,6 @@ void tst_QSslSocket::sslErrors_data() << 993 << (SslErrorList() << QSslError::HostNameMismatch << QSslError::SelfSignedCertificate); - - QTest::newRow("imap.trolltech.com") - << "imap.trolltech.com" - << 993 - << (SslErrorList() << QSslError::SelfSignedCertificateInChain); } void tst_QSslSocket::sslErrors() diff --git a/tests/auto/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro b/tests/auto/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro new file mode 100644 index 0000000..ea62865 --- /dev/null +++ b/tests/auto/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro @@ -0,0 +1,36 @@ +load(qttest_p4) + +SOURCES += tst_qsslsocket_onDemandCertificates_member.cpp +!wince*:win32:LIBS += -lws2_32 +QT += network +QT -= gui + +TARGET = tst_qsslsocket_onDemandCertificates_member + +win32 { + CONFIG(debug, debug|release) { + DESTDIR = debug +} else { + DESTDIR = release + } +} + +wince* { + DEFINES += SRCDIR=\\\"./\\\" + + certFiles.files = certs ssl.tar.gz + certFiles.path = . + DEPLOYMENT += certFiles +} else:symbian { + TARGET.EPOCHEAPSIZE="0x100 0x1000000" + TARGET.CAPABILITY=NetworkServices + + certFiles.files = certs ssl.tar.gz + certFiles.path = . + DEPLOYMENT += certFiles + INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE # Needed for e32svr.h in S^3 envs +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + +requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp b/tests/auto/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp new file mode 100644 index 0000000..2a1358d --- /dev/null +++ b/tests/auto/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** 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 <QtNetwork> +#include <QtTest/QtTest> + +#include <QNetworkProxy> +#include <QAuthenticator> + +#include "private/qhostinfo_p.h" + +#include "../network-settings.h" + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "" +#endif + +#ifndef QT_NO_OPENSSL +class QSslSocketPtr: public QSharedPointer<QSslSocket> +{ +public: + inline QSslSocketPtr(QSslSocket *ptr = 0) + : QSharedPointer<QSslSocket>(ptr) + { } + + inline operator QSslSocket *() const { return data(); } +}; +#endif + +class tst_QSslSocket_onDemandCertificates_member : public QObject +{ + Q_OBJECT + + int proxyAuthCalled; + +public: + tst_QSslSocket_onDemandCertificates_member(); + virtual ~tst_QSslSocket_onDemandCertificates_member(); + +#ifndef QT_NO_OPENSSL + QSslSocketPtr newSocket(); +#endif + +public slots: + void initTestCase_data(); + void init(); + void cleanup(); + void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth); + +#ifndef QT_NO_OPENSSL +private slots: + void onDemandRootCertLoadingMemberMethods(); + +private: + QSslSocket *socket; +#endif // QT_NO_OPENSSL +}; + +tst_QSslSocket_onDemandCertificates_member::tst_QSslSocket_onDemandCertificates_member() +{ + Q_SET_DEFAULT_IAP +} + +tst_QSslSocket_onDemandCertificates_member::~tst_QSslSocket_onDemandCertificates_member() +{ +} + +enum ProxyTests { + NoProxy = 0x00, + Socks5Proxy = 0x01, + HttpProxy = 0x02, + TypeMask = 0x0f, + + NoAuth = 0x00, + AuthBasic = 0x10, + AuthNtlm = 0x20, + AuthMask = 0xf0 +}; + +void tst_QSslSocket_onDemandCertificates_member::initTestCase_data() +{ + QTest::addColumn<bool>("setProxy"); + QTest::addColumn<int>("proxyType"); + + QTest::newRow("WithoutProxy") << false << 0; + QTest::newRow("WithSocks5Proxy") << true << int(Socks5Proxy); + QTest::newRow("WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic); + + QTest::newRow("WithHttpProxy") << true << int(HttpProxy); + QTest::newRow("WithHttpProxyBasicAuth") << true << int(HttpProxy | AuthBasic); + // uncomment the line below when NTLM works +// QTest::newRow("WithHttpProxyNtlmAuth") << true << int(HttpProxy | AuthNtlm); +} + +void tst_QSslSocket_onDemandCertificates_member::init() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) { + QFETCH_GLOBAL(int, proxyType); + QString testServer = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); + QNetworkProxy proxy; + + switch (proxyType) { + case Socks5Proxy: + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, testServer, 1080); + break; + + case Socks5Proxy | AuthBasic: + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, testServer, 1081); + break; + + case HttpProxy | NoAuth: + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3128); + break; + + case HttpProxy | AuthBasic: + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3129); + break; + + case HttpProxy | AuthNtlm: + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3130); + break; + } + QNetworkProxy::setApplicationProxy(proxy); + } + + qt_qhostinfo_clear_cache(); +} + +void tst_QSslSocket_onDemandCertificates_member::cleanup() +{ + QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); +} + +#ifndef QT_NO_OPENSSL +QSslSocketPtr tst_QSslSocket_onDemandCertificates_member::newSocket() +{ + QSslSocket *socket = new QSslSocket; + + proxyAuthCalled = 0; + connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + Qt::DirectConnection); + + return QSslSocketPtr(socket); +} +#endif + +void tst_QSslSocket_onDemandCertificates_member::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth) +{ + ++proxyAuthCalled; + auth->setUser("qsockstest"); + auth->setPassword("password"); +} + +#ifndef QT_NO_OPENSSL + +void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMethods() +{ + QString host("qt.nokia.com"); + + // not using any root certs -> should not work + QSslSocketPtr socket2 = newSocket(); + this->socket = socket2; + socket2->setCaCertificates(QList<QSslCertificate>()); + socket2->connectToHostEncrypted(host, 443); + QVERIFY(!socket2->waitForEncrypted()); + + // default: using on demand loading -> should work + QSslSocketPtr socket = newSocket(); + this->socket = socket; + socket->connectToHostEncrypted(host, 443); + QVERIFY(socket->waitForEncrypted()); + + // not using any root certs again -> should not work + QSslSocketPtr socket3 = newSocket(); + this->socket = socket3; + socket3->setCaCertificates(QList<QSslCertificate>()); + socket3->connectToHostEncrypted(host, 443); + QVERIFY(!socket3->waitForEncrypted()); +} + +#endif // QT_NO_OPENSSL + +QTEST_MAIN(tst_QSslSocket_onDemandCertificates_member) +#include "tst_qsslsocket_onDemandCertificates_member.moc" diff --git a/tests/auto/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro b/tests/auto/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro new file mode 100644 index 0000000..13990cb --- /dev/null +++ b/tests/auto/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro @@ -0,0 +1,36 @@ +load(qttest_p4) + +SOURCES += tst_qsslsocket_onDemandCertificates_static.cpp +!wince*:win32:LIBS += -lws2_32 +QT += network +QT -= gui + +TARGET = tst_qsslsocket_onDemandCertificates_static + +win32 { + CONFIG(debug, debug|release) { + DESTDIR = debug +} else { + DESTDIR = release + } +} + +wince* { + DEFINES += SRCDIR=\\\"./\\\" + + certFiles.files = certs ssl.tar.gz + certFiles.path = . + DEPLOYMENT += certFiles +} else:symbian { + TARGET.EPOCHEAPSIZE="0x100 0x1000000" + TARGET.CAPABILITY=NetworkServices + + certFiles.files = certs ssl.tar.gz + certFiles.path = . + DEPLOYMENT += certFiles + INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE # Needed for e32svr.h in S^3 envs +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + +requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp b/tests/auto/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp new file mode 100644 index 0000000..8259977 --- /dev/null +++ b/tests/auto/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** 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 <QtNetwork> +#include <QtTest/QtTest> + +#include <QNetworkProxy> +#include <QAuthenticator> + +#include "private/qhostinfo_p.h" + +#include "../network-settings.h" + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "" +#endif + +#ifndef QT_NO_OPENSSL +class QSslSocketPtr: public QSharedPointer<QSslSocket> +{ +public: + inline QSslSocketPtr(QSslSocket *ptr = 0) + : QSharedPointer<QSslSocket>(ptr) + { } + + inline operator QSslSocket *() const { return data(); } +}; +#endif + +class tst_QSslSocket_onDemandCertificates_static : public QObject +{ + Q_OBJECT + + int proxyAuthCalled; + +public: + tst_QSslSocket_onDemandCertificates_static(); + virtual ~tst_QSslSocket_onDemandCertificates_static(); + +#ifndef QT_NO_OPENSSL + QSslSocketPtr newSocket(); +#endif + +public slots: + void initTestCase_data(); + void init(); + void cleanup(); + void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth); + +#ifndef QT_NO_OPENSSL +private slots: + void onDemandRootCertLoadingStaticMethods(); + +private: + QSslSocket *socket; +#endif // QT_NO_OPENSSL +}; + +tst_QSslSocket_onDemandCertificates_static::tst_QSslSocket_onDemandCertificates_static() +{ + Q_SET_DEFAULT_IAP +} + +tst_QSslSocket_onDemandCertificates_static::~tst_QSslSocket_onDemandCertificates_static() +{ +} + +enum ProxyTests { + NoProxy = 0x00, + Socks5Proxy = 0x01, + HttpProxy = 0x02, + TypeMask = 0x0f, + + NoAuth = 0x00, + AuthBasic = 0x10, + AuthNtlm = 0x20, + AuthMask = 0xf0 +}; + +void tst_QSslSocket_onDemandCertificates_static::initTestCase_data() +{ + QTest::addColumn<bool>("setProxy"); + QTest::addColumn<int>("proxyType"); + + QTest::newRow("WithoutProxy") << false << 0; + QTest::newRow("WithSocks5Proxy") << true << int(Socks5Proxy); + QTest::newRow("WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic); + + QTest::newRow("WithHttpProxy") << true << int(HttpProxy); + QTest::newRow("WithHttpProxyBasicAuth") << true << int(HttpProxy | AuthBasic); + // uncomment the line below when NTLM works +// QTest::newRow("WithHttpProxyNtlmAuth") << true << int(HttpProxy | AuthNtlm); +} + +void tst_QSslSocket_onDemandCertificates_static::init() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) { + QFETCH_GLOBAL(int, proxyType); + QString testServer = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); + QNetworkProxy proxy; + + switch (proxyType) { + case Socks5Proxy: + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, testServer, 1080); + break; + + case Socks5Proxy | AuthBasic: + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, testServer, 1081); + break; + + case HttpProxy | NoAuth: + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3128); + break; + + case HttpProxy | AuthBasic: + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3129); + break; + + case HttpProxy | AuthNtlm: + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, testServer, 3130); + break; + } + QNetworkProxy::setApplicationProxy(proxy); + } + + qt_qhostinfo_clear_cache(); +} + +void tst_QSslSocket_onDemandCertificates_static::cleanup() +{ + QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); +} + +#ifndef QT_NO_OPENSSL +QSslSocketPtr tst_QSslSocket_onDemandCertificates_static::newSocket() +{ + QSslSocket *socket = new QSslSocket; + + proxyAuthCalled = 0; + connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + Qt::DirectConnection); + + return QSslSocketPtr(socket); +} +#endif + +void tst_QSslSocket_onDemandCertificates_static::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth) +{ + ++proxyAuthCalled; + auth->setUser("qsockstest"); + auth->setPassword("password"); +} + +#ifndef QT_NO_OPENSSL + +void tst_QSslSocket_onDemandCertificates_static::onDemandRootCertLoadingStaticMethods() +{ + QString host("qt.nokia.com"); + + // not using any root certs -> should not work + QSslSocket::setDefaultCaCertificates(QList<QSslCertificate>()); + QSslSocketPtr socket = newSocket(); + this->socket = socket; + socket->connectToHostEncrypted(host, 443); + QVERIFY(!socket->waitForEncrypted()); + + // using system root certs -> should work + QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates()); + QSslSocketPtr socket2 = newSocket(); + this->socket = socket2; + socket2->connectToHostEncrypted(host, 443); + QVERIFY(socket2->waitForEncrypted()); + + // not using any root certs again -> should not work + QSslSocket::setDefaultCaCertificates(QList<QSslCertificate>()); + QSslSocketPtr socket3 = newSocket(); + this->socket = socket3; + socket3->connectToHostEncrypted(host, 443); + QVERIFY(!socket3->waitForEncrypted()); +} + +#endif // QT_NO_OPENSSL + +QTEST_MAIN(tst_QSslSocket_onDemandCertificates_static) +#include "tst_qsslsocket_onDemandCertificates_static.moc" diff --git a/tests/auto/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp b/tests/auto/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp index a6499ff..92e8608 100644 --- a/tests/auto/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp +++ b/tests/auto/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp @@ -201,6 +201,7 @@ void tst_QtConcurrentIterateKernel::noIterations() startThreadEngine(new IterateKernel<TestIterator, void>(0, 0)).startBlocking(); } +QMutex threadsMutex; QSet<QThread *> threads; class ThrottleFor : public IterateKernel<TestIterator, void> { @@ -219,8 +220,10 @@ public: QThread *thread = QThread::currentThread(); - if (begin > 140 && end < 160) + if (begin > 140 && end < 160) { + QMutexLocker locker(&threadsMutex); threads.insert(thread); + } if (100 >= begin && 100 < end) { throttling = true; diff --git a/tests/auto/qtextlayout/tst_qtextlayout.cpp b/tests/auto/qtextlayout/tst_qtextlayout.cpp index d1b615e..0a14e4a 100644 --- a/tests/auto/qtextlayout/tst_qtextlayout.cpp +++ b/tests/auto/qtextlayout/tst_qtextlayout.cpp @@ -124,8 +124,8 @@ private slots: void testLineBreakingAllSpaces(); void lineWidthFromBOM(); void textWidthVsWIdth(); - void textWithSurrogates_qtbug15679(); + void textWidthWithStackedTextEngine(); private: QFont testFont; @@ -1432,5 +1432,16 @@ void tst_QTextLayout::textWithSurrogates_qtbug15679() QCOMPARE(x[2] - x[0], x[5] - x[3]); } +void tst_QTextLayout::textWidthWithStackedTextEngine() +{ + QString text = QString::fromUtf8("คลิก ถัดไป เพื่อดำเนินการต่อ"); + QTextLayout layout(text); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + QFontMetricsF fm(layout.font()); + QCOMPARE(line.naturalTextWidth(), fm.width(text)); +} + QTEST_MAIN(tst_QTextLayout) #include "tst_qtextlayout.moc" diff --git a/tests/auto/qtimer/tst_qtimer.cpp b/tests/auto/qtimer/tst_qtimer.cpp index 6cff7c53..c2acc18 100644 --- a/tests/auto/qtimer/tst_qtimer.cpp +++ b/tests/auto/qtimer/tst_qtimer.cpp @@ -50,6 +50,8 @@ #include <unistd.h> #endif +#include "../../shared/util.h" + //TESTED_CLASS= //TESTED_FILES= @@ -272,9 +274,9 @@ void tst_QTimer::livelock() QFETCH(int, interval); LiveLockTester tester(interval); QTest::qWait(180); // we have to use wait here, since we're testing timers with a non-zero timeout - QCOMPARE(tester.timeoutsForFirst, 1); + QTRY_COMPARE(tester.timeoutsForFirst, 1); QCOMPARE(tester.timeoutsForExtra, 0); - QCOMPARE(tester.timeoutsForSecond, 1); + QTRY_COMPARE(tester.timeoutsForSecond, 1); #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (QSysInfo::WindowsVersion < QSysInfo::WV_XP) QEXPECT_FAIL("non-zero timer", "Multimedia timers are not available on Windows 2000", Continue); @@ -724,7 +726,7 @@ void tst_QTimer::QTBUG13633_dontBlockEvents() { DontBlockEvents t; QTest::qWait(60); - QVERIFY(t.total > 2); + QTRY_VERIFY(t.total > 2); } class SlotRepeater : public QObject { diff --git a/tests/auto/qvolatileimage/qvolatileimage.pro b/tests/auto/qvolatileimage/qvolatileimage.pro new file mode 100644 index 0000000..5a0a613 --- /dev/null +++ b/tests/auto/qvolatileimage/qvolatileimage.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +SOURCES += tst_qvolatileimage.cpp + +symbian { + TARGET.EPOCHEAPSIZE = 0x200000 0x800000 + LIBS += -lfbscli +} diff --git a/tests/auto/qvolatileimage/tst_qvolatileimage.cpp b/tests/auto/qvolatileimage/tst_qvolatileimage.cpp new file mode 100644 index 0000000..b91a150 --- /dev/null +++ b/tests/auto/qvolatileimage/tst_qvolatileimage.cpp @@ -0,0 +1,403 @@ +/**************************************************************************** +** +** 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 <QtTest/QtTest> +#include <QtGui/qpainter.h> +#include <QtGui/qpaintengine.h> +#include <QtGui/private/qvolatileimage_p.h> +#ifdef Q_OS_SYMBIAN +#include <fbs.h> +#endif + +class tst_QVolatileImage : public QObject +{ + Q_OBJECT + +public: + tst_QVolatileImage() { } + +private slots: + void create(); + void ensureFormat(); + void dataAccess(); + void sharing(); + void paint(); + void fill(); + void copy(); + void bitmap(); +}; + +void tst_QVolatileImage::create() +{ + QVolatileImage nullImg; + QVERIFY(nullImg.isNull()); + + QVolatileImage img(100, 200, QImage::Format_ARGB32); + QVERIFY(!img.isNull()); + QCOMPARE(img.width(), 100); + QCOMPARE(img.height(), 200); + QCOMPARE(img.format(), QImage::Format_ARGB32); + QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height()); + QCOMPARE(img.hasAlphaChannel(), true); + QCOMPARE(img.depth(), 32); + + QImage source(12, 23, QImage::Format_ARGB32_Premultiplied); + img = QVolatileImage(source); + QVERIFY(!img.isNull()); + QCOMPARE(img.width(), 12); + QCOMPARE(img.height(), 23); + QCOMPARE(img.format(), source.format()); + QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height()); + QVERIFY(img.imageRef() == source); + QVERIFY(img.toImage() == source); + QCOMPARE(img.hasAlphaChannel(), true); + QCOMPARE(img.hasAlphaChannel(), img.imageRef().hasAlphaChannel()); + QCOMPARE(img.hasAlphaChannel(), img.toImage().hasAlphaChannel()); + QCOMPARE(img.depth(), 32); + +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone); + QVolatileImage bmpimg(bmp); + QVERIFY(!bmpimg.isNull()); + QCOMPARE(bmpimg.width(), 100); + QCOMPARE(bmpimg.height(), 50); + // Verify that we only did handle duplication, not pixel data copying. + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + delete bmp; + // Check if content is still valid. + QImage copyimg = bmpimg.toImage(); + QCOMPARE(copyimg.format(), QImage::Format_ARGB32_Premultiplied); +#endif +} + +void tst_QVolatileImage::ensureFormat() +{ + QImage source(12, 23, QImage::Format_ARGB32_Premultiplied); + QVolatileImage img(source); + QVERIFY(!img.isNull()); + QVERIFY(img.imageRef() == source); + QVERIFY(img.toImage() == source); + + QVERIFY(img.ensureFormat(QImage::Format_ARGB32_Premultiplied)); // no-op + QVERIFY(img.imageRef() == source); + QVERIFY(img.toImage() == source); + QVERIFY(img.format() == QImage::Format_ARGB32_Premultiplied); + + QVERIFY(img.ensureFormat(QImage::Format_RGB32)); // new data under-the-hood + QVERIFY(img.imageRef() != source); + QVERIFY(img.toImage() != source); + QVERIFY(img.format() == QImage::Format_RGB32); + +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone); + QVolatileImage bmpimg(bmp); + QVERIFY(bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied)); // no-op + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + + // A different format should cause data copying. + QVERIFY(bmpimg.ensureFormat(QImage::Format_RGB32)); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + const uchar *prevBits = bmpimg.constBits(); + + QVERIFY(bmpimg.ensureFormat(QImage::Format_RGB16)); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + QVERIFY(bmpimg.constBits() != prevBits); + prevBits = bmpimg.constBits(); + + QVERIFY(bmpimg.ensureFormat(QImage::Format_MonoLSB)); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + QVERIFY(bmpimg.constBits() != prevBits); + + delete bmp; +#endif +} + +void tst_QVolatileImage::dataAccess() +{ + QImage source(12, 23, QImage::Format_ARGB32_Premultiplied); + QVolatileImage img(source); + QVERIFY(!img.isNull()); + img.beginDataAccess(); + QVERIFY(img.constBits()); + QVERIFY(img.imageRef().constBits()); + QVERIFY(img.bits()); + QVERIFY(img.imageRef().bits()); + img.endDataAccess(); + + img = QVolatileImage(12, 23, QImage::Format_ARGB32); + img.beginDataAccess(); + QVERIFY(img.constBits() && img.bits()); + img.endDataAccess(); +} + +void tst_QVolatileImage::sharing() +{ + QVolatileImage img1(100, 100, QImage::Format_ARGB32); + QVolatileImage img2 = img1; + img1.beginDataAccess(); + img2.beginDataAccess(); + QVERIFY(img1.constBits() == img2.constBits()); + img2.endDataAccess(); + img1.endDataAccess(); + img1.imageRef(); // non-const call, should detach + img1.beginDataAccess(); + img2.beginDataAccess(); + QVERIFY(img1.constBits() != img2.constBits()); + img2.endDataAccess(); + img1.endDataAccess(); + + // toImage() should return a copy of the internal QImage. + // imageRef() is a reference to the internal QImage. + QVERIFY(img1.imageRef().constBits() != img1.toImage().constBits()); + +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone); + QVolatileImage bmpimg(bmp); + QVolatileImage bmpimg2; + bmpimg2 = bmpimg; + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + QCOMPARE(bmpimg2.constBits(), (const uchar *) bmp->DataAddress()); + // Now force a detach, which should copy the pixel data under-the-hood. + bmpimg.imageRef(); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + QCOMPARE(bmpimg2.constBits(), (const uchar *) bmp->DataAddress()); + delete bmp; +#endif +} + +bool fuzzyCompareImages(const QImage &image1, const QImage &image2, int tolerance) +{ + if (image1.bytesPerLine() != image2.bytesPerLine() + || image1.width() != image2.width() + || image1.height() != image2.height()) { + return false; + } + for (int i = 0; i < image1.height(); i++) { + const uchar *line1 = image1.scanLine(i); + const uchar *line2 = image2.scanLine(i); + int bytes = image1.bytesPerLine(); + for (int j = 0; j < bytes; j++) { + int delta = line1[j] - line2[j]; + if (qAbs(delta) > tolerance) + return false; + } + } + return true; +} + +void tst_QVolatileImage::paint() +{ +#ifdef Q_OS_SYMBIAN + QVolatileImage img(100, 100, QImage::Format_ARGB32); + img.beginDataAccess(); + img.imageRef().fill(QColor(Qt::green).rgba()); + QPainter p(&img.imageRef()); + p.drawRect(10, 10, 50, 50); + p.end(); + img.endDataAccess(); + QImage imgA = img.toImage(); + + // The following assumes that on openvg the pixmapdata is backed by QVolatileImage) + // (and that openvg is in use) + // It should pass with any engine nonetheless. + // See if painting into the underlying QImage succeeds. + QPixmap pm(100, 100); + if (pm.paintEngine()->type() == QPaintEngine::Raster) { + pm.fill(Qt::green); + QPainter pmp(&pm); + pmp.drawRect(10, 10, 50, 50); + pmp.end(); + QImage imgB = pm.toImage(); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); + // Exercise the accelerated QVolatileImagePaintEngine::drawPixmap() a bit. + QPixmap targetPm(pm.size()); + targetPm.fill(Qt::black); + pmp.begin(&targetPm); + pmp.drawPixmap(QPointF(0, 0), pm); + pmp.end(); + imgB = targetPm.toImage(); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); + // Now the overload taking rects. + targetPm.fill(Qt::black); + pmp.begin(&targetPm); + QRectF rect(QPointF(0, 0), pm.size()); + pmp.drawPixmap(rect, pm, rect); + pmp.end(); + imgB = targetPm.toImage(); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); + } else { + QSKIP("Pixmaps not painted via raster, skipping paint test", SkipSingle); + } +#endif +} + +void tst_QVolatileImage::fill() +{ + QVolatileImage img(100, 100, QImage::Format_ARGB32_Premultiplied); + QColor col = QColor(10, 20, 30); + img.fill(col.rgba()); + QVERIFY(img.imageRef().pixel(1, 1) == col.rgba()); + QVERIFY(img.toImage().pixel(1, 1) == col.rgba()); + +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = static_cast<CFbsBitmap *>(img.duplicateNativeImage()); + QVERIFY(bmp); + TRgb pix; + bmp->GetPixel(pix, TPoint(1, 1)); + QCOMPARE(pix.Red(), col.red()); + QCOMPARE(pix.Green(), col.green()); + QCOMPARE(pix.Blue(), col.blue()); + delete bmp; +#endif +} + +void tst_QVolatileImage::copy() +{ + QVolatileImage img(100, 100, QImage::Format_RGB32); + img.beginDataAccess(); + img.imageRef().fill(QColor(Qt::green).rgba()); + QPainter p(&img.imageRef()); + p.drawRect(10, 10, 50, 50); + p.end(); + img.endDataAccess(); + + QVolatileImage img2(100, 100, QImage::Format_RGB32); + img2.copyFrom(&img, QRect()); + QImage imgA = img.toImage(); + QImage imgB = img2.toImage(); + QCOMPARE(imgA.size(), imgB.size()); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); + + img2 = QVolatileImage(20, 20, QImage::Format_RGB32); + img2.copyFrom(&img, QRect(5, 5, 20, 20)); + imgA = img.toImage().copy(5, 5, 20, 20); + imgB = img2.toImage(); + QCOMPARE(imgA.size(), imgB.size()); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); +} + +void tst_QVolatileImage::bitmap() +{ +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(100, 50), EColor64K) == KErrNone); + QVolatileImage bmpimg(bmp); + CFbsBitmap *dupbmp = static_cast<CFbsBitmap *>(bmpimg.duplicateNativeImage()); + QVERIFY(dupbmp); + QVERIFY(dupbmp != bmp); + QCOMPARE(dupbmp->DataAddress(), bmp->DataAddress()); + delete dupbmp; + delete bmp; + bmpimg.beginDataAccess(); + qMemSet(bmpimg.bits(), 0, bmpimg.byteCount()); + qMemSet(bmpimg.bits(), 1, bmpimg.bytesPerLine() * bmpimg.height()); + bmpimg.endDataAccess(); + + // Test bgr->rgb conversion in case of EColor16M. + bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(101, 89), EColor16M) == KErrNone); + bmp->BeginDataAccess(); + TUint32 *addr = bmp->DataAddress(); + uint rgb = QColor(10, 20, 30).rgb(); + qMemCopy(bmp->DataAddress(), &rgb, 3); + bmp->EndDataAccess(); + TRgb symrgb; + bmp->GetPixel(symrgb, TPoint(0, 0)); + QVERIFY(symrgb.Red() == 10 && symrgb.Green() == 20 && symrgb.Blue() == 30); + bmpimg = QVolatileImage(bmp); + QVERIFY(bmpimg.toImage().pixel(0, 0) == rgb); + // check if there really was a conversion + bmp->BeginDataAccess(); + bmpimg.beginDataAccess(); + qMemCopy(&rgb, bmpimg.constBits(), 3); + uint rgb2 = rgb; + qMemCopy(&rgb2, bmp->DataAddress(), 3); + QVERIFY(rgb != rgb2); + bmpimg.endDataAccess(true); + bmp->EndDataAccess(true); + delete bmp; + + bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(101, 89), EGray2) == KErrNone); + bmpimg = QVolatileImage(bmp); // inverts pixels, but should do it in place + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + QCOMPARE(bmpimg.format(), QImage::Format_MonoLSB); + bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + QCOMPARE(bmpimg.format(), QImage::Format_ARGB32_Premultiplied); + delete bmp; + + // The following two formats must be optimal always. + bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(101, 89), EColor16MAP) == KErrNone); + bmpimg = QVolatileImage(bmp); + QCOMPARE(bmpimg.format(), QImage::Format_ARGB32_Premultiplied); + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied); + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + delete bmp; + bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(101, 89), EColor16MU) == KErrNone); + bmpimg = QVolatileImage(bmp); + QCOMPARE(bmpimg.format(), QImage::Format_RGB32); + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + bmpimg.ensureFormat(QImage::Format_RGB32); + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + delete bmp; + +#else + QSKIP("CFbsBitmap is only available on Symbian, skipping bitmap test", SkipSingle); +#endif +} + +int main(int argc, char *argv[]) +{ + QApplication::setGraphicsSystem("openvg"); + QApplication app(argc, argv); + tst_QVolatileImage tc; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_qvolatileimage.moc" diff --git a/tests/benchmarks/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/benchmarks/network/ssl/qsslsocket/tst_qsslsocket.cpp index 6cb62d0..041b61a 100644 --- a/tests/benchmarks/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/benchmarks/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -46,7 +46,7 @@ #include <qsslsocket.h> -// #include "../../../../auto/network-settings.h" +#include "../../../../auto/network-settings.h" //TESTED_CLASS= //TESTED_FILES= @@ -65,6 +65,7 @@ public slots: void init(); void cleanup(); private slots: + void rootCertLoading(); void systemCaCertificates(); }; @@ -89,6 +90,16 @@ void tst_QSslSocket::cleanup() } //---------------------------------------------------------------------------------- + +void tst_QSslSocket::rootCertLoading() +{ + QBENCHMARK_ONCE { + QSslSocket socket; + socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket.waitForEncrypted(); + } +} + void tst_QSslSocket::systemCaCertificates() { // The results of this test change if the benchmarking system changes too much. diff --git a/tests/benchmarks/script/script.pro b/tests/benchmarks/script/script.pro index d4fc822..80278d0 100644 --- a/tests/benchmarks/script/script.pro +++ b/tests/benchmarks/script/script.pro @@ -13,6 +13,8 @@ SUBDIRS = \ TRUSTED_BENCHMARKS += \ qscriptclass \ qscriptvalue \ - qscriptengine + qscriptengine \ + qscriptobject \ + context2d include(../trusted-benchmarks.pri) diff --git a/tests/benchmarks/script/sunspider/tst_sunspider.cpp b/tests/benchmarks/script/sunspider/tst_sunspider.cpp index 0df19b6..9e2bb6f 100644 --- a/tests/benchmarks/script/sunspider/tst_sunspider.cpp +++ b/tests/benchmarks/script/sunspider/tst_sunspider.cpp @@ -110,7 +110,7 @@ void tst_SunSpider::benchmark_data() void tst_SunSpider::benchmark() { QFETCH(QString, testName); - QString testContents = readFile(testsDir.absoluteFilePath(testName + ".js")); + QString testContents = readFile(testsDir.filePath(testName + ".js")); QVERIFY(!testContents.isEmpty()); QScriptEngine engine; diff --git a/tests/benchmarks/script/v8/tst_v8.cpp b/tests/benchmarks/script/v8/tst_v8.cpp index 841e2f3..b9cb859 100644 --- a/tests/benchmarks/script/v8/tst_v8.cpp +++ b/tests/benchmarks/script/v8/tst_v8.cpp @@ -115,10 +115,10 @@ void tst_V8::benchmark() { QFETCH(QString, testName); - QString baseDotJsContents = readFile(testsDir.absoluteFilePath("base.js")); + QString baseDotJsContents = readFile(testsDir.filePath("base.js")); QVERIFY(!baseDotJsContents.isEmpty()); - QString testContents = readFile(testsDir.absoluteFilePath(testName + ".js")); + QString testContents = readFile(testsDir.filePath(testName + ".js")); QVERIFY(!testContents.isEmpty()); QScriptEngine engine; diff --git a/tools/assistant/tools/assistant/helpviewer_qwv.cpp b/tools/assistant/tools/assistant/helpviewer_qwv.cpp index 2d31ad7..efb9b59 100644 --- a/tools/assistant/tools/assistant/helpviewer_qwv.cpp +++ b/tools/assistant/tools/assistant/helpviewer_qwv.cpp @@ -379,7 +379,7 @@ bool HelpViewer::findText(const QString &text, FindFlags flags, bool incremental bool fromSearch) { TRACE_OBJ - Q_UNUSED((incremental && fromSearch)) + Q_UNUSED(incremental); Q_UNUSED(fromSearch); QWebPage::FindFlags options = QWebPage::FindWrapsAroundDocument; if (flags & FindBackward) options |= QWebPage::FindBackward; diff --git a/tools/designer/src/components/propertyeditor/propertyeditor.cpp b/tools/designer/src/components/propertyeditor/propertyeditor.cpp index 521b5cb..9f298d0 100644 --- a/tools/designer/src/components/propertyeditor/propertyeditor.cpp +++ b/tools/designer/src/components/propertyeditor/propertyeditor.cpp @@ -91,6 +91,7 @@ static const char *ViewKeyC = "View"; static const char *ColorKeyC = "Colored"; static const char *SortedKeyC = "Sorted"; static const char *ExpansionKeyC = "ExpandedItems"; +static const char *SplitterPositionKeyC = "SplitterPosition"; enum SettingsView { TreeView, ButtonView }; @@ -365,10 +366,12 @@ PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *pare m_sorting = settings->value(QLatin1String(SortedKeyC), false).toBool(); m_coloring = settings->value(QLatin1String(ColorKeyC), true).toBool(); const QVariantMap expansionState = settings->value(QLatin1String(ExpansionKeyC), QVariantMap()).toMap(); + const int splitterPosition = settings->value(QLatin1String(SplitterPositionKeyC), 150).toInt(); settings->endGroup(); // Apply settings m_sortingAction->setChecked(m_sorting); m_coloringAction->setChecked(m_coloring); + m_treeBrowser->setSplitterPosition(splitterPosition); #if QT_VERSION >= 0x040500 switch (view) { case TreeView: @@ -415,6 +418,7 @@ void PropertyEditor::saveSettings() const expansionState.insert(it.key(), QVariant(it.value())); } settings->setValue(QLatin1String(ExpansionKeyC), expansionState); + settings->setValue(QLatin1String(SplitterPositionKeyC), m_treeBrowser->splitterPosition()); settings->endGroup(); } diff --git a/tools/designer/src/lib/shared/grid.cpp b/tools/designer/src/lib/shared/grid.cpp index 6add8bd..ba991c7 100644 --- a/tools/designer/src/lib/shared/grid.cpp +++ b/tools/designer/src/lib/shared/grid.cpp @@ -89,12 +89,20 @@ Grid::Grid() : bool Grid::fromVariantMap(const QVariantMap& vm) { - *this = Grid(); - valueFromVariantMap(vm, QLatin1String(KEY_VISIBLE), m_visible); - valueFromVariantMap(vm, QLatin1String(KEY_SNAPX), m_snapX); - valueFromVariantMap(vm, QLatin1String(KEY_SNAPY), m_snapY); - valueFromVariantMap(vm, QLatin1String(KEY_DELTAX), m_deltaX); - return valueFromVariantMap(vm, QLatin1String(KEY_DELTAY), m_deltaY); + Grid grid; + bool anyData = valueFromVariantMap(vm, QLatin1String(KEY_VISIBLE), grid.m_visible); + anyData |= valueFromVariantMap(vm, QLatin1String(KEY_SNAPX), grid.m_snapX); + anyData |= valueFromVariantMap(vm, QLatin1String(KEY_SNAPY), grid.m_snapY); + anyData |= valueFromVariantMap(vm, QLatin1String(KEY_DELTAX), grid.m_deltaX); + anyData |= valueFromVariantMap(vm, QLatin1String(KEY_DELTAY), grid.m_deltaY); + if (!anyData) + return false; + if (grid.m_deltaX == 0 || grid.m_deltaY == 0) { + qWarning("Attempt to set invalid grid with a spacing of 0."); + return false; + } + *this = grid; + return true; } QVariantMap Grid::toVariantMap(bool forceKeys) const diff --git a/tools/qdoc3/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp index e27916b..c2cad89 100644 --- a/tools/qdoc3/cppcodemarker.cpp +++ b/tools/qdoc3/cppcodemarker.cpp @@ -49,6 +49,8 @@ #include "text.h" #include "tree.h" +#include <ctype.h> + QT_BEGIN_NAMESPACE /*! diff --git a/tools/qml/qml.pri b/tools/qml/qml.pri index 08cd506..cfc74af 100644 --- a/tools/qml/qml.pri +++ b/tools/qml/qml.pri @@ -19,18 +19,18 @@ SOURCES += $$PWD/qmlruntime.cpp \ RESOURCES = $$PWD/browser/browser.qrc \ $$PWD/startup/startup.qrc -symbian: { - contains(QT_CONFIG, s60): { +symbian { + contains(QT_CONFIG, s60) { LIBS += -lavkon -lcone } !contains(S60_VERSION, 3.1):!contains(S60_VERSION, 3.2) { LIBS += -lsensrvclient -lsensrvutil - } - !contains(S60_VERSION, 3.1):!contains(S60_VERSION, 3.2): { SOURCES += $$PWD/deviceorientation_symbian.cpp - FORMS = $$PWD/recopts.ui \ - $$PWD/proxysettings.ui + } else { + SOURCES += $$PWD/deviceorientation.cpp } + FORMS = $$PWD/recopts.ui \ + $$PWD/proxysettings.ui } else:maemo5 { QT += dbus HEADERS += $$PWD/texteditautoresizer_maemo5.h diff --git a/tools/shared/symbian/epocroot.cpp b/tools/shared/symbian/epocroot.cpp index e128cd2..5e6bc12 100644 --- a/tools/shared/symbian/epocroot.cpp +++ b/tools/shared/symbian/epocroot.cpp @@ -99,6 +99,11 @@ static void fixEpocRoot(QString &path) if (!path.size() || path[path.size()-1] != QLatin1Char('/')) { path += QLatin1Char('/'); } +#ifdef Q_OS_WIN32 + // Make sure we have drive letter in epocroot + if (path.startsWith(QLatin1Char('/'))) + path.prepend(QDir::currentPath().left(2)); +#endif } /** diff --git a/util/integrity/qt.bod b/util/integrity/qt.bod new file mode 100644 index 0000000..bdf50ce --- /dev/null +++ b/util/integrity/qt.bod @@ -0,0 +1,111 @@ +CommandOptions { + MOCCommandOptions { + MOCOutput { + { + name="-o" + } + delimiter="Space" + merge="Replace" + #flags={"OUTPUTNAME"} + } + MOCDefines { + { + name="-D" + } + delimiter="Touching" + merge="Concat" + } + MOCIncludes { + { + name="-I" + } + delimiter="Touching" + merge="Concat" + flags={"RELATIVEPATH"} + } + } + UICommandOptions { + UIOutput { + { + name="-o" + } + delimiter="Space" + merge="Replace" + flags={"OUTPUTNAME"} + } + } + RCCCommandOptions { + RCCOutput { + { + name="-o" + } + delimiter="Space" + merge="Replace" + flags={"OUTPUTNAME"} + } + RCCName { + { + name="-name" + } + delimiter="Space" + merge="Replace" + } + } +} + +Commands { + MOCPreprocessor { + name="MOCPreprocessor" + exec="${QT_BUILD_DIR}/bin/moc" + options={ "MOCCommandOptions", "SpecialOptions" } + } + UIPreprocessor { + name="UIPreprocessor" + exec="${QT_BUILD_DIR}/bin/uic" + options={ "UICommandOptions" } + } + RCCPreprocessor { + name="RCCPreprocessor" + exec="${QT_BUILD_DIR}/bin/rcc" + options={ "RCCCommandOptions" } + } +} + +FileTypes { + MocCPP { + name="MOC/Qt Header" + outputExtension="time" + outputType="SourceFile" + command="MOCPreprocessor" + commandLine="${QT_BUILD_DIR}/bin/moc -nn $OPTIONS $INPUTFILE" + progress="MOCing" + extraFiles="$(OUTPUTDIR)/moc_$(OUTPUTNAMEBASE).cpp" + #postExecSafe={"${GHS_TOOLS_DIR}/filechanged work/$(OUTPUTNAME)"} + color="#0020a0" + grepable=true + } + RCC { + name="Qt Resource" + outputExtension="time" + #extensions={"qrc"} + outputType="SourceFile" + command="RCCPreprocessor" + commandLine="${QT_BUILD_DIR}/bin/rcc $OPTIONS $INPUTFILE" + extraFiles="$(OUTPUTDIR)/qrc_$(OUTPUTNAMEBASE).cpp" + progress="Generating Resource source from" + action="Generate Resource source for" + grepable=true + } + UI { + name="Qt Dialog" + outputExtension="time" + #extensions={"ui"} + outputType="SourceFile" + command="UIPreprocessor" + commandLine="${QT_BUILD_DIR}/bin/uic $OPTIONS $INPUTFILE" + extraFiles="$(OUTPUTDIR)/ui_$(OUTPUTNAMEBASE).cpp" + progress="Generating Dialog source from" + action="Generate Dialog source for" + grepable=true + } +} |