Improve readability of QTextLine's handling of (negative) right bearing

- Helper functions in LineBreakHelper have been renamed from
    adjustFoo to calculateFoo, to signal that they do work, and
    are not adjusting something relative to something else.

  - The use of QFixed(1) and >= 0 has been replaced with an explicit
    constant for the case of the bearing not being calculated yet.

  - A helper function negativeRightBearing() has been added that
    returns the absolute value of any negative right bearing, making
    the width computations simpler.

  - Comments have been added and rewritten to make the logic clearer.

Change-Id: I1d3a0214cfa8b4fed4551f3444b43a37d55bd69b
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@theqtcompany.com>
This commit is contained in:
Tor Arne Vestbø 2015-08-07 15:37:07 +02:00
parent d7b847112a
commit e92c2e119b

View File

@ -1605,8 +1605,8 @@ namespace {
bool checkFullOtherwiseExtend(QScriptLine &line); bool checkFullOtherwiseExtend(QScriptLine &line);
QFixed calculateNewWidth(const QScriptLine &line) const { QFixed calculateNewWidth(const QScriptLine &line) const {
return line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth return line.textWidth + tmpData.textWidth + spaceData.textWidth
- qMin(rightBearing, QFixed()); + softHyphenWidth + negativeRightBearing();
} }
inline glyph_t currentGlyph() const inline glyph_t currentGlyph() const
@ -1626,33 +1626,51 @@ namespace {
} }
} }
inline void adjustRightBearing(glyph_t glyph) inline void calculateRightBearing(glyph_t glyph)
{ {
qreal rb; qreal rb;
fontEngine->getGlyphBearings(glyph, 0, &rb); fontEngine->getGlyphBearings(glyph, 0, &rb);
rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
// We only care about negative right bearings, so we limit the range
// of the bearing here so that we can assume it's negative in the rest
// of the code, as well ase use QFixed(1) as a sentinel to represent
// the state where we have yet to compute the right bearing.
rightBearing = qMin(QFixed::fromReal(rb), QFixed(0));
} }
inline void adjustRightBearing() inline void calculateRightBearing()
{ {
if (currentPosition <= 0) if (currentPosition <= 0)
return; return;
adjustRightBearing(currentGlyph()); calculateRightBearing(currentGlyph());
} }
inline void adjustPreviousRightBearing() inline void calculateRightBearingForPreviousGlyph()
{ {
if (previousGlyph > 0) if (previousGlyph > 0)
adjustRightBearing(previousGlyph); calculateRightBearing(previousGlyph);
} }
static const QFixed RightBearingNotCalculated;
inline void resetRightBearing() inline void resetRightBearing()
{ {
rightBearing = QFixed(1); // Any positive number is defined as invalid since only rightBearing = RightBearingNotCalculated;
// negative right bearings are interesting to us. }
// We express the negative right bearing as an absolute number
// so that it can be applied to the width using addition.
inline QFixed negativeRightBearing() const
{
if (rightBearing == RightBearingNotCalculated)
return QFixed(0);
return qAbs(rightBearing);
} }
}; };
const QFixed LineBreakHelper::RightBearingNotCalculated = QFixed(1);
inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line) inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
{ {
LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal()); LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
@ -1805,7 +1823,7 @@ void QTextLine::layout_helper(int maxGlyphs)
current, lbh.logClusters, lbh.glyphs); current, lbh.logClusters, lbh.glyphs);
} else { } else {
lbh.tmpData.length++; lbh.tmpData.length++;
lbh.adjustPreviousRightBearing(); lbh.calculateRightBearingForPreviousGlyph();
} }
line += lbh.tmpData; line += lbh.tmpData;
goto found; goto found;
@ -1887,22 +1905,29 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.tmpData.textWidth += lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; lbh.tmpData.textWidth += lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]];
} }
// The actual width of the text needs to take the right bearing into account. The if (sb_or_ws|breakany) {
// right bearing is left-ward, which means that if the rightmost pixel is to the right // To compute the final width of the text we need to take negative right bearing
// of the advance of the glyph, the bearing will be negative. We flip the sign // into account (negative right bearing means the glyph has pixel data past the
// for the code to be more readable. Logic borrowed from qfontmetrics.cpp. // advance length). Note that the negative right bearing is an absolute number,
// so that we can apply it to the width using straight forward addition.
// Store previous right bearing (for the already accepted glyph) in case we
// end up breaking due to the current glyph being too wide.
QFixed previousRightBearing = lbh.rightBearing;
// We ignore the right bearing if the minimum negative bearing is too little to // We ignore the right bearing if the minimum negative bearing is too little to
// expand the text beyond the edge. // expand the text beyond the edge.
if (sb_or_ws|breakany) {
QFixed rightBearing = lbh.rightBearing; // store previous right bearing
if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width) if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
lbh.adjustRightBearing(); lbh.calculateRightBearing();
if (lbh.checkFullOtherwiseExtend(line)) { if (lbh.checkFullOtherwiseExtend(line)) {
// we are too wide, fix right bearing // We are too wide to accept the next glyph with its bearing, so we restore the
if (rightBearing <= 0) // right bearing to that of the previous glyph (the one that was already accepted),
lbh.rightBearing = rightBearing; // take from cache // so that the bearing can be be applied to the final width of the text below.
if (previousRightBearing != LineBreakHelper::RightBearingNotCalculated)
lbh.rightBearing = previousRightBearing;
else else
lbh.adjustPreviousRightBearing(); lbh.calculateRightBearingForPreviousGlyph();
if (!breakany) { if (!breakany) {
line.textWidth += lbh.softHyphenWidth; line.textWidth += lbh.softHyphenWidth;
@ -1919,10 +1944,14 @@ void QTextLine::layout_helper(int maxGlyphs)
LB_DEBUG("reached end of line"); LB_DEBUG("reached end of line");
lbh.checkFullOtherwiseExtend(line); lbh.checkFullOtherwiseExtend(line);
found: found:
if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
lbh.adjustRightBearing();
line.textAdvance = line.textWidth; line.textAdvance = line.textWidth;
line.textWidth -= qMin(QFixed(), lbh.rightBearing);
// If right bearing has not been calculated yet, do that now
if (lbh.rightBearing == LineBreakHelper::RightBearingNotCalculated && !lbh.whiteSpaceOrObject)
lbh.calculateRightBearing();
// Then apply any negative right bearing
line.textWidth += lbh.negativeRightBearing();
if (line.length == 0) { if (line.length == 0) {
LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f", LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f",