Move QTextEngine implementation details from QTextLayout

As of now, we'll have everything related to the additional formats handling
just in a single place. Make specialData private to prevent accessing it
from outside. This helped in tracking-down several related issues:
- in format(const QScriptItem *), the resolvedFormatIndices can not be empty
  at that point, so the code path is dead;
- in resolveAdditionalFormats(), testing if formats has not been indexed yet
  is not needed since they are indexed just in the setter;
- in useRawFont mode, hasFormats() didn't check if QTextEngine really
  has some formats, which potentially leads to formatting artifacts.

Change-Id: Id4b912888fd5a1fa83f01007170134b6386e2879
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
This commit is contained in:
Konstantin Ritt 2013-03-18 18:16:40 +02:00 committed by The Qt Project
parent bd8630763c
commit 0654c066d9
3 changed files with 95 additions and 86 deletions

View File

@ -1164,7 +1164,7 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const
layoutData->used += si.num_glyphs;
}
static void init(QTextEngine *e)
void QTextEngine::init(QTextEngine *e)
{
e->ignoreBidi = false;
e->cacheGlyphs = false;
@ -1433,10 +1433,11 @@ void QTextEngine::itemize() const
#ifndef QT_NO_RAWFONT
if (useRawFont && specialData) {
int lastIndex = 0;
const QTextFormatCollection *collection = formats();
for (int i = 0; i < specialData->addFormats.size(); ++i) {
const QTextLayout::FormatRange &range = specialData->addFormats.at(i);
QTextCharFormat format = formats()->charFormat(specialData->addFormatIndices.at(i));
if (format.fontCapitalization()) {
const QTextCharFormat format = collection->charFormat(specialData->addFormatIndices.at(i));
if (format.hasProperty(QTextFormat::FontCapitalization)) {
itemizer.generate(lastIndex, range.start - lastIndex, QFont::MixedCase);
itemizer.generate(range.start, range.length, format.fontCapitalization());
lastIndex = range.start + range.length;
@ -2209,25 +2210,9 @@ int QTextEngine::formatIndex(const QScriptItem *si) const
QTextCharFormat QTextEngine::format(const QScriptItem *si) const
{
QTextCharFormat format;
const QTextFormatCollection *formats = this->formats();
if (formats)
format = formats->charFormat(formatIndex(si));
if (specialData && specialData->resolvedFormatIndices.isEmpty()) {
int end = si->position + length(si);
for (int i = 0; i < specialData->addFormats.size(); ++i) {
const QTextLayout::FormatRange &r = specialData->addFormats.at(i);
if (r.start <= si->position && r.start + r.length >= end) {
if (!specialData->addFormatIndices.isEmpty())
format.merge(formats->format(specialData->addFormatIndices.at(i)));
else
format.merge(r.format);
}
}
}
return format;
if (const QTextFormatCollection *formats = this->formats())
return formats->charFormat(formatIndex(si));
return QTextCharFormat();
}
void QTextEngine::addRequiredBoundaries() const
@ -2298,6 +2283,67 @@ bool QTextEngine::atSpace(int position) const
return false;
}
void QTextEngine::setPreeditArea(int position, const QString &preeditText)
{
if (preeditText.isEmpty()) {
if (!specialData)
return;
if (specialData->addFormats.isEmpty()) {
delete specialData;
specialData = 0;
} else {
specialData->preeditText = QString();
specialData->preeditPosition = -1;
}
} else {
if (!specialData)
specialData = new SpecialData;
specialData->preeditPosition = position;
specialData->preeditText = preeditText;
}
invalidate();
clearLineData();
}
QList<QTextLayout::FormatRange> QTextEngine::additionalFormats() const
{
QList<QTextLayout::FormatRange> formatList;
if (!specialData)
return formatList;
formatList = specialData->addFormats;
if (!specialData->addFormatIndices.isEmpty()) {
const QTextFormatCollection *formats = this->formats();
Q_ASSERT(formats);
for (int i = 0; i < specialData->addFormatIndices.size(); ++i)
formatList[i].format = formats->charFormat(specialData->addFormatIndices.at(i));
}
return formatList;
}
void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList)
{
if (formatList.isEmpty()) {
if (!specialData)
return;
if (specialData->preeditText.isEmpty()) {
delete specialData;
specialData = 0;
} else {
specialData->addFormats.clear();
specialData->addFormatIndices.clear();
}
} else {
if (!specialData) {
specialData = new SpecialData;
specialData->preeditPosition = -1;
}
specialData->addFormats = formatList;
indexAdditionalFormats();
}
resetFontEngineCache();
}
void QTextEngine::indexAdditionalFormats()
{
@ -2775,13 +2821,9 @@ void QTextEngine::resolveAdditionalFormats() const
}
foreach (int cur, currentFormats) {
const QTextLayout::FormatRange &r = specialData->addFormats.at(cur);
Q_ASSERT (r.start <= si->position && r.start + r.length >= end);
if (!specialData->addFormatIndices.isEmpty()) {
format.merge(collection->format(specialData->addFormatIndices.at(cur)));
} else {
format.merge(r.format);
}
Q_ASSERT(specialData->addFormats.at(cur).start <= si->position
&& specialData->addFormats.at(cur).start + specialData->addFormats.at(cur).length >= end);
format.merge(collection->format(specialData->addFormatIndices.at(cur)));
}
indices[i] = collection->indexForFormat(format);
}

View File

@ -617,13 +617,23 @@ public:
ItemDecorationList strikeOutList;
ItemDecorationList overlineList;
inline bool hasFormats() const { return (block.docHandle() || specialData); }
inline bool visualCursorMovement() const
{
return (visualMovement ||
(block.docHandle() ? block.docHandle()->defaultCursorMoveStyle == Qt::VisualMoveStyle : false));
}
inline int preeditAreaPosition() const { return specialData ? specialData->preeditPosition : -1; }
inline QString preeditAreaText() const { return specialData ? specialData->preeditText : QString(); }
void setPreeditArea(int position, const QString &text);
inline bool hasFormats() const { return block.docHandle() || (specialData && !specialData->addFormats.isEmpty()); }
QList<QTextLayout::FormatRange> additionalFormats() const;
void setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList);
private:
static void init(QTextEngine *e);
struct SpecialData {
int preeditPosition;
QString preeditText;
@ -635,9 +645,12 @@ public:
};
SpecialData *specialData;
void indexAdditionalFormats();
void resolveAdditionalFormats() const;
public:
bool atWordSeparator(int position) const;
bool atSpace(int position) const;
void indexAdditionalFormats();
QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0, int from = 0, int count = -1) const;
@ -675,7 +688,6 @@ private:
void shapeTextWithHarfbuzz(int item) const;
void splitItem(int item, int pos) const;
void resolveAdditionalFormats() const;
int endOfLine(int lineNum);
int beginningOfLine(int lineNum);
int getClusterLength(unsigned short *logClusters, const QCharAttributes *attributes, int from, int to, int glyph_pos, int *start);

View File

@ -463,24 +463,10 @@ const QTextOption &QTextLayout::textOption() const
*/
void QTextLayout::setPreeditArea(int position, const QString &text)
{
if (text.isEmpty()) {
if (!d->specialData)
return;
if (d->specialData->addFormats.isEmpty()) {
delete d->specialData;
d->specialData = 0;
} else {
d->specialData->preeditText = QString();
d->specialData->preeditPosition = -1;
}
} else {
if (!d->specialData)
d->specialData = new QTextEngine::SpecialData;
d->specialData->preeditPosition = position;
d->specialData->preeditText = text;
}
d->invalidate();
d->clearLineData();
if (d->preeditAreaPosition() == position && d->preeditAreaText() == text)
return;
d->setPreeditArea(position, text);
if (d->block.docHandle())
d->block.docHandle()->documentChange(d->block.position(), d->block.length());
}
@ -493,7 +479,7 @@ void QTextLayout::setPreeditArea(int position, const QString &text)
*/
int QTextLayout::preeditAreaPosition() const
{
return d->specialData ? d->specialData->preeditPosition : -1;
return d->preeditAreaPosition();
}
/*!
@ -503,7 +489,7 @@ int QTextLayout::preeditAreaPosition() const
*/
QString QTextLayout::preeditAreaText() const
{
return d->specialData ? d->specialData->preeditText : QString();
return d->preeditAreaText();
}
@ -515,27 +501,10 @@ QString QTextLayout::preeditAreaText() const
*/
void QTextLayout::setAdditionalFormats(const QList<FormatRange> &formatList)
{
if (formatList.isEmpty()) {
if (!d->specialData)
return;
if (d->specialData->preeditText.isEmpty()) {
delete d->specialData;
d->specialData = 0;
} else {
d->specialData->addFormats = formatList;
d->specialData->addFormatIndices.clear();
}
} else {
if (!d->specialData) {
d->specialData = new QTextEngine::SpecialData;
d->specialData->preeditPosition = -1;
}
d->specialData->addFormats = formatList;
d->indexAdditionalFormats();
}
d->setAdditionalFormats(formatList);
if (d->block.docHandle())
d->block.docHandle()->documentChange(d->block.position(), d->block.length());
d->resetFontEngineCache();
}
/*!
@ -545,21 +514,7 @@ void QTextLayout::setAdditionalFormats(const QList<FormatRange> &formatList)
*/
QList<QTextLayout::FormatRange> QTextLayout::additionalFormats() const
{
QList<FormatRange> formats;
if (!d->specialData)
return formats;
formats = d->specialData->addFormats;
if (d->specialData->addFormatIndices.isEmpty())
return formats;
const QTextFormatCollection *collection = d->formats();
for (int i = 0; i < d->specialData->addFormatIndices.count(); ++i)
formats[i].format = collection->charFormat(d->specialData->addFormatIndices.at(i));
return formats;
return d->additionalFormats();
}
/*!