diff options
author | Jiang Jiang <jiang.jiang@nokia.com> | 2010-08-10 13:58:25 (GMT) |
---|---|---|
committer | Jiang Jiang <jiang.jiang@nokia.com> | 2010-08-10 14:09:10 (GMT) |
commit | 99fd5825dfb4d50cff93165995701a65b7a8e4ed (patch) | |
tree | 7d2f019ae010e304d400a04da2d604ef3daaeec2 /src/gui/text | |
parent | dd2a5c1556cf29fac03ae789dd5c43f482011d68 (diff) | |
download | Qt-99fd5825dfb4d50cff93165995701a65b7a8e4ed.zip Qt-99fd5825dfb4d50cff93165995701a65b7a8e4ed.tar.gz Qt-99fd5825dfb4d50cff93165995701a65b7a8e4ed.tar.bz2 |
Make selection work across ligatures
For widgets like QPlainTextEdit, selection across ligatures (typically
'fi', 'ffi', 'fl', etc.) end up highlighting the entire ligature
glyphs, this patch fixed that by dividing width inside the ligature so
that selection will not expand past the actual selected characters.
Since cursor position already considered this, we merely adopted the
algorithm and made it a separated helper function for all necessary
cases. Dividing width directly looks like a temporary workaround but
works well enough so far for cursor positions.
Task-number: QTBUG-11969
Reviewed-by: Eskil
Diffstat (limited to 'src/gui/text')
-rw-r--r-- | src/gui/text/qtextlayout.cpp | 64 |
1 files changed, 43 insertions, 21 deletions
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 531e46b..9d27343 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1035,6 +1035,35 @@ QScriptItem &QTextLineItemIterator::next() return *si; } +static QFixed offsetInLigature(const unsigned short *logClusters, + const QGlyphLayout &glyphs, + int pos, int max, int glyph_pos) +{ + int offsetInCluster = 0; + for (int i = pos - 1; i >= 0; i--) { + if (logClusters[i] == glyph_pos) + offsetInCluster++; + else + break; + } + + // in the case that the offset is inside a (multi-character) glyph, + // interpolate the position. + if (offsetInCluster > 0) { + int clusterLength = 0; + for (int i = pos - offsetInCluster; i < max; i++) { + if (logClusters[i] == glyph_pos) + clusterLength++; + else + break; + } + if (clusterLength) + return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength; + } + + return 0; +} + bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const { *selectionX = *selectionWidth = 0; @@ -1074,8 +1103,19 @@ bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selec swidth += glyphs.effectiveAdvance(g); } - *selectionX = x + soff; - *selectionWidth = swidth; + // If the starting character is in the middle of a ligature, + // selection should only contain the right part of that ligature + // glyph, so we need to get the width of the left part here and + // add it to *selectionX + QFixed leftOffsetInLigature = offsetInLigature(logClusters, glyphs, from, + to, start_glyph); + *selectionX = x + soff + leftOffsetInLigature; + *selectionWidth = swidth - leftOffsetInLigature; + // If the ending character is also part of a ligature, swidth does + // not contain that part yet, we also need to find out the width of + // that left part + *selectionWidth += offsetInLigature(logClusters, glyphs, to, + eng->length(item), end_glyph); } return true; } @@ -2633,14 +2673,6 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const if(pos == l) x += si->width; } else { - int offsetInCluster = 0; - for (int i=pos-1; i >= 0; i--) { - if (logClusters[i] == glyph_pos) - offsetInCluster++; - else - break; - } - if (reverse) { int end = qMin(lineEnd, si->position + l) - si->position; int glyph_end = end == l ? si->num_glyphs : logClusters[end]; @@ -2652,17 +2684,7 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const for (int i = glyph_start; i < glyph_pos; i++) x += glyphs.effectiveAdvance(i); } - if (offsetInCluster > 0) { // in the case that the offset is inside a (multi-character) glyph, interpolate the position. - int clusterLength = 0; - for (int i=pos - offsetInCluster; i < line.length; i++) { - if (logClusters[i] == glyph_pos) - clusterLength++; - else - break; - } - if (clusterLength) - x+= glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength; - } + x += offsetInLigature(logClusters, glyphs, pos, line.length, glyph_pos); } *cursorPos = pos + si->position; |