say goodbye to negative font bounds

This commit is contained in:
Ivailo Monev 2022-01-06 04:06:35 +02:00
parent 1a98081e34
commit 56e3d126d0
6 changed files with 23 additions and 97 deletions

View file

@ -192,7 +192,7 @@ QWhatsThat::QWhatsThat(const QString& txt, QWidget* parent, QWidget *showTextFor
else if (sw > 300)
sw = 300;
r = fontMetrics().boundingRect(0, 0, sw, 1000,
r = fontMetrics().boundingRect(QRect(0, 0, sw, 1000),
Qt::AlignLeft + Qt::AlignTop
+ Qt::TextWordWrap,
text);

View file

@ -437,7 +437,7 @@ QRect QStyle::itemTextRect(const QFontMetrics &metrics, const QRect &rect, int a
const QString &text) const
{
if (!text.isEmpty()) {
QRect result = metrics.boundingRect(rect.x(), rect.y(), rect.width(), rect.height(), alignment, text);
QRect result = metrics.boundingRect(rect, alignment, text);
if (!enabled && proxy()->styleHint(SH_EtchDisabledText)) {
result.setWidth(result.width()+1);
result.setHeight(result.height()+1);

View file

@ -110,16 +110,6 @@ extern void qt_format_text(const QFont& font, const QRectF &_r,
\sa QFont, QFontInfo, QFontDatabase, QFontComboBox, {Character Map Example}
*/
/*!
\fn QRect QFontMetrics::boundingRect(int x, int y, int width, int height,
int flags, const QString &text) const
\overload
Returns the bounding rectangle for the given \a text within the
rectangle specified by the \a x and \a y coordinates, \a width, and
\a height.
*/
/*!
Constructs a font metrics object for \a font.
@ -477,9 +467,8 @@ int QFontMetrics::width(QChar ch) const
specified by \a text. The bounding rectangle always covers at least
the set of pixels the text would cover if drawn at (0, 0).
Note that the bounding rectangle may extend to the left of (0, 0),
e.g. for italicized fonts, and that the width of the returned
rectangle might be different than what the width() method returns.
Note that the width of the returned rectangle might be different
than what the width() method returns.
If you want to know the advance width of the string (to layout
a set of strings next to each other), use width() instead.
@ -497,40 +486,11 @@ QRect QFontMetrics::boundingRect(const QString &text) const
if (text.isEmpty())
return QRect();
QTextEngine layout(text, d.data());
layout.itemize();
glyph_metrics_t gm = layout.boundingBox();
return QRect(qRound(gm.x), qRound(gm.y), qRound(gm.width), qRound(gm.height));
}
/*!
Returns the rectangle that is covered by ink if character \a ch
were to be drawn at the origin of the coordinate system.
Note that the bounding rectangle may extend to the left of (0, 0)
(e.g., for italicized fonts), and that the text output may cover \e
all pixels in the bounding rectangle. For a space character the rectangle
will usually be empty.
Note that the rectangle usually extends both above and below the
base line.
\warning The width of the returned rectangle is not the advance width
of the character. Use boundingRect(const QString &) or width() instead.
\sa width()
*/
QRect QFontMetrics::boundingRect(QChar ch) const
{
const QUnicodeTables::Script script = QUnicodeTables::script(ch.unicode());
QFontEngine *engine = d->engineForScript(script);
Q_ASSERT(engine != 0);
QGlyphLayoutArray<10> glyphs;
int nglyphs = 9;
engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]);
return QRect(qRound(gm.x), qRound(gm.y), qRound(gm.width), qRound(gm.height));
QTextLayout textlayout(text, d.data());
textlayout.beginLayout();
QTEXTLAYOUT(textlayout)
textlayout.endLayout();
return textlayout.boundingRect().toRect();
}
/*!
@ -564,9 +524,8 @@ QRect QFontMetrics::boundingRect(QChar ch) const
If several of the horizontal or several of the vertical alignment
flags are set, the resulting alignment is undefined.
Note that the bounding rectangle may extend to the left of (0, 0),
e.g. for italicized fonts, and that the text output may cover \e
all pixels in the bounding rectangle.
Note that the text output may cover \e all pixels in the bounding
rectangle.
Newline characters are processed as linebreaks.
@ -1119,9 +1078,8 @@ qreal QFontMetricsF::width(QChar ch) const
specified by \a text. The bounding rectangle always covers at least
the set of pixels the text would cover if drawn at (0, 0).
Note that the bounding rectangle may extend to the left of (0, 0),
e.g. for italicized fonts, and that the width of the returned
rectangle might be different than what the width() method returns.
Note that the width of the returned rectangle might be different
than what the width() method returns.
If you want to know the advance width of the string (to layout
a set of strings next to each other), use width() instead.
@ -1139,36 +1097,11 @@ QRectF QFontMetricsF::boundingRect(const QString &text) const
if (text.isEmpty())
return QRectF();
QTextEngine layout(text, d.data());
layout.itemize();
glyph_metrics_t gm = layout.boundingBox();
return QRectF(gm.x.toReal(), gm.y.toReal(), gm.width.toReal(), gm.height.toReal());
}
/*!
Returns the bounding rectangle of the character \a ch relative to
the left-most point on the base line.
Note that the bounding rectangle may extend to the left of (0, 0),
e.g. for italicized fonts, and that the text output may cover \e
all pixels in the bounding rectangle.
Note that the rectangle usually extends both above and below the
base line.
\sa width()
*/
QRectF QFontMetricsF::boundingRect(QChar ch) const
{
const QUnicodeTables::Script script = QUnicodeTables::script(ch.unicode());
QFontEngine *engine = d->engineForScript(script);
Q_ASSERT(engine != 0);
QGlyphLayoutArray<10> glyphs;
int nglyphs = 9;
engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]);
return QRectF(gm.x.toReal(), gm.y.toReal(), gm.width.toReal(), gm.height.toReal());
QTextLayout textlayout(text, d.data());
textlayout.beginLayout();
QTEXTLAYOUT(textlayout)
textlayout.endLayout();
return textlayout.boundingRect();
}
/*!
@ -1203,9 +1136,6 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const
These flags are defined in \l{Qt::AlignmentFlag}.
Note that the bounding rectangle may extend to the left of (0, 0),
e.g. for italicized fonts.
Newline characters are processed as line breaks.
Despite the different actual character heights, the heights of the

View file

@ -63,11 +63,8 @@ public:
int width(const QString &, int len = -1) const;
int width(QChar) const;
QRect boundingRect(QChar) const;
QRect boundingRect(const QString &text) const;
QRect boundingRect(const QRect &r, int flags, const QString &text) const;
inline QRect boundingRect(int x, int y, int w, int h, int flags, const QString &text) const
{ return boundingRect(QRect(x, y, w, h), flags, text); }
QSize size(int flags, const QString& str) const;
QString elidedText(const QString &text, Qt::TextElideMode mode, int width, int flags = 0) const;
@ -121,7 +118,6 @@ public:
qreal width(QChar) const;
QRectF boundingRect(const QString &string) const;
QRectF boundingRect(QChar) const;
QRectF boundingRect(const QRectF &r, int flags, const QString& string) const;
QSizeF size(int flags, const QString& str) const;

View file

@ -554,11 +554,11 @@ QSize QLabelPrivate::sizeForWidth(int w) const
else if (w < 0)
w = 2000;
w -= (hextra + contentsMargin.width());
br = fm.boundingRect(0, 0, w ,2000, flags, text);
br = fm.boundingRect(QRect(0, 0, w , 2000), flags, text);
if (tryWidth && br.height() < 4*fm.lineSpacing() && br.width() > w/2)
br = fm.boundingRect(0, 0, w/2, 2000, flags, text);
br = fm.boundingRect(QRect(0, 0, w/2, 2000), flags, text);
if (tryWidth && br.height() < 2*fm.lineSpacing() && br.width() > w/4)
br = fm.boundingRect(0, 0, w/4, 2000, flags, text);
br = fm.boundingRect(QRect(0, 0, w/4, 2000), flags, text);
}
} else {
br = QRect(QPoint(0, 0), QSize(fm.averageCharWidth(), fm.lineSpacing()));

View file

@ -156,9 +156,9 @@ void tst_QFontMetrics::boundingRect()
f.setPointSize(24);
QFontMetrics fm(f);
QRect r = fm.boundingRect(QChar('Y'));
QVERIFY(r.top() < 0);
QVERIFY(r.top() >= 0);
r = fm.boundingRect(QString("Y"));
QVERIFY(r.top() < 0);
QVERIFY(r.top() >= 0);
}
void tst_QFontMetrics::elidedText_data()