summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/text/qtextengine.cpp69
-rw-r--r--src/gui/text/qtextengine_p.h3
-rw-r--r--src/gui/text/qtextlayout.cpp16
3 files changed, 81 insertions, 7 deletions
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 806779a..9271f34 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -2697,6 +2697,75 @@ QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line)
return width(line.from + pos, line.length - pos);
}
+// Scan in logClusters[from..to-1] for glyph_pos
+int QTextEngine::getClusterLength(unsigned short *logClusters,
+ const HB_CharAttributes *attributes,
+ int from, int to, int glyph_pos, int *start)
+{
+ int clusterLength = 0;
+ for (int i = from; i < to; i++) {
+ if (logClusters[i] == glyph_pos && attributes[i].charStop) {
+ if (*start < 0)
+ *start = i;
+ clusterLength++;
+ }
+ else if (clusterLength)
+ break;
+ }
+ return clusterLength;
+}
+
+int QTextEngine::positionInLigature(const QScriptItem *si, int end,
+ QFixed x, QFixed edge, int glyph_pos,
+ bool cursorOnCharacter)
+{
+ unsigned short *logClusters = this->logClusters(si);
+ int clusterStart = -1;
+ int clusterLength = 0;
+
+ if (si->analysis.script != QUnicodeTables::Common &&
+ si->analysis.script != QUnicodeTables::Greek) {
+ if (glyph_pos == -1)
+ return si->position + end;
+ else {
+ int i;
+ for (i = 0; i < end; i++)
+ if (logClusters[i] == glyph_pos)
+ break;
+ return si->position + i;
+ }
+ }
+
+ if (glyph_pos == -1 && end > 0)
+ glyph_pos = logClusters[end - 1];
+ else {
+ if (x <= edge)
+ glyph_pos--;
+ }
+
+ const HB_CharAttributes *attrs = attributes();
+ clusterLength = getClusterLength(logClusters, attrs, 0, end, glyph_pos, &clusterStart);
+
+ if (clusterLength) {
+ const QGlyphLayout &glyphs = shapedGlyphs(si);
+ QFixed glyphWidth = glyphs.effectiveAdvance(glyph_pos);
+ // the approximate width of each individual element of the ligature
+ QFixed perItemWidth = glyphWidth / clusterLength;
+ QFixed left = x > edge ? edge : edge - glyphWidth;
+ int n = ((x - left) / perItemWidth).floor().toInt();
+ QFixed dist = x - left - n * perItemWidth;
+ int closestItem = dist > (perItemWidth / 2) ? n + 1 : n;
+ if (cursorOnCharacter && closestItem > 0)
+ closestItem--;
+ int pos = si->position + clusterStart + closestItem;
+ // Jump to the next charStop
+ while (!attrs[pos].charStop && pos < end)
+ pos++;
+ return pos;
+ }
+ return si->position + end;
+}
+
QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f)
: QTextEngine(string, f),
_layoutData(string, _memory, MemSize)
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index 5e33f21..09610ff 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -594,6 +594,8 @@ public:
void shapeLine(const QScriptLine &line);
QFixed leadingSpaceWidth(const QScriptLine &line);
+ int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter);
+
private:
void setBoundary(int strPos) const;
void addRequiredBoundaries() const;
@@ -608,6 +610,7 @@ private:
void splitItem(int item, int pos) const;
void resolveAdditionalFormats() const;
+ int getClusterLength(unsigned short *logClusters, const HB_CharAttributes *attributes, int from, int to, int glyph_pos, int *start);
};
class QStackTextEngine : public QTextEngine {
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index de4ca4f..4b3c9e7 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -2622,6 +2622,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
}
int glyph_pos = -1;
+ QFixed edge;
// has to be inside run
if (cpos == QTextLine::CursorOnCharacter) {
if (si.analysis.bidiLevel % 2) {
@@ -2632,6 +2633,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
if (pos < x)
break;
glyph_pos = gs;
+ edge = pos;
break;
}
pos -= glyphs.effectiveAdvance(gs);
@@ -2644,6 +2646,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
if (pos > x)
break;
glyph_pos = gs;
+ edge = pos;
}
pos += glyphs.effectiveAdvance(gs);
++gs;
@@ -2656,6 +2659,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
while (gs <= ge) {
if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
glyph_pos = gs;
+ edge = pos;
dist = qAbs(x-pos);
}
pos -= glyphs.effectiveAdvance(gs);
@@ -2665,6 +2669,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
while (gs <= ge) {
if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
glyph_pos = gs;
+ edge = pos;
dist = qAbs(x-pos);
}
pos += glyphs.effectiveAdvance(gs);
@@ -2672,15 +2677,12 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
}
}
if (qAbs(x-pos) < dist)
- return si.position + end;
+ return eng->positionInLigature(&si, end, x, pos, -1,
+ cpos == QTextLine::CursorOnCharacter);
}
Q_ASSERT(glyph_pos != -1);
- int j;
- for (j = 0; j < eng->length(item); ++j)
- if (logClusters[j] == glyph_pos)
- break;
-// qDebug("at pos %d (in run: %d)", si.position + j, j);
- return si.position + j;
+ return eng->positionInLigature(&si, end, x, edge, glyph_pos,
+ cpos == QTextLine::CursorOnCharacter);
}
}
// right of last item