From 199f9c54484b0dae3bc81f83c880a965192ecb24 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 9 Nov 2018 15:57:42 +0100 Subject: 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 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qtextdocumentlayout.cpp | 18 ++++------- src/gui/text/qtextlayout.cpp | 60 ++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index a9227f0171..9aeea44dd3 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -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()); } diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index ca6866d836..be306ed224 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -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 ¤t = 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()); -- cgit v1.2.3