0.9.47 alpha: fixed crash in text processing (Qt pach updated).

This commit is contained in:
John Preston 2016-05-02 16:42:09 +03:00
parent 724ba9e429
commit dff5765f9f
11 changed files with 236 additions and 132 deletions

View File

@ -17,17 +17,19 @@ index eec9e1f..ec3015e 100644
QMAKE_CFLAGS_LTCG = -GL QMAKE_CFLAGS_LTCG = -GL
QMAKE_CFLAGS_SSE2 = -arch:SSE2 QMAKE_CFLAGS_SSE2 = -arch:SSE2
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index f1a6019..a53a6c4 100644 index f1a6019..81ff6ef 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp --- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -1416,8 +1416,9 @@ bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSyst @@ -1416,8 +1416,10 @@ bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSyst
COPYFILE2_EXTENDED_PARAMETERS copyParams = { COPYFILE2_EXTENDED_PARAMETERS copyParams = {
sizeof(copyParams), COPY_FILE_FAIL_IF_EXISTS, NULL, NULL, NULL sizeof(copyParams), COPY_FILE_FAIL_IF_EXISTS, NULL, NULL, NULL
}; };
+ // CopyFile2 returns HRESULT, not BOOL, so it should be tested for S_OK, not 0. - bool ret = ::CopyFile2((const wchar_t*)source.nativeFilePath().utf16(),
bool ret = ::CopyFile2((const wchar_t*)source.nativeFilePath().utf16(),
- (const wchar_t*)target.nativeFilePath().utf16(), &copyParams) != 0; - (const wchar_t*)target.nativeFilePath().utf16(), &copyParams) != 0;
+ (const wchar_t*)target.nativeFilePath().utf16(), &copyParams) == S_OK; + // CopyFile2 returns HRESULT, not BOOL, so it should be tested for S_OK, not 0.
+ HRESULT hres = ::CopyFile2((const wchar_t*)source.nativeFilePath().utf16(),
+ (const wchar_t*)target.nativeFilePath().utf16(), &copyParams);
+ bool ret = SUCCEEDED(hres);
#endif // Q_OS_WINRT #endif // Q_OS_WINRT
if(!ret) if(!ret)
error = QSystemError(::GetLastError(), QSystemError::NativeError); error = QSystemError(::GetLastError(), QSystemError::NativeError);
@ -114,7 +116,7 @@ index 39c228f..b72fdc0 100644
public: public:
inline QTextItemInt() inline QTextItemInt()
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 9e2a23a..861f202 100644 index 9e2a23a..4466a4e 100644
--- a/src/gui/text/qtextlayout.cpp --- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp
@@ -694,6 +694,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const @@ -694,6 +694,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
@ -136,6 +138,47 @@ index 9e2a23a..861f202 100644
} }
return oldPos; return oldPos;
@@ -1644,6 +1645,7 @@ namespace {
int maxGlyphs;
int currentPosition;
glyph_t previousGlyph;
+ QFontEngine *previousGlyphFontEngine;
QFixed minw;
QFixed softHyphenWidth;
@@ -1677,13 +1679,14 @@ namespace {
if (currentPosition > 0 &&
logClusters[currentPosition - 1] < glyphs.numGlyphs) {
previousGlyph = currentGlyph(); // needed to calculate right bearing later
+ previousGlyphFontEngine = fontEngine;
}
}
- inline void calculateRightBearing(glyph_t glyph)
+ inline void calculateRightBearing(QFontEngine *engine, glyph_t glyph)
{
qreal rb;
- fontEngine->getGlyphBearings(glyph, 0, &rb);
+ engine->getGlyphBearings(glyph, 0, &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
@@ -1696,13 +1699,13 @@ namespace {
{
if (currentPosition <= 0)
return;
- calculateRightBearing(currentGlyph());
+ calculateRightBearing(fontEngine, currentGlyph());
}
inline void calculateRightBearingForPreviousGlyph()
{
if (previousGlyph > 0)
- calculateRightBearing(previousGlyph);
+ calculateRightBearing(previousGlyphFontEngine, previousGlyph);
}
static const QFixed RightBearingNotCalculated;
diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h
index f74d4d4..57d449a 100644 index f74d4d4..57d449a 100644
--- a/src/gui/text/qtextlayout.h --- a/src/gui/text/qtextlayout.h

View File

@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,9,46,0 FILEVERSION 0,9,47,0
PRODUCTVERSION 0,9,46,0 PRODUCTVERSION 0,9,47,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileVersion", "0.9.46.0" VALUE "FileVersion", "0.9.47.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.9.46.0" VALUE "ProductVersion", "0.9.47.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,9,46,0 FILEVERSION 0,9,47,0
PRODUCTVERSION 0,9,46,0 PRODUCTVERSION 0,9,47,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -43,10 +43,10 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Telegram Messenger LLP" VALUE "CompanyName", "Telegram Messenger LLP"
VALUE "FileDescription", "Telegram Updater" VALUE "FileDescription", "Telegram Updater"
VALUE "FileVersion", "0.9.46.0" VALUE "FileVersion", "0.9.47.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "LegalCopyright", "Copyright (C) 2014-2016"
VALUE "ProductName", "Telegram Desktop" VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "0.9.46.0" VALUE "ProductVersion", "0.9.47.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#define BETA_VERSION_MACRO (0ULL) #define BETA_VERSION_MACRO (0ULL)
static constexpr int AppVersion = 9046; static constexpr int AppVersion = 9047;
static constexpr str_const AppVersionStr = "0.9.46"; static constexpr str_const AppVersionStr = "0.9.47";
static constexpr bool AppAlphaVersion = true; static constexpr bool AppAlphaVersion = true;
static constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; static constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO;

View File

@ -944,10 +944,14 @@ namespace internal {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
internal::BreakpadExceptionHandler = new google_breakpad::ExceptionHandler( internal::BreakpadExceptionHandler = new google_breakpad::ExceptionHandler(
dumpspath.toStdWString(), dumpspath.toStdWString(),
/*FilterCallback*/ 0, google_breakpad::ExceptionHandler::FilterCallback(nullptr),
internal::DumpCallback, internal::DumpCallback,
/*context*/ 0, (void*)nullptr, // callback_context
true google_breakpad::ExceptionHandler::HANDLER_ALL,
MINIDUMP_TYPE(MiniDumpNormal),
// MINIDUMP_TYPE(MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithProcessThreadData | MiniDumpWithFullMemoryInfo | MiniDumpWithUnloadedModules | MiniDumpWithFullAuxiliaryState | MiniDumpIgnoreInaccessibleMemory | MiniDumpWithTokenInformation),
(const wchar_t*)nullptr, // pipe_name
(const google_breakpad::CustomClientInfo*)nullptr
); );
#elif defined Q_OS_MAC // Q_OS_WIN #elif defined Q_OS_MAC // Q_OS_WIN
@ -968,11 +972,11 @@ namespace internal {
std::string handler = (cExeDir() + cExeName() + qsl("/Contents/Helpers/crashpad_handler")).toUtf8().constData(); std::string handler = (cExeDir() + cExeName() + qsl("/Contents/Helpers/crashpad_handler")).toUtf8().constData();
std::string database = QFile::encodeName(dumpspath).constData(); std::string database = QFile::encodeName(dumpspath).constData();
if (crashpad_client.StartHandler(base::FilePath(handler), if (crashpad_client.StartHandler(base::FilePath(handler),
base::FilePath(database), base::FilePath(database),
std::string(), std::string(),
ProcessAnnotations, ProcessAnnotations,
std::vector<std::string>(), std::vector<std::string>(),
false)) { false)) {
crashpad_client.UseHandler(); crashpad_client.UseHandler();
} }
#endif // else for MAC_USE_BREAKPAD #endif // else for MAC_USE_BREAKPAD

View File

@ -34,18 +34,14 @@ namespace {
const style::textStyle *_textStyle = nullptr; const style::textStyle *_textStyle = nullptr;
void _initDefault() { void initDefault() {
_textStyle = &st::defaultTextStyle; _textStyle = &st::defaultTextStyle;
} }
inline int32 _blockHeight(const ITextBlock *b, const style::font &font) { inline int32 countBlockHeight(const ITextBlock *b, const style::font &font) {
return (b->type() == TextBlockTSkip) ? static_cast<const SkipBlock*>(b)->height() : (_textStyle->lineHeight > font->height) ? _textStyle->lineHeight : font->height; return (b->type() == TextBlockTSkip) ? static_cast<const SkipBlock*>(b)->height() : (_textStyle->lineHeight > font->height) ? _textStyle->lineHeight : font->height;
} }
inline QFixed _blockRBearing(const ITextBlock *b) {
return (b->type() == TextBlockTText) ? static_cast<const TextBlock*>(b)->f_rbearing() : 0;
}
} // namespace } // namespace
const style::textStyle *textstyleCurrent() { const style::textStyle *textstyleCurrent() {
@ -908,7 +904,7 @@ public:
if (_t->isEmpty()) return; if (_t->isEmpty()) return;
_blocksSize = _t->_blocks.size(); _blocksSize = _t->_blocks.size();
if (!_textStyle) _initDefault(); if (!_textStyle) initDefault();
if (_p) { if (_p) {
_p->setFont(_t->_font->f); _p->setFont(_t->_font->f);
@ -955,8 +951,7 @@ public:
for (Text::TextBlocks::const_iterator i = _t->_blocks.cbegin(); i != e; ++i, ++blockIndex) { for (Text::TextBlocks::const_iterator i = _t->_blocks.cbegin(); i != e; ++i, ++blockIndex) {
ITextBlock *b = *i; ITextBlock *b = *i;
TextBlockType _btype = b->type(); TextBlockType _btype = b->type();
int32 blockHeight = _blockHeight(b, _t->_font); int32 blockHeight = countBlockHeight(b, _t->_font);
QFixed _rb = _blockRBearing(b);
if (_btype == TextBlockTNewline) { if (_btype == TextBlockTNewline) {
if (!_lineHeight) _lineHeight = blockHeight; if (!_lineHeight) _lineHeight = blockHeight;
@ -968,7 +963,7 @@ public:
_lineStart = nextStart; _lineStart = nextStart;
_lineStartBlock = blockIndex + 1; _lineStartBlock = blockIndex + 1;
last_rBearing = _rb; last_rBearing = b->f_rbearing();
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
_wLeft = _w - (b->f_width() - last_rBearing); _wLeft = _w - (b->f_width() - last_rBearing);
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) { if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) {
@ -983,10 +978,11 @@ public:
continue; continue;
} }
QFixed lpadding = b->f_lpadding(); auto b__f_lpadding = b->f_lpadding();
QFixed newWidthLeft = _wLeft - lpadding - last_rBearing - (last_rPadding + b->f_width() - _rb); auto b__f_rbearing = b->f_rbearing();
QFixed newWidthLeft = _wLeft - b__f_lpadding - last_rBearing - (last_rPadding + b->f_width() - b__f_rbearing);
if (newWidthLeft >= 0) { if (newWidthLeft >= 0) {
last_rBearing = _rb; last_rBearing = b__f_rbearing;
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
_wLeft = newWidthLeft; _wLeft = newWidthLeft;
@ -999,7 +995,7 @@ public:
if (_btype == TextBlockTText) { if (_btype == TextBlockTText) {
TextBlock *t = static_cast<TextBlock*>(b); TextBlock *t = static_cast<TextBlock*>(b);
if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line
last_rPadding += lpadding; last_rPadding += b__f_lpadding;
_lineHeight = qMax(_lineHeight, blockHeight); _lineHeight = qMax(_lineHeight, blockHeight);
@ -1010,14 +1006,14 @@ public:
QFixed f_wLeft = _wLeft; // vars for saving state of the last word start QFixed f_wLeft = _wLeft; // vars for saving state of the last word start
int32 f_lineHeight = _lineHeight; // f points to the last word-start element of t->_words int32 f_lineHeight = _lineHeight; // f points to the last word-start element of t->_words
for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), en = t->_words.cend(), f = j; j != en; ++j) { for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), en = t->_words.cend(), f = j; j != en; ++j) {
bool wordEndsHere = (j->width >= 0); bool wordEndsHere = (j->f_width() >= 0);
QFixed j_width = wordEndsHere ? j->width : -j->width; QFixed j_width = wordEndsHere ? j->f_width() : -j->f_width();
QFixed newWidthLeft = _wLeft - lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing()); QFixed newWidthLeft = _wLeft - b__f_lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing());
lpadding = 0; b__f_lpadding = 0;
if (newWidthLeft >= 0) { if (newWidthLeft >= 0) {
last_rBearing = j->f_rbearing(); last_rBearing = j->f_rbearing();
last_rPadding = j->rpadding; last_rPadding = j->f_rpadding();
_wLeft = newWidthLeft; _wLeft = newWidthLeft;
_lineHeight = qMax(_lineHeight, blockHeight); _lineHeight = qMax(_lineHeight, blockHeight);
@ -1042,16 +1038,16 @@ public:
j = f; j = f;
_wLeft = f_wLeft; _wLeft = f_wLeft;
_lineHeight = f_lineHeight; _lineHeight = f_lineHeight;
j_width = (j->width >= 0) ? j->width : -j->width; j_width = (j->f_width() >= 0) ? j->f_width() : -j->f_width();
} }
if (!drawLine(elidedLine ? ((j + 1 == en) ? _blockEnd(_t, i, e) : (j + 1)->from) : j->from, i, e)) return; if (!drawLine(elidedLine ? ((j + 1 == en) ? _blockEnd(_t, i, e) : (j + 1)->from()) : j->from(), i, e)) return;
_y += _lineHeight; _y += _lineHeight;
_lineHeight = qMax(0, blockHeight); _lineHeight = qMax(0, blockHeight);
_lineStart = j->from; _lineStart = j->from();
_lineStartBlock = blockIndex; _lineStartBlock = blockIndex;
last_rBearing = j->f_rbearing(); last_rBearing = j->f_rbearing();
last_rPadding = j->rpadding; last_rPadding = j->f_rpadding();
_wLeft = _w - (j_width - last_rBearing); _wLeft = _w - (j_width - last_rBearing);
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) { if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) {
_wLeft -= _elideRemoveFromEnd; _wLeft -= _elideRemoveFromEnd;
@ -1076,7 +1072,7 @@ public:
_lineStart = b->from(); _lineStart = b->from();
_lineStartBlock = blockIndex; _lineStartBlock = blockIndex;
last_rBearing = _rb; last_rBearing = b__f_rbearing;
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
_wLeft = _w - (b->f_width() - last_rBearing); _wLeft = _w - (b->f_width() - last_rBearing);
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) { if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) {
@ -2404,7 +2400,7 @@ Text &Text::operator=(Text &&other) {
} }
void Text::setText(style::font font, const QString &text, const TextParseOptions &options) { void Text::setText(style::font font, const QString &text, const TextParseOptions &options) {
if (!_textStyle) _initDefault(); if (!_textStyle) initDefault();
_font = font; _font = font;
clear(); clear();
{ {
@ -2423,9 +2419,7 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) {
for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) {
ITextBlock *b = *i; ITextBlock *b = *i;
TextBlockType _btype = b->type(); TextBlockType _btype = b->type();
int32 blockHeight = _blockHeight(b, _font); int32 blockHeight = countBlockHeight(b, _font);
QFixed _rb = _blockRBearing(b);
if (_btype == TextBlockTNewline) { if (_btype == TextBlockTNewline) {
if (!lineHeight) lineHeight = blockHeight; if (!lineHeight) lineHeight = blockHeight;
if (initial) { if (initial) {
@ -2444,7 +2438,7 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) {
_minHeight += lineHeight; _minHeight += lineHeight;
lineHeight = 0; lineHeight = 0;
last_rBearing = _rb; last_rBearing = b->f_rbearing();
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
if (_maxWidth < _width) { if (_maxWidth < _width) {
_maxWidth = _width; _maxWidth = _width;
@ -2453,11 +2447,13 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) {
continue; continue;
} }
auto b__f_rbearing = b->f_rbearing(); // cache
_width += b->f_lpadding(); _width += b->f_lpadding();
_width += last_rBearing + (last_rPadding + b->f_width() - _rb); _width += last_rBearing + (last_rPadding + b->f_width() - b__f_rbearing);
lineHeight = qMax(lineHeight, blockHeight); lineHeight = qMax(lineHeight, blockHeight);
last_rBearing = _rb; last_rBearing = b__f_rbearing;
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
continue; continue;
} }
@ -2473,7 +2469,7 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) {
} }
} }
if (_width > 0) { if (_width > 0) {
if (!lineHeight) lineHeight = _blockHeight(_blocks.back(), _font); if (!lineHeight) lineHeight = countBlockHeight(_blocks.back(), _font);
_minHeight += lineHeight; _minHeight += lineHeight;
if (_maxWidth < _width) { if (_maxWidth < _width) {
_maxWidth = _width; _maxWidth = _width;
@ -2482,7 +2478,7 @@ void Text::recountNaturalSize(bool initial, Qt::LayoutDirection optionsDir) {
} }
void Text::setMarkedText(style::font font, const QString &text, const EntitiesInText &entities, const TextParseOptions &options) { void Text::setMarkedText(style::font font, const QString &text, const EntitiesInText &entities, const TextParseOptions &options) {
if (!_textStyle) _initDefault(); if (!_textStyle) initDefault();
_font = font; _font = font;
clear(); clear();
{ {
@ -2644,11 +2640,10 @@ int32 Text::countWidth(int32 w) const {
for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) {
ITextBlock *b = *i; ITextBlock *b = *i;
TextBlockType _btype = b->type(); TextBlockType _btype = b->type();
int32 blockHeight = _blockHeight(b, _font); int32 blockHeight = countBlockHeight(b, _font);
QFixed _rb = _blockRBearing(b);
if (_btype == TextBlockTNewline) { if (_btype == TextBlockTNewline) {
last_rBearing = _rb; last_rBearing = b->f_rbearing();
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
if (widthLeft < minWidthLeft) { if (widthLeft < minWidthLeft) {
minWidthLeft = widthLeft; minWidthLeft = widthLeft;
@ -2658,10 +2653,11 @@ int32 Text::countWidth(int32 w) const {
longWordLine = true; longWordLine = true;
continue; continue;
} }
QFixed lpadding = b->f_lpadding(); auto b__f_lpadding = b->f_lpadding();
QFixed newWidthLeft = widthLeft - lpadding - last_rBearing - (last_rPadding + b->f_width() - _rb); auto b__f_rbearing = b->f_rbearing(); // cache
QFixed newWidthLeft = widthLeft - b__f_lpadding - last_rBearing - (last_rPadding + b->f_width() - b__f_rbearing);
if (newWidthLeft >= 0) { if (newWidthLeft >= 0) {
last_rBearing = _rb; last_rBearing = b__f_rbearing;
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
widthLeft = newWidthLeft; widthLeft = newWidthLeft;
@ -2672,7 +2668,7 @@ int32 Text::countWidth(int32 w) const {
if (_btype == TextBlockTText) { if (_btype == TextBlockTText) {
TextBlock *t = static_cast<TextBlock*>(b); TextBlock *t = static_cast<TextBlock*>(b);
if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line
last_rPadding += lpadding; last_rPadding += b__f_lpadding;
longWordLine = false; longWordLine = false;
continue; continue;
@ -2680,14 +2676,14 @@ int32 Text::countWidth(int32 w) const {
QFixed f_wLeft = widthLeft; QFixed f_wLeft = widthLeft;
for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), e = t->_words.cend(), f = j; j != e; ++j) { for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), e = t->_words.cend(), f = j; j != e; ++j) {
bool wordEndsHere = (j->width >= 0); bool wordEndsHere = (j->f_width() >= 0);
QFixed j_width = wordEndsHere ? j->width : -j->width; QFixed j_width = wordEndsHere ? j->f_width() : -j->f_width();
QFixed newWidthLeft = widthLeft - lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing()); QFixed newWidthLeft = widthLeft - b__f_lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing());
lpadding = 0; b__f_lpadding = 0;
if (newWidthLeft >= 0) { if (newWidthLeft >= 0) {
last_rBearing = j->f_rbearing(); last_rBearing = j->f_rbearing();
last_rPadding = j->rpadding; last_rPadding = j->f_rpadding();
widthLeft = newWidthLeft; widthLeft = newWidthLeft;
if (wordEndsHere) { if (wordEndsHere) {
@ -2703,11 +2699,11 @@ int32 Text::countWidth(int32 w) const {
if (f != j) { if (f != j) {
j = f; j = f;
widthLeft = f_wLeft; widthLeft = f_wLeft;
j_width = (j->width >= 0) ? j->width : -j->width; j_width = (j->f_width() >= 0) ? j->f_width() : -j->f_width();
} }
last_rBearing = j->f_rbearing(); last_rBearing = j->f_rbearing();
last_rPadding = j->rpadding; last_rPadding = j->f_rpadding();
if (widthLeft < minWidthLeft) { if (widthLeft < minWidthLeft) {
minWidthLeft = widthLeft; minWidthLeft = widthLeft;
} }
@ -2720,7 +2716,7 @@ int32 Text::countWidth(int32 w) const {
continue; continue;
} }
last_rBearing = _rb; last_rBearing = b__f_rbearing;
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
if (widthLeft < minWidthLeft) { if (widthLeft < minWidthLeft) {
minWidthLeft = widthLeft; minWidthLeft = widthLeft;
@ -2750,24 +2746,24 @@ int32 Text::countHeight(int32 w) const {
for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) { for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); i != e; ++i) {
ITextBlock *b = *i; ITextBlock *b = *i;
TextBlockType _btype = b->type(); TextBlockType _btype = b->type();
int32 blockHeight = _blockHeight(b, _font); int32 blockHeight = countBlockHeight(b, _font);
QFixed _rb = _blockRBearing(b);
if (_btype == TextBlockTNewline) { if (_btype == TextBlockTNewline) {
if (!lineHeight) lineHeight = blockHeight; if (!lineHeight) lineHeight = blockHeight;
result += lineHeight; result += lineHeight;
lineHeight = 0; lineHeight = 0;
last_rBearing = _rb; last_rBearing = b->f_rbearing();
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
widthLeft = width - (b->f_width() - last_rBearing); widthLeft = width - (b->f_width() - last_rBearing);
longWordLine = true; longWordLine = true;
continue; continue;
} }
QFixed lpadding = b->f_lpadding(); auto b__f_lpadding = b->f_lpadding();
QFixed newWidthLeft = widthLeft - lpadding - last_rBearing - (last_rPadding + b->f_width() - _rb); auto b__f_rbearing = b->f_rbearing();
QFixed newWidthLeft = widthLeft - b__f_lpadding - last_rBearing - (last_rPadding + b->f_width() - b__f_rbearing);
if (newWidthLeft >= 0) { if (newWidthLeft >= 0) {
last_rBearing = _rb; last_rBearing = b__f_rbearing;
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
widthLeft = newWidthLeft; widthLeft = newWidthLeft;
@ -2780,7 +2776,7 @@ int32 Text::countHeight(int32 w) const {
if (_btype == TextBlockTText) { if (_btype == TextBlockTText) {
TextBlock *t = static_cast<TextBlock*>(b); TextBlock *t = static_cast<TextBlock*>(b);
if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line
last_rPadding += lpadding; last_rPadding += b__f_lpadding;
lineHeight = qMax(lineHeight, blockHeight); lineHeight = qMax(lineHeight, blockHeight);
@ -2791,14 +2787,14 @@ int32 Text::countHeight(int32 w) const {
QFixed f_wLeft = widthLeft; QFixed f_wLeft = widthLeft;
int32 f_lineHeight = lineHeight; int32 f_lineHeight = lineHeight;
for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), e = t->_words.cend(), f = j; j != e; ++j) { for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), e = t->_words.cend(), f = j; j != e; ++j) {
bool wordEndsHere = (j->width >= 0); bool wordEndsHere = (j->f_width() >= 0);
QFixed j_width = wordEndsHere ? j->width : -j->width; QFixed j_width = wordEndsHere ? j->f_width() : -j->f_width();
QFixed newWidthLeft = widthLeft - lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing()); QFixed newWidthLeft = widthLeft - b__f_lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing());
lpadding = 0; b__f_lpadding = 0;
if (newWidthLeft >= 0) { if (newWidthLeft >= 0) {
last_rBearing = j->f_rbearing(); last_rBearing = j->f_rbearing();
last_rPadding = j->rpadding; last_rPadding = j->f_rpadding();
widthLeft = newWidthLeft; widthLeft = newWidthLeft;
lineHeight = qMax(lineHeight, blockHeight); lineHeight = qMax(lineHeight, blockHeight);
@ -2818,13 +2814,13 @@ int32 Text::countHeight(int32 w) const {
j = f; j = f;
widthLeft = f_wLeft; widthLeft = f_wLeft;
lineHeight = f_lineHeight; lineHeight = f_lineHeight;
j_width = (j->width >= 0) ? j->width : -j->width; j_width = (j->f_width() >= 0) ? j->f_width() : -j->f_width();
} }
result += lineHeight; result += lineHeight;
lineHeight = qMax(0, blockHeight); lineHeight = qMax(0, blockHeight);
last_rBearing = j->f_rbearing(); last_rBearing = j->f_rbearing();
last_rPadding = j->rpadding; last_rPadding = j->f_rpadding();
widthLeft = width - (j_width - last_rBearing); widthLeft = width - (j_width - last_rBearing);
longWordLine = true; longWordLine = true;
@ -2837,7 +2833,7 @@ int32 Text::countHeight(int32 w) const {
result += lineHeight; result += lineHeight;
lineHeight = qMax(0, blockHeight); lineHeight = qMax(0, blockHeight);
last_rBearing = _rb; last_rBearing = b__f_rbearing;
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
widthLeft = width - (b->f_width() - last_rBearing); widthLeft = width - (b->f_width() - last_rBearing);

View File

@ -32,10 +32,11 @@ struct ScriptLine {
QFixed textWidth; QFixed textWidth;
}; };
// All members finished with "_" are internal.
struct LineBreakHelper struct LineBreakHelper
{ {
LineBreakHelper() LineBreakHelper()
: glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0) : glyphCount(0), maxGlyphs(INT_MAX), currentPosition(0), fontEngine(0), logClusters(0)
{ {
} }
@ -48,7 +49,9 @@ struct LineBreakHelper
int glyphCount; int glyphCount;
int maxGlyphs; int maxGlyphs;
int currentPosition; int currentPosition;
glyph_t previousGlyph;
glyph_t previousGlyph_ = 0;
QFontEngine *previousFontEngine_ = nullptr;
QFixed rightBearing; QFixed rightBearing;
@ -65,35 +68,71 @@ struct LineBreakHelper
inline void saveCurrentGlyph() inline void saveCurrentGlyph()
{ {
previousGlyph = 0;
if (currentPosition > 0 && if (currentPosition > 0 &&
logClusters[currentPosition - 1] < glyphs.numGlyphs) { logClusters[currentPosition - 1] < glyphs.numGlyphs) {
previousGlyph = currentGlyph(); // needed to calculate right bearing later previousGlyph_ = currentGlyph(); // needed to calculate right bearing later
previousFontEngine_ = fontEngine;
} else {
previousGlyph_ = 0;
previousFontEngine_ = nullptr;
} }
} }
inline void adjustRightBearing(glyph_t glyph) inline void calculateRightBearing(QFontEngine *engine, glyph_t glyph)
{ {
qreal rb; qreal rb;
fontEngine->getGlyphBearings(glyph, 0, &rb); engine->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; logClusters[currentPosition - 1] < glyphs.numGlyphs) {
adjustRightBearing(currentGlyph()); calculateRightBearing(fontEngine, currentGlyph());
} else {
rightBearing = 0;
}
} }
inline void adjustPreviousRightBearing() inline void calculateRightBearingForPreviousGlyph()
{ {
if (previousGlyph > 0) if (previousGlyph_ > 0) {
adjustRightBearing(previousGlyph); calculateRightBearing(previousFontEngine_, previousGlyph_);
} else {
rightBearing = 0;
}
}
// We always calculate the right bearing right before it is needed.
// So we don't need caching / optimizations referred to delayed right bearing calculations.
//static const QFixed RightBearingNotCalculated;
//inline void resetRightBearing()
//{
// rightBearing = RightBearingNotCalculated;
//}
// 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);
static inline void addNextCluster(int &pos, int end, ScriptLine &line, int &glyphCount, static inline void addNextCluster(int &pos, int end, ScriptLine &line, int &glyphCount,
const QScriptItem &current, const unsigned short *logClusters, const QScriptItem &current, const unsigned short *logClusters,
const QGlyphLayout &glyphs) const QGlyphLayout &glyphs)
@ -127,8 +166,6 @@ public:
void parseWords(QFixed minResizeWidth, int32 blockFrom) { void parseWords(QFixed minResizeWidth, int32 blockFrom) {
LineBreakHelper lbh; LineBreakHelper lbh;
lbh.maxGlyphs = INT_MAX;
int item = -1; int item = -1;
int newItem = eng->findItem(0); int newItem = eng->findItem(0);
@ -137,10 +174,8 @@ public:
const QCharAttributes *attributes = eng->attributes(); const QCharAttributes *attributes = eng->attributes();
if (!attributes) if (!attributes)
return; return;
lbh.currentPosition = 0;
int end = 0; int end = 0;
lbh.logClusters = eng->layoutData->logClustersPtr; lbh.logClusters = eng->layoutData->logClustersPtr;
lbh.previousGlyph = 0;
block->_lpadding = 0; block->_lpadding = 0;
block->_words.clear(); block->_words.clear();
@ -180,7 +215,7 @@ public:
if (block->_words.isEmpty()) { if (block->_words.isEmpty()) {
block->_lpadding = lbh.spaceData.textWidth; block->_lpadding = lbh.spaceData.textWidth;
} else { } else {
block->_words.back().rpadding += lbh.spaceData.textWidth; block->_words.back().add_rpadding(lbh.spaceData.textWidth);
block->_width += lbh.spaceData.textWidth; block->_width += lbh.spaceData.textWidth;
} }
lbh.spaceData.length = 0; lbh.spaceData.length = 0;
@ -199,8 +234,8 @@ public:
if (lbh.currentPosition >= eng->layoutData->string.length() if (lbh.currentPosition >= eng->layoutData->string.length()
|| attributes[lbh.currentPosition].whiteSpace || attributes[lbh.currentPosition].whiteSpace
|| isLineBreak(attributes, lbh.currentPosition)) { || isLineBreak(attributes, lbh.currentPosition)) {
lbh.adjustRightBearing(); lbh.calculateRightBearing();
block->_words.push_back(TextWord(wordStart + blockFrom, lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing))); block->_words.push_back(TextWord(wordStart + blockFrom, lbh.tmpData.textWidth, -lbh.negativeRightBearing()));
block->_width += lbh.tmpData.textWidth; block->_width += lbh.tmpData.textWidth;
lbh.tmpData.textWidth = 0; lbh.tmpData.textWidth = 0;
lbh.tmpData.length = 0; lbh.tmpData.length = 0;
@ -209,8 +244,8 @@ public:
} else if (attributes[lbh.currentPosition].graphemeBoundary) { } else if (attributes[lbh.currentPosition].graphemeBoundary) {
if (!addingEachGrapheme && lbh.tmpData.textWidth > minResizeWidth) { if (!addingEachGrapheme && lbh.tmpData.textWidth > minResizeWidth) {
if (lastGraphemeBoundaryPosition >= 0) { if (lastGraphemeBoundaryPosition >= 0) {
lbh.adjustPreviousRightBearing(); lbh.calculateRightBearingForPreviousGlyph();
block->_words.push_back(TextWord(wordStart + blockFrom, -lastGraphemeBoundaryLine.textWidth, qMin(QFixed(), lbh.rightBearing))); block->_words.push_back(TextWord(wordStart + blockFrom, -lastGraphemeBoundaryLine.textWidth, -lbh.negativeRightBearing()));
block->_width += lastGraphemeBoundaryLine.textWidth; block->_width += lastGraphemeBoundaryLine.textWidth;
lbh.tmpData.textWidth -= lastGraphemeBoundaryLine.textWidth; lbh.tmpData.textWidth -= lastGraphemeBoundaryLine.textWidth;
lbh.tmpData.length -= lastGraphemeBoundaryLine.length; lbh.tmpData.length -= lastGraphemeBoundaryLine.length;
@ -219,8 +254,8 @@ public:
addingEachGrapheme = true; addingEachGrapheme = true;
} }
if (addingEachGrapheme) { if (addingEachGrapheme) {
lbh.adjustRightBearing(); lbh.calculateRightBearing();
block->_words.push_back(TextWord(wordStart + blockFrom, -lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing))); block->_words.push_back(TextWord(wordStart + blockFrom, -lbh.tmpData.textWidth, -lbh.negativeRightBearing()));
block->_width += lbh.tmpData.textWidth; block->_width += lbh.tmpData.textWidth;
lbh.tmpData.textWidth = 0; lbh.tmpData.textWidth = 0;
lbh.tmpData.length = 0; lbh.tmpData.length = 0;
@ -239,7 +274,7 @@ public:
if (block->_words.isEmpty()) { if (block->_words.isEmpty()) {
block->_rpadding = 0; block->_rpadding = 0;
} else { } else {
block->_rpadding = block->_words.back().rpadding; block->_rpadding = block->_words.back().f_rpadding();
block->_width -= block->_rpadding; block->_width -= block->_rpadding;
block->_words.squeeze(); block->_words.squeeze();
} }
@ -261,6 +296,10 @@ private:
}; };
QFixed ITextBlock::f_rbearing() const {
return (type() == TextBlockTText) ? static_cast<const TextBlock*>(this)->real_f_rbearing() : 0;
}
TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex) : ITextBlock(font, str, from, length, flags, color, lnkIndex) { TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex) : ITextBlock(font, str, from, length, flags, color, lnkIndex) {
_flags |= ((TextBlockTText & 0x0F) << 8); _flags |= ((TextBlockTText & 0x0F) << 8);
if (length) { if (length) {

View File

@ -75,6 +75,9 @@ public:
return _rpadding; return _rpadding;
} }
// Should be virtual, but optimized throught type() call.
QFixed f_rbearing() const;
uint16 lnkIndex() const { uint16 lnkIndex() const {
return (_flags >> 12) & 0xFFFF; return (_flags >> 12) & 0xFFFF;
} }
@ -132,27 +135,41 @@ private:
friend class TextPainter; friend class TextPainter;
}; };
struct TextWord { class TextWord {
TextWord() { public:
TextWord() = default;
TextWord(uint16 from, QFixed width, QFixed rbearing, QFixed rpadding = 0)
: _from(from)
, _rbearing(rbearing.value() > 0x7FFF ? 0x7FFF : (rbearing.value() < -0x7FFF ? -0x7FFF : rbearing.value()))
, _width(width)
, _rpadding(rpadding) {
} }
TextWord(uint16 from, QFixed width, QFixed rbearing, QFixed rpadding = 0) : from(from), uint16 from() const {
_rbearing(rbearing.value() > 0x7FFF ? 0x7FFF : (rbearing.value() < -0x7FFF ? -0x7FFF : rbearing.value())), width(width), rpadding(rpadding) { return _from;
} }
QFixed f_rbearing() const { QFixed f_rbearing() const {
return QFixed::fromFixed(_rbearing); return QFixed::fromFixed(_rbearing);
} }
uint16 from; QFixed f_width() const {
int16 _rbearing; return _width;
QFixed width, rpadding; }
QFixed f_rpadding() const {
return _rpadding;
}
void add_rpadding(QFixed padding) {
_rpadding += padding;
}
private:
uint16 _from = 0;
QFixed _width, _rpadding;
int16 _rbearing = 0;
}; };
class TextBlock : public ITextBlock { class TextBlock : public ITextBlock {
public: public:
QFixed f_rbearing() const {
return _words.isEmpty() ? 0 : _words.back().f_rbearing();
}
ITextBlock *clone() const { ITextBlock *clone() const {
return new TextBlock(*this); return new TextBlock(*this);
} }
@ -161,6 +178,11 @@ private:
TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex); TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex);
friend class ITextBlock;
QFixed real_f_rbearing() const {
return _words.isEmpty() ? 0 : _words.back().f_rbearing();
}
typedef QVector<TextWord> TextWords; typedef QVector<TextWord> TextWords;
TextWords _words; TextWords _words;

View File

@ -75,7 +75,7 @@
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile> <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalOptions>/Zm152 %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/Zm152 /Zo </AdditionalOptions>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError> <TreatWarningAsError>true</TreatWarningAsError>
</ClCompile> </ClCompile>
@ -107,7 +107,7 @@
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<AdditionalOptions>/Zm110 %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/Zm152 /Zo </AdditionalOptions>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError> <TreatWarningAsError>true</TreatWarningAsError>
</ClCompile> </ClCompile>
@ -140,7 +140,7 @@
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion> <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<AdditionalOptions>/Zm110 %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/Zm152 /Zo </AdditionalOptions>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError> <TreatWarningAsError>true</TreatWarningAsError>
</ClCompile> </ClCompile>

View File

@ -2023,7 +2023,7 @@
SDKROOT = macosx; SDKROOT = macosx;
SYMROOT = ./../Mac; SYMROOT = ./../Mac;
TDESKTOP_MAJOR_VERSION = 0.9; TDESKTOP_MAJOR_VERSION = 0.9;
TDESKTOP_VERSION = 0.9.46; TDESKTOP_VERSION = 0.9.47;
}; };
name = Release; name = Release;
}; };
@ -2164,7 +2164,7 @@
SDKROOT = macosx; SDKROOT = macosx;
SYMROOT = ./../Mac; SYMROOT = ./../Mac;
TDESKTOP_MAJOR_VERSION = 0.9; TDESKTOP_MAJOR_VERSION = 0.9;
TDESKTOP_VERSION = 0.9.46; TDESKTOP_VERSION = 0.9.47;
}; };
name = Debug; name = Debug;
}; };

View File

@ -1,6 +1,6 @@
AppVersion 9046 AppVersion 9047
AppVersionStrMajor 0.9 AppVersionStrMajor 0.9
AppVersionStrSmall 0.9.46 AppVersionStrSmall 0.9.47
AppVersionStr 0.9.46 AppVersionStr 0.9.47
AlphaChannel 1 AlphaChannel 1
BetaVersion 0 BetaVersion 0