aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc116
-rw-r--r--examples/quick/demos/photosurface/doc/src/photosurface.qdoc130
-rw-r--r--examples/quick/quick.pro4
-rw-r--r--examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro12
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp4
-rw-r--r--src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h6
-rw-r--r--src/plugins/accessible/quick/qaccessiblequickitem.cpp22
-rw-r--r--src/plugins/accessible/quick/qaccessiblequickitem.h5
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp1
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp21
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp8
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp10
-rw-r--r--src/qml/compiler/qv4codegen.cpp10
-rw-r--r--src/qml/compiler/qv4codegen_p.h2
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp13
-rw-r--r--src/qml/compiler/qv4isel_util_p.h6
-rw-r--r--src/qml/compiler/qv4jsir.cpp177
-rw-r--r--src/qml/compiler/qv4jsir_p.h307
-rw-r--r--src/qml/compiler/qv4ssa.cpp730
-rw-r--r--src/qml/compiler/qv4ssa_p.h16
-rw-r--r--src/qml/debugger/debugger.pri2
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp1
-rw-r--r--src/qml/debugger/qv4profilerservice.cpp310
-rw-r--r--src/qml/doc/src/cppintegration/exposecppattributes.qdoc5
-rw-r--r--src/qml/doc/src/javascript/expressions.qdoc32
-rw-r--r--src/qml/doc/src/javascript/topic.qdoc13
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/scope.qdoc8
-rw-r--r--src/qml/doc/src/qmllanguageref/qmlreference.qdoc14
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/basics.qdoc10
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc52
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc91
-rw-r--r--src/qml/jit/qv4assembler_p.h2
-rw-r--r--src/qml/jit/qv4binop.cpp36
-rw-r--r--src/qml/jit/qv4isel_masm.cpp28
-rw-r--r--src/qml/jit/qv4isel_masm_p.h2
-rw-r--r--src/qml/jit/qv4regalloc.cpp115
-rw-r--r--src/qml/jsapi/qjsvalueiterator.cpp9
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h2
-rw-r--r--src/qml/jsruntime/qv4global_p.h4
-rw-r--r--src/qml/qml/qqmlengine.cpp2
-rw-r--r--src/qml/qml/qqmlplatform.cpp22
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp19
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp59
-rw-r--r--src/qml/types/qqmldelegatemodel_p.h3
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h2
-rw-r--r--src/qml/util/qqmladaptormodel.cpp12
-rw-r--r--src/qmldevtools/qmldevtools.pro6
-rw-r--r--src/quick/doc/src/concepts/convenience/topic.qdoc13
-rw-r--r--src/quick/doc/src/tutorial.qdoc4
-rw-r--r--src/quick/items/qquickgridview.cpp4
-rw-r--r--src/quick/items/qquickimage.cpp2
-rw-r--r--src/quick/items/qquickitem.cpp8
-rw-r--r--src/quick/items/qquickitemview.cpp5
-rw-r--r--src/quick/items/qquicklistview.cpp4
-rw-r--r--src/quick/items/qquickrendercontrol_p.h2
-rw-r--r--src/quick/items/qquicktext.cpp2
-rw-r--r--src/quick/items/qquicktextcontrol.cpp7
-rw-r--r--src/quick/items/qquicktextedit.cpp20
-rw-r--r--src/quick/items/qquicktextedit_p.h4
-rw-r--r--src/quick/items/qquicktextnode.cpp11
-rw-r--r--src/quick/items/qquickwindow.cpp9
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode.cpp20
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp2
-rw-r--r--src/quick/util/qquickanimatorcontroller.cpp42
-rw-r--r--src/quick/util/qquickanimatorcontroller_p.h4
-rw-r--r--src/quick/util/qquickanimatorjob.cpp26
-rw-r--r--src/quick/util/qquickanimatorjob_p.h4
-rw-r--r--src/quick/util/qquickpath.cpp4
-rw-r--r--src/quick/util/qquickpropertychanges.cpp2
-rw-r--r--src/quick/util/qquickstyledtext.cpp2
-rw-r--r--src/src.pro4
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp65
-rw-r--r--tests/auto/qml/qjsvalueiterator/tst_qjsvalueiterator.cpp27
-rw-r--r--tests/auto/qmltest/animators/tst_mixed.qml179
-rw-r--r--tests/auto/qmltest/animators/tst_multiwindow.qml (renamed from src/qml/debugger/qv4profilerservice_p.h)140
-rw-r--r--tests/auto/qmltest/animators/tst_on.qml4
-rw-r--r--tests/auto/qmltest/textedit/tst_textedit.qml47
-rw-r--r--tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp2
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp6
-rw-r--r--tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp6
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp4
-rw-r--r--tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp40
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp7
-rw-r--r--tests/auto/quick/qquicktextedit/data/qtbug-38947.qml16
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp28
-rw-r--r--tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp6
-rw-r--r--tests/testapplications/text/text.qml6
-rw-r--r--tests/testapplications/text/textedit.qml6
-rw-r--r--tests/testapplications/text/textinput.qml4
-rw-r--r--tools/qml/main.cpp4
-rw-r--r--tools/qmlplugindump/qmlplugindump.pro4
94 files changed, 2025 insertions, 1248 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 88d13d1eef..d170e6d272 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -2,4 +2,4 @@ load(qt_build_config)
CONFIG += qt_example_installs
CONFIG += warning_clean
-MODULE_VERSION = 5.3.0
+MODULE_VERSION = 5.3.1
diff --git a/examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc b/examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc
index ff8061e2ea..e72d048567 100644
--- a/examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc
+++ b/examples/quick/demos/calqlatr/doc/src/calqlatr.qdoc
@@ -29,14 +29,122 @@
\title Qt Quick Demo - Calqlatr
\ingroup qtquickdemos
\example demos/calqlatr
- \brief A simple QML calculator app, designed for portrait devices.
+ \brief A QML app designed for portrait devices that uses custom components,
+ animated with AnimationController, and JavaScript for the application logic.
\image qtquick-demo-calqlatr.png
- \e{Calqlatr} demonstrates various QML and \l{Qt Quick} features such as
- displaying custom components. The logic is implemented in JavaScript and the
- appearance implemented in QML.
+ \e{Calqlatr} demonstrates various QML and \l{Qt Quick} features, such as
+ displaying custom components and using animation to move the components
+ around in the application view. The application logic is implemented in
+ JavaScript and the appearance is implemented in QML.
\include examples-run.qdocinc
+ \section1 Displaying Custom Components
+
+ In the Calqlatr application, we use the following custom types that are
+ each defined in a separate .qml file:
+
+ \list
+ \li Button.qml
+ \li Display.qml
+ \li NumberPad.qml
+ \li StyleLabel.qml
+ \endlist
+
+ To use the custom types, we add an import statement to the main QML file,
+ calqlatr.qml that imports the folder called \c content where the types are
+ located:
+
+ \code
+ import "content"
+ \endcode
+
+ We can then display custom components by adding the component types to
+ any QML file. For example, we use the NumberPad type in calqlatr.qml to
+ create the number pad of the calculator. We place the type inside an
+ \l{Item} QML type, which is the base type for all visual items in Qt Quick:
+
+ \quotefromfile demos/calqlatr/calqlatr.qml
+ \skipto Item
+ \printuntil }
+ \printuntil }
+
+ Further, we use the Button type in the NumberPad type to create the
+ calculator buttons. Button.qml specifies the basic properties for a
+ button that we can modify for each button instance in NumberPad.qml. For the
+ digit and separator buttons, we additionally specify the text property using
+ the property alias \c text that we define in Button.qml.
+
+ For the operator buttons, we also specify another color (green) using the
+ property alias \c color and set the operator property to \c true. We use
+ the operator property in functions that perform the calculations.
+
+ We place the buttons inside a \l{Grid} QML type to position them in a grid:
+
+ \quotefromfile demos/calqlatr/content/NumberPad.qml
+ \skipto Grid
+ \printuntil /^\}/
+
+ \section1 Animating Components
+
+ We use the Display type to display calculations. In Display.qml, we use
+ images to make the display component look like a slip of paper that contains
+ a grip. Users can drag the grip to move the display from left to right.
+
+ When users release the grip, the AnimationController QML type that we define
+ in the calqlatr.qml file finishes running the controlled animation in either
+ a forwards or a backwards direction. To run the animation, we call either
+ completeToEnd() or completeToBeginning(), depending on the direction. We do
+ this in the MouseArea's \c onReleased signal handler, where \c controller
+ is the id of our AnimationController:
+
+ \quotefromfile demos/calqlatr/calqlatr.qml
+ \skipto onPressed
+ \printuntil }
+
+ Unlike other QML animation types, AnimationController is not driven by
+ internal timers but by explicitly setting its progress property to a
+ value between \c 0.0 and \c 1.0.
+
+ Inside the AnimationController, we run two NumberAnimation instances in
+ parallel to move the number pad and the display components simultaneously to
+ the opposite sides of the view. In addition, we run a SequentialAnimation
+ instance to scale the number pad during the transition, giving the animation
+ some depth.
+
+ \quotefromfile demos/calqlatr/calqlatr.qml
+ \skipto AnimationController
+ \printuntil 1; easing.type
+ \printuntil }
+ \printuntil }
+ \printuntil }
+
+ We use the easing curve of the type \c Easing.InOutQuad to accelerate the
+ motion until halfway and then decelerate it.
+
+ \section1 Performing Calculations
+
+ The calculator.js file contains definitions for the functions to execute
+ when users press the digit and operator buttons. To use the functions, we
+ import calculator.js in the calqlatr.qml file as \c CalcEngine:
+
+ \code
+ import "content/calculator.js" as CalcEngine
+ \endcode
+
+ We can then declare the functions to execute depending on whether the
+ operator property for a button is set to \c true in NumberPad.qml:
+
+ \quotefromfile demos/calqlatr/calqlatr.qml
+ \skipto operatorPressed
+ \printuntil digitPressed
+
+ When users press a digit or operator, the text from the digit appears on the
+ display. When they press the equals operator (=), the appropriate
+ calculation is performed, and the results appear on the display.
+
+ \section1 List of Files
+
\sa {QML Applications}
*/
diff --git a/examples/quick/demos/photosurface/doc/src/photosurface.qdoc b/examples/quick/demos/photosurface/doc/src/photosurface.qdoc
index d56b34365d..b66143368e 100644
--- a/examples/quick/demos/photosurface/doc/src/photosurface.qdoc
+++ b/examples/quick/demos/photosurface/doc/src/photosurface.qdoc
@@ -29,13 +29,135 @@
\title Qt Quick Demo - Photo Surface
\ingroup qtquickdemos
\example demos/photosurface
- \brief A touch-based app for shuffling photos around a virtual surface.
+ \brief A QML app for touch devices that uses a Repeater with a
+ FolderListModel to access content in a folder, and a PinchArea that contains
+ a MouseArea to handle pinch gestures on the fetched content.
\image qtquick-demo-photosurface-small.png
- \e{Photo Surface} demonstrates how to handle dragging, rotation and pinch
- zooming within the same item using a \l PinchArea containing a \l MouseArea.
+ \e{Photo Surface} demonstrates how to use a \l{Repeater} with a
+ FolderListModel and a FileDialog to access images from a folder selected
+ by a user and how to handle dragging, rotation and pinch zooming within the
+ same item using a \l PinchArea that contains a \l MouseArea.
+
+ All the app code is contained in one QML file, photosurface.qml. Inline
+ JavaScript code is used to place, rotate, and scale images on the photo
+ surface.
\include examples-run.qdocinc
- \sa {QML Applications}
+ \section1 Creating the Main Window
+
+ To create the main window for the Photo Surface app, we use the \l{Window}
+ QML type as the root item. It automatically sets up the window for use with
+ \l{Qt Quick} graphical types:
+
+ \quotefromfile demos/photosurface/photosurface.qml
+ \skipto Window {
+ \printuntil defaultSize
+
+ To use the \l{Window} type, we must import it:
+
+ \code
+ import QtQuick.Window 2.1
+ \endcode
+
+ \section1 Accessing Folder Contents
+
+ We use a \l{Repeater} QML type together with the FolderListModel to display
+ GIF, JPG, and PNG images located in a folder:
+
+ \quotefromfile demos/photosurface/photosurface.qml
+ \skipto Repeater
+ \printuntil }
+
+ To use the FolderListModel type, we must import it:
+
+ \code
+ import Qt.labs.folderlistmodel 1.0
+ \endcode
+
+ We use a FileDialog to enable users to select the folder that contains
+ the images:
+
+ \quotefromfile demos/photosurface/photosurface.qml
+ \skipto FileDialog
+ \printuntil }
+
+ To use the FileDialog type, we must import \l{Qt Quick Dialogs}:
+
+ \code
+ import QtQuick.Dialogs 1.0
+ \endcode
+
+ We use the \c {fileDialog.open()} function to open the file dialog when the
+ app starts:
+
+ \code
+ Component.onCompleted: fileDialog.open()
+ \endcode
+
+ Users can also click the file dialog icon to open the file dialog. We use
+ an \l{Image} QML type to display the icon. Inside the \l{Image} type, we
+ use a MouseArea with the \c onClicked signal handler to call the
+ \c {fileDialog.open()} function:
+
+ \quotefromfile demos/photosurface/photosurface.qml
+ \skipuntil Image {
+ \skipto Image {
+ \printuntil }
+ \printuntil }
+
+ \section1 Displaying Images on the Photo Surface
+
+ We use a \l{Rectangle} as a delegate for a \l{Repeater} to provide a frame
+ for each image that the FolderListModel finds in the selected folder. We use
+ JavaScript \c Math() methods to place the frames randomly on the photo
+ surface and to rotate them at random angles, as well as to scale the images:
+
+ \quotefromfile demos/photosurface/photosurface.qml
+ \skipto Rectangle
+ \printuntil }
+
+ \section1 Handling Pinch Gestures
+
+ We use a PinchArea that contains a MouseArea in the photo frames to handle
+ dragging, rotation and pinch zooming of the frame:
+
+ \quotefromfile demos/photosurface/photosurface.qml
+ \skipto PinchArea
+ \printuntil onPinchFinished
+
+ We use the \c pinch group property to control how the photo frames react to
+ pinch gestures. The \c pinch.target sets \c photoFrame as the item to
+ manipulate. The rotation properties specify that the frames can be rotated
+ at all angles and the scale properties specify that they can be scaled
+ between \c 0.1 and \c 10.
+
+ In the MouseArea's \c onPressed signal handler, we raise the selected photo
+ frame to the top by increasing the value of its \c z property. The root item
+ stores the z value of the top-most frame. The border color of the photo
+ frame is controlled in the \c onEntered and \c onExited signal handlers to
+ highlight the selected image.
+
+ \quotefromfile demos/photosurface/photosurface.qml
+ \skipto MouseArea
+ \printuntil onExited
+
+ To enable you to test the example on the desktop, we use the MouseArea's
+ \c onWheel signal handler to simulate pinch gestures by using a mouse:
+
+ \quotefromfile demos/photosurface/photosurface.qml
+ \skipto onWheel
+ \printuntil photoFrame.y
+ \printuntil }
+ \printuntil }
+ \printuntil }
+
+ The \c onWheel signal handler is called in response to mouse wheel gestures.
+ Use the vertical wheel to zoom and Ctrl and the vertical wheel to rotate
+ frames. If the mouse has a horizontal wheel, use it to rotate frames.
+
+ \section1 List of Files
+
+ \sa {QML Applications}
*/
diff --git a/examples/quick/quick.pro b/examples/quick/quick.pro
index f39931bd94..421f95a162 100644
--- a/examples/quick/quick.pro
+++ b/examples/quick/quick.pro
@@ -26,8 +26,8 @@ SUBDIRS = quick-accessibility \
# Widget dependent examples
qtHaveModule(widgets) {
- SUBDIRS += embeddedinwidgets \
- quickwidgets
+ SUBDIRS += embeddedinwidgets
+ qtHaveModule(quickwidgets): SUBDIRS += quickwidgets
}
EXAMPLE_FILES = \
diff --git a/examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro b/examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro
index 0886f37b1f..e88e8f670c 100644
--- a/examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro
+++ b/examples/quick/tutorials/gettingStartedQml/filedialog/filedialog.pro
@@ -20,14 +20,6 @@ SOURCES += \
OTHER_FILES += qmldir
-copyfile = $$PWD/qmldir
-copydest = $$DESTDIR
-
-# On Windows, use backslashes as directory separators
-win32: {
- copyfile ~= s,/,\\,g
- copydest ~= s,/,\\,g
-}
-
# Copy the qmldir file to the same folder as the plugin binary
-QMAKE_POST_LINK += $$QMAKE_COPY $$quote($$copyfile) $$quote($$copydest) $$escape_expand(\\n\\t)
+QMAKE_POST_LINK += $$QMAKE_COPY $$shell_quote($$shell_path($$PWD/qmldir)) \
+ $$shell_quote($$shell_path($$DESTDIR)) $$escape_expand(\\n\\t)
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
index 81063e2b11..ae7b0859ed 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.cpp
@@ -49,7 +49,7 @@ const char* const ARMv7DOpcode::s_optionName[8] = {
};
const char* const ARMv7DOpcode::s_shiftNames[4] = {
- "lsl", "lsr", "asl", "ror"
+ "lsl", "lsr", "asr", "ror"
};
const char* const ARMv7DOpcode::s_specialRegisterNames[3] = { "sp", "lr", "pc" };
@@ -944,7 +944,7 @@ const char* ARMv7DOpcodeDataProcessingShiftedReg::format()
appendSeparator();
appendRegisterName(rm());
appendSeparator();
- appendUnsignedImmediate(immediate5());
+ appendImmShift(type(), immediate5());
return m_formatBuffer;
}
diff --git a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
index ca5f955ba1..5bcb6b15b9 100644
--- a/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
+++ b/src/3rdparty/masm/disassembler/ARMv7/ARMv7DOpcode.h
@@ -69,6 +69,7 @@ protected:
static const char* conditionName(unsigned condition) { return s_conditionNames[condition & 0xf]; }
static const char* shiftName(unsigned shiftValue) { return s_shiftNames[shiftValue & 0x3]; }
+ static bool isRightShift(unsigned shiftValue) { return shiftValue == 1 || shiftValue == 2; }
bool inITBlock() { return m_ITConditionIndex < m_ITBlocksize; }
bool startingITBlock() { return m_ITConditionIndex == m_ITBlocksize + 1; }
@@ -514,7 +515,10 @@ protected:
const char* opName() { return shiftName(op()); }
unsigned op() { return (m_opcode >> 12) & 0x3; }
- unsigned immediate5() { return (m_opcode >> 6) & 0x1f; }
+ unsigned immediate5() {
+ unsigned imm = (m_opcode >> 6) & 0x1f;
+ return isRightShift(op()) && imm == 0 ? 32 : imm;
+ }
};
class ARMv7DOpcodeMiscAddSubSP : public ARMv7D16BitOpcode {
diff --git a/src/plugins/accessible/quick/qaccessiblequickitem.cpp b/src/plugins/accessible/quick/qaccessiblequickitem.cpp
index 4b68574149..164144c052 100644
--- a/src/plugins/accessible/quick/qaccessiblequickitem.cpp
+++ b/src/plugins/accessible/quick/qaccessiblequickitem.cpp
@@ -193,6 +193,28 @@ bool QAccessibleQuickItem::isAccessible() const
return item()->d_func()->isAccessible;
}
+QStringList QAccessibleQuickItem::actionNames() const
+{
+ QStringList actions = QQmlAccessible::actionNames();
+ if (state().focusable)
+ actions.append(QAccessibleActionInterface::setFocusAction());
+ return actions;
+}
+
+void QAccessibleQuickItem::doAction(const QString &actionName)
+{
+ if (actionName == QAccessibleActionInterface::setFocusAction()) {
+ item()->forceActiveFocus();
+ } else {
+ QQmlAccessible::doAction(actionName);
+ }
+}
+
+QStringList QAccessibleQuickItem::keyBindingsForAction(const QString &actionName) const
+{
+ return QQmlAccessible::keyBindingsForAction(actionName);
+}
+
QString QAccessibleQuickItem::text(QAccessible::Text textType) const
{
// handles generic behavior not specific to an item
diff --git a/src/plugins/accessible/quick/qaccessiblequickitem.h b/src/plugins/accessible/quick/qaccessiblequickitem.h
index d9eb652030..b486720c68 100644
--- a/src/plugins/accessible/quick/qaccessiblequickitem.h
+++ b/src/plugins/accessible/quick/qaccessiblequickitem.h
@@ -74,6 +74,11 @@ public:
bool isAccessible() const;
+ // Action Interface
+ QStringList actionNames() const;
+ void doAction(const QString &actionName);
+ QStringList keyBindingsForAction(const QString &actionName) const;
+
// Value Interface
QVariant currentValue() const;
void setCurrentValue(const QVariant &value);
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index 0928c0efc1..991b1fad5c 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -380,6 +380,7 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
{
// this ensures that the value is updated now that the animation is running
if (oldState == Stopped) {
+ m_currentLoop = 0;
if (isTopLevel) {
// currentTime needs to be updated if pauseTimer is active
RETURN_IF_DELETED(QQmlAnimationTimer::ensureTimerUpdate());
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
index 80538432ef..818988b310 100644
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -61,13 +61,8 @@ int QParallelAnimationGroupJob::duration() const
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
int currentDuration = animation->totalDuration();
- //this takes care of the case where a parallel animation group has controlled and uncontrolled
- //animations, and the uncontrolled stop before the controlled
- if (currentDuration == -1)
- currentDuration = uncontrolledAnimationFinishTime(animation);
if (currentDuration == -1)
return -1; // Undetermined length
-
ret = qMax(ret, currentDuration);
}
@@ -82,6 +77,16 @@ void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
if (m_currentLoop > m_previousLoop) {
// simulate completion of the loop
int dura = duration();
+ if (dura < 0) {
+ // For an uncontrolled parallel group, we need to simulate the end of running animations.
+ // As uncontrolled animation finish time is already reset for this next loop, we pick the
+ // longest of the known stop times.
+ for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
+ int currentDuration = animation->totalDuration();
+ if (currentDuration >= 0)
+ dura = qMax(dura, currentDuration);
+ }
+ }
if (dura > 0) {
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
if (!animation->isStopped())
@@ -137,8 +142,10 @@ void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newSta
break;
case Running:
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) {
- if (oldState == Stopped)
+ if (oldState == Stopped) {
animation->stop();
+ m_previousLoop = m_direction == Forward ? 0 : m_loopCount - 1;
+ }
resetUncontrolledAnimationFinishTime(animation);
animation->setDirection(m_direction);
if (shouldAnimationStart(animation, oldState == Stopped))
@@ -223,7 +230,7 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
maxDuration = qMax(maxDuration, job->totalDuration());
}
- setUncontrolledAnimationFinishTime(this, qMax(maxDuration, currentTime()));
+ setUncontrolledAnimationFinishTime(this, qMax(maxDuration + m_currentLoopStartTime, currentTime()));
if (!running
&& ((m_direction == Forward && m_currentLoop == m_loopCount -1)
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
index 135760b3cb..cfc53d552a 100644
--- a/src/qml/animations/qsequentialanimationgroupjob.cpp
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -75,8 +75,12 @@ bool QSequentialAnimationGroupJob::atEnd() const
int QSequentialAnimationGroupJob::animationActualTotalDuration(QAbstractAnimationJob *anim) const
{
int ret = anim->totalDuration();
- if (ret == -1)
- ret = uncontrolledAnimationFinishTime(anim); //we can try the actual duration there
+ if (ret == -1) {
+ int done = uncontrolledAnimationFinishTime(anim);
+ // If the animation has reached the end, use the uncontrolledFinished value.
+ if (done >= 0 && (anim->loopCount() - 1 == anim->currentLoop() || anim->state() == Stopped))
+ return done;
+ }
return ret;
}
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 6e60bce0e5..1110b3f29d 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -2694,11 +2694,11 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR:
// It would seem unlikely that function with some many basic blocks (after optimization)
// consists merely of a qsTr call or a constant value return ;-)
- if (function->basicBlocks.count() > 10)
+ if (function->basicBlockCount() > 10)
return false;
- foreach (QV4::IR::BasicBlock *bb, function->basicBlocks) {
- foreach (QV4::IR::Stmt *s, bb->statements) {
+ foreach (QV4::IR::BasicBlock *bb, function->basicBlocks()) {
+ foreach (QV4::IR::Stmt *s, bb->statements()) {
s->accept(this);
if (!_canSimplify)
return false;
@@ -2867,8 +2867,8 @@ void QQmlIRFunctionCleanser::clean()
module->functions = newFunctions;
foreach (QV4::IR::Function *function, module->functions) {
- foreach (QV4::IR::BasicBlock *block, function->basicBlocks) {
- foreach (QV4::IR::Stmt *s, block->statements) {
+ foreach (QV4::IR::BasicBlock *block, function->basicBlocks()) {
+ foreach (QV4::IR::Stmt *s, block->statements()) {
s->accept(this);
}
}
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 166fb518ff..fdc4d5c9f2 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2045,7 +2045,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
sourceElements(body);
- _function->insertBasicBlock(_exitBlock);
+ _function->addBasicBlock(_exitBlock);
_block->JUMP(_exitBlock);
@@ -2599,7 +2599,7 @@ bool Codegen::visit(TryStatement *ast)
if (ast->catchExpression) {
pushExceptionHandler(catchExceptionHandler);
- _function->insertBasicBlock(catchBody);
+ _function->addBasicBlock(catchBody);
_block = catchBody;
++_function->insideWithOrCatch;
@@ -2617,7 +2617,7 @@ bool Codegen::visit(TryStatement *ast)
_block->JUMP(finallyBody ? finallyBody : end);
popExceptionHandler();
- _function->insertBasicBlock(catchExceptionHandler);
+ _function->addBasicBlock(catchExceptionHandler);
catchExceptionHandler->EXP(catchExceptionHandler->CALL(catchExceptionHandler->NAME(IR::Name::builtin_pop_scope, 0, 0), 0));
if (finallyBody || surroundingExceptionHandler)
catchExceptionHandler->JUMP(finallyBody ? finallyBody : surroundingExceptionHandler);
@@ -2628,7 +2628,7 @@ bool Codegen::visit(TryStatement *ast)
_scopeAndFinally = tcf.parent;
if (finallyBody) {
- _function->insertBasicBlock(finallyBody);
+ _function->addBasicBlock(finallyBody);
_block = finallyBody;
int hasException = _block->newTemp();
@@ -2643,7 +2643,7 @@ bool Codegen::visit(TryStatement *ast)
_block->JUMP(end);
}
- _function->insertBasicBlock(end);
+ _function->addBasicBlock(end);
_block = end;
return false;
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index fafcfdd04e..0d52fb83fa 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -286,7 +286,7 @@ protected:
}
void pushExceptionHandler(QV4::IR::BasicBlock *handler)
{
- handler->isExceptionHandler = true;
+ handler->setExceptionHandler(true);
_exceptionHandlers.push(handler);
}
void popExceptionHandler()
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index df0625b48e..9288008632 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -257,7 +257,7 @@ protected:
if (IR::Jump *jump = s->asJump()) {
IR::MoveMapping moves;
- foreach (IR::Stmt *succStmt, jump->target->statements) {
+ foreach (IR::Stmt *succStmt, jump->target->statements()) {
if (IR::Phi *phi = succStmt->asPhi()) {
forceActivation(*phi->targetTemp);
for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) {
@@ -360,7 +360,7 @@ void InstructionSelection::run(int functionIndex)
qgetenv("QV4_NO_INTERPRETER_STACK_SLOT_ALLOCATION").isEmpty();
if (doStackSlotAllocation) {
- AllocateStackSlots(opt.lifeRanges()).forFunction(_function);
+ AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function);
} else {
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
@@ -386,10 +386,11 @@ void InstructionSelection::run(int functionIndex)
addInstruction(push);
currentLine = 0;
- for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
+ QVector<IR::BasicBlock *> basicBlocks = _function->basicBlocks();
+ for (int i = 0, ei = basicBlocks.size(); i != ei; ++i) {
blockNeedsDebugInstruction = irModule->debugMode;
- _block = _function->basicBlocks[i];
- _nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
+ _block = basicBlocks[i];
+ _nextBlock = (i < ei - 1) ? basicBlocks[i + 1] : 0;
_addrs.insert(_block, _codeNext - _codeStart);
if (_block->catchBlock != exceptionHandler) {
@@ -404,7 +405,7 @@ void InstructionSelection::run(int functionIndex)
exceptionHandler = _block->catchBlock;
}
- foreach (IR::Stmt *s, _block->statements) {
+ foreach (IR::Stmt *s, _block->statements()) {
_currentStatement = s;
if (s->location.isValid()) {
diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h
index be1714f2de..09b98a18d1 100644
--- a/src/qml/compiler/qv4isel_util_p.h
+++ b/src/qml/compiler/qv4isel_util_p.h
@@ -136,9 +136,11 @@ public:
{
_stackSlotForTemp.reserve(function->tempCount);
- foreach (IR::BasicBlock *bb, function->basicBlocks) {
+ foreach (IR::BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
_currentBasicBlock = bb;
- foreach (IR::Stmt *s, bb->statements)
+ foreach (IR::Stmt *s, bb->statements())
process(s);
}
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index a5ccaeb3fc..5d30d6e3b9 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -166,11 +166,14 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor
void operator()(IR::Function *function)
{
subexpressions.clear();
+ subexpressions.reserve(function->basicBlockCount() * 8);
- foreach (BasicBlock *block, function->basicBlocks) {
+ foreach (BasicBlock *block, function->basicBlocks()) {
+ if (block->isRemoved())
+ continue;
clone.setBasicBlock(block);
- foreach (Stmt *s, block->statements) {
+ foreach (Stmt *s, block->statements()) {
s->accept(this);
}
}
@@ -592,7 +595,7 @@ void Move::dump(QTextStream &out, Mode mode)
void Jump::dump(QTextStream &out, Mode mode)
{
Q_UNUSED(mode);
- out << "goto " << 'L' << target->index << ';';
+ out << "goto " << 'L' << target->index() << ';';
}
void CJump::dump(QTextStream &out, Mode mode)
@@ -601,9 +604,9 @@ void CJump::dump(QTextStream &out, Mode mode)
out << "if (";
cond->dump(out);
if (mode == HIR)
- out << ") goto " << 'L' << iftrue->index << "; else goto " << 'L' << iffalse->index << ';';
+ out << ") goto " << 'L' << iftrue->index() << "; else goto " << 'L' << iffalse->index() << ';';
else
- out << ") goto " << 'L' << iftrue->index << ";";
+ out << ") goto " << 'L' << iftrue->index() << ";";
}
void Ret::dump(QTextStream &out, Mode)
@@ -660,15 +663,37 @@ void Module::setFileName(const QString &name)
}
}
+Function::Function(Module *module, Function *outer, const QString &name)
+ : module(module)
+ , pool(&module->pool)
+ , tempCount(0)
+ , maxNumberOfArguments(0)
+ , outer(outer)
+ , insideWithOrCatch(0)
+ , hasDirectEval(false)
+ , usesArgumentsObject(false)
+ , isStrict(false)
+ , isNamedExpression(false)
+ , hasTry(false)
+ , hasWith(false)
+ , unused(0)
+ , line(-1)
+ , column(-1)
+ , _allBasicBlocks(0)
+{
+ this->name = newString(name);
+ _basicBlocks.reserve(8);
+}
+
Function::~Function()
{
- // destroy the Stmt::Data blocks manually, because memory pool cleanup won't
- // call the Stmt destructors.
- foreach (IR::BasicBlock *b, basicBlocks)
- foreach (IR::Stmt *s, b->statements)
- s->destroyData();
+ if (_allBasicBlocks) {
+ qDeleteAll(*_allBasicBlocks);
+ delete _allBasicBlocks;
+ } else {
+ qDeleteAll(_basicBlocks);
+ }
- qDeleteAll(basicBlocks);
pool = 0;
module = 0;
}
@@ -682,7 +707,31 @@ const QString *Function::newString(const QString &text)
BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode)
{
BasicBlock *block = new BasicBlock(this, containingLoop, catchBlock);
- return mode == InsertBlock ? insertBasicBlock(block) : block;
+ return mode == InsertBlock ? addBasicBlock(block) : block;
+}
+
+BasicBlock *Function::addBasicBlock(BasicBlock *block)
+{
+ Q_ASSERT(block->index() < 0);
+ block->setIndex(_basicBlocks.size());
+ _basicBlocks.append(block);
+ return block;
+}
+
+void Function::removeBasicBlock(BasicBlock *block)
+{
+ block->markAsRemoved();
+ block->in.clear();
+ block->out.clear();
+}
+
+int Function::liveBasicBlocksCount() const
+{
+ int count = 0;
+ foreach (BasicBlock *bb, basicBlocks())
+ if (!bb->isRemoved())
+ ++count;
+ return count;
}
void Function::dump(QTextStream &out, Stmt::Mode mode)
@@ -695,7 +744,7 @@ void Function::dump(QTextStream &out, Stmt::Mode mode)
out << "\treceive " << *formal << ';' << endl;
foreach (const QString *local, locals)
out << "\tlocal " << *local << ';' << endl;
- foreach (BasicBlock *bb, basicBlocks)
+ foreach (BasicBlock *bb, basicBlocks())
bb->dump(out, mode);
out << '}' << endl;
}
@@ -714,13 +763,35 @@ int Function::indexOfArgument(const QStringRef &string) const
}
return -1;
}
+
+void Function::setScheduledBlocks(const QVector<BasicBlock *> &scheduled)
+{
+ Q_ASSERT(!_allBasicBlocks);
+ _allBasicBlocks = new QVector<BasicBlock *>(basicBlocks());
+ _basicBlocks = scheduled;
+}
+
+void Function::renumberBasicBlocks()
+{
+ for (int i = 0, ei = basicBlockCount(); i != ei; ++i)
+ basicBlock(i)->changeIndex(i);
+}
+
+BasicBlock::~BasicBlock()
+{
+ foreach (Stmt *s, _statements)
+ s->destroyData();
+}
+
unsigned BasicBlock::newTemp()
{
+ Q_ASSERT(!isRemoved());
return function->tempCount++;
}
Temp *BasicBlock::TEMP(unsigned index)
{
+ Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
e->init(Temp::VirtualRegister, index, 0);
return e;
@@ -728,6 +799,7 @@ Temp *BasicBlock::TEMP(unsigned index)
Temp *BasicBlock::ARG(unsigned index, unsigned scope)
{
+ Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
e->init(scope ? Temp::ScopedFormal : Temp::Formal, index, scope);
return e;
@@ -735,6 +807,7 @@ Temp *BasicBlock::ARG(unsigned index, unsigned scope)
Temp *BasicBlock::LOCAL(unsigned index, unsigned scope)
{
+ Q_ASSERT(!isRemoved());
Temp *e = function->New<Temp>();
e->init(scope ? Temp::ScopedLocal : Temp::Local, index, scope);
return e;
@@ -742,6 +815,7 @@ Temp *BasicBlock::LOCAL(unsigned index, unsigned scope)
Expr *BasicBlock::CONST(Type type, double value)
{
+ Q_ASSERT(!isRemoved());
Const *e = function->New<Const>();
if (type == NumberType) {
int ival = (int)value;
@@ -762,6 +836,7 @@ Expr *BasicBlock::CONST(Type type, double value)
Expr *BasicBlock::STRING(const QString *value)
{
+ Q_ASSERT(!isRemoved());
String *e = function->New<String>();
e->init(value);
return e;
@@ -769,6 +844,7 @@ Expr *BasicBlock::STRING(const QString *value)
Expr *BasicBlock::REGEXP(const QString *value, int flags)
{
+ Q_ASSERT(!isRemoved());
RegExp *e = function->New<RegExp>();
e->init(value, flags);
return e;
@@ -776,6 +852,7 @@ Expr *BasicBlock::REGEXP(const QString *value, int flags)
Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
{
+ Q_ASSERT(!isRemoved());
Name *e = function->New<Name>();
e->init(function->newString(id), line, column);
return e;
@@ -783,6 +860,7 @@ Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column)
{
+ Q_ASSERT(!isRemoved());
Name *e = function->New<Name>();
e->initGlobal(function->newString(id), line, column);
return e;
@@ -791,6 +869,7 @@ Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column)
Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
{
+ Q_ASSERT(!isRemoved());
Name *e = function->New<Name>();
e->init(builtin, line, column);
return e;
@@ -798,6 +877,7 @@ Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
Closure *BasicBlock::CLOSURE(int functionInModule)
{
+ Q_ASSERT(!isRemoved());
Closure *clos = function->New<Closure>();
clos->init(functionInModule, function->module->functions.at(functionInModule)->name);
return clos;
@@ -805,6 +885,7 @@ Closure *BasicBlock::CLOSURE(int functionInModule)
Expr *BasicBlock::CONVERT(Expr *expr, Type type)
{
+ Q_ASSERT(!isRemoved());
Convert *e = function->New<Convert>();
e->init(expr, type);
return e;
@@ -812,6 +893,7 @@ Expr *BasicBlock::CONVERT(Expr *expr, Type type)
Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
{
+ Q_ASSERT(!isRemoved());
Unop *e = function->New<Unop>();
e->init(op, expr);
return e;
@@ -819,6 +901,7 @@ Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
{
+ Q_ASSERT(!isRemoved());
Binop *e = function->New<Binop>();
e->init(op, left, right);
return e;
@@ -826,6 +909,7 @@ Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
Expr *BasicBlock::CALL(Expr *base, ExprList *args)
{
+ Q_ASSERT(!isRemoved());
Call *e = function->New<Call>();
e->init(base, args);
int argc = 0;
@@ -837,6 +921,7 @@ Expr *BasicBlock::CALL(Expr *base, ExprList *args)
Expr *BasicBlock::NEW(Expr *base, ExprList *args)
{
+ Q_ASSERT(!isRemoved());
New *e = function->New<New>();
e->init(base, args);
return e;
@@ -844,6 +929,7 @@ Expr *BasicBlock::NEW(Expr *base, ExprList *args)
Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
{
+ Q_ASSERT(!isRemoved());
Subscript *e = function->New<Subscript>();
e->init(base, index);
return e;
@@ -851,6 +937,7 @@ Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue)
{
+ Q_ASSERT(!isRemoved());
Member*e = function->New<Member>();
e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue);
return e;
@@ -858,6 +945,7 @@ Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *prop
Stmt *BasicBlock::EXP(Expr *expr)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -869,6 +957,7 @@ Stmt *BasicBlock::EXP(Expr *expr)
Stmt *BasicBlock::MOVE(Expr *target, Expr *source)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -880,6 +969,7 @@ Stmt *BasicBlock::MOVE(Expr *target, Expr *source)
Stmt *BasicBlock::JUMP(BasicBlock *target)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -898,6 +988,7 @@ Stmt *BasicBlock::JUMP(BasicBlock *target)
Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -927,6 +1018,7 @@ Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
Stmt *BasicBlock::RET(Temp *expr)
{
+ Q_ASSERT(!isRemoved());
if (isTerminated())
return 0;
@@ -938,11 +1030,11 @@ Stmt *BasicBlock::RET(Temp *expr)
void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
{
- out << 'L' << index << ':';
+ out << 'L' << index() << ':';
if (catchBlock)
- out << " (catchBlock L" << catchBlock->index << ")";
+ out << " (catchBlock L" << catchBlock->index() << ")";
out << endl;
- foreach (Stmt *s, statements) {
+ foreach (Stmt *s, statements()) {
out << '\t';
s->dump(out, mode);
@@ -953,11 +1045,62 @@ void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
}
}
+void BasicBlock::setStatements(const QVector<Stmt *> &newStatements)
+{
+ Q_ASSERT(!isRemoved());
+ Q_ASSERT(newStatements.size() >= _statements.size());
+ _statements = newStatements;
+}
+
void BasicBlock::appendStatement(Stmt *statement)
{
+ Q_ASSERT(!isRemoved());
if (nextLocation.isValid())
statement->location = nextLocation;
- statements.append(statement);
+ _statements.append(statement);
+}
+
+void BasicBlock::prependStatement(Stmt *stmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.prepend(stmt);
+}
+
+void BasicBlock::insertStatementBefore(Stmt *before, Stmt *newStmt)
+{
+ int idx = _statements.indexOf(before);
+ Q_ASSERT(idx >= 0);
+ _statements.insert(idx, newStmt);
+}
+
+void BasicBlock::insertStatementBefore(int index, Stmt *newStmt)
+{
+ Q_ASSERT(index >= 0);
+ _statements.insert(index, newStmt);
+}
+
+void BasicBlock::insertStatementBeforeTerminator(Stmt *stmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.insert(_statements.size() - 1, stmt);
+}
+
+void BasicBlock::replaceStatement(int index, Stmt *newStmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements[index] = newStmt;
+}
+
+void BasicBlock::removeStatement(Stmt *stmt)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.remove(_statements.indexOf(stmt));
+}
+
+void BasicBlock::removeStatement(int idx)
+{
+ Q_ASSERT(!isRemoved());
+ _statements.remove(idx);
}
CloneExpr::CloneExpr(BasicBlock *block)
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 71120e6054..9eff90dd30 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -643,6 +643,8 @@ struct Stmt {
virtual Phi *asPhi() { return 0; }
virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
+private: // For memory management in BasicBlock
+ friend struct BasicBlock;
void destroyData() {
delete d;
d = 0;
@@ -762,122 +764,75 @@ struct Q_QML_PRIVATE_EXPORT Module {
void setFileName(const QString &name);
};
-// Map from meta property index (existence implies dependency) to notify signal index
-typedef QHash<int, int> PropertyDependencyMap;
-
-struct Function {
- Module *module;
- QQmlJS::MemoryPool *pool;
- const QString *name;
- QVector<BasicBlock *> basicBlocks;
- int tempCount;
- int maxNumberOfArguments;
- QSet<QString> strings;
- QList<const QString *> formals;
- QList<const QString *> locals;
- QVector<Function *> nestedFunctions;
- Function *outer;
-
- int insideWithOrCatch;
-
- uint hasDirectEval: 1;
- uint usesArgumentsObject : 1;
- uint usesThis : 1;
- uint isStrict: 1;
- uint isNamedExpression : 1;
- uint hasTry: 1;
- uint hasWith: 1;
- uint unused : 25;
-
- // Location of declaration in source code (-1 if not specified)
- int line;
- int column;
-
- // Qml extension:
- QSet<int> idObjectDependencies;
- PropertyDependencyMap contextObjectPropertyDependencies;
- PropertyDependencyMap scopeObjectPropertyDependencies;
-
- template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
-
- Function(Module *module, Function *outer, const QString &name)
- : module(module)
- , pool(&module->pool)
- , tempCount(0)
- , maxNumberOfArguments(0)
- , outer(outer)
- , insideWithOrCatch(0)
- , hasDirectEval(false)
- , usesArgumentsObject(false)
- , isStrict(false)
- , isNamedExpression(false)
- , hasTry(false)
- , hasWith(false)
- , unused(0)
- , line(-1)
- , column(-1)
- { this->name = newString(name); }
-
- ~Function();
-
- enum BasicBlockInsertMode {
- InsertBlock,
- DontInsertBlock
- };
-
- BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
- const QString *newString(const QString &text);
-
- void RECEIVE(const QString &name) { formals.append(newString(name)); }
- void LOCAL(const QString &name) { locals.append(newString(name)); }
-
- inline BasicBlock *insertBasicBlock(BasicBlock *block) { basicBlocks.append(block); return block; }
-
- void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
-
- void removeSharedExpressions();
-
- int indexOfArgument(const QStringRef &string) const;
-
- bool variablesCanEscape() const
- { return hasDirectEval || !nestedFunctions.isEmpty() || module->debugMode; }
-};
-
struct BasicBlock {
+private:
+ Q_DISABLE_COPY(BasicBlock)
+
+public:
Function *function;
BasicBlock *catchBlock;
- QVector<Stmt *> statements;
QVector<BasicBlock *> in;
QVector<BasicBlock *> out;
- QBitArray liveIn;
- QBitArray liveOut;
- int index;
- bool isExceptionHandler;
QQmlJS::AST::SourceLocation nextLocation;
BasicBlock(Function *function, BasicBlock *containingLoop, BasicBlock *catcher)
: function(function)
, catchBlock(catcher)
- , index(-1)
- , isExceptionHandler(false)
, _containingGroup(containingLoop)
+ , _index(-1)
+ , _isExceptionHandler(false)
, _groupStart(false)
- {}
- ~BasicBlock() {}
+ , _isRemoved(false)
+ {
+ in.reserve(2);
+ out.reserve(2);
+ }
+ ~BasicBlock();
+
+ const QVector<Stmt *> &statements() const
+ {
+ Q_ASSERT(!isRemoved());
+ return _statements;
+ }
+
+ int statementCount() const
+ {
+ Q_ASSERT(!isRemoved());
+ return _statements.size();
+ }
+
+ void setStatements(const QVector<Stmt *> &newStatements);
+
+ template <typename Instr> inline Instr i(Instr i)
+ {
+ Q_ASSERT(!isRemoved());
+ appendStatement(i);
+ return i;
+ }
- template <typename Instr> inline Instr i(Instr i) { statements.append(i); return i; }
+ void appendStatement(Stmt *statement);
+ void prependStatement(Stmt *stmt);
+ void insertStatementBefore(Stmt *before, Stmt *newStmt);
+ void insertStatementBefore(int index, Stmt *newStmt);
+ void insertStatementBeforeTerminator(Stmt *stmt);
+ void replaceStatement(int index, Stmt *newStmt);
+ void removeStatement(Stmt *stmt);
+ void removeStatement(int idx);
inline bool isEmpty() const {
- return statements.isEmpty();
+ Q_ASSERT(!isRemoved());
+ return _statements.isEmpty();
}
inline Stmt *terminator() const {
- if (! statements.isEmpty() && statements.at(statements.size() - 1)->asTerminator() != 0)
- return statements.at(statements.size() - 1);
+ Q_ASSERT(!isRemoved());
+ if (! _statements.isEmpty() && _statements.last()->asTerminator() != 0)
+ return _statements.last();
return 0;
}
inline bool isTerminated() const {
+ Q_ASSERT(!isRemoved());
if (terminator() != 0)
return true;
return false;
@@ -918,20 +873,172 @@ struct BasicBlock {
void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
- void appendStatement(Stmt *statement);
-
BasicBlock *containingGroup() const
- { return _containingGroup; }
+ {
+ Q_ASSERT(!isRemoved());
+ return _containingGroup;
+ }
+
+ void setContainingGroup(BasicBlock *loopHeader)
+ {
+ Q_ASSERT(!isRemoved());
+ _containingGroup = loopHeader;
+ }
bool isGroupStart() const
- { return _groupStart; }
+ {
+ Q_ASSERT(!isRemoved());
+ return _groupStart;
+ }
void markAsGroupStart()
- { _groupStart = true; }
+ {
+ Q_ASSERT(!isRemoved());
+ _groupStart = true;
+ }
+
+ // Returns the index of the basic-block.
+ // See Function for the full description.
+ int index() const
+ {
+ Q_ASSERT(!isRemoved());
+ return _index;
+ }
+
+ bool isExceptionHandler() const
+ { return _isExceptionHandler; }
+
+ void setExceptionHandler(bool onoff)
+ { _isExceptionHandler = onoff; }
+
+ bool isRemoved() const
+ { return _isRemoved; }
+
+private: // For Function's eyes only.
+ friend struct Function;
+ void setIndex(int index)
+ {
+ Q_ASSERT(_index < 0);
+ changeIndex(index);
+ }
+
+ void changeIndex(int index)
+ {
+ Q_ASSERT(index >= 0);
+ _index = index;
+ }
+
+ void markAsRemoved()
+ {
+ _isRemoved = true;
+ _index = -1;
+ }
private:
+ QVector<Stmt *> _statements;
BasicBlock *_containingGroup;
- bool _groupStart;
+ int _index;
+ unsigned _isExceptionHandler : 1;
+ unsigned _groupStart : 1;
+ unsigned _isRemoved : 1;
+};
+
+// Map from meta property index (existence implies dependency) to notify signal index
+typedef QHash<int, int> PropertyDependencyMap;
+
+// The Function owns (manages), among things, a list of basic-blocks. All the blocks have an index,
+// which corresponds to the index in the entry/index in the vector in which they are stored. This
+// means that algorithms/classes can also store any information about a basic block in an array,
+// where the index corresponds to the index of the basic block, which can then be used to query
+// the function for a pointer to a basic block. This also means that basic-blocks cannot be removed
+// or renumbered.
+//
+// Note that currently there is one exception: after optimization and block scheduling, the
+// method setScheduledBlocks can be called once, to register a newly ordered list. For debugging
+// purposes, these blocks are not immediately renumbered, so renumberBasicBlocks should be called
+// immediately after changing the order. That will restore the property of having a corresponding
+// block-index and block-position-in-basicBlocks-vector.
+//
+// In order for optimization/transformation passes to skip uninteresting basic blocks that will be
+// removed, the block can be marked as such. After doing so, any access will result in a failing
+// assertion.
+struct Function {
+ Module *module;
+ QQmlJS::MemoryPool *pool;
+ const QString *name;
+ int tempCount;
+ int maxNumberOfArguments;
+ QSet<QString> strings;
+ QList<const QString *> formals;
+ QList<const QString *> locals;
+ QVector<Function *> nestedFunctions;
+ Function *outer;
+
+ int insideWithOrCatch;
+
+ uint hasDirectEval: 1;
+ uint usesArgumentsObject : 1;
+ uint usesThis : 1;
+ uint isStrict: 1;
+ uint isNamedExpression : 1;
+ uint hasTry: 1;
+ uint hasWith: 1;
+ uint unused : 25;
+
+ // Location of declaration in source code (-1 if not specified)
+ int line;
+ int column;
+
+ // Qml extension:
+ QSet<int> idObjectDependencies;
+ PropertyDependencyMap contextObjectPropertyDependencies;
+ PropertyDependencyMap scopeObjectPropertyDependencies;
+
+ template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
+
+ Function(Module *module, Function *outer, const QString &name);
+ ~Function();
+
+ enum BasicBlockInsertMode {
+ InsertBlock,
+ DontInsertBlock
+ };
+
+ BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock);
+ const QString *newString(const QString &text);
+
+ void RECEIVE(const QString &name) { formals.append(newString(name)); }
+ void LOCAL(const QString &name) { locals.append(newString(name)); }
+
+ BasicBlock *addBasicBlock(BasicBlock *block);
+ void removeBasicBlock(BasicBlock *block);
+
+ const QVector<BasicBlock *> &basicBlocks() const
+ { return _basicBlocks; }
+
+ BasicBlock *basicBlock(int idx) const
+ { return _basicBlocks.at(idx); }
+
+ int basicBlockCount() const
+ { return _basicBlocks.size(); }
+
+ int liveBasicBlocksCount() const;
+
+ void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
+
+ void removeSharedExpressions();
+
+ int indexOfArgument(const QStringRef &string) const;
+
+ bool variablesCanEscape() const
+ { return hasDirectEval || !nestedFunctions.isEmpty() || module->debugMode; }
+
+ void setScheduledBlocks(const QVector<BasicBlock *> &scheduled);
+ void renumberBasicBlocks();
+
+private:
+ QVector<BasicBlock *> _basicBlocks;
+ QVector<BasicBlock *> *_allBasicBlocks;
};
class CloneExpr: protected IR::ExprVisitor
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 6112c490f7..97114b9507 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -79,11 +79,11 @@ void showMeTheCode(IR::Function *function)
QVector<Stmt *> code;
QHash<Stmt *, BasicBlock *> leader;
- foreach (BasicBlock *block, function->basicBlocks) {
- if (block->statements.isEmpty())
+ foreach (BasicBlock *block, function->basicBlocks()) {
+ if (block->isRemoved() || block->isEmpty())
continue;
- leader.insert(block->statements.first(), block);
- foreach (Stmt *s, block->statements) {
+ leader.insert(block->statements().first(), block);
+ foreach (Stmt *s, block->statements()) {
code.append(s);
}
}
@@ -115,11 +115,11 @@ void showMeTheCode(IR::Function *function)
qout << endl;
QByteArray str;
str.append('L');
- str.append(QByteArray::number(bb->index));
+ str.append(QByteArray::number(bb->index()));
str.append(':');
if (bb->catchBlock) {
str.append(" (exception handler L");
- str.append(QByteArray::number(bb->catchBlock->index));
+ str.append(QByteArray::number(bb->catchBlock->index()));
str.append(')');
}
for (int i = 66 - str.length(); i; --i)
@@ -127,11 +127,11 @@ void showMeTheCode(IR::Function *function)
qout << str;
qout << "// predecessor blocks:";
foreach (BasicBlock *in, bb->in)
- qout << " L" << in->index;
+ qout << " L" << in->index();
if (bb->in.isEmpty())
qout << "(none)";
if (BasicBlock *container = bb->containingGroup())
- qout << "; container block: L" << container->index;
+ qout << "; container block: L" << container->index();
if (bb->isGroupStart())
qout << "; group start";
qout << endl;
@@ -158,7 +158,7 @@ void showMeTheCode(IR::Function *function)
qout << endl;
if (n && s->asCJump()) {
- qout << " else goto L" << s->asCJump()->iffalse->index << ";" << endl;
+ qout << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl;
}
}
@@ -172,24 +172,21 @@ class ProcessedBlocks
QBitArray processed;
public:
- ProcessedBlocks(const QVector<BasicBlock *> allBlocks)
+ ProcessedBlocks(IR::Function *function)
{
- int maxBB = 0;
- foreach (BasicBlock *bb, allBlocks)
- maxBB = qMax(maxBB, bb->index);
- processed = QBitArray(maxBB + 1, false);
+ processed = QBitArray(function->basicBlockCount(), false);
}
bool alreadyProcessed(BasicBlock *bb) const
{
Q_ASSERT(bb);
- return processed.at(bb->index);
+ return processed.at(bb->index());
}
void markAsProcessed(BasicBlock *bb)
{
- processed.setBit(bb->index);
+ processed.setBit(bb->index());
}
};
@@ -223,7 +220,7 @@ class BasicBlockSet
Numbers *blockNumbers;
Flags *blockFlags;
- QVector<BasicBlock *> allBlocks;
+ IR::Function *function;
enum { MaxVectorCapacity = 8 };
// Q_DISABLE_COPY(BasicBlockSet); disabled because MSVC wants assignment operator for std::vector
@@ -246,18 +243,13 @@ public:
else
flagIt = set.blockFlags->size();
} else {
- if (set.blockNumbers) {
+ if (set.blockNumbers)
numberIt = set.blockNumbers->begin();
- } else {
- flagIt = 0;
- size_t eIt = set.blockFlags->size();
- while (flagIt != eIt) {
- if (set.blockFlags->operator[](flagIt))
- break;
- else
- ++flagIt;
- }
- }
+ else
+ flagIt = std::distance(set.blockFlags->begin(),
+ std::find(set.blockFlags->begin(),
+ set.blockFlags->end(),
+ true));
}
}
@@ -265,10 +257,10 @@ public:
BasicBlock *operator*() const
{
if (set.blockNumbers) {
- return set.allBlocks.at(*numberIt);
+ return set.function->basicBlock(*numberIt);
} else {
Q_ASSERT(flagIt <= INT_MAX);
- return set.allBlocks.at(static_cast<int>(flagIt));
+ return set.function->basicBlock(static_cast<int>(flagIt));
}
}
@@ -287,16 +279,13 @@ public:
const_iterator &operator++()
{
- if (set.blockNumbers) {
+ if (set.blockNumbers)
++numberIt;
- } else {
- size_t eIt = set.blockFlags->size();
- while (flagIt != eIt) {
- ++flagIt;
- if (flagIt == eIt || set.blockFlags->operator[](flagIt))
- break;
- }
- }
+ else
+ flagIt = std::distance(set.blockFlags->begin(),
+ std::find(set.blockFlags->begin() + flagIt + 1,
+ set.blockFlags->end(),
+ true));
return *this;
}
@@ -305,22 +294,23 @@ public:
friend class const_iterator;
public:
- BasicBlockSet(): blockNumbers(0), blockFlags(0) {}
+ BasicBlockSet(): blockNumbers(0), blockFlags(0), function(0) {}
#ifdef Q_COMPILER_RVALUE_REFS
BasicBlockSet(BasicBlockSet &&other): blockNumbers(0), blockFlags(0)
{
std::swap(blockNumbers, other.blockNumbers);
std::swap(blockFlags, other.blockFlags);
- std::swap(allBlocks, other.allBlocks);
+ std::swap(function, other.function);
}
#endif // Q_COMPILER_RVALUE_REFS
~BasicBlockSet() { delete blockNumbers; delete blockFlags; }
- void init(const QVector<BasicBlock *> &nodes)
+ void init(IR::Function *f)
{
- Q_ASSERT(allBlocks.isEmpty());
- allBlocks = nodes;
+ Q_ASSERT(!function);
+ Q_ASSERT(f);
+ function = f;
blockNumbers = new Numbers;
blockNumbers->reserve(MaxVectorCapacity);
}
@@ -328,25 +318,25 @@ public:
void insert(BasicBlock *bb)
{
if (blockFlags) {
- (*blockFlags)[bb->index] = true;
+ (*blockFlags)[bb->index()] = true;
return;
}
for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end();
i != ei; ++i)
- if (*i == bb->index)
+ if (*i == bb->index())
return;
if (blockNumbers->size() == MaxVectorCapacity) {
- blockFlags = new Flags(allBlocks.size(), false);
+ blockFlags = new Flags(function->basicBlockCount(), false);
for (std::vector<int>::const_iterator i = blockNumbers->begin(), ei = blockNumbers->end();
i != ei; ++i)
blockFlags->operator[](*i) = true;
delete blockNumbers;
blockNumbers = 0;
- blockFlags->operator[](bb->index) = true;
+ blockFlags->operator[](bb->index()) = true;
} else {
- blockNumbers->push_back(bb->index);
+ blockNumbers->push_back(bb->index());
}
}
@@ -368,7 +358,7 @@ class DominatorTree {
typedef int BasicBlockIndex;
enum { InvalidBasicBlockIndex = -1 };
- QVector<BasicBlock *> nodes;
+ IR::Function *function;
int N;
std::vector<int> dfnum; // BasicBlock index -> dfnum
std::vector<int> vertex;
@@ -407,12 +397,12 @@ class DominatorTree {
vertex[N] = n;
parent[n] = todo.parent;
++N;
- const QVector<BasicBlock *> &out = nodes[n]->out;
+ const QVector<BasicBlock *> &out = function->basicBlock(n)->out;
for (int i = out.size() - 1; i > 0; --i)
- worklist.push_back(DFSTodo(out[i]->index, n));
+ worklist.push_back(DFSTodo(out[i]->index(), n));
if (out.size() > 0) {
- todo.node = out.first()->index;
+ todo.node = out.first()->index();
todo.parent = n;
continue;
}
@@ -460,21 +450,23 @@ class DominatorTree {
}
void calculateIDoms() {
- Q_ASSERT(nodes.first()->in.isEmpty());
-
- vertex = std::vector<int>(nodes.size(), InvalidBasicBlockIndex);
- parent = std::vector<int>(nodes.size(), InvalidBasicBlockIndex);
- dfnum = std::vector<int>(nodes.size(), 0);
- semi = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- ancestor = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- idom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- samedom = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
- best = std::vector<BasicBlockIndex>(nodes.size(), InvalidBasicBlockIndex);
+ Q_ASSERT(function->basicBlock(0)->in.isEmpty());
+
+ const int bbCount = function->basicBlockCount();
+ vertex = std::vector<int>(bbCount, InvalidBasicBlockIndex);
+ parent = std::vector<int>(bbCount, InvalidBasicBlockIndex);
+ dfnum = std::vector<int>(bbCount, 0);
+ semi = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ ancestor = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ idom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ samedom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
+ best = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex);
QHash<BasicBlockIndex, std::vector<BasicBlockIndex> > bucket;
+ bucket.reserve(bbCount);
- DFS(nodes.first()->index);
- Q_ASSERT(N == nodes.size()); // fails with unreachable nodes, but those should have been removed before.
+ DFS(function->basicBlock(0)->index());
+ Q_ASSERT(N == function->liveBasicBlocksCount());
std::vector<BasicBlockIndex> worklist;
worklist.reserve(vertex.capacity() / 2);
@@ -484,12 +476,12 @@ class DominatorTree {
BasicBlockIndex p = parent[n];
BasicBlockIndex s = p;
- foreach (BasicBlock *v, nodes.at(n)->in) {
+ foreach (BasicBlock *v, function->basicBlock(n)->in) {
BasicBlockIndex ss = InvalidBasicBlockIndex;
- if (dfnum[v->index] <= dfnum[n])
- ss = v->index;
+ if (dfnum[v->index()] <= dfnum[n])
+ ss = v->index();
else
- ss = semi[ancestorWithLowestSemi(v->index, worklist)];
+ ss = semi[ancestorWithLowestSemi(v->index(), worklist)];
if (dfnum[ss] < dfnum[s])
s = ss;
}
@@ -537,6 +529,7 @@ class DominatorTree {
qout << "(none)";
qout << " -> " << to->index << endl;
}
+ qout << "N = " << N << endl;
#endif // SHOW_SSA
}
@@ -548,10 +541,12 @@ class DominatorTree {
void computeDF() {
// compute children of each node in the dominator tree
std::vector<std::vector<BasicBlockIndex> > children; // BasicBlock index -> children
- children.resize(nodes.size());
- foreach (BasicBlock *n, nodes) {
- const BasicBlockIndex nodeIndex = n->index;
- Q_ASSERT(nodes.at(nodeIndex) == n);
+ children.resize(function->basicBlockCount());
+ foreach (BasicBlock *n, function->basicBlocks()) {
+ if (n->isRemoved())
+ continue;
+ const BasicBlockIndex nodeIndex = n->index();
+ Q_ASSERT(function->basicBlock(nodeIndex) == n);
const BasicBlockIndex nodeDominator = idom[nodeIndex];
if (nodeDominator == InvalidBasicBlockIndex)
continue; // there is no dominator to add this node to as a child (e.g. the start node)
@@ -560,18 +555,20 @@ class DominatorTree {
// Fill the worklist and initialize the node status for each basic-block
QHash<BasicBlockIndex, NodeProgress> nodeStatus;
- nodeStatus.reserve(nodes.size());
+ nodeStatus.reserve(function->basicBlockCount());
std::vector<BasicBlockIndex> worklist;
- worklist.reserve(nodes.size() * 2);
- for (int i = 0, ei = nodes.size(); i != ei; ++i) {
- BasicBlockIndex nodeIndex = nodes.at(i)->index;
+ worklist.reserve(function->basicBlockCount() * 2);
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+ BasicBlockIndex nodeIndex = bb->index();
worklist.push_back(nodeIndex);
NodeProgress &np = nodeStatus[nodeIndex];
np.children = children[nodeIndex];
np.todo = children[nodeIndex];
}
- std::vector<bool> DF_done(nodes.size(), false);
+ std::vector<bool> DF_done(function->basicBlockCount(), false);
while (!worklist.empty()) {
BasicBlockIndex node = worklist.back();
@@ -594,16 +591,16 @@ class DominatorTree {
if (np.todo.empty()) {
BasicBlockSet &S = DF[node];
- S.init(nodes);
- foreach (BasicBlock *y, nodes.at(node)->out)
- if (idom[y->index] != node)
+ S.init(function);
+ foreach (BasicBlock *y, function->basicBlock(node)->out)
+ if (idom[y->index()] != node)
S.insert(y);
foreach (BasicBlockIndex child, np.children) {
const BasicBlockSet &ws = DF[child];
for (BasicBlockSet::const_iterator it = ws.begin(), eit = ws.end(); it != eit; ++it) {
BasicBlock *w = *it;
- const BasicBlockIndex wIndex = w->index;
- if (node == wIndex || !dominates(node, w->index))
+ const BasicBlockIndex wIndex = w->index();
+ if (node == wIndex || !dominates(node, w->index()))
S.insert(w);
}
}
@@ -648,21 +645,21 @@ class DominatorTree {
}
public:
- DominatorTree(const QVector<BasicBlock *> &nodes)
- : nodes(nodes)
+ DominatorTree(IR::Function *function)
+ : function(function)
, N(0)
{
- DF.resize(nodes.size());
+ DF.resize(function->basicBlockCount());
calculateIDoms();
computeDF();
}
const BasicBlockSet &dominatorFrontier(BasicBlock *n) const {
- return DF[n->index];
+ return DF[n->index()];
}
BasicBlock *immediateDominator(BasicBlock *bb) const {
- return nodes[idom[bb->index]];
+ return function->basicBlock(idom[bb->index()]);
}
void dumpImmediateDominators() const
@@ -677,46 +674,30 @@ public:
void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator)
{
- Q_ASSERT(bb->index >= 0);
+ Q_ASSERT(bb->index() >= 0);
- int blockIndex;
- if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index) >= idom.size()) {
+ if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index()) >= idom.size()) {
// This is a new block, probably introduced by edge splitting. So, we'll have to grow
// the array before inserting the immediate dominator.
- nodes.append(bb);
- idom.resize(nodes.size(), InvalidBasicBlockIndex);
- blockIndex = nodes.size() - 1;
- } else {
- blockIndex = getBlockIndex(bb);
+ idom.resize(function->basicBlockCount(), InvalidBasicBlockIndex);
}
- idom[blockIndex] = getBlockIndex(newDominator);
+ idom[bb->index()] = newDominator->index();
}
bool dominates(BasicBlock *dominator, BasicBlock *dominated) const {
- // The index of the basic blocks might have changed, or the nodes array might have changed,
- // so get the index from our copy of the array.
- return dominates(getBlockIndex(dominator), getBlockIndex(dominated));
+ return dominates(dominator->index(), dominated->index());
}
private:
- int getBlockIndex(BasicBlock *bb) const {
- if (!bb)
- return InvalidBasicBlockIndex;
-
- if (bb->index >= 0 && bb->index < nodes.size()) {
- if (nodes.at(bb->index) == bb)
- return bb->index;
- }
-
- return nodes.indexOf(bb);
- }
-
bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const {
// dominator can be Invalid when the dominated block has no dominator (i.e. the start node)
Q_ASSERT(dominated != InvalidBasicBlockIndex);
- for (BasicBlockIndex it = dominated; it != InvalidBasicBlockIndex; it = idom[it]) {
+ if (dominator == dominated)
+ return false;
+
+ for (BasicBlockIndex it = idom[dominated]; it != InvalidBasicBlockIndex; it = idom[it]) {
if (it == dominator)
return true;
}
@@ -726,8 +707,9 @@ private:
};
class VariableCollector: public StmtVisitor, ExprVisitor {
- QHash<Temp, QSet<BasicBlock *> > _defsites;
- QHash<BasicBlock *, QSet<Temp> > A_orig;
+ typedef QHash<Temp, QSet<BasicBlock *> > DefSites;
+ DefSites _defsites;
+ QVector<QSet<Temp> > A_orig;
QSet<Temp> nonLocals;
QSet<Temp> killed;
@@ -744,16 +726,22 @@ public:
: function(function)
{
_defsites.reserve(function->tempCount);
+ A_orig.resize(function->basicBlockCount());
+ for (int i = 0, ei = A_orig.size(); i != ei; ++i)
+ A_orig[i].reserve(8);
#if defined(SHOW_SSA)
qout << "Variables collected:" << endl;
#endif // SHOW_SSA
- foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
currentBB = bb;
killed.clear();
- killed.reserve(bb->statements.size() / 2);
- foreach (Stmt *s, bb->statements) {
+ killed.reserve(bb->statements().size() / 2);
+ foreach (Stmt *s, bb->statements()) {
s->accept(this);
}
}
@@ -779,7 +767,7 @@ public:
}
QSet<Temp> inBlock(BasicBlock *n) const {
- return A_orig[n];
+ return A_orig.at(n->index());
}
bool isNonLocal(const Temp &var) const { return nonLocals.contains(var); }
@@ -825,8 +813,15 @@ protected:
qout << " -> L" << currentBB->index << endl;
#endif // SHOW_SSA
- _defsites[*t].insert(currentBB);
- A_orig[currentBB].insert(*t);
+ DefSites::iterator defsitesIt = _defsites.find(*t);
+ if (defsitesIt == _defsites.end()) {
+ QSet<BasicBlock *> bbs;
+ bbs.reserve(4);
+ defsitesIt = _defsites.insert(*t, bbs);
+ }
+ defsitesIt->insert(currentBB);
+
+ A_orig[currentBB->index()].insert(*t);
// For semi-pruned SSA:
killed.insert(*t);
@@ -855,7 +850,7 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) {
phiNode->d = new Stmt::Data;
phiNode->targetTemp = f->New<Temp>();
phiNode->targetTemp->init(a.kind, a.index, 0);
- y->statements.prepend(phiNode);
+ y->prependStatement(phiNode);
phiNode->d->incoming.resize(y->in.size());
for (int i = 0, ei = y->in.size(); i < ei; ++i) {
@@ -994,15 +989,15 @@ public:
VariableRenamer(IR::Function *f)
: function(f)
, tempCount(0)
- , processed(f->basicBlocks)
+ , processed(f)
{
localMapping.reserve(f->tempCount);
vregMapping.reserve(f->tempCount);
- todo.reserve(f->basicBlocks.size());
+ todo.reserve(f->basicBlockCount());
}
void run() {
- todo.append(TodoAction(function->basicBlocks.first()));
+ todo.append(TodoAction(function->basicBlock(0)));
while (!todo.isEmpty()) {
TodoAction todoAction = todo.back();
@@ -1057,13 +1052,13 @@ private:
void renameStatementsAndPhis(BasicBlock *bb)
{
- foreach (Stmt *s, bb->statements)
+ foreach (Stmt *s, bb->statements())
s->accept(this);
foreach (BasicBlock *Y, bb->out) {
const int j = Y->in.indexOf(bb);
Q_ASSERT(j >= 0 && j < Y->in.size());
- foreach (Stmt *s, Y->statements) {
+ foreach (Stmt *s, Y->statements()) {
if (Phi *phi = s->asPhi()) {
Temp *t = phi->d->incoming[j]->asTemp();
unsigned newTmp = currentNumber(*t);
@@ -1198,7 +1193,7 @@ protected:
void convertToSSA(IR::Function *function, const DominatorTree &df)
{
-#ifdef SHOW_SSA
+#if defined(SHOW_SSA)
qout << "Converting function ";
if (function->name)
qout << *function->name;
@@ -1210,8 +1205,16 @@ void convertToSSA(IR::Function *function, const DominatorTree &df)
// Collect all applicable variables:
VariableCollector variables(function);
+ // Prepare for phi node insertion:
+ QVector<QSet<Temp> > A_phi;
+ A_phi.resize(function->basicBlockCount());
+ for (int i = 0, ei = A_phi.size(); i != ei; ++i) {
+ QSet<Temp> temps;
+ temps.reserve(4);
+ A_phi[i] = temps;
+ }
+
// Place phi functions:
- QHash<BasicBlock *, QSet<Temp> > A_phi;
foreach (Temp a, variables.vars()) {
if (!variables.isNonLocal(a))
continue; // for semi-pruned SSA
@@ -1224,9 +1227,9 @@ void convertToSSA(IR::Function *function, const DominatorTree &df)
for (BasicBlockSet::const_iterator it = dominatorFrontierForN.begin(), eit = dominatorFrontierForN.end();
it != eit; ++it) {
BasicBlock *y = *it;
- if (!A_phi[y].contains(a)) {
+ if (!A_phi.at(y->index()).contains(a)) {
insertPhiNode(a, y, function);
- A_phi[y].insert(a);
+ A_phi[y->index()].insert(a);
if (!variables.inBlock(y).contains(a))
W.append(y);
}
@@ -1264,7 +1267,8 @@ public:
private:
IR::Function *function;
- QHash<UntypedTemp, DefUse> _defUses;
+ typedef QHash<UntypedTemp, DefUse> DefUses;
+ DefUses _defUses;
QHash<Stmt *, QList<Temp> > _usesPerStatement;
BasicBlock *_block;
@@ -1299,9 +1303,12 @@ public:
DefUsesCalculator(IR::Function *function)
: function(function)
{
- foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
_block = bb;
- foreach (Stmt *stmt, bb->statements) {
+ foreach (Stmt *stmt, bb->statements()) {
_stmt = stmt;
stmt->accept(this);
}
@@ -1357,8 +1364,16 @@ public:
QList<Temp> usedVars(Stmt *s) const
{ return _usesPerStatement[s]; }
- QList<Stmt *> uses(const UntypedTemp &var) const
- { return _defUses[var].uses; }
+ const QList<Stmt *> &uses(const UntypedTemp &var) const
+ {
+ static const QList<Stmt *> noUses;
+
+ DefUses::const_iterator it = _defUses.find(var);
+ if (it == _defUses.end())
+ return noUses;
+ else
+ return it->uses;
+ }
QVector<Stmt*> removeDefUses(Stmt *s)
{
@@ -1383,7 +1398,7 @@ public:
foreach (const UntypedTemp &var, _defUses.keys()) {
const DefUse &du = _defUses[var];
var.temp.dump(qout);
- qout<<" -> defined in block "<<du.blockOfStatement->index<<", statement: ";
+ qout<<" -> defined in block "<<du.blockOfStatement->index()<<", statement: ";
du.defStmt->dump(qout);
qout<<endl<<" uses:"<<endl;
foreach (Stmt *s, du.uses) {
@@ -1475,10 +1490,7 @@ void cleanupPhis(DefUsesCalculator &defUses)
foreach (Phi *phi, toRemove) {
Temp targetVar = *phi->targetTemp;
- BasicBlock *bb = defUses.defStmtBlock(targetVar);
- int idx = bb->statements.indexOf(phi);
- bb->statements[idx]->destroyData();
- bb->statements.remove(idx);
+ defUses.defStmtBlock(targetVar)->removeStatement(phi);
foreach (const Temp &usedVar, defUses.usedVars(phi))
defUses.removeUse(phi, usedVar);
@@ -1490,7 +1502,10 @@ class StatementWorklist
{
QVector<Stmt *> worklist;
QBitArray inWorklist;
- QHash<Stmt*,Stmt**> ref;
+ QSet<Stmt *> removed;
+ QHash<Stmt*,Stmt*> replaced;
+
+ Q_DISABLE_COPY(StatementWorklist)
public:
StatementWorklist(IR::Function *function)
@@ -1500,12 +1515,13 @@ public:
// Put in all statements, and number them on the fly. The numbering is used to index the
// bit array.
- foreach (BasicBlock *bb, function->basicBlocks) {
- for (int i = 0, ei = bb->statements.size(); i != ei; ++i) {
- Stmt **s = &bb->statements[i];
- (*s)->id = stmtCount++;
- w.append(*s);
- ref.insert(*s, s);
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ foreach (Stmt *s, bb->statements()) {
+ s->id = stmtCount++;
+ w.append(s);
}
}
@@ -1524,29 +1540,40 @@ public:
void clear(Stmt *stmt)
{
Q_ASSERT(!inWorklist.at(stmt->id));
- *ref[stmt] = 0;
+ removed.insert(stmt);
}
void replace(Stmt *oldStmt, Stmt *newStmt)
{
Q_ASSERT(oldStmt);
Q_ASSERT(newStmt);
+ Q_ASSERT(!removed.contains(oldStmt));
if (newStmt->id == -1)
newStmt->id = oldStmt->id;
- *ref[oldStmt] = newStmt;
+ QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(oldStmt);
+ if (it != replaced.end())
+ oldStmt = it.key();
+ replaced[oldStmt] = newStmt;
}
void cleanup(IR::Function *function)
{
- foreach (BasicBlock *bb, function->basicBlocks) {
- for (int i = 0; i < bb->statements.size();) {
- if (bb->statements[i]) {
- bb->statements[i]->id = -1;
- ++i;
- } else {
- bb->statements.remove(i);
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+
+ for (int i = 0; i < bb->statementCount();) {
+ Stmt *stmt = bb->statements()[i];
+ QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(stmt);
+ if (it != replaced.end() && !removed.contains(it.value())) {
+ bb->replaceStatement(i, it.value());
+ } else if (removed.contains(stmt)) {
+ bb->removeStatement(i);
+ continue;
}
+
+ ++i;
}
}
}
@@ -1846,8 +1873,9 @@ class TypeInference: public StmtVisitor, public ExprVisitor {
QQmlEnginePrivate *qmlEngine;
IR::Function *function;
const DefUsesCalculator &_defUses;
- QHash<Temp, DiscoveredType> _tempTypes;
- QSet<Stmt *> _worklist;
+ typedef QHash<Temp, DiscoveredType> TempTypes;
+ TempTypes _tempTypes;
+ QList<Stmt *> _worklist;
struct TypingResult {
DiscoveredType type;
bool fullyTyped;
@@ -1869,26 +1897,29 @@ public:
// TODO: the worklist handling looks a bit inefficient... check if there is something better
_worklist.clear();
- for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) {
- BasicBlock *bb = function->basicBlocks[i];
+ for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
+ BasicBlock *bb = function->basicBlock(i);
+ if (bb->isRemoved())
+ continue;
if (i == 0 || !bb->in.isEmpty())
- foreach (Stmt *s, bb->statements)
- if (!s->asJump())
- _worklist.insert(s);
+ _worklist += bb->statements().toList();
}
while (!_worklist.isEmpty()) {
- QList<Stmt *> worklist = _worklist.values();
+ QList<Stmt *> worklist = QSet<Stmt *>::fromList(_worklist).toList();
_worklist.clear();
while (!worklist.isEmpty()) {
Stmt *s = worklist.first();
worklist.removeFirst();
+ if (s->asJump())
+ continue;
+
#if defined(SHOW_SSA)
qout<<"Typing stmt ";s->dump(qout);qout<<endl;
#endif
if (!run(s)) {
- _worklist.insert(s);
+ _worklist += s;
#if defined(SHOW_SSA)
qout<<"Pushing back stmt: ";
s->dump(qout);qout<<endl;
@@ -1939,8 +1970,11 @@ private:
#endif
if (isAlwaysVar(t))
ty = DiscoveredType(VarType);
- if (_tempTypes[*t] != ty) {
- _tempTypes[*t] = ty;
+ TempTypes::iterator it = _tempTypes.find(*t);
+ if (it == _tempTypes.end())
+ it = _tempTypes.insert(*t, DiscoveredType());
+ if (it.value() != ty) {
+ it.value() = ty;
#if defined(SHOW_SSA)
foreach (Stmt *s, _defUses.uses(*t)) {
@@ -1950,7 +1984,7 @@ private:
}
#endif
- _worklist += QSet<Stmt *>::fromList(_defUses.uses(*t));
+ _worklist += _defUses.uses(*t);
}
} else {
e->type = (Type) ty.type;
@@ -2240,7 +2274,7 @@ public:
private:
bool isUsedAsInt32(const UntypedTemp &t, const QVector<UntypedTemp> &knownOk) const
{
- QList<Stmt *> uses = _defUses.uses(t);
+ const QList<Stmt *> &uses = _defUses.uses(t);
if (uses.isEmpty())
return false;
@@ -2370,10 +2404,12 @@ public:
void run(IR::Function *f) {
_f = f;
- foreach (BasicBlock *bb, f->basicBlocks) {
+ foreach (BasicBlock *bb, f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
_conversions.clear();
- foreach (Stmt *s, bb->statements) {
+ foreach (Stmt *s, bb->statements()) {
_currStmt = s;
s->accept(this);
}
@@ -2404,11 +2440,9 @@ public:
if (Phi *phi = conversion.stmt->asPhi()) {
int idx = phi->d->incoming.indexOf(t);
Q_ASSERT(idx != -1);
- QVector<Stmt *> &stmts = bb->in[idx]->statements;
- stmts.insert(stmts.size() - 1, convCall);
+ bb->in[idx]->insertStatementBeforeTerminator(convCall);
} else {
- int idx = bb->statements.indexOf(conversion.stmt);
- bb->statements.insert(idx, convCall);
+ bb->insertStatementBefore(conversion.stmt, convCall);
}
*conversion.expr = source;
@@ -2429,9 +2463,7 @@ public:
_defUses.removeUse(move, *unopOperand);
}
- int idx = bb->statements.indexOf(conversion.stmt);
- Q_ASSERT(idx != -1);
- bb->statements.insert(idx, extraMove);
+ bb->insertStatementBefore(conversion.stmt, extraMove);
*conversion.expr = bb->CONVERT(tmp, conversion.targetType);
_defUses.addUse(*tmp, move);
@@ -2563,56 +2595,55 @@ protected:
void splitCriticalEdges(IR::Function *f, DominatorTree &df)
{
- for (int i = 0, ei = f->basicBlocks.size(); i != ei; ++i) {
- BasicBlock *bb = f->basicBlocks[i];
- if (bb->in.size() > 1) {
- for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
- BasicBlock *inBB = bb->in[inIdx];
- if (inBB->out.size() > 1) { // this should have been split!
- int newIndex = f->basicBlocks.last()->index + 1;
-#if defined(SHOW_SSA)
- qDebug() << "Splitting edge from block" << inBB->index << "to block" << bb->index << "by introducing block" << newIndex;
-#endif
+ foreach (BasicBlock *bb, f->basicBlocks()) {
+ if (bb->isRemoved())
+ continue;
+ if (bb->in.size() < 2)
+ continue;
- BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
-
- // create the basic block:
- BasicBlock *newBB = new BasicBlock(f, containingGroup, bb->catchBlock);
- newBB->index = newIndex;
- f->basicBlocks.append(newBB);
- Jump *s = f->New<Jump>();
- s->init(bb);
- newBB->statements.append(s);
-
- // rewire the old outgoing edge
- int outIdx = inBB->out.indexOf(bb);
- inBB->out[outIdx] = newBB;
- newBB->in.append(inBB);
-
- // rewire the old incoming edge
- bb->in[inIdx] = newBB;
- newBB->out.append(bb);
-
- // patch the terminator
- Stmt *terminator = inBB->terminator();
- if (Jump *j = terminator->asJump()) {
- Q_ASSERT(outIdx == 0);
- j->target = newBB;
- } else if (CJump *j = terminator->asCJump()) {
- if (outIdx == 0)
- j->iftrue = newBB;
- else if (outIdx == 1)
- j->iffalse = newBB;
- else
- Q_ASSERT(!"Invalid out edge index for CJUMP!");
- } else {
- Q_ASSERT(!"Unknown terminator!");
- }
+ for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
+ BasicBlock *inBB = bb->in[inIdx];
+ if (inBB->out.size() < 2)
+ continue;
- // Set the immediate dominator of the new block to inBB
- df.updateImmediateDominator(newBB, inBB);
- }
+ // We found a critical edge.
+ BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup();
+
+ // create the basic block:
+ BasicBlock *newBB = f->newBasicBlock(containingGroup, bb->catchBlock);
+ Jump *s = f->New<Jump>();
+ s->init(bb);
+ newBB->appendStatement(s);
+
+ // rewire the old outgoing edge
+ int outIdx = inBB->out.indexOf(bb);
+ inBB->out[outIdx] = newBB;
+ newBB->in.append(inBB);
+
+ // rewire the old incoming edge
+ bb->in[inIdx] = newBB;
+ newBB->out.append(bb);
+
+ // patch the terminator
+ Stmt *terminator = inBB->terminator();
+ if (Jump *j = terminator->asJump()) {
+ Q_ASSERT(outIdx == 0);
+ j->target = newBB;
+ } else if (CJump *j = terminator->asCJump()) {
+ if (outIdx == 0)
+ j->iftrue = newBB;
+ else if (outIdx == 1)
+ j->iffalse = newBB;
+ else
+ Q_ASSERT(!"Invalid out edge index for CJUMP!");
+ } else if (terminator->asRet()) {
+ Q_ASSERT(!"A block with a RET at the end cannot have outgoing edges.");
+ } else {
+ Q_ASSERT(!"Unknown terminator!");
}
+
+ // Set the immediate dominator of the new block to inBB
+ df.updateImmediateDominator(newBB, inBB);
}
}
}
@@ -2705,6 +2736,7 @@ class BlockScheduler
void emitBlock(BasicBlock *bb)
{
+ Q_ASSERT(!bb->isRemoved());
if (emitted.alreadyProcessed(bb))
return;
@@ -2752,22 +2784,24 @@ public:
BlockScheduler(IR::Function *function, const DominatorTree &dominatorTree)
: function(function)
, dominatorTree(dominatorTree)
- , emitted(function->basicBlocks)
+ , sequence(0)
+ , emitted(function)
{}
QHash<BasicBlock *, BasicBlock *> go()
{
showMeTheCode(function);
- schedule(function->basicBlocks.first());
+ schedule(function->basicBlock(0));
#if defined(SHOW_SSA)
qDebug() << "Block sequence:";
foreach (BasicBlock *bb, sequence)
- qDebug("\tL%d", bb->index);
+ qDebug("\tL%d", bb->index());
#endif // SHOW_SSA
- Q_ASSERT(function->basicBlocks.size() == sequence.size());
- function->basicBlocks = sequence;
+ Q_ASSERT(function->liveBasicBlocksCount() == sequence.size());
+ function->setScheduledBlocks(sequence);
+ function->renumberBasicBlocks();
return loopsStartEnd;
}
};
@@ -2779,7 +2813,7 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
foreach (BasicBlock *bb2, bb->out) {
if (bb2 && bb2->in.size() > 1) {
qout << "found critical edge between block "
- << bb->index << " and block " << bb2->index;
+ << bb->index() << " and block " << bb2->index();
Q_ASSERT(false);
}
}
@@ -2788,51 +2822,50 @@ void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
}
#endif
-void cleanupBasicBlocks(IR::Function *function, bool renumber)
+void cleanupBasicBlocks(IR::Function *function)
{
showMeTheCode(function);
// Algorithm: this is the iterative version of a depth-first search for all blocks that are
// reachable through outgoing edges, starting with the start block and all exception handler
// blocks.
- QSet<BasicBlock *> postponed, done;
- QSet<BasicBlock *> toRemove;
- toRemove.reserve(function->basicBlocks.size());
- done.reserve(function->basicBlocks.size());
- postponed.reserve(8);
- for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) {
- BasicBlock *bb = function->basicBlocks[i];
- if (i == 0 || bb->isExceptionHandler)
- postponed.insert(bb);
- else
- toRemove.insert(bb);
+ QBitArray reachableBlocks(function->basicBlockCount());
+ QVector<BasicBlock *> postponed;
+ postponed.reserve(16);
+ for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) {
+ BasicBlock *bb = function->basicBlock(i);
+ if (i == 0 || bb->isExceptionHandler())
+ postponed.append(bb);
}
while (!postponed.isEmpty()) {
- QSet<BasicBlock *>::iterator it = postponed.begin();
- BasicBlock *bb = *it;
- postponed.erase(it);
- done.insert(bb);
+ BasicBlock *bb = postponed.back();
+ postponed.pop_back();
+ if (bb->isRemoved()) // this block was removed before, we don't need to clean it up.
+ continue;
+
+ reachableBlocks.setBit(bb->index());
foreach (BasicBlock *outBB, bb->out) {
- if (!done.contains(outBB)) {
- postponed.insert(outBB);
- toRemove.remove(outBB);
- }
+ if (!reachableBlocks.at(outBB->index()))
+ postponed.append(outBB);
}
}
- foreach (BasicBlock *bb, toRemove) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ if (bb->isRemoved()) // the block has already been removed, so ignore it
+ continue;
+ if (reachableBlocks.at(bb->index())) // the block is reachable, so ignore it
+ continue;
+
foreach (BasicBlock *outBB, bb->out) {
- if (toRemove.contains(outBB))
+ if (outBB->isRemoved() || !reachableBlocks.at(outBB->index()))
continue; // We do not need to unlink from blocks that are scheduled to be removed.
- // Actually, it is potentially dangerous: if that block was already
- // destroyed, this could result in a use-after-free.
int idx = outBB->in.indexOf(bb);
if (idx != -1) {
outBB->in.remove(idx);
- foreach (Stmt *s, outBB->statements) {
+ foreach (Stmt *s, outBB->statements()) {
if (Phi *phi = s->asPhi())
phi->d->incoming.remove(idx);
else
@@ -2841,18 +2874,9 @@ void cleanupBasicBlocks(IR::Function *function, bool renumber)
}
}
- foreach (Stmt *s, bb->statements)
- s->destroyData();
- int idx = function->basicBlocks.indexOf(bb);
- if (idx != -1)
- function->basicBlocks.remove(idx);
- delete bb;
+ function->removeBasicBlock(bb);
}
- if (renumber)
- for (int i = 0; i < function->basicBlocks.size(); ++i)
- function->basicBlocks[i]->index = i;
-
showMeTheCode(function);
}
@@ -2905,7 +2929,7 @@ public:
, _replacement(0)
{}
- QVector<Stmt *> operator()(Temp *toReplace, Expr *replacement)
+ void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QList<Stmt *> *newUses = 0)
{
Q_ASSERT(replacement->asTemp() || replacement->asConst() || replacement->asName());
@@ -2914,20 +2938,22 @@ public:
qSwap(_toReplace, toReplace);
qSwap(_replacement, replacement);
- QList<Stmt *> uses = _defUses.uses(*_toReplace);
+ const QList<Stmt *> &uses = _defUses.uses(*_toReplace);
+ if (newUses)
+ newUses->reserve(uses.size());
+
// qout << " " << uses.size() << " uses:"<<endl;
- QVector<Stmt *> result;
- result.reserve(uses.size());
foreach (Stmt *use, uses) {
// qout<<" ";use->dump(qout);qout<<"\n";
use->accept(this);
// qout<<" -> ";use->dump(qout);qout<<"\n";
- result.append(use);
+ W += use;
+ if (newUses)
+ newUses->append(use);
}
qSwap(_replacement, replacement);
qSwap(_toReplace, toReplace);
- return result;
}
protected:
@@ -3009,28 +3035,24 @@ namespace {
void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, StatementWorklist &W,
DominatorTree &df)
{
- // TODO: change this to mark the block as deleted, but leave it alone so that other references
- // won't be dangling pointers.
// TODO: after the change above: if we keep on detaching the block from predecessors or
// successors, update the DominatorTree too.
// don't purge blocks that are entry points for catch statements. They might not be directly
// connected, but are required anyway
- if (bb->isExceptionHandler)
+ if (bb->isExceptionHandler())
return;
QVector<BasicBlock *> toPurge;
+ toPurge.reserve(8);
toPurge.append(bb);
while (!toPurge.isEmpty()) {
bb = toPurge.first();
toPurge.removeFirst();
- int bbIdx = func->basicBlocks.indexOf(bb);
- if (bbIdx == -1)
+ if (bb->isRemoved())
continue;
- else
- func->basicBlocks.remove(bbIdx);
// unlink all incoming edges
foreach (BasicBlock *in, bb->in) {
@@ -3044,7 +3066,7 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta
int idx = out->in.indexOf(bb);
if (idx != -1) {
out->in.remove(idx);
- foreach (Stmt *outStmt, out->statements) {
+ foreach (Stmt *outStmt, out->statements()) {
if (!outStmt)
continue;
if (Phi *phi = outStmt->asPhi()) {
@@ -3069,19 +3091,15 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta
}
// unlink all defs/uses from the statements in the basic block
- foreach (Stmt *s, bb->statements) {
+ foreach (Stmt *s, bb->statements()) {
if (!s)
continue;
W += defUses.removeDefUses(s);
W -= s;
-
- // clean-up the statement's data
- s->destroyData();
}
- bb->statements.clear();
- delete bb;
+ func->removeBasicBlock(bb);
}
}
@@ -3162,7 +3180,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
if (Phi *phi = s->asPhi()) {
// constant propagation:
if (Const *c = isConstPhi(phi)) {
- W += replaceUses(phi->targetTemp, c);
+ replaceUses(phi->targetTemp, c, W);
defUses.removeDef(*phi->targetTemp);
W.clear(s);
continue;
@@ -3173,11 +3191,11 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
Temp *t = phi->targetTemp;
Expr *e = phi->d->incoming.first();
- QVector<Stmt *> newT2Uses = replaceUses(t, e);
- W += newT2Uses;
+ QList<Stmt *> newT2Uses;
+ replaceUses(t, e, W, &newT2Uses);
if (Temp *t2 = e->asTemp()) {
defUses.removeUse(s, *t2);
- defUses.addUses(*t2, QList<Stmt*>::fromVector(newT2Uses));
+ defUses.addUses(*t2, newT2Uses);
}
defUses.removeDef(*t);
W.clear(s);
@@ -3222,7 +3240,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
// constant propagation:
if (Const *sourceConst = m->source->asConst()) {
- W += replaceUses(targetTemp, sourceConst);
+ replaceUses(targetTemp, sourceConst, W);
defUses.removeDef(*targetTemp);
W.clear(s);
continue;
@@ -3232,7 +3250,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
Const *c = function->New<Const>();
const int enumValue = member->attachedPropertiesIdOrEnumValue;
c->init(SInt32Type, enumValue);
- W += replaceUses(targetTemp, c);
+ replaceUses(targetTemp, c, W);
defUses.removeDef(*targetTemp);
W.clear(s);
defUses.removeUse(s, *member->base->asTemp());
@@ -3250,10 +3268,10 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr
// copy propagation:
if (Temp *sourceTemp = unescapableTemp(m->source, function)) {
- QVector<Stmt *> newT2Uses = replaceUses(targetTemp, sourceTemp);
- W += newT2Uses;
+ QList<Stmt *> newT2Uses;
+ replaceUses(targetTemp, sourceTemp, W, &newT2Uses);
defUses.removeUse(s, *sourceTemp);
- defUses.addUses(*sourceTemp, QList<Stmt*>::fromVector(newT2Uses));
+ defUses.addUses(*sourceTemp, newT2Uses);
defUses.removeDef(*targetTemp);
W.clear(s);
continue;
@@ -3518,16 +3536,19 @@ protected:
class LifeRanges {
typedef QSet<Temp> LiveRegs;
- QHash<BasicBlock *, LiveRegs> _liveIn;
+ QVector<LiveRegs> _liveIn;
QHash<Temp, LifeTimeInterval> _intervals;
- QVector<LifeTimeInterval> _sortedRanges;
+ typedef QVector<LifeTimeInterval> LifeTimeIntervals;
+ LifeTimeIntervals _sortedIntervals;
public:
LifeRanges(IR::Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops)
{
+ _liveIn.resize(function->basicBlockCount());
+
int id = 0;
- foreach (BasicBlock *bb, function->basicBlocks) {
- foreach (Stmt *s, bb->statements) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ foreach (Stmt *s, bb->statements()) {
if (s->asPhi())
s->id = id + 1;
else
@@ -3535,34 +3556,34 @@ public:
}
}
- for (int i = function->basicBlocks.size() - 1; i >= 0; --i) {
- BasicBlock *bb = function->basicBlocks[i];
+ for (int i = function->basicBlockCount() - 1; i >= 0; --i) {
+ BasicBlock *bb = function->basicBlock(i);
buildIntervals(bb, startEndLoops.value(bb, 0), function);
}
- _sortedRanges.reserve(_intervals.size());
+ _sortedIntervals.reserve(_intervals.size());
for (QHash<Temp, LifeTimeInterval>::const_iterator i = _intervals.begin(), ei = _intervals.end(); i != ei; ++i) {
- LifeTimeInterval range = i.value();
- range.setTemp(i.key());
- _sortedRanges.append(range);
+ LifeTimeIntervals::iterator lti = _sortedIntervals.insert(_sortedIntervals.end(), i.value());
+ lti->setTemp(i.key());
}
- std::sort(_sortedRanges.begin(), _sortedRanges.end(), LifeTimeInterval::lessThan);
+ std::sort(_sortedIntervals.begin(), _sortedIntervals.end(), LifeTimeInterval::lessThan);
+ _intervals.clear();
}
- QVector<LifeTimeInterval> ranges() const { return _sortedRanges; }
+ QVector<LifeTimeInterval> intervals() const { return _sortedIntervals; }
void dump() const
{
qout << "Life ranges:" << endl;
qout << "Intervals:" << endl;
- foreach (const LifeTimeInterval &range, _sortedRanges) {
+ foreach (const LifeTimeInterval &range, _sortedIntervals) {
range.dump(qout);
qout << endl;
}
- foreach (BasicBlock *bb, _liveIn.keys()) {
- qout << "L" << bb->index <<" live-in: ";
- QList<Temp> live = QList<Temp>::fromSet(_liveIn.value(bb));
+ for (int i = 0, ei = _liveIn.size(); i != ei; ++i) {
+ qout << "L" << i <<" live-in: ";
+ QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i));
std::sort(live.begin(), live.end());
for (int i = 0; i < live.size(); ++i) {
if (i > 0) qout << ", ";
@@ -3577,11 +3598,11 @@ private:
{
LiveRegs live;
foreach (BasicBlock *successor, bb->out) {
- live.unite(_liveIn[successor]);
+ live.unite(_liveIn[successor->index()]);
const int bbIndex = successor->in.indexOf(bb);
Q_ASSERT(bbIndex >= 0);
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (Phi *phi = s->asPhi()) {
if (Temp *t = phi->d->incoming[bbIndex]->asTemp())
live.insert(*t);
@@ -3591,12 +3612,14 @@ private:
}
}
+ QVector<Stmt *> statements = bb->statements();
+
foreach (const Temp &opd, live)
- _intervals[opd].addRange(bb->statements.first()->id, bb->statements.last()->id);
+ _intervals[opd].addRange(statements.first()->id, statements.last()->id);
InputOutputCollector collector(function);
- for (int i = bb->statements.size() - 1; i >= 0; --i) {
- Stmt *s = bb->statements[i];
+ for (int i = statements.size() - 1; i >= 0; --i) {
+ Stmt *s = statements[i];
if (Phi *phi = s->asPhi()) {
LiveRegs::iterator it = live.find(*phi->targetTemp);
if (it == live.end()) {
@@ -3613,19 +3636,30 @@ private:
live.remove(opd);
}
foreach (const Temp &opd, collector.inputs) {
- _intervals[opd].addRange(bb->statements.first()->id, s->id);
+ _intervals[opd].addRange(statements.first()->id, s->id);
live.insert(opd);
}
}
if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null.
foreach (const Temp &opd, live)
- _intervals[opd].addRange(bb->statements.first()->id, loopEnd->statements.last()->id);
+ _intervals[opd].addRange(statements.first()->id, loopEnd->terminator()->id);
}
- _liveIn[bb] = live;
+ _liveIn[bb->index()] = live;
}
};
+
+void removeUnreachleBlocks(IR::Function *function)
+{
+ QVector<BasicBlock *> newSchedule;
+ newSchedule.reserve(function->basicBlockCount());
+ foreach (BasicBlock *bb, function->basicBlocks())
+ if (!bb->isRemoved())
+ newSchedule.append(bb);
+ function->setScheduledBlocks(newSchedule);
+ function->renumberBasicBlocks();
+}
} // anonymous namespace
void LifeTimeInterval::setFrom(Stmt *from) {
@@ -3688,8 +3722,8 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
// search where to split the interval
for (int i = 0, ei = _ranges.size(); i < ei; ++i) {
- if (_ranges[i].start <= atPosition) {
- if (_ranges[i].end >= atPosition) {
+ if (_ranges.at(i).start <= atPosition) {
+ if (_ranges.at(i).end >= atPosition) {
// split happens in the middle of a range. Keep this range in both the old and the
// new interval, and correct the end/start later
_ranges.resize(i + 1);
@@ -3771,6 +3805,11 @@ bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTim
return r1.temp() < r2.temp();
}
+Optimizer::Optimizer(IR::Function *function)
+ : function(function)
+ , inSSA(false)
+{}
+
void Optimizer::run(QQmlEnginePrivate *qmlEngine)
{
#if defined(SHOW_SSA)
@@ -3778,12 +3817,9 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
<< " with " << function->basicBlocks.size() << " basic blocks." << endl << flush;
#endif
- // Number all basic blocks, so we have nice numbers in the dumps:
- for (int i = 0; i < function->basicBlocks.size(); ++i)
- function->basicBlocks[i]->index = i;
// showMeTheCode(function);
- cleanupBasicBlocks(function, true);
+ cleanupBasicBlocks(function);
function->removeSharedExpressions();
@@ -3795,7 +3831,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
// qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
// Calculate the dominator tree:
- DominatorTree df(function->basicBlocks);
+ DominatorTree df(function);
// qout << "Converting to SSA..." << endl;
convertToSSA(function, df);
@@ -3840,21 +3876,22 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine)
// condition is calculated to be always false) are not yet removed. This will choke the
// block scheduling, so remove those now.
// qout << "Cleaning up unreachable basic blocks..." << endl;
- cleanupBasicBlocks(function, false);
+ cleanupBasicBlocks(function);
// showMeTheCode(function);
// qout << "Doing block scheduling..." << endl;
// df.dumpImmediateDominators();
startEndLoops = BlockScheduler(function, df).go();
-// showMeTheCode(function);
+ showMeTheCode(function);
#ifndef QT_NO_DEBUG
- checkCriticalEdges(function->basicBlocks);
+ checkCriticalEdges(function->basicBlocks());
#endif
// qout << "Finished SSA." << endl;
inSSA = true;
} else {
+ removeUnreachleBlocks(function);
inSSA = false;
}
}
@@ -3865,13 +3902,13 @@ void Optimizer::convertOutOfSSA() {
// There should be no critical edges at this point.
- foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
MoveMapping moves;
foreach (BasicBlock *successor, bb->out) {
const int inIdx = successor->in.indexOf(bb);
Q_ASSERT(inIdx >= 0);
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (Phi *phi = s->asPhi()) {
moves.add(clone(phi->d->incoming[inIdx], function),
clone(phi->targetTemp, function)->asTemp());
@@ -3897,11 +3934,10 @@ void Optimizer::convertOutOfSSA() {
moves.insertMoves(bb, function, true);
}
- foreach (BasicBlock *bb, function->basicBlocks) {
- while (!bb->statements.isEmpty()) {
- if (Phi *phi = bb->statements.first()->asPhi()) {
- phi->destroyData();
- bb->statements.removeFirst();
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ while (!bb->isEmpty()) {
+ if (bb->statements().first()->asPhi()) {
+ bb->removeStatement(0);
} else {
break;
}
@@ -3909,14 +3945,14 @@ void Optimizer::convertOutOfSSA() {
}
}
-QVector<LifeTimeInterval> Optimizer::lifeRanges() const
+QVector<LifeTimeInterval> Optimizer::lifeTimeIntervals() const
{
Q_ASSERT(isInSSA());
LifeRanges lifeRanges(function, startEndLoops);
// lifeRanges.dump();
// showMeTheCode(function);
- return lifeRanges.ranges();
+ return lifeRanges.intervals();
}
QSet<Jump *> Optimizer::calculateOptionalJumps()
@@ -3924,16 +3960,18 @@ QSet<Jump *> Optimizer::calculateOptionalJumps()
QSet<Jump *> optional;
QSet<BasicBlock *> reachableWithoutJump;
- const int maxSize = function->basicBlocks.size();
+ const int maxSize = function->basicBlockCount();
optional.reserve(maxSize);
reachableWithoutJump.reserve(maxSize);
- for (int i = function->basicBlocks.size() - 1; i >= 0; --i) {
- BasicBlock *bb = function->basicBlocks[i];
+ for (int i = maxSize - 1; i >= 0; --i) {
+ BasicBlock *bb = function->basicBlock(i);
+ if (bb->isRemoved())
+ continue;
- if (Jump *jump = bb->statements.last()->asJump()) {
+ if (Jump *jump = bb->statements().last()->asJump()) {
if (reachableWithoutJump.contains(jump->target)) {
- if (bb->statements.size() > 1)
+ if (bb->statements().size() > 1)
reachableWithoutJump.clear();
optional.insert(jump);
reachableWithoutJump.insert(bb);
@@ -4048,12 +4086,12 @@ QList<IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, IR::Function *functio
QList<IR::Move *> newMoves;
newMoves.reserve(_moves.size());
- int insertionPoint = atEnd ? bb->statements.size() - 1 : 0;
+ int insertionPoint = atEnd ? bb->statements().size() - 1 : 0;
foreach (const Move &m, _moves) {
IR::Move *move = function->New<IR::Move>();
move->init(clone(m.to, function), clone(m.from, function));
move->swap = m.needsSwap;
- bb->statements.insert(insertionPoint++, move);
+ bb->insertStatementBefore(insertionPoint++, move);
newMoves.append(move);
}
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index 0fa6f146f3..372fe5cdeb 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -77,12 +77,12 @@ private:
public:
enum { Invalid = -1 };
- LifeTimeInterval()
+ explicit LifeTimeInterval(int rangeCapacity = 2)
: _end(Invalid)
, _reg(Invalid)
, _isFixedInterval(0)
, _isSplitFromInterval(0)
- {}
+ { _ranges.reserve(rangeCapacity); }
bool isValid() const { return _end != Invalid; }
@@ -92,8 +92,7 @@ public:
void setFrom(Stmt *from);
void addRange(int from, int to);
- Ranges ranges() const { return _ranges; }
- void reserveRanges(int capacity) { _ranges.reserve(capacity); }
+ const Ranges &ranges() const { return _ranges; }
int start() const { return _ranges.first().start; }
int end() const { return _end; }
@@ -139,11 +138,10 @@ public:
class Q_QML_PRIVATE_EXPORT Optimizer
{
+ Q_DISABLE_COPY(Optimizer)
+
public:
- Optimizer(Function *function)
- : function(function)
- , inSSA(false)
- {}
+ Optimizer(Function *function);
void run(QQmlEnginePrivate *qmlEngine);
void convertOutOfSSA();
@@ -153,7 +151,7 @@ public:
QHash<BasicBlock *, BasicBlock *> loopStartEndBlocks() const { return startEndLoops; }
- QVector<LifeTimeInterval> lifeRanges() const;
+ QVector<LifeTimeInterval> lifeTimeIntervals() const;
QSet<IR::Jump *> calculateOptionalJumps();
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri
index 5f3aec1c9a..2545c7836d 100644
--- a/src/qml/debugger/debugger.pri
+++ b/src/qml/debugger/debugger.pri
@@ -3,7 +3,6 @@ SOURCES += \
$$PWD/qqmlprofilerservice.cpp \
$$PWD/qqmldebugserver.cpp \
$$PWD/qqmlinspectorservice.cpp \
- $$PWD/qv4profilerservice.cpp \
$$PWD/qqmlenginedebugservice.cpp \
$$PWD/qdebugmessageservice.cpp \
$$PWD/qv4debugservice.cpp \
@@ -22,7 +21,6 @@ HEADERS += \
$$PWD/qqmldebugstatesdelegate_p.h \
$$PWD/qqmlinspectorservice_p.h \
$$PWD/qqmlinspectorinterface_p.h \
- $$PWD/qv4profilerservice_p.h \
$$PWD/qqmlenginedebugservice_p.h \
$$PWD/qqmldebug.h \
$$PWD/qdebugmessageservice_p.h \
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
index b1eb130ee8..0a99030897 100644
--- a/src/qml/debugger/qqmldebugserver.cpp
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -44,7 +44,6 @@
#include "qqmldebugservice_p_p.h"
#include "qqmlenginedebugservice_p.h"
#include "qv4debugservice_p.h"
-#include "qv4profilerservice_p.h"
#include "qdebugmessageservice_p.h"
#include "qqmlprofilerservice_p.h"
diff --git a/src/qml/debugger/qv4profilerservice.cpp b/src/qml/debugger/qv4profilerservice.cpp
deleted file mode 100644
index d8f69aecd9..0000000000
--- a/src/qml/debugger/qv4profilerservice.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** 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, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4profilerservice_p.h"
-#include "qqmlconfigurabledebugservice_p_p.h"
-
-#include <QtCore/QHash>
-#include <QtCore/QMutex>
-#include <QtCore/QWaitCondition>
-
-QT_BEGIN_NAMESPACE
-
-Q_GLOBAL_STATIC(QV4ProfilerService, v4ProfilerInstance)
-
-#if 0
-// ### FIXME: v4
-class DebugServiceOutputStream : public v8::OutputStream
-{
-public:
- DebugServiceOutputStream()
- : v8::OutputStream() {}
- void EndOfStream() {}
- WriteResult WriteAsciiChunk(char *rawData, int size)
- {
- QByteArray data;
- QQmlDebugStream ds(&data, QIODevice::WriteOnly);
- ds << QV4ProfilerService::V4SnapshotChunk << QByteArray(rawData, size);
- messages.append(data);
- return kContinue;
- }
- QList<QByteArray> messages;
-};
-#endif
-
-// convert to a QByteArray that can be sent to the debug client
-QByteArray QV4ProfilerData::toByteArray() const
-{
- QByteArray data;
- //### using QDataStream is relatively expensive
- QQmlDebugStream ds(&data, QIODevice::WriteOnly);
- ds << messageType << filename << functionname << lineNumber << totalTime << selfTime << treeLevel;
-
- return data;
-}
-
-class QV4ProfilerServicePrivate : public QQmlConfigurableDebugServicePrivate
-{
- Q_DECLARE_PUBLIC(QV4ProfilerService)
-
-public:
- QV4ProfilerServicePrivate()
- :initialized(false)
- {
- }
-
- // ### FIXME: v4
-// void takeSnapshot(v8::HeapSnapshot::Type);
-// void printProfileTree(const v8::CpuProfileNode *node, int level = 0);
-// void sendMessages();
-
- QList<QV4ProfilerData> m_data;
-
- bool initialized;
- QList<QString> m_ongoing;
-};
-
-QV4ProfilerService::QV4ProfilerService(QObject *parent)
- : QQmlConfigurableDebugService(*(new QV4ProfilerServicePrivate()), QStringLiteral("V8Profiler"), 1, parent)
-{
-}
-
-QV4ProfilerService::~QV4ProfilerService()
-{
-}
-
-QV4ProfilerService *QV4ProfilerService::instance()
-{
- return v4ProfilerInstance();
-}
-
-void QV4ProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
-{
- Q_D(QV4ProfilerService);
- QMutexLocker lock(configMutex());
-
- if (state() == newState)
- return;
-
- if (state() == Enabled) {
- foreach (const QString &title, d->m_ongoing) {
- QMetaObject::invokeMethod(this, "stopProfiling", Qt::BlockingQueuedConnection,
- Q_ARG(QString, title));
- }
- QMetaObject::invokeMethod(this, "sendProfilingData", Qt::BlockingQueuedConnection);
- }
-}
-
-void QV4ProfilerService::messageReceived(const QByteArray &message)
-{
- Q_D(QV4ProfilerService);
-
- QQmlDebugStream ds(message);
- QByteArray command;
- QByteArray option;
- QByteArray title;
- ds >> command >> option;
-
- QMutexLocker lock(configMutex());
-
- if (command == "V8PROFILER") {
- ds >> title;
- QString titleStr = QString::fromUtf8(title);
- if (option == "start") {
- QMetaObject::invokeMethod(this, "startProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
- } else if (option == "stop" && d->initialized) {
- QMetaObject::invokeMethod(this, "stopProfiling", Qt::QueuedConnection, Q_ARG(QString, titleStr));
- QMetaObject::invokeMethod(this, "sendProfilingData", Qt::QueuedConnection);
- }
- d->initialized = true;
- }
-
- if (command == "V8SNAPSHOT") {
- if (option == "full")
- QMetaObject::invokeMethod(this, "takeSnapshot", Qt::QueuedConnection);
- else if (option == "delete") {
- QMetaObject::invokeMethod(this, "deleteSnapshots", Qt::QueuedConnection);
- }
- }
-
- // wake up constructor in blocking mode
- stopWaiting();
-
- QQmlDebugService::messageReceived(message);
-}
-
-void QV4ProfilerService::startProfiling(const QString &title)
-{
- Q_D(QV4ProfilerService);
- // Start Profiling
-
- if (d->m_ongoing.contains(title))
- return;
-
-// v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
- // ### FIXME: v4
-// v8::CpuProfiler::StartProfiling(v8title);
-
- d->m_ongoing.append(title);
-
- // indicate profiling started
- QByteArray data;
- QQmlDebugStream ds(&data, QIODevice::WriteOnly);
- ds << (int)QV4ProfilerService::V4Started;
-
- sendMessage(data);
-}
-
-void QV4ProfilerService::stopProfiling(const QString &title)
-{
- Q_D(QV4ProfilerService);
- // Stop profiling
-
- if (!d->m_ongoing.contains(title))
- return;
- d->m_ongoing.removeOne(title);
-
-#if 0
- // ### FIXME: v4
- v8::HandleScope handle_scope;
- v8::Handle<v8::String> v8title = v8::String::New(reinterpret_cast<const uint16_t*>(title.data()), title.size());
- const v8::CpuProfile *cpuProfile = v8::CpuProfiler::StopProfiling(v8title);
- if (cpuProfile) {
- // can happen at start
- const v8::CpuProfileNode *rootNode = cpuProfile->GetTopDownRoot();
- d->printProfileTree(rootNode);
- } else {
-#endif
- // indicate completion, even without data
- QByteArray data;
- QQmlDebugStream ds(&data, QIODevice::WriteOnly);
- ds << (int)QV4ProfilerService::V4Complete;
-
- sendMessage(data);
-#if 0
- }
-#endif
-}
-
-void QV4ProfilerService::takeSnapshot()
-{
-// Q_D(QV4ProfilerService);
- // ### FIXME: v4
-// d->takeSnapshot(v8::HeapSnapshot::kFull);
-}
-
-void QV4ProfilerService::deleteSnapshots()
-{
- // ### FIXME: v4
-// v8::HeapProfiler::DeleteAllSnapshots();
-}
-
-void QV4ProfilerService::sendProfilingData()
-{
-// Q_D(QV4ProfilerService);
- // Send messages to client
- // ### FIXME: v4
-// d->sendMessages();
-}
-
-#if 0
-// ### FIXME: v4
-void QV4ProfilerServicePrivate::printProfileTree(const v8::CpuProfileNode *node, int level)
-{
- for (int index = 0 ; index < node->GetChildrenCount() ; index++) {
- const v8::CpuProfileNode* childNode = node->GetChild(index);
- QString scriptResourceName = QJSConverter::toString(childNode->GetScriptResourceName());
- if (scriptResourceName.length() > 0) {
-
- QV4ProfilerData rd = {(int)QV4ProfilerService::V4Entry, scriptResourceName,
- QJSConverter::toString(childNode->GetFunctionName()),
- childNode->GetLineNumber(), childNode->GetTotalTime(), childNode->GetSelfTime(), level};
- m_data.append(rd);
-
- // different nodes might have common children: fix at client side
- if (childNode->GetChildrenCount() > 0) {
- printProfileTree(childNode, level+1);
- }
- }
- }
-}
-
-void QV4ProfilerServicePrivate::takeSnapshot(v8::HeapSnapshot::Type snapshotType)
-{
- Q_Q(QV4ProfilerService);
-
- v8::HandleScope scope;
- v8::Handle<v8::String> title = v8::String::New("");
-
- DebugServiceOutputStream outputStream;
- const v8::HeapSnapshot *snapshot = v8::HeapProfiler::TakeSnapshot(title, snapshotType);
- snapshot->Serialize(&outputStream, v8::HeapSnapshot::kJSON);
- QList<QByteArray> messages = outputStream.messages;
-
- //indicate completion
- QByteArray data;
- QQmlDebugStream ds(&data, QIODevice::WriteOnly);
- ds << (int)QV4ProfilerService::V4SnapshotComplete;
- messages.append(data);
-
- q->sendMessages(messages);
-}
-
-void QV4ProfilerServicePrivate::sendMessages()
-{
- Q_Q(QV4ProfilerService);
-
- QList<QByteArray> messages;
- for (int i = 0; i < m_data.count(); ++i)
- messages.append(m_data.at(i).toByteArray());
- m_data.clear();
-
- //indicate completion
- QByteArray data;
- QQmlDebugStream ds(&data, QIODevice::WriteOnly);
- ds << (int)QV4ProfilerService::V4Complete;
- messages.append(data);
-
- q->sendMessages(messages);
-}
-#endif
-
-QT_END_NAMESPACE
diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
index 86715e93f1..f02c3da6af 100644
--- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
+++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc
@@ -148,8 +148,9 @@ Text {
For maximum interoperability with QML, \b {any property that is writable should
have an associated NOTIFY signal} that is emitted whenever the property value
has changed. This allows the property to be used with \l{Property
-Binding}{property binding}, which is an essential feature of QML that enables
-specific values to be updated whenever an associated property changes.
+Binding}{property binding}, which is an essential feature of QML that enforces
+relationships between properties by automatically updating a property whenever
+any of its dependencies change in value.
In the above example, the associated NOTIFY signal for the \c author property is
\c authorChanged, as specified in the Q_PROPERTY() macro call. This means that
diff --git a/src/qml/doc/src/javascript/expressions.qdoc b/src/qml/doc/src/javascript/expressions.qdoc
index c33daf7acc..79c11b3ac5 100644
--- a/src/qml/doc/src/javascript/expressions.qdoc
+++ b/src/qml/doc/src/javascript/expressions.qdoc
@@ -57,30 +57,28 @@ QML \l{QML Object Types}{object types} defined in \l{QML Documents}
{QML documents} can make use of JavaScript expressions which implement program
logic. There are four ways that JavaScript can be used in a QML document:
-\list
- \li \l{Property Attributes}{properties} can be
- assigned \l{Property Binding}{bindings} which are defined with
- JavaScript expressions, and which are automatically evaluated by the
- \l{QQmlEngine}{QML engine} when any properties accessed in the binding
- change, in order to ensure always-up-to-date property values. Binding
- expressions can also perform function evaluation as an explicit side
- effect
- \li \l{Signal Attributes}{signal handlers} can be defined
+\list 1
+ \li Relationships between \l{Property Attributes}{properties} are described
+ using JavaScript expressions in \l{Property Binding}{property bindings}.
+ When any of a property's \e dependencies change, the property is
+ automatically updated too, according to the specified relationship.
+ \li \l{Signal Attributes}{Signal handlers} can be defined
which are automatically evaluated when the object emits the associated
- signal
- \li \l{Method Attributes}{custom methods} can be defined
- in QML files as JavaScript functions
+ signal.
+ \li \l{Method Attributes}{Custom methods} can be defined
+ in QML files as JavaScript functions.
\li JavaScript files providing functions and variables can be
\l{Importing JavaScript Resources in QML}{imported} in a QML
- document
+ document.
\endlist
\section2 Property Bindings
-During startup, the QML engine will set up and initialize the property
-bindings. The JavaScript conditional operator is a valid property binding.
+In the following example, the \l Rectangle's \c color depends on the
+\l MouseArea's \c pressed property. This relationship is described using a
+conditional expression:
\qml
import QtQuick 2.0
@@ -100,7 +98,9 @@ Rectangle {
In fact, any JavaScript expression (no matter how complex) may be used in a
property binding definition, as long as the result of the expression is a
-value whose type can be assigned to the property.
+value whose type can be assigned to the property. This includes side effects.
+However, complex bindings and side effects are discouraged because they can
+reduce the performance, readability, and maintainability of the code.
There are two ways to define a property binding: the first (and most common)
is, as previously shown, in a \l{QML Object Attributes#Value Assignment on Initialization}
diff --git a/src/qml/doc/src/javascript/topic.qdoc b/src/qml/doc/src/javascript/topic.qdoc
index 40602b5017..f341816201 100644
--- a/src/qml/doc/src/javascript/topic.qdoc
+++ b/src/qml/doc/src/javascript/topic.qdoc
@@ -38,14 +38,11 @@ JavaScript to quickly develop both user-interfaces and application logic.
\section1 JavaScript Expressions
-QML has a deep JavaScript integration, and allows
-\l{Signal Attributes}{signal handlers}
-and \l{Method Attributes}{methods}
-to be defined in JavaScript. One of the other fundamental concepts of QML is
-the ability to bind property values to the result of complex expressions which
-can include properties from other objects. These
-\l{Property Binding}{property bindings}
-are JavaScript expressions.
+QML has a deep JavaScript integration, and allows \l{Signal Attributes}
+{signal handlers} and \l{Method Attributes}{methods} to be defined in JavaScript.
+Another core feature of QML is the ability to specify and enforce relationships
+between object properties using \l{Property Binding}{property bindings}, which
+are also defined using JavaScript.
See the documentation page titled
\l{qtqml-javascript-expressions.html}{JavaScript Expressions in QML Documents}
diff --git a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
index 845ca30b4f..af59afe1fb 100644
--- a/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/scope.qdoc
@@ -105,11 +105,9 @@ ListView {
\section1 Binding Scope Object
-Property bindings are the most common use of JavaScript in QML. Property
-bindings associate the result of a JavaScript expression with a property of an
-object. The object to which the bound property belongs is known as the binding's
-scope object. In this QML simple declaration the \l Item object is the
-binding's scope object.
+An object which has a \l{Property Binding}{property binding} is known has the
+binding's \e{scope object}. In the following example, the \l Item object is
+the binding's scope object.
\code
Item {
diff --git a/src/qml/doc/src/qmllanguageref/qmlreference.qdoc b/src/qml/doc/src/qmllanguageref/qmlreference.qdoc
index 0bc8f90238..5111990b46 100644
--- a/src/qml/doc/src/qmllanguageref/qmlreference.qdoc
+++ b/src/qml/doc/src/qmllanguageref/qmlreference.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -28,14 +28,14 @@
/*!
\page qmlreference.html
\title The QML Reference
-\brief A declarative language for application development
+\brief A multi-paradigm language for application development
-QML is a declarative language for creating highly dynamic applications. With
+QML is a multi-paradigm language for creating highly dynamic applications. With
QML, application building blocks such as UI components are \e declared and
-various properties set to define the application behavior. When coupled with
-JavaScript, application behavior becomes scriptable. In addition, QML heavily
-uses Qt, which allows types and other Qt features to be accessible directly from
-QML applications.
+various properties set to define the application behavior. Application behavior
+can be further scripted through JavaScript, which is a subset of the language.
+In addition, QML heavily uses Qt, which allows types and other Qt features to
+be accessible directly from QML applications.
This reference guide describes the features of the QML language. Many of the
QML types in the guide originate from the \l{Qt QML} or \l{Qt Quick}
diff --git a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
index cdfab3cd3f..8d71a04ac2 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/basics.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -29,8 +29,12 @@
\title QML Syntax Basics
\brief Description of the basics of QML syntax
-QML is a declarative language that enables objects to be defined in terms of their attributes
-and how they relate and respond to changes in other objects. In contrast to imperative code, where changes in attributes and behavior are expressed through a series of statements that are processed step by step, the declarative QML syntax integrates attribute and behavioral changes directly into the definitions of individual objects.
+QML is a multi-paradigm language that enables objects to be defined in terms of their attributes
+and how they relate and respond to changes in other objects. In contrast to purely imperative code,
+where changes in attributes and behavior are expressed through a series of statements that are
+processed step by step, QML's declarative syntax integrates attribute and behavioral changes
+directly into the definitions of individual objects. These attribute definitions can then include
+imperative code, in the case where complex custom application behavior is needed.
QML source code is generally loaded by the engine through QML \e documents, which are
standalone documents of QML code. These can be used to define \l {QML Object Types}{QML object types} that can then be reused throughout an application.
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 46a225ee30..3e48ec2308 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -189,16 +189,16 @@ which was then imported by the client), then a property of type
\c ColorfulButton would also be valid.
-\section3 Values of Property Attributes
+\section3 Assigning Values to Property Attributes
-The value of a property of an object instance may specified in an
-object declaration in two separate ways:
+The value of a property of an object instance may specified in two separate ways:
\list
\li a value assignment on initialization
\li an imperative value assignment
\endlist
-The value in either case may be either a binding expression or a static value.
+In either case, the value may be either a \e static value or a \e {binding expression}
+value.
\section4 Value Assignment on Initialization
@@ -251,10 +251,11 @@ Rectangle {
}
\endqml
-\section4 Valid Property Values
+\section3 Static Values and Binding Expression Values
As previously noted, there are two kinds of values which may be assigned to a
-property: static values, and binding expression values.
+property: \e static values, and \e {binding expression} values. The latter are
+also known as \l{Property Binding}{property bindings}.
\table
\header
@@ -263,20 +264,21 @@ property: static values, and binding expression values.
\row
\li Static Value
- \li A value whose type matches (or can be converted to) that of
- the property may be assigned to the property.
+ \li A constant value which does not depend on other properties.
\row
\li Binding Expression
- \li A JavaScript expression which may be evaluated, whose result is a
- value whose type matches (or can be converted to) that of the
- property may be assigned to the property. The expression will be
- automatically re-evaluated (and the new result assigned to the
- property) by the QML engine should the value of any properties accessed
- during evaluation change.
+ \li A JavaScript expression which describes a property's relationship with
+ other properties. The variables in this expression are called the
+ property's \e dependencies.
+
+ The QML engine enforces the relationship between a property and its
+ dependencies. When any of the dependencies change in value, the QML
+ engine automatically re-evaluates the binding expression and assigns
+ the new result to the property.
\endtable
-An example of these two types of values being assigned to properties follows:
+Here is an example that shows both kinds of values being assigned to properties:
\qml
import QtQuick 2.0
@@ -294,19 +296,11 @@ Rectangle {
}
\endqml
-In many cases, a string value may be converted automatically to a
-different type of value, as QML provides string converters for many property
-types (thus you can assign the string \c "red" to a color property).
-
-It is important to note that in order to assign a binding expression to a
-property in an imperative value assignment, the right-hand-side of
-the assignment (the binding expression) must be a function returned by the
-\l{Qt::binding()}{Qt.binding()} function, which returns a value of the
-appropriate type. A binding expression value may be assigned to a property
-via an initialization value assignment without using that function (and, in
-fact, attempting to do so will result in an error). See the documentation
-about \l{qtqml-syntax-propertybinding.html}{property binding} for more
-information on the topic.
+\note To assign a binding expression imperatively, the binding expression
+must be contained in a function that is passed into \l{Qt::binding()}{Qt.binding()},
+and then the value returned by Qt.binding() must be assigned to the property.
+In contrast, Qt.binding() must not be used when assigning a binding expression
+upon initialization. See \l{Property Binding} for more information.
\section3 Type Safety
@@ -324,7 +318,7 @@ property int volume: "four" // generates an error; the property's object will n
Likewise if a property is assigned a value of the wrong type during run time,
the new value will not be assigned, and an error will be generated.
-As noted in a previous section, some property types do not have a natural
+Some property types do not have a natural
value representation, and for those property types the QML engine
automatically performs string-to-typed-value conversion. So, for example,
even though properties of the \c color type store colors and not strings,
diff --git a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
index 653fe2391e..4f4d6ed9d8 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
@@ -30,32 +30,44 @@
\title Property Binding
\brief binding object properties
-To make the fullest use of QML and its built-in support for implementing dynamic object behavioral changes, most QML objects will use \e {property binding}. This is a core feature of QML that allows objects to automatically update their properties in response to changing attributes in other objects or the occurrence of some external event.
+An object's property can be assigned a static value which stays constant until it
+is explicitly assigned a new value. However, to make the fullest use of QML and its
+built-in support for dynamic object behaviors, most QML objects use \e {property bindings}.
-When an object's property is assigned a value, it can either be assigned a static value, or \e bound to a JavaScript expression. In the first case, the property's value will not change unless a new value is assigned to the property. In the latter case, a \e {property binding} is created and the property's value is automatically updated by the QML engine whenever the value of the evaluated expression changes.
+Property bindings are a core feature of QML that lets developers specify relationships
+between different object properties. When a property's \e dependencies change in
+value, the property is automatically updated according to the specified relationship.
+Behind the scenes, the QML engine monitors the property's dependencies (that is,
+the variables in the binding expression). When a change is detected, the QML engine
+re-evaluates the binding expression and applies the new result to the property.
\section1 Overview
-To create a property binding, a property is assigned an expression that evaluates to the desired value. At its simplest, an expression may simply be a reference to another object's property. Take the following example, where the blue \l Rectangle's \c height is bound to the height of its parent:
+To create a property binding, a property is assigned a JavaScript expression that
+evaluates to the desired value. At its simplest, a binding may be a reference to
+another property. Take the following example, where the blue \l Rectangle's height
+is bound to the height of its parent:
\qml
Rectangle {
width: 200; height: 200
Rectangle {
- width: 100; height: parent.height
+ width: 100
+ height: parent.height
color: "blue"
}
}
\endqml
-Whenever the \c height of the parent item changes, the \c height of the blue rectangle will update to be of the same value.
+Whenever the height of the parent rectangle changes, the height of the blue
+rectangle automatically updates to be of the same value.
-Furthermore, a binding can contain any valid JavaScript expression or
-statement, as QML uses a standards compliant JavaScript engine. Below are
-valid bindings that could be substituted for the \c height binding from the
-above example:
+A binding can contain any valid JavaScript expression or statement, as QML uses
+a standards compliant JavaScript engine. Bindings can access object properties,
+call methods and use built-in JavaScript objects such as \c Date and \c Math.
+Below are other possible bindings for the previous example:
\code
height: parent.height / 2
@@ -74,16 +86,16 @@ height: {
height: someMethodThatReturnsHeight()
\endcode
-Whenever the value of \c parent.height changes, the QML engine will re-evaluate the above expression and assign the blue rectangle's \c width property with the appropriate updated value.
-
-Bindings can access object properties, call methods and use built-in JavaScript objects such as \c Date and \c Math. Here is an example with various valid bindings:
+Below is a more complex example involving more objects and types:
\qml
Column {
+ id: column
width: 200
height: 200
Rectangle {
+ id: topRect
width: Math.max(bottomRect.width, parent.width/2)
height: (parent.height / 3) + 10
color: "yellow"
@@ -103,15 +115,33 @@ Column {
}
\endqml
-While syntactically bindings can be of arbitrary complexity, if a binding starts to become overly complex - such as involving multiple lines, or imperative loops - it may be better to refactor the component entirely, or at least factor the binding out into a separate function.
+In the previous example,
+\list
+\li \c topRect.width depends on \c bottomRect.width and \c column.width
+\li \c topRect.height depends on \c column.height
+\li \c bottomRect.color depends on \c myTextInput.text.length
+\endlist
+
+Syntactically, bindings are allowed to be of arbitrary complexity. However, if
+a binding is overly complex - such as involving multiple lines, or imperative
+loops - it could indicate that the binding is being used for more than describing
+property relationships. Complex bindings can reduce code performance, readability,
+and maintainability. It may be a good idea to redesign components that have
+complex bindings, or at least factor the binding out into a separate function.
\keyword qml-javascript-assignment
\section1 Creating Property Bindings from JavaScript
-Once a property has been bound to an expression, the property is set to be automatically updated as necessary. However, be aware that if the property is later assigned a static value from a JavaScript statement, this will remove the binding.
+A property with a binding is automatically updated as necessary. However, if the
+property is later assigned a static value from a JavaScript statement, the binding
+will be removed.
-For example, the \c height of the \l Rectangle below is initially bound to be twice its \c width. However, when the space key is pressed, the \c height value is changed to be three times its \c width. At this point, the \c height is assigned the currently evaluated result of \c width*3 and \e {the height will no longer be automatically updated whenever the width changes}. The assignment of the static value removes the binding.
+For example, the \l Rectangle below initially ensures that its \c height is always
+twice its \c width. However, when the space key is pressed, the current value
+of \c {width*3} will be assigned to \c height as a \e static value. After that,
+\e {the \c height will remain fixed at this value, even if the \c width changes}.
+The assignment of the static value removes the binding.
\qml
import QtQuick 2.0
@@ -127,7 +157,10 @@ Rectangle {
}
\endqml
-If the intention is to remove the binding, then this is not a problem. However if the intention is to create a new binding of \c width*3 then the property must be assigned a Qt.binding() value instead. This is done by passing a function to Qt.binding() that returns the desired result:
+If the intention is to give the rectangle a fixed height and stop automatic
+updates, then this is not a problem. However, if the intention is to establish
+a new relationship between \c width and \c height, then the new binding
+expression must be wrapped in the Qt.binding() function instead:
\qml
import QtQuick 2.0
@@ -143,22 +176,21 @@ Rectangle {
}
\endqml
-Now when the space key is pressed, a new binding of \c width*3 is assigned, instead of simply removing the initial binding.
+Now, after the space key is pressed, the rectangle's height will continue
+auto-updating to always be three times its width.
\section2 Using \c this with Property Binding
-When creating a property binding from JavaScript, QML allows the use of the \c
-this keyword to refer to the object to which the property binding will be
-assigned. This allows one to explicitly refer to a property within an object
-when there may be ambiguity about the exact property that should be used for the
-binding.
+When creating a property binding from JavaScript, the \c this keyword can be used
+to refer to the object which receives the binding. This is helpful for resolving
+ambiguities with property names.
For example, the \c Component.onCompleted handler below is defined within the
-scope of the \l Item, and references to \c width within this scope would refer
-to the \l Item's width, rather than that of the \l Rectangle. To bind the \l
-Rectangle's \c height to its own \c width, the function passed to Qt.binding()
-needs to explicitly refer to \c this.width rather than just \c width.
+scope of the \l Item. In this scope, \c width refers to the \l Item's width, not
+the \l Rectangle's width. To bind the \l Rectangle's \c height to its own \c width,
+the binding expression must explicitly refer to \c this.width (or alternatively,
+\c{rect.width}):
\qml
Item {
@@ -178,12 +210,7 @@ Item {
}
\endqml
-In this case, the function could also have referred to \c rect.width rather than
-\c this.width.
-
-Note that the value of \c this is not defined outside of its use in property binding.
+\note The value of \c this is not defined outside of property bindings.
See \l {JavaScript Environment Restrictions} for details.
-
-
*/
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index 32f9d7e867..6fde517e1f 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -446,6 +446,7 @@ public:
struct CallToLink {
Call call;
FunctionPtr externalFunction;
+ Label label;
const char* functionName;
};
struct PointerToValue {
@@ -473,6 +474,7 @@ public:
ctl.call = call();
ctl.externalFunction = function;
ctl.functionName = functionName;
+ ctl.label = label();
_callsToLink.append(ctl);
}
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index 74024752cf..344bbf56e0 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -299,13 +299,19 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (IR::Const *c = rightSource->asConst()) {
- as->lshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
+ if (int(c->value) == 0)
+ as->move(as->toInt32Register(leftSource, Assembler::ReturnValueRegister), targetReg);
+ else
+ as->lshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
+ Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
} else {
as->move(as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
- if (!rightSource->asConst())
- as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister);
+#if CPU(ARM) || CPU(X86) || CPU(X86_64)
+ // The ARM assembler will generate this for us, and Intel will do it on the CPU.
+#else
+ as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister);
+#endif
as->lshift32(as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg);
}
as->storeInt32(targetReg, target);
@@ -314,12 +320,19 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (IR::Const *c = rightSource->asConst()) {
- as->rshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
+ if (int(c->value) == 0)
+ as->move(as->toInt32Register(leftSource, Assembler::ReturnValueRegister), targetReg);
+ else
+ as->rshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
+ Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
} else {
as->move(as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
+#if CPU(ARM) || CPU(X86) || CPU(X86_64)
+ // The ARM assembler will generate this for us, and Intel will do it on the CPU.
+#else
as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister);
+#endif
as->rshift32(as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg);
}
as->storeInt32(targetReg, target);
@@ -328,12 +341,19 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta
Q_ASSERT(rightSource->type == IR::SInt32Type);
if (IR::Const *c = rightSource->asConst()) {
- as->urshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
+ if (int(c->value) == 0)
+ as->move(as->toInt32Register(leftSource, Assembler::ReturnValueRegister), targetReg);
+ else
+ as->urshift32(as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
+ Assembler::TrustedImm32(int(c->value) & 0x1f), targetReg);
} else {
as->move(as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
+#if CPU(ARM) || CPU(X86) || CPU(X86_64)
+ // The ARM assembler will generate this for us, and Intel will do it on the CPU.
+#else
as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister);
+#endif
as->urshift32(as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister, targetReg);
}
as->storeUInt32(targetReg, target);
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 051677d84a..3307fcc0d1 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -115,7 +115,13 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput, const Q
it != end; ++it) {
QByteArray ptrString = QByteArray::number(quintptr(it.key()), 16);
ptrString.prepend("0x");
- processedOutput = processedOutput.replace(ptrString, it.value());
+ int idx = processedOutput.indexOf(ptrString);
+ if (idx < 0)
+ continue;
+ idx = processedOutput.lastIndexOf('\n', idx);
+ if (idx < 0)
+ continue;
+ processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; call ") + it.value());
}
fprintf(stderr, "%s\n", processedOutput.constData());
fflush(stderr);
@@ -143,7 +149,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
QHash<void*, const char*> functions;
foreach (CallToLink ctl, _callsToLink) {
linkBuffer.link(ctl.call, ctl.externalFunction);
- functions[ctl.externalFunction.value()] = ctl.functionName;
+ functions[linkBuffer.locationOf(ctl.label).dataLocation()] = ctl.functionName;
}
foreach (const DataLabelPatch &p, _dataLabelPatches)
@@ -336,12 +342,14 @@ void InstructionSelection::run(int functionIndex)
_as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
int lastLine = 0;
- for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
- IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
- _block = _function->basicBlocks[i];
+ for (int i = 0, ei = _function->basicBlockCount(); i != ei; ++i) {
+ IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlock(i + 1) : 0;
+ _block = _function->basicBlock(i);
+ if (_block->isRemoved())
+ continue;
_as->registerBlock(_block, nextBlock);
- foreach (IR::Stmt *s, _block->statements) {
+ foreach (IR::Stmt *s, _block->statements()) {
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lineNumber));
@@ -366,14 +374,14 @@ void InstructionSelection::run(int functionIndex)
qSwap(_removableJumps, removableJumps);
}
-void *InstructionSelection::addConstantTable(QVector<Primitive> *values)
+const void *InstructionSelection::addConstantTable(QVector<Primitive> *values)
{
compilationUnit->constantValues.append(*values);
values->clear();
QVector<QV4::Primitive> &finalValues = compilationUnit->constantValues.last();
finalValues.squeeze();
- return finalValues.data();
+ return finalValues.constData();
}
QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
@@ -1612,10 +1620,10 @@ Assembler::ImplicitAddress Assembler::ConstantTable::loadValueAddress(const Prim
void Assembler::ConstantTable::finalize(JSC::LinkBuffer &linkBuffer, InstructionSelection *isel)
{
- void *tablePtr = isel->addConstantTable(&_values);
+ const void *tablePtr = isel->addConstantTable(&_values);
foreach (DataLabelPtr label, _toPatch)
- linkBuffer.patch(label, tablePtr);
+ linkBuffer.patch(label, const_cast<void *>(tablePtr));
}
bool InstructionSelection::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 0e8db93e85..d589223d7e 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -72,7 +72,7 @@ public:
virtual void run(int functionIndex);
- void *addConstantTable(QVector<QV4::Primitive> *values);
+ const void *addConstantTable(QVector<QV4::Primitive> *values);
protected:
virtual QV4::CompiledData::CompilationUnit *backendCompileStep();
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index ba128c1036..b5765cd589 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -97,8 +97,8 @@ public:
void collect(IR::Function *function)
{
- foreach (BasicBlock *bb, function->basicBlocks) {
- foreach (Stmt *s, bb->statements) {
+ foreach (BasicBlock *bb, function->basicBlocks()) {
+ foreach (Stmt *s, bb->statements()) {
Q_ASSERT(s->id > 0);
_currentStmt = s;
s->accept(this);
@@ -705,8 +705,8 @@ public:
for (int i = 0, ei = _intervals.size(); i != ei; ++i)
_unprocessed[i] = &_intervals[i];
- _liveAtStart.reserve(function->basicBlocks.size());
- _liveAtEnd.reserve(function->basicBlocks.size());
+ _liveAtStart.reserve(function->basicBlockCount());
+ _liveAtEnd.reserve(function->basicBlockCount());
}
void run() {
@@ -718,13 +718,14 @@ public:
private:
void renumber()
{
- foreach (BasicBlock *bb, _function->basicBlocks) {
+ foreach (BasicBlock *bb, _function->basicBlocks()) {
+ QVector<Stmt *> statements = bb->statements();
QVector<Stmt *> newStatements;
- newStatements.reserve(bb->statements.size() + 7);
+ newStatements.reserve(bb->statements().size() + 7);
bool seenFirstNonPhiStmt = false;
- for (int i = 0, ei = bb->statements.size(); i != ei; ++i) {
- _currentStmt = bb->statements[i];
+ for (int i = 0, ei = statements.size(); i != ei; ++i) {
+ _currentStmt = statements[i];
_loads.clear();
_stores.clear();
addNewIntervals();
@@ -766,7 +767,7 @@ private:
}
#endif
- bb->statements = newStatements;
+ bb->setStatements(newStatements);
}
}
@@ -833,7 +834,7 @@ private:
void resolve()
{
- foreach (BasicBlock *bb, _function->basicBlocks) {
+ foreach (BasicBlock *bb, _function->basicBlocks()) {
foreach (BasicBlock *bbOut, bb->out)
resolveEdge(bb, bbOut);
}
@@ -848,11 +849,11 @@ private:
MoveMapping mapping;
- const int predecessorEnd = predecessor->statements.last()->id; // the terminator is always last and always has an id set...
+ const int predecessorEnd = predecessor->terminator()->id; // the terminator is always last and always has an id set...
Q_ASSERT(predecessorEnd > 0); // ... but we verify it anyway for good measure.
int successorStart = -1;
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (s && s->id > 0) {
successorStart = s->id;
break;
@@ -869,7 +870,7 @@ private:
Expr *moveFrom = 0;
if (it->start() == successorStart) {
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (!s || s->id < 1)
continue;
if (Phi *phi = s->asPhi()) {
@@ -925,14 +926,14 @@ private:
Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole);
if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) {
- const int successorEnd = successor->statements.last()->id;
+ const int successorEnd = successor->terminator()->id;
const int idx = successor->in.indexOf(predecessor);
foreach (const Use &use, _info->uses(it->temp())) {
if (use.pos == static_cast<unsigned>(successorStart)) {
// only check the current edge, not all other possible ones. This is
// important for phi nodes: they have uses that are only valid when
// coming in over a specific edge.
- foreach (Stmt *s, successor->statements) {
+ foreach (Stmt *s, successor->statements()) {
if (Phi *phi = s->asPhi()) {
Q_ASSERT(it->temp().index != phi->targetTemp->index);
Q_ASSERT(phi->d->incoming[idx]->asTemp() == 0
@@ -1076,6 +1077,8 @@ RegisterAllocator::RegisterAllocator(const QVector<int> &normalRegisters, const
{
Q_ASSERT(normalRegisters.size() >= 2);
Q_ASSERT(fpRegisters.size() >= 2);
+ _active.reserve((normalRegisters.size() + fpRegisters.size()) * 2);
+ _inactive.reserve(_active.size());
}
RegisterAllocator::~RegisterAllocator()
@@ -1084,13 +1087,16 @@ RegisterAllocator::~RegisterAllocator()
void RegisterAllocator::run(IR::Function *function, const Optimizer &opt)
{
+ _lastAssignedRegister.reserve(function->tempCount);
+ _assignedSpillSlots.reserve(function->tempCount);
_activeSpillSlots.resize(function->tempCount);
#ifdef DEBUG_REGALLOC
qDebug() << "*** Running regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***";
#endif // DEBUG_REGALLOC
- _unhandled = opt.lifeRanges();
+ _unhandled = opt.lifeTimeIntervals();
+ _handled.reserve(_unhandled.size());
_info.reset(new RegAllocInfo);
_info->collect(function);
@@ -1111,10 +1117,6 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt)
prepareRanges();
- _handled.reserve(_unhandled.size());
- _active.reserve(32);
- _inactive.reserve(16);
-
Optimizer::showMeTheCode(function);
linearScan();
@@ -1135,46 +1137,55 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt)
#endif // DEBUG_REGALLOC
}
-static inline LifeTimeInterval createFixedInterval(int reg, bool isFP, int rangeCount)
+static inline LifeTimeInterval createFixedInterval(int rangeCount)
{
+ LifeTimeInterval i(rangeCount);
+ i.setReg(0);
+
Temp t;
- t.init(Temp::PhysicalRegister, reg, 0);
- t.type = isFP ? IR::DoubleType : IR::SInt32Type;
- LifeTimeInterval i;
+ t.init(Temp::PhysicalRegister, 0, 0);
+ t.type = IR::SInt32Type;
i.setTemp(t);
- i.setReg(reg);
- i.setFixedInterval(true);
- i.reserveRanges(rangeCount);
+
return i;
}
+static inline LifeTimeInterval cloneFixedInterval(int reg, bool isFP, LifeTimeInterval lti)
+{
+ lti.setReg(reg);
+ lti.setFixedInterval(true);
+
+ Temp t;
+ t.init(Temp::PhysicalRegister, reg, 0);
+ t.type = isFP ? IR::DoubleType : IR::SInt32Type;
+ lti.setTemp(t);
+
+ return lti;
+}
+
void RegisterAllocator::prepareRanges()
{
+ LifeTimeInterval ltiWithCalls = createFixedInterval(_info->calls().size());
+ foreach (int callPosition, _info->calls())
+ ltiWithCalls.addRange(callPosition, callPosition);
+
const int regCount = _normalRegisters.size();
- _fixedRegisterRanges.resize(regCount);
- for (int reg = 0; reg < regCount; ++reg)
- _fixedRegisterRanges[reg] = createFixedInterval(reg, false, _info->calls().size());
+ _fixedRegisterRanges.reserve(regCount);
+ for (int reg = 0; reg < regCount; ++reg) {
+ LifeTimeInterval lti = cloneFixedInterval(reg, false, ltiWithCalls);
+ _fixedRegisterRanges.append(lti);
+ if (lti.isValid())
+ _active.append(lti);
+ }
const int fpRegCount = _fpRegisters.size();
- _fixedFPRegisterRanges.resize(fpRegCount);
+ _fixedFPRegisterRanges.reserve(fpRegCount);
for (int fpReg = 0; fpReg < fpRegCount; ++fpReg) {
- _fixedFPRegisterRanges[fpReg] = createFixedInterval(fpReg, true, _info->calls().size());
+ LifeTimeInterval lti = cloneFixedInterval(fpReg, true, ltiWithCalls);
+ _fixedFPRegisterRanges.append(lti);
+ if (lti.isValid())
+ _active.append(lti);
}
-
- foreach (int callPosition, _info->calls()) {
- for (int reg = 0; reg < regCount; ++reg)
- _fixedRegisterRanges[reg].addRange(callPosition, callPosition);
- for (int fpReg = 0; fpReg < fpRegCount; ++fpReg)
- _fixedFPRegisterRanges[fpReg].addRange(callPosition, callPosition);
- }
- for (int reg = 0; reg < regCount; ++reg)
- if (_fixedRegisterRanges[reg].isValid())
- _active.append(_fixedRegisterRanges[reg]);
- for (int fpReg = 0; fpReg < fpRegCount; ++fpReg)
- if (_fixedFPRegisterRanges[fpReg].isValid())
- _active.append(_fixedFPRegisterRanges[fpReg]);
-
- std::sort(_active.begin(), _active.end(), LifeTimeInterval::lessThan);
}
void RegisterAllocator::linearScan()
@@ -1186,7 +1197,7 @@ void RegisterAllocator::linearScan()
// check for intervals in active that are handled or inactive
for (int i = 0; i < _active.size(); ) {
- const LifeTimeInterval &it = _active[i];
+ const LifeTimeInterval &it = _active.at(i);
if (it.end() < position) {
if (!it.isFixedInterval())
_handled += it;
@@ -1201,7 +1212,7 @@ void RegisterAllocator::linearScan()
// check for intervals in inactive that are handled or active
for (int i = 0; i < _inactive.size(); ) {
- LifeTimeInterval &it = _inactive[i];
+ const LifeTimeInterval &it = _inactive.at(i);
if (it.end() < position) {
if (!it.isFixedInterval())
_handled += it;
@@ -1448,8 +1459,8 @@ void RegisterAllocator::allocateBlockedReg(LifeTimeInterval &current, const int
splitInactiveAtEndOfLifetimeHole(reg, needsFPReg, position);
// make sure that current does not intersect with the fixed interval for reg
- const LifeTimeInterval &fixedRegRange = needsFPReg ? _fixedFPRegisterRanges[reg]
- : _fixedRegisterRanges[reg];
+ const LifeTimeInterval &fixedRegRange = needsFPReg ? _fixedFPRegisterRanges.at(reg)
+ : _fixedRegisterRanges.at(reg);
int ni = nextIntersection(current, fixedRegRange, position);
if (ni != -1) {
#ifdef DEBUG_REGALLOC
@@ -1611,7 +1622,7 @@ void RegisterAllocator::assignSpillSlot(const Temp &t, int startPos, int endPos)
return;
for (int i = 0, ei = _activeSpillSlots.size(); i != ei; ++i) {
- if (_activeSpillSlots[i] < startPos) {
+ if (_activeSpillSlots.at(i) < startPos) {
_activeSpillSlots[i] = endPos;
_assignedSpillSlots.insert(t, i);
return;
diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp
index 9e02310815..6dcfafaa27 100644
--- a/src/qml/jsapi/qjsvalueiterator.cpp
+++ b/src/qml/jsapi/qjsvalueiterator.cpp
@@ -135,13 +135,10 @@ bool QJSValueIterator::hasNext() const
/*!
Advances the iterator by one position.
- Returns true if there is at least one item ahead of the iterator
- (i.e. the iterator is \e not at the back of the property sequence);
+ Returns true if there was at least one item ahead of the iterator
+ (i.e. the iterator was \e not already at the back of the property sequence);
otherwise returns false.
- Calling this function on an iterator located at the back of the
- container leads to undefined results.
-
\sa hasNext(), name()
*/
bool QJSValueIterator::next()
@@ -159,7 +156,7 @@ bool QJSValueIterator::next()
QV4::Scope scope(v4);
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes);
- return !!d_ptr->nextName || d_ptr->nextIndex != UINT_MAX;
+ return !!d_ptr->currentName || d_ptr->currentIndex != UINT_MAX;
}
/*!
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index ddced40714..a07cbf2da5 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -60,7 +60,7 @@ struct ValueRef;
namespace CompiledData {
struct CompilationUnit;
struct Function;
-};
+}
struct CallContext;
struct CallContext;
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index fc94862bfd..ceef88455b 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -633,7 +633,7 @@ static double getLocalTZA()
time_t locl = mktime(&t);
gmtime_r(&curr, &t);
time_t globl = mktime(&t);
- return double(locl - globl) * 1000.0;
+ return (double(locl) - double(globl)) * 1000.0;
#else
TIME_ZONE_INFORMATION tzInfo;
GetTimeZoneInformation(&tzInfo);
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index 8ce1146ac9..d54f29b89a 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -52,7 +52,7 @@
namespace WTF {
class PageAllocation;
-};
+}
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index b5dc6742f9..a00231c3a1 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -189,8 +189,8 @@ enum PropertyFlag {
Attr_Invalid = 0xff
};
-Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag);
-Q_DECLARE_OPERATORS_FOR_FLAGS(PropertyFlags);
+Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
+Q_DECLARE_OPERATORS_FOR_FLAGS(PropertyFlags)
struct PropertyAttributes
{
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index d378d77bb0..610bbcfe1e 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -69,7 +69,6 @@
#include <private/qqmlenginecontrolservice_p.h>
#include "qqmlincubator.h"
#include "qqmlabstracturlinterceptor.h"
-#include <private/qv4profilerservice_p.h>
#include <private/qqmlboundsignal_p.h>
#include <QtCore/qstandardpaths.h>
@@ -823,7 +822,6 @@ void QQmlEnginePrivate::init()
isDebugging = true;
QQmlEngineDebugService::instance();
QV4DebugService::instance();
- QV4ProfilerService::instance();
QQmlProfilerService::instance();
QDebugMessageService::instance();
QQmlEngineControlService::instance();
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index 04862379be..8ee4a542de 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -60,23 +60,27 @@ QQmlPlatform::~QQmlPlatform()
QString QQmlPlatform::os()
{
#if defined(Q_OS_ANDROID)
- return QLatin1String("android");
+ return QStringLiteral("android");
#elif defined(Q_OS_BLACKBERRY)
- return QLatin1String("blackberry");
+ return QStringLiteral("blackberry");
#elif defined(Q_OS_IOS)
- return QLatin1String("ios");
+ return QStringLiteral("ios");
#elif defined(Q_OS_MAC)
- return QLatin1String("osx");
+ return QStringLiteral("osx");
#elif defined(Q_OS_WINCE)
- return QLatin1String("wince");
+ return QStringLiteral("wince");
+#elif defined(Q_OS_WINPHONE)
+ return QStringLiteral("winphone");
+#elif defined(Q_OS_WINRT)
+ return QStringLiteral("winrt");
#elif defined(Q_OS_WIN)
- return QLatin1String("windows");
+ return QStringLiteral("windows");
#elif defined(Q_OS_LINUX)
- return QLatin1String("linux");
+ return QStringLiteral("linux");
#elif defined(Q_OS_UNIX)
- return QLatin1String("unix");
+ return QStringLiteral("unix");
#else
- return QLatin1String("unknown");
+ return QStringLiteral("unknown");
#endif
}
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 5e0e68472d..d0d6839bdc 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -48,7 +48,6 @@
#include <private/qqmllocale_p.h>
#include <private/qv8engine_p.h>
-#include <private/qv4profilerservice_p.h>
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlglobal_p.h>
@@ -1208,18 +1207,16 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
/*!
\qmlmethod Qt::binding(function)
- Returns a JS object representing a binding expression which may be
- assigned to any property in imperative code to cause a binding
- assignment.
+ Returns a JavaScript object representing a \l{Property Binding}{property binding}.
- There are two main use-cases for the function: firstly, in imperative
- JavaScript code to cause a binding assignment:
+ There are two main use-cases for the function: firstly, to apply a
+ property binding imperatively from JavaScript code:
\snippet qml/qtBinding.1.qml 0
- and secondly, when defining initial property values of dynamically
- constructed objects (via Component.createObject() or
- Loader.setSource()) as being bound to the result of an expression.
+ and secondly, to apply a property binding when initializing property values
+ of dynamically constructed objects (via \l{Component::createObject()}
+ {Component.createObject()} or \l{Loader::setSource()}{Loader.setSource()}).
For example, assuming the existence of a DynamicText component:
\snippet qml/DynamicText.qml 0
@@ -1245,8 +1242,8 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
\snippet qml/qtBinding.4.qml 0
- \note In \l {Qt Quick 1}, all function assignment was treated as
- binding assignment, so the Qt.binding() function is new in
+ \note In \l {Qt Quick 1}, all function assignments were treated as
+ binding assignments. The Qt.binding() function is new to
\l {Qt Quick}{Qt Quick 2}.
\since 5.0
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index be479ee17d..4591d42710 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -1521,9 +1521,64 @@ void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelInd
_q_itemsChanged(begin.row(), end.row() - begin.row() + 1, roles);
}
-void QQmlDelegateModel::_q_layoutChanged()
+void QQmlDelegateModel::_q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
{
- _q_modelReset();
+ Q_D(QQmlDelegateModel);
+ if (!d->m_complete)
+ return;
+
+ if (hint == QAbstractItemModel::VerticalSortHint) {
+ d->m_storedPersistentIndexes.clear();
+ if (!parents.contains(d->m_adaptorModel.rootIndex))
+ return;
+
+ for (int i = 0; i < d->m_count; ++i) {
+ const QModelIndex index = d->m_adaptorModel.aim()->index(i, 0, d->m_adaptorModel.rootIndex);
+ d->m_storedPersistentIndexes.append(index);
+ }
+ } else if (hint == QAbstractItemModel::HorizontalSortHint) {
+ // Ignored
+ } else {
+ // Triggers model reset, no preparations for that are needed
+ }
+}
+
+void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
+{
+ Q_D(QQmlDelegateModel);
+ if (!d->m_complete)
+ return;
+
+ if (hint == QAbstractItemModel::VerticalSortHint) {
+ if (!parents.contains(d->m_adaptorModel.rootIndex))
+ return;
+
+ for (int i = 0, c = d->m_storedPersistentIndexes.count(); i < c; ++i) {
+ const QPersistentModelIndex &index = d->m_storedPersistentIndexes.at(i);
+ if (i == index.row())
+ continue;
+
+ QVector<Compositor::Insert> inserts;
+ QVector<Compositor::Remove> removes;
+ d->m_compositor.listItemsMoved(&d->m_adaptorModel, i, index.row(), 1, &removes, &inserts);
+ if (!removes.isEmpty() || !inserts.isEmpty()) {
+ d->itemsMoved(removes, inserts);
+ }
+ }
+
+ d->m_storedPersistentIndexes.clear();
+
+ // layoutUpdate does not necessarily have any move changes, but it can
+ // also mean data changes. We can't detect what exactly has changed, so
+ // just emit it for all items
+ _q_itemsChanged(0, d->m_count, QVector<int>());
+
+ } else if (hint == QAbstractItemModel::HorizontalSortHint) {
+ // Ignored
+ } else {
+ // We don't know what's going on, so reset the model
+ _q_modelReset();
+ }
}
QQmlDelegateModelAttached *QQmlDelegateModel::qmlAttachedProperties(QObject *obj)
diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h
index 51f846ea0b..0b67179163 100644
--- a/src/qml/types/qqmldelegatemodel_p.h
+++ b/src/qml/types/qqmldelegatemodel_p.h
@@ -139,7 +139,8 @@ private Q_SLOTS:
void _q_rowsRemoved(const QModelIndex &,int,int);
void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void _q_dataChanged(const QModelIndex&,const QModelIndex&,const QVector<int> &);
- void _q_layoutChanged();
+ void _q_layoutAboutToBeChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint);
+ void _q_layoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint);
private:
Q_DISABLE_COPY(QQmlDelegateModel)
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 7da089c9b8..d64f641a1b 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -331,6 +331,8 @@ public:
};
QQmlDelegateModelGroup *m_groups[Compositor::MaximumGroupCount];
};
+
+ QList<QPersistentModelIndex> m_storedPersistentIndexes;
};
class QQmlPartsModel : public QQmlInstanceModel, public QQmlDelegateModelGroupEmitter
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index d38e5ac3df..c1c8bfa81d 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -467,8 +467,10 @@ public:
vdm, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
QObject::disconnect(aim, SIGNAL(modelReset()),
vdm, SLOT(_q_modelReset()));
- QObject::disconnect(aim, SIGNAL(layoutChanged()),
- vdm, SLOT(_q_layoutChanged()));
+ QObject::disconnect(aim, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
+ vdm, SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ QObject::disconnect(aim, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
+ vdm, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
}
const_cast<VDMAbstractItemModelDataType *>(this)->release();
@@ -920,8 +922,10 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
vdm, QQmlDelegateModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
qmlobject_connect(model, QAbstractItemModel, SIGNAL(modelReset()),
vdm, QQmlDelegateModel, SLOT(_q_modelReset()));
- qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutChanged()),
- vdm, QQmlDelegateModel, SLOT(_q_layoutChanged()));
+ qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
+ vdm, QQmlDelegateModel, SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
+ vdm, QQmlDelegateModel, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
} else {
accessors = new VDMObjectDelegateDataType;
}
diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro
index 25d6494558..5af5443df7 100644
--- a/src/qmldevtools/qmldevtools.pro
+++ b/src/qmldevtools/qmldevtools.pro
@@ -10,6 +10,12 @@ MODULE_PRIVATE_INCLUDES = \
\$\$QT_MODULE_INCLUDE_BASE/QtQml/$$QT.qml.VERSION \
\$\$QT_MODULE_INCLUDE_BASE/QtQml/$$QT.qml.VERSION/QtQml
+# 2415: variable "xx" of static storage duration was declared but never referenced
+# unused variable 'xx' [-Werror,-Wunused-const-variable]
+intel_icc: WERROR += -ww2415
+clang:if(greaterThan(QT_CLANG_MAJOR_VERSION, 3)|greaterThan(QT_CLANG_MINOR_VERSION, 3)): \
+ WERROR += -Wno-error=unused-const-variable
+
load(qt_module)
include(../3rdparty/masm/masm-defs.pri)
diff --git a/src/quick/doc/src/concepts/convenience/topic.qdoc b/src/quick/doc/src/concepts/convenience/topic.qdoc
index 1a6feeaa61..b87cfd84c1 100644
--- a/src/quick/doc/src/concepts/convenience/topic.qdoc
+++ b/src/quick/doc/src/concepts/convenience/topic.qdoc
@@ -54,14 +54,11 @@ application performance.
\section1 Dynamic Bindings
-Assigning binding expressions to properties is a fundamental concept of QML,
-and Qt Quick extends upon the idea with the \l Binding type. While bindings
-are typically specified as property initialization assignments, the \l Binding
-type allows the target of a binding to be defined explicitly and separately
-from the definition of the binding expression itself.
-By declaring a \l Binding instance, the client can dynamically bind properties
-from arbitrary objects at run-time, and can modify the binding target when
-required (or when it becomes available).
+\l{Property Binding}{Property bindings} are a fundamental feature of QML.
+Typically, a property is initialized with its binding. However, the \l Binding
+type and \l {Qt::binding()}{Qt.binding()} function allows the client to
+dynamically bind properties from any object at run-time, and modify the binding
+target when required (or when it becomes available).
\section1 Dynamic Signal Connections
diff --git a/src/quick/doc/src/tutorial.qdoc b/src/quick/doc/src/tutorial.qdoc
index e0c05b16a8..75ca1b8d55 100644
--- a/src/quick/doc/src/tutorial.qdoc
+++ b/src/quick/doc/src/tutorial.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
@@ -31,7 +31,7 @@
\brief An introduction to the basic concepts and features of QML.
\nextpage QML Tutorial 1 - Basic Types
-This tutorial gives an introduction to QML, the declarative language for Qt Quick. It doesn't cover everything;
+This tutorial gives an introduction to QML, the language for Qt Quick UIs. It doesn't cover everything;
the emphasis is on teaching the key principles, and features are introduced as needed.
Through the different steps of this tutorial we will learn about QML basic types, we will create our own QML component
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 82658c73fc..2c03903f36 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -1524,7 +1524,7 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
This property determines whether delegates are retained outside the
visible area of the view.
- If non-zero the view may keep as many delegates
+ If this value is greater than zero, the view may keep as many delegates
instantiated as will fit within the buffer specified. For example,
if in a vertical view the delegate is 20 pixels high, there are 3
columns and \c cacheBuffer is
@@ -1535,7 +1535,7 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight)
delegates outside the visible area are not painted.
The default value of this property is platform dependent, but will usually
- be a non-zero value.
+ be a value greater than zero. Negative values are ignored.
Note that cacheBuffer is not a pixel buffer - it only maintains additional
instantiated delegates.
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 08dbfa3c23..d7527742dc 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -108,7 +108,7 @@ QQuickImagePrivate::QQuickImagePrivate()
\inherits Item
\brief Displays an image
- The Image type display an image.
+ The Image type displays an image.
The source of the image is specified as a URL using the \l source property.
Images can be supplied in any of the standard image formats supported by Qt,
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 3f0dae8070..ef2eac4b61 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -5691,10 +5691,12 @@ void QQuickItem::setAntialiasing(bool aa)
{
Q_D(QQuickItem);
- bool changed = (aa != antialiasing());
- d->antialiasingValid = true;
+ if (!d->antialiasingValid) {
+ d->antialiasingValid = true;
+ d->antialiasing = d->implicitAntialiasing;
+ }
- if (!changed)
+ if (aa == d->antialiasing)
return;
d->antialiasing = aa;
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index b4f6c34c6a..87e6728f86 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -454,6 +454,11 @@ int QQuickItemView::cacheBuffer() const
void QQuickItemView::setCacheBuffer(int b)
{
Q_D(QQuickItemView);
+ if (b < 0) {
+ qmlInfo(this) << "Cannot set a negative cache buffer";
+ return;
+ }
+
if (d->buffer != b) {
d->buffer = b;
if (isComponentComplete()) {
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 8f9dbb567f..ba4f1c53ba 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -2138,7 +2138,7 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
This property determines whether delegates are retained outside the
visible area of the view.
- If this value is non-zero, the view may keep as many delegates
+ If this value is greater than zero, the view may keep as many delegates
instantiated as it can fit within the buffer specified. For example,
if in a vertical view the delegate is 20 pixels high and \c cacheBuffer is
set to 40, then up to 2 delegates above and 2 delegates below the visible
@@ -2148,7 +2148,7 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
delegates outside the visible area are not painted.
The default value of this property is platform dependent, but will usually
- be a non-zero value.
+ be a value greater than zero. Negative values are ignored.
Note that cacheBuffer is not a pixel buffer - it only maintains additional
instantiated delegates.
diff --git a/src/quick/items/qquickrendercontrol_p.h b/src/quick/items/qquickrendercontrol_p.h
index 4cc2cf1252..e7b7759afa 100644
--- a/src/quick/items/qquickrendercontrol_p.h
+++ b/src/quick/items/qquickrendercontrol_p.h
@@ -63,7 +63,7 @@ public:
~QQuickRenderControl();
QQuickWindow *window() const;
- virtual QWindow *renderWindow(QPoint */*offset*/) { return 0; }
+ virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return 0; }
static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = 0);
void windowDestroyed();
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 312cd483e2..cbdea3917a 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -2359,7 +2359,7 @@ void QQuickText::setLineHeightMode(LineHeightMode mode)
within the width of the item without wrapping is used.
\li Text.VerticalFit - The largest size up to the size specified that fits
the height of the item is used.
- \li Text.Fit - The largest size up to the size specified the fits within the
+ \li Text.Fit - The largest size up to the size specified that fits within the
width and height of the item is used.
\endlist
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 53d736fb36..3087835212 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -423,7 +423,6 @@ void QQuickTextControlPrivate::selectionChanged(bool forceEmitSelectionChanged /
#endif
emit q->selectionChanged();
}
- q->updateCursorRectangle(true);
}
void QQuickTextControlPrivate::_q_updateCurrentCharFormatAndSelection()
@@ -1152,8 +1151,10 @@ void QQuickTextControlPrivate::mouseMoveEvent(QMouseEvent *e, const QPointF &mou
#endif
if (interactionFlags & Qt::TextEditable) {
- if (cursor.position() != oldCursorPos)
+ if (cursor.position() != oldCursorPos) {
emit q->cursorPositionChanged();
+ q->updateCursorRectangle(true);
+ }
_q_updateCurrentCharFormatAndSelection();
#ifndef QT_NO_IM
if (qGuiApp)
@@ -1161,6 +1162,7 @@ void QQuickTextControlPrivate::mouseMoveEvent(QMouseEvent *e, const QPointF &mou
#endif
} else if (cursor.position() != oldCursorPos) {
emit q->cursorPositionChanged();
+ q->updateCursorRectangle(true);
}
selectionChanged(true);
repaintOldAndNewSelection(oldSelection);
@@ -1255,6 +1257,7 @@ void QQuickTextControlPrivate::mouseDoubleClickEvent(QMouseEvent *e, const QPoin
setClipboardSelection();
#endif
emit q->cursorPositionChanged();
+ q->updateCursorRectangle(true);
}
} else if (!sendMouseEventToInputContext(e, pos)) {
e->ignore();
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index b69d8fa03b..5280301675 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1709,9 +1709,9 @@ void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
/*!
\overload
-Returns the value of the given \a property.
+Returns the value of the given \a property and \a argument.
*/
-QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
{
Q_D(const QQuickTextEdit);
@@ -1724,11 +1724,19 @@ QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
v = (int)d->effectiveInputMethodHints();
break;
default:
- v = d->control->inputMethodQuery(property);
+ v = d->control->inputMethodQuery(property, argument);
break;
}
return v;
+}
+/*!
+\overload
+Returns the value of the given \a property.
+*/
+QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ return inputMethodQuery(property, QVariant());
}
#endif // QT_NO_IM
@@ -2011,6 +2019,7 @@ void QQuickTextEditPrivate::init()
qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(redoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canRedoChanged()));
qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), q, QQuickTextEdit, SLOT(updateSize()));
QObject::connect(document, &QQuickTextDocumentWithImageResources::contentsChange, q, &QQuickTextEdit::q_contentsChange);
+ QObject::connect(document->documentLayout(), &QAbstractTextDocumentLayout::updateBlock, q, &QQuickTextEdit::invalidateBlock);
document->setDefaultFont(font);
document->setDocumentMargin(textMargin);
@@ -2245,6 +2254,11 @@ void QQuickTextEdit::updateWholeDocument()
}
}
+void QQuickTextEdit::invalidateBlock(const QTextBlock &block)
+{
+ markDirtyNodesForRange(block.position(), block.position() + block.length(), 0);
+}
+
void QQuickTextEdit::updateCursor()
{
Q_D(QQuickTextEdit);
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index b84552d255..614effd4c9 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -50,6 +50,8 @@ QT_BEGIN_NAMESPACE
class QQuickTextDocument;
class QQuickTextEditPrivate;
+class QTextBlock;
+
class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem
{
Q_OBJECT
@@ -227,6 +229,7 @@ public:
#ifndef QT_NO_IM
QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+ Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const;
#endif
qreal contentWidth() const;
@@ -326,6 +329,7 @@ private Q_SLOTS:
void createCursor();
void q_canPasteChanged();
void updateWholeDocument();
+ void invalidateBlock(const QTextBlock &block);
void updateCursor();
void q_updateAlignment();
void updateSize();
diff --git a/src/quick/items/qquicktextnode.cpp b/src/quick/items/qquicktextnode.cpp
index 1133636a74..da0d9cd714 100644
--- a/src/quick/items/qquicktextnode.cpp
+++ b/src/quick/items/qquicktextnode.cpp
@@ -144,8 +144,15 @@ QSGGlyphNode *QQuickTextNode::addGlyphs(const QPointF &position, const QGlyphRun
{
QSGRenderContext *sg = QQuickItemPrivate::get(m_ownerElement)->sceneGraphRenderContext();
QRawFont font = glyphs.rawFont();
- bool smoothScalable = QFontDatabase().isSmoothlyScalable(font.familyName(), font.styleName());
- bool preferNativeGlyphNode = m_useNativeRenderer || !smoothScalable;
+ bool preferNativeGlyphNode = m_useNativeRenderer;
+ if (!preferNativeGlyphNode) {
+ QRawFontPrivate *fontPriv = QRawFontPrivate::get(font);
+ if (fontPriv->fontEngine->hasUnreliableGlyphOutline())
+ preferNativeGlyphNode = true;
+ else
+ preferNativeGlyphNode = !QFontDatabase().isSmoothlyScalable(font.familyName(), font.styleName());
+ }
+
QSGGlyphNode *node = sg->sceneGraphContext()->createGlyphNode(sg, preferNativeGlyphNode);
node->setOwnerElement(m_ownerElement);
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 4592be3af8..6220ea2e1f 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1291,9 +1291,11 @@ bool QQuickWindow::event(QEvent *e)
QTouchEvent *touch = static_cast<QTouchEvent*>(e);
d->translateTouchEvent(touch);
d->deliverTouchEvent(touch);
- // we consume all touch events ourselves to avoid duplicate
- // mouse delivery by QtGui mouse synthesis
- e->accept();
+ if (Q_LIKELY(qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
+ // we consume all touch events ourselves to avoid duplicate
+ // mouse delivery by QtGui mouse synthesis
+ e->accept();
+ }
return true;
}
break;
@@ -2447,6 +2449,7 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown()
QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
for (; it != parentlessItems.end(); ++it)
cleanupNodesOnShutdown(*it);
+ animationController->windowNodesDestroyed();
q->cleanupSceneGraph();
}
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
index 810a503cee..467f454d0f 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
@@ -289,10 +289,22 @@ void QSGDefaultRectangleNode::update()
if (m_dirty_geometry) {
updateGeometry();
m_dirty_geometry = false;
+
+ QSGNode::DirtyState state = QSGNode::DirtyGeometry;
+ // smoothed material is always blended, so no change in material state
+ if (material() == &m_material) {
+ bool wasBlending = (m_material.flags() & QSGMaterial::Blending);
+ bool isBlending = (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
+ || (m_color.alpha() < 255 && m_color.alpha() != 0)
+ || (m_pen_width > 0 && m_border_color.alpha() < 255);
+ if (wasBlending != isBlending) {
+ m_material.setFlag(QSGMaterial::Blending, isBlending);
+ state |= QSGNode::DirtyMaterial;
+ }
+ }
+
+ markDirty(state);
}
- m_material.setFlag(QSGMaterial::Blending, (m_gradient_stops.size() > 0 && !m_gradient_is_opaque)
- || (m_color.alpha() < 255 && m_color.alpha() != 0)
- || (m_pen_width > 0 && m_border_color.alpha() < 255));
}
void QSGDefaultRectangleNode::updateGeometry()
@@ -770,8 +782,6 @@ void QSGDefaultRectangleNode::updateGeometry()
Q_ASSERT(outerAATail == indexCount);
}
}
-
- markDirty(DirtyGeometry);
}
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index c47fd8cdf4..e37344b21c 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -275,7 +275,7 @@ void Atlas::uploadBgra(Texture *texture)
QImage image = texture->image();
if (image.format() != QImage::Format_ARGB32_Premultiplied
- || image.format() != QImage::Format_RGB32) {
+ && image.format() != QImage::Format_RGB32) {
image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
index 7991dd8110..697c25b211 100644
--- a/src/quick/util/qquickanimatorcontroller.cpp
+++ b/src/quick/util/qquickanimatorcontroller.cpp
@@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE
QQuickAnimatorController::QQuickAnimatorController()
: m_window(0)
+ , m_nodesAreInvalid(false)
{
}
@@ -80,6 +81,26 @@ QQuickAnimatorController::~QQuickAnimatorController()
}
}
+static void qquickanimator_invalidate_node(QAbstractAnimationJob *job)
+{
+ if (job->isRenderThreadJob()) {
+ static_cast<QQuickAnimatorJob *>(job)->nodeWasDestroyed();
+ } else if (job->isGroup()) {
+ QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
+ for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
+ qquickanimator_invalidate_node(a);
+ }
+}
+
+void QQuickAnimatorController::windowNodesDestroyed()
+{
+ m_nodesAreInvalid = true;
+ for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
+ it != m_animatorRoots.constEnd(); ++it) {
+ qquickanimator_invalidate_node(it.key());
+ }
+}
+
void QQuickAnimatorController::itemDestroyed(QObject *o)
{
m_deletedSinceLastFrame << (QQuickItem *) o;
@@ -112,7 +133,7 @@ void QQuickAnimatorController::advance()
m_window->update();
}
-static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c)
+static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c, bool attachListener)
{
if (job->isRenderThreadJob()) {
QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
@@ -121,13 +142,14 @@ static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorC
} else if (c->m_deletedSinceLastFrame.contains(j->target())) {
j->targetWasDeleted();
} else {
- j->addAnimationChangeListener(c, QAbstractAnimationJob::StateChange);
+ if (attachListener)
+ j->addAnimationChangeListener(c, QAbstractAnimationJob::StateChange);
j->initialize(c);
}
} else if (job->isGroup()) {
QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
- qquick_initialize_helper(a, c);
+ qquick_initialize_helper(a, c, attachListener);
}
}
@@ -147,7 +169,7 @@ void QQuickAnimatorController::beforeNodeSync()
foreach (QQuickAnimatorProxyJob *proxy, m_starting) {
QAbstractAnimationJob *job = proxy->job();
job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
- qquick_initialize_helper(job, this);
+ qquick_initialize_helper(job, this, true);
m_animatorRoots[job] = proxy;
job->start();
proxy->startedByController();
@@ -160,6 +182,18 @@ void QQuickAnimatorController::beforeNodeSync()
}
m_stopping.clear();
+ // First sync after a window was hidden or otherwise invalidated.
+ // call initialize again to pick up new nodes..
+ if (m_nodesAreInvalid) {
+ for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
+ it != m_animatorRoots.constEnd(); ++it) {
+ qquick_initialize_helper(it.key(), this, false);
+ }
+ m_nodesAreInvalid = false;
+ }
+
+
+
foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) {
if (!job->target())
continue;
diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h
index 6223a9938f..745a494eec 100644
--- a/src/quick/util/qquickanimatorcontroller_p.h
+++ b/src/quick/util/qquickanimatorcontroller_p.h
@@ -76,6 +76,8 @@ public:
void lock() { m_mutex.lock(); }
void unlock() { m_mutex.unlock(); }
+ void windowNodesDestroyed();
+
public Q_SLOTS:
void itemDestroyed(QObject *);
@@ -92,6 +94,8 @@ public:
QSet<QQuickItem *> m_deletedSinceLastFrame;
QQuickWindow *m_window;
QMutex m_mutex;
+
+ bool m_nodesAreInvalid;
};
QT_END_NAMESPACE
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 3bc4cef5b9..0bf95a49b4 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -281,6 +281,12 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
}
}
+void QQuickTransformAnimatorJob::nodeWasDestroyed()
+{
+ if (m_helper)
+ m_helper->node = 0;
+}
+
void QQuickTransformAnimatorJob::Helper::sync()
{
const quint32 mask = QQuickItemPrivate::Position
@@ -326,7 +332,7 @@ void QQuickTransformAnimatorJob::Helper::sync()
void QQuickTransformAnimatorJob::Helper::apply()
{
- if (!wasChanged)
+ if (!wasChanged || !node)
return;
QMatrix4x4 m;
@@ -412,6 +418,11 @@ void QQuickOpacityAnimatorJob::initialize(QQuickAnimatorController *controller)
}
}
+void QQuickOpacityAnimatorJob::nodeWasDestroyed()
+{
+ m_opacityNode = 0;
+}
+
void QQuickOpacityAnimatorJob::writeBack()
{
if (m_target)
@@ -420,7 +431,7 @@ void QQuickOpacityAnimatorJob::writeBack()
void QQuickOpacityAnimatorJob::updateCurrentTime(int time)
{
- if (!m_controller)
+ if (!m_controller || !m_opacityNode)
return;
Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
@@ -504,13 +515,18 @@ void QQuickUniformAnimatorJob::setTarget(QQuickItem *target)
m_target = target;
}
+void QQuickUniformAnimatorJob::nodeWasDestroyed()
+{
+ m_node = 0;
+ m_uniformIndex = -1;
+ m_uniformType = -1;
+}
+
void QQuickUniformAnimatorJob::afterNodeSync()
{
m_node = static_cast<QQuickShaderEffectNode *>(QQuickItemPrivate::get(m_target)->paintNode);
- if (m_node) {
- m_uniformIndex = -1;
- m_uniformType = -1;
+ if (m_node && m_uniformIndex == -1 && m_uniformType == -1) {
QQuickShaderEffectMaterial *material =
static_cast<QQuickShaderEffectMaterial *>(m_node->material());
bool found = false;
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index 8aae121106..03b13bcd30 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -131,6 +131,7 @@ public:
void targetWasDeleted();
virtual void initialize(QQuickAnimatorController *controller);
virtual void writeBack() = 0;
+ virtual void nodeWasDestroyed() = 0;
bool isTransform() const { return m_isTransform; }
bool isUniform() const { return m_isUniform; }
@@ -208,6 +209,7 @@ public:
protected:
QQuickTransformAnimatorJob();
void initialize(QQuickAnimatorController *controller);
+ void nodeWasDestroyed();
Helper *m_helper;
};
@@ -256,6 +258,7 @@ public:
void initialize(QQuickAnimatorController *controller);
void updateCurrentTime(int time);
void writeBack();
+ void nodeWasDestroyed();
private:
QSGOpacityNode *m_opacityNode;
@@ -275,6 +278,7 @@ public:
void updateCurrentTime(int time);
void writeBack();
+ void nodeWasDestroyed();
private:
QByteArray m_uniform;
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index 25e40d8eb6..7e8b71da63 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -320,8 +320,6 @@ void QQuickPath::endpoint(QList<AttributePoint> &attributePoints, const QString
}
}
-static QString percentString(QLatin1String("_qfx_percent"));
-
void QQuickPath::processPath()
{
Q_D(QQuickPath);
@@ -358,6 +356,8 @@ QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &en
qreal startY = d->startY.isValid() ? d->startY.value : startPoint.y();
path.moveTo(startX, startY);
+ const QString percentString = QStringLiteral("_qfx_percent");
+
bool usesPercent = false;
int index = 0;
foreach (QQuickPathElement *pathElement, d->_pathElements) {
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index 1786317356..1a631703fb 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -102,7 +102,7 @@ QT_BEGIN_NAMESPACE
\note PropertyChanges can be used to change anchor margins, but not other anchor
values; use AnchorChanges for this instead. Similarly, to change an \l Item's
- \l {Item::}{parent} value, use ParentChanges instead.
+ \l {Item::}{parent} value, use ParentChange instead.
\section2 Resetting property values
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index f2b2d2af06..80586bd45b 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -89,7 +89,7 @@ public:
QQmlContext *context,
bool preloadImages,
bool *fontSizeModified)
- : text(t), layout(l), imgTags(&imgTags), baseFont(layout.font()), baseUrl(baseUrl), hasNewLine(false), nbImages(0), updateImagePositions(false)
+ : text(t), layout(l), imgTags(&imgTags), baseFont(layout.font()), baseUrl(baseUrl), hasNewLine(true), nbImages(0), updateImagePositions(false)
, preFormat(false), prependSpace(false), hasSpace(true), preloadImages(preloadImages), fontSizeModified(fontSizeModified), context(context)
{
}
diff --git a/src/src.pro b/src/src.pro
index 0cffc9abc0..ac48f017e6 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -8,6 +8,8 @@ qtHaveModule(gui):contains(QT_CONFIG, opengl(es1|es2)?) {
quick \
qmltest \
particles
+
+ qtHaveModule(widgets): SUBDIRS += quickwidgets
}
SUBDIRS += \
@@ -15,6 +17,4 @@ SUBDIRS += \
imports \
qmldevtools
-qtHaveModule(widgets):SUBDIRS += quickwidgets
-
qmldevtools.CONFIG = host_build
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index 4722c6bd54..a918e23a05 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -398,6 +398,7 @@ void tst_QQmlProfilerService::nonBlockingConnect()
m_client->setTraceState(true);
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
+ QVERIFY(m_client->traceMessages.count());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
@@ -424,7 +425,8 @@ void tst_QQmlProfilerService::pixmapCacheData()
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 20);
+ QVERIFY2(m_client->traceMessages.count() >= 20,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
@@ -497,7 +499,8 @@ void tst_QQmlProfilerService::profileOnExit()
m_client->setTraceState(true);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 2);
+ QVERIFY2(m_client->traceMessages.count() >= 2,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
@@ -516,7 +519,8 @@ void tst_QQmlProfilerService::controlFromJS()
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 2);
+ QVERIFY2(m_client->traceMessages.count() >= 2,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
@@ -539,22 +543,26 @@ void tst_QQmlProfilerService::signalSourceLocation()
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 20);
+ QVERIFY2(m_client->traceMessages.count() >= 20,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
+
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace);
- QVERIFY(m_client->traceMessages[14].messageType == QQmlProfilerClient::RangeLocation);
- QVERIFY(m_client->traceMessages[14].detailType == QQmlProfilerClient::HandlingSignal);
- QVERIFY(m_client->traceMessages[14].detailData.endsWith("signalSourceLocation.qml"));
- QVERIFY(m_client->traceMessages[14].line == 8);
- QVERIFY(m_client->traceMessages[14].column == 28);
+ QCOMPARE(m_client->traceMessages[14].messageType, (int)QQmlProfilerClient::RangeLocation);
+ QCOMPARE(m_client->traceMessages[14].detailType, (int)QQmlProfilerClient::HandlingSignal);
+ QVERIFY2(m_client->traceMessages[14].detailData.endsWith("signalSourceLocation.qml"),
+ m_client->traceMessages[14].detailData.toUtf8().constData());
+ QCOMPARE(m_client->traceMessages[14].line, 8);
+ QCOMPARE(m_client->traceMessages[14].column, 28);
- QVERIFY(m_client->traceMessages[19].messageType == QQmlProfilerClient::RangeLocation);
- QVERIFY(m_client->traceMessages[19].detailType == QQmlProfilerClient::HandlingSignal);
- QVERIFY(m_client->traceMessages[19].detailData.endsWith("signalSourceLocation.qml"));
- QVERIFY(m_client->traceMessages[19].line == 7);
- QVERIFY(m_client->traceMessages[19].column == 21);
+ QCOMPARE(m_client->traceMessages[19].messageType, (int)QQmlProfilerClient::RangeLocation);
+ QCOMPARE(m_client->traceMessages[19].detailType, (int)QQmlProfilerClient::HandlingSignal);
+ QVERIFY2(m_client->traceMessages[19].detailData.endsWith("signalSourceLocation.qml"),
+ m_client->traceMessages[19].detailData.toUtf8().constData());
+ QCOMPARE(m_client->traceMessages[19].line, 7);
+ QCOMPARE(m_client->traceMessages[19].column, 21);
// must end with "EndTrace"
QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event);
@@ -573,26 +581,29 @@ void tst_QQmlProfilerService::javascript()
m_client->setTraceState(false);
QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time.");
- QVERIFY(m_client->traceMessages.count() >= 36);
+ QVERIFY2(m_client->traceMessages.count() >= 36,
+ QString::number(m_client->traceMessages.count()).toUtf8().constData());
// must start with "StartTrace"
QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event);
QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace);
- QVERIFY(m_client->traceMessages[32].messageType == QQmlProfilerClient::RangeStart);
- QVERIFY(m_client->traceMessages[32].detailType == QQmlProfilerClient::Javascript);
+ QCOMPARE(m_client->traceMessages[32].messageType, (int)QQmlProfilerClient::RangeStart);
+ QCOMPARE(m_client->traceMessages[32].detailType, (int)QQmlProfilerClient::Javascript);
- QVERIFY(m_client->traceMessages[33].messageType == QQmlProfilerClient::RangeLocation);
- QVERIFY(m_client->traceMessages[33].detailType == QQmlProfilerClient::Javascript);
- QVERIFY(m_client->traceMessages[33].detailData.endsWith("javascript.qml"));
- QVERIFY(m_client->traceMessages[33].line == 4);
- QVERIFY(m_client->traceMessages[33].column == 5);
+ QCOMPARE(m_client->traceMessages[33].messageType, (int)QQmlProfilerClient::RangeLocation);
+ QCOMPARE(m_client->traceMessages[33].detailType, (int)QQmlProfilerClient::Javascript);
+ QVERIFY2(m_client->traceMessages[33].detailData.endsWith("javascript.qml"),
+ m_client->traceMessages[33].detailData.toUtf8().constData());
+ QCOMPARE(m_client->traceMessages[33].line, 4);
+ QCOMPARE(m_client->traceMessages[33].column, 5);
- QVERIFY(m_client->traceMessages[34].messageType == QQmlProfilerClient::RangeData);
- QVERIFY(m_client->traceMessages[34].detailType == QQmlProfilerClient::Javascript);
- QVERIFY(m_client->traceMessages[34].detailData == "something");
+ QCOMPARE(m_client->traceMessages[34].messageType, (int)QQmlProfilerClient::RangeData);
+ QCOMPARE(m_client->traceMessages[34].detailType, (int)QQmlProfilerClient::Javascript);
+ QVERIFY2(m_client->traceMessages[34].detailData == "something",
+ m_client->traceMessages[34].detailData.toUtf8().constData());
- QVERIFY(m_client->traceMessages[35].messageType == QQmlProfilerClient::RangeEnd);
- QVERIFY(m_client->traceMessages[35].detailType == QQmlProfilerClient::Javascript);
+ QCOMPARE(m_client->traceMessages[35].messageType, (int)QQmlProfilerClient::RangeEnd);
+ QCOMPARE(m_client->traceMessages[35].detailType, (int)QQmlProfilerClient::Javascript);
// must end with "EndTrace"
QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event);
diff --git a/tests/auto/qml/qjsvalueiterator/tst_qjsvalueiterator.cpp b/tests/auto/qml/qjsvalueiterator/tst_qjsvalueiterator.cpp
index fa6ac3249b..73c880cc2d 100644
--- a/tests/auto/qml/qjsvalueiterator/tst_qjsvalueiterator.cpp
+++ b/tests/auto/qml/qjsvalueiterator/tst_qjsvalueiterator.cpp
@@ -66,6 +66,7 @@ private slots:
void assignObjectToIterator();
void iterateNonObject();
void iterateOverObjectFromDeletedEngine();
+ void iterateWithNext();
};
tst_QJSValueIterator::tst_QJSValueIterator()
@@ -516,5 +517,31 @@ void tst_QJSValueIterator::iterateOverObjectFromDeletedEngine()
}
+void tst_QJSValueIterator::iterateWithNext()
+{
+ QJSEngine engine;
+ QJSValue value = engine.newObject();
+ value.setProperty("one", 1);
+ value.setProperty("two", 2);
+ value.setProperty("three", 3);
+
+ QStringList list;
+ list << QStringLiteral("one") << QStringLiteral("three") << QStringLiteral("two");
+
+ int counter = 0;
+ QJSValueIterator it(value);
+ QStringList actualList;
+ while (it.next()) {
+ ++counter;
+ actualList << it.name();
+ }
+
+ std::sort(actualList.begin(), actualList.end());
+
+ QCOMPARE(counter, 3);
+ QCOMPARE(list, actualList);
+
+}
+
QTEST_MAIN(tst_QJSValueIterator)
#include "tst_qjsvalueiterator.moc"
diff --git a/tests/auto/qmltest/animators/tst_mixed.qml b/tests/auto/qmltest/animators/tst_mixed.qml
new file mode 100644
index 0000000000..1eb0cf019f
--- /dev/null
+++ b/tests/auto/qmltest/animators/tst_mixed.qml
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtTest 1.0
+
+Item {
+ id: root;
+ width: 200
+ height: 200
+
+ TestCase {
+ id: testCase
+ name: "animators-mixed"
+ when: !rootAnimation.running
+ function test_endresult() {
+ compare(box.rootStart, 2);
+ compare(box.rootEnd, 2);
+
+ compare(parallelWithOneSequential.before, 4);
+ compare(parallelWithOneSequential.scaleUpdates, 4);
+
+ compare(parallelWithTwoSequentialNormalEndsLast.beforeAnimator, 4);
+ compare(parallelWithTwoSequentialNormalEndsLast.scaleUpdates, 4);
+ compare(parallelWithTwoSequentialNormalEndsLast.afterAnimator, 4);
+ compare(parallelWithTwoSequentialNormalEndsLast.beforePause, 4);
+ compare(parallelWithTwoSequentialNormalEndsLast.afterPause, 4);
+
+ compare(parallelWithTwoSequentialNormalEndsFirst.beforeAnimator, 4);
+ compare(parallelWithTwoSequentialNormalEndsFirst.scaleUpdates, 4);
+ compare(parallelWithTwoSequentialNormalEndsFirst.afterAnimator, 4);
+ compare(parallelWithTwoSequentialNormalEndsFirst.beforePause, 4);
+ compare(parallelWithTwoSequentialNormalEndsFirst.afterPause, 4);
+
+ }
+ }
+
+ Box {
+ id: box
+
+ property int rootStart : 0
+ property int rootEnd : 0;
+
+ SequentialAnimation {
+ id: rootAnimation
+
+ running: true
+ loops: 2
+
+ ScriptAction { script: box.rootStart++; }
+
+ ParallelAnimation {
+ id: parallelWithOneSequential
+ property int before : 0;
+ property int scaleUpdates : 0;
+ loops: 2
+ SequentialAnimation {
+ ScriptAction { script: {
+ parallelWithOneSequential.before++;
+ box.scale = 1;
+ box.scaleChangeCounter = 0;
+ }
+ }
+ ScaleAnimator { target: box; from: 1; to: 2; duration: 100; }
+ ScriptAction { script: {
+ parallelWithOneSequential.scaleUpdates += box.scaleChangeCounter;
+ }
+ }
+ }
+ }
+
+ ParallelAnimation {
+ id: parallelWithTwoSequentialNormalEndsLast
+ property int beforeAnimator : 0;
+ property int scaleUpdates : 0;
+ property int afterAnimator : 0;
+ property int beforePause : 0;
+ property int afterPause : 0;
+ loops: 2
+ SequentialAnimation {
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsLast.beforeAnimator++;
+ box.scale = 1;
+ box.scaleChangeCounter = 0;
+ }
+ }
+ ScaleAnimator { target: box; from: 1; to: 2; duration: 100; }
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsLast.scaleUpdates += box.scaleChangeCounter;
+ parallelWithTwoSequentialNormalEndsLast.afterAnimator++;
+ }
+ }
+ }
+ SequentialAnimation {
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsLast.beforePause++
+ }
+ }
+ PauseAnimation { duration: 200 }
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsLast.afterPause++
+ }
+ }
+ }
+ }
+
+ ParallelAnimation {
+ id: parallelWithTwoSequentialNormalEndsFirst
+ property int beforeAnimator : 0;
+ property int scaleUpdates : 0;
+ property int afterAnimator : 0;
+ property int beforePause : 0;
+ property int afterPause : 0;
+ loops: 2
+ SequentialAnimation {
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsFirst.beforeAnimator++;
+ box.scale = 1;
+ box.scaleChangeCounter = 0;
+ }
+ }
+ ScaleAnimator { target: box; from: 1; to: 2; duration: 200; }
+ ScriptAction { script: {
+ parallelWithTwoSequentialNormalEndsFirst.scaleUpdates += box.scaleChangeCounter;
+ parallelWithTwoSequentialNormalEndsFirst.afterAnimator++;
+ }
+ }
+ }
+ SequentialAnimation {
+ ScriptAction { script: parallelWithTwoSequentialNormalEndsFirst.beforePause++ }
+ PauseAnimation { duration: 100 }
+ ScriptAction { script: parallelWithTwoSequentialNormalEndsFirst.afterPause++ }
+ }
+ }
+
+ ScriptAction { script: box.rootEnd++; }
+ }
+
+ }
+
+}
diff --git a/src/qml/debugger/qv4profilerservice_p.h b/tests/auto/qmltest/animators/tst_multiwindow.qml
index b1a58dae03..7f7ca253d3 100644
--- a/src/qml/debugger/qv4profilerservice_p.h
+++ b/tests/auto/qmltest/animators/tst_multiwindow.qml
@@ -1,9 +1,9 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -39,77 +39,65 @@
**
****************************************************************************/
-#ifndef QV4PROFILERSERVICE_P_H
-#define QV4PROFILERSERVICE_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 <private/qqmlconfigurabledebugservice_p.h>
-
-QT_BEGIN_NAMESPACE
-
-
-struct Q_AUTOTEST_EXPORT QV4ProfilerData
-{
- int messageType;
- QString filename;
- QString functionname;
- int lineNumber;
- double totalTime;
- double selfTime;
- int treeLevel;
-
- QByteArray toByteArray() const;
-};
-
-class QQmlEngine;
-class QV4ProfilerServicePrivate;
-
-class Q_AUTOTEST_EXPORT QV4ProfilerService : public QQmlConfigurableDebugService
-{
- Q_OBJECT
-public:
- enum MessageType {
- V4Entry,
- V4Complete,
- V4SnapshotChunk,
- V4SnapshotComplete,
- V4Started,
-
- V4MaximumMessage
- };
-
- QV4ProfilerService(QObject *parent = 0);
- ~QV4ProfilerService();
-
- static QV4ProfilerService *instance();
-
-public Q_SLOTS:
- void startProfiling(const QString &title);
- void stopProfiling(const QString &title);
- void takeSnapshot();
- void deleteSnapshots();
-
- void sendProfilingData();
-
-protected:
- void stateAboutToBeChanged(State state);
- void messageReceived(const QByteArray &);
-
-private:
- Q_DISABLE_COPY(QV4ProfilerService)
- Q_DECLARE_PRIVATE(QV4ProfilerService)
-};
-
-QT_END_NAMESPACE
-
-#endif // QV4PROFILERSERVICE_P_H
+import QtQuick 2.2
+import QtTest 1.0
+import QtQuick.Window 2.0
+
+Item {
+ id: root;
+ width: 200
+ height: 200
+
+ TestCase {
+ id: testCase
+ name: "animators-mixed"
+ when: countdown == 0
+ function test_endresult() {
+ verify(true, "Just making sure we didn't crash");
+ }
+ }
+
+ property int countdown: 5;
+
+ Window {
+ id: window
+
+ width: 100
+ height: 100
+
+ ShaderEffect {
+ width: 50
+ height: 50
+
+ property real t;
+ UniformAnimator on t { from: 0; to: 1; duration: 1000; loops: Animation.Infinite }
+ RotationAnimator on rotation { from: 0; to: 360; duration: 1000; loops: Animation.Infinite }
+ ScaleAnimator on scale { from: 0.5; to: 1.5; duration: 1000; loops: Animation.Infinite }
+ XAnimator on x { from: 0; to: 50; duration: 1000; loops: Animation.Infinite }
+ YAnimator on y { from: 0; to: 50; duration: 1000; loops: Animation.Infinite }
+ OpacityAnimator on opacity { from: 1; to: 0.5; duration: 1000; loops: Animation.Infinite }
+
+ fragmentShader: "
+ uniform lowp float t;
+ uniform lowp float qt_Opacity;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ gl_FragColor = vec4(qt_TexCoord0, t, 1) * qt_Opacity;
+ }
+ "
+ }
+
+ visible: true
+ }
+
+ Timer {
+ interval: 250
+ running: true
+ repeat: true
+ onTriggered: {
+ if (window.visible)
+ --countdown
+ window.visible = !window.visible;
+ }
+ }
+}
diff --git a/tests/auto/qmltest/animators/tst_on.qml b/tests/auto/qmltest/animators/tst_on.qml
index 7930dc5be3..b3fc719dcc 100644
--- a/tests/auto/qmltest/animators/tst_on.qml
+++ b/tests/auto/qmltest/animators/tst_on.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@@ -54,7 +54,7 @@ Item {
&& !anims.running && !animr.running
&& !animo.running;
function test_endresult() {
- compare(box.xChangeCounter, 1);
+ tryCompare(box, 'xChangeCounter', 1);
compare(box.yChangeCounter, 1);
compare(box.scaleChangeCounter, 1);
compare(box.rotationChangeCounter, 1);
diff --git a/tests/auto/qmltest/textedit/tst_textedit.qml b/tests/auto/qmltest/textedit/tst_textedit.qml
index eb53eaa604..1dc7084049 100644
--- a/tests/auto/qmltest/textedit/tst_textedit.qml
+++ b/tests/auto/qmltest/textedit/tst_textedit.qml
@@ -43,6 +43,8 @@ import QtTest 1.0
Item {
id: top
+ height: 30
+ width: 60
TextEdit {
id: emptyText
@@ -82,6 +84,13 @@ Item {
TextEdit {
id: txtfunctions
+ text: "The quick brown fox"
+ height: 20
+ width: 50
+ }
+
+ TextEdit {
+ id: txtclipboard
text: "The quick brown fox jumped over the lazy dog"
height: 20
width: 50
@@ -148,31 +157,51 @@ Item {
compare(txtentry2.text, "hello World")
}
- function test_functions() {
+ function test_select_insert() {
compare(txtfunctions.getText(4,9), "quick")
txtfunctions.select(4,9);
compare(txtfunctions.selectedText, "quick")
+ txtfunctions.insert(4, "very ")
+ compare(txtfunctions.text, "The very quick brown fox")
txtfunctions.deselect();
compare(txtfunctions.selectedText, "")
- txtfunctions.select(4,9);
- txtfunctions.cut();
- compare(txtfunctions.text, "The brown fox jumped over the lazy dog")
txtfunctions.text = "Qt";
txtfunctions.insert(txtfunctions.text.length, " ")
compare(txtfunctions.text, "Qt ");
- txtfunctions.cursorPosition = txtfunctions.text.length;
- txtfunctions.paste();
+ txtfunctions.insert(txtfunctions.text.length, "quick")
compare(txtfunctions.text, "Qt quick");
txtfunctions.cursorPosition = txtfunctions.text.length;
txtfunctions.selectWord();
compare(txtfunctions.selectedText, "quick")
- txtfunctions.copy();
txtfunctions.selectAll();
compare(txtfunctions.selectedText, "Qt quick")
txtfunctions.deselect();
compare(txtfunctions.selectedText, "")
- txtfunctions.paste();
- compare(txtfunctions.text, "Qt quickquick");
+ }
+
+ function test_clipboard() {
+ if (typeof(txtclipboard.copy) !== "function"
+ || typeof(txtclipboard.paste) !== "function"
+ || typeof(txtclipboard.cut) !== "function") {
+ skip("Clipboard is not supported on this platform.")
+ }
+ txtclipboard.select(4,10);
+ txtclipboard.cut();
+ compare(txtclipboard.text, "The brown fox jumped over the lazy dog")
+ txtclipboard.select(30,35)
+ txtclipboard.paste();
+ compare(txtclipboard.text, "The brown fox jumped over the quick dog")
+ txtclipboard.text = "Qt ";
+ txtclipboard.cursorPosition = txtclipboard.text.length;
+ txtclipboard.paste();
+ compare(txtclipboard.text, "Qt quick ");
+ txtclipboard.cursorPosition = txtclipboard.text.length-1;
+ txtclipboard.selectWord();
+ compare(txtclipboard.selectedText, "quick")
+ txtclipboard.copy();
+ txtclipboard.cursorPosition = txtclipboard.text.length;
+ txtclipboard.paste();
+ compare(txtclipboard.text, "Qt quick quick");
}
function test_linecounts() {
diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
index 54eb3509bd..7d50e130f2 100644
--- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
+++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
@@ -131,6 +131,8 @@ void tst_QQuickAccessible::initTestCase()
QQmlDataTest::initTestCase();
QTestAccessibility::initialize();
QPlatformIntegration *pfIntegration = QGuiApplicationPrivate::platformIntegration();
+ if (!pfIntegration->accessibility())
+ QSKIP("This platform does not support accessibility");
pfIntegration->accessibility()->setActive(true);
}
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index 0855403d5a..0e012c5c6a 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -308,6 +308,10 @@ void tst_qquickimage::mirror()
qreal height = 250;
foreach (QQuickImage::FillMode fillMode, fillModes) {
+#if defined(Q_OS_BLACKBERRY)
+ QWindow dummy; // On BlackBerry first window is always full screen,
+ dummy.showFullScreen(); // so make test window a second window.
+#endif
QQuickView *window = new QQuickView;
window->setSource(testFileUrl("mirror.qml"));
@@ -316,7 +320,7 @@ void tst_qquickimage::mirror()
obj->setFillMode(fillMode);
obj->setProperty("mirror", true);
- window->show();
+ window->showNormal();
QVERIFY(QTest::qWaitForWindowExposed(window));
QImage screenshot = window->grabWindow();
diff --git a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp
index 4f103bd1fa..b5980929a6 100644
--- a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp
+++ b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp
@@ -55,10 +55,14 @@ public:
QImage runTest(const QString &fileName)
{
+#if defined(Q_OS_BLACKBERRY)
+ QWindow dummy; // On BlackBerry first window is always full screen,
+ dummy.showFullScreen(); // so make test window a second window.
+#endif
QQuickView view;
view.setSource(testFileUrl(fileName));
- view.show();
+ view.showNormal();
QTest::qWaitForWindowExposed(&view);
return view.grabWindow();
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 29755e3890..5cc3c7e642 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -3012,6 +3012,10 @@ void tst_QQuickListView::cacheBuffer()
controller.incubateWhile(&b);
}
+ // negative cache buffer is ignored
+ listview->setCacheBuffer(-1);
+ QCOMPARE(listview->cacheBuffer(), 200);
+
delete window;
delete testObject;
}
diff --git a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
index a2e05ba883..be46f362d6 100644
--- a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
+++ b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
@@ -126,26 +126,26 @@ void tst_qquickstyledtext::textOutput_data()
QTest::newRow("paragraph closed") << "text<p>more text</p>more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false;
QTest::newRow("paragraph closed bold") << "<b>text<p>more text</p>more text</b>" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << (FormatList() << Format(Format::Bold, 0, 24)) << false;
QTest::newRow("unknown tag") << "<a href='#'><foo>underline</foo></a> not" << "underline not" << (FormatList() << Format(Format::Underline, 0, 9)) << false;
- QTest::newRow("ordered list") << "<ol><li>one<li>two" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false;
- QTest::newRow("ordered list closed") << "<ol><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list alpha") << "<ol type=\"a\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("a.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("b.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list upper alpha") << "<ol type=\"A\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("A.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("B.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list roman") << "<ol type=\"i\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("i.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("ii.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list upper roman") << "<ol type=\"I\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("I.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("II.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("ordered list bad") << "<ol type=\"z\"><li>one</li><li>two</li></ol>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("unordered list") << "<ul><li>one<li>two" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false;
- QTest::newRow("unordered list closed") << "<ul><li>one</li><li>two</li></ul>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("unordered list disc") << "<ul type=\"disc\"><li>one</li><li>two</li></ul>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("unordered list square") << "<ul type=\"square\"><li>one</li><li>two</li></ul>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("unordered list bad") << "<ul type=\"bad\"><li>one</li><li>two</li></ul>" << QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
- QTest::newRow("header close") << "<h1>head</h1>more" << QChar(QChar::LineSeparator) + QLatin1String("head") + QChar(QChar::LineSeparator) + QLatin1String("more") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
+ QTest::newRow("ordered list") << "<ol><li>one<li>two" << QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false;
+ QTest::newRow("ordered list closed") << "<ol><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list alpha") << "<ol type=\"a\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("a.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("b.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list upper alpha") << "<ol type=\"A\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("A.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("B.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list roman") << "<ol type=\"i\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("i.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("ii.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list upper roman") << "<ol type=\"I\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("I.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("II.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("ordered list bad") << "<ol type=\"z\"><li>one</li><li>two</li></ol>" << QString(6, QChar::Nbsp) + QLatin1String("1.") + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + QLatin1String("2.") + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("unordered list") << "<ul><li>one<li>two" << QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") << FormatList() << false;
+ QTest::newRow("unordered list closed") << "<ul><li>one</li><li>two</li></ul>" << QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("unordered list disc") << "<ul type=\"disc\"><li>one</li><li>two</li></ul>" << QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + disc + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("unordered list square") << "<ul type=\"square\"><li>one</li><li>two</li></ul>" << QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + square + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("unordered list bad") << "<ul type=\"bad\"><li>one</li><li>two</li></ul>" << QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("one") + QChar(QChar::LineSeparator) + QString(6, QChar::Nbsp) + bullet + QString(2, QChar::Nbsp) + QLatin1String("two") + QChar(QChar::LineSeparator) << FormatList() << false;
+ QTest::newRow("header close") << "<h1>head</h1>more" << QLatin1String("head") + QChar(QChar::LineSeparator) + QLatin1String("more") << (FormatList() << Format(Format::Bold, 0, 4)) << true;
QTest::newRow("h0") << "<h0>head" << "head" << FormatList() << false;
- QTest::newRow("h1") << "<h1>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h2") << "<h2>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h3") << "<h3>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h4") << "<h4>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h5") << "<h5>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
- QTest::newRow("h6") << "<h6>head" << QChar(QChar::LineSeparator) + QLatin1String("head") << (FormatList() << Format(Format::Bold, 0, 5)) << true;
+ QTest::newRow("h1") << "<h1>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h2") << "<h2>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h3") << "<h3>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h4") << "<h4>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h5") << "<h5>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
+ QTest::newRow("h6") << "<h6>head" << "head" << (FormatList() << Format(Format::Bold, 0, 4)) << true;
QTest::newRow("h7") << "<h7>head" << "head" << FormatList() << false;
QTest::newRow("pre") << "normal<pre>pre text</pre>normal" << QLatin1String("normal") + QChar(QChar::LineSeparator) + QLatin1String("pre") + QChar(QChar::Nbsp) + QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("normal") << (FormatList() << Format(0, 6, 9)) << false;
QTest::newRow("pre lb") << "normal<pre>pre\n text</pre>normal" << QLatin1String("normal") + QChar(QChar::LineSeparator) + QLatin1String("pre") + QChar(QChar::LineSeparator) + QChar(QChar::Nbsp) + QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("normal") << (FormatList() << Format(0, 6, 10)) << false;
@@ -155,7 +155,7 @@ void tst_qquickstyledtext::textOutput_data()
QTest::newRow("consecutive whitespace") << " consecutive \t \n whitespace" << "consecutive whitespace" << FormatList() << false;
QTest::newRow("space after newline") << "text<br/> more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false;
QTest::newRow("space after paragraph") << "text<p> more text</p> more text" << QLatin1String("text") + QChar(QChar::LineSeparator) + QLatin1String("more text") + QChar(QChar::LineSeparator) + QLatin1String("more text") << FormatList() << false;
- QTest::newRow("space in header") << "<h1> head</h1> " << QChar(QChar::LineSeparator) + QLatin1String("head") + QChar(QChar::LineSeparator) << (FormatList() << Format(Format::Bold, 0, 5)) << true;
+ QTest::newRow("space in header") << "<h1> head</h1> " << QLatin1String("head") + QChar(QChar::LineSeparator) << (FormatList() << Format(Format::Bold, 0, 4)) << true;
QTest::newRow("space before bold") << "this is <b>bold</b>" << "this is bold" << (FormatList() << Format(Format::Bold, 8, 4)) << false;
QTest::newRow("space leading bold") << "this is<b> bold</b>" << "this is bold" << (FormatList() << Format(Format::Bold, 7, 5)) << false;
QTest::newRow("space trailing bold") << "this is <b>bold </b>" << "this is bold " << (FormatList() << Format(Format::Bold, 8, 5)) << false;
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 0b6998146e..d36c55d687 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -1334,6 +1334,13 @@ void tst_qquicktext::antialiasing()
text->resetAntialiasing();
QCOMPARE(text->antialiasing(), true);
QCOMPARE(spy.count(), 2);
+
+ // QTBUG-39047
+ component.setData("import QtQuick 2.0\n Text { antialiasing: true }", QUrl());
+ object.reset(component.create());
+ text = qobject_cast<QQuickText *>(object.data());
+ QVERIFY(text);
+ QCOMPARE(text->antialiasing(), true);
}
void tst_qquicktext::weight()
diff --git a/tests/auto/quick/qquicktextedit/data/qtbug-38947.qml b/tests/auto/quick/qquicktextedit/data/qtbug-38947.qml
new file mode 100644
index 0000000000..ebf8080e69
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/qtbug-38947.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+
+Item {
+ height: 200
+ width: 200
+ TextEdit {
+ objectName: "textedit"
+ text: "Hello\nWorld!"
+ selectByMouse: true
+ cursorDelegate: Rectangle {
+ width: 10
+ color: "transparent"
+ border.color: "red"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index 45d23abbf6..1ffd67cbf1 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -207,6 +207,7 @@ private slots:
void embeddedImages_data();
void emptytags_QTBUG_22058();
+ void cursorRectangle_QTBUG_38947();
private:
void simulateKeys(QWindow *window, const QList<Key> &keys);
@@ -5259,6 +5260,33 @@ void tst_qquicktextedit::emptytags_QTBUG_22058()
QCOMPARE(input->text(), QString("<b>Bold<>"));
}
+void tst_qquicktextedit::cursorRectangle_QTBUG_38947()
+{
+ QQuickView window(testFileUrl("qtbug-38947.qml"));
+
+ window.show();
+ window.requestActivate();
+ QTest::qWaitForWindowExposed(&window);
+ QQuickTextEdit *edit = window.rootObject()->findChild<QQuickTextEdit *>("textedit");
+ QVERIFY(edit);
+
+ QPoint from = edit->positionToRectangle(0).center().toPoint();
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, from);
+
+ QSignalSpy spy(edit, SIGNAL(cursorRectangleChanged()));
+ QVERIFY(spy.isValid());
+
+ for (int i = 1; i < edit->length() - 1; ++i) {
+ QRectF rect = edit->positionToRectangle(i);
+ QTest::mouseMove(&window, rect.center().toPoint());
+ QCOMPARE(edit->cursorRectangle(), rect);
+ QCOMPARE(spy.count(), i);
+ }
+
+ QPoint to = edit->positionToRectangle(edit->length() - 1).center().toPoint();
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, to);
+}
+
QTEST_MAIN(tst_qquicktextedit)
#include "tst_qquicktextedit.moc"
diff --git a/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp b/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp
index e9fbb5448c..9b62eb311c 100644
--- a/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp
+++ b/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp
@@ -53,6 +53,12 @@ private slots:
void tst_QQuickTimeLine::overflow()
{
+ // Test ensures that time value used in QQuickTimeLine::accel methods is always positive.
+ // On platforms where casting qreal value infinity to int yields a positive value this is
+ // always the case and the test would fail. Strictly speaking, the cast is undefined behavior.
+ if (static_cast<int>(qInf()) > 0)
+ QSKIP("Test is not applicable on this platform");
+
QQuickTimeLine timeline;
QQuickTimeLineValue value;
diff --git a/tests/testapplications/text/text.qml b/tests/testapplications/text/text.qml
index 56ca825d0a..b1e600a633 100644
--- a/tests/testapplications/text/text.qml
+++ b/tests/testapplications/text/text.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@@ -130,7 +130,7 @@ Rectangle {
"value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+
"modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices.\n"+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime. "+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
textmodel.append({ "name": "Short",
@@ -143,7 +143,7 @@ Rectangle {
"value": "<b>Qt Quick</b> is a collection of technologies that are designed to help developers create the kind of <i>intuitive, "+
"modern, fluid</i> user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices.<br>"+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime. "+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
}
diff --git a/tests/testapplications/text/textedit.qml b/tests/testapplications/text/textedit.qml
index 6546abfe91..3baa307d8d 100644
--- a/tests/testapplications/text/textedit.qml
+++ b/tests/testapplications/text/textedit.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@@ -127,7 +127,7 @@ Rectangle {
"value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+
"modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices."+texteditelement.newline+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime.\n"+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
textmodel.append({ "name": "Short",
@@ -140,7 +140,7 @@ Rectangle {
"value": "<b>Qt Quick</b> is a collection of technologies that are designed to help developers create the kind of <i>intuitive, "+
"modern, fluid</i> user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices.<br>"+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime. "+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
textmodel.append({ "name": "Links",
diff --git a/tests/testapplications/text/textinput.qml b/tests/testapplications/text/textinput.qml
index 556771bcb5..d15d02232a 100644
--- a/tests/testapplications/text/textinput.qml
+++ b/tests/testapplications/text/textinput.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@@ -175,7 +175,7 @@ Rectangle {
"value": "Qt Quick is a collection of technologies that are designed to help developers create the kind of intuitive, "+
"modern, fluid user interfaces that are increasingly used on mobile phones, media players, set-top boxes and other "+
"portable devices. "+
- "Qt Quick consists of a rich set of user interface elements, a declarative language for describing user interfaces "+
+ "Qt Quick consists of a rich set of user interface elements, a language for describing user interfaces "+
"and a language runtime. "+
"A collection of C++ APIs is used to integrate these high level features with classic Qt applications."});
}
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp
index 3fa36ad8f7..1c349d8538 100644
--- a/tools/qml/main.cpp
+++ b/tools/qml/main.cpp
@@ -264,8 +264,8 @@ void printUsage()
printf("Any argument ending in .qml will be treated as a QML file to be loaded.\n");
printf("Any number of QML files can be loaded. They will share the same engine.\n");
printf("Any argument which is not a recognized option and which does not end in .qml will be ignored.\n");
- printf("'gui' application type is only available if the QtGui module is avaialble.\n");
- printf("'widget' application type is only available if the QtWidgets module is avaialble.\n");
+ printf("'gui' application type is only available if the QtGui module is available.\n");
+ printf("'widget' application type is only available if the QtWidgets module is available.\n");
printf("\n");
printf("General Options:\n");
printf("\t-h, -help..................... Print this usage information and exit.\n");
diff --git a/tools/qmlplugindump/qmlplugindump.pro b/tools/qmlplugindump/qmlplugindump.pro
index 67af71c59f..6fdcd349d1 100644
--- a/tools/qmlplugindump/qmlplugindump.pro
+++ b/tools/qmlplugindump/qmlplugindump.pro
@@ -1,6 +1,8 @@
QT += qml qml-private quick-private core-private
-CONFIG += no_import_scan qpa_minimal_plugin
+CONFIG += no_import_scan
+
+QTPLUGIN.platforms = qminimal
SOURCES += \
main.cpp \