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