diff --git a/doc/src/declarative/whatsnew.qdoc b/doc/src/declarative/whatsnew.qdoc
index 2ae46714b6b5cab3b89d964121056bd0412468fa..ef23d15f62c26d37c28e12aab082ae65cbb210fd 100644
--- a/doc/src/declarative/whatsnew.qdoc
+++ b/doc/src/declarative/whatsnew.qdoc
@@ -127,6 +127,9 @@ Text improvements:
 TextEdit:
  - the default value of the textFormat property is now PlainText instead of AutoText.
 
+TextInput has new wrapMode and verticalAlignment properties, and the positionAt function now takes
+a y parameter.
+
 PathView now has a \c currentItem property
 
 ListView and GridView:
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 649e29d6bcde38bb4b7f3d567aa67f3006fa9d53..b6bc33c7675061216d206d95b1ed5f7bf5cb1921 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -92,6 +92,18 @@ QQuickTextInput::~QQuickTextInput()
 {
 }
 
+void QQuickTextInput::componentComplete()
+{
+    Q_D(QQuickTextInput);
+
+    QQuickImplicitSizeItem::componentComplete();
+
+    d->updateLayout();
+    updateCursorRectangle();
+    if (d->cursorComponent && d->cursorComponent->isReady())
+        createCursor();
+}
+
 /*!
     \qmlproperty string QtQuick2::TextInput::text
 
@@ -251,12 +263,8 @@ void QQuickTextInput::setFont(const QFont &font)
         d->font.setPointSizeF(size/2.0);
     }
     if (oldFont != d->font) {
-        d->updateDisplayText();
-        updateSize();
+        d->updateLayout();
         updateCursorRectangle();
-        if (d->cursorItem) {
-            d->cursorItem->setHeight(QFontMetrics(d->font).height());
-        }
     }
     emit fontChanged(d->sourceFont);
 }
@@ -338,6 +346,7 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
 /*!
     \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
     \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
+    \qmlproperty enumeration QtQuick2::TextInput::verticalAlignment
 
     Sets the horizontal alignment of the text within the TextInput item's
     width and height. By default, the text alignment follows the natural alignment
@@ -353,6 +362,9 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
     The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
     \c TextInput.AlignHCenter.
 
+    Valid values for \c verticalAlignment are \c TextEdit.AlignTop (default),
+    \c TextEdit.AlignBottom \c TextEdit.AlignVCenter.
+
     When using the attached property LayoutMirroring::enabled to mirror application
     layouts, the horizontal alignment of text will also be mirrored. However, the property
     \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
@@ -370,6 +382,7 @@ void QQuickTextInput::setHAlign(HAlignment align)
     bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
     d->hAlignImplicit = false;
     if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+        d->updateLayout();
         updateCursorRectangle();
     }
 }
@@ -379,6 +392,7 @@ void QQuickTextInput::resetHAlign()
     Q_D(QQuickTextInput);
     d->hAlignImplicit = true;
     if (d->determineHorizontalAlignment() && isComponentComplete()) {
+        d->updateLayout();
         updateCursorRectangle();
     }
 }
@@ -429,6 +443,56 @@ bool QQuickTextInputPrivate::determineHorizontalAlignment()
     return false;
 }
 
+QQuickTextInput::VAlignment QQuickTextInput::vAlign() const
+{
+    Q_D(const QQuickTextInput);
+    return d->vAlign;
+}
+
+void QQuickTextInput::setVAlign(QQuickTextInput::VAlignment alignment)
+{
+    Q_D(QQuickTextInput);
+    if (alignment == d->vAlign)
+        return;
+    d->vAlign = alignment;
+    emit verticalAlignmentChanged(d->vAlign);
+    if (isComponentComplete()) {
+        updateCursorRectangle();
+    }
+}
+
+/*!
+    \qmlproperty enumeration QtQuick2::TextInput::wrapMode
+
+    Set this property to wrap the text to the TextEdit item's width.
+    The text will only wrap if an explicit width has been set.
+
+    \list
+    \o TextInput.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
+    \o TextInput.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
+    \o TextInput.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
+    \o TextInput.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
+    \endlist
+
+    The default is TextInput.NoWrap. If you set a width, consider using TextInput.Wrap.
+*/
+QQuickTextInput::WrapMode QQuickTextInput::wrapMode() const
+{
+    Q_D(const QQuickTextInput);
+    return d->wrapMode;
+}
+
+void QQuickTextInput::setWrapMode(WrapMode mode)
+{
+    Q_D(QQuickTextInput);
+    if (mode == d->wrapMode)
+        return;
+    d->wrapMode = mode;
+    d->updateLayout();
+    updateCursorRectangle();
+    emit wrapModeChanged();
+}
+
 void QQuickTextInputPrivate::mirrorChange()
 {
     Q_Q(QQuickTextInput);
@@ -567,12 +631,20 @@ void QQuickTextInput::setCursorPosition(int cp)
 QRect QQuickTextInput::cursorRectangle() const
 {
     Q_D(const QQuickTextInput);
-    QTextLine l = d->m_textLayout.lineAt(0);
+
     int c = d->m_cursor;
     if (d->m_preeditCursor != -1)
         c += d->m_preeditCursor;
-    return QRect(qRound(l.cursorToX(c)) - d->hscroll, 0, d->m_cursorWidth, l.height());
+    if (d->m_echoMode == NoEcho || !isComponentComplete())
+        c = 0;
+    QTextLine l = d->m_textLayout.lineForTextPosition(c);
+    return QRect(
+            qRound(l.cursorToX(c) - d->hscroll),
+            qRound(l.y() - d->vscroll),
+            d->m_cursorWidth,
+            qCeil(l.height()));
 }
+
 /*!
     \qmlproperty int QtQuick2::TextInput::selectionStart
 
@@ -686,7 +758,6 @@ void QQuickTextInput::setAutoScroll(bool b)
 
     d->autoScroll = b;
     //We need to repaint so that the scrolling is taking into account.
-    updateSize(true);
     updateCursorRectangle();
     emit autoScrollChanged(d->autoScroll);
 }
@@ -908,9 +979,8 @@ void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
     d->m_echoMode = echo;
     d->m_passwordEchoEditing = false;
     d->updateInputMethodHints();
-
     d->updateDisplayText();
-    q_textChanged();
+    updateCursorRectangle();
 
     emit echoModeChanged(echoMode());
 }
@@ -982,6 +1052,9 @@ void QQuickTextInputPrivate::startCreatingCursor()
 void QQuickTextInput::createCursor()
 {
     Q_D(QQuickTextInput);
+    if (!isComponentComplete())
+        return;
+
     if (d->cursorComponent->isError()) {
         qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
         return;
@@ -1001,10 +1074,12 @@ void QQuickTextInput::createCursor()
         return;
     }
 
+    QRectF r = cursorRectangle();
+
     QDeclarative_setParent_noEvent(d->cursorItem, this);
     d->cursorItem->setParentItem(this);
-    d->cursorItem->setX(d->cursorToX());
-    d->cursorItem->setHeight(d->calculateTextHeight());
+    d->cursorItem->setPos(r.topLeft());
+    d->cursorItem->setHeight(r.height());
 }
 
 /*!
@@ -1022,19 +1097,22 @@ QRectF QQuickTextInput::positionToRectangle(int pos) const
     if (pos > d->m_cursor)
         pos += d->preeditAreaText().length();
     QTextLine l = d->m_textLayout.lineAt(0);
-    return QRectF( l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height());
+    return QRectF(l.cursorToX(pos) - d->hscroll, 0.0, d->m_cursorWidth, l.height());
 }
 
 /*!
-    \qmlmethod int QtQuick2::TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters)
+    \qmlmethod int QtQuick2::TextInput::positionAt(real x, real y, CursorPosition position = CursorBetweenCharacters)
 
     This function returns the character position at
-    x pixels from the left of the textInput. Position 0 is before the
+    x and y pixels from the top left  of the textInput. Position 0 is before the
     first character, position 1 is after the first character but before the second,
     and so on until position text.length, which is after all characters.
 
     This means that for all x values before the first character this function returns 0,
-    and for all x values after the last character this function returns text.length.
+    and for all x values after the last character this function returns text.length.  If
+    the y value is above the text the position will be that of the nearest character on
+    the first line line and if it is below the text the position of the nearest character
+    on the last line will be returned.
 
     The cursor position type specifies how the cursor position should be resolved.
 
@@ -1043,15 +1121,33 @@ QRectF QQuickTextInput::positionToRectangle(int pos) const
     \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
     \endlist
 */
-int QQuickTextInput::positionAt(int x) const
-{
-    return positionAt(x, CursorBetweenCharacters);
-}
 
-int QQuickTextInput::positionAt(int x, CursorPosition position) const
+void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const
 {
     Q_D(const QQuickTextInput);
-    int pos = d->m_textLayout.lineAt(0).xToCursor(x + d->hscroll, QTextLine::CursorPosition(position));
+
+    qreal x = 0;
+    qreal y = 0;
+    QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters;
+
+    if (args->Length() < 1)
+        return;
+
+    int i = 0;
+    v8::Local<v8::Value> arg = (*args)[i];
+    x = arg->NumberValue();
+
+    if (++i < args->Length()) {
+        arg = (*args)[i];
+        y = arg->NumberValue();
+    }
+
+    if (++i < args->Length()) {
+        arg = (*args)[i];
+        position = QTextLine::CursorPosition(arg->Int32Value());
+    }
+
+    int pos = d->positionAt(x, y, position);
     const int cursor = d->m_cursor;
     if (pos > cursor) {
         const int preeditLength = d->preeditAreaText().length();
@@ -1059,7 +1155,22 @@ int QQuickTextInput::positionAt(int x, CursorPosition position) const
                 ? pos - preeditLength
                 : cursor;
     }
-    return pos;
+    args->returnValue(v8::Int32::New(pos));
+}
+
+int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const
+{
+    x += hscroll;
+    y += vscroll;
+    QTextLine line = m_textLayout.lineAt(0);
+    for (int i = 1; i < m_textLayout.lineCount(); ++i) {
+        QTextLine nextLine = m_textLayout.lineAt(i);
+
+        if (y < (line.rect().bottom() + nextLine.y()) / 2)
+            break;
+        line = nextLine;
+    }
+    return line.xToCursor(x, position);
 }
 
 void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
@@ -1107,7 +1218,7 @@ void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
 
     if (d->selectByMouse && event->button() == Qt::LeftButton) {
         d->commitPreedit();
-        int cursor = d->xToPos(event->localPos().x());
+        int cursor = d->positionAt(event->localPos());
         d->selectWordAtPos(cursor);
         event->setAccepted(true);
         if (!d->hasPendingTripleClick()) {
@@ -1150,7 +1261,7 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event)
         return;
 
     bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
-    int cursor = d->xToPos(event->localPos().x());
+    int cursor = d->positionAt(event->localPos());
     d->moveCursor(cursor, mark);
     event->setAccepted(true);
 }
@@ -1165,12 +1276,12 @@ void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
 
         if (d->composeMode()) {
             // start selection
-            int startPos = d->xToPos(d->pressPos.x());
-            int currentPos = d->xToPos(event->localPos().x());
+            int startPos = d->positionAt(d->pressPos);
+            int currentPos = d->positionAt(event->localPos());
             if (startPos != currentPos)
                 d->setSelection(startPos, currentPos - startPos);
         } else {
-            moveCursorSelection(d->xToPos(event->localPos().x()), d->mouseSelectionMode);
+            moveCursorSelection(d->positionAt(event->localPos()), d->mouseSelectionMode);
         }
         event->setAccepted(true);
     } else {
@@ -1205,7 +1316,7 @@ bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
 {
 #if !defined QT_NO_IM
     if (composeMode()) {
-        int tmp_cursor = xToPos(event->localPos().x());
+        int tmp_cursor = positionAt(event->localPos());
         int mousePos = tmp_cursor - m_cursor;
         if (mousePos >= 0 && mousePos <= m_textLayout.preeditAreaText().length()) {
             if (event->type() == QEvent::MouseButtonRelease) {
@@ -1284,37 +1395,26 @@ bool QQuickTextInput::event(QEvent* ev)
 void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
                                   const QRectF &oldGeometry)
 {
-    if (newGeometry.width() != oldGeometry.width()) {
-        updateSize();
-        updateCursorRectangle();
-    }
+    Q_D(QQuickTextInput);
+    if (newGeometry.width() != oldGeometry.width())
+        d->updateLayout();
+    updateCursorRectangle();
     QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
 }
 
 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();
-    int widthUsed = calculateTextWidth();
+    int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0;
+    int previousScroll = hscroll;
 
-    if (!autoScroll || widthUsed <=  width) {
-        QQuickTextInput::HAlignment effectiveHAlign = q->effectiveHAlign();
-        // text fits in br; use hscroll for alignment
-        switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
-        case Qt::AlignRight:
-            hscroll = widthUsed - width;
-            break;
-        case Qt::AlignHCenter:
-            hscroll = (widthUsed - width) / 2;
-            break;
-        default:
-            // Left
-            hscroll = 0;
-            break;
-        }
+    if (!autoScroll || widthUsed <=  width || m_echoMode == QQuickTextInput::NoEcho) {
+        hscroll = 0;
     } else {
-        int cix = qRound(cursorToX(m_cursor + preeditLength));
+        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)
             hscroll = cix - width;
@@ -1329,12 +1429,64 @@ void QQuickTextInputPrivate::updateHorizontalScroll()
         if (preeditLength > 0) {
             // check to ensure long pre-edit text doesn't push the cursor
             // off to the left
-             cix = qRound(cursorToX(
-                     m_cursor + qMax(0, m_preeditCursor - 1)));
+             cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)));
              if (cix < hscroll)
                  hscroll = cix;
         }
     }
+    if (previousScroll != hscroll)
+        textLayoutDirty = true;
+}
+
+void QQuickTextInputPrivate::updateVerticalScroll()
+{
+    Q_Q(QQuickTextInput);
+    const int preeditLength = m_textLayout.preeditAreaText().length();
+    const int height = q->height();
+    int heightUsed = boundingRect.height();
+    int previousScroll = vscroll;
+
+    if (!autoScroll || heightUsed <=  height) {
+        // text fits in br; use vscroll for alignment
+        switch (vAlign & ~(Qt::AlignAbsolute|Qt::AlignHorizontal_Mask)) {
+        case Qt::AlignBottom:
+            vscroll = heightUsed - height;
+            break;
+        case Qt::AlignVCenter:
+            vscroll = (heightUsed - height) / 2;
+            break;
+        default:
+            // Top
+            vscroll = 0;
+            break;
+        }
+    } else {
+        QRectF r = m_textLayout.lineForTextPosition(m_cursor + preeditLength).rect();
+        int top = qFloor(r.top());
+        int bottom = qCeil(r.bottom());
+
+        if (bottom - vscroll >= height) {
+            // text doesn't fit, cursor is to the below the br (scroll down)
+            vscroll = bottom - height;
+        } else if (top - vscroll < 0 && vscroll < heightUsed) {
+            // text doesn't fit, cursor is above br (scroll up)
+            vscroll = top;
+        } else if (heightUsed - vscroll < height) {
+            // text doesn't fit, text document is to the left of br; align
+            // right
+            vscroll = heightUsed - height;
+        }
+        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;
+        }
+    }
+    if (previousScroll != vscroll)
+        textLayoutDirty = true;
 }
 
 QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
@@ -1364,12 +1516,11 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
 
         QPoint offset = QPoint(0,0);
         QFontMetrics fm = QFontMetrics(d->font);
-        QRect br(boundingRect().toRect());
         if (d->autoScroll) {
             // the y offset is there to keep the baseline constant in case we have script changes in the text.
-            offset = br.topLeft() - QPoint(d->hscroll, d->ascent() - fm.ascent());
+            offset = -QPoint(d->hscroll, d->vscroll + d->m_ascent - fm.ascent());
         } else {
-            offset = QPoint(d->hscroll, 0);
+            offset = -QPoint(d->hscroll, d->vscroll);
         }
 
         if (!d->m_textLayout.text().isEmpty()) {
@@ -1554,10 +1705,8 @@ void QQuickTextInput::setPasswordCharacter(const QString &str)
     if (str.length() < 1)
         return;
     d->m_passwordCharacter = str.constData()[0];
-    d->updateDisplayText();
-    if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit) {
-        updateSize();
-    }
+    if (d->m_echoMode == Password || d->m_echoMode == PasswordEchoOnEdit)
+        d->updateDisplayText();
     emit passwordCharacterChanged();
 }
 
@@ -1883,8 +2032,10 @@ void QQuickTextInputPrivate::init()
             q, SLOT(q_canPasteChanged()));
     canPaste = !m_readOnly && QGuiApplication::clipboard()->text().length() != 0;
 #endif // QT_NO_CLIPBOARD
-    updateDisplayText();
-    q->updateSize();
+    m_textLayout.beginLayout();
+    m_textLayout.createLine();
+    m_textLayout.endLayout();
+
     imHints &= ~Qt::ImhMultiLine;
     oldValidity = hasAcceptableInput(m_text);
     lastSelectionStart = 0;
@@ -1903,13 +2054,19 @@ void QQuickTextInputPrivate::init()
 void QQuickTextInput::updateCursorRectangle()
 {
     Q_D(QQuickTextInput);
-    d->determineHorizontalAlignment();
+    if (!isComponentComplete())
+        return;
+
     d->updateHorizontalScroll();
-    updateRect();//TODO: Only update rect between pos's
+    d->updateVerticalScroll();
+    update();
     updateMicroFocus();
     emit cursorRectangleChanged();
-    if (d->cursorItem)
-        d->cursorItem->setX(d->cursorToX() - d->hscroll);
+    if (d->cursorItem) {
+        QRectF r = cursorRectangle();
+        d->cursorItem->setPos(r.topLeft());
+        d->cursorItem->setHeight(r.height());
+    }
 }
 
 void QQuickTextInput::selectionChanged()
@@ -1932,21 +2089,6 @@ void QQuickTextInput::selectionChanged()
     }
 }
 
-void QQuickTextInput::q_textChanged()
-{
-    Q_D(QQuickTextInput);
-    emit textChanged();
-    emit displayTextChanged();
-    updateSize();
-    d->determineHorizontalAlignment();
-    d->updateHorizontalScroll();
-    updateMicroFocus();
-    if (hasAcceptableInput() != d->oldValidity) {
-        d->oldValidity = hasAcceptableInput();
-        emit acceptableInputChanged();
-    }
-}
-
 void QQuickTextInputPrivate::showCursor()
 {
     if (textNode != 0 && textNode->cursorNode() != 0)
@@ -1975,26 +2117,17 @@ void QQuickTextInput::updateRect(const QRect &r)
 QRectF QQuickTextInput::boundingRect() const
 {
     Q_D(const QQuickTextInput);
-    QRectF r = QQuickImplicitSizeItem::boundingRect();
 
+    QRectF r = d->boundingRect;
     int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->m_cursorWidth;
 
     // Could include font max left/right bearings to either side of rectangle.
 
     r.setRight(r.right() + cursorWidth);
+    r.translate(-d->hscroll, -d->vscroll);
     return r;
 }
 
-void QQuickTextInput::updateSize(bool needsRedraw)
-{
-    Q_D(QQuickTextInput);
-    int w = width();
-    int h = height();
-    setImplicitSize(d->calculateTextWidth(), d->calculateTextHeight());
-    if (w==width() && h==height() && needsRedraw)
-        update();
-}
-
 void QQuickTextInput::q_canPasteChanged()
 {
     Q_D(QQuickTextInput);
@@ -2041,20 +2174,53 @@ void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
             uc[i] = QChar(0x0020);
     }
 
-    m_textLayout.setText(str);
+    if (str != orig || forceUpdate) {
+        m_textLayout.setText(str);
+        updateLayout(); // polish?
+        emit q_func()->displayTextChanged();
+    }
+}
+
+void QQuickTextInputPrivate::updateLayout()
+{
+    Q_Q(QQuickTextInput);
+
+    if (!q->isComponentComplete())
+        return;
 
     QTextOption option = m_textLayout.textOption();
     option.setTextDirection(m_layoutDirection);
     option.setFlags(QTextOption::IncludeTrailingSpaces);
+    option.setWrapMode(QTextOption::WrapMode(wrapMode));
+    option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
     m_textLayout.setTextOption(option);
+    m_textLayout.setFont(font);
 
+    boundingRect = QRectF();
     m_textLayout.beginLayout();
-    QTextLine l = m_textLayout.createLine();
+    QTextLine line = m_textLayout.createLine();
+    qreal lineWidth = q->widthValid() ? q->width() : INT_MAX;
+    qreal height = 0;
+    QTextLine firstLine = line;
+    do {
+        line.setLineWidth(lineWidth);
+        line.setPosition(QPointF(line.position().x(), height));
+        boundingRect = boundingRect.united(line.naturalTextRect());
+
+        height += line.height();
+        line = m_textLayout.createLine();
+    } while (line.isValid());
     m_textLayout.endLayout();
-    m_ascent = qRound(l.ascent());
 
-    if (str != orig || forceUpdate)
-        emit q_func()->displayTextChanged();
+    option.setWrapMode(QTextOption::NoWrap);
+    m_textLayout.setTextOption(option);
+
+    m_ascent = qRound(firstLine.ascent());
+    textLayoutDirty = true;
+
+    q->update();
+    q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height()));
+
 }
 
 #ifndef QT_NO_CLIPBOARD
@@ -2117,7 +2283,7 @@ void QQuickTextInputPrivate::commitPreedit()
     m_preeditCursor = 0;
     m_textLayout.setPreeditArea(-1, QString());
     m_textLayout.clearAdditionalFormats();
-    updateDisplayText(/*force*/ true);
+    updateLayout();
 }
 
 /*!
@@ -2275,21 +2441,6 @@ void QQuickTextInputPrivate::updatePasswordEchoEditing(bool editing)
     updateDisplayText();
 }
 
-/*!
-    \internal
-
-    Returns the cursor position of the given \a x pixel value in relation
-    to the displayed text.  The given \a betweenOrOn specified what kind
-    of cursor position is requested.
-*/
-int QQuickTextInputPrivate::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
-{
-    Q_Q(const QQuickTextInput);
-    QRect cr = q->boundingRect().toRect();
-    x-= cr.x() - hscroll;
-    return m_textLayout.lineAt(0).xToCursor(x, betweenOrOn);
-}
-
 /*!
     \internal
 
@@ -2340,7 +2491,6 @@ void QQuickTextInputPrivate::moveCursor(int pos, bool mark)
             anchor = m_cursor;
         m_selstart = qMin(anchor, pos);
         m_selend = qMax(anchor, pos);
-        updateDisplayText();
     } else {
         internalDeselect();
     }
@@ -2368,6 +2518,7 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
             || event->replacementLength() > 0;
     bool cursorPositionChanged = false;
     bool selectionChange = false;
+    m_preeditDirty = event->preeditString() != preeditAreaText();
 
     if (isGettingInput) {
         // If any text is being input, remove selected text.
@@ -2442,6 +2593,7 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
         }
     }
     m_textLayout.setAdditionalFormats(formats);
+
     updateDisplayText(/*force*/ true);
     if (cursorPositionChanged)
         emitCursorPositionChanged();
@@ -2542,8 +2694,17 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
 
         if (m_textDirty) {
             m_textDirty = false;
-            q_func()->q_textChanged();
+            m_preeditDirty = false;
+            determineHorizontalAlignment();
+            emit q->textChanged();
         }
+
+        if (m_validInput != wasValidInput)
+            emit q->acceptableInputChanged();
+    }
+    if (m_preeditDirty) {
+        m_preeditDirty = false;
+        determineHorizontalAlignment();
     }
     if (m_selDirty) {
         m_selDirty = false;
diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h
index 7a07de60a3b6af3af1f9a94ddf14e14076142b01..447f3330ece6ba8abbf17be2c1c7747745d3cdfa 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -44,6 +44,7 @@
 #define QQUICKTEXTINPUT_P_H
 
 #include "qquickimplicitsizeitem_p.h"
+#include <QtGui/qtextoption.h>
 #include <QtGui/qvalidator.h>
 
 QT_BEGIN_HEADER
@@ -56,8 +57,11 @@ class Q_AUTOTEST_EXPORT QQuickTextInput : public QQuickImplicitSizeItem
 {
     Q_OBJECT
     Q_ENUMS(HAlignment)
+    Q_ENUMS(VAlignment)
+    Q_ENUMS(WrapMode)
     Q_ENUMS(EchoMode)
     Q_ENUMS(SelectionMode)
+    Q_ENUMS(CursorPosition)
 
     Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
@@ -66,6 +70,8 @@ class Q_AUTOTEST_EXPORT QQuickTextInput : public QQuickImplicitSizeItem
     Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
     Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
     Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged)
+    Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged)
+    Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
 
     Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged)
     Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible NOTIFY cursorVisibleChanged)
@@ -98,6 +104,8 @@ public:
     QQuickTextInput(QQuickItem * parent=0);
     ~QQuickTextInput();
 
+    void componentComplete();
+
     enum EchoMode {//To match QLineEdit::EchoMode
         Normal,
         NoEcho,
@@ -111,6 +119,20 @@ public:
         AlignHCenter = Qt::AlignHCenter
     };
 
+    enum VAlignment {
+        AlignTop = Qt::AlignTop,
+        AlignBottom = Qt::AlignBottom,
+        AlignVCenter = Qt::AlignVCenter
+    };
+
+    enum WrapMode {
+        NoWrap = QTextOption::NoWrap,
+        WordWrap = QTextOption::WordWrap,
+        WrapAnywhere = QTextOption::WrapAnywhere,
+        WrapAtWordBoundaryOrAnywhere = QTextOption::WrapAtWordBoundaryOrAnywhere, // COMPAT
+        Wrap = QTextOption::WrapAtWordBoundaryOrAnywhere
+    };
+
     enum SelectionMode {
         SelectCharacters,
         SelectWords
@@ -121,9 +143,9 @@ public:
         CursorOnCharacter
     };
 
+
     //Auxilliary functions needed to control the TextInput from QML
-    Q_INVOKABLE int positionAt(int x) const;
-    Q_INVOKABLE int positionAt(int x, CursorPosition position) const;
+    Q_INVOKABLE void positionAt(QDeclarativeV8Function *args) const;
     Q_INVOKABLE QRectF positionToRectangle(int pos) const;
     Q_INVOKABLE void moveCursorSelection(int pos);
     Q_INVOKABLE void moveCursorSelection(int pos, SelectionMode mode);
@@ -151,6 +173,12 @@ public:
     void resetHAlign();
     HAlignment effectiveHAlign() const;
 
+    VAlignment vAlign() const;
+    void setVAlign(VAlignment align);
+
+    WrapMode wrapMode() const;
+    void setWrapMode(WrapMode w);
+
     bool isReadOnly() const;
     void setReadOnly(bool);
 
@@ -226,6 +254,8 @@ Q_SIGNALS:
     void selectedTextColorChanged(const QColor &color);
     void fontChanged(const QFont &font);
     void horizontalAlignmentChanged(HAlignment alignment);
+    void verticalAlignmentChanged(VAlignment alignment);
+    void wrapModeChanged();
     void readOnlyChanged(bool isReadOnly);
     void cursorVisibleChanged(bool isCursorVisible);
     void cursorDelegateChanged();
@@ -273,8 +303,6 @@ public Q_SLOTS:
 #endif
 
 private Q_SLOTS:
-    void updateSize(bool needsRedraw = true);
-    void q_textChanged();
     void selectionChanged();
     void createCursor();
     void updateCursorRectangle();
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index b410bfd187c5be535030786913b66958ffe424e4..a5fa6d58b8e5e482f4809221ef57ed02c310eb98 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -81,7 +81,7 @@ public:
         , textNode(0)
         , m_maskData(0)
         , hscroll(0)
-        , oldScroll(0)
+        , vscroll(0)
         , m_cursor(0)
         , m_preeditCursor(0)
         , m_cursorWidth(1)
@@ -97,6 +97,8 @@ public:
         , m_selend(0)
         , style(QQuickText::Normal)
         , hAlign(QQuickTextInput::AlignLeft)
+        , vAlign(QQuickTextInput::AlignTop)
+        , wrapMode(QQuickTextInput::NoWrap)
         , mouseSelectionMode(QQuickTextInput::SelectCharacters)
         , inputMethodHints(Qt::ImhNone)
         , m_layoutDirection(Qt::LayoutDirectionAuto)
@@ -116,6 +118,7 @@ public:
         , m_readOnly(0)
         , m_echoMode(QQuickTextInput::Normal)
         , m_textDirty(0)
+        , m_preeditDirty(0)
         , m_selDirty(0)
         , m_validInput(1)
         , m_blinkStatus(0)
@@ -130,6 +133,7 @@ public:
     void init();
     void startCreatingCursor();
     void updateHorizontalScroll();
+    void updateVerticalScroll();
     bool determineHorizontalAlignment();
     bool setHAlign(QQuickTextInput::HAlignment, bool forceAlign = false);
     void mirrorChange();
@@ -186,13 +190,14 @@ public:
     QPoint tripleClickStartPoint;
     QList<int> m_transactions;
     QVector<Command> m_history;
+    QRectF boundingRect;
 
     int lastSelectionStart;
     int lastSelectionEnd;
     int oldHeight;
     int oldWidth;
     int hscroll;
-    int oldScroll;
+    int vscroll;
     int m_cursor;
     int m_preeditCursor;
     int m_cursorWidth;
@@ -209,6 +214,8 @@ public:
 
     QQuickText::TextStyle style;
     QQuickTextInput::HAlignment hAlign;
+    QQuickTextInput::VAlignment vAlign;
+    QQuickTextInput::WrapMode wrapMode;
     QQuickTextInput::SelectionMode mouseSelectionMode;
     Qt::InputMethodHints inputMethodHints;
     Qt::LayoutDirection m_layoutDirection;
@@ -232,6 +239,7 @@ public:
     uint m_readOnly : 1;
     uint m_echoMode : 2;
     uint m_textDirty : 1;
+    uint m_preeditDirty : 1;
     uint m_selDirty : 1;
     uint m_validInput : 1;
     uint m_blinkStatus : 1;
@@ -269,10 +277,6 @@ public:
     bool allSelected() const { return !m_text.isEmpty() && m_selstart == 0 && m_selend == (int)m_text.length(); }
     bool hasSelectedText() const { return !m_text.isEmpty() && m_selend > m_selstart; }
 
-    int calculateTextHeight() const { return qRound(m_textLayout.lineAt(0).height()); }
-    int calculateTextWidth() const { return qRound(m_textLayout.lineAt(0).naturalTextWidth()); }
-    int ascent() const { return m_ascent; }
-
     void setSelection(int start, int length);
 
     inline QString selectedText() const { return hasSelectedText() ? m_text.mid(m_selstart, m_selend - m_selstart) : QString(); }
@@ -281,12 +285,10 @@ public:
 
     int selectionStart() const { return hasSelectedText() ? m_selstart : -1; }
     int selectionEnd() const { return hasSelectedText() ? m_selend : -1; }
-    bool inSelection(int x) const
-    {
-        if (m_selstart >= m_selend)
-            return false;
-        int pos = xToPos(x, QTextLine::CursorOnCharacter);
-        return pos >= m_selstart && pos < m_selend;
+
+    int positionAt(int x, int y, QTextLine::CursorPosition position) const;
+    int positionAt(const QPointF &point, QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters) const {
+        return positionAt(point.x(), point.y(), position);
     }
 
     void removeSelection()
@@ -333,17 +335,6 @@ public:
     void home(bool mark) { moveCursor(0, mark); }
     void end(bool mark) { moveCursor(q_func()->text().length(), mark); }
 
-    int xToPos(int x, QTextLine::CursorPosition = QTextLine::CursorBetweenCharacters) const;
-
-    qreal cursorToX(int cursor) const { return m_textLayout.lineAt(0).cursorToX(cursor); }
-    qreal cursorToX() const
-    {
-        int cursor = m_cursor;
-        if (m_preeditCursor != -1)
-            cursor += m_preeditCursor;
-        return cursorToX(cursor);
-    }
-
     void backspace();
     void del();
     void deselect() { internalDeselect(); finishChange(); }
@@ -398,6 +389,8 @@ public:
     void setCursorBlinkPeriod(int msec);
     void resetCursorBlinkTimer();
 
+    void updateLayout();
+
 private:
     void init(const QString &txt);
     void removeSelectedText();
@@ -425,7 +418,6 @@ private:
 
     inline void separate() { m_separator = true; }
 
-
     // masking
     void parseInputMask(const QString &maskFields);
     bool isValidInput(QChar key, QChar mask) const;
diff --git a/tests/auto/qtquick2/qquicktextinput/data/horizontalAlignment.qml b/tests/auto/qtquick2/qquicktextinput/data/horizontalAlignment.qml
index e0fef4c11e793ea1568aa26ec042334653b2ba2e..89934532e3c1994c06e7d9ad1526ad678f4b2159 100644
--- a/tests/auto/qtquick2/qquicktextinput/data/horizontalAlignment.qml
+++ b/tests/auto/qtquick2/qquicktextinput/data/horizontalAlignment.qml
@@ -10,10 +10,11 @@ Rectangle {
     Rectangle {
         anchors.centerIn: parent
         width: 60
-        height: 20
+        height: 60
         color: "green"
 
         TextInput {
+            objectName: "text"
             id: text
             anchors.fill: parent
             text: top.text
diff --git a/tests/auto/qtquick2/qquicktextinput/data/positionAt.qml b/tests/auto/qtquick2/qquicktextinput/data/positionAt.qml
index 1840462c87ed95fccd813acb471d951f396a6180..edb47441075356f98afd2280966c9e20f73fe6e6 100644
--- a/tests/auto/qtquick2/qquicktextinput/data/positionAt.qml
+++ b/tests/auto/qtquick2/qquicktextinput/data/positionAt.qml
@@ -4,5 +4,6 @@ TextInput{
     focus: true
     objectName: "myInput"
     width: 50
+    height: 100
     text: "AAAAAAAAAAAAAAAAAAAAAAAAAAAA"
 }
diff --git a/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp
index 6b6fd73b017c5ec6a73bf9affacb4bfd1e080580..a626cb2929145a5a39c3719d78b1866352be2cb3 100644
--- a/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp
@@ -43,6 +43,7 @@
 #include "../../shared/util.h"
 #include <private/qinputpanel_p.h>
 #include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativeexpression.h>
 #include <QFile>
 #include <QtQuick/qquickview.h>
 #include <QtGui/qguiapplication.h>
@@ -83,6 +84,15 @@ QString createExpectedFileIfNotFound(const QString& filebasename, const QImage&
     return expectfile;
 }
 
+template <typename T> static T evaluate(QObject *scope, const QString &expression)
+{
+    QDeclarativeExpression expr(qmlContext(scope), scope, expression);
+    T result = expr.evaluate().value<T>();
+    if (expr.hasError())
+        qWarning() << expr.error().toString();
+    return result;
+}
+
 typedef QPair<int, QChar> Key;
 
 class tst_qquicktextinput : public QObject
@@ -100,6 +110,7 @@ private slots:
     void width();
     void font();
     void color();
+    void wrap();
     void selection();
     void isRightToLeft_data();
     void isRightToLeft();
@@ -115,6 +126,7 @@ private slots:
     void horizontalAlignment_data();
     void horizontalAlignment();
     void horizontalAlignment_RightToLeft();
+    void verticalAlignment();
 
     void positionAt();
 
@@ -479,6 +491,41 @@ void tst_qquicktextinput::color()
     }
 }
 
+void tst_qquicktextinput::wrap()
+{
+    int textHeight = 0;
+    // for specified width and wrap set true
+    {
+        QDeclarativeComponent textComponent(&engine);
+        textComponent.setData("import QtQuick 2.0\nTextInput { text: \"Hello\"; wrapMode: Text.WrapAnywhere; width: 300 }", QUrl::fromLocalFile(""));
+        QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(textComponent.create());
+        textHeight = textObject->height();
+
+        QVERIFY(textObject != 0);
+        QVERIFY(textObject->wrapMode() == QQuickTextInput::WrapAnywhere);
+        QCOMPARE(textObject->width(), 300.);
+
+        delete textObject;
+    }
+
+    for (int i = 0; i < standard.count(); i++) {
+        QString componentStr = "import QtQuick 2.0\nTextInput { wrapMode: Text.WrapAnywhere; width: 30; text: \"" + standard.at(i) + "\" }";
+        QDeclarativeComponent textComponent(&engine);
+        textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+        QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(textComponent.create());
+
+        QVERIFY(textObject != 0);
+        QCOMPARE(textObject->width(), 30.);
+        QVERIFY(textObject->height() > textHeight);
+
+        int oldHeight = textObject->height();
+        textObject->setWidth(100);
+        QVERIFY(textObject->height() < oldHeight);
+
+        delete textObject;
+    }
+}
+
 void tst_qquicktextinput::selection()
 {
     QString testStr = standard[0];
@@ -1178,37 +1225,37 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft()
 
     QQuickTextInputPrivate *textInputPrivate = QQuickTextInputPrivate::get(textInput);
     QVERIFY(textInputPrivate != 0);
-    QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() > canvas.width()/2);
 
     // implicit alignment should follow the reading direction of RTL text
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
-    QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() > canvas.width()/2);
 
     // explicitly left aligned
     textInput->setHAlign(QQuickTextInput::AlignLeft);
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft);
     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
-    QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() < canvas.width()/2);
 
     // explicitly right aligned
     textInput->setHAlign(QQuickTextInput::AlignRight);
     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
-    QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() > canvas.width()/2);
 
     // explicitly center aligned
     textInput->setHAlign(QQuickTextInput::AlignHCenter);
     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignHCenter);
-    QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
-    QVERIFY(-textInputPrivate->hscroll + textInputPrivate->width > canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() < canvas.width()/2);
+    QVERIFY(textInput->boundingRect().right() > canvas.width()/2);
 
     // reseted alignment should go back to following the text reading direction
     textInput->resetHAlign();
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
-    QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() > canvas.width()/2);
 
     // mirror the text item
     QQuickItemPrivate::get(textInput)->setLayoutMirror(true);
@@ -1216,19 +1263,19 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft()
     // mirrored implicit alignment should continue to follow the reading direction of the text
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
     QCOMPARE(textInput->effectiveHAlign(), textInput->hAlign());
-    QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() > canvas.width()/2);
 
     // explicitly right aligned behaves as left aligned
     textInput->setHAlign(QQuickTextInput::AlignRight);
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
     QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignLeft);
-    QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() < canvas.width()/2);
 
     // mirrored explicitly left aligned behaves as right aligned
     textInput->setHAlign(QQuickTextInput::AlignLeft);
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft);
     QCOMPARE(textInput->effectiveHAlign(), QQuickTextInput::AlignRight);
-    QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() > canvas.width()/2);
 
     // disable mirroring
     QQuickItemPrivate::get(textInput)->setLayoutMirror(false);
@@ -1238,7 +1285,7 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft()
     // English text should be implicitly left aligned
     textInput->setText("Hello world!");
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft);
-    QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() < canvas.width()/2);
 
     canvas.requestActivateWindow();
     QTest::qWaitForWindowShown(&canvas);
@@ -1261,12 +1308,12 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft()
     QCOMPARE(textInput->hAlign(), QGuiApplication::keyboardInputDirection() == Qt::LeftToRight ?
                                   QQuickTextInput::AlignLeft : QQuickTextInput::AlignRight);
     if (QGuiApplication::keyboardInputDirection() == Qt::LeftToRight)
-        QVERIFY(-textInputPrivate->hscroll < canvas.width()/2);
+        QVERIFY(textInput->boundingRect().left() < canvas.width()/2);
     else
-        QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+        QVERIFY(textInput->boundingRect().left() > canvas.width()/2);
     textInput->setHAlign(QQuickTextInput::AlignRight);
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
-    QVERIFY(-textInputPrivate->hscroll > canvas.width()/2);
+    QVERIFY(textInput->boundingRect().left() > canvas.width()/2);
 
     QString componentStr = "import QtQuick 2.0\nTextInput {}";
     QDeclarativeComponent textComponent(&engine);
@@ -1277,6 +1324,31 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft()
     delete textObject;
 }
 
+void tst_qquicktextinput::verticalAlignment()
+{
+    QQuickView canvas(QUrl::fromLocalFile(TESTDATA("horizontalAlignment.qml")));
+    QQuickTextInput *textInput = canvas.rootObject()->findChild<QQuickTextInput*>("text");
+    QVERIFY(textInput != 0);
+    canvas.show();
+
+    QQuickTextInputPrivate *textInputPrivate = QQuickTextInputPrivate::get(textInput);
+    QVERIFY(textInputPrivate != 0);
+
+    QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignTop);
+    QVERIFY(textInput->boundingRect().bottom() < canvas.height() / 2);
+
+    // bottom aligned
+    textInput->setVAlign(QQuickTextInput::AlignBottom);
+    QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignBottom);
+    QVERIFY(textInput->boundingRect().top () > canvas.height() / 2);
+
+    // explicitly center aligned
+    textInput->setVAlign(QQuickTextInput::AlignVCenter);
+    QCOMPARE(textInput->vAlign(), QQuickTextInput::AlignVCenter);
+    QVERIFY(textInput->boundingRect().top() < canvas.height() / 2);
+    QVERIFY(textInput->boundingRect().bottom() > canvas.height() / 2);
+}
+
 void tst_qquicktextinput::positionAt()
 {
     QQuickView canvas(QUrl::fromLocalFile(TESTDATA("positionAt.qml")));
@@ -1290,7 +1362,7 @@ void tst_qquicktextinput::positionAt()
 
     // Check autoscrolled...
 
-    int pos = textinputObject->positionAt(textinputObject->width()/2);
+    int pos = evaluate<int>(textinputObject, QString("positionAt(%1)").arg(textinputObject->width()/2));
 
     QTextLayout layout(textinputObject->text());
     layout.setFont(textinputObject->font());
@@ -1312,12 +1384,12 @@ void tst_qquicktextinput::positionAt()
     QVERIFY(textLeftWidthEnd >= textWidth - textinputObject->width() / 2);
 
     int x = textinputObject->positionToRectangle(pos + 1).x() - 1;
-    QCOMPARE(textinputObject->positionAt(x, QQuickTextInput::CursorBetweenCharacters), pos + 1);
-    QCOMPARE(textinputObject->positionAt(x, QQuickTextInput::CursorOnCharacter), pos);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, 0, TextInput.CursorBetweenCharacters)").arg(x)), pos + 1);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, 0, TextInput.CursorOnCharacter)").arg(x)), pos);
 
     // Check without autoscroll...
     textinputObject->setAutoScroll(false);
-    pos = textinputObject->positionAt(textinputObject->width()/2);
+    pos = evaluate<int>(textinputObject, QString("positionAt(%1)").arg(textinputObject->width() / 2));
 
     textLeftWidthBegin = floor(line.cursorToX(pos - 1));
     textLeftWidthEnd = ceil(line.cursorToX(pos + 1));
@@ -1326,8 +1398,8 @@ void tst_qquicktextinput::positionAt()
     QVERIFY(textLeftWidthEnd >= textinputObject->width() / 2);
 
     x = textinputObject->positionToRectangle(pos + 1).x() - 1;
-    QCOMPARE(textinputObject->positionAt(x, QQuickTextInput::CursorBetweenCharacters), pos + 1);
-    QCOMPARE(textinputObject->positionAt(x, QQuickTextInput::CursorOnCharacter), pos);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, 0, TextInput.CursorBetweenCharacters)").arg(x)), pos + 1);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, 0, TextInput.CursorOnCharacter)").arg(x)), pos);
 
     const qreal x0 = textinputObject->positionToRectangle(pos).x();
     const qreal x1 = textinputObject->positionToRectangle(pos + 1).x();
@@ -1336,17 +1408,33 @@ void tst_qquicktextinput::positionAt()
     textinputObject->setText(textinputObject->text().mid(pos));
     textinputObject->setCursorPosition(0);
 
-    QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>());
-    QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &inputEvent);
+    {   QInputMethodEvent inputEvent(preeditText, QList<QInputMethodEvent::Attribute>());
+        QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &inputEvent); }
 
     // Check all points within the preedit text return the same position.
-    QCOMPARE(textinputObject->positionAt(0), 0);
-    QCOMPARE(textinputObject->positionAt(x0 / 2), 0);
-    QCOMPARE(textinputObject->positionAt(x0), 0);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1)").arg(0)), 0);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1)").arg(x0 / 2)), 0);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1)").arg(x0)), 0);
 
     // Verify positioning returns to normal after the preedit text.
-    QCOMPARE(textinputObject->positionAt(x1), 1);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1)").arg(x1)), 1);
     QCOMPARE(textinputObject->positionToRectangle(1).x(), x1);
+
+    {   QInputMethodEvent inputEvent;
+        QGuiApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &inputEvent); }
+
+    // With wrapping.
+    textinputObject->setWrapMode(QQuickTextInput::WrapAnywhere);
+
+    const qreal y0 = line.height() / 2;
+    const qreal y1 = line.height() * 3 / 2;
+
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, %2)").arg(x0).arg(y0)), pos);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, %2)").arg(x1).arg(y0)), pos + 1);
+
+    int newLinePos = evaluate<int>(textinputObject, QString("positionAt(%1, %2)").arg(x0).arg(y1));
+    QVERIFY(newLinePos > pos);
+    QCOMPARE(evaluate<int>(textinputObject, QString("positionAt(%1, %2)").arg(x1).arg(y1)), newLinePos + 1);
 }
 
 void tst_qquicktextinput::maxLength()
@@ -1962,6 +2050,7 @@ void tst_qquicktextinput::cursorRectangle()
     layout.endLayout();
 
     input.setWidth(line.cursorToX(5, QTextLine::Leading));
+    input.setHeight(qCeil(line.height() * 3 / 2));
 
     QRect r;
 
@@ -1982,7 +2071,7 @@ void tst_qquicktextinput::cursorRectangle()
     }
 
     // Check the cursor rectangle remains within the input bounding rect when auto scrolling.
-    QVERIFY(r.left() < input.boundingRect().width());
+    QVERIFY(r.left() < input.width());
     QVERIFY(r.right() >= input.width() - error);
 
     for (int i = 6; i < text.length(); ++i) {
@@ -1994,14 +2083,50 @@ void tst_qquicktextinput::cursorRectangle()
     for (int i = text.length() - 2; i >= 0; --i) {
         input.setCursorPosition(i);
         r = input.cursorRectangle();
+        QCOMPARE(r.top(), 0);
         QVERIFY(r.right() >= 0);
         QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRect(), r);
     }
 
+    // Check vertical scrolling with word wrap.
+    input.setWrapMode(QQuickTextInput::WordWrap);
+    for (int i = 0; i <= 5; ++i) {
+        input.setCursorPosition(i);
+        r = input.cursorRectangle();
+
+        QVERIFY(r.left() < qCeil(line.cursorToX(i, QTextLine::Trailing)));
+        QVERIFY(r.right() >= qFloor(line.cursorToX(i , QTextLine::Leading)));
+        QCOMPARE(r.top(), 0);
+        QCOMPARE(input.inputMethodQuery(Qt::ImCursorRectangle).toRect(), r);
+    }
+
+    input.setCursorPosition(6);
+    r = input.cursorRectangle();
+    QCOMPARE(r.left(), 0);
+    QVERIFY(r.bottom() >= input.height() - error);
+
+    for (int i = 7; i < text.length(); ++i) {
+        input.setCursorPosition(i);
+        r = input.cursorRectangle();
+        QVERIFY(r.bottom() >= input.height() - error);
+    }
+
+    for (int i = text.length() - 2; i >= 6; --i) {
+        input.setCursorPosition(i);
+        r = input.cursorRectangle();
+        QVERIFY(r.bottom() >= input.height() - error);
+    }
+
+    for (int i = 5; i >= 0; --i) {
+        input.setCursorPosition(i);
+        r = input.cursorRectangle();
+        QCOMPARE(r.top(), 0);
+    }
+
     input.setText("Hi!");
     input.setHAlign(QQuickTextInput::AlignRight);
     r = input.cursorRectangle();
-    QVERIFY(r.left() < input.boundingRect().width());
+    QVERIFY(r.left() < input.width() + error);
     QVERIFY(r.right() >= input.width() - error);
 }
 
@@ -2215,7 +2340,6 @@ void tst_qquicktextinput::openInputPanel()
     // check default values
     QVERIFY(input->focusOnPress());
     QVERIFY(!input->hasActiveFocus());
-    qDebug() << &input << qApp->inputPanel()->inputItem();
     QCOMPARE(qApp->inputPanel()->inputItem(), static_cast<QObject*>(0));
     QCOMPARE(qApp->inputPanel()->visible(), false);
 
@@ -2419,15 +2543,15 @@ void tst_qquicktextinput::preeditAutoScroll()
 
     // test the text is scrolled so the preedit is visible.
     sendPreeditText(preeditText.mid(0, 3), 1);
-    QVERIFY(input->positionAt(0) != 0);
+    QVERIFY(evaluate<int>(input, QString("positionAt(0)")) != 0);
     QVERIFY(input->cursorRectangle().left() < input->boundingRect().width());
     QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
 
     // test the text is scrolled back when the preedit is removed.
     QInputMethodEvent imEvent;
     QCoreApplication::sendEvent(qGuiApp->inputPanel()->inputItem(), &imEvent);
-    QCOMPARE(input->positionAt(0), 0);
-    QCOMPARE(input->positionAt(input->width()), 5);
+    QCOMPARE(evaluate<int>(input, QString("positionAt(%1)").arg(0)), 0);
+    QCOMPARE(evaluate<int>(input, QString("positionAt(%1)").arg(input->width())), 5);
     QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
 
     QTextLayout layout(preeditText);
@@ -2482,8 +2606,8 @@ void tst_qquicktextinput::preeditAutoScroll()
 
     input->setAutoScroll(false);
     sendPreeditText(preeditText.mid(0, 3), 1);
-    QCOMPARE(input->positionAt(0), 0);
-    QCOMPARE(input->positionAt(input->width()), 5);
+    QCOMPARE(evaluate<int>(input, QString("positionAt(%1)").arg(0)), 0);
+    QCOMPARE(evaluate<int>(input, QString("positionAt(%1)").arg(input->width())), 5);
 }
 
 void tst_qquicktextinput::preeditCursorRectangle()
diff --git a/tests/testapplications/text/textinput.qml b/tests/testapplications/text/textinput.qml
index 98f262837257be8367339e171f90c27d6f59f7d6..271466d59afff899d66c9abbc2832f08f25109ba 100644
--- a/tests/testapplications/text/textinput.qml
+++ b/tests/testapplications/text/textinput.qml
@@ -73,6 +73,8 @@ Rectangle {
             font.pointSize: { pointvalue.model.get(pointvalue.currentIndex).value }
             font.pixelSize: { pixelvalue.model.get(pixelvalue.currentIndex).value }
             horizontalAlignment: { halignvalue.model.get(halignvalue.currentIndex).value }
+            verticalAlignment: { valignvalue.model.get(valignvalue.currentIndex).value }
+            wrapMode: { wrapvalue.model.get(wrapvalue.currentIndex).value }
             smooth: { smoothvalue.model.get(smoothvalue.currentIndex).value }
             selectByMouse: { mousevalue.model.get(mousevalue.currentIndex).value }
             echoMode: { echovalue.model.get(echovalue.currentIndex).value }