Fix crash in TextInput.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Fri, 23 Dec 2011 06:04:44 +0000 (16:04 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 4 Jan 2012 04:43:14 +0000 (05:43 +0100)
Ensure the text is laid out before calling componentComplete() on
QImplicitSizeItem, as that can potentially evaluate bindings which
would then access the uninitialized layout.

Change-Id: I5152c1494c54209dae61c13b2f45d343fb76bf9e
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
src/quick/items/qquicktextinput.cpp
tests/auto/qtquick2/qquicktextinput/data/negativeDimensions.qml [new file with mode: 0644]
tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp

index 2d5f5af..b4f31e3 100644 (file)
@@ -1412,13 +1412,14 @@ void QQuickTextInputPrivate::updateHorizontalScroll()
     Q_Q(QQuickTextInput);
     QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor);
     const int preeditLength = m_textLayout.preeditAreaText().length();
-    const int width = q->width();
+    const int width = qMax(0, qFloor(q->width()));
     int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
     int previousScroll = hscroll;
 
     if (!autoScroll || widthUsed <=  width || m_echoMode == QQuickTextInput::NoEcho) {
         hscroll = 0;
     } else {
+        Q_ASSERT(currentLine.isValid());
         int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength));
         if (cix - hscroll >= width) {
             // text doesn't fit, cursor is to the right of br (scroll right)
@@ -1447,7 +1448,7 @@ void QQuickTextInputPrivate::updateVerticalScroll()
 {
     Q_Q(QQuickTextInput);
     const int preeditLength = m_textLayout.preeditAreaText().length();
-    const int height = q->height();
+    const int height = qMax(0, qFloor(q->height()));
     int heightUsed = boundingRect.height();
     int previousScroll = vscroll;
 
@@ -1466,7 +1467,8 @@ void QQuickTextInputPrivate::updateVerticalScroll()
             break;
         }
     } else {
-        QRectF r = m_textLayout.lineForTextPosition(m_cursor + preeditLength).rect();
+        QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength);
+        QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF();
         int top = qFloor(r.top());
         int bottom = qCeil(r.bottom());
 
@@ -1484,10 +1486,10 @@ void QQuickTextInputPrivate::updateVerticalScroll()
         if (preeditLength > 0) {
             // check to ensure long pre-edit text doesn't push the cursor
             // off the top
-             top = qRound(m_textLayout.lineForTextPosition(
-                    m_cursor + qMax(0, m_preeditCursor - 1)).rect().top());
-             if (top < vscroll)
-                 vscroll = top;
+            currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1));
+            top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0;
+            if (top < vscroll)
+                vscroll = top;
         }
     }
     if (previousScroll != vscroll)
diff --git a/tests/auto/qtquick2/qquicktextinput/data/negativeDimensions.qml b/tests/auto/qtquick2/qquicktextinput/data/negativeDimensions.qml
new file mode 100644 (file)
index 0000000..7a58c85
--- /dev/null
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Item {
+    TextInput {
+        objectName: "input"
+
+        focus: true
+        width: -1
+        height: -1
+        text: "sushi"
+
+        anchors {
+            left: parent.left;
+            leftMargin: 5
+            top: parent.top
+            topMargin: font.pixelSize
+        }
+    }
+}
index 3319936..0286cea 100644 (file)
@@ -176,6 +176,8 @@ private slots:
     void QTBUG_19956_data();
     void QTBUG_19956_regexp();
 
+    void negativeDimensions();
+
 private:
     void simulateKey(QQuickView *, int key);
 
@@ -3390,6 +3392,19 @@ void tst_qquicktextinput::QTBUG_19956_regexp()
     QVERIFY(canvas.rootObject()->property("acceptableInput").toBool());
 }
 
+
+void tst_qquicktextinput::negativeDimensions()
+{
+    // Verify this doesn't assert during initialization.
+    QDeclarativeComponent component(&engine, testFileUrl("negativeDimensions.qml"));
+    QScopedPointer<QObject> o(component.create());
+    QVERIFY(o);
+    QQuickTextInput *input = o->findChild<QQuickTextInput *>("input");
+    QVERIFY(input);
+    QCOMPARE(input->width(), qreal(-1));
+    QCOMPARE(input->height(), qreal(-1));
+}
+
 QTEST_MAIN(tst_qquicktextinput)
 
 #include "tst_qquicktextinput.moc"