diff options
Diffstat (limited to 'src/gui/text')
-rw-r--r-- | src/gui/text/qfontdatabase_s60.cpp | 5 | ||||
-rw-r--r-- | src/gui/text/qfontengine.cpp | 15 | ||||
-rw-r--r-- | src/gui/text/qfontengine_p.h | 3 | ||||
-rw-r--r-- | src/gui/text/qfontengine_win.cpp | 31 | ||||
-rw-r--r-- | src/gui/text/qfontengine_win_p.h | 4 | ||||
-rw-r--r-- | src/gui/text/qfontmetrics.cpp | 21 | ||||
-rw-r--r-- | src/gui/text/qstatictext.cpp | 168 | ||||
-rw-r--r-- | src/gui/text/qstatictext.h | 8 | ||||
-rw-r--r-- | src/gui/text/qstatictext_p.h | 13 | ||||
-rw-r--r-- | src/gui/text/qtextlayout.cpp | 6 |
10 files changed, 189 insertions, 85 deletions
diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp index 621f666..ef5e0c4 100644 --- a/src/gui/text/qfontdatabase_s60.cpp +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -332,6 +332,11 @@ bool QFontDatabase::removeApplicationFont(int handle) return false; } +bool QFontDatabase::removeAllApplicationFonts() +{ + return false; +} + bool QFontDatabase::supportsThreadedFontRendering() { return false; diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index e5975d2..194c5f3 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -379,6 +379,15 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform Q_ASSERT(positions.size() == glyphs_out.size()); } +void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing) +{ + glyph_metrics_t gi = boundingBox(glyph); + bool isValid = gi.isValid(); + if (leftBearing != 0) + *leftBearing = isValid ? gi.x.toReal() : 0.0; + if (rightBearing != 0) + *rightBearing = isValid ? (gi.xoff - gi.x - gi.width).toReal() : 0.0; +} glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs) { @@ -1389,6 +1398,12 @@ glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs) return overall; } +void QFontEngineMulti::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing) +{ + int which = highByte(glyph); + engine(which)->getGlyphBearings(stripped(glyph), leftBearing, rightBearing); +} + void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) { diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 71ab5a5..e645caf 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -206,6 +206,8 @@ public: virtual qreal minLeftBearing() const { return qreal(); } virtual qreal minRightBearing() const { return qreal(); } + virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0); + virtual const char *name() const = 0; virtual bool canRender(const QChar *string, int len) = 0; @@ -374,6 +376,7 @@ public: virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const; virtual void doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const; virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags); + virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0); virtual QFixed ascent() const; virtual QFixed descent() const; diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp index 55e93bd..a805612 100644 --- a/src/gui/text/qfontengine_win.cpp +++ b/src/gui/text/qfontengine_win.cpp @@ -39,6 +39,11 @@ ** ****************************************************************************/ +#if _WIN32_WINNT < 0x0500 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif + #include "qfontengine_p.h" #include "qtextengine_p.h" #include <qglobal.h> @@ -649,6 +654,32 @@ static const ushort char_table[] = { static const int char_table_entries = sizeof(char_table)/sizeof(ushort); +#ifndef Q_CC_MINGW +void QFontEngineWin::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing) +{ + HDC hdc = shared_dc(); + SelectObject(hdc, hfont); + +#ifndef Q_WS_WINCE + if (ttf) +#endif + + { + ABC abcWidths; + GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths); + if (leftBearing) + *leftBearing = abcWidths.abcA; + if (rightBearing) + *rightBearing = abcWidths.abcC; + } + +#ifndef Q_WS_WINCE + else { + QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing); + } +#endif +} +#endif // Q_CC_MINGW qreal QFontEngineWin::minLeftBearing() const { diff --git a/src/gui/text/qfontengine_win_p.h b/src/gui/text/qfontengine_win_p.h index f9d8f8b..68b53b5 100644 --- a/src/gui/text/qfontengine_win_p.h +++ b/src/gui/text/qfontengine_win_p.h @@ -106,6 +106,10 @@ public: virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform); virtual QImage alphaRGBMapForGlyph(glyph_t t, int margin, const QTransform &xform); +#ifndef Q_CC_MINGW + virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0); +#endif + int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, bool mirrored) const; void getCMap(); diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 7f9ae8b..3a52e8e 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -472,8 +472,9 @@ int QFontMetrics::leftBearing(QChar ch) const int nglyphs = 9; engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); // ### can nglyphs != 1 happen at all? Not currently I think - glyph_metrics_t gi = engine->boundingBox(glyphs.glyphs[0]); - return qRound(gi.x); + qreal lb; + engine->getGlyphBearings(glyphs.glyphs[0], &lb); + return qRound(lb); } /*! @@ -506,8 +507,9 @@ int QFontMetrics::rightBearing(QChar ch) const int nglyphs = 9; engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); // ### can nglyphs != 1 happen at all? Not currently I think - glyph_metrics_t gi = engine->boundingBox(glyphs.glyphs[0]); - return qRound(gi.xoff - gi.x - gi.width); + qreal rb; + engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb); + return qRound(rb); } /*! @@ -1317,8 +1319,9 @@ qreal QFontMetricsF::leftBearing(QChar ch) const int nglyphs = 9; engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); // ### can nglyphs != 1 happen at all? Not currently I think - glyph_metrics_t gi = engine->boundingBox(glyphs.glyphs[0]); - return gi.x.toReal(); + qreal lb; + engine->getGlyphBearings(glyphs.glyphs[0], &lb); + return lb; } /*! @@ -1351,8 +1354,10 @@ qreal QFontMetricsF::rightBearing(QChar ch) const int nglyphs = 9; engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0); // ### can nglyphs != 1 happen at all? Not currently I think - glyph_metrics_t gi = engine->boundingBox(glyphs.glyphs[0]); - return (gi.xoff - gi.x - gi.width).toReal(); + qreal rb; + engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb); + return rb; + } /*! diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index d685cd9..5f31ef0 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,55 @@ 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; + QColor color = p->pen().color(); + document.setDefaultStyleSheet(QString::fromLatin1("body { color: #%1%2%3 }") + .arg(QString::number(color.red(), 16), 2, QLatin1Char('0')) + .arg(QString::number(color.green(), 16), 2, QLatin1Char('0')) + .arg(QString::number(color.blue(), 16), 2, QLatin1Char('0'))); 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 +648,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/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 2fc5d1a..312d135 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1702,9 +1702,9 @@ namespace { if (currentPosition <= 0) return; - glyph_metrics_t gi = fontEngine->boundingBox(currentGlyph()); - if (gi.isValid()) - rightBearing = qMin(QFixed(), gi.xoff - gi.x - gi.width); + qreal rb; + fontEngine->getGlyphBearings(currentGlyph(), 0, &rb); + rightBearing = qMin(QFixed(), QFixed::fromReal(rb)); } inline void resetRightBearing() |