Fix clipped text when combining multiple writing systems
When a QTextLine consists of multiple different scripts and the fonts had negative bearing, the background for a script item could overdraw the previous item's text, causing it to look clipped. This was because the background and text was drawn in a single pass, and moving the background drawing into its own pre-pass fixes the issue. [ChangeLog][QtGui] Fixed an issue where drawing text from different writing systems in the same line and including a background could cause parts of the text to be clipped. Pick-to: 6.5 Fixes: QTBUG-121040 Change-Id: I3f79e6d33c09a2a92853bc8752dbe11a0bea2dd0 Reviewed-by: Lars Knoll <lars@knoll.priv.no> (cherry picked from commit 8be3c9f4867ce7982387b075739b8f55c5c45753) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 55b2011bcd3cfd93baf9db1a03a6672220c26413)
This commit is contained in:
parent
7de26479e1
commit
c64fb06afa
@ -2232,20 +2232,20 @@ int QTextLine::textLength() const
|
||||
return eng->lines.at(index).length + eng->lines.at(index).trailingSpaces;
|
||||
}
|
||||
|
||||
static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r)
|
||||
static void drawBackground(QPainter *p, const QTextCharFormat &chf, const QRectF &r)
|
||||
{
|
||||
QBrush c = chf.foreground();
|
||||
if (c.style() == Qt::NoBrush) {
|
||||
p->setPen(defaultPen);
|
||||
}
|
||||
|
||||
QBrush bg = chf.background();
|
||||
if (bg.style() != Qt::NoBrush && !chf.property(SuppressBackground).toBool())
|
||||
p->fillRect(r.toAlignedRect(), bg);
|
||||
if (c.style() != Qt::NoBrush) {
|
||||
p->setPen(QPen(c, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void setPen(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf)
|
||||
{
|
||||
QBrush c = chf.foreground();
|
||||
if (c.style() == Qt::NoBrush)
|
||||
p->setPen(defaultPen);
|
||||
else
|
||||
p->setPen(QPen(c, 0));
|
||||
}
|
||||
|
||||
#if !defined(QT_NO_RAWFONT)
|
||||
@ -2640,7 +2640,6 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
|
||||
Q_ASSERT(!eng->useRawFont);
|
||||
#endif
|
||||
const QScriptLine &line = eng->lines[index];
|
||||
QPen pen = p->pen();
|
||||
|
||||
bool noText = (selection && selection->format.property(SuppressText).toBool());
|
||||
|
||||
@ -2652,8 +2651,7 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
|
||||
const qreal lineHeight = line.height().toReal();
|
||||
QRectF r(origPos.x() + line.x.toReal(), origPos.y() + line.y.toReal(),
|
||||
lineHeight / 2, QFontMetrics(eng->font()).horizontalAdvance(u' '));
|
||||
setPenAndDrawBackground(p, QPen(), selection->format, r);
|
||||
p->setPen(pen);
|
||||
drawBackground(p, selection->format, r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -2666,7 +2664,7 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
|
||||
else
|
||||
p->translate(origPos);
|
||||
|
||||
QTextLineItemIterator iterator(eng, index, pos, selection);
|
||||
|
||||
QFixed lineBase = line.base();
|
||||
eng->clearDecorations();
|
||||
eng->enableDelayDecorations();
|
||||
@ -2676,6 +2674,39 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
|
||||
const QTextFormatCollection *formatCollection = eng->formatCollection();
|
||||
|
||||
bool suppressColors = (eng->option.flags() & QTextOption::SuppressColors);
|
||||
|
||||
auto prepareFormat = [suppressColors, selection, this](QTextCharFormat &format,
|
||||
QScriptItem *si) {
|
||||
format.merge(eng->format(si));
|
||||
|
||||
if (suppressColors) {
|
||||
format.clearForeground();
|
||||
format.clearBackground();
|
||||
format.clearProperty(QTextFormat::TextUnderlineColor);
|
||||
}
|
||||
if (selection)
|
||||
format.merge(selection->format);
|
||||
};
|
||||
|
||||
{
|
||||
QTextLineItemIterator iterator(eng, index, pos, selection);
|
||||
while (!iterator.atEnd()) {
|
||||
QScriptItem &si = iterator.next();
|
||||
|
||||
if (eng->hasFormats() || selection || formatCollection) {
|
||||
QTextCharFormat format;
|
||||
if (formatCollection != nullptr)
|
||||
format = formatCollection->defaultTextFormat();
|
||||
prepareFormat(format, &si);
|
||||
drawBackground(p, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(),
|
||||
iterator.itemWidth.toReal(), line.height().toReal()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPen pen = p->pen();
|
||||
{
|
||||
QTextLineItemIterator iterator(eng, index, pos, selection);
|
||||
while (!iterator.atEnd()) {
|
||||
QScriptItem &si = iterator.next();
|
||||
|
||||
@ -2693,18 +2724,8 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
|
||||
format = formatCollection->defaultTextFormat();
|
||||
|
||||
if (eng->hasFormats() || selection || formatCollection) {
|
||||
format.merge(eng->format(&si));
|
||||
|
||||
if (suppressColors) {
|
||||
format.clearForeground();
|
||||
format.clearBackground();
|
||||
format.clearProperty(QTextFormat::TextUnderlineColor);
|
||||
}
|
||||
if (selection)
|
||||
format.merge(selection->format);
|
||||
|
||||
setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(),
|
||||
iterator.itemWidth.toReal(), line.height().toReal()));
|
||||
prepareFormat(format, &si);
|
||||
setPen(p, pen, format);
|
||||
|
||||
const qreal baseLineOffset = format.baselineOffset() / 100.0;
|
||||
QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
|
||||
@ -2855,6 +2876,7 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
|
||||
p->setFont(oldFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
eng->drawDecorations(p);
|
||||
|
||||
if (xlateToFixedRange)
|
||||
|
@ -17,6 +17,7 @@ public:
|
||||
private slots:
|
||||
void tst_render_data();
|
||||
void tst_render();
|
||||
void tst_differentScriptsBackgrounds();
|
||||
|
||||
private:
|
||||
QDir htmlDir;
|
||||
@ -81,6 +82,26 @@ void tst_Text::tst_render()
|
||||
QBASELINE_TEST(image);
|
||||
}
|
||||
|
||||
void tst_Text::tst_differentScriptsBackgrounds()
|
||||
{
|
||||
QTextDocument textDocument;
|
||||
textDocument.setPageSize(QSizeF(800, 600));
|
||||
textDocument.setHtml(QString::fromUtf8("<i><font style=\"font-size:72px\"><font style=\"background:#FFFF00\">イ雨エ</font></font></i>"));
|
||||
|
||||
QImage image(800, 600, QImage::Format_ARGB32);
|
||||
image.fill(Qt::white);
|
||||
|
||||
{
|
||||
QPainter painter(&image);
|
||||
|
||||
QAbstractTextDocumentLayout::PaintContext context;
|
||||
context.palette.setColor(QPalette::Text, Qt::black);
|
||||
textDocument.documentLayout()->draw(&painter, context);
|
||||
}
|
||||
|
||||
QBASELINE_CHECK(image, "tst_differentScriptsBackgrounds");
|
||||
}
|
||||
|
||||
|
||||
#define main _realmain
|
||||
QTEST_MAIN(tst_Text)
|
||||
|
Loading…
x
Reference in New Issue
Block a user