src/declarative/graphicsitems/qdeclarativetext.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
equal deleted inserted replaced
30:5dc02b23752f 33:3e2da88830cd
    55 #include <QAbstractTextDocumentLayout>
    55 #include <QAbstractTextDocumentLayout>
    56 #include <qmath.h>
    56 #include <qmath.h>
    57 
    57 
    58 QT_BEGIN_NAMESPACE
    58 QT_BEGIN_NAMESPACE
    59 
    59 
       
    60 extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
       
    61 
    60 class QTextDocumentWithImageResources : public QTextDocument {
    62 class QTextDocumentWithImageResources : public QTextDocument {
    61     Q_OBJECT
    63     Q_OBJECT
    62 
    64 
    63 public:
    65 public:
    64     QTextDocumentWithImageResources(QDeclarativeText *parent) :
    66     QTextDocumentWithImageResources(QDeclarativeText *parent);
    65         QTextDocument(parent),
    67     virtual ~QTextDocumentWithImageResources();
    66         outstanding(0)
    68 
    67     {
    69     void setText(const QString &);
    68     }
       
    69 
       
    70     int resourcesLoading() const { return outstanding; }
    70     int resourcesLoading() const { return outstanding; }
    71 
    71 
    72 protected:
    72 protected:
    73     QVariant loadResource(int type, const QUrl &name)
    73     QVariant loadResource(int type, const QUrl &name);
    74     {
       
    75         QUrl url = qmlContext(parent())->resolvedUrl(name);
       
    76 
       
    77         if (type == QTextDocument::ImageResource) {
       
    78             QPixmap pm;
       
    79             QString errorString;
       
    80             QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(url, &pm, &errorString, 0, false, 0, 0);
       
    81             if (status == QDeclarativePixmapReply::Ready)
       
    82                 return pm;
       
    83             if (status == QDeclarativePixmapReply::Error) {
       
    84                 if (!errors.contains(url)) {
       
    85                     errors.insert(url);
       
    86                     qmlInfo(parent()) << errorString;
       
    87                 }
       
    88             } else {
       
    89                 QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(parent()), url);
       
    90                 connect(reply, SIGNAL(finished()), this, SLOT(requestFinished()));
       
    91                 outstanding++;
       
    92             }
       
    93         }
       
    94 
       
    95         return QTextDocument::loadResource(type,url); // The *resolved* URL
       
    96     }
       
    97 
    74 
    98 private slots:
    75 private slots:
    99     void requestFinished()
    76     void requestFinished();
   100     {
       
   101         outstanding--;
       
   102         if (outstanding == 0)
       
   103             static_cast<QDeclarativeText*>(parent())->reloadWithResources();
       
   104     }
       
   105 
    77 
   106 private:
    78 private:
       
    79     QHash<QUrl, QDeclarativePixmap *> m_resources;
       
    80 
   107     int outstanding;
    81     int outstanding;
   108     static QSet<QUrl> errors;
    82     static QSet<QUrl> errors;
   109 };
    83 };
       
    84 
       
    85 QTextDocumentWithImageResources::QTextDocumentWithImageResources(QDeclarativeText *parent) 
       
    86 : QTextDocument(parent), outstanding(0)
       
    87 {
       
    88 }
       
    89 
       
    90 QTextDocumentWithImageResources::~QTextDocumentWithImageResources()
       
    91 {
       
    92     if (!m_resources.isEmpty()) 
       
    93         qDeleteAll(m_resources);
       
    94 }
       
    95 
       
    96 QVariant QTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
       
    97 {
       
    98     QDeclarativeContext *context = qmlContext(parent());
       
    99     QUrl url = context->resolvedUrl(name);
       
   100 
       
   101     if (type == QTextDocument::ImageResource) {
       
   102         QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url);
       
   103 
       
   104         if (iter == m_resources.end()) {
       
   105             QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url);
       
   106             iter = m_resources.insert(name, p);
       
   107 
       
   108             if (p->isLoading()) {
       
   109                 p->connectFinished(this, SLOT(requestFinished()));
       
   110                 outstanding++;
       
   111             }
       
   112         }
       
   113 
       
   114         QDeclarativePixmap *p = *iter;
       
   115         if (p->isReady()) {
       
   116             return p->pixmap();
       
   117         } else if (p->isError()) {
       
   118             if (!errors.contains(url)) {
       
   119                 errors.insert(url);
       
   120                 qmlInfo(parent()) << p->error();
       
   121             }
       
   122         }
       
   123     }
       
   124 
       
   125     return QTextDocument::loadResource(type,url); // The *resolved* URL
       
   126 }
       
   127 
       
   128 void QTextDocumentWithImageResources::requestFinished()
       
   129 {
       
   130     outstanding--;
       
   131     if (outstanding == 0) {
       
   132         QDeclarativeText *textItem = static_cast<QDeclarativeText*>(parent());
       
   133         QString text = textItem->text();
       
   134 #ifndef QT_NO_TEXTHTMLPARSER
       
   135         setHtml(text);
       
   136 #else
       
   137         setPlainText(text);
       
   138 #endif
       
   139         QDeclarativeTextPrivate *d = QDeclarativeTextPrivate::get(textItem);
       
   140         d->updateLayout();
       
   141         d->markImgDirty();
       
   142     }
       
   143 }
       
   144 
       
   145 void QTextDocumentWithImageResources::setText(const QString &text)
       
   146 {
       
   147     if (!m_resources.isEmpty()) {
       
   148         qWarning("CLEAR");
       
   149         qDeleteAll(m_resources);
       
   150         m_resources.clear();
       
   151         outstanding = 0;
       
   152     }
       
   153 
       
   154 #ifndef QT_NO_TEXTHTMLPARSER
       
   155     setHtml(text);
       
   156 #else
       
   157     setPlainText(text);
       
   158 #endif
       
   159 }
   110 
   160 
   111 QSet<QUrl> QTextDocumentWithImageResources::errors;
   161 QSet<QUrl> QTextDocumentWithImageResources::errors;
   112 
   162 
   113 /*!
   163 /*!
   114     \qmlclass Text QDeclarativeText
   164     \qmlclass Text QDeclarativeText
   124     \endqml
   174     \endqml
   125 
   175 
   126     \image declarative-text.png
   176     \image declarative-text.png
   127 
   177 
   128     If height and width are not explicitly set, Text will attempt to determine how
   178     If height and width are not explicitly set, Text will attempt to determine how
   129     much room is needed and set it accordingly. Unless \c wrapMode is set, it will always
   179     much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
   130     prefer width to height (all text will be placed on a single line).
   180     prefer width to height (all text will be placed on a single line).
   131 
   181 
   132     The \c elide property can alternatively be used to fit a single line of
   182     The \l elide property can alternatively be used to fit a single line of
   133     plain text to a set width.
   183     plain text to a set width.
   134 
   184 
   135     Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
   185     Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
   136     HTML img tags that load remote images, the text is reloaded.
   186     HTML img tags that load remote images, the text is reloaded.
   137 
   187 
   138     Text provides read-only text. For editable text, see \l TextEdit.
   188     Text provides read-only text. For editable text, see \l TextEdit.
       
   189 
       
   190     \sa {declarative/text/fonts}{Fonts example}
   139 */
   191 */
   140 
   192 
   141 /*!
   193 /*!
   142     \internal
   194     \internal
   143     \class QDeclarativeText
   195     \class QDeclarativeText
   159     much room is needed and set it accordingly. Unless \c wrapMode is set, it will always
   211     much room is needed and set it accordingly. Unless \c wrapMode is set, it will always
   160     prefer width to height (all text will be placed on a single line).
   212     prefer width to height (all text will be placed on a single line).
   161 
   213 
   162     The \c elide property can alternatively be used to fit a line of plain text to a set width.
   214     The \c elide property can alternatively be used to fit a line of plain text to a set width.
   163 
   215 
   164     A QDeclarativeText object can be instantiated in Qml using the tag \c Text.
   216     A QDeclarativeText object can be instantiated in QML using the tag \c Text.
   165 */
   217 */
   166 QDeclarativeText::QDeclarativeText(QDeclarativeItem *parent)
   218 QDeclarativeText::QDeclarativeText(QDeclarativeItem *parent)
   167   : QDeclarativeItem(*(new QDeclarativeTextPrivate), parent)
   219   : QDeclarativeItem(*(new QDeclarativeTextPrivate), parent)
   168 {
   220 {
   169 }
   221 }
   223 
   275 
   224     Sets whether the text is underlined.
   276     Sets whether the text is underlined.
   225 */
   277 */
   226 
   278 
   227 /*!
   279 /*!
   228     \qmlproperty bool Text::font.outline
       
   229 
       
   230     Sets whether the font has an outline style.
       
   231 */
       
   232 
       
   233 /*!
       
   234     \qmlproperty bool Text::font.strikeout
   280     \qmlproperty bool Text::font.strikeout
   235 
   281 
   236     Sets whether the font has a strikeout style.
   282     Sets whether the font has a strikeout style.
   237 */
   283 */
   238 
   284 
   255     \qmlproperty real Text::font.letterSpacing
   301     \qmlproperty real Text::font.letterSpacing
   256 
   302 
   257     Sets the letter spacing for the font.
   303     Sets the letter spacing for the font.
   258 
   304 
   259     Letter spacing changes the default spacing between individual letters in the font.
   305     Letter spacing changes the default spacing between individual letters in the font.
   260     A value of 100 will keep the spacing unchanged; a value of 200 will enlarge the spacing after a character by
   306     A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
   261     the width of the character itself.
       
   262 */
   307 */
   263 
   308 
   264 /*!
   309 /*!
   265     \qmlproperty real Text::font.wordSpacing
   310     \qmlproperty real Text::font.wordSpacing
   266 
   311 
   316 
   361 
   317     d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n));
   362     d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n));
   318     if (d->richText) {
   363     if (d->richText) {
   319         if (isComponentComplete()) {
   364         if (isComponentComplete()) {
   320             d->ensureDoc();
   365             d->ensureDoc();
   321             d->doc->setHtml(n);
   366             d->doc->setText(n);
   322         }
   367         }
   323     }
   368     }
   324 
   369 
   325     d->text = n;
   370     d->text = n;
   326     d->updateLayout();
   371     d->updateLayout();
   435     used at all.
   480     used at all.
   436 
   481 
   437     \qml
   482     \qml
   438     Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
   483     Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
   439     \endqml
   484     \endqml
       
   485 
       
   486     \sa style
   440  */
   487  */
   441 QColor QDeclarativeText::styleColor() const
   488 QColor QDeclarativeText::styleColor() const
   442 {
   489 {
   443     Q_D(const QDeclarativeText);
   490     Q_D(const QDeclarativeText);
   444     return d->styleColor;
   491     return d->styleColor;
   471     Q_D(QDeclarativeText);
   518     Q_D(QDeclarativeText);
   472     if (d->hAlign == align)
   519     if (d->hAlign == align)
   473         return;
   520         return;
   474 
   521 
   475     d->hAlign = align;
   522     d->hAlign = align;
       
   523     update();
   476     emit horizontalAlignmentChanged(align);
   524     emit horizontalAlignmentChanged(align);
   477 }
   525 }
   478 
   526 
   479 QDeclarativeText::VAlignment QDeclarativeText::vAlign() const
   527 QDeclarativeText::VAlignment QDeclarativeText::vAlign() const
   480 {
   528 {
   487     Q_D(QDeclarativeText);
   535     Q_D(QDeclarativeText);
   488     if (d->vAlign == align)
   536     if (d->vAlign == align)
   489         return;
   537         return;
   490 
   538 
   491     d->vAlign = align;
   539     d->vAlign = align;
       
   540     update();
   492     emit verticalAlignmentChanged(align);
   541     emit verticalAlignmentChanged(align);
   493 }
   542 }
   494 
   543 
   495 /*!
   544 /*!
   496     \qmlproperty enumeration Text::wrapMode
   545     \qmlproperty enumeration Text::wrapMode
   497 
   546 
   498     Set this property to wrap the text to the Text item's width.  The text will only
   547     Set this property to wrap the text to the Text item's width.  The text will only
   499     wrap if an explicit width has been set.  wrapMode can be one of:
   548     wrap if an explicit width has been set.  wrapMode can be one of:
   500 
   549 
   501     \list
   550     \list
   502     \o Text.NoWrap - no wrapping will be performed.
   551     \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
   503     \o Text.WordWrap - wrapping is done on word boundaries. If the text cannot be
   552     \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
   504     word-wrapped to the specified width it will be partially drawn outside of the item's bounds.
   553     \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
   505     If this is undesirable then enable clipping on the item (Item::clip).
   554     \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.
   506     \o Text.WrapAnywhere - Text can be wrapped at any point on a line, even if it occurs in the middle of a word.
       
   507     \o Text.WrapAtWordBoundaryOrAnywhere - If possible, wrapping occurs at a word boundary; otherwise it
       
   508        will occur at the appropriate point on the line, even in the middle of a word.
       
   509     \endlist
   555     \endlist
   510 
       
   511     The default is Text.NoWrap.
       
   512 */
   556 */
   513 QDeclarativeText::WrapMode QDeclarativeText::wrapMode() const
   557 QDeclarativeText::WrapMode QDeclarativeText::wrapMode() const
   514 {
   558 {
   515     Q_D(const QDeclarativeText);
   559     Q_D(const QDeclarativeText);
   516     return d->wrapMode;
   560     return d->wrapMode;
   536     The way the text property should be displayed.
   580     The way the text property should be displayed.
   537 
   581 
   538     Supported text formats are:
   582     Supported text formats are:
   539     
   583     
   540     \list
   584     \list
   541     \o Text.AutoText
   585     \o Text.AutoText (default)
   542     \o Text.PlainText
   586     \o Text.PlainText
   543     \o Text.RichText
   587     \o Text.RichText
   544     \o Text.StyledText
   588     \o Text.StyledText
   545     \endlist
   589     \endlist
   546 
   590 
   547     The default is Text.AutoText.  If the text format is Text.AutoText the text element
   591     If the text format is \c Text.AutoText the text element
   548     will automatically determine whether the text should be treated as
   592     will automatically determine whether the text should be treated as
   549     rich text.  This determination is made using Qt::mightBeRichText().
   593     rich text.  This determination is made using Qt::mightBeRichText().
   550 
   594 
   551     Text.StyledText is an optimized format supporting some basic text
   595     Text.StyledText is an optimized format supporting some basic text
   552     styling markup, in the style of html 3.2:
   596     styling markup, in the style of html 3.2:
   606         d->updateLayout();
   650         d->updateLayout();
   607         d->markImgDirty();
   651         d->markImgDirty();
   608     } else if (!wasRich && d->richText) {
   652     } else if (!wasRich && d->richText) {
   609         if (isComponentComplete()) {
   653         if (isComponentComplete()) {
   610             d->ensureDoc();
   654             d->ensureDoc();
   611             d->doc->setHtml(d->text);
   655             d->doc->setText(d->text);
   612         }
   656         }
   613         d->updateLayout();
   657         d->updateLayout();
   614         d->markImgDirty();
   658         d->markImgDirty();
   615     }
   659     }
   616 
   660 
   656     d->updateLayout();
   700     d->updateLayout();
   657     d->markImgDirty();
   701     d->markImgDirty();
   658     emit elideModeChanged(d->elideMode);
   702     emit elideModeChanged(d->elideMode);
   659 }
   703 }
   660 
   704 
       
   705 QRectF QDeclarativeText::boundingRect() const
       
   706 {
       
   707     Q_D(const QDeclarativeText);
       
   708 
       
   709     int w = width();
       
   710     int h = height();
       
   711 
       
   712     int x = 0;
       
   713     int y = 0;
       
   714 
       
   715     QSize size = d->cachedLayoutSize;
       
   716     if (d->style != Normal)
       
   717         size += QSize(2,2);
       
   718 
       
   719     // Could include font max left/right bearings to either side of rectangle.
       
   720 
       
   721     switch (d->hAlign) {
       
   722     case AlignLeft:
       
   723         x = 0;
       
   724         break;
       
   725     case AlignRight:
       
   726         x = w - size.width();
       
   727         break;
       
   728     case AlignHCenter:
       
   729         x = (w - size.width()) / 2;
       
   730         break;
       
   731     }
       
   732 
       
   733     switch (d->vAlign) {
       
   734     case AlignTop:
       
   735         y = 0;
       
   736         break;
       
   737     case AlignBottom:
       
   738         y = h - size.height();
       
   739         break;
       
   740     case AlignVCenter:
       
   741         y = (h - size.height()) / 2;
       
   742         break;
       
   743     }
       
   744 
       
   745     return QRectF(x,y,size.width(),size.height());
       
   746 }
       
   747 
   661 void QDeclarativeText::geometryChanged(const QRectF &newGeometry,
   748 void QDeclarativeText::geometryChanged(const QRectF &newGeometry,
   662                               const QRectF &oldGeometry)
   749                               const QRectF &oldGeometry)
   663 {
   750 {
   664     Q_D(QDeclarativeText);
   751     Q_D(QDeclarativeText);
   665     if (newGeometry.width() != oldGeometry.width()) {
   752     if (!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width()) {
   666         if (d->wrapMode != QDeclarativeText::NoWrap || d->elideMode != QDeclarativeText::ElideNone) {
   753         if (d->wrapMode != QDeclarativeText::NoWrap || d->elideMode != QDeclarativeText::ElideNone) {
   667             //re-elide if needed
   754             //re-elide if needed
   668             if (d->singleline && d->elideMode != QDeclarativeText::ElideNone &&
   755             if (d->singleline && d->elideMode != QDeclarativeText::ElideNone &&
   669                 isComponentComplete() && widthValid()) {
   756                 isComponentComplete() && widthValid()) {
   670 
   757 
   706     } else {
   793     } else {
   707         dirty = true;
   794         dirty = true;
   708     }
   795     }
   709 }
   796 }
   710 
   797 
       
   798 
   711 void QDeclarativeTextPrivate::updateSize()
   799 void QDeclarativeTextPrivate::updateSize()
   712 {
   800 {
   713     Q_Q(QDeclarativeText);
   801     Q_Q(QDeclarativeText);
   714     if (q->isComponentComplete()) {
   802     if (q->isComponentComplete()) {
   715         QFontMetrics fm(font);
   803         QFontMetrics fm(font);
   716         if (text.isEmpty()) {
   804         if (text.isEmpty()) {
   717             q->setImplicitHeight(fm.height());
   805             q->setImplicitHeight(fm.height());
       
   806             emit q->paintedSizeChanged();
   718             return;
   807             return;
   719         }
   808         }
   720 
   809 
   721         int dy = q->height();
   810         int dy = q->height();
   722         QSize size(0, 0);
   811         QSize size(0, 0);
   723 
   812 
   724         //setup instance of QTextLayout for all cases other than richtext
   813         //setup instance of QTextLayout for all cases other than richtext
   725         if (!richText) {
   814         if (!richText) {
   726             size = setupTextLayout(&layout);
   815             size = setupTextLayout(&layout);
   727             cachedLayoutSize = size;
   816             if (cachedLayoutSize != size) {
       
   817                 q->prepareGeometryChange();
       
   818                 cachedLayoutSize = size;
       
   819             }
   728             dy -= size.height();
   820             dy -= size.height();
   729         } else {
   821         } else {
   730             singleline = false; // richtext can't elide or be optimized for single-line case
   822             singleline = false; // richtext can't elide or be optimized for single-line case
   731             ensureDoc();
   823             ensureDoc();
   732             doc->setDefaultFont(font);
   824             doc->setDefaultFont(font);
   736             if (wrapMode != QDeclarativeText::NoWrap && q->widthValid())
   828             if (wrapMode != QDeclarativeText::NoWrap && q->widthValid())
   737                 doc->setTextWidth(q->width());
   829                 doc->setTextWidth(q->width());
   738             else
   830             else
   739                 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
   831                 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
   740             dy -= (int)doc->size().height();
   832             dy -= (int)doc->size().height();
   741             cachedLayoutSize = doc->size().toSize();
   833                 q->prepareGeometryChange();
       
   834             QSize dsize = doc->size().toSize();
       
   835             if (dsize != cachedLayoutSize) {
       
   836                 q->prepareGeometryChange();
       
   837                 cachedLayoutSize = dsize;
       
   838             }
       
   839             size = QSize(int(doc->idealWidth()),dsize.height());
   742         }
   840         }
   743         int yoff = 0;
   841         int yoff = 0;
   744 
   842 
   745         if (q->heightValid()) {
   843         if (q->heightValid()) {
   746             if (vAlign == QDeclarativeText::AlignBottom)
   844             if (vAlign == QDeclarativeText::AlignBottom)
   749                 yoff = dy/2;
   847                 yoff = dy/2;
   750         }
   848         }
   751         q->setBaselineOffset(fm.ascent() + yoff);
   849         q->setBaselineOffset(fm.ascent() + yoff);
   752 
   850 
   753         //### need to comfirm cost of always setting these for richText
   851         //### need to comfirm cost of always setting these for richText
   754         q->setImplicitWidth(richText ? (int)doc->idealWidth() : size.width());
   852         internalWidthUpdate = true;
   755         q->setImplicitHeight(richText ? (int)doc->size().height() : size.height());
   853         q->setImplicitWidth(size.width());
       
   854         internalWidthUpdate = false;
       
   855         q->setImplicitHeight(size.height());
       
   856         emit q->paintedSizeChanged();
   756     } else {
   857     } else {
   757         dirty = true;
   858         dirty = true;
   758     }
   859     }
   759 }
   860 }
       
   861 
       
   862 /*!
       
   863     \qmlproperty real Text::paintedWidth
       
   864 
       
   865     Returns the width of the text, including width past the width
       
   866     which is covered due to insufficient wrapping if WrapMode is set.
       
   867 */
       
   868 qreal QDeclarativeText::paintedWidth() const
       
   869 {
       
   870     return implicitWidth();
       
   871 }
       
   872 
       
   873 /*!
       
   874     \qmlproperty real Text::paintedHeight
       
   875 
       
   876     Returns the height of the text, including height past the height
       
   877     which is covered due to there being more text than fits in the set height.
       
   878 */
       
   879 qreal QDeclarativeText::paintedHeight() const
       
   880 {
       
   881     return implicitHeight();
       
   882 }
       
   883 
       
   884 
   760 
   885 
   761 // ### text layout handling should be profiled and optimized as needed
   886 // ### text layout handling should be profiled and optimized as needed
   762 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
   887 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
   763 
   888 
   764 void QDeclarativeTextPrivate::drawOutline()
   889 void QDeclarativeTextPrivate::drawOutline()
   780 
   905 
   781     pos += QPoint(0, -1);
   906     pos += QPoint(0, -1);
   782     ppm.drawPixmap(pos, imgCache);
   907     ppm.drawPixmap(pos, imgCache);
   783     ppm.end();
   908     ppm.end();
   784 
   909 
       
   910     if (imgCache.size() != img.size())
       
   911         q_func()->prepareGeometryChange();
   785     imgCache = img;
   912     imgCache = img;
   786 }
   913 }
   787 
   914 
   788 void QDeclarativeTextPrivate::drawOutline(int yOffset)
   915 void QDeclarativeTextPrivate::drawOutline(int yOffset)
   789 {
   916 {
   798 
   925 
   799     pos += QPoint(0, -yOffset);
   926     pos += QPoint(0, -yOffset);
   800     ppm.drawPixmap(pos, imgCache);
   927     ppm.drawPixmap(pos, imgCache);
   801     ppm.end();
   928     ppm.end();
   802 
   929 
       
   930     if (imgCache.size() != img.size())
       
   931         q_func()->prepareGeometryChange();
   803     imgCache = img;
   932     imgCache = img;
   804 }
   933 }
   805 
   934 
   806 QSize QDeclarativeTextPrivate::setupTextLayout(QTextLayout *layout)
   935 QSize QDeclarativeTextPrivate::setupTextLayout(QTextLayout *layout)
   807 {
   936 {
   874 
  1003 
   875     //paint text
  1004     //paint text
   876     QPixmap img(size);
  1005     QPixmap img(size);
   877     if (!size.isEmpty()) {
  1006     if (!size.isEmpty()) {
   878         img.fill(Qt::transparent);
  1007         img.fill(Qt::transparent);
       
  1008 #ifdef Q_WS_MAC
       
  1009         bool oldSmooth = qt_applefontsmoothing_enabled;
       
  1010         qt_applefontsmoothing_enabled = false;
       
  1011 #endif
   879         QPainter p(&img);
  1012         QPainter p(&img);
       
  1013 #ifdef Q_WS_MAC
       
  1014         qt_applefontsmoothing_enabled = oldSmooth;
       
  1015 #endif
   880         drawWrappedText(&p, QPointF(0,0), drawStyle);
  1016         drawWrappedText(&p, QPointF(0,0), drawStyle);
   881     }
  1017     }
   882     return img;
  1018     return img;
   883 }
  1019 }
   884 
  1020 
   897     QSize size = doc->size().toSize();
  1033     QSize size = doc->size().toSize();
   898 
  1034 
   899     //paint text
  1035     //paint text
   900     QPixmap img(size);
  1036     QPixmap img(size);
   901     img.fill(Qt::transparent);
  1037     img.fill(Qt::transparent);
       
  1038 #ifdef Q_WS_MAC
       
  1039     bool oldSmooth = qt_applefontsmoothing_enabled;
       
  1040     qt_applefontsmoothing_enabled = false;
       
  1041 #endif
   902     QPainter p(&img);
  1042     QPainter p(&img);
       
  1043 #ifdef Q_WS_MAC
       
  1044     qt_applefontsmoothing_enabled = oldSmooth;
       
  1045 #endif
   903 
  1046 
   904     QAbstractTextDocumentLayout::PaintContext context;
  1047     QAbstractTextDocumentLayout::PaintContext context;
   905 
  1048 
   906     if (drawStyle) {
  1049     if (drawStyle) {
   907         context.palette.setColor(QPalette::Text, styleColor);
  1050         context.palette.setColor(QPalette::Text, styleColor);
   922 {
  1065 {
   923     if (!imgDirty)
  1066     if (!imgDirty)
   924         return;
  1067         return;
   925 
  1068 
   926     bool empty = text.isEmpty();
  1069     bool empty = text.isEmpty();
       
  1070     QPixmap newImgCache;
   927     if (empty) {
  1071     if (empty) {
   928         imgCache = QPixmap();
       
   929         imgStyleCache = QPixmap();
  1072         imgStyleCache = QPixmap();
   930     } else if (richText) {
  1073     } else if (richText) {
   931         imgCache = richTextImage(false);
  1074         newImgCache = richTextImage(false);
   932         if (style != QDeclarativeText::Normal)
  1075         if (style != QDeclarativeText::Normal)
   933             imgStyleCache = richTextImage(true); //### should use styleColor
  1076             imgStyleCache = richTextImage(true); //### should use styleColor
   934     } else {
  1077     } else {
   935         imgCache = wrappedTextImage(false);
  1078         newImgCache = wrappedTextImage(false);
   936         if (style != QDeclarativeText::Normal)
  1079         if (style != QDeclarativeText::Normal)
   937             imgStyleCache = wrappedTextImage(true); //### should use styleColor
  1080             imgStyleCache = wrappedTextImage(true); //### should use styleColor
   938     }
  1081     }
       
  1082     if (imgCache.size() != newImgCache.size())
       
  1083         q_func()->prepareGeometryChange();
       
  1084     imgCache = newImgCache;
   939     if (!empty)
  1085     if (!empty)
   940         switch (style) {
  1086         switch (style) {
   941         case QDeclarativeText::Outline:
  1087         case QDeclarativeText::Outline:
   942             drawOutline();
  1088             drawOutline();
   943             break;
  1089             break;
   961         doc = new QTextDocumentWithImageResources(q);
  1107         doc = new QTextDocumentWithImageResources(q);
   962         doc->setDocumentMargin(0);
  1108         doc->setDocumentMargin(0);
   963     }
  1109     }
   964 }
  1110 }
   965 
  1111 
   966 void QDeclarativeText::reloadWithResources()
       
   967 {
       
   968     Q_D(QDeclarativeText);
       
   969     if (!d->richText)
       
   970         return;
       
   971     d->doc->setHtml(d->text);
       
   972     d->updateLayout();
       
   973     d->markImgDirty();
       
   974 }
       
   975 
       
   976 /*!
  1112 /*!
   977     Returns the number of resources (images) that are being loaded asynchronously.
  1113     Returns the number of resources (images) that are being loaded asynchronously.
   978 */
  1114 */
   979 int QDeclarativeText::resourcesLoading() const
  1115 int QDeclarativeText::resourcesLoading() const
   980 {
  1116 {
   981     Q_D(const QDeclarativeText);
  1117     Q_D(const QDeclarativeText);
   982     return d->doc ? d->doc->resourcesLoading() : 0;
  1118     return d->doc ? d->doc->resourcesLoading() : 0;
   983 }
  1119 }
       
  1120 
       
  1121 /*!
       
  1122   \qmlproperty bool Text::clip
       
  1123   This property holds whether the text is clipped.
       
  1124 
       
  1125   Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
       
  1126 
       
  1127   If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
       
  1128 */
   984 
  1129 
   985 void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
  1130 void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
   986 {
  1131 {
   987     Q_D(QDeclarativeText);
  1132     Q_D(QDeclarativeText);
   988 
  1133 
   994         bool oldAA = p->testRenderHint(QPainter::Antialiasing);
  1139         bool oldAA = p->testRenderHint(QPainter::Antialiasing);
   995         bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform);
  1140         bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform);
   996         if (d->smooth)
  1141         if (d->smooth)
   997             p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
  1142             p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth);
   998 
  1143 
   999         int w = width();
  1144         QRect br = boundingRect().toRect();
  1000         int h = height();
       
  1001 
       
  1002         int x = 0;
       
  1003         int y = 0;
       
  1004 
       
  1005         switch (d->hAlign) {
       
  1006         case AlignLeft:
       
  1007             x = 0;
       
  1008             break;
       
  1009         case AlignRight:
       
  1010             x = w - d->imgCache.width();
       
  1011             break;
       
  1012         case AlignHCenter:
       
  1013             x = (w - d->imgCache.width()) / 2;
       
  1014             break;
       
  1015         }
       
  1016 
       
  1017         switch (d->vAlign) {
       
  1018         case AlignTop:
       
  1019             y = 0;
       
  1020             break;
       
  1021         case AlignBottom:
       
  1022             y = h - d->imgCache.height();
       
  1023             break;
       
  1024         case AlignVCenter:
       
  1025             y = (h - d->imgCache.height()) / 2;
       
  1026             break;
       
  1027         }
       
  1028 
  1145 
  1029         bool needClip = clip() && (d->imgCache.width() > width() ||
  1146         bool needClip = clip() && (d->imgCache.width() > width() ||
  1030                                    d->imgCache.height() > height());
  1147                                    d->imgCache.height() > height());
  1031 
  1148 
  1032         if (needClip) {
       
  1033             p->save();
       
  1034             p->setClipRect(boundingRect(), Qt::IntersectClip);
       
  1035         }
       
  1036         p->drawPixmap(x, y, d->imgCache);
       
  1037         if (needClip)
  1149         if (needClip)
  1038             p->restore();
  1150             p->drawPixmap(0, 0, width(), height(), d->imgCache, -br.x(), -br.y(), width(), height());
       
  1151         else
       
  1152             p->drawPixmap(br.x(), br.y(), d->imgCache);
  1039 
  1153 
  1040         if (d->smooth) {
  1154         if (d->smooth) {
  1041             p->setRenderHint(QPainter::Antialiasing, oldAA);
  1155             p->setRenderHint(QPainter::Antialiasing, oldAA);
  1042             p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
  1156             p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth);
  1043         }
  1157         }
  1044     } else {
  1158     } else {
  1045         int h = height();
  1159         qreal y = boundingRect().y();
  1046         int y = 0;
  1160 
  1047 
       
  1048         switch (d->vAlign) {
       
  1049         case AlignTop:
       
  1050             y = 0;
       
  1051             break;
       
  1052         case AlignBottom:
       
  1053             y = h - d->cachedLayoutSize.height();
       
  1054             break;
       
  1055         case AlignVCenter:
       
  1056             y = (h - d->cachedLayoutSize.height()) / 2;
       
  1057             break;
       
  1058         }
       
  1059         bool needClip = !clip() && (d->cachedLayoutSize.width() > width() ||
  1161         bool needClip = !clip() && (d->cachedLayoutSize.width() > width() ||
  1060                                     d->cachedLayoutSize.height() > height());
  1162                                     d->cachedLayoutSize.height() > height());
  1061 
  1163 
  1062         if (needClip) {
  1164         if (needClip) {
  1063             p->save();
  1165             p->save();
  1064             p->setClipRect(boundingRect(), Qt::IntersectClip);
  1166             p->setClipRect(0, 0, width(), height(), Qt::IntersectClip);
  1065         }
  1167         }
  1066         if (d->richText) {
  1168         if (d->richText) {
  1067             QAbstractTextDocumentLayout::PaintContext context;
  1169             QAbstractTextDocumentLayout::PaintContext context;
  1068             context.palette.setColor(QPalette::Text, d->color);
  1170             context.palette.setColor(QPalette::Text, d->color);
  1069             p->translate(0, y);
  1171             p->translate(0, y);
  1096     Q_D(QDeclarativeText);
  1198     Q_D(QDeclarativeText);
  1097     QDeclarativeItem::componentComplete();
  1199     QDeclarativeItem::componentComplete();
  1098     if (d->dirty) {
  1200     if (d->dirty) {
  1099         if (d->richText) {
  1201         if (d->richText) {
  1100             d->ensureDoc();
  1202             d->ensureDoc();
  1101             d->doc->setHtml(d->text);
  1203             d->doc->setText(d->text);
  1102         }
  1204         }
  1103         d->updateLayout();
  1205         d->updateLayout();
  1104         d->dirty = false;
  1206         d->dirty = false;
  1105     }
  1207     }
  1106 }
  1208 }
  1126         QDeclarativeItem::mousePressEvent(event);
  1228         QDeclarativeItem::mousePressEvent(event);
  1127 
  1229 
  1128 }
  1230 }
  1129 
  1231 
  1130 /*!
  1232 /*!
  1131     \qmlsignal Text::linkActivated(link)
  1233     \qmlsignal Text::onLinkActivated(link)
  1132 
  1234 
  1133     This handler is called when the user clicks on a link embedded in the text.
  1235     This handler is called when the user clicks on a link embedded in the text.
  1134 */
  1236 */
  1135 
  1237 
  1136 /*!
  1238 /*!