mirror of
https://bitbucket.org/smil3y/katie.git
synced 2025-02-25 03:12:56 +00:00
drop BiDi support
still wonky on selection: https://ibb.co/D4bWVqX Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
57dbb8d1cd
commit
a699a16de9
7 changed files with 54 additions and 389 deletions
|
@ -4789,17 +4789,11 @@ void QPainter::drawText(const QPointF &p, const QString &str)
|
||||||
engine.shapeLine(line);
|
engine.shapeLine(line);
|
||||||
|
|
||||||
int nItems = engine.layoutData->items.size();
|
int nItems = engine.layoutData->items.size();
|
||||||
QVarLengthArray<int> visualOrder(nItems);
|
|
||||||
QVarLengthArray<uchar> levels(nItems);
|
|
||||||
for (int i = 0; i < nItems; ++i)
|
|
||||||
levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
|
|
||||||
QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
|
|
||||||
|
|
||||||
QFixed x = QFixed::fromReal(p.x());
|
QFixed x = QFixed::fromReal(p.x());
|
||||||
|
|
||||||
for (int i = 0; i < nItems; ++i) {
|
for (int i = 0; i < nItems; ++i) {
|
||||||
int item = visualOrder[i];
|
const QScriptItem &si = engine.layoutData->items.at(i);
|
||||||
const QScriptItem &si = engine.layoutData->items.at(item);
|
|
||||||
if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
|
if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
|
||||||
x += si.width;
|
x += si.width;
|
||||||
continue;
|
continue;
|
||||||
|
@ -4808,7 +4802,7 @@ void QPainter::drawText(const QPointF &p, const QString &str)
|
||||||
QTextItemInt gf(si, &f);
|
QTextItemInt gf(si, &f);
|
||||||
gf.glyphs = engine.shapedGlyphs(&si);
|
gf.glyphs = engine.shapedGlyphs(&si);
|
||||||
gf.chars = engine.layoutData->string.unicode() + si.position;
|
gf.chars = engine.layoutData->string.unicode() + si.position;
|
||||||
gf.num_chars = engine.length(item);
|
gf.num_chars = engine.length(i);
|
||||||
if (engine.forceJustification) {
|
if (engine.forceJustification) {
|
||||||
for (int j=0; j<gf.glyphs.numGlyphs; ++j)
|
for (int j=0; j<gf.glyphs.numGlyphs; ++j)
|
||||||
gf.width += gf.glyphs.effectiveAdvance(j);
|
gf.width += gf.glyphs.effectiveAdvance(j);
|
||||||
|
@ -6379,9 +6373,7 @@ start_lengthVariant:
|
||||||
qreal advance = line.horizontalAdvance();
|
qreal advance = line.horizontalAdvance();
|
||||||
xoff = 0;
|
xoff = 0;
|
||||||
if (tf & Qt::AlignRight) {
|
if (tf & Qt::AlignRight) {
|
||||||
QTextEngine *eng = textLayout.engine();
|
xoff = r.width() - advance;
|
||||||
xoff = r.width() - advance -
|
|
||||||
eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal();
|
|
||||||
}
|
}
|
||||||
else if (tf & Qt::AlignHCenter)
|
else if (tf & Qt::AlignHCenter)
|
||||||
xoff = (r.width() - advance) / 2;
|
xoff = (r.width() - advance) / 2;
|
||||||
|
|
|
@ -1104,24 +1104,14 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &
|
||||||
qreal x(point.x());
|
qreal x(point.x());
|
||||||
qreal y(point.y());
|
qreal y(point.y());
|
||||||
|
|
||||||
QVarLengthArray<int> visualOrder(nItems);
|
|
||||||
QVarLengthArray<uchar> levels(nItems);
|
|
||||||
for (int i = 0; i < nItems; ++i)
|
|
||||||
levels[i] = eng->layoutData->items[i].analysis.bidiLevel;
|
|
||||||
QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
|
|
||||||
|
|
||||||
for (int i = 0; i < nItems; ++i) {
|
for (int i = 0; i < nItems; ++i) {
|
||||||
int item = visualOrder[i];
|
QScriptItem &si = eng->layoutData->items[i];
|
||||||
QScriptItem &si = eng->layoutData->items[item];
|
|
||||||
|
|
||||||
if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
|
if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
|
||||||
QGlyphLayout glyphs = eng->shapedGlyphs(&si);
|
QGlyphLayout glyphs = eng->shapedGlyphs(&si);
|
||||||
QFontEngine *fe = f.d->engineForScript(si.analysis.script);
|
QFontEngine *fe = f.d->engineForScript(si.analysis.script);
|
||||||
Q_ASSERT(fe);
|
Q_ASSERT(fe);
|
||||||
fe->addOutlineToPath(x, y, glyphs, this,
|
fe->addOutlineToPath(x, y, glyphs, this, QTextItem::RenderFlags(0));
|
||||||
si.analysis.bidiLevel % 2
|
|
||||||
? QTextItem::RenderFlags(QTextItem::RightToLeft)
|
|
||||||
: QTextItem::RenderFlags(0));
|
|
||||||
|
|
||||||
const qreal lw = fe->lineThickness().toReal();
|
const qreal lw = fe->lineThickness().toReal();
|
||||||
if (f.d->underline) {
|
if (f.d->underline) {
|
||||||
|
|
|
@ -113,8 +113,6 @@ static bool qHB_ConvertStringToGlyphIndices(HB_ShaperItem *shaper_item)
|
||||||
QVarLengthGlyphLayoutArray qglyphs(shaper_item->num_glyphs);
|
QVarLengthGlyphLayoutArray qglyphs(shaper_item->num_glyphs);
|
||||||
|
|
||||||
QTextEngine::ShaperFlags shaperFlags(QTextEngine::GlyphIndicesOnly);
|
QTextEngine::ShaperFlags shaperFlags(QTextEngine::GlyphIndicesOnly);
|
||||||
if (shaper_item->item.bidiLevel % 2)
|
|
||||||
shaperFlags |= QTextEngine::RightToLeft;
|
|
||||||
|
|
||||||
int nGlyphs = shaper_item->num_glyphs;
|
int nGlyphs = shaper_item->num_glyphs;
|
||||||
bool result = fe->stringToCMap(reinterpret_cast<const QChar *>(shaper_item->string + shaper_item->item.pos),
|
bool result = fe->stringToCMap(reinterpret_cast<const QChar *>(shaper_item->string + shaper_item->item.pos),
|
||||||
|
@ -270,8 +268,6 @@ static inline void positionCluster(HB_ShaperItem *item, int gfrom, int glast)
|
||||||
//qreal offsetBase = (size - 4) / 4 + qMin<qreal>(size, 4) + 1;
|
//qreal offsetBase = (size - 4) / 4 + qMin<qreal>(size, 4) + 1;
|
||||||
// qDebug("offset = %f", offsetBase);
|
// qDebug("offset = %f", offsetBase);
|
||||||
|
|
||||||
bool rightToLeft = item->item.bidiLevel % 2;
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
unsigned char lastCmb = 0;
|
unsigned char lastCmb = 0;
|
||||||
HB_GlyphMetrics attachmentRect;
|
HB_GlyphMetrics attachmentRect;
|
||||||
|
@ -365,13 +361,8 @@ static inline void positionCluster(HB_ShaperItem *item, int gfrom, int glast)
|
||||||
attachmentRect = unitedAttachmentRect;
|
attachmentRect = unitedAttachmentRect;
|
||||||
|
|
||||||
lastCmb = cmb;
|
lastCmb = cmb;
|
||||||
if (rightToLeft) {
|
|
||||||
item->offsets[gfrom+i].x = p.x;
|
|
||||||
item->offsets[gfrom+i].y = p.y;
|
|
||||||
} else {
|
|
||||||
item->offsets[gfrom+i].x = p.x - baseMetrics.xOffset;
|
item->offsets[gfrom+i].x = p.x - baseMetrics.xOffset;
|
||||||
item->offsets[gfrom+i].y = p.y - baseMetrics.yOffset;
|
item->offsets[gfrom+i].y = p.y - baseMetrics.yOffset;
|
||||||
}
|
|
||||||
item->advances[gfrom+i] = 0;
|
item->advances[gfrom+i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,7 +400,6 @@ typedef struct {
|
||||||
uint32_t pos;
|
uint32_t pos;
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
HB_Script script;
|
HB_Script script;
|
||||||
uint8_t bidiLevel;
|
|
||||||
} HB_ScriptItem;
|
} HB_ScriptItem;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -78,8 +78,7 @@ public:
|
||||||
// the font and because Japanese and Chinese are also aliases of the script "Common",
|
// the font and because Japanese and Chinese are also aliases of the script "Common",
|
||||||
// doing this would break too many things. So instead we only pass the full stop
|
// doing this would break too many things. So instead we only pass the full stop
|
||||||
// along, and nothing else.
|
// along, and nothing else.
|
||||||
if (m_analysis[i].bidiLevel == m_analysis[start].bidiLevel
|
if (m_analysis[i].flags == m_analysis[start].flags
|
||||||
&& m_analysis[i].flags == m_analysis[start].flags
|
|
||||||
&& (m_analysis[i].script == m_analysis[start].script || m_string[i] == QLatin1Char('.'))
|
&& (m_analysis[i].script == m_analysis[start].script || m_string[i] == QLatin1Char('.'))
|
||||||
&& m_analysis[i].flags < QScriptAnalysis::SpaceTabOrObject
|
&& m_analysis[i].flags < QScriptAnalysis::SpaceTabOrObject
|
||||||
&& i - start < MaxItemLength)
|
&& i - start < MaxItemLength)
|
||||||
|
@ -99,88 +98,12 @@ private:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// The BiDi algorithm
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
#if (BIDI_DEBUG >= 1)
|
|
||||||
static const char *directions[] = {
|
|
||||||
"DirL", "DirR", "DirEN", "DirES", "DirET", "DirAN", "DirCS", "DirB", "DirS", "DirWS", "DirON",
|
|
||||||
"DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN", "DirLRI",
|
|
||||||
"DirRLI", "DirFSI", "DirPDI"
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void QTextEngine::bidiReorder(int numItems, const quint8 *levels, int *visualOrder)
|
|
||||||
{
|
|
||||||
|
|
||||||
// first find highest and lowest levels
|
|
||||||
quint8 levelLow = 128;
|
|
||||||
quint8 levelHigh = 0;
|
|
||||||
int i = 0;
|
|
||||||
while (i < numItems) {
|
|
||||||
//printf("level = %d\n", r->level);
|
|
||||||
if (levels[i] > levelHigh)
|
|
||||||
levelHigh = levels[i];
|
|
||||||
if (levels[i] < levelLow)
|
|
||||||
levelLow = levels[i];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// implements reordering of the line (L2 according to BiDi spec):
|
|
||||||
// L2. From the highest level found in the text to the lowest odd level on each line,
|
|
||||||
// reverse any contiguous sequence of characters that are at that level or higher.
|
|
||||||
|
|
||||||
// reversing is only done up to the lowest odd level
|
|
||||||
if(!(levelLow%2)) levelLow++;
|
|
||||||
|
|
||||||
#if (BIDI_DEBUG >= 1)
|
|
||||||
// qDebug() << "reorderLine: lineLow = " << (uint)levelLow << ", lineHigh = " << (uint)levelHigh;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int count = numItems - 1;
|
|
||||||
for (i = 0; i < numItems; i++)
|
|
||||||
visualOrder[i] = i;
|
|
||||||
|
|
||||||
while(levelHigh >= levelLow) {
|
|
||||||
int i = 0;
|
|
||||||
while (i < count) {
|
|
||||||
while(i < count && levels[i] < levelHigh) i++;
|
|
||||||
int start = i;
|
|
||||||
while(i <= count && levels[i] >= levelHigh) i++;
|
|
||||||
int end = i-1;
|
|
||||||
|
|
||||||
if(start != end) {
|
|
||||||
//qDebug() << "reversing from " << start << " to " << end;
|
|
||||||
for(int j = 0; j < (end-start+1)/2; j++) {
|
|
||||||
int tmp = visualOrder[start+j];
|
|
||||||
visualOrder[start+j] = visualOrder[end-j];
|
|
||||||
visualOrder[end-j] = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
levelHigh--;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (BIDI_DEBUG >= 1)
|
|
||||||
// qDebug() << "visual order is:";
|
|
||||||
// for (i = 0; i < numItems; i++)
|
|
||||||
// qDebug() << visualOrder[i];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// ask the font engine to find out which glyphs (as an index in the specific font) to use for the text in one item.
|
// ask the font engine to find out which glyphs (as an index in the specific font) to use for the text in one item.
|
||||||
static bool stringToGlyphs(HB_ShaperItem *item, QGlyphLayout *glyphs, QFontEngine *fontEngine)
|
static bool stringToGlyphs(HB_ShaperItem *item, QGlyphLayout *glyphs, QFontEngine *fontEngine)
|
||||||
{
|
{
|
||||||
int nGlyphs = item->num_glyphs;
|
int nGlyphs = item->num_glyphs;
|
||||||
|
|
||||||
QTextEngine::ShaperFlags shaperFlags(QTextEngine::GlyphIndicesOnly);
|
QTextEngine::ShaperFlags shaperFlags(QTextEngine::GlyphIndicesOnly);
|
||||||
if (item->item.bidiLevel % 2)
|
|
||||||
shaperFlags |= QTextEngine::RightToLeft;
|
|
||||||
|
|
||||||
bool result = fontEngine->stringToCMap(reinterpret_cast<const QChar *>(item->string + item->item.pos), item->item.length, glyphs, &nGlyphs, shaperFlags);
|
bool result = fontEngine->stringToCMap(reinterpret_cast<const QChar *>(item->string + item->item.pos), item->item.length, glyphs, &nGlyphs, shaperFlags);
|
||||||
item->num_glyphs = nGlyphs;
|
item->num_glyphs = nGlyphs;
|
||||||
|
@ -298,7 +221,6 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
|
||||||
entire_shaper_item.item.script = (HB_Script)si.analysis.script;
|
entire_shaper_item.item.script = (HB_Script)si.analysis.script;
|
||||||
entire_shaper_item.item.pos = si.position;
|
entire_shaper_item.item.pos = si.position;
|
||||||
entire_shaper_item.item.length = length(item);
|
entire_shaper_item.item.length = length(item);
|
||||||
entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel;
|
|
||||||
|
|
||||||
entire_shaper_item.shaperFlags = 0;
|
entire_shaper_item.shaperFlags = 0;
|
||||||
if (!kerningEnabled)
|
if (!kerningEnabled)
|
||||||
|
@ -487,12 +409,6 @@ void QTextEngine::itemize() const
|
||||||
QSTACKARRAY(QScriptAnalysis, scriptAnalysis, length);
|
QSTACKARRAY(QScriptAnalysis, scriptAnalysis, length);
|
||||||
QScriptAnalysis *analysis = scriptAnalysis;
|
QScriptAnalysis *analysis = scriptAnalysis;
|
||||||
|
|
||||||
if (option.textDirection() == Qt::RightToLeft) {
|
|
||||||
for (int i = 0; i < length; ++i)
|
|
||||||
analysis[i].bidiLevel = 1;
|
|
||||||
layoutData->hasBidi = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ushort *uc = reinterpret_cast<const ushort *>(layoutData->string.unicode());
|
const ushort *uc = reinterpret_cast<const ushort *>(layoutData->string.unicode());
|
||||||
const ushort *e = uc + length;
|
const ushort *e = uc + length;
|
||||||
QUnicodeTables::Script lastScript = QUnicodeTables::Common;
|
QUnicodeTables::Script lastScript = QUnicodeTables::Common;
|
||||||
|
@ -503,8 +419,6 @@ void QTextEngine::itemize() const
|
||||||
analysis->flags = QScriptAnalysis::Object;
|
analysis->flags = QScriptAnalysis::Object;
|
||||||
break;
|
break;
|
||||||
case QChar::LineSeparator:
|
case QChar::LineSeparator:
|
||||||
if (analysis->bidiLevel % 2)
|
|
||||||
--analysis->bidiLevel;
|
|
||||||
analysis->script = QUnicodeTables::Common;
|
analysis->script = QUnicodeTables::Common;
|
||||||
analysis->flags = QScriptAnalysis::LineOrParagraphSeparator;
|
analysis->flags = QScriptAnalysis::LineOrParagraphSeparator;
|
||||||
if (option.flags() & QTextOption::ShowLineAndParagraphSeparators)
|
if (option.flags() & QTextOption::ShowLineAndParagraphSeparators)
|
||||||
|
@ -513,14 +427,12 @@ void QTextEngine::itemize() const
|
||||||
case 9: // Tab
|
case 9: // Tab
|
||||||
analysis->script = QUnicodeTables::Common;
|
analysis->script = QUnicodeTables::Common;
|
||||||
analysis->flags = QScriptAnalysis::Tab;
|
analysis->flags = QScriptAnalysis::Tab;
|
||||||
analysis->bidiLevel = 0;
|
|
||||||
break;
|
break;
|
||||||
case 32: // Space
|
case 32: // Space
|
||||||
case QChar::Nbsp:
|
case QChar::Nbsp:
|
||||||
if (option.flags() & QTextOption::ShowTabsAndSpaces) {
|
if (option.flags() & QTextOption::ShowTabsAndSpaces) {
|
||||||
analysis->script = QUnicodeTables::Common;
|
analysis->script = QUnicodeTables::Common;
|
||||||
analysis->flags = QScriptAnalysis::Space;
|
analysis->flags = QScriptAnalysis::Space;
|
||||||
analysis->bidiLevel = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// fall through
|
// fall through
|
||||||
|
@ -578,25 +490,6 @@ void QTextEngine::itemize() const
|
||||||
resolveAdditionalFormats();
|
resolveAdditionalFormats();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTextEngine::isRightToLeft() const
|
|
||||||
{
|
|
||||||
switch (option.textDirection()) {
|
|
||||||
case Qt::LeftToRight:
|
|
||||||
return false;
|
|
||||||
case Qt::RightToLeft:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!layoutData)
|
|
||||||
itemize();
|
|
||||||
// this places the cursor in the right position depending on the keyboard layout
|
|
||||||
if (layoutData->string.isEmpty())
|
|
||||||
return QApplication::keyboardInputDirection() == Qt::RightToLeft;
|
|
||||||
return layoutData->string.isRightToLeft();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int QTextEngine::findItem(int strPos) const
|
int QTextEngine::findItem(int strPos) const
|
||||||
{
|
{
|
||||||
itemize();
|
itemize();
|
||||||
|
@ -1015,8 +908,7 @@ void QTextEngine::justify(const QScriptLine &line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QFixed leading = leadingSpaceWidth(line);
|
QFixed need = line.width - line.textWidth;
|
||||||
QFixed need = line.width - line.textWidth - leading;
|
|
||||||
if (need < 0) {
|
if (need < 0) {
|
||||||
// line overflows already!
|
// line overflows already!
|
||||||
const_cast<QScriptLine &>(line).justified = true;
|
const_cast<QScriptLine &>(line).justified = true;
|
||||||
|
@ -1105,7 +997,6 @@ QTextEngine::LayoutData::LayoutData()
|
||||||
allocated = 0;
|
allocated = 0;
|
||||||
memory_on_stack = false;
|
memory_on_stack = false;
|
||||||
used = 0;
|
used = 0;
|
||||||
hasBidi = false;
|
|
||||||
layoutState = LayoutEmpty;
|
layoutState = LayoutEmpty;
|
||||||
haveCharAttributes = false;
|
haveCharAttributes = false;
|
||||||
logClustersPtr = 0;
|
logClustersPtr = 0;
|
||||||
|
@ -1139,7 +1030,6 @@ QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int
|
||||||
::memset(memory, 0, space_charAttributes * QT_POINTER_SIZE);
|
::memset(memory, 0, space_charAttributes * QT_POINTER_SIZE);
|
||||||
}
|
}
|
||||||
used = 0;
|
used = 0;
|
||||||
hasBidi = false;
|
|
||||||
layoutState = LayoutEmpty;
|
layoutState = LayoutEmpty;
|
||||||
haveCharAttributes = false;
|
haveCharAttributes = false;
|
||||||
}
|
}
|
||||||
|
@ -1225,7 +1115,6 @@ void QTextEngine::freeMemory()
|
||||||
layoutData = 0;
|
layoutData = 0;
|
||||||
} else {
|
} else {
|
||||||
layoutData->used = 0;
|
layoutData->used = 0;
|
||||||
layoutData->hasBidi = false;
|
|
||||||
layoutData->layoutState = LayoutEmpty;
|
layoutData->layoutState = LayoutEmpty;
|
||||||
layoutData->haveCharAttributes = false;
|
layoutData->haveCharAttributes = false;
|
||||||
}
|
}
|
||||||
|
@ -1566,20 +1455,6 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
|
||||||
|
|
||||||
QList<QTextOption::Tab> tabArray = option.tabs();
|
QList<QTextOption::Tab> tabArray = option.tabs();
|
||||||
if (!tabArray.isEmpty()) {
|
if (!tabArray.isEmpty()) {
|
||||||
if (isRightToLeft()) { // rebase the tabArray positions.
|
|
||||||
QList<QTextOption::Tab> newTabs;
|
|
||||||
QList<QTextOption::Tab>::Iterator iter = tabArray.begin();
|
|
||||||
while(iter != tabArray.end()) {
|
|
||||||
QTextOption::Tab tab = *iter;
|
|
||||||
if (tab.type == QTextOption::LeftTab)
|
|
||||||
tab.type = QTextOption::RightTab;
|
|
||||||
else if (tab.type == QTextOption::RightTab)
|
|
||||||
tab.type = QTextOption::LeftTab;
|
|
||||||
newTabs << tab;
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
tabArray = newTabs;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < tabArray.size(); ++i) {
|
for (int i = 0; i < tabArray.size(); ++i) {
|
||||||
QFixed tab = QFixed::fromReal(tabArray[i].position) * dpiScale;
|
QFixed tab = QFixed::fromReal(tabArray[i].position) * dpiScale;
|
||||||
if (tab > x) { // this is the tab we need.
|
if (tab > x) { // this is the tab we need.
|
||||||
|
@ -1663,16 +1538,6 @@ void QTextEngine::resolveAdditionalFormats() const
|
||||||
specialData->resolvedFormatIndices = indices;
|
specialData->resolvedFormatIndices = indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line)
|
|
||||||
{
|
|
||||||
if (!line.hasTrailingSpaces
|
|
||||||
|| (option.flags() & QTextOption::IncludeTrailingSpaces)
|
|
||||||
|| !isRightToLeft())
|
|
||||||
return QFixed();
|
|
||||||
|
|
||||||
return width(line.from + line.length, line.trailingSpaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
QFixed QTextEngine::alignLine(const QScriptLine &line)
|
QFixed QTextEngine::alignLine(const QScriptLine &line)
|
||||||
{
|
{
|
||||||
QFixed x = 0;
|
QFixed x = 0;
|
||||||
|
@ -1680,8 +1545,6 @@ QFixed QTextEngine::alignLine(const QScriptLine &line)
|
||||||
// if width is QFIXED_MAX that means we used setNumColumns() and that implicitly makes this line left aligned.
|
// if width is QFIXED_MAX that means we used setNumColumns() and that implicitly makes this line left aligned.
|
||||||
if (!line.justified && line.width != QFIXED_MAX) {
|
if (!line.justified && line.width != QFIXED_MAX) {
|
||||||
int align = option.alignment();
|
int align = option.alignment();
|
||||||
if (align & Qt::AlignJustify && isRightToLeft())
|
|
||||||
align = Qt::AlignRight;
|
|
||||||
if (align & Qt::AlignRight)
|
if (align & Qt::AlignRight)
|
||||||
x = line.width - (line.textAdvance);
|
x = line.width - (line.textAdvance);
|
||||||
else if (align & Qt::AlignHCenter)
|
else if (align & Qt::AlignHCenter)
|
||||||
|
@ -1838,26 +1701,17 @@ int QTextEngine::lineNumberForTextPosition(int pos)
|
||||||
void QTextEngine::insertionPointsForLine(int lineNum, QVector<int> &insertionPoints)
|
void QTextEngine::insertionPointsForLine(int lineNum, QVector<int> &insertionPoints)
|
||||||
{
|
{
|
||||||
QTextLineItemIterator iterator(this, lineNum);
|
QTextLineItemIterator iterator(this, lineNum);
|
||||||
bool rtl = isRightToLeft();
|
|
||||||
bool lastLine = lineNum >= lines.size() - 1;
|
bool lastLine = lineNum >= lines.size() - 1;
|
||||||
|
|
||||||
while (!iterator.atEnd()) {
|
while (!iterator.atEnd()) {
|
||||||
iterator.next();
|
iterator.next();
|
||||||
const QScriptItem *si = &layoutData->items[iterator.item];
|
const QScriptItem *si = &layoutData->items[iterator.item];
|
||||||
if (si->analysis.bidiLevel % 2) {
|
|
||||||
int i = iterator.itemEnd - 1, min = iterator.itemStart;
|
|
||||||
if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd()))
|
|
||||||
i++;
|
|
||||||
for (; i >= min; i--)
|
|
||||||
insertionPoints.push_back(i);
|
|
||||||
} else {
|
|
||||||
int i = iterator.itemStart, max = iterator.itemEnd;
|
int i = iterator.itemStart, max = iterator.itemEnd;
|
||||||
if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd()))
|
if (lastLine && iterator.atEnd())
|
||||||
max++;
|
max++;
|
||||||
for (; i < max; i++)
|
for (; i < max; i++)
|
||||||
insertionPoints.push_back(i);
|
insertionPoints.push_back(i);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int QTextEngine::endOfLine(int lineNum)
|
int QTextEngine::endOfLine(int lineNum)
|
||||||
|
@ -1886,37 +1740,8 @@ int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation
|
||||||
itemize();
|
itemize();
|
||||||
|
|
||||||
bool moveRight = (op == QTextCursor::Right);
|
bool moveRight = (op == QTextCursor::Right);
|
||||||
bool alignRight = isRightToLeft();
|
|
||||||
if (!layoutData->hasBidi)
|
|
||||||
return moveRight ^ alignRight ? nextLogicalPosition(pos) : previousLogicalPosition(pos);
|
|
||||||
|
|
||||||
int lineNum = lineNumberForTextPosition(pos);
|
return (moveRight ? nextLogicalPosition(pos) : previousLogicalPosition(pos));
|
||||||
Q_ASSERT(lineNum >= 0);
|
|
||||||
|
|
||||||
QVector<int> insertionPoints;
|
|
||||||
insertionPointsForLine(lineNum, insertionPoints);
|
|
||||||
int i, max = insertionPoints.size();
|
|
||||||
for (i = 0; i < max; i++)
|
|
||||||
if (pos == insertionPoints[i]) {
|
|
||||||
if (moveRight) {
|
|
||||||
if (i + 1 < max)
|
|
||||||
return insertionPoints[i + 1];
|
|
||||||
} else {
|
|
||||||
if (i > 0)
|
|
||||||
return insertionPoints[i - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moveRight ^ alignRight) {
|
|
||||||
if (lineNum + 1 < lines.size())
|
|
||||||
return alignRight ? endOfLine(lineNum + 1) : beginningOfLine(lineNum + 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (lineNum > 0)
|
|
||||||
return alignRight ? beginningOfLine(lineNum - 1) : endOfLine(lineNum - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f)
|
QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f)
|
||||||
|
@ -1950,8 +1775,6 @@ void QTextItemInt::initWithScriptItem(const QScriptItem &si)
|
||||||
// explicitly initialize flags so that initFontAttributes can be called
|
// explicitly initialize flags so that initFontAttributes can be called
|
||||||
// multiple times on the same TextItem
|
// multiple times on the same TextItem
|
||||||
flags = 0;
|
flags = 0;
|
||||||
if (si.analysis.bidiLevel %2)
|
|
||||||
flags |= QTextItem::RightToLeft;
|
|
||||||
ascent = si.ascent;
|
ascent = si.ascent;
|
||||||
descent = si.descent;
|
descent = si.descent;
|
||||||
|
|
||||||
|
@ -1984,8 +1807,6 @@ QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int _lineNum, co
|
||||||
nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0),
|
nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0),
|
||||||
logicalItem(-1),
|
logicalItem(-1),
|
||||||
item(-1),
|
item(-1),
|
||||||
visualOrder(nItems),
|
|
||||||
levels(nItems),
|
|
||||||
selection(_selection)
|
selection(_selection)
|
||||||
{
|
{
|
||||||
pos_x = x = QFixed::fromReal(pos.x());
|
pos_x = x = QFixed::fromReal(pos.x());
|
||||||
|
@ -1994,10 +1815,6 @@ QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int _lineNum, co
|
||||||
|
|
||||||
x += eng->alignLine(line);
|
x += eng->alignLine(line);
|
||||||
|
|
||||||
for (int i = 0; i < nItems; ++i)
|
|
||||||
levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
|
|
||||||
QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
|
|
||||||
|
|
||||||
eng->shapeLine(line);
|
eng->shapeLine(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2006,7 +1823,7 @@ QScriptItem &QTextLineItemIterator::next()
|
||||||
x += itemWidth;
|
x += itemWidth;
|
||||||
|
|
||||||
++logicalItem;
|
++logicalItem;
|
||||||
item = visualOrder[logicalItem] + firstItem;
|
item = (logicalItem + firstItem);
|
||||||
itemLength = eng->length(item);
|
itemLength = eng->length(item);
|
||||||
si = &eng->layoutData->items[item];
|
si = &eng->layoutData->items[item];
|
||||||
if (!si->num_glyphs)
|
if (!si->num_glyphs)
|
||||||
|
@ -2068,17 +1885,10 @@ bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selec
|
||||||
int end_glyph = (to == eng->length(item)) ? si->num_glyphs : logClusters[to];
|
int end_glyph = (to == eng->length(item)) ? si->num_glyphs : logClusters[to];
|
||||||
QFixed soff;
|
QFixed soff;
|
||||||
QFixed swidth;
|
QFixed swidth;
|
||||||
if (si->analysis.bidiLevel %2) {
|
|
||||||
for (int g = glyphsEnd - 1; g >= end_glyph; --g)
|
|
||||||
soff += glyphs.effectiveAdvance(g);
|
|
||||||
for (int g = end_glyph - 1; g >= start_glyph; --g)
|
|
||||||
swidth += glyphs.effectiveAdvance(g);
|
|
||||||
} else {
|
|
||||||
for (int g = glyphsStart; g < start_glyph; ++g)
|
for (int g = glyphsStart; g < start_glyph; ++g)
|
||||||
soff += glyphs.effectiveAdvance(g);
|
soff += glyphs.effectiveAdvance(g);
|
||||||
for (int g = start_glyph; g < end_glyph; ++g)
|
for (int g = start_glyph; g < end_glyph; ++g)
|
||||||
swidth += glyphs.effectiveAdvance(g);
|
swidth += glyphs.effectiveAdvance(g);
|
||||||
}
|
|
||||||
|
|
||||||
// If the starting character is in the middle of a ligature,
|
// If the starting character is in the middle of a ligature,
|
||||||
// selection should only contain the right part of that ligature
|
// selection should only contain the right part of that ligature
|
||||||
|
|
|
@ -90,10 +90,9 @@ struct Q_AUTOTEST_EXPORT QScriptAnalysis
|
||||||
Object = 4
|
Object = 4
|
||||||
};
|
};
|
||||||
QUnicodeTables::Script script;
|
QUnicodeTables::Script script;
|
||||||
unsigned short bidiLevel; // Unicode Bidi algorithm embedding level (0-61)
|
|
||||||
Flags flags;
|
Flags flags;
|
||||||
inline bool operator == (const QScriptAnalysis &other) const {
|
inline bool operator == (const QScriptAnalysis &other) const {
|
||||||
return script == other.script && bidiLevel == other.bidiLevel && flags == other.flags;
|
return script == other.script && flags == other.flags;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE);
|
Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE);
|
||||||
|
@ -356,7 +355,6 @@ public:
|
||||||
unsigned short *logClustersPtr;
|
unsigned short *logClustersPtr;
|
||||||
QGlyphLayout glyphLayout;
|
QGlyphLayout glyphLayout;
|
||||||
mutable int used;
|
mutable int used;
|
||||||
bool hasBidi;
|
|
||||||
LayoutState layoutState;
|
LayoutState layoutState;
|
||||||
bool memory_on_stack;
|
bool memory_on_stack;
|
||||||
bool haveCharAttributes;
|
bool haveCharAttributes;
|
||||||
|
@ -383,9 +381,6 @@ public:
|
||||||
void validate() const;
|
void validate() const;
|
||||||
void itemize() const;
|
void itemize() const;
|
||||||
|
|
||||||
bool isRightToLeft() const;
|
|
||||||
static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
|
|
||||||
|
|
||||||
const HB_CharAttributes *attributes() const;
|
const HB_CharAttributes *attributes() const;
|
||||||
|
|
||||||
void shape(int item) const;
|
void shape(int item) const;
|
||||||
|
@ -509,7 +504,6 @@ public:
|
||||||
QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const;
|
QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const;
|
||||||
|
|
||||||
void shapeLine(const QScriptLine &line);
|
void shapeLine(const QScriptLine &line);
|
||||||
QFixed leadingSpaceWidth(const QScriptLine &line);
|
|
||||||
|
|
||||||
QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos);
|
QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos);
|
||||||
int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter);
|
int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter);
|
||||||
|
@ -577,9 +571,6 @@ struct QTextLineItemIterator
|
||||||
|
|
||||||
QFixed itemWidth;
|
QFixed itemWidth;
|
||||||
|
|
||||||
QVarLengthArray<int> visualOrder;
|
|
||||||
QVarLengthArray<uchar> levels;
|
|
||||||
|
|
||||||
const QTextLayout::FormatRange *selection;
|
const QTextLayout::FormatRange *selection;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,7 @@ QTextFormat QTextInlineObject::format() const
|
||||||
*/
|
*/
|
||||||
Qt::LayoutDirection QTextInlineObject::textDirection() const
|
Qt::LayoutDirection QTextInlineObject::textDirection() const
|
||||||
{
|
{
|
||||||
return (eng->layoutData->items[itm].analysis.bidiLevel % 2 ? Qt::RightToLeft : Qt::LeftToRight);
|
return Qt::LeftToRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1027,7 +1027,6 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRang
|
||||||
|
|
||||||
QRectF lineRect(tl.naturalTextRect());
|
QRectF lineRect(tl.naturalTextRect());
|
||||||
lineRect.translate(position);
|
lineRect.translate(position);
|
||||||
lineRect.adjust(0, 0, d->leadingSpaceWidth(sl).toReal(), 0);
|
|
||||||
|
|
||||||
bool isLastLineInBlock = (line == d->lines.size()-1);
|
bool isLastLineInBlock = (line == d->lines.size()-1);
|
||||||
int sl_length = sl.length + (isLastLineInBlock? 1 : 0); // the infamous newline
|
int sl_length = sl.length + (isLastLineInBlock? 1 : 0); // the infamous newline
|
||||||
|
@ -1202,14 +1201,12 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
|
||||||
|
|
||||||
QFixed base = sl.base();
|
QFixed base = sl.base();
|
||||||
QFixed descent = sl.descent;
|
QFixed descent = sl.descent;
|
||||||
bool rightToLeft = d->isRightToLeft();
|
|
||||||
if (itm >= 0) {
|
if (itm >= 0) {
|
||||||
const QScriptItem &si = d->layoutData->items.at(itm);
|
const QScriptItem &si = d->layoutData->items.at(itm);
|
||||||
if (si.ascent > 0)
|
if (si.ascent > 0)
|
||||||
base = si.ascent;
|
base = si.ascent;
|
||||||
if (si.descent > 0)
|
if (si.descent > 0)
|
||||||
descent = si.descent;
|
descent = si.descent;
|
||||||
rightToLeft = si.analysis.bidiLevel % 2;
|
|
||||||
}
|
}
|
||||||
qreal y = position.y() + (sl.y + sl.base() - base).toReal();
|
qreal y = position.y() + (sl.y + sl.base() - base).toReal();
|
||||||
bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing)
|
bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing)
|
||||||
|
@ -1219,13 +1216,6 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
|
||||||
p->fillRect(QRectF(x, y, qreal(width), (base + descent + 1).toReal()), p->pen().brush());
|
p->fillRect(QRectF(x, y, qreal(width), (base + descent + 1).toReal()), p->pen().brush());
|
||||||
if (toggleAntialiasing)
|
if (toggleAntialiasing)
|
||||||
p->setRenderHint(QPainter::Antialiasing, false);
|
p->setRenderHint(QPainter::Antialiasing, false);
|
||||||
if (d->layoutData->hasBidi) {
|
|
||||||
const int arrow_extent = 4;
|
|
||||||
int sign = rightToLeft ? -1 : 1;
|
|
||||||
p->drawLine(QLineF(x, y, x + (sign * arrow_extent/2), y + arrow_extent/2));
|
|
||||||
p->drawLine(QLineF(x, y+arrow_extent, x + (sign * arrow_extent/2), y + arrow_extent/2));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -1966,9 +1956,6 @@ static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si,
|
||||||
if (ul)
|
if (ul)
|
||||||
while (*ul != -1 && *ul < start)
|
while (*ul != -1 && *ul < start)
|
||||||
++ul;
|
++ul;
|
||||||
bool rtl = si.analysis.bidiLevel % 2;
|
|
||||||
if (rtl)
|
|
||||||
x += si.width;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int gtmp = ge;
|
int gtmp = ge;
|
||||||
|
@ -1988,11 +1975,8 @@ static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si,
|
||||||
}
|
}
|
||||||
start = stmp;
|
start = stmp;
|
||||||
gf.width = w;
|
gf.width = w;
|
||||||
if (rtl)
|
|
||||||
x -= w;
|
|
||||||
if (gf.num_chars)
|
if (gf.num_chars)
|
||||||
p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
|
p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
|
||||||
if (!rtl)
|
|
||||||
x += w;
|
x += w;
|
||||||
if (ul && *ul != -1 && *ul < end) {
|
if (ul && *ul != -1 && *ul < end) {
|
||||||
// draw underline
|
// draw underline
|
||||||
|
@ -2010,10 +1994,7 @@ static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si,
|
||||||
++start;
|
++start;
|
||||||
gf.width = w;
|
gf.width = w;
|
||||||
gf.underlineStyle = QTextCharFormat::SingleUnderline;
|
gf.underlineStyle = QTextCharFormat::SingleUnderline;
|
||||||
if (rtl)
|
|
||||||
x -= w;
|
|
||||||
p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
|
p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
|
||||||
if (!rtl)
|
|
||||||
x += w;
|
x += w;
|
||||||
gf.underlineStyle = QTextCharFormat::NoUnderline;
|
gf.underlineStyle = QTextCharFormat::NoUnderline;
|
||||||
++gf.chars;
|
++gf.chars;
|
||||||
|
@ -2279,7 +2260,7 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
|
||||||
bool lastLine = i >= eng->lines.size() - 1;
|
bool lastLine = i >= eng->lines.size() - 1;
|
||||||
|
|
||||||
QFixed x = line.x;
|
QFixed x = line.x;
|
||||||
x += eng->alignLine(line) - eng->leadingSpaceWidth(line);
|
x += eng->alignLine(line);
|
||||||
|
|
||||||
if (!i && !eng->layoutData->items.size()) {
|
if (!i && !eng->layoutData->items.size()) {
|
||||||
*cursorPos = 0;
|
*cursorPos = 0;
|
||||||
|
@ -2326,23 +2307,14 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
|
||||||
glyph_pos++;
|
glyph_pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool reverse = eng->layoutData->items[itm].analysis.bidiLevel % 2;
|
|
||||||
|
|
||||||
|
|
||||||
// add the items left of the cursor
|
// add the items left of the cursor
|
||||||
|
|
||||||
int firstItem = eng->findItem(line.from);
|
int firstItem = eng->findItem(line.from);
|
||||||
int lastItem = eng->findItem(lineEnd - 1);
|
int lastItem = eng->findItem(lineEnd - 1);
|
||||||
int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
|
int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
|
||||||
|
|
||||||
QVarLengthArray<int> visualOrder(nItems);
|
|
||||||
QVarLengthArray<uchar> levels(nItems);
|
|
||||||
for (int i = 0; i < nItems; ++i)
|
|
||||||
levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
|
|
||||||
QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
|
|
||||||
|
|
||||||
for (int i = 0; i < nItems; ++i) {
|
for (int i = 0; i < nItems; ++i) {
|
||||||
int item = visualOrder[i]+firstItem;
|
int item = (i + firstItem);
|
||||||
if (item == itm)
|
if (item == itm)
|
||||||
break;
|
break;
|
||||||
QScriptItem &si = eng->layoutData->items[item];
|
QScriptItem &si = eng->layoutData->items[item];
|
||||||
|
@ -2372,26 +2344,16 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
|
||||||
logClusters = eng->logClusters(si);
|
logClusters = eng->logClusters(si);
|
||||||
glyphs = eng->shapedGlyphs(si);
|
glyphs = eng->shapedGlyphs(si);
|
||||||
if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
|
if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
|
||||||
if (pos == (reverse ? 0 : l))
|
if (pos == l)
|
||||||
x += si->width;
|
x += si->width;
|
||||||
} else {
|
} else {
|
||||||
bool rtl = eng->isRightToLeft();
|
|
||||||
bool visual = eng->visualCursorMovement();
|
bool visual = eng->visualCursorMovement();
|
||||||
int end = qMin(lineEnd, si->position + l) - si->position;
|
int end = qMin(lineEnd, si->position + l) - si->position;
|
||||||
if (reverse) {
|
|
||||||
int glyph_end = end == l ? si->num_glyphs : logClusters[end];
|
|
||||||
int glyph_start = glyph_pos;
|
|
||||||
if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem)))
|
|
||||||
glyph_start++;
|
|
||||||
for (int i = glyph_end - 1; i >= glyph_start; i--)
|
|
||||||
x += glyphs.effectiveAdvance(i);
|
|
||||||
} else {
|
|
||||||
int start = qMax(line.from - si->position, 0);
|
int start = qMax(line.from - si->position, 0);
|
||||||
int glyph_start = logClusters[start];
|
int glyph_start = logClusters[start];
|
||||||
int glyph_end = glyph_pos;
|
int glyph_end = glyph_pos;
|
||||||
if (!visual || !rtl || (lastLine && itm == visualOrder[0] + firstItem))
|
|
||||||
glyph_end--;
|
glyph_end--;
|
||||||
for (int i = glyph_start; i <= glyph_end; i++)
|
for (int i = glyph_start; i <= glyph_end; i++) {
|
||||||
x += glyphs.effectiveAdvance(i);
|
x += glyphs.effectiveAdvance(i);
|
||||||
}
|
}
|
||||||
x += eng->offsetInLigature(si, pos, end, glyph_pos);
|
x += eng->offsetInLigature(si, pos, end, glyph_pos);
|
||||||
|
@ -2441,22 +2403,14 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
|
||||||
x -= eng->alignLine(line);
|
x -= eng->alignLine(line);
|
||||||
// qDebug("xToCursor: x=%f, cpos=%d", x.toReal(), cpos);
|
// qDebug("xToCursor: x=%f, cpos=%d", x.toReal(), cpos);
|
||||||
|
|
||||||
QSTACKARRAY(int, visualOrder, nItems);
|
|
||||||
QSTACKARRAY(unsigned char, levels, nItems);
|
|
||||||
for (int i = 0; i < nItems; ++i)
|
|
||||||
levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
|
|
||||||
QTextEngine::bidiReorder(nItems, levels, visualOrder);
|
|
||||||
|
|
||||||
bool visual = eng->visualCursorMovement();
|
bool visual = eng->visualCursorMovement();
|
||||||
if (x <= 0) {
|
if (x <= 0) {
|
||||||
// left of first item
|
// left of first item
|
||||||
int item = visualOrder[0]+firstItem;
|
int item = firstItem;
|
||||||
QScriptItem &si = eng->layoutData->items[item];
|
QScriptItem &si = eng->layoutData->items[item];
|
||||||
if (!si.num_glyphs)
|
if (!si.num_glyphs)
|
||||||
eng->shape(item);
|
eng->shape(item);
|
||||||
int pos = si.position;
|
int pos = si.position;
|
||||||
if (si.analysis.bidiLevel % 2)
|
|
||||||
pos += eng->length(item);
|
|
||||||
pos = qMax(line.from, pos);
|
pos = qMax(line.from, pos);
|
||||||
pos = qMin(line.from + line_length, pos);
|
pos = qMin(line.from + line_length, pos);
|
||||||
return pos;
|
return pos;
|
||||||
|
@ -2464,15 +2418,11 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
|
||||||
|| (line.justified && x < line.width)) {
|
|| (line.justified && x < line.width)) {
|
||||||
// has to be in one of the runs
|
// has to be in one of the runs
|
||||||
QFixed pos;
|
QFixed pos;
|
||||||
bool rtl = eng->isRightToLeft();
|
|
||||||
|
|
||||||
eng->shapeLine(line);
|
eng->shapeLine(line);
|
||||||
QVector<int> insertionPoints;
|
|
||||||
if (visual && rtl)
|
|
||||||
eng->insertionPointsForLine(lineNum, insertionPoints);
|
|
||||||
int nchars = 0;
|
int nchars = 0;
|
||||||
for (int i = 0; i < nItems; ++i) {
|
for (int i = 0; i < nItems; ++i) {
|
||||||
int item = visualOrder[i]+firstItem;
|
int item = (i + firstItem);
|
||||||
QScriptItem &si = eng->layoutData->items[item];
|
QScriptItem &si = eng->layoutData->items[item];
|
||||||
int item_length = eng->length(item);
|
int item_length = eng->length(item);
|
||||||
// qDebug(" item %d, visual %d x_remain=%f", i, item, x.toReal());
|
// qDebug(" item %d, visual %d x_remain=%f", i, item, x.toReal());
|
||||||
|
@ -2509,7 +2459,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
|
||||||
return si.position;
|
return si.position;
|
||||||
bool left_half = (x - pos) < item_width/2;
|
bool left_half = (x - pos) < item_width/2;
|
||||||
|
|
||||||
if (bool(si.analysis.bidiLevel % 2) != left_half)
|
if (left_half)
|
||||||
return si.position;
|
return si.position;
|
||||||
return si.position + 1;
|
return si.position + 1;
|
||||||
}
|
}
|
||||||
|
@ -2518,21 +2468,6 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
|
||||||
QFixed edge;
|
QFixed edge;
|
||||||
// has to be inside run
|
// has to be inside run
|
||||||
if (cpos == QTextLine::CursorOnCharacter) {
|
if (cpos == QTextLine::CursorOnCharacter) {
|
||||||
if (si.analysis.bidiLevel % 2) {
|
|
||||||
pos += item_width;
|
|
||||||
glyph_pos = gs;
|
|
||||||
while (gs <= ge) {
|
|
||||||
if (glyphs.attributes[gs].clusterStart) {
|
|
||||||
if (pos < x)
|
|
||||||
break;
|
|
||||||
glyph_pos = gs;
|
|
||||||
edge = pos;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos -= glyphs.effectiveAdvance(gs);
|
|
||||||
++gs;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
glyph_pos = gs;
|
glyph_pos = gs;
|
||||||
while (gs <= ge) {
|
while (gs <= ge) {
|
||||||
if (glyphs.attributes[gs].clusterStart) {
|
if (glyphs.attributes[gs].clusterStart) {
|
||||||
|
@ -2544,34 +2479,8 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
|
||||||
pos += glyphs.effectiveAdvance(gs);
|
pos += glyphs.effectiveAdvance(gs);
|
||||||
++gs;
|
++gs;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
QFixed dist = INT_MAX/256;
|
QFixed dist = INT_MAX/256;
|
||||||
if (si.analysis.bidiLevel % 2) {
|
|
||||||
if (!visual || rtl || (lastLine && i == nItems - 1)) {
|
|
||||||
pos += item_width;
|
|
||||||
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);
|
|
||||||
++gs;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (ge >= gs) {
|
|
||||||
if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) {
|
|
||||||
glyph_pos = ge;
|
|
||||||
edge = pos;
|
|
||||||
dist = qAbs(x-pos);
|
|
||||||
}
|
|
||||||
pos += glyphs.effectiveAdvance(ge);
|
|
||||||
--ge;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!visual || !rtl || (lastLine && i == 0)) {
|
|
||||||
while (gs <= ge) {
|
while (gs <= ge) {
|
||||||
if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
|
if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
|
||||||
glyph_pos = gs;
|
glyph_pos = gs;
|
||||||
|
@ -2581,28 +2490,12 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
|
||||||
pos += glyphs.effectiveAdvance(gs);
|
pos += glyphs.effectiveAdvance(gs);
|
||||||
++gs;
|
++gs;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
QFixed oldPos = pos;
|
|
||||||
while (gs <= ge) {
|
|
||||||
pos += glyphs.effectiveAdvance(gs);
|
|
||||||
if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
|
|
||||||
glyph_pos = gs;
|
|
||||||
edge = pos;
|
|
||||||
dist = qAbs(x-pos);
|
|
||||||
}
|
|
||||||
++gs;
|
|
||||||
}
|
|
||||||
pos = oldPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (qAbs(x-pos) < dist) {
|
if (qAbs(x-pos) < dist) {
|
||||||
if (visual) {
|
if (visual) {
|
||||||
if (!rtl && i < nItems - 1) {
|
if (i < nItems - 1) {
|
||||||
nchars += end;
|
nchars += end;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rtl && nchars > 0)
|
|
||||||
return insertionPoints[lastLine ? nchars : nchars - 1];
|
|
||||||
}
|
}
|
||||||
return eng->positionInLigature(&si, end, x, pos, -1,
|
return eng->positionInLigature(&si, end, x, pos, -1,
|
||||||
cpos == QTextLine::CursorOnCharacter);
|
cpos == QTextLine::CursorOnCharacter);
|
||||||
|
@ -2615,12 +2508,11 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
|
||||||
}
|
}
|
||||||
// right of last item
|
// right of last item
|
||||||
// qDebug() << "right of last";
|
// qDebug() << "right of last";
|
||||||
int item = visualOrder[nItems-1]+firstItem;
|
int item = (nItems -1 + firstItem);
|
||||||
QScriptItem &si = eng->layoutData->items[item];
|
QScriptItem &si = eng->layoutData->items[item];
|
||||||
if (!si.num_glyphs)
|
if (!si.num_glyphs)
|
||||||
eng->shape(item);
|
eng->shape(item);
|
||||||
int pos = si.position;
|
int pos = si.position;
|
||||||
if (!(si.analysis.bidiLevel % 2))
|
|
||||||
pos += eng->length(item);
|
pos += eng->length(item);
|
||||||
pos = qMax(line.from, pos);
|
pos = qMax(line.from, pos);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue