Fix vertical alignment of inline images

Inline images can have 4 different alignments. Unfortunately,
AlignTop and AlignBottom can only be set once we have laid out
the whole line and know the total height of the line, as one
could otherwise end up with lines that are too high.

To fix this, position the images for these cases in a second loop
after we have calculated the length of the line and the maximal
image height in that line.

Task-number: QTBUG-59310
Change-Id: I1fd4cd39e43a13d1967b9f5c9ce8270a99269cd9
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
bb10
Lars Knoll 2018-11-09 15:57:42 +01:00 committed by Liang Qi
parent 4d180586cd
commit 199f9c5448
2 changed files with 63 additions and 15 deletions

View File

@ -3049,18 +3049,12 @@ void QTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int posInDo
QSizeF inlineSize = (pos == QTextFrameFormat::InFlow ? intrinsic : QSizeF(0, 0));
item.setWidth(inlineSize.width());
QFontMetrics m(f.font());
switch (f.verticalAlignment())
{
case QTextCharFormat::AlignMiddle:
item.setDescent(inlineSize.height() / 2);
item.setAscent(inlineSize.height() / 2);
break;
case QTextCharFormat::AlignBaseline:
item.setDescent(m.descent());
item.setAscent(inlineSize.height() - m.descent());
break;
default:
if (f.verticalAlignment() == QTextCharFormat::AlignMiddle) {
QFontMetrics m(f.font());
qreal halfX = m.xHeight()/2.;
item.setAscent((inlineSize.height() + halfX) / 2.);
item.setDescent((inlineSize.height() - halfX) / 2.);
} else {
item.setDescent(0);
item.setAscent(inlineSize.height());
}

View File

@ -1823,6 +1823,9 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.logClusters = eng->layoutData->logClustersPtr;
lbh.previousGlyph = 0;
bool hasInlineObject = false;
QFixed maxInlineObjectHeight = 0;
while (newItem < eng->layoutData->items.size()) {
lbh.resetRightBearing();
lbh.softHyphenWidth = 0;
@ -1851,8 +1854,11 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent,
current.leading + current.ascent) - qMax(lbh.tmpData.ascent,
current.ascent);
lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent);
lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent);
if (current.analysis.flags != QScriptAnalysis::Object) {
// objects need some special treatment as they can special alignment or be floating
lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent);
lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent);
}
if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) {
lbh.whiteSpaceOrObject = true;
@ -1900,9 +1906,18 @@ void QTextLine::layout_helper(int maxGlyphs)
if (eng->block.docHandle()) {
QTextInlineObject inlineObject(item, eng);
eng->docLayout()->positionInlineObject(inlineObject, eng->block.position() + current.position, inlineObject.format());
QTextFormat f = inlineObject.format();
eng->docLayout()->positionInlineObject(inlineObject, eng->block.position() + current.position, f);
QTextCharFormat::VerticalAlignment valign = f.toCharFormat().verticalAlignment();
if (valign != QTextCharFormat::AlignTop && valign != QTextCharFormat::AlignBottom) {
lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent);
lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent);
}
}
hasInlineObject = true;
maxInlineObjectHeight = qMax(maxInlineObjectHeight, current.ascent + current.descent);
lbh.tmpData.textWidth += current.width;
newItem = item + 1;
@ -2038,6 +2053,43 @@ found:
line += lbh.tmpData;
}
if (hasInlineObject && eng->block.docHandle()) {
// position top/bottom aligned inline objects
if (maxInlineObjectHeight > line.ascent + line.descent) {
// extend line height if required
QFixed toAdd = (maxInlineObjectHeight - line.ascent - line.descent)/2;
line.ascent += toAdd;
line.descent = maxInlineObjectHeight - line.ascent;
}
int startItem = eng->findItem(line.from);
int endItem = eng->findItem(line.from + line.length);
if (endItem < 0)
endItem = eng->layoutData->items.size();
for (int item = startItem; item < endItem; ++item) {
QScriptItem &current = eng->layoutData->items[item];
if (current.analysis.flags == QScriptAnalysis::Object) {
QTextInlineObject inlineObject(item, eng);
QTextCharFormat::VerticalAlignment align = inlineObject.format().toCharFormat().verticalAlignment();
QFixed height = current.ascent + current.descent;
switch (align) {
case QTextCharFormat::AlignTop:
current.ascent = line.ascent;
current.descent = height - line.ascent;
break;
case QTextCharFormat::AlignBottom:
current.descent = line.descent;
current.ascent = height - line.descent;
break;
default:
break;
}
Q_ASSERT(line.ascent >= current.ascent);
Q_ASSERT(line.descent >= current.descent);
}
}
}
LB_DEBUG("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(),
line.descent.toReal(), line.textWidth.toReal(), lbh.spaceData.width.toReal());
LB_DEBUG(" : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data());
@ -2511,6 +2563,8 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR
QFixed itemY = y - si.ascent;
if (format.verticalAlignment() == QTextCharFormat::AlignTop) {
itemY = y - lineBase;
} else if (format.verticalAlignment() == QTextCharFormat::AlignBottom) {
itemY = y + line.descent - si.ascent - si.descent;
}
QRectF itemRect(iterator.x.toReal(), itemY.toReal(), iterator.itemWidth.toReal(), si.height().toReal());