Also check notifier endpoints when checking whether a signal is connected.
[profile/ivi/qtdeclarative.git] / src / quick / items / qquicktext.cpp
index 6f8aa38..2407ade 100644 (file)
@@ -3,7 +3,7 @@
 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
 ** Contact: http://www.qt-project.org/
 **
-** This file is part of the QtDeclarative module of the Qt Toolkit.
+** This file is part of the QtQml module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
 ** GNU Lesser General Public License Usage
 #include "qquicktext_p_p.h"
 
 #include <QtQuick/private/qsgcontext_p.h>
+#include <private/qqmlglobal_p.h>
 #include <private/qsgadaptationlayer_p.h>
 #include "qquicktextnode_p.h"
 #include "qquickimage_p_p.h"
 #include <QtQuick/private/qsgtexture_p.h>
 
-#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtQml/qqmlinfo.h>
 #include <QtGui/qevent.h>
 #include <QtGui/qabstracttextdocumentlayout.h>
 #include <QtGui/qpainter.h>
@@ -59,8 +60,8 @@
 #include <QtGui/qinputmethod.h>
 
 #include <private/qtextengine_p.h>
-#include <private/qdeclarativestyledtext_p.h>
-#include <QtQuick/private/qdeclarativepixmapcache_p.h>
+#include <private/qquickstyledtext_p.h>
+#include <QtQuick/private/qquickpixmapcache_p.h>
 
 #include <qmath.h>
 #include <limits.h>
@@ -71,21 +72,32 @@ QT_BEGIN_NAMESPACE
 const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
 
 QQuickTextPrivate::QQuickTextPrivate()
-    : lineHeight(1)
-    , elideLayout(0), textLine(0), doc(0)
+    : elideLayout(0), textLine(0)
 #if defined(Q_OS_MAC)
     , layoutThread(0), paintingThread(0)
 #endif
     , color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
-    , lineCount(1), maximumLineCount(INT_MAX), multilengthEos(-1), minimumPixelSize(12), minimumPointSize(12), nbActiveDownloads(0)
-    , hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop), elideMode(QQuickText::ElideNone)
+    , lineCount(1), multilengthEos(-1)
+    , elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
     , format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap)
-    , lineHeightMode(QQuickText::ProportionalHeight), style(QQuickText::Normal)
-    , fontSizeMode(QQuickText::FixedSize), updateType(UpdatePaintNode)
+    , style(QQuickText::Normal)
+    , updateType(UpdatePaintNode)
     , maximumLineCountValid(false), updateOnComponentComplete(true), richText(false)
     , styledText(false), singleline(false), internalWidthUpdate(false), requireImplicitWidth(false)
     , truncated(false), hAlignImplicit(true), rightToLeftText(false)
-    , layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false)
+    , layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
+{
+}
+
+QQuickTextPrivate::ExtraData::ExtraData()
+    : lineHeight(1.0)
+    , doc(0)
+    , minimumPixelSize(12)
+    , minimumPointSize(12)
+    , nbActiveDownloads(0)
+    , maximumLineCount(INT_MAX)
+    , lineHeightMode(QQuickText::ProportionalHeight)
+    , fontSizeMode(QQuickText::FixedSize)
 {
 }
 
@@ -111,11 +123,11 @@ QQuickTextDocumentWithImageResources::~QQuickTextDocumentWithImageResources()
 
 QVariant QQuickTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
 {
-    QDeclarativeContext *context = qmlContext(parent());
+    QQmlContext *context = qmlContext(parent());
     QUrl url = m_baseUrl.resolved(name);
 
     if (type == QTextDocument::ImageResource) {
-        QDeclarativePixmap *p = loadPixmap(context, url);
+        QQuickPixmap *p = loadPixmap(context, url);
         return p->image();
     }
 
@@ -152,10 +164,10 @@ QSizeF QQuickTextDocumentWithImageResources::intrinsicSize(
 
         QSizeF size(width, height);
         if (!hasWidth || !hasHeight) {
-            QDeclarativeContext *context = qmlContext(parent());
+            QQmlContext *context = qmlContext(parent());
             QUrl url = m_baseUrl.resolved(QUrl(imageFormat.name()));
 
-            QDeclarativePixmap *p = loadPixmap(context, url);
+            QQuickPixmap *p = loadPixmap(context, url);
             if (!p->isReady()) {
                 if (!hasWidth)
                     size.setWidth(16);
@@ -190,10 +202,10 @@ void QQuickTextDocumentWithImageResources::drawObject(
 
 QImage QQuickTextDocumentWithImageResources::image(const QTextImageFormat &format)
 {
-    QDeclarativeContext *context = qmlContext(parent());
+    QQmlContext *context = qmlContext(parent());
     QUrl url = m_baseUrl.resolved(QUrl(format.name()));
 
-    QDeclarativePixmap *p = loadPixmap(context, url);
+    QQuickPixmap *p = loadPixmap(context, url);
     return p->image();
 }
 
@@ -206,14 +218,14 @@ void QQuickTextDocumentWithImageResources::setBaseUrl(const QUrl &url, bool clea
     }
 }
 
-QDeclarativePixmap *QQuickTextDocumentWithImageResources::loadPixmap(
-        QDeclarativeContext *context, const QUrl &url)
+QQuickPixmap *QQuickTextDocumentWithImageResources::loadPixmap(
+        QQmlContext *context, const QUrl &url)
 {
 
-    QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url);
+    QHash<QUrl, QQuickPixmap *>::Iterator iter = m_resources.find(url);
 
     if (iter == m_resources.end()) {
-        QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url);
+        QQuickPixmap *p = new QQuickPixmap(context->engine(), url);
         iter = m_resources.insert(url, p);
 
         if (p->isLoading()) {
@@ -222,7 +234,7 @@ QDeclarativePixmap *QQuickTextDocumentWithImageResources::loadPixmap(
         }
     }
 
-    QDeclarativePixmap *p = *iter;
+    QQuickPixmap *p = *iter;
     if (p->isError()) {
         if (!errors.contains(url)) {
             errors.insert(url);
@@ -234,7 +246,7 @@ QDeclarativePixmap *QQuickTextDocumentWithImageResources::loadPixmap(
 
 void QQuickTextDocumentWithImageResources::clearResources()
 {
-    foreach (QDeclarativePixmap *pixmap, m_resources)
+    foreach (QQuickPixmap *pixmap, m_resources)
         pixmap->clear(this);
     qDeleteAll(m_resources);
     m_resources.clear();
@@ -298,12 +310,24 @@ void QQuickTextPrivate::updateLayout()
     if (!richText) {
         if (textHasChanged) {
             if (styledText && !text.isEmpty()) {
-                QDeclarativeStyledText::parse(text, layout, imgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid);
+                layout.setFont(font);
+                // needs temporary bool because formatModifiesFontSize is in a bit-field
+                bool fontSizeModified = false;
+                QQuickStyledText::parse(text, layout, imgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid, &fontSizeModified);
+                formatModifiesFontSize = fontSizeModified;
             } else {
                 layout.clearAdditionalFormats();
-                multilengthEos = text.indexOf(QLatin1Char('\x9c'));
-                QString tmp = multilengthEos != -1 ? text.mid(0, multilengthEos) : text;
-                tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+                QString tmp = text;
+                multilengthEos = tmp.indexOf(QLatin1Char('\x9c'));
+                if (multilengthEos != -1) {
+                    tmp = tmp.mid(0, multilengthEos);
+                    tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+                } else if (tmp.contains(QLatin1Char('\n'))) {
+                    // Replace always does a detach.  Checking for the new line character first
+                    // means iterating over those items again if found but prevents a realloc
+                    // otherwise.
+                    tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+                }
                 layout.setText(tmp);
             }
             textHasChanged = false;
@@ -311,10 +335,10 @@ void QQuickTextPrivate::updateLayout()
     } else {
         ensureDoc();
         QTextBlockFormat::LineHeightTypes type;
-        type = lineHeightMode == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
+        type = lineHeightMode() == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
         QTextBlockFormat blockFormat;
-        blockFormat.setLineHeight((lineHeightMode == QQuickText::FixedHeight ? lineHeight : lineHeight * 100), type);
-        for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next()) {
+        blockFormat.setLineHeight((lineHeightMode() == QQuickText::FixedHeight ? lineHeight() : lineHeight() * 100), type);
+        for (QTextBlock it = extra->doc->begin(); it != extra->doc->end(); it = it.next()) {
             QTextCursor cursor(it);
             cursor.mergeBlockFormat(blockFormat);
         }
@@ -333,15 +357,15 @@ void QQuickText::imageDownloadFinished()
 {
     Q_D(QQuickText);
 
-    (d->nbActiveDownloads)--;
+    (d->extra->nbActiveDownloads)--;
 
     // when all the remote images have been downloaded,
     // if one of the sizes was not specified at parsing time
     // we use the implicit size from pixmapcache and re-layout.
 
-    if (d->nbActiveDownloads == 0) {
+    if (d->extra.isAllocated() && d->extra->nbActiveDownloads == 0) {
         bool needToUpdateLayout = false;
-        foreach (QDeclarativeStyledTextImgTag *img, d->visibleImgTags) {
+        foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
             if (!img->size.isValid()) {
                 img->size = img->pix->implicitSize();
                 needToUpdateLayout = true;
@@ -358,6 +382,22 @@ void QQuickText::imageDownloadFinished()
     }
 }
 
+void QQuickTextPrivate::updateBaseline(qreal baseline, qreal dy)
+{
+    Q_Q(QQuickText);
+
+    qreal yoff = 0;
+
+    if (q->heightValid()) {
+        if (vAlign == QQuickText::AlignBottom)
+            yoff = dy;
+        else if (vAlign == QQuickText::AlignVCenter)
+            yoff = dy/2;
+    }
+
+    q->setBaselineOffset(baseline + yoff);
+}
+
 void QQuickTextPrivate::updateSize()
 {
     Q_Q(QQuickText);
@@ -374,11 +414,21 @@ void QQuickTextPrivate::updateSize()
             return;
     }
 
-    QFontMetrics fm(font);
-    if (text.isEmpty()) {
-        qreal fontHeight = fm.height();
+    if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) {
+        // How much more expensive is it to just do a full layout on an empty string here?
+        // There may be subtle differences in the height and baseline calculations between
+        // QTextLayout and QFontMetrics and the number of variables that can affect the size
+        // and position of a line is increasing.
+        QFontMetricsF fm(font);
+        qreal fontHeight = qCeil(fm.height());  // QScriptLine and therefore QTextLine rounds up
+        if (!richText) {                        // line height, so we will as well.
+            fontHeight = lineHeightMode() == QQuickText::FixedHeight
+                    ? lineHeight()
+                    : fontHeight * lineHeight();
+        }
+        updateBaseline(fm.ascent(), q->height() - fontHeight);
         q->setImplicitSize(0, fontHeight);
-        layedOutTextRect = QRect(0, 0, 0, fontHeight);
+        layedOutTextRect = QRectF(0, 0, 0, fontHeight);
         emit q->contentSizeChanged();
         updateType = UpdatePaintNode;
         q->update();
@@ -387,23 +437,27 @@ void QQuickTextPrivate::updateSize()
 
     qreal naturalWidth = 0;
 
-    int dy = q->height();
-    QSize size(0, 0);
-    QSize previousSize = layedOutTextRect.size();
+    QSizeF size(0, 0);
+    QSizeF previousSize = layedOutTextRect.size();
 #if defined(Q_OS_MAC)
     layoutThread = QThread::currentThread();
 #endif
 
     //setup instance of QTextLayout for all cases other than richtext
     if (!richText) {
-        QRect textRect = setupTextLayout(&naturalWidth);
+        qreal baseline = 0;
+        QRectF textRect = setupTextLayout(&naturalWidth, &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.
+
         layedOutTextRect = textRect;
         size = textRect.size();
-        dy -= size.height();
+        updateBaseline(baseline, q->height() - size.height());
     } else {
         singleline = false; // richtext can't elide or be optimized for single-line case
         ensureDoc();
-        doc->setDefaultFont(font);
+        extra->doc->setDefaultFont(font);
         QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
         if (rightToLeftText) {
             if (horizontalAlignment == QQuickText::AlignLeft)
@@ -415,37 +469,34 @@ void QQuickTextPrivate::updateSize()
         option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
         option.setWrapMode(QTextOption::WrapMode(wrapMode));
         option.setUseDesignMetrics(true);
-        doc->setDefaultTextOption(option);
+        extra->doc->setDefaultTextOption(option);
         if (requireImplicitWidth && q->widthValid()) {
-            doc->setTextWidth(-1);
-            naturalWidth = doc->idealWidth();
+            extra->doc->setTextWidth(-1);
+            naturalWidth = extra->doc->idealWidth();
+            const bool wasInLayout = internalWidthUpdate;
+            internalWidthUpdate = true;
+            q->setImplicitWidth(naturalWidth);
+            internalWidthUpdate = wasInLayout;
         }
+        if (internalWidthUpdate)
+            return;
         if (wrapMode != QQuickText::NoWrap && q->widthValid())
-            doc->setTextWidth(q->width());
+            extra->doc->setTextWidth(q->width());
         else
-            doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
-        dy -= (int)doc->size().height();
-        QSize dsize = doc->size().toSize();
-        layedOutTextRect = QRect(QPoint(0,0), dsize);
-        size = QSize(int(doc->idealWidth()),dsize.height());
-    }
-    int yoff = 0;
+            extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
+        QSizeF dsize = extra->doc->size();
+        layedOutTextRect = QRectF(QPointF(0,0), dsize);
+        size = QSizeF(extra->doc->idealWidth(),dsize.height());
 
-    if (q->heightValid()) {
-        if (vAlign == QQuickText::AlignBottom)
-            yoff = dy;
-        else if (vAlign == QQuickText::AlignVCenter)
-            yoff = dy/2;
+        QFontMetricsF fm(font);
+        updateBaseline(fm.ascent(), q->height() - size.height());
     }
-    q->setBaselineOffset(fm.ascent() + yoff);
 
     //### need to comfirm cost of always setting these for richText
     internalWidthUpdate = true;
     qreal iWidth = -1;
     if (!q->widthValid())
         iWidth = size.width();
-    else if (requireImplicitWidth)
-        iWidth = naturalWidth;
     if (iWidth > -1)
         q->setImplicitSize(iWidth, size.height());
     internalWidthUpdate = false;
@@ -543,8 +594,8 @@ void QQuickText::doLayout()
 
 bool QQuickTextPrivate::isLineLaidOutConnected()
 {
-    static int idx = this->signalIndex("lineLaidOut(QQuickTextLine*)");
-    return this->isSignalConnected(idx);
+    Q_Q(QQuickText);
+    IS_SIGNAL_CONNECTED(q, "lineLaidOut(QQuickTextLine*)");
 }
 
 void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset)
@@ -569,8 +620,8 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height,
             textLine->setWidth(q->width());
         else
             textLine->setWidth(INT_MAX);
-        if (lineHeight != 1.0)
-            textLine->setHeight((lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight);
+        if (lineHeight() != 1.0)
+            textLine->setHeight((lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : line.height() * lineHeight());
 
         emit q->lineLaidOut(textLine);
 
@@ -589,24 +640,43 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height,
 #endif
 }
 
-QString QQuickTextPrivate::elidedText(int lineWidth, const QTextLine &line, QTextLine *nextLine) const
+void QQuickTextPrivate::elideFormats(
+        const int start, const int length, int offset, QList<QTextLayout::FormatRange> *elidedFormats)
+{
+    const int end = start + length;
+    QList<QTextLayout::FormatRange> formats = layout.additionalFormats();
+    for (int i = 0; i < formats.count(); ++i) {
+        QTextLayout::FormatRange format = formats.at(i);
+        const int formatLength = qMin(format.start + format.length, end) - qMax(format.start, start);
+        if (formatLength > 0) {
+            format.start = qMax(offset, format.start - start + offset);
+            format.length = formatLength;
+            elidedFormats->append(format);
+        }
+    }
+}
+
+QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine) const
 {
     if (nextLine) {
         nextLine->setLineWidth(INT_MAX);
         return layout.engine()->elidedText(
                 Qt::TextElideMode(elideMode),
-                lineWidth,
+                QFixed::fromReal(lineWidth),
                 0,
                 line.textStart(),
                 line.textLength() + nextLine->textLength());
     } else {
         QString elideText = layout.text().mid(line.textStart(), line.textLength());
-        elideText[elideText.length() - 1] = elideChar;
-        // Appending the elide character may push the line over the maximum width
-        // in which case the elided text will need to be elided.
-        QFontMetricsF metrics(layout.font());
-        if (metrics.width(elideChar) + line.naturalTextWidth() >= lineWidth)
-            elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth);
+        if (!styledText) {
+            // QFontMetrics won't help eliding styled text.
+            elideText[elideText.length() - 1] = elideChar;
+            // Appending the elide character may push the line over the maximum width
+            // in which case the elided text will need to be elided.
+            QFontMetricsF metrics(layout.font());
+            if (metrics.width(elideChar) + line.naturalTextWidth() >= lineWidth)
+                elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth);
+        }
         return elideText;
     }
 }
@@ -618,7 +688,7 @@ QString QQuickTextPrivate::elidedText(int lineWidth, const QTextLine &line, QTex
     already absolutely positioned horizontally).
 */
 
-QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
+QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *const baseline)
 {
     Q_Q(QQuickText);
     layout.setCacheEnabled(true);
@@ -630,8 +700,9 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
     layout.setTextOption(textOption);
     layout.setFont(font);
 
-    if ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
-            || (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight)) {
+    if (!requireImplicitWidth
+            && ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
+            || (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight))) {
         // we are elided and we have a zero width or height
         if (!truncated) {
             truncated = true;
@@ -642,45 +713,34 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
             emit q->lineCountChanged();
         }
 
-        if (requireImplicitWidth) {
-            // Layout to determine the implicit width.
-            layout.beginLayout();
-
-            for (int i = 0; i < maximumLineCount; ++i) {
-                QTextLine line = layout.createLine();
-                if (!line.isValid())
-                    break;
-            }
-            layout.endLayout();
-            *naturalWidth = layout.maximumWidth();
-            layout.clearLayout();
-        }
-
-        QFontMetrics fm(font);
-        qreal height = (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : fm.height() * lineHeight;
-        return QRect(0, 0, 0, height);
+        QFontMetricsF fm(font);
+        qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : fm.height() * lineHeight();
+        *baseline = fm.ascent();
+        return QRectF(0, 0, 0, height);
     }
 
-    const int lineWidth = q->widthValid() ? q->width() : INT_MAX;
+    qreal lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
+    const qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
+
     const bool customLayout = isLineLaidOutConnected();
     const bool wasTruncated = truncated;
 
-    const bool singlelineElide = !styledText && elideMode != QQuickText::ElideNone && q->widthValid();
-    const bool multilineElide = !styledText
-            && elideMode == QQuickText::ElideRight
+    bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
+    bool multilineElide = elideMode == QQuickText::ElideRight
             && q->widthValid()
             && (q->heightValid() || maximumLineCountValid);
-    const bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
+    bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
 
-    const bool horizontalFit = fontSizeMode & QQuickText::HorizontalFit && q->widthValid();
-    const bool verticalFit = fontSizeMode & QQuickText::VerticalFit
+    bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
+    bool verticalFit = fontSizeMode() & QQuickText::VerticalFit
             && (q->heightValid() || (maximumLineCountValid && canWrap));
+
     const bool pixelSize = font.pixelSize() != -1;
     QString layoutText = layout.text();
 
     int largeFont = pixelSize ? font.pixelSize() : font.pointSize();
-    int smallFont = fontSizeMode != QQuickText::FixedSize
-            ? qMin(pixelSize ? minimumPixelSize : minimumPointSize, largeFont)
+    int smallFont = fontSizeMode() != QQuickText::FixedSize
+            ? qMin(pixelSize ? minimumPixelSize() : minimumPointSize(), largeFont)
             : largeFont;
     int scaledFontSize = largeFont;
 
@@ -694,6 +754,8 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
     qreal height = 0;
     QString elideText;
     bool once = true;
+    int elideStart = 0;
+    int elideEnd = 0;
 
     *naturalWidth = 0;
 
@@ -709,6 +771,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
                 scaledFont.setPointSize(scaledFontSize);
             layout.setFont(scaledFont);
         }
+
         layout.beginLayout();
 
         bool wrapped = false;
@@ -717,6 +780,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
         elide = false;
         int characterCount = 0;
         int unwrappedLineCount = 1;
+        int maxLineCount = maximumLineCount();
         height = 0;
         br = QRectF();
         line = layout.createLine();
@@ -731,7 +795,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
 
             // Elide the previous line if the accumulated height of the text exceeds the height
             // of the element.
-            if (multilineElide && height > q->height() && visibleCount > 1) {
+            if (multilineElide && height > maxHeight && visibleCount > 1) {
                 elide = true;
                 if (eos != -1)  // There's an abbreviated string available, skip the rest as it's
                     break;      // all going to be discarded.
@@ -741,18 +805,17 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
                 height = preLayoutHeight;
 
                 characterCount = line.textStart() + line.textLength();
+                visibleCount -= 1;
 
-                QTextLine previousLine = layout.lineAt(visibleCount - 2);
+                QTextLine previousLine = layout.lineAt(visibleCount - 1);
                 elideText = layoutText.at(line.textStart() - 1) != QChar::LineSeparator
                         ? elidedText(lineWidth, previousLine, &line)
                         : elidedText(lineWidth, previousLine);
-                // The previous line is the last one visible so move the current one off somewhere
-                // out of the way and back everything up one line.
-                line.setLineWidth(0);
-                line.setPosition(QPointF(FLT_MAX, FLT_MAX));
+                elideStart = previousLine.textStart();
+                // elideEnd isn't required for right eliding.
+
                 line = previousLine;
-                --visibleCount;
-                height -= (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : previousLine.height() * lineHeight;
+                height -= (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : previousLine.height() * lineHeight();
                 break;
             }
 
@@ -769,10 +832,12 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
                     height = preLayoutHeight;
                     elideText = layout.engine()->elidedText(
                             Qt::TextElideMode(elideMode),
-                            lineWidth,
+                            QFixed::fromReal(lineWidth),
                             0,
                             line.textStart(),
                             line.textLength());
+                    elideStart = line.textStart();
+                    elideEnd = elideStart + line.textLength();
                 } else {
                     br = br.united(line.naturalTextRect());
                 }
@@ -786,7 +851,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
 
                 // Stop if the maximum number of lines has been reached and elide the last line
                 // if enabled.
-                if (visibleCount == maximumLineCount) {
+                if (visibleCount == maxLineCount) {
                     truncated = true;
                     characterCount = nextLine.textStart() + nextLine.textLength();
 
@@ -798,18 +863,17 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
                         elideText = wrappedLine
                                 ? elidedText(lineWidth, line, &nextLine)
                                 : elidedText(lineWidth, line);
+                        elideStart = line.textStart();
+                        // elideEnd isn't required for right eliding.
                     } else {
                         br = br.united(line.naturalTextRect());
                     }
-                    nextLine.setLineWidth(0);
-                    nextLine.setPosition(QPointF(FLT_MAX, FLT_MAX));
                     break;
                 }
             }
             br = br.united(line.naturalTextRect());
             line = nextLine;
         }
-
         layout.endLayout();
         br.moveTop(0);
 
@@ -820,19 +884,41 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
 
             if (requireImplicitWidth
                     && characterCount < layoutText.length()
-                    && unwrappedLineCount < maximumLineCount) {
+                    && 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());
 
-                for (; unwrappedLineCount <= maximumLineCount; ++unwrappedLineCount) {
+                widthLayout.beginLayout();
+                for (; unwrappedLineCount <= maxLineCount; ++unwrappedLineCount) {
                     QTextLine line = widthLayout.createLine();
                     if (!line.isValid())
                         break;
                 }
+                widthLayout.endLayout();
                 *naturalWidth = qMax(*naturalWidth, widthLayout.maximumWidth());
             }
+
+            bool wasInLayout = internalWidthUpdate;
+            internalWidthUpdate = true;
+            q->setImplicitWidth(*naturalWidth);
+            internalWidthUpdate = wasInLayout;
+
+            singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
+            multilineElide = elideMode == QQuickText::ElideRight
+                    && q->widthValid()
+                    && (q->heightValid() || maximumLineCountValid);
+            canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
+
+            horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
+            verticalFit = fontSizeMode() & QQuickText::VerticalFit
+                    && (q->heightValid() || (maximumLineCountValid && canWrap));
+
+            const qreal oldWidth = lineWidth;
+            lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
+            if (lineWidth != oldWidth && (singlelineElide || multilineElide || canWrap || horizontalFit))
+                continue;
         }
 
         // If the next needs to be elided and there's an abbreviated string available
@@ -856,40 +942,73 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
         if (horizontalFit) {
             if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
                 largeFont = scaledFontSize - 1;
-                scaledFontSize = (smallFont + largeFont) / 2;
                 if (smallFont > largeFont)
                     break;
+                scaledFontSize = (smallFont + largeFont) / 2;
+                if (pixelSize)
+                    scaledFont.setPixelSize(scaledFontSize);
+                else
+                    scaledFont.setPointSize(scaledFontSize);
                 continue;
             } else if (!verticalFit) {
                 smallFont = scaledFontSize;
-                scaledFontSize = (smallFont + largeFont + 1) / 2;
                 if (smallFont == largeFont)
                     break;
+                scaledFontSize = (smallFont + largeFont + 1) / 2;
             }
         }
 
         if (verticalFit) {
-            if (truncateHeight || (q->heightValid() && unelidedRect.height() > q->height())) {
+            if (truncateHeight || unelidedRect.height() > maxHeight) {
                 largeFont = scaledFontSize - 1;
-                scaledFontSize = (smallFont + largeFont + 1) / 2;
                 if (smallFont > largeFont)
                     break;
+                scaledFontSize = (smallFont + largeFont) / 2;
+
             } else {
                 smallFont = scaledFontSize;
-                scaledFontSize = (smallFont + largeFont + 1) / 2;
                 if (smallFont == largeFont)
                     break;
+                scaledFontSize = (smallFont + largeFont + 1) / 2;
             }
         }
-
     }
 
     if (eos != multilengthEos)
         truncated = true;
 
     if (elide) {
-        if (!elideLayout)
+        if (!elideLayout) {
             elideLayout = new QTextLayout;
+            elideLayout->setCacheEnabled(true);
+        }
+        if (styledText) {
+            QList<QTextLayout::FormatRange> formats;
+            switch (elideMode) {
+            case QQuickText::ElideRight:
+                elideFormats(elideStart, elideText.length() - 1, 0, &formats);
+                break;
+            case QQuickText::ElideLeft:
+                elideFormats(elideEnd - elideText.length() + 1, elideText.length() - 1, 1, &formats);
+                break;
+            case QQuickText::ElideMiddle: {
+                const int index = elideText.indexOf(elideChar);
+                if (index != -1) {
+                    elideFormats(elideStart, index, 0, &formats);
+                    elideFormats(
+                            elideEnd - elideText.length() + index + 1,
+                            elideText.length() - index - 1,
+                            index + 1,
+                            &formats);
+                }
+                break;
+            }
+            default:
+                break;
+            }
+            elideLayout->setAdditionalFormats(formats);
+        }
+
         elideLayout->setFont(layout.font());
         elideLayout->setTextOption(layout.textOption());
         elideLayout->setText(elideText);
@@ -906,15 +1025,19 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
 
         br = br.united(elidedLine.naturalTextRect());
 
-        if (visibleCount > 1)
-            line.setPosition(QPointF(FLT_MAX, FLT_MAX));
-        else
+        if (visibleCount == 1)
             layout.clearLayout();
     } else {
         delete elideLayout;
         elideLayout = 0;
     }
 
+    QTextLine firstLine = visibleCount == 1 && elideLayout
+            ? elideLayout->lineAt(0)
+            : layout.lineAt(0);
+    Q_ASSERT(firstLine.isValid());
+    *baseline = firstLine.y() + firstLine.ascent();
+
     if (!customLayout)
         br.setHeight(height);
 
@@ -927,7 +1050,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth)
     if (truncated != wasTruncated)
         emit q->truncatedChanged();
 
-    return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
+    return br;
 }
 
 void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height)
@@ -937,7 +1060,7 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
 
     if (imgTags.isEmpty()) {
         line.setPosition(QPointF(line.position().x(), height));
-        height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight;
+        height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : line.height() * lineHeight();
         return;
     }
 
@@ -945,18 +1068,20 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
     qreal textHeight = line.height();
     qreal totalLineHeight = textHeight;
 
-    QList<QDeclarativeStyledTextImgTag *> imagesInLine;
+    QList<QQuickStyledTextImgTag *> imagesInLine;
 
-    foreach (QDeclarativeStyledTextImgTag *image, imgTags) {
+    foreach (QQuickStyledTextImgTag *image, imgTags) {
         if (image->position >= line.textStart() &&
             image->position < line.textStart() + line.textLength()) {
 
             if (!image->pix) {
                 QUrl url = q->baseUrl().resolved(image->url);
-                image->pix = new QDeclarativePixmap(qmlEngine(q), url, image->size);
+                image->pix = new QQuickPixmap(qmlEngine(q), url, image->size);
                 if (image->pix->isLoading()) {
                     image->pix->connectFinished(q, SLOT(imageDownloadFinished()));
-                    nbActiveDownloads++;
+                    if (!extra.isAllocated() || !extra->nbActiveDownloads)
+                        extra.value().nbActiveDownloads = 0;
+                    extra->nbActiveDownloads++;
                 } else if (image->pix->isReady()) {
                     if (!image->size.isValid()) {
                         image->size = image->pix->implicitSize();
@@ -970,9 +1095,9 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
             }
 
             qreal ih = qreal(image->size.height());
-            if (image->align == QDeclarativeStyledTextImgTag::Top)
+            if (image->align == QQuickStyledTextImgTag::Top)
                 image->pos.setY(0);
-            else if (image->align == QDeclarativeStyledTextImgTag::Middle)
+            else if (image->align == QQuickStyledTextImgTag::Middle)
                 image->pos.setY((textHeight / 2.0) - (ih / 2.0));
             else
                 image->pos.setY(textHeight - ih);
@@ -981,7 +1106,7 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
         }
     }
 
-    foreach (QDeclarativeStyledTextImgTag *image, imagesInLine) {
+    foreach (QQuickStyledTextImgTag *image, imagesInLine) {
         totalLineHeight = qMax(totalLineHeight, textTop + image->pos.y() + image->size.height());
         image->pos.setX(line.cursorToX(image->position));
         image->pos.setY(image->pos.y() + height + textTop);
@@ -989,7 +1114,7 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
     }
 
     line.setPosition(QPointF(line.position().x(), height + textTop));
-    height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : totalLineHeight * lineHeight;
+    height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : totalLineHeight * lineHeight();
 }
 
 /*!
@@ -997,12 +1122,12 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
 */
 void QQuickTextPrivate::ensureDoc()
 {
-    if (!doc) {
+    if (!extra.isAllocated() || !extra->doc) {
         Q_Q(QQuickText);
-        doc = new QQuickTextDocumentWithImageResources(q);
-        doc->setDocumentMargin(0);
-        doc->setBaseUrl(q->baseUrl());
-        FAST_CONNECT(doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded()));
+        extra.value().doc = new QQuickTextDocumentWithImageResources(q);
+        extra->doc->setDocumentMargin(0);
+        extra->doc->setBaseUrl(q->baseUrl());
+        FAST_CONNECT(extra->doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded()));
     }
 }
 
@@ -1092,11 +1217,11 @@ QQuickText::~QQuickText()
 
     The properties of a line are:
     \list
-    \o number (read-only)
-    \o x
-    \o y
-    \o width
-    \o height
+    \li number (read-only)
+    \li x
+    \li y
+    \li width
+    \li height
     \endlist
 
     For example, this will move the first 5 lines of a text element by 100 pixels to the right:
@@ -1117,7 +1242,7 @@ QQuickText::~QQuickText()
     The link must be in rich text or HTML format and the
     \a link string provides access to the particular link.
 
-    \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
+    \snippet doc/src/snippets/qml/text/onLinkActivated.qml 0
 
     The example code will display the text
     "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
@@ -1149,11 +1274,11 @@ QQuickText::~QQuickText()
 
     The weight can be one of:
     \list
-    \o Font.Light
-    \o Font.Normal - the default
-    \o Font.DemiBold
-    \o Font.Bold
-    \o Font.Black
+    \li Font.Light
+    \li Font.Normal - the default
+    \li Font.DemiBold
+    \li Font.Bold
+    \li Font.Black
     \endlist
 
     \qml
@@ -1219,11 +1344,11 @@ QQuickText::~QQuickText()
     Sets the capitalization for the text.
 
     \list
-    \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
-    \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
-    \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
-    \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
-    \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
+    \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
+    \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
+    \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
+    \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
+    \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
     \endlist
 
     \qml
@@ -1252,8 +1377,13 @@ void QQuickText::setFont(const QFont &font)
         d->font.setPointSizeF(size/2.0);
     }
 
-    if (oldFont != d->font)
+    if (oldFont != d->font) {
+        // if the format changes the size of the text
+        // with headings or <font> tag, we need to re-parse
+        if (d->formatModifiesFontSize)
+            d->textHasChanged = true;
         d->updateLayout();
+    }
 
     emit fontChanged(d->sourceFont);
 }
@@ -1284,8 +1414,8 @@ void QQuickText::setText(const QString &n)
     if (isComponentComplete()) {
         if (d->richText) {
             d->ensureDoc();
-            d->doc->setText(n);
-            d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+            d->extra->doc->setText(n);
+            d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
         } else {
             d->rightToLeftText = d->text.isRightToLeft();
         }
@@ -1375,10 +1505,10 @@ void QQuickText::setLinkColor(const QColor &color)
 
     Supported text styles are:
     \list
-    \o Text.Normal - the default
-    \o Text.Outline
-    \o Text.Raised
-    \o Text.Sunken
+    \li Text.Normal - the default
+    \li Text.Outline
+    \li Text.Raised
+    \li Text.Sunken
     \endlist
 
     \qml
@@ -1549,11 +1679,6 @@ void QQuickTextPrivate::mirrorChange()
     }
 }
 
-QTextDocument *QQuickTextPrivate::textDocument()
-{
-    return doc;
-}
-
 QQuickText::VAlignment QQuickText::vAlign() const
 {
     Q_D(const QQuickText);
@@ -1577,10 +1702,10 @@ void QQuickText::setVAlign(VAlignment align)
     wrap if an explicit width has been set.  wrapMode can be one of:
 
     \list
-    \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l contentWidth will exceed a set width.
-    \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l contentWidth will exceed a set width.
-    \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
-    \o Text.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.
+    \li Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l contentWidth will exceed a set width.
+    \li Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l contentWidth will exceed a set width.
+    \li Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
+    \li Text.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
 */
 QQuickText::WrapMode QQuickText::wrapMode() const
@@ -1646,7 +1771,7 @@ bool QQuickText::truncated() const
 int QQuickText::maximumLineCount() const
 {
     Q_D(const QQuickText);
-    return d->maximumLineCount;
+    return d->maximumLineCount();
 }
 
 void QQuickText::setMaximumLineCount(int lines)
@@ -1654,8 +1779,8 @@ void QQuickText::setMaximumLineCount(int lines)
     Q_D(QQuickText);
 
     d->maximumLineCountValid = lines==INT_MAX ? false : true;
-    if (d->maximumLineCount != lines) {
-        d->maximumLineCount = lines;
+    if (d->maximumLineCount() != lines) {
+        d->extra.value().maximumLineCount = lines;
         d->updateLayout();
         emit maximumLineCountChanged();
     }
@@ -1679,10 +1804,10 @@ void QQuickText::resetMaximumLineCount()
     Supported text formats are:
 
     \list
-    \o Text.AutoText (default)
-    \o Text.PlainText
-    \o Text.StyledText
-    \o Text.RichText
+    \li Text.AutoText (default)
+    \li Text.PlainText
+    \li Text.StyledText
+    \li Text.RichText
     \endlist
 
     If the text format is \c Text.AutoText the text element
@@ -1716,7 +1841,7 @@ void QQuickText::resetMaximumLineCount()
 
     \table
     \row
-    \o
+    \li
     \qml
 Column {
     Text {
@@ -1735,7 +1860,7 @@ Column {
     }
 }
     \endqml
-    \o \image declarative-textformat.png
+    \li \image declarative-textformat.png
     \endtable
 */
 QQuickText::TextFormat QQuickText::textFormat() const
@@ -1757,8 +1882,8 @@ void QQuickText::setTextFormat(TextFormat format)
     if (isComponentComplete()) {
         if (!wasRich && d->richText) {
             d->ensureDoc();
-            d->doc->setText(d->text);
-            d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+            d->extra->doc->setText(d->text);
+            d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
         } else {
             d->rightToLeftText = d->text.isRightToLeft();
         }
@@ -1779,10 +1904,10 @@ void QQuickText::setTextFormat(TextFormat format)
 
     Eliding can be:
     \list
-    \o Text.ElideNone  - the default
-    \o Text.ElideLeft
-    \o Text.ElideMiddle
-    \o Text.ElideRight
+    \li Text.ElideNone  - the default
+    \li Text.ElideLeft
+    \li Text.ElideMiddle
+    \li Text.ElideRight
     \endlist
 
     If this property is set to Text.ElideRight, it can be used with \l {wrapMode}{wrapped}
@@ -1811,7 +1936,7 @@ void QQuickText::setElideMode(QQuickText::TextElideMode mode)
     d->elideMode = mode;
     d->updateLayout();
 
-    emit elideModeChanged(d->elideMode);
+    emit elideModeChanged(mode);
 }
 
 /*!
@@ -1824,14 +1949,14 @@ void QQuickText::setElideMode(QQuickText::TextElideMode mode)
     URL meaning any portion of the path after the last '/' will be ignored.
 
     \table
-    \header \o Base URL \o Relative URL \o Resolved URL
-    \row \o http://qt-project.org/ \o images/logo.png \o http://qt-project.org/images/logo.png
-    \row \o http://qt-project.org/index.html \o images/logo.png \o http://qt-project.org/images/logo.png
-    \row \o http://qt-project.org/content \o images/logo.png \o http://qt-project.org/content/images/logo.png
-    \row \o http://qt-project.org/content/ \o images/logo.png \o http://qt-project.org/content/images/logo.png
-    \row \o http://qt-project.org/content/index.html \o images/logo.png \o http://qt-project.org/content/images/logo.png
-    \row \o http://qt-project.org/content/index.html \o ../images/logo.png \o http://qt-project.org/images/logo.png
-    \row \o http://qt-project.org/content/index.html \o /images/logo.png \o http://qt-project.org/images/logo.png
+    \header \li Base URL \li Relative URL \li Resolved URL
+    \row \li http://qt-project.org/ \li images/logo.png \li http://qt-project.org/images/logo.png
+    \row \li http://qt-project.org/index.html \li images/logo.png \li http://qt-project.org/images/logo.png
+    \row \li http://qt-project.org/content \li images/logo.png \li http://qt-project.org/content/images/logo.png
+    \row \li http://qt-project.org/content/ \li images/logo.png \li http://qt-project.org/content/images/logo.png
+    \row \li http://qt-project.org/content/index.html \li images/logo.png \li http://qt-project.org/content/images/logo.png
+    \row \li http://qt-project.org/content/index.html \li ../images/logo.png \li http://qt-project.org/images/logo.png
+    \row \li http://qt-project.org/content/index.html \li /images/logo.png \li http://qt-project.org/images/logo.png
     \endtable
 
     By default is the url of the Text element.
@@ -1841,7 +1966,7 @@ QUrl QQuickText::baseUrl() const
 {
     Q_D(const QQuickText);
     if (d->baseUrl.isEmpty()) {
-        if (QDeclarativeContext *context = qmlContext(this))
+        if (QQmlContext *context = qmlContext(this))
             const_cast<QQuickTextPrivate *>(d)->baseUrl = context->baseUrl();
     }
     return d->baseUrl;
@@ -1853,8 +1978,10 @@ void QQuickText::setBaseUrl(const QUrl &url)
     if (baseUrl() != url) {
         d->baseUrl = url;
 
-        if (d->doc)
-            d->doc->setBaseUrl(url);
+        if (d->richText) {
+            d->ensureDoc();
+            d->extra->doc->setBaseUrl(url);
+        }
         if (d->styledText) {
             d->textHasChanged = true;
             qDeleteAll(d->imgTags);
@@ -1867,7 +1994,7 @@ void QQuickText::setBaseUrl(const QUrl &url)
 
 void QQuickText::resetBaseUrl()
 {
-    if (QDeclarativeContext *context = qmlContext(this))
+    if (QQmlContext *context = qmlContext(this))
         setBaseUrl(context->baseUrl());
     else
         setBaseUrl(QUrl());
@@ -1878,13 +2005,26 @@ QRectF QQuickText::boundingRect() const
 {
     Q_D(const QQuickText);
 
-    QRect rect = d->layedOutTextRect;
+    QRectF rect = d->layedOutTextRect;
     if (d->style != Normal)
         rect.adjust(-1, 0, 1, 2);
 
     // Could include font max left/right bearings to either side of rectangle.
 
-    int h = height();
+    qreal w = width();
+    switch (d->hAlign) {
+    case AlignLeft:
+    case AlignJustify:
+        break;
+    case AlignRight:
+        rect.moveLeft(w - rect.width());
+        break;
+    case AlignHCenter:
+        rect.moveLeft((w - rect.width()) / 2);
+        break;
+    }
+
+    qreal h = height();
     switch (d->vAlign) {
     case AlignTop:
         break;
@@ -1896,7 +2036,7 @@ QRectF QQuickText::boundingRect() const
         break;
     }
 
-    return QRectF(rect);
+    return rect;
 }
 
 /*! \internal */
@@ -1913,7 +2053,7 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
     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 scaleFont = d->fontSizeMode() != QQuickText::FixedSize && (widthValid() || heightValid());
 
     if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
         goto geomChangeDone;
@@ -1934,7 +2074,7 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
     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)
+        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.
     }
 
@@ -2001,15 +2141,25 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
 
     if (d->richText) {
         d->ensureDoc();
-        node->addTextDocument(bounds.topLeft(), d->doc, color, d->style, styleColor, linkColor);
+        node->addTextDocument(bounds.topLeft(), d->extra->doc, color, d->style, styleColor, linkColor);
     } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) {
-        node->addTextLayout(QPoint(0, bounds.y()), &d->layout, color, d->style, styleColor, linkColor);
+        int unelidedLineCount = d->lineCount;
+        if (d->elideLayout)
+            unelidedLineCount -= 1;
+        if (unelidedLineCount > 0) {
+            node->addTextLayout(
+                        QPoint(0, bounds.y()),
+                        &d->layout,
+                        d->color, d->style, d->styleColor, d->linkColor,
+                        QColor(), QColor(), -1, -1,
+                        0, unelidedLineCount);
+        }
         if (d->elideLayout)
             node->addTextLayout(QPoint(0, bounds.y()), d->elideLayout, color, d->style, styleColor, linkColor);
     }
 
-    foreach (QDeclarativeStyledTextImgTag *img, d->visibleImgTags) {
-        QDeclarativePixmap *pix = img->pix;
+    foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
+        QQuickPixmap *pix = img->pix;
         if (pix && pix->isReady())
             node->addImage(QRectF(img->pos.x(), img->pos.y() + bounds.y(), pix->width(), pix->height()), pix->image());
     }
@@ -2019,10 +2169,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
 void QQuickText::updatePolish()
 {
     Q_D(QQuickText);
-    if (d->updateLayoutOnPolish)
-        d->updateLayout();
-    else
-        d->updateSize();
+    d->updateSize();
 }
 
 /*!
@@ -2061,17 +2208,17 @@ qreal QQuickText::contentHeight() const
 qreal QQuickText::lineHeight() const
 {
     Q_D(const QQuickText);
-    return d->lineHeight;
+    return d->lineHeight();
 }
 
 void QQuickText::setLineHeight(qreal lineHeight)
 {
     Q_D(QQuickText);
 
-    if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
+    if ((d->lineHeight() == lineHeight) || (lineHeight < 0.0))
         return;
 
-    d->lineHeight = lineHeight;
+    d->extra.value().lineHeight = lineHeight;
     d->updateLayout();
     emit lineHeightChanged(lineHeight);
 }
@@ -2083,24 +2230,24 @@ void QQuickText::setLineHeight(qreal lineHeight)
     The possible values are:
 
     \list
-    \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
+    \li Text.ProportionalHeight (default) - this sets the spacing proportional to the
        line (as a multiplier). For example, set to 2 for double spacing.
-    \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
+    \li Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
     \endlist
 */
 QQuickText::LineHeightMode QQuickText::lineHeightMode() const
 {
     Q_D(const QQuickText);
-    return d->lineHeightMode;
+    return d->lineHeightMode();
 }
 
 void QQuickText::setLineHeightMode(LineHeightMode mode)
 {
     Q_D(QQuickText);
-    if (mode == d->lineHeightMode)
+    if (mode == d->lineHeightMode())
         return;
 
-    d->lineHeightMode = mode;
+    d->extra.value().lineHeightMode = mode;
     d->updateLayout();
 
     emit lineHeightModeChanged(mode);
@@ -2113,13 +2260,13 @@ void QQuickText::setLineHeightMode(LineHeightMode mode)
     The possible values are:
 
     \list
-    \o Text.FixedSize (default) - The size specified by \l font.pixelSize
+    \li Text.FixedSize (default) - The size specified by \l font.pixelSize
     or \l font.pointSize is used.
-    \o Text.HorizontalFit - The largest size up to the size specified that fits
+    \li Text.HorizontalFit - The largest size up to the size specified that fits
     within the width of the item without wrapping is used.
-    \o Text.VerticalFit - The largest size up to the size specified that fits
+    \li Text.VerticalFit - The largest size up to the size specified that fits
     the height of the item is used.
-    \o Text.Fit - The largest size up to the size specified the fits within the
+    \li Text.Fit - The largest size up to the size specified the fits within the
     width and height of the item is used.
     \endlist
 
@@ -2134,18 +2281,18 @@ void QQuickText::setLineHeightMode(LineHeightMode mode)
 QQuickText::FontSizeMode QQuickText::fontSizeMode() const
 {
     Q_D(const QQuickText);
-    return d->fontSizeMode;
+    return d->fontSizeMode();
 }
 
 void QQuickText::setFontSizeMode(FontSizeMode mode)
 {
     Q_D(QQuickText);
-    if (d->fontSizeMode == mode)
+    if (d->fontSizeMode() == mode)
         return;
 
     polish();
 
-    d->fontSizeMode = mode;
+    d->extra.value().fontSizeMode = mode;
     emit fontSizeModeChanged();
 }
 
@@ -2162,18 +2309,18 @@ void QQuickText::setFontSizeMode(FontSizeMode mode)
 int QQuickText::minimumPixelSize() const
 {
     Q_D(const QQuickText);
-    return d->minimumPixelSize;
+    return d->minimumPixelSize();
 }
 
 void QQuickText::setMinimumPixelSize(int size)
 {
     Q_D(QQuickText);
-    if (d->minimumPixelSize == size)
+    if (d->minimumPixelSize() == size)
         return;
 
-    if (d->fontSizeMode != FixedSize && (widthValid() || heightValid()))
+    if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid()))
         polish();
-    d->minimumPixelSize = size;
+    d->extra.value().minimumPixelSize = size;
     emit minimumPixelSizeChanged();
 }
 
@@ -2190,18 +2337,18 @@ void QQuickText::setMinimumPixelSize(int size)
 int QQuickText::minimumPointSize() const
 {
     Q_D(const QQuickText);
-    return d->minimumPointSize;
+    return d->minimumPointSize();
 }
 
 void QQuickText::setMinimumPointSize(int size)
 {
     Q_D(QQuickText);
-    if (d->minimumPointSize == size)
+    if (d->minimumPointSize() == size)
         return;
 
-    if (d->fontSizeMode != FixedSize && (widthValid() || heightValid()))
+    if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid()))
         polish();
-    d->minimumPointSize = size;
+    d->extra.value().minimumPointSize = size;
     emit minimumPointSizeChanged();
 }
 
@@ -2211,7 +2358,9 @@ void QQuickText::setMinimumPointSize(int size)
 int QQuickText::resourcesLoading() const
 {
     Q_D(const QQuickText);
-    return d->doc ? d->doc->resourcesLoading() : 0;
+    if (d->richText && d->extra.isAllocated() && d->extra->doc)
+        return d->extra->doc->resourcesLoading();
+    return 0;
 }
 
 /*! \internal */
@@ -2221,8 +2370,8 @@ void QQuickText::componentComplete()
     if (d->updateOnComponentComplete) {
         if (d->richText) {
             d->ensureDoc();
-            d->doc->setText(d->text);
-            d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+            d->extra->doc->setText(d->text);
+            d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft();
         } else {
             d->rightToLeftText = d->text.isRightToLeft();
         }
@@ -2231,9 +2380,6 @@ void QQuickText::componentComplete()
     QQuickItem::componentComplete();
     if (d->updateOnComponentComplete)
         d->updateLayout();
-
-    // Enable accessibility for text items.
-    d->setAccessibleFlagAndListener();
 }
 
 
@@ -2260,8 +2406,8 @@ QString QQuickTextPrivate::anchorAt(const QPointF &mousePos)
 
 bool QQuickTextPrivate::isLinkActivatedConnected()
 {
-    static int idx = this->signalIndex("linkActivated(QString)");
-    return this->isSignalConnected(idx);
+    Q_Q(QQuickText);
+    IS_SIGNAL_CONNECTED(q, "linkActivated(QString)");
 }
 
 /*!  \internal */
@@ -2269,15 +2415,21 @@ void QQuickText::mousePressEvent(QMouseEvent *event)
 {
     Q_D(QQuickText);
 
+    QString link;
     if (d->isLinkActivatedConnected()) {
         if (d->styledText)
-            d->activeLink = d->anchorAt(event->localPos());
-        else if (d->richText && d->doc)
-            d->activeLink = d->doc->documentLayout()->anchorAt(event->localPos());
+            link = d->anchorAt(event->localPos());
+        else if (d->richText) {
+            d->ensureDoc();
+            link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
+        }
     }
 
-    if (d->activeLink.isEmpty())
+    if (link.isEmpty()) {
         event->setAccepted(false);
+    } else {
+        d->extra.value().activeLink = link;
+    }
 
     // ### may malfunction if two of the same links are clicked & dragged onto each other)
 
@@ -2297,12 +2449,14 @@ void QQuickText::mouseReleaseEvent(QMouseEvent *event)
     if (d->isLinkActivatedConnected()) {
         if (d->styledText)
             link = d->anchorAt(event->localPos());
-        else if (d->richText && d->doc)
-            link = d->doc->documentLayout()->anchorAt(event->localPos());
+        else if (d->richText) {
+            d->ensureDoc();
+            link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
+        }
     }
 
-    if (!link.isEmpty() && d->activeLink == link)
-        emit linkActivated(d->activeLink);
+    if (!link.isEmpty() && d->extra.isAllocated() && d->extra->activeLink == link)
+        emit linkActivated(d->extra->activeLink);
     else
         event->setAccepted(false);