diff options
-rw-r--r-- | src/gui/painting/qpaintbuffer.cpp | 33 | ||||
-rw-r--r-- | src/gui/painting/qpainter.cpp | 56 | ||||
-rw-r--r-- | src/gui/painting/qpainter.h | 6 | ||||
-rw-r--r-- | src/gui/text/qstatictext.cpp | 163 | ||||
-rw-r--r-- | src/gui/text/qstatictext.h | 8 | ||||
-rw-r--r-- | src/gui/text/qstatictext_p.h | 13 | ||||
-rw-r--r-- | tests/auto/qstatictext/tst_qstatictext.cpp | 135 |
7 files changed, 282 insertions, 132 deletions
diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index ca2077f..e1156dc 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -557,11 +557,7 @@ QString QPaintBuffer::commandDescription(int command) const debug << "Cmd_Translate:" << delta; break; } case QPaintBufferPrivate::Cmd_DrawStaticText: { - QPointF delta(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1)); - QVariantList variants(d_ptr->variants.at(cmd.offset).value<QVariantList>()); - - QStaticText text(variants.at(0).value<QStaticText>()); - debug << "Cmd_DrawStaticText:" << text.text(); + debug << "Cmd_DrawStaticText"; break; } } @@ -1272,13 +1268,14 @@ void QPaintBufferEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem) { - QString text = QString(staticTextItem->chars, staticTextItem->numChars); + QVariantList variants; - QStaticText staticText(text); - staticText.prepare(state()->matrix, staticTextItem->font); + variants << QVariant(staticTextItem->font); + for (int i=0; i<staticTextItem->numGlyphs; ++i) { + variants.append(staticTextItem->glyphs[i]); + variants.append(staticTextItem->glyphPositions[i].toPointF()); + } - QVariantList variants; - variants << QVariant(staticTextItem->font) << QVariant::fromValue(staticText); buffer->addCommand(QPaintBufferPrivate::Cmd_DrawStaticText, QVariant(variants)); } @@ -1761,11 +1758,19 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) QVariantList variants(d->variants.at(cmd.offset).value<QVariantList>()); - QFont font(variants.at(0).value<QFont>()); - QStaticText text(variants.at(0).value<QStaticText>()); - + QFont font = variants.at(0).value<QFont>(); + + QVector<quint32> glyphs; + QVector<QPointF> positions; + + for (int i=0; i<(variants.size() - 1) / 2; ++i) { + glyphs.append(variants.at(i*2 + 1).toUInt()); + positions.append(variants.at(i*2 + 2).toPointF()); + } + painter->setFont(font); - painter->drawStaticText(QPointF(0, 0), text); + + qt_draw_glyphs(painter, glyphs.constData(), positions.constData(), glyphs.size()); break; } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 1c528fe..7b5fcc2 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5720,6 +5720,16 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, const QPointF *posit QFontEngine *fontEngine = state->font.d->engineForScript(QUnicodeTables::Common); + while (fontEngine->type() == QFontEngine::Multi) { + // Pick engine based on first glyph in array if we are using a multi engine. + // (all glyphs must be for same font) + int engineIdx = 0; + if (glyphCount > 0) + engineIdx = glyphArray[0] >> 24; + + fontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx); + } + QVarLengthArray<QFixedPoint, 128> positions; for (int i=0; i<glyphCount; ++i) { QFixedPoint fp = QFixedPoint::fromPointF(positionArray[i]); @@ -5762,19 +5772,24 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, const QPointF *posit /*! - \fn void QPainter::drawStaticText(const QPoint &position, const QStaticText &staticText) + \fn void QPainter::drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText) \since 4.7 \overload - Draws the \a staticText at the \a position. + Draws the \a staticText at the \a topLeftPosition. + + \note The y-position is used as the top of the font. + */ /*! - \fn void QPainter::drawStaticText(int x, int y, const QStaticText &staticText) + \fn void QPainter::drawStaticText(int left, int top, const QStaticText &staticText) \since 4.7 \overload - Draws the \a staticText at coordinates \a x and \a y. + Draws the \a staticText at coordinates \a left and \a top. + + \note The y-position is used as the top of the font. */ /*! @@ -5802,7 +5817,7 @@ void QPainter::drawText(const QPointF &p, const QString &str) /*! \since 4.7 - Draws the given \a staticText at the given \a position. + Draws the given \a staticText at the given \a topLeftPosition. The text will be drawn using the font and the transformation set on the painter. If the font and/or transformation set on the painter are different from the ones used to initialize @@ -5810,15 +5825,17 @@ void QPainter::drawText(const QPointF &p, const QString &str) QStaticText::prepare() to initialize \a staticText with the font and transformation with which it will later be drawn. - If \a position is not the same as when \a staticText was initialized, or when it was last drawn, - then there will be a slight overhead when translating the text to its new position. + If \a topLeftPosition is not the same as when \a staticText was initialized, or when it was + last drawn, then there will be a slight overhead when translating the text to its new position. + + \note If the painter's transformation is not affine, then \a staticText will be drawn using + regular calls to drawText(), losing any potential for performance improvement. - \note If the painter's transformation is not affine, then \a staticText will be drawn using regular - calls to drawText(), losing any potential performance improvement. + \note The y-position is used as the top of the font. \sa QStaticText */ -void QPainter::drawStaticText(const QPointF &position, const QStaticText &staticText) +void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText) { Q_D(QPainter); if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen) @@ -5830,13 +5847,13 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static // If we don't have an extended paint engine, or if the painter is projected, // we go through standard code path if (d->extended == 0 || !d->state->matrix.isAffine()) { - staticText_d->paintText(position, this); + staticText_d->paintText(topLeftPosition, this); return; } // Don't recalculate entire layout because of translation, rather add the dx and dy // into the position to move each text item the correct distance. - QPointF transformedPosition = position * d->state->matrix; + QPointF transformedPosition = topLeftPosition * d->state->matrix; QTransform matrix = d->state->matrix; // The translation has been applied to transformedPosition. Remove translation @@ -5857,20 +5874,12 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static // If the transform is not identical to the text transform, // we have to relayout the text (for other transformations than plain translation) - bool staticTextNeedsReinit = false; + bool staticTextNeedsReinit = staticText_d->needsRelayout; if (staticText_d->matrix != d->state->matrix) { staticText_d->matrix = d->state->matrix; staticTextNeedsReinit = true; } - bool restoreWhenFinished = false; - if (staticText_d->needsClipRect) { - save(); - setClipRect(QRectF(position, staticText_d->maximumSize)); - - restoreWhenFinished = true; - } - if (font() != staticText_d->font) { staticText_d->font = font(); staticTextNeedsReinit = true; @@ -5901,7 +5910,7 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static QColor currentColor = oldPen.color(); for (int i=0; i<staticText_d->itemCount; ++i) { QStaticTextItem *item = staticText_d->items + i; - if (currentColor != item->color) { + if (item->color.isValid() && currentColor != item->color) { setPen(item->color); currentColor = item->color; } @@ -5910,9 +5919,6 @@ void QPainter::drawStaticText(const QPointF &position, const QStaticText &static if (currentColor != oldPen.color()) setPen(oldPen); - if (restoreWhenFinished) - restore(); - if (matrix.isTranslating()) d->state->matrix = matrix; } diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index 443925b..edfb67e 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -396,9 +396,9 @@ public: void setLayoutDirection(Qt::LayoutDirection direction); Qt::LayoutDirection layoutDirection() const; - void drawStaticText(const QPointF &p, const QStaticText &staticText); - inline void drawStaticText(const QPoint &p, const QStaticText &staticText); - inline void drawStaticText(int x, int y, const QStaticText &staticText); + void drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText); + inline void drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText); + inline void drawStaticText(int left, int top, const QStaticText &staticText); void drawText(const QPointF &p, const QString &s); inline void drawText(const QPoint &p, const QString &s); diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index d685cd9..45252d8 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -99,20 +99,27 @@ QT_BEGIN_NAMESPACE point with no boundaries, and also when QPainter::drawText() is called with a bounding rectangle. - If a bounding rectangle is not required, create a QStaticText object without setting a maximum - size. The text will then occupy a single line. + If a bounding rectangle is not required, create a QStaticText object without setting a preferred + text width. The text will then occupy a single line. - If you set a maximum size on the QStaticText object, this will bound the text. The text will - be formatted so that no line exceeds the given width. When the object is painted, it will - be clipped at the given size. The position of the text is decided by the argument - passed to QPainter::drawStaticText() and can change from call to call with a minimal impact - on performance. + If you set a text width on the QStaticText object, this will bound the text. The text will + be formatted so that no line exceeds the given width. The text width set for QStaticText will + not automatically be used for clipping. To achieve clipping in addition to line breaks, use + QPainter::setClipRect(). The position of the text is decided by the argument passed to + QPainter::drawStaticText() and can change from call to call with a minimal impact on + performance. QStaticText will attempt to guess the format of the input text using Qt::mightBeRichText(). To force QStaticText to display its contents as either plain text or rich text, use the function QStaticText::setTextFormat() and pass in, respectively, Qt::PlainText and Qt::RichText. + If it's the first time the static text is drawn, or if the static text, or the painter's font + or matrix have been altered since the last time it was drawn, the text's layout has to be + recalculated. This will impose an overhead on the QPainter::drawStaticText() call where the + relayout occurs. To avoid this overhead in the paint event, you can call prepare() ahead of + time to ensure that the layout is calculated. + \sa QPainter::drawText(), QPainter::drawStaticText(), QTextLayout, QTextDocument */ @@ -143,12 +150,11 @@ QStaticText::QStaticText() If an invalid size is passed for \a size the text will be unbounded. */ -QStaticText::QStaticText(const QString &text, const QSizeF &size) +QStaticText::QStaticText(const QString &text) : data(new QStaticTextPrivate) { data->text = text; - data->maximumSize = size; - data->init(); + data->invalidate(); } /*! @@ -177,17 +183,17 @@ void QStaticText::detach() } /*! - Prepares the QStaticText object for being painted with the given \a matrix and the given - \a font to avoid overhead when the actual drawStaticText() call is made. + Prepares the QStaticText object for being painted with the given \a matrix and the given \a font + to avoid overhead when the actual drawStaticText() call is made. - When drawStaticText() is called, the layout of the QStaticText will be recalculated if the - painter's font or matrix is different from the one used for the currently cached layout. By - default, QStaticText will use a default constructed QFont and an identity matrix to create - its layout. + When drawStaticText() is called, the layout of the QStaticText will be recalculated if any part + of the QStaticText object has changed since the last time it was drawn. It will also be + recalculated if the painter's font or matrix are not the same as when the QStaticText was last + drawn. - To avoid the overhead of creating the layout the first time you draw the QStaticText with - a painter whose matrix or font are different from the defaults, you can use the prepare() - function and pass in the matrix and font you expect to use when drawing the text. + To avoid the overhead of creating the layout the first time you draw the QStaticText after + making changes, you can use the prepare() function and pass in the \a matrix and \a font you + expect to use when drawing the text. \sa QPainter::setFont(), QPainter::setMatrix() */ @@ -209,7 +215,7 @@ QStaticText &QStaticText::operator=(const QStaticText &other) } /*! - Compares \a other to this QStaticText. Returns true if the texts, fonts and maximum sizes + Compares \a other to this QStaticText. Returns true if the texts, fonts and text widths are equal. */ bool QStaticText::operator==(const QStaticText &other) const @@ -217,7 +223,7 @@ bool QStaticText::operator==(const QStaticText &other) const return (data == other.data || (data->text == other.data->text && data->font == other.data->font - && data->maximumSize == other.data->maximumSize)); + && data->textWidth == other.data->textWidth)); } /*! @@ -232,7 +238,7 @@ bool QStaticText::operator!=(const QStaticText &other) const /*! Sets the text of the QStaticText to \a text. - \note This function will cause the layout of the text to be recalculated. + \note This function will cause the layout of the text to require recalculation. \sa text() */ @@ -240,7 +246,7 @@ void QStaticText::setText(const QString &text) { detach(); data->text = text; - data->init(); + data->invalidate(); } /*! @@ -250,7 +256,7 @@ void QStaticText::setText(const QString &text) displayed as is, whereas it will be interpreted as HTML if the format is Qt::RichText. HTML tags that alter the font of the text, its color, or its layout are supported by QStaticText. - \note This function will cause the layout of the text to be recalculated. + \note This function will cause the layout of the text to require recalculation. \sa textFormat(), setText(), text() */ @@ -258,7 +264,7 @@ void QStaticText::setTextFormat(Qt::TextFormat textFormat) { detach(); data->textFormat = textFormat; - data->init(); + data->invalidate(); } /*! @@ -289,7 +295,7 @@ QString QStaticText::text() const The default is QStaticText::ModerateCaching. - \note This function will cause the layout of the text to be recalculated. + \note This function will cause the layout of the text to require recalculation. \sa performanceHint() */ @@ -301,7 +307,7 @@ void QStaticText::setPerformanceHint(PerformanceHint performanceHint) } detach(); data->useBackendOptimizations = (performanceHint == AggressiveCaching); - data->init(); + data->invalidate(); } /*! @@ -315,48 +321,56 @@ QStaticText::PerformanceHint QStaticText::performanceHint() const } /*! - Sets the maximum size of the QStaticText to \a size. + Sets the preferred width for this QStaticText. If the text is wider than the specified width, + it will be broken into multiple lines and grow vertically. If the text cannot be split into + multiple lines, it will be larger than the specified \a textWidth. - \note This function will cause the layout of the text to be recalculated. + Setting the preferred text width to a negative number will cause the text to be unbounded. - \sa maximumSize(), size() + Use size() to get the actual size of the text. + + \note This function will cause the layout of the text to require recalculation. + + \sa textWidth(), size() */ -void QStaticText::setMaximumSize(const QSizeF &size) +void QStaticText::setTextWidth(qreal textWidth) { detach(); - data->maximumSize = size; - data->init(); + data->textWidth = textWidth; + data->invalidate(); } /*! - Returns the maximum size of the QStaticText. + Returns the preferred width for this QStaticText. - \sa setMaximumSize() + \sa setTextWidth() */ -QSizeF QStaticText::maximumSize() const +qreal QStaticText::textWidth() const { - return data->maximumSize; + return data->textWidth; } /*! Returns the size of the bounding rect for this QStaticText. - \sa maximumSize() + \sa textWidth() */ QSizeF QStaticText::size() const { + if (data->needsRelayout) + data->init(); return data->actualSize; } QStaticTextPrivate::QStaticTextPrivate() - : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false), - useBackendOptimizations(false), textFormat(Qt::AutoText) + : items(0), itemCount(0), glyphPool(0), positionPool(0), textWidth(-1.0), + needsRelayout(true), useBackendOptimizations(false), textFormat(Qt::AutoText) { } QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other) - : text(other.text), font(other.font), maximumSize(other.maximumSize), matrix(other.matrix), - items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false), + : text(other.text), font(other.font), textWidth(other.textWidth), matrix(other.matrix), + items(0), itemCount(0), glyphPool(0), positionPool(0), needsRelayout(true), useBackendOptimizations(other.useBackendOptimizations), textFormat(other.textFormat) { } @@ -388,8 +402,15 @@ namespace { m_expectedItemCount(expectedItemCount), m_expectedGlyphCount(expectedGlyphCount), m_glyphPool(glyphPool), - m_positionPool(positionPool) + m_positionPool(positionPool), + m_dirtyPen(false) + { + } + + virtual void updateState(const QPaintEngineState &newState) { + if (newState.state() & QPaintEngine::DirtyPen) + m_dirtyPen = true; } virtual void drawTextItem(const QPointF &position, const QTextItem &textItem) @@ -412,7 +433,8 @@ namespace { currentItem->numGlyphs = ti.glyphs.numGlyphs; currentItem->glyphs = m_glyphPool; currentItem->glyphPositions = m_positionPool; - currentItem->color = state->pen().color(); + if (m_dirtyPen) + currentItem->color = state->pen().color(); QTransform matrix = state->transform(); matrix.translate(position.x(), position.y()); @@ -435,7 +457,6 @@ namespace { virtual bool begin(QPaintDevice *) { return true; } virtual bool end() { return true; } - virtual void updateState(const QPaintEngineState &) {} virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {} virtual Type type() const { @@ -461,6 +482,8 @@ namespace { glyph_t *m_glyphPool; QFixedPoint *m_positionPool; + + bool m_dirtyPen; }; class DrawTextItemDevice: public QPaintDevice @@ -530,43 +553,50 @@ namespace { }; } -void QStaticTextPrivate::paintText(const QPointF &pos, QPainter *p) +void QStaticTextPrivate::paintText(const QPointF &topLeftPosition, QPainter *p) { bool preferRichText = textFormat == Qt::RichText || (textFormat == Qt::AutoText && Qt::mightBeRichText(text)); if (!preferRichText) { - if (maximumSize.isValid()) { - QRectF boundingRect; - p->drawText(QRectF(pos, maximumSize), Qt::TextWordWrap, text, &boundingRect); - - actualSize = boundingRect.size(); - needsClipRect = boundingRect.width() > maximumSize.width() - || boundingRect.height() > maximumSize.height(); - } else { - p->drawText(pos, text); - needsClipRect = false; - - QFontMetrics fm(font); - actualSize = fm.boundingRect(text).size(); + QTextLayout textLayout; + textLayout.setText(text); + textLayout.setFont(font); + + qreal leading = QFontMetricsF(font).leading(); + qreal height = -leading; + + textLayout.beginLayout(); + while (1) { + QTextLine line = textLayout.createLine(); + if (!line.isValid()) + break; + + if (textWidth >= 0.0) + line.setLineWidth(textWidth); + height += leading; + line.setPosition(QPointF(0.0, height)); + height += line.height(); } + textLayout.endLayout(); + + actualSize = textLayout.boundingRect().size(); + textLayout.draw(p, topLeftPosition); } else { QTextDocument document; document.setDefaultFont(font); document.setDocumentMargin(0.0); + if (textWidth >= 0.0) + document.setTextWidth(textWidth); document.setHtml(text); - QPointF adjustedPos = pos - QPointF(0, QFontMetricsF(font).ascent()); - QRectF rect = maximumSize.isValid() ? QRectF(adjustedPos, maximumSize) : QRectF(); document.adjustSize(); p->save(); - p->translate(adjustedPos); - document.drawContents(p, rect); + p->translate(topLeftPosition); + document.drawContents(p); p->restore(); + actualSize = document.size(); - needsClipRect = maximumSize.isValid() - && (actualSize.width() > maximumSize.width() - || actualSize.height() > maximumSize.height()); } } @@ -613,6 +643,7 @@ void QStaticTextPrivate::init() paintText(QPointF(0, 0), &painter); } + needsRelayout = false; } QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h index 00d42e0..f3bef93 100644 --- a/src/gui/text/qstatictext.h +++ b/src/gui/text/qstatictext.h @@ -66,7 +66,7 @@ public: }; QStaticText(); - QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF()); + QStaticText(const QString &text); QStaticText(const QStaticText &other); ~QStaticText(); @@ -76,12 +76,12 @@ public: void setTextFormat(Qt::TextFormat textFormat); Qt::TextFormat textFormat() const; - void setMaximumSize(const QSizeF &maximumSize); - QSizeF maximumSize() const; + void setTextWidth(qreal textWidth); + qreal textWidth() const; QSizeF size() const; - void prepare(const QTransform &matrix, const QFont &font); + void prepare(const QTransform &matrix = QTransform(), const QFont &font = QFont()); void setPerformanceHint(PerformanceHint performanceHint); PerformanceHint performanceHint() const; diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index e758244..f017ed1 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -118,11 +118,16 @@ public: void init(); void paintText(const QPointF &pos, QPainter *p); + void invalidate() + { + needsRelayout = true; + } + QAtomicInt ref; // 4 bytes per text QString text; // 4 bytes per text QFont font; // 8 bytes per text - QSizeF maximumSize; // 16 bytes per text + qreal textWidth; // 8 bytes per text QSizeF actualSize; // 16 bytes per text QPointF position; // 16 bytes per text @@ -132,11 +137,11 @@ public: glyph_t *glyphPool; // 4 bytes per text QFixedPoint *positionPool; // 4 bytes per text - unsigned char needsClipRect : 1; // 1 byte per text - unsigned char useBackendOptimizations : 1; + unsigned char needsRelayout : 1; + unsigned char useBackendOptimizations : 1; // 1 byte per text unsigned char textFormat : 2; // ================ - // 171 bytes per text + // 163 bytes per text static QStaticTextPrivate *get(const QStaticText *q); }; diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp index a038878..e7a22b3 100644 --- a/tests/auto/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/qstatictext/tst_qstatictext.cpp @@ -69,7 +69,7 @@ private slots: void drawToRect_data(); void drawToRect(); void setFont(); - void setMaximumSize(); + void setTextWidth(); void prepareToCorrectData(); void prepareToWrongData(); @@ -81,6 +81,10 @@ private slots: void transformationChanged(); void plainTextVsRichText(); + + void setPenPlainText(); + void setPenRichText(); + void richTextOverridesPen(); }; void tst_QStaticText::init() @@ -123,7 +127,7 @@ void tst_QStaticText::drawToPoint() QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.setTextFormat(Qt::PlainText); text.setPerformanceHint(performanceHint); - p.drawStaticText(QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -152,12 +156,19 @@ void tst_QStaticText::drawToRect() imageDrawStaticText.fill(Qt::white); { QPainter p(&imageDrawStaticText); - QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", QSizeF(10, 500)); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextWidth(10), + p.setClipRect(QRectF(11, 12, 10, 500)); text.setPerformanceHint(performanceHint); text.setTextFormat(Qt::PlainText); p.drawStaticText(QPointF(11, 12), text); } +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawToRect_imageDrawText.png"); + imageDrawStaticText.save("drawToRect_imageDrawStaticText.png"); +#endif + QCOMPARE(imageDrawStaticText, imageDrawText); } @@ -183,7 +194,7 @@ void tst_QStaticText::prepareToCorrectData() QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.prepare(transform, p.font()); text.setTextFormat(Qt::PlainText); - p.drawStaticText(QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); } if (!supportsTransformations()) @@ -211,7 +222,7 @@ void tst_QStaticText::prepareToWrongData() QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.prepare(transform, p.font()); text.setTextFormat(Qt::PlainText); - p.drawStaticText(QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -228,10 +239,10 @@ void tst_QStaticText::setFont() imageDrawText.fill(Qt::white); { QPainter p(&imageDrawText); - p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawText(0, 0 + QFontMetrics(p.font()).ascent(), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); p.setFont(font); - p.drawText(11, 120, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawText(11, 120 + QFontMetrics(p.font()).ascent(), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } QPixmap imageDrawStaticText(1000, 1000); @@ -249,10 +260,15 @@ void tst_QStaticText::setFont() p.drawStaticText(11, 120, text); } +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("setFont_imageDrawText.png"); + imageDrawStaticText.save("setFont_imageDrawStaticText.png"); +#endif + QCOMPARE(imageDrawStaticText, imageDrawText); } -void tst_QStaticText::setMaximumSize() +void tst_QStaticText::setTextWidth() { QPixmap imageDrawText(1000, 1000); imageDrawText.fill(Qt::white); @@ -266,7 +282,8 @@ void tst_QStaticText::setMaximumSize() { QPainter p(&imageDrawStaticText); QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); - text.setMaximumSize(QSizeF(10, 500)); + text.setTextWidth(10); + p.setClipRect(QRectF(11, 12, 10, 500)); p.drawStaticText(QPointF(11, 12), text); } @@ -293,7 +310,7 @@ void tst_QStaticText::translatedPainter() QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.setTextFormat(Qt::PlainText); - p.drawStaticText(QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -325,7 +342,7 @@ void tst_QStaticText::rotatedPainter() { QPainter p(&imageDrawText); p.rotate(30.0); - p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawText(0, 0 + QFontMetricsF(p.font()).ascent(), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } QPixmap imageDrawStaticText(1000, 1000); @@ -369,7 +386,7 @@ void tst_QStaticText::scaledPainter() QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.setTextFormat(Qt::PlainText); - p.drawStaticText(QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); } if (!supportsTransformations()) @@ -400,7 +417,7 @@ void tst_QStaticText::projectedPainter() QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.setTextFormat(Qt::PlainText); - p.drawStaticText(QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); } QCOMPARE(imageDrawStaticText, imageDrawText); @@ -430,7 +447,7 @@ void tst_QStaticText::rotatedScaledAndTranslatedPainter() QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); text.setTextFormat(Qt::PlainText); - p.drawStaticText(QPointF(11, 12), text); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); } #if defined(DEBUG_SAVE_IMAGE) @@ -452,10 +469,10 @@ void tst_QStaticText::transformationChanged() p.rotate(33.0); p.scale(0.5, 0.7); - p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawText(0, 0 + QFontMetricsF(p.font()).ascent(), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); p.scale(7.0, 5.0); - p.drawText(0, 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + p.drawText(0, 0 + QFontMetricsF(p.font()).ascent(), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); } QPixmap imageDrawStaticText(1000, 1000); @@ -518,5 +535,91 @@ void tst_QStaticText::plainTextVsRichText() QCOMPARE(imagePlainText, imageRichText); } +void tst_QStaticText::setPenPlainText() +{ + QFont font = QApplication::font(); + font.setStyleStrategy(QFont::NoAntialias); + + QFontMetricsF fm(font); + QPixmap image(qCeil(fm.width("XXXXX")), qCeil(fm.height())); + image.fill(Qt::white); + { + QPainter p(&image); + p.setFont(font); + p.setPen(Qt::green); + + QStaticText staticText("XXXXX"); + staticText.setTextFormat(Qt::PlainText); + p.drawStaticText(0, fm.ascent(), staticText); + } + + QImage img = image.toImage(); + for (int x=0; x<img.width(); ++x) { + for (int y=0; y<img.height(); ++y) { + QRgb pixel = img.pixel(x, y); + QVERIFY(pixel == QColor(Qt::white).rgba() + || pixel == QColor(Qt::green).rgba()); + } + } +} + +void tst_QStaticText::setPenRichText() +{ + QFont font = QApplication::font(); + font.setStyleStrategy(QFont::NoAntialias); + + QFontMetricsF fm(font); + QPixmap image(qCeil(fm.width("XXXXX")), qCeil(fm.height())); + image.fill(Qt::white); + { + QPainter p(&image); + p.setFont(font); + p.setPen(Qt::green); + + QStaticText staticText; + staticText.setText("<html><body>XXXXX</body></html>"); + staticText.setTextFormat(Qt::RichText); + p.drawStaticText(0, 0, staticText); + } + + QImage img = image.toImage(); + for (int x=0; x<img.width(); ++x) { + for (int y=0; y<img.height(); ++y) { + QRgb pixel = img.pixel(x, y); + QVERIFY(pixel == QColor(Qt::white).rgba() + || pixel == QColor(Qt::green).rgba()); + } + } +} + +void tst_QStaticText::richTextOverridesPen() +{ + QFont font = QApplication::font(); + font.setStyleStrategy(QFont::NoAntialias); + + QFontMetricsF fm(font); + QPixmap image(qCeil(fm.width("XXXXX")), qCeil(fm.height())); + image.fill(Qt::white); + { + QPainter p(&image); + p.setFont(font); + p.setPen(Qt::green); + + QStaticText staticText; + staticText.setText("<html><body><font color=\"#ff0000\">XXXXX</font></body></html>"); + staticText.setTextFormat(Qt::RichText); + p.drawStaticText(0, 0, staticText); + } + + QImage img = image.toImage(); + for (int x=0; x<img.width(); ++x) { + for (int y=0; y<img.height(); ++y) { + QRgb pixel = img.pixel(x, y); + QVERIFY(pixel == QColor(Qt::white).rgba() + || pixel == QColor(Qt::red).rgba()); + } + } +} + QTEST_MAIN(tst_QStaticText) #include "tst_qstatictext.moc" |