src/gui/text/qstatictext.cpp
branchGCC_SURGE
changeset 31 5daf16870df6
parent 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
27:93b982ccede2 31:5daf16870df6
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qstatictext.h"
       
    43 #include "qstatictext_p.h"
       
    44 #include <private/qtextengine_p.h>
       
    45 #include <private/qfontengine_p.h>
       
    46 
       
    47 #include <QtGui/qapplication.h>
       
    48 
       
    49 QT_BEGIN_NAMESPACE
       
    50 
       
    51 /*!
       
    52     \class QStaticText
       
    53     \brief The QStaticText class enables optimized drawing of text when the text and its layout
       
    54     is updated rarely.
       
    55     \since 4.7
       
    56 
       
    57     \ingroup multimedia
       
    58     \ingroup text
       
    59     \mainclass
       
    60 
       
    61     QStaticText provides a way to cache layout data for a block of text so that it can be drawn
       
    62     more efficiently than by using QPainter::drawText() in which the layout information is 
       
    63     recalculated with every call. 
       
    64 
       
    65     The class primarily provides an optimization for cases where the text, its font and the
       
    66     transformations on the painter are static over several paint events. If the text or its layout
       
    67     is changed for every iteration, QPainter::drawText() is the more efficient alternative, since
       
    68     the static text's layout would have to be recalculated to take the new state into consideration.
       
    69 
       
    70     Translating the painter will not cause the layout of the text to be recalculated, but will cause
       
    71     a very small performance impact on drawStaticText(). Altering any other parts of the painter's
       
    72     transformation or the painter's font will cause the layout of the static text to be
       
    73     recalculated. This should be avoided as often as possible to maximize the performance
       
    74     benefit of using QStaticText.
       
    75 
       
    76     In addition, only affine transformations are supported by drawStaticText(). Calling
       
    77     drawStaticText() on a projected painter will perform slightly worse than using the regular
       
    78     drawText() call, so this should be avoided.
       
    79 
       
    80     \code
       
    81     class MyWidget: public QWidget
       
    82     {
       
    83     public:
       
    84         MyWidget(QWidget *parent = 0) : QWidget(parent), m_staticText("This is static text")
       
    85 
       
    86     protected:
       
    87         void paintEvent(QPaintEvent *)
       
    88         {
       
    89             QPainter painter(this);
       
    90             painter.drawStaticText(0, 0, m_staticText);
       
    91         }
       
    92 
       
    93     private:
       
    94         QStaticText m_staticText;
       
    95     };
       
    96     \endcode
       
    97 
       
    98     The QStaticText class can be used to mimic the behavior of QPainter::drawText() to a specific
       
    99     point with no boundaries, and also when QPainter::drawText() is called with a bounding 
       
   100     rectangle. 
       
   101 
       
   102     If a bounding rectangle is not required, create a QStaticText object without setting a preferred
       
   103     text width. The text will then occupy a single line.
       
   104 
       
   105     If you set a text width on the QStaticText object, this will bound the text. The text will
       
   106     be formatted so that no line exceeds the given width. The text width set for QStaticText will
       
   107     not automatically be used for clipping. To achieve clipping in addition to line breaks, use
       
   108     QPainter::setClipRect(). The position of the text is decided by the argument passed to
       
   109     QPainter::drawStaticText() and can change from call to call with a minimal impact on
       
   110     performance.
       
   111 
       
   112     QStaticText will attempt to guess the format of the input text using Qt::mightBeRichText().
       
   113     To force QStaticText to display its contents as either plain text or rich text, use the
       
   114     function QStaticText::setTextFormat() and pass in, respectively, Qt::PlainText and
       
   115     Qt::RichText.
       
   116 
       
   117     If it's the first time the static text is drawn, or if the static text, or the painter's font
       
   118     or matrix have been altered since the last time it was drawn, the text's layout has to be
       
   119     recalculated. This will impose an overhead on the QPainter::drawStaticText() call where the
       
   120     relayout occurs. To avoid this overhead in the paint event, you can call prepare() ahead of
       
   121     time to ensure that the layout is calculated.
       
   122 
       
   123     \sa QPainter::drawText(), QPainter::drawStaticText(), QTextLayout, QTextDocument
       
   124 */
       
   125 
       
   126 /*!
       
   127     \enum QStaticText::PerformanceHint
       
   128 
       
   129     This enum the different performance hints that can be set on the QStaticText. These hints
       
   130     can be used to indicate that the QStaticText should use additional caches, if possible,
       
   131     to improve performance at the expense of memory. In particular, setting the performance hint
       
   132     AggressiveCaching on the QStaticText will improve performance when using the OpenGL graphics
       
   133     system or when drawing to a QGLWidget.
       
   134 
       
   135     \value ModerateCaching Do basic caching for high performance at a low memory cost.
       
   136     \value AggressiveCaching Use additional caching when available. This may improve performance
       
   137            at a higher memory cost.
       
   138 */
       
   139 
       
   140 /*!
       
   141     Constructs an empty QStaticText
       
   142 */
       
   143 QStaticText::QStaticText()    
       
   144     : data(new QStaticTextPrivate)
       
   145 {
       
   146 }
       
   147 
       
   148 /*!
       
   149     Constructs a QStaticText object with the given \a text and bounded by the given \a size.
       
   150 
       
   151     If an invalid size is passed for \a size the text will be unbounded.
       
   152 */
       
   153 QStaticText::QStaticText(const QString &text)
       
   154     : data(new QStaticTextPrivate)
       
   155 {    
       
   156     data->text = text;
       
   157     data->invalidate();
       
   158 }
       
   159 
       
   160 /*!
       
   161     Constructs a QStaticText object which is a copy of \a other.
       
   162 */
       
   163 QStaticText::QStaticText(const QStaticText &other)    
       
   164 {
       
   165     data = other.data;
       
   166 }
       
   167 
       
   168 /*!
       
   169     Destroys the QStaticText.
       
   170 */
       
   171 QStaticText::~QStaticText()
       
   172 {
       
   173     Q_ASSERT(!data || data->ref >= 1);
       
   174 }
       
   175 
       
   176 /*!
       
   177     \internal
       
   178 */
       
   179 void QStaticText::detach()
       
   180 {    
       
   181     if (data->ref != 1)
       
   182         data.detach();
       
   183 }
       
   184 
       
   185 /*!
       
   186   Prepares the QStaticText object for being painted with the given \a matrix and the given \a font
       
   187   to avoid overhead when the actual drawStaticText() call is made.
       
   188 
       
   189   When drawStaticText() is called, the layout of the QStaticText will be recalculated if any part
       
   190   of the QStaticText object has changed since the last time it was drawn. It will also be
       
   191   recalculated if the painter's font or matrix are not the same as when the QStaticText was last
       
   192   drawn.
       
   193 
       
   194   To avoid the overhead of creating the layout the first time you draw the QStaticText after
       
   195   making changes, you can use the prepare() function and pass in the \a matrix and \a font you
       
   196   expect to use when drawing the text.
       
   197 
       
   198   \sa QPainter::setFont(), QPainter::setMatrix()
       
   199 */
       
   200 void QStaticText::prepare(const QTransform &matrix, const QFont &font)
       
   201 {
       
   202     data->matrix = matrix;
       
   203     data->font = font;
       
   204     data->init();
       
   205 }
       
   206 
       
   207 
       
   208 /*!
       
   209     Assigns \a other to this QStaticText.
       
   210 */
       
   211 QStaticText &QStaticText::operator=(const QStaticText &other)
       
   212 {    
       
   213     data = other.data;
       
   214     return *this;
       
   215 }
       
   216 
       
   217 /*!
       
   218     Compares \a other to this QStaticText. Returns true if the texts, fonts and text widths
       
   219     are equal.
       
   220 */
       
   221 bool QStaticText::operator==(const QStaticText &other) const
       
   222 {
       
   223     return (data == other.data
       
   224             || (data->text == other.data->text
       
   225                 && data->font == other.data->font
       
   226                 && data->textWidth == other.data->textWidth));
       
   227 }
       
   228 
       
   229 /*!
       
   230     Compares \a other to this QStaticText. Returns true if the texts, fonts or maximum sizes
       
   231     are different.
       
   232 */
       
   233 bool QStaticText::operator!=(const QStaticText &other) const
       
   234 {
       
   235     return !(*this == other);
       
   236 }
       
   237 
       
   238 /*!
       
   239     Sets the text of the QStaticText to \a text.
       
   240 
       
   241     \note This function will cause the layout of the text to require recalculation.
       
   242 
       
   243     \sa text()
       
   244 */
       
   245 void QStaticText::setText(const QString &text)
       
   246 {
       
   247     detach();
       
   248     data->text = text;
       
   249     data->invalidate();
       
   250 }
       
   251 
       
   252 /*!
       
   253    Sets the text format of the QStaticText to \a textFormat. If \a textFormat is set to
       
   254    Qt::AutoText (the default), the format of the text will try to be determined using the
       
   255    function Qt::mightBeRichText(). If the text format is Qt::PlainText, then the text will be
       
   256    displayed as is, whereas it will be interpreted as HTML if the format is Qt::RichText. HTML tags
       
   257    that alter the font of the text, its color, or its layout are supported by QStaticText.
       
   258 
       
   259    \note This function will cause the layout of the text to require recalculation.
       
   260 
       
   261    \sa textFormat(), setText(), text()
       
   262 */
       
   263 void QStaticText::setTextFormat(Qt::TextFormat textFormat)
       
   264 {
       
   265     detach();
       
   266     data->textFormat = textFormat;
       
   267     data->invalidate();
       
   268 }
       
   269 
       
   270 /*!
       
   271   Returns the text format of the QStaticText.
       
   272 
       
   273   \sa setTextFormat(), setText(), text()
       
   274 */
       
   275 Qt::TextFormat QStaticText::textFormat() const
       
   276 {
       
   277     return Qt::TextFormat(data->textFormat);
       
   278 }
       
   279 
       
   280 /*!
       
   281     Returns the text of the QStaticText.
       
   282 
       
   283     \sa setText()
       
   284 */
       
   285 QString QStaticText::text() const 
       
   286 {
       
   287     return data->text;
       
   288 }
       
   289 
       
   290 /*!
       
   291   Sets the performance hint of the QStaticText according to the \a
       
   292   performanceHint provided. The \a performanceHint is used to
       
   293   customize how much caching is done internally to improve
       
   294   performance.
       
   295 
       
   296   The default is QStaticText::ModerateCaching.
       
   297 
       
   298   \note This function will cause the layout of the text to require recalculation.
       
   299 
       
   300   \sa performanceHint()
       
   301 */
       
   302 void QStaticText::setPerformanceHint(PerformanceHint performanceHint)
       
   303 {
       
   304     if ((performanceHint == ModerateCaching && !data->useBackendOptimizations)
       
   305         || (performanceHint == AggressiveCaching && data->useBackendOptimizations)) {
       
   306         return;
       
   307     }
       
   308     detach();
       
   309     data->useBackendOptimizations = (performanceHint == AggressiveCaching);
       
   310     data->invalidate();
       
   311 }
       
   312 
       
   313 /*!
       
   314   Returns which performance hint is set for the QStaticText.
       
   315 
       
   316   \sa setPerformanceHint()
       
   317 */
       
   318 QStaticText::PerformanceHint QStaticText::performanceHint() const
       
   319 {
       
   320     return data->useBackendOptimizations ? AggressiveCaching : ModerateCaching;
       
   321 }
       
   322 
       
   323 /*!
       
   324     Sets the preferred width for this QStaticText. If the text is wider than the specified width,
       
   325     it will be broken into multiple lines and grow vertically. If the text cannot be split into
       
   326     multiple lines, it will be larger than the specified \a textWidth.
       
   327 
       
   328     Setting the preferred text width to a negative number will cause the text to be unbounded.
       
   329 
       
   330     Use size() to get the actual size of the text.
       
   331 
       
   332     \note This function will cause the layout of the text to require recalculation.
       
   333 
       
   334     \sa textWidth(), size()
       
   335 */
       
   336 void QStaticText::setTextWidth(qreal textWidth)
       
   337 {
       
   338     detach();
       
   339     data->textWidth = textWidth;
       
   340     data->invalidate();
       
   341 }
       
   342 
       
   343 /*!
       
   344     Returns the preferred width for this QStaticText.
       
   345 
       
   346     \sa setTextWidth()
       
   347 */
       
   348 qreal QStaticText::textWidth() const
       
   349 {
       
   350     return data->textWidth;
       
   351 }
       
   352 
       
   353 /*!
       
   354   Returns the size of the bounding rect for this QStaticText.
       
   355 
       
   356   \sa textWidth()
       
   357 */
       
   358 QSizeF QStaticText::size() const
       
   359 {
       
   360     if (data->needsRelayout)
       
   361         data->init();
       
   362     return data->actualSize;
       
   363 }
       
   364 
       
   365 QStaticTextPrivate::QStaticTextPrivate()
       
   366         : textWidth(-1.0), items(0), itemCount(0), glyphPool(0), positionPool(0),
       
   367           needsRelayout(true), useBackendOptimizations(false), textFormat(Qt::AutoText)
       
   368 {
       
   369 }
       
   370 
       
   371 QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other)
       
   372     : text(other.text), font(other.font), textWidth(other.textWidth), matrix(other.matrix),
       
   373       items(0), itemCount(0), glyphPool(0), positionPool(0), needsRelayout(true),
       
   374       useBackendOptimizations(other.useBackendOptimizations), textFormat(other.textFormat)
       
   375 {
       
   376 }
       
   377 
       
   378 QStaticTextPrivate::~QStaticTextPrivate()
       
   379 {
       
   380     delete[] items;    
       
   381     delete[] glyphPool;
       
   382     delete[] positionPool;
       
   383 }
       
   384 
       
   385 QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q)
       
   386 {
       
   387     return q->data.data();
       
   388 }
       
   389 
       
   390 Q_GUI_EXPORT extern int qt_defaultDpiX();
       
   391 Q_GUI_EXPORT extern int qt_defaultDpiY();
       
   392 
       
   393 namespace {
       
   394 
       
   395     class DrawTextItemRecorder: public QPaintEngine
       
   396     {
       
   397     public:
       
   398         DrawTextItemRecorder(int expectedItemCount, QStaticTextItem *items,
       
   399                              int expectedGlyphCount, QFixedPoint *positionPool, glyph_t *glyphPool)
       
   400                 : m_items(items),
       
   401                   m_itemCount(0), m_glyphCount(0),
       
   402                   m_expectedItemCount(expectedItemCount),
       
   403                   m_expectedGlyphCount(expectedGlyphCount),
       
   404                   m_glyphPool(glyphPool),
       
   405                   m_positionPool(positionPool),
       
   406                   m_dirtyPen(false)
       
   407         {
       
   408         }
       
   409 
       
   410         virtual void updateState(const QPaintEngineState &newState)
       
   411         {
       
   412             if (newState.state() & QPaintEngine::DirtyPen)
       
   413                 m_dirtyPen = true;
       
   414         }
       
   415 
       
   416         virtual void drawTextItem(const QPointF &position, const QTextItem &textItem)
       
   417         {
       
   418             const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);          
       
   419 
       
   420             m_itemCount++;
       
   421             m_glyphCount += ti.glyphs.numGlyphs;
       
   422             if (m_items == 0)
       
   423                 return;
       
   424 
       
   425             Q_ASSERT(m_itemCount <= m_expectedItemCount);
       
   426             Q_ASSERT(m_glyphCount <= m_expectedGlyphCount);
       
   427 
       
   428             QStaticTextItem *currentItem = (m_items + (m_itemCount - 1));
       
   429             currentItem->fontEngine = ti.fontEngine;
       
   430             currentItem->font = ti.font();
       
   431             currentItem->chars = ti.chars;
       
   432             currentItem->numChars = ti.num_chars;
       
   433             currentItem->numGlyphs = ti.glyphs.numGlyphs;
       
   434             currentItem->glyphs = m_glyphPool;
       
   435             currentItem->glyphPositions = m_positionPool;
       
   436             if (m_dirtyPen)
       
   437                 currentItem->color = state->pen().color();
       
   438 
       
   439             QTransform matrix = state->transform();
       
   440             matrix.translate(position.x(), position.y());
       
   441 
       
   442             QVarLengthArray<glyph_t> glyphs;
       
   443             QVarLengthArray<QFixedPoint> positions;
       
   444             ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
       
   445 
       
   446             int size = glyphs.size();
       
   447             Q_ASSERT(size == ti.glyphs.numGlyphs);
       
   448             Q_ASSERT(size == positions.size());
       
   449 
       
   450             memmove(currentItem->glyphs, glyphs.constData(), sizeof(glyph_t) * size);
       
   451             memmove(currentItem->glyphPositions, positions.constData(), sizeof(QFixedPoint) * size);
       
   452 
       
   453             m_glyphPool += size;
       
   454             m_positionPool += size;
       
   455         }                
       
   456 
       
   457 
       
   458         virtual bool begin(QPaintDevice *)  { return true; }
       
   459         virtual bool end() { return true; }
       
   460         virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
       
   461         virtual Type type() const
       
   462         {
       
   463             return User;
       
   464         }
       
   465 
       
   466         int itemCount() const
       
   467         {
       
   468             return m_itemCount;
       
   469         }
       
   470 
       
   471         int glyphCount() const
       
   472         {
       
   473             return m_glyphCount;
       
   474         }
       
   475 
       
   476     private:
       
   477         QStaticTextItem *m_items;
       
   478         int m_itemCount;
       
   479         int m_glyphCount;
       
   480         int m_expectedItemCount;
       
   481         int m_expectedGlyphCount;
       
   482 
       
   483         glyph_t *m_glyphPool;
       
   484         QFixedPoint *m_positionPool;
       
   485 
       
   486         bool m_dirtyPen;
       
   487     };
       
   488 
       
   489     class DrawTextItemDevice: public QPaintDevice
       
   490     {
       
   491     public:
       
   492         DrawTextItemDevice(int expectedItemCount = -1,  QStaticTextItem *items = 0,
       
   493                            int expectedGlyphCount = -1, QFixedPoint *positionPool = 0,
       
   494                            glyph_t *glyphPool = 0)
       
   495         {
       
   496             m_paintEngine = new DrawTextItemRecorder(expectedItemCount, items,
       
   497                                                      expectedGlyphCount, positionPool, glyphPool);
       
   498         }
       
   499 
       
   500         ~DrawTextItemDevice()
       
   501         {
       
   502             delete m_paintEngine;
       
   503         }
       
   504 
       
   505         int metric(PaintDeviceMetric m) const
       
   506         {
       
   507             int val;
       
   508             switch (m) {
       
   509             case PdmWidth:
       
   510             case PdmHeight:
       
   511             case PdmWidthMM:
       
   512             case PdmHeightMM:
       
   513                 val = 0;
       
   514                 break;
       
   515             case PdmDpiX:
       
   516             case PdmPhysicalDpiX:
       
   517                 val = qt_defaultDpiX();
       
   518                 break;
       
   519             case PdmDpiY:
       
   520             case PdmPhysicalDpiY:
       
   521                 val = qt_defaultDpiY();
       
   522                 break;
       
   523             case PdmNumColors:
       
   524                 val = 16777216;
       
   525                 break;
       
   526             case PdmDepth:
       
   527                 val = 24;
       
   528                 break;
       
   529             default:
       
   530                 val = 0;
       
   531                 qWarning("DrawTextItemDevice::metric: Invalid metric command");
       
   532             }
       
   533             return val;
       
   534         }
       
   535 
       
   536         virtual QPaintEngine *paintEngine() const
       
   537         {
       
   538             return m_paintEngine;
       
   539         }
       
   540 
       
   541         int itemCount() const
       
   542         {
       
   543             return m_paintEngine->itemCount();
       
   544         }
       
   545 
       
   546         int glyphCount() const
       
   547         {
       
   548             return m_paintEngine->glyphCount();
       
   549         }
       
   550 
       
   551     private:
       
   552         DrawTextItemRecorder *m_paintEngine;
       
   553     };
       
   554 }
       
   555 
       
   556 void QStaticTextPrivate::paintText(const QPointF &topLeftPosition, QPainter *p)
       
   557 {
       
   558     bool preferRichText = textFormat == Qt::RichText
       
   559                           || (textFormat == Qt::AutoText && Qt::mightBeRichText(text));
       
   560 
       
   561     if (!preferRichText) {
       
   562         QTextLayout textLayout;
       
   563         textLayout.setText(text);
       
   564         textLayout.setFont(font);
       
   565 
       
   566         qreal leading = QFontMetricsF(font).leading();
       
   567         qreal height = -leading;
       
   568 
       
   569         textLayout.beginLayout();
       
   570         while (1) {
       
   571             QTextLine line = textLayout.createLine();
       
   572             if (!line.isValid())
       
   573                 break;
       
   574 
       
   575             if (textWidth >= 0.0)
       
   576                 line.setLineWidth(textWidth);
       
   577             height += leading;
       
   578             line.setPosition(QPointF(0.0, height));
       
   579             height += line.height();
       
   580         }
       
   581         textLayout.endLayout();
       
   582 
       
   583         actualSize = textLayout.boundingRect().size();
       
   584         textLayout.draw(p, topLeftPosition);
       
   585     } else {
       
   586         QTextDocument document;
       
   587 #ifndef QT_NO_CSSPARSER
       
   588         QColor color = p->pen().color();
       
   589         document.setDefaultStyleSheet(QString::fromLatin1("body { color: #%1%2%3 }")
       
   590                                       .arg(QString::number(color.red(), 16), 2, QLatin1Char('0'))
       
   591                                       .arg(QString::number(color.green(), 16), 2, QLatin1Char('0'))
       
   592                                       .arg(QString::number(color.blue(), 16), 2, QLatin1Char('0')));
       
   593 #endif
       
   594         document.setDefaultFont(font);
       
   595         document.setDocumentMargin(0.0);
       
   596         if (textWidth >= 0.0)
       
   597             document.setTextWidth(textWidth);
       
   598 #ifndef QT_NO_TEXTHTMLPARSER
       
   599         document.setHtml(text);
       
   600 #else
       
   601         document.setPlainText(text);
       
   602 #endif
       
   603 
       
   604         document.adjustSize();
       
   605         p->save();
       
   606         p->translate(topLeftPosition);
       
   607         document.drawContents(p);
       
   608         p->restore();
       
   609 
       
   610         actualSize = document.size();
       
   611     }
       
   612 }
       
   613 
       
   614 void QStaticTextPrivate::init()
       
   615 {
       
   616     delete[] items;
       
   617     delete[] glyphPool;
       
   618     delete[] positionPool;
       
   619 
       
   620     position = QPointF(0, 0);
       
   621 
       
   622     // Draw once to count number of items and glyphs, so that we can use as little memory
       
   623     // as possible to store the data
       
   624     DrawTextItemDevice counterDevice;
       
   625     {
       
   626         QPainter painter(&counterDevice);
       
   627         painter.setFont(font);
       
   628         painter.setTransform(matrix);
       
   629 
       
   630         paintText(QPointF(0, 0), &painter);
       
   631 
       
   632     }
       
   633 
       
   634     itemCount = counterDevice.itemCount();    
       
   635     items = new QStaticTextItem[itemCount];
       
   636 
       
   637     if (useBackendOptimizations) {
       
   638         for (int i=0; i<itemCount; ++i)
       
   639             items[i].useBackendOptimizations = true;
       
   640     }
       
   641 
       
   642 
       
   643     int glyphCount = counterDevice.glyphCount();
       
   644     glyphPool = new glyph_t[glyphCount];
       
   645     positionPool = new QFixedPoint[glyphCount];
       
   646 
       
   647     // Draw again to actually record the items and glyphs
       
   648     DrawTextItemDevice recorderDevice(itemCount, items, glyphCount, positionPool, glyphPool);
       
   649     {
       
   650         QPainter painter(&recorderDevice);
       
   651         painter.setFont(font);
       
   652         painter.setTransform(matrix);
       
   653 
       
   654         paintText(QPointF(0, 0), &painter);
       
   655     }
       
   656 
       
   657     needsRelayout = false;
       
   658 }
       
   659 
       
   660 QT_END_NAMESPACE