diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index b19b13fec213ec84d0f7f338c07c1023168ec7da..fa5652141c108173a8703546549fb235d5c1d83e 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -78,6 +78,7 @@ QQuickTextPrivate::QQuickTextPrivate()
 #if defined(Q_OS_MAC)
     , layoutThread(0), paintingThread(0)
 #endif
+    , lineWidth(0)
     , color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
     , lineCount(1), multilengthEos(-1)
     , elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
@@ -85,7 +86,8 @@ QQuickTextPrivate::QQuickTextPrivate()
     , style(QQuickText::Normal)
     , updateType(UpdatePaintNode)
     , maximumLineCountValid(false), updateOnComponentComplete(true), richText(false)
-    , styledText(false), singleline(false), internalWidthUpdate(false), requireImplicitWidth(false)
+    , styledText(false), widthExceeded(false), heightExceeded(false), internalWidthUpdate(false)
+    , requireImplicitSize(false), implicitWidthValid(false), implicitHeightValid(false)
     , truncated(false), hAlignImplicit(true), rightToLeftText(false)
     , layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
 {
@@ -278,16 +280,26 @@ QQuickTextPrivate::~QQuickTextPrivate()
 
 qreal QQuickTextPrivate::getImplicitWidth() const
 {
-    if (!requireImplicitWidth) {
+    if (!requireImplicitSize) {
         // We don't calculate implicitWidth unless it is required.
         // We need to force a size update now to ensure implicitWidth is calculated
         QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
-        me->requireImplicitWidth = true;
+        me->requireImplicitSize = true;
         me->updateSize();
     }
     return implicitWidth;
 }
 
+qreal QQuickTextPrivate::getImplicitHeight() const
+{
+    if (!requireImplicitSize) {
+        QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
+        me->requireImplicitSize = true;
+        me->updateSize();
+    }
+    return implicitHeight;
+}
+
 void QQuickText::q_imagesLoaded()
 {
     Q_D(QQuickText);
@@ -409,10 +421,11 @@ void QQuickTextPrivate::updateSize()
         return;
     }
 
-    if (!requireImplicitWidth) {
+    if (!requireImplicitSize) {
         emit q->implicitWidthChanged();
+        emit q->implicitHeightChanged();
         // if the implicitWidth is used, then updateSize() has already been called (recursively)
-        if (requireImplicitWidth)
+        if (requireImplicitSize)
             return;
     }
 
@@ -437,8 +450,6 @@ void QQuickTextPrivate::updateSize()
         return;
     }
 
-    qreal naturalWidth = 0;
-
     QSizeF size(0, 0);
     QSizeF previousSize = layedOutTextRect.size();
 #if defined(Q_OS_MAC)
@@ -448,7 +459,7 @@ void QQuickTextPrivate::updateSize()
     //setup instance of QTextLayout for all cases other than richtext
     if (!richText) {
         qreal baseline = 0;
-        QRectF textRect = setupTextLayout(&naturalWidth, &baseline);
+        QRectF textRect = setupTextLayout(&baseline);
 
         if (internalWidthUpdate)    // probably the result of a binding loop, but by letting it
             return;      // get this far we'll get a warning to that effect if it is.
@@ -457,7 +468,8 @@ void QQuickTextPrivate::updateSize()
         size = textRect.size();
         updateBaseline(baseline, q->height() - size.height());
     } else {
-        singleline = false; // richtext can't elide or be optimized for single-line case
+        widthExceeded = true; // always relayout rich text on width changes..
+        heightExceeded = false; // rich text layout isn't affected by height changes.
         ensureDoc();
         extra->doc->setDefaultFont(font);
         QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
@@ -472,7 +484,8 @@ void QQuickTextPrivate::updateSize()
         option.setWrapMode(QTextOption::WrapMode(wrapMode));
         option.setUseDesignMetrics(true);
         extra->doc->setDefaultTextOption(option);
-        if (requireImplicitWidth && q->widthValid()) {
+        qreal naturalWidth = 0;
+        if (requireImplicitSize && q->widthValid()) {
             extra->doc->setTextWidth(-1);
             naturalWidth = extra->doc->idealWidth();
             const bool wasInLayout = internalWidthUpdate;
@@ -486,25 +499,27 @@ void QQuickTextPrivate::updateSize()
             extra->doc->setTextWidth(q->width());
         else
             extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
+        widthExceeded = extra->doc->textWidth() < extra->doc->idealWidth();
         QSizeF dsize = extra->doc->size();
         layedOutTextRect = QRectF(QPointF(0,0), dsize);
         size = QSizeF(extra->doc->idealWidth(),dsize.height());
 
         QFontMetricsF fm(font);
         updateBaseline(fm.ascent(), q->height() - size.height());
-    }
 
-    //### need to comfirm cost of always setting these for richText
-    internalWidthUpdate = true;
-    qreal iWidth = -1;
-    if (!q->widthValid())
-        iWidth = size.width();
-    if (iWidth > -1)
-        q->setImplicitSize(iWidth, size.height());
-    internalWidthUpdate = false;
+        //### need to confirm cost of always setting these for richText
+        internalWidthUpdate = true;
+        qreal iWidth = -1;
+        if (!q->widthValid())
+            iWidth = size.width();
+        if (iWidth > -1)
+            q->setImplicitSize(iWidth, size.height());
+        internalWidthUpdate = false;
+
+        if (iWidth == -1)
+            q->setImplicitHeight(size.height());
+    }
 
-    if (iWidth == -1)
-        q->setImplicitHeight(size.height());
     if (layedOutTextRect.size() != previousSize)
         emit q->contentSizeChanged();
     updateType = UpdatePaintNode;
@@ -661,7 +676,6 @@ void QQuickTextPrivate::elideFormats(
 QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine) const
 {
     if (nextLine) {
-        nextLine->setLineWidth(INT_MAX);
         return layout.engine()->elidedText(
                 Qt::TextElideMode(elideMode),
                 QFixed::fromReal(lineWidth),
@@ -690,22 +704,21 @@ QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QT
     already absolutely positioned horizontally).
 */
 
-QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *const baseline)
+QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
 {
     Q_Q(QQuickText);
-    layout.setCacheEnabled(true);
 
-    QTextOption textOption = layout.textOption();
-    textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
-    textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
-    textOption.setUseDesignMetrics(true);
-    layout.setTextOption(textOption);
-    layout.setFont(font);
-
-    if (!requireImplicitWidth
-            && ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
-            || (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight))) {
+    bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
+    bool multilineElide = elideMode == QQuickText::ElideRight
+            && q->widthValid()
+            && (q->heightValid() || maximumLineCountValid);
+
+    if ((!requireImplicitSize || (implicitWidthValid && implicitHeightValid))
+            && ((singlelineElide && q->width() <= 0.) || (multilineElide && q->heightValid() && q->height() <= 0.))) {
         // we are elided and we have a zero width or height
+        widthExceeded = q->widthValid() && q->width() <= 0.;
+        heightExceeded = q->heightValid() && q->height() <= 0.;
+
         if (!truncated) {
             truncated = true;
             emit q->truncatedChanged();
@@ -716,21 +729,32 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
         }
 
         QFontMetricsF fm(font);
-        qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : fm.height() * lineHeight();
+        qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : qCeil(fm.height()) * lineHeight();
         *baseline = fm.ascent();
         return QRectF(0, 0, 0, height);
     }
 
-    qreal lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
-    const qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
+    layout.setCacheEnabled(true);
+    QTextOption textOption = layout.textOption();
+    if (textOption.alignment() != q->effectiveHAlign()
+            || textOption.wrapMode() != QTextOption::WrapMode(wrapMode)
+            || !textOption.useDesignMetrics()) {
+        textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
+        textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
+        textOption.setUseDesignMetrics(true);
+        layout.setTextOption(textOption);
+    }
+    if (layout.font() != font)
+        layout.setFont(font);
+
+    lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0
+            ? q->width()
+            : FLT_MAX;
+    qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
 
     const bool customLayout = isLineLaidOutConnected();
     const bool wasTruncated = truncated;
 
-    bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
-    bool multilineElide = elideMode == QQuickText::ElideRight
-            && q->widthValid()
-            && (q->heightValid() || maximumLineCountValid);
     bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
 
     bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
@@ -746,11 +770,13 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
             : largeFont;
     int scaledFontSize = largeFont;
 
+    widthExceeded = q->width() <= 0 && (singlelineElide || canWrap || horizontalFit);
+    heightExceeded = q->height() <= 0 && (multilineElide || verticalFit);
+
     QRectF br;
 
     QFont scaledFont = font;
 
-    QTextLine line;
     int visibleCount = 0;
     bool elide;
     qreal height = 0;
@@ -759,19 +785,19 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
     int elideStart = 0;
     int elideEnd = 0;
 
-    *naturalWidth = 0;
-
     int eos = multilengthEos;
 
     // Repeated layouts with reduced font sizes or abbreviated strings may be required if the text
-    // doesn't fit within the element dimensions.
+    // doesn't fit within the item dimensions,  or a binding to implicitWidth/Height changes
+    // the item dimensions.
     for (;;) {
         if (!once) {
             if (pixelSize)
                 scaledFont.setPixelSize(scaledFontSize);
             else
                 scaledFont.setPointSize(scaledFontSize);
-            layout.setFont(scaledFont);
+            if (layout.font() != scaledFont)
+                layout.setFont(scaledFont);
         }
 
         layout.beginLayout();
@@ -784,27 +810,31 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
         int unwrappedLineCount = 1;
         int maxLineCount = maximumLineCount();
         height = 0;
+        qreal naturalHeight = 0;
+        qreal previousHeight = 0;
         br = QRectF();
-        line = layout.createLine();
-        for (visibleCount = 1; ; ++visibleCount) {
-            qreal preLayoutHeight = height;
 
+        QRectF unelidedRect;
+        QTextLine line = layout.createLine();
+        for (visibleCount = 1; ; ++visibleCount) {
             if (customLayout) {
-                setupCustomLineGeometry(line, height);
+                setupCustomLineGeometry(line, naturalHeight);
             } else {
-                setLineGeometry(line, lineWidth, height);
+                setLineGeometry(line, lineWidth, naturalHeight);
             }
 
+            unelidedRect = br.united(line.naturalTextRect());
+
             // Elide the previous line if the accumulated height of the text exceeds the height
             // of the element.
-            if (multilineElide && height > maxHeight && visibleCount > 1) {
+            if (multilineElide && naturalHeight > maxHeight && visibleCount > 1) {
                 elide = true;
+                heightExceeded = true;
                 if (eos != -1)  // There's an abbreviated string available, skip the rest as it's
                     break;      // all going to be discarded.
 
                 truncated = true;
                 truncateHeight = true;
-                height = preLayoutHeight;
 
                 characterCount = line.textStart() + line.textLength();
                 visibleCount -= 1;
@@ -816,36 +846,37 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
                 elideStart = previousLine.textStart();
                 // elideEnd isn't required for right eliding.
 
-                line = previousLine;
-                height -= (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : previousLine.height() * lineHeight();
+                height = previousHeight;
                 break;
             }
 
-            QTextLine nextLine = layout.createLine();
-            if (!nextLine.isValid()) {
-                characterCount = line.textStart() + line.textLength();
-                if (singlelineElide && visibleCount == 1 && line.naturalTextWidth() > lineWidth) {
-                    // Elide a single line of  text if its width exceeds the element width.
+            const QTextLine previousLine = line;
+            line = layout.createLine();
+            if (!line.isValid()) {
+                characterCount = previousLine.textStart() + previousLine.textLength();
+                if (singlelineElide && visibleCount == 1 && previousLine.naturalTextWidth() > lineWidth) {
+                    // Elide a single previousLine of  text if its width exceeds the element width.
                     elide = true;
+                    widthExceeded = true;
                     if (eos != -1) // There's an abbreviated string available.
                         break;
 
                     truncated = true;
-                    height = preLayoutHeight;
                     elideText = layout.engine()->elidedText(
                             Qt::TextElideMode(elideMode),
                             QFixed::fromReal(lineWidth),
                             0,
-                            line.textStart(),
-                            line.textLength());
-                    elideStart = line.textStart();
-                    elideEnd = elideStart + line.textLength();
+                            previousLine.textStart(),
+                            previousLine.textLength());
+                    elideStart = previousLine.textStart();
+                    elideEnd = elideStart + previousLine.textLength();
                 } else {
-                    br = br.united(line.naturalTextRect());
+                    br = unelidedRect;
+                    height = naturalHeight;
                 }
                 break;
             } else {
-                const bool wrappedLine = layoutText.at(nextLine.textStart() - 1) != QChar::LineSeparator;
+                const bool wrappedLine = layoutText.at(line.textStart() - 1) != QChar::LineSeparator;
                 wrapped |= wrappedLine;
 
                 if (!wrappedLine)
@@ -855,58 +886,66 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
                 // if enabled.
                 if (visibleCount == maxLineCount) {
                     truncated = true;
-                    characterCount = nextLine.textStart() + nextLine.textLength();
+                    heightExceeded |= wrapped;
+                    characterCount = line.textStart() + line.textLength();
 
                     if (multilineElide) {
                         elide = true;
                         if (eos != -1)  // There's an abbreviated string available
                             break;
-                        height = preLayoutHeight;
                         elideText = wrappedLine
-                                ? elidedText(lineWidth, line, &nextLine)
-                                : elidedText(lineWidth, line);
-                        elideStart = line.textStart();
+                                ? elidedText(lineWidth, previousLine, &line)
+                                : elidedText(lineWidth, previousLine);
+                        elideStart = previousLine.textStart();
                         // elideEnd isn't required for right eliding.
                     } else {
-                        br = br.united(line.naturalTextRect());
+                        br = unelidedRect;
+                        height = naturalHeight;
                     }
                     break;
                 }
             }
-            br = br.united(line.naturalTextRect());
-            line = nextLine;
+            br = unelidedRect;
+            previousHeight = height;
+            height = naturalHeight;
         }
-        layout.endLayout();
-        br.moveTop(0);
+        widthExceeded |= wrapped;
 
-        // Save the implicitWidth of the text on the first layout only.
+        // Save the implicit size of the text on the first layout only.
         if (once) {
-            *naturalWidth = layout.maximumWidth();
             once = false;
 
-            if (requireImplicitWidth
-                    && characterCount < layoutText.length()
-                    && unwrappedLineCount < maxLineCount) {
-                // Use a new layout to get the maximum width for the remaining text.  Using a
-                // different layout excludes the truncated text from rendering.
-                QTextLayout widthLayout(layoutText.mid(characterCount), scaledFont);
-                widthLayout.setTextOption(layout.textOption());
-
-                widthLayout.beginLayout();
-                for (; unwrappedLineCount <= maxLineCount; ++unwrappedLineCount) {
-                    QTextLine line = widthLayout.createLine();
+            // If implicit sizes are required layout any additional lines up to the maximum line
+            // count.
+            if ((requireImplicitSize) && line.isValid() && unwrappedLineCount < maxLineCount) {
+                // Layout the remainder of the wrapped lines up to maxLineCount to get the implicit
+                // height.
+                for (int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
+                    line = layout.createLine();
                     if (!line.isValid())
                         break;
+                    if (layoutText.at(line.textStart() - 1) == QChar::LineSeparator)
+                        ++unwrappedLineCount;
+                    setLineGeometry(line, lineWidth, naturalHeight);
                 }
-                widthLayout.endLayout();
-                *naturalWidth = qMax(*naturalWidth, widthLayout.maximumWidth());
+
+                // Create the remainder of the unwrapped lines up to maxLineCount to get the
+                // implicit width.
+                if (line.isValid() && layoutText.at(line.textStart() + line.textLength()) != QChar::LineSeparator)
+                    line = layout.createLine();
+                for (; line.isValid() && unwrappedLineCount <= maxLineCount; ++unwrappedLineCount)
+                    line = layout.createLine();
             }
+            layout.endLayout();
+
+            const qreal naturalWidth = layout.maximumWidth();
 
             bool wasInLayout = internalWidthUpdate;
             internalWidthUpdate = true;
-            q->setImplicitWidth(*naturalWidth);
+            q->setImplicitSize(naturalWidth, naturalHeight);
             internalWidthUpdate = wasInLayout;
 
+            // Update any variables that are dependent on the validity of the width or height.
             singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
             multilineElide = elideMode == QQuickText::ElideRight
                     && q->widthValid()
@@ -918,13 +957,38 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
                     && (q->heightValid() || (maximumLineCountValid && canWrap));
 
             const qreal oldWidth = lineWidth;
-            lineWidth = q->widthValid() && q->width() > 0 ? q->width() : *naturalWidth;
-            if (lineWidth != oldWidth && (singlelineElide || multilineElide || canWrap || horizontalFit))
+            const qreal oldHeight = maxHeight;
+
+            lineWidth = q->widthValid() && q->width() > 0 ? q->width() : naturalWidth;
+            maxHeight = q->heightValid() ? q->height() : FLT_MAX;
+
+            // If the width of the item has changed and it's possible the result of wrapping,
+            // eliding, or scaling has changed do another layout.
+            if ((lineWidth < qMin(oldWidth, naturalWidth) || (widthExceeded && lineWidth > oldWidth))
+                    && (singlelineElide || multilineElide || canWrap || horizontalFit)) {
+                widthExceeded = false;
+                heightExceeded = false;
+                continue;
+            }
+
+            // If the height of the item has changed and it's possible the result of eliding,
+            // line count truncation or scaling has changed, do another layout.
+            if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
+                    && (multilineElide || (canWrap && maximumLineCountValid))) {
+                widthExceeded = false;
+                heightExceeded = false;
                 continue;
+            }
+
             // If the horizontal alignment is not left and the width was not valid we need to relayout
             // now that we know the maximum line width.
-            if (!q->widthValid() && maxLineCount > 1 && q->effectiveHAlign() != QQuickText::AlignLeft)
+            if (!implicitWidthValid && lineCount > 1 && q->effectiveHAlign() != QQuickText::AlignLeft) {
+                widthExceeded = false;
+                heightExceeded = false;
                 continue;
+            }
+        } else {
+            layout.endLayout();
         }
 
         // If the next needs to be elided and there's an abbreviated string available
@@ -939,14 +1003,15 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
             continue;
         }
 
+        br.moveTop(0);
+
         if (!horizontalFit && !verticalFit)
             break;
 
         // Try and find a font size that better fits the dimensions of the element.
-        QRectF unelidedRect = br.united(line.naturalTextRect());
-
         if (horizontalFit) {
             if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
+                widthExceeded = true;
                 largeFont = scaledFontSize - 1;
                 if (smallFont > largeFont)
                     break;
@@ -966,6 +1031,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
 
         if (verticalFit) {
             if (truncateHeight || unelidedRect.height() > maxHeight) {
+                heightExceeded = true;
                 largeFont = scaledFontSize - 1;
                 if (smallFont > largeFont)
                     break;
@@ -980,6 +1046,9 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
         }
     }
 
+    implicitWidthValid = true;
+    implicitHeightValid = true;
+
     if (eos != multilengthEos)
         truncated = true;
 
@@ -1023,7 +1092,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
         QTextLine elidedLine = elideLayout->createLine();
         elidedLine.setPosition(QPointF(0, height));
         if (customLayout) {
-            setupCustomLineGeometry(elidedLine, height, line.lineNumber());
+            setupCustomLineGeometry(elidedLine, height, visibleCount - 1);
         } else {
             setLineGeometry(elidedLine, lineWidth, height);
         }
@@ -1389,6 +1458,8 @@ void QQuickText::setFont(const QFont &font)
         // with headings or <font> tag, we need to re-parse
         if (d->formatModifiesFontSize)
             d->textHasChanged = true;
+        d->implicitWidthValid = false;
+        d->implicitHeightValid = false;
         d->updateLayout();
     }
 
@@ -1429,6 +1500,8 @@ void QQuickText::setText(const QString &n)
         d->determineHorizontalAlignment();
     }
     d->textHasChanged = true;
+    d->implicitWidthValid = false;
+    d->implicitHeightValid = false;
     qDeleteAll(d->imgTags);
     d->imgTags.clear();
     d->updateLayout();
@@ -1788,6 +1861,7 @@ void QQuickText::setMaximumLineCount(int lines)
     d->maximumLineCountValid = lines==INT_MAX ? false : true;
     if (d->maximumLineCount() != lines) {
         d->extra.value().maximumLineCount = lines;
+        d->implicitHeightValid = false;
         d->updateLayout();
         emit maximumLineCountChanged();
     }
@@ -2013,8 +2087,8 @@ QRectF QQuickText::boundingRect() const
     Q_D(const QQuickText);
 
     QRectF rect = d->layedOutTextRect;
-    rect.moveLeft(QQuickTextUtil::alignedX(rect, width(), d->hAlign));
-    rect.moveTop(QQuickTextUtil::alignedY(rect, height(), d->vAlign));
+    rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), d->hAlign));
+    rect.moveTop(QQuickTextUtil::alignedY(rect.height(), height(), d->vAlign));
 
     if (d->style != Normal)
         rect.adjust(-1, 0, 1, 2);
@@ -2044,32 +2118,54 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
 
     bool widthChanged = newGeometry.width() != oldGeometry.width();
     bool heightChanged = newGeometry.height() != oldGeometry.height();
-    bool leftAligned = effectiveHAlign() == QQuickText::AlignLeft;
     bool wrapped = d->wrapMode != QQuickText::NoWrap;
     bool elide = d->elideMode != QQuickText::ElideNone;
     bool scaleFont = d->fontSizeMode() != QQuickText::FixedSize && (widthValid() || heightValid());
+    bool verticalScale = (d->fontSizeMode() & QQuickText::VerticalFit) && heightValid();
+
+    bool widthMaximum = newGeometry.width() >= oldGeometry.width() && !d->widthExceeded;
+    bool heightMaximum = newGeometry.height() >= oldGeometry.height() && !d->heightExceeded;
 
     if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
         goto geomChangeDone;
 
-    if (leftAligned && !wrapped && !elide && !scaleFont)
-        goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
+    if (effectiveHAlign() != QQuickText::AlignLeft && widthChanged) {
+        // If the width has changed and we're not left aligned do an update so the text is
+        // repositioned even if a full layout isn't required.
+        d->updateType = QQuickTextPrivate::UpdatePaintNode;
+        update();
+    }
 
-    if (!widthChanged && !wrapped && d->singleline && !scaleFont)
-        goto geomChangeDone; // only height has changed which doesn't affect single line unwrapped text
+    if (!wrapped && !elide && !scaleFont)
+        goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
 
-    if (!widthChanged && wrapped && d->elideMode != QQuickText::ElideRight && !scaleFont && !d->isLineLaidOutConnected())
-        goto geomChangeDone; // only height changed and no multiline eliding.
+    if (elide // eliding and dimensions were and remain invalid;
+            && ((widthValid() && oldGeometry.width() <= 0 && newGeometry.width() <= 0)
+            || (heightValid() && oldGeometry.height() <= 0 && newGeometry.height() <= 0))) {
+        goto geomChangeDone;
+    }
 
-    if (leftAligned && d->elideMode == QQuickText::ElideRight && !d->truncated && d->singleline
-            && !wrapped && newGeometry.width() > oldGeometry.width() && !scaleFont)
-        goto geomChangeDone; // Eliding not affected if we're not currently truncated and we get wider.
+    if (widthMaximum && heightMaximum && !d->isLineLaidOutConnected())  // Size is sufficient and growing.
+        goto geomChangeDone;
 
-    if (d->elideMode == QQuickText::ElideRight && wrapped && newGeometry.height() > oldGeometry.height() && !scaleFont) {
-        if (!d->truncated)
-            goto geomChangeDone; // Multiline eliding not affected if we're not currently truncated and we get higher.
-        if (d->maximumLineCountValid && d->lineCount == d->maximumLineCount())
-            goto geomChangeDone; // Multiline eliding not affected if we're already at max line count and we get higher.
+    if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
+        if (newGeometry.height() > oldGeometry.height()) {
+            if (!d->heightExceeded) // Height is adequate and growing.
+                goto geomChangeDone;
+            if (d->lineCount == d->maximumLineCount())  // Reached maximum line and height is growing.
+                goto geomChangeDone;
+        } else if (newGeometry.height() < oldGeometry.height()) {
+            if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0)  // A single line won't be truncated until the text is 0 height.
+                goto geomChangeDone;
+
+            if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
+                    && d->elideMode != QQuickText::ElideRight
+                    && !(d->maximumLineCountValid && d->widthExceeded)) {
+                goto geomChangeDone;
+            }
+        }
+    } else if (!heightChanged && widthMaximum) {
+        goto geomChangeDone;
     }
 
     if (d->updateOnComponentComplete || d->textHasChanged) {
@@ -2110,7 +2206,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
 
     d->updateType = QQuickTextPrivate::UpdateNone;
 
-    const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect, height(), d->vAlign);
+    const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height(), height(), d->vAlign);
 
     // We need to make sure the layout is done in the current thread
 #if defined(Q_OS_MAC)
@@ -2134,29 +2230,30 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
     const QColor linkColor = QColor::fromRgba(d->linkColor);
 
     if (d->richText) {
+        const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), width(), d->hAlign);
         d->ensureDoc();
-        const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect, width(), d->hAlign);
         node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor);
-    } else if (d->elideMode == QQuickText::ElideNone || d->layedOutTextRect.width() > 0.) {
+    } else if (d->layedOutTextRect.width() > 0) {
+        const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, width(), d->hAlign);
         int unelidedLineCount = d->lineCount;
         if (d->elideLayout)
             unelidedLineCount -= 1;
         if (unelidedLineCount > 0) {
             node->addTextLayout(
-                        QPoint(0, dy),
+                        QPointF(dx, dy),
                         &d->layout,
                         color, d->style, styleColor, linkColor,
                         QColor(), QColor(), -1, -1,
                         0, unelidedLineCount);
         }
         if (d->elideLayout)
-            node->addTextLayout(QPoint(0, dy), d->elideLayout, color, d->style, styleColor, linkColor);
-    }
+            node->addTextLayout(QPointF(dx, dy), d->elideLayout, color, d->style, styleColor, linkColor);
 
-    foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
-        QQuickPixmap *pix = img->pix;
-        if (pix && pix->isReady())
-            node->addImage(QRectF(img->pos.x(), img->pos.y() + dy, pix->width(), pix->height()), pix->image());
+        foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
+            QQuickPixmap *pix = img->pix;
+            if (pix && pix->isReady())
+                node->addImage(QRectF(img->pos.x() + dx, img->pos.y() + dy, pix->width(), pix->height()), pix->image());
+        }
     }
     return node;
 }
@@ -2214,6 +2311,7 @@ void QQuickText::setLineHeight(qreal lineHeight)
         return;
 
     d->extra.value().lineHeight = lineHeight;
+    d->implicitHeightValid = false;
     d->updateLayout();
     emit lineHeightChanged(lineHeight);
 }
@@ -2242,6 +2340,7 @@ void QQuickText::setLineHeightMode(LineHeightMode mode)
     if (mode == d->lineHeightMode())
         return;
 
+    d->implicitHeightValid = false;
     d->extra.value().lineHeightMode = mode;
     d->updateLayout();
 
@@ -2400,14 +2499,14 @@ QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const
 {
     Q_Q(const QQuickText);
     QPointF translatedMousePos = mousePos;
-    translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect, q->height(), vAlign);
+    translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect.height(), q->height(), vAlign);
     if (styledText) {
         QString link = anchorAt(&layout, translatedMousePos);
         if (link.isEmpty() && elideLayout)
             link = anchorAt(elideLayout, translatedMousePos);
         return link;
     } else if (richText && extra.isAllocated() && extra->doc) {
-        translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect, q->width(), hAlign);
+        translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), q->width(), hAlign);
         return extra->doc->documentLayout()->anchorAt(translatedMousePos);
     }
     return QString();
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index 985b1e1c80fb9831d83300969409f079763ab90e..49d3580578e5187337902986a91b2b44a6cc3a1d 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -121,6 +121,8 @@ public:
     QThread *paintingThread;
 #endif
 
+    qreal lineWidth;
+
     QRgb color;
     QRgb linkColor;
     QRgb styleColor;
@@ -146,9 +148,12 @@ public:
     bool updateOnComponentComplete:1;
     bool richText:1;
     bool styledText:1;
-    bool singleline:1;
+    bool widthExceeded:1;
+    bool heightExceeded:1;
     bool internalWidthUpdate:1;
-    bool requireImplicitWidth:1;
+    bool requireImplicitSize:1;
+    bool implicitWidthValid:1;
+    bool implicitHeightValid:1;
     bool truncated:1;
     bool hAlignImplicit:1;
     bool rightToLeftText:1;
@@ -160,10 +165,11 @@ public:
     static const QChar elideChar;
 
     virtual qreal getImplicitWidth() const;
+    virtual qreal getImplicitHeight() const;
 
     void ensureDoc();
 
-    QRectF setupTextLayout(qreal *const naturalWidth,  qreal * const baseline);
+    QRectF setupTextLayout(qreal * const baseline);
     void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0);
     bool isLinkActivatedConnected();
     static QString anchorAt(const QTextLayout *layout, const QPointF &mousePos);
diff --git a/src/quick/items/qquicktextutil.cpp b/src/quick/items/qquicktextutil.cpp
index 176301d450b4d1de521fe5bd4f820146147fc466..151d72c6ee233e95382dd4cf283321651f168cdf 100644
--- a/src/quick/items/qquicktextutil.cpp
+++ b/src/quick/items/qquicktextutil.cpp
@@ -78,7 +78,7 @@ QQuickItem *QQuickTextUtil::createCursor(
     return item;
 }
 
-qreal QQuickTextUtil::alignedX(const QRectF &rect, qreal width, int alignment)
+qreal QQuickTextUtil::alignedX(const qreal textWidth, const qreal itemWidth, int alignment)
 {
     qreal x = 0;
     switch (alignment) {
@@ -86,26 +86,26 @@ qreal QQuickTextUtil::alignedX(const QRectF &rect, qreal width, int alignment)
     case Qt::AlignJustify:
         break;
     case Qt::AlignRight:
-        x = width - rect.width();
+        x = itemWidth - textWidth;
         break;
     case Qt::AlignHCenter:
-        x = (width - rect.width()) / 2;
+        x = (itemWidth - textWidth) / 2;
         break;
     }
     return x;
 }
 
-qreal QQuickTextUtil::alignedY(const QRectF &rect, const qreal height, int alignment)
+qreal QQuickTextUtil::alignedY(const qreal textHeight, const qreal itemHeight, int alignment)
 {
     qreal y = 0;
     switch (alignment) {
     case Qt::AlignTop:
         break;
     case Qt::AlignBottom:
-        y = height - rect.height();
+        y = itemHeight - textHeight;
         break;
     case Qt::AlignVCenter:
-        y = (height - rect.height()) / 2;
+        y = (itemHeight - textHeight) / 2;
         break;
     }
     return y;
diff --git a/src/quick/items/qquicktextutil_p.h b/src/quick/items/qquicktextutil_p.h
index d6c05aac3b88cf1a9790b11bff94631723e041d5..21435c31f80b92bbb881a0aad7ce51d844812ade 100644
--- a/src/quick/items/qquicktextutil_p.h
+++ b/src/quick/items/qquicktextutil_p.h
@@ -66,8 +66,9 @@ public:
     template <typename Private> static void setCursorDelegate(Private *d, QQmlComponent *delegate);
     template <typename Private> static void createCursor(Private *d);
 
-    static qreal alignedX(const QRectF &rect, qreal width, int alignment);
-    static qreal alignedY(const QRectF &rect, qreal height, int alignment);
+
+    static qreal alignedX(qreal textWidth, qreal itemWidth, int alignment);
+    static qreal alignedY(qreal textHeight, qreal itemHeight, int alignment);
 
 private:
     static QQuickItem *createCursor(
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 0adddb9c85f98f36811577e2e1301ae16b3209d6..7a7f5cc053c327489ff3360e9e9e957b433b6de5 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -62,6 +62,10 @@ DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
 
 Q_DECLARE_METATYPE(QQuickText::TextFormat)
 
+QT_BEGIN_NAMESPACE
+extern void qt_setQtEnableTestFont(bool value);
+QT_END_NAMESPACE
+
 class tst_qquicktext : public QQmlDataTest
 {
     Q_OBJECT
@@ -116,6 +120,7 @@ private slots:
     void contentSize();
     void implicitSizeBinding_data();
     void implicitSizeBinding();
+    void geometryChanged();
 
     void boundingRect_data();
     void boundingRect();
@@ -218,6 +223,7 @@ tst_qquicktext::tst_qquicktext()
     // << "#AA0011DD"
     // << "#00F16B11";
     //
+    qt_setQtEnableTestFont(true);
 }
 
 QQuickView *tst_qquicktext::createView(const QString &filename)
@@ -2031,6 +2037,260 @@ void tst_qquicktext::contentSize()
     QCOMPARE(spy.count(), ++spyCount);
 }
 
+void tst_qquicktext::geometryChanged()
+{
+    // Test that text is re-laid out when the geometry of the item by verifying changes in content
+    // size.  Implicit width is also tested as that in combination with item geometry provides a
+    // reference for expected content sizes.
+
+    QString componentStr = "import QtQuick 2.0\nText { font.family: \"__Qt__Box__Engine__\"; font.pixelSize: 10 }";
+    QQmlComponent textComponent(&engine);
+    textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+    QScopedPointer<QObject> object(textComponent.create());
+    QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
+
+    const qreal implicitHeight = textObject->implicitHeight();
+
+    const qreal widths[] = { 100, 2000, 3000, -100, 100 };
+    const qreal heights[] = { implicitHeight, 2000, 3000, -implicitHeight, implicitHeight };
+
+    QCOMPARE(textObject->implicitWidth(), 0.);
+    QVERIFY(implicitHeight > 0.);
+    QCOMPARE(textObject->width(), textObject->implicitWidth());
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setText("The quick red fox jumped over the lazy brown dog");
+
+    const qreal implicitWidth = textObject->implicitWidth();
+
+    QVERIFY(implicitWidth > 0.);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), textObject->implicitWidth());
+    QCOMPARE(textObject->height(), textObject->implicitHeight());
+    QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
+    QCOMPARE(textObject->contentHeight(), textObject->implicitHeight());
+
+    // Changing the geometry with no eliding, or wrapping doesn't change the content size.
+    for (int i = 0; i < 5; ++i) {
+        textObject->setWidth(widths[i]);
+        QCOMPARE(textObject->implicitWidth(), implicitWidth);
+        QCOMPARE(textObject->implicitHeight(), implicitHeight);
+        QCOMPARE(textObject->width(), widths[i]);
+        QCOMPARE(textObject->height(), implicitHeight);
+        QCOMPARE(textObject->contentWidth(), implicitWidth);
+        QCOMPARE(textObject->contentHeight(), implicitHeight);
+    }
+
+    // With eliding enabled the content width is bounded to the item width, but is never
+    // larger than the implicit width.
+    textObject->setElideMode(QQuickText::ElideRight);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(2000.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), 2000.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), implicitWidth);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(3000.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), 3000.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), implicitWidth);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(-100);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), -100.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), 0.);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(100.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    // With wrapping enabled the implicit height changes with the width.
+    textObject->setElideMode(QQuickText::ElideNone);
+    textObject->setWrapMode(QQuickText::Wrap);
+    const qreal wrappedImplicitHeight = textObject->implicitHeight();
+
+    QVERIFY(wrappedImplicitHeight > implicitHeight);
+
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), wrappedImplicitHeight);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+
+    textObject->setWidth(2000.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), 2000.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), implicitWidth);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(3000.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), 3000.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), implicitWidth);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(-100);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), -100.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), implicitWidth);    // 0 or negative width item won't wrap.
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(100.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), wrappedImplicitHeight);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+
+    // With no eliding or maximum line count the content height is the same as the implicit height.
+    for (int i = 0; i < 5; ++i) {
+        textObject->setHeight(heights[i]);
+        QCOMPARE(textObject->implicitWidth(), implicitWidth);
+        QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+        QCOMPARE(textObject->width(), 100.);
+        QCOMPARE(textObject->height(), heights[i]);
+        QVERIFY(textObject->contentWidth() <= 100.);
+        QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+    }
+
+    // The implicit height is unaffected by eliding but the content height will change.
+    textObject->setElideMode(QQuickText::ElideRight);
+
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setHeight(2000);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), 2000.);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+
+    textObject->setHeight(3000);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), 3000.);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+
+    textObject->setHeight(-implicitHeight);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), -implicitHeight);
+    QVERIFY(textObject->contentWidth() <= 0.);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);  // content height is never less than font height. seems a little odd in this instance.
+
+    textObject->setHeight(implicitHeight);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    // Varying the height with a maximum line count but no eliding won't affect the content height.
+    textObject->setElideMode(QQuickText::ElideNone);
+    textObject->setMaximumLineCount(2);
+    textObject->resetHeight();
+
+    const qreal maxLineCountImplicitHeight = textObject->implicitHeight();
+    QVERIFY(maxLineCountImplicitHeight > implicitHeight);
+    QVERIFY(maxLineCountImplicitHeight < wrappedImplicitHeight);
+
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), maxLineCountImplicitHeight);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
+
+    for (int i = 0; i < 5; ++i) {
+        textObject->setHeight(heights[i]);
+        QCOMPARE(textObject->implicitWidth(), implicitWidth);
+        QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
+        QCOMPARE(textObject->width(), 100.);
+        QCOMPARE(textObject->height(), heights[i]);
+        QVERIFY(textObject->contentWidth() <= 100.);
+        QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
+    }
+
+    // Varying the width with a maximum line count won't increase the implicit height beyond the
+    // height of the maximum number of lines.
+    textObject->setWidth(2000.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), 2000.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), implicitWidth);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(3000.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), 3000.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), implicitWidth);
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(-100);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), implicitHeight);
+    QCOMPARE(textObject->width(), -100.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QCOMPARE(textObject->contentWidth(), implicitWidth);    // 0 or negative width item won't wrap.
+    QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+    textObject->setWidth(50.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
+    QCOMPARE(textObject->width(), 50.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QVERIFY(textObject->contentWidth() <= 50.);
+    QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
+
+    textObject->setWidth(100.);
+    QCOMPARE(textObject->implicitWidth(), implicitWidth);
+    QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
+    QCOMPARE(textObject->width(), 100.);
+    QCOMPARE(textObject->height(), implicitHeight);
+    QVERIFY(textObject->contentWidth() <= 100.);
+    QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
+}
+
 void tst_qquicktext::implicitSizeBinding_data()
 {
     implicitSize_data();