Use quote instead of paragraph for quotes.

This commit is contained in:
John Preston 2023-10-13 18:23:56 +04:00
parent 48012d7f4a
commit 9eb9fcf043
9 changed files with 275 additions and 240 deletions

View file

@ -19,7 +19,7 @@ TextPalette {
linkAlwaysActive: bool; linkAlwaysActive: bool;
} }
ParagraphStyle { QuoteStyle {
padding: margins; padding: margins;
verticalSkip: pixels; verticalSkip: pixels;
header: pixels; header: pixels;
@ -35,8 +35,8 @@ TextStyle {
font: font; font: font;
linkUnderline: int; linkUnderline: int;
lineHeight: pixels; lineHeight: pixels;
blockquote: ParagraphStyle; blockquote: QuoteStyle;
pre: ParagraphStyle; pre: QuoteStyle;
} }
kLinkUnderlineNever: 0; kLinkUnderlineNever: 0;
@ -65,14 +65,14 @@ defaultTextPalette: TextPalette {
selectSpoilerFg: msgInDateFgSelected; selectSpoilerFg: msgInDateFgSelected;
selectOverlay: msgSelectOverlay; selectOverlay: msgSelectOverlay;
} }
defaultParagraphStyle: ParagraphStyle { defaultQuoteStyle: QuoteStyle {
} }
defaultTextStyle: TextStyle { defaultTextStyle: TextStyle {
font: normalFont; font: normalFont;
linkUnderline: kLinkUnderlineActive; linkUnderline: kLinkUnderlineActive;
lineHeight: 0px; lineHeight: 0px;
blockquote: defaultParagraphStyle; blockquote: defaultQuoteStyle;
pre: defaultParagraphStyle; pre: defaultQuoteStyle;
} }
semiboldTextStyle: TextStyle(defaultTextStyle) { semiboldTextStyle: TextStyle(defaultTextStyle) {
font: semiboldFont; font: semiboldFont;

View file

@ -185,9 +185,9 @@ GeometryDescriptor SimpleGeometry(
} }
}; };
void ValidateBlockPaintCache( void ValidateQuotePaintCache(
BlockPaintCache &cache, QuotePaintCache &cache,
const style::ParagraphStyle &st) { const style::QuoteStyle &st) {
const auto icon = st.icon.empty() ? nullptr : &st.icon; const auto icon = st.icon.empty() ? nullptr : &st.icon;
if (!cache.corners.isNull() if (!cache.corners.isNull()
&& cache.bgCached == cache.bg && cache.bgCached == cache.bg
@ -248,11 +248,11 @@ void ValidateBlockPaintCache(
cache.corners = std::move(image); cache.corners = std::move(image);
} }
void FillBlockPaint( void FillQuotePaint(
QPainter &p, QPainter &p,
QRect rect, QRect rect,
const BlockPaintCache &cache, const QuotePaintCache &cache,
const style::ParagraphStyle &st, const style::QuoteStyle &st,
SkipBlockPaintParts parts) { SkipBlockPaintParts parts) {
const auto &image = cache.corners; const auto &image = cache.corners;
const auto ratio = int(image.devicePixelRatio()); const auto ratio = int(image.devicePixelRatio());
@ -431,18 +431,18 @@ void String::recountNaturalSize(
} }
}; };
auto pindex = paragraphIndex(nullptr); auto qindex = quoteIndex(nullptr);
auto paragraph = paragraphByIndex(pindex); auto quote = quoteByIndex(qindex);
auto ppadding = paragraphPadding(paragraph); auto qpadding = quotePadding(quote);
auto pminwidth = paragraphMinWidth(paragraph); auto qminwidth = quoteMinWidth(quote);
auto pmaxwidth = QFixed(pminwidth); auto qmaxwidth = QFixed(qminwidth);
auto poldheight = 0; auto qoldheight = 0;
_maxWidth = 0; _maxWidth = 0;
_minHeight = ppadding.top(); _minHeight = qpadding.top();
auto lineHeight = 0; auto lineHeight = 0;
auto maxWidth = QFixed(); auto maxWidth = QFixed();
auto width = QFixed(pminwidth); auto width = QFixed(qminwidth);
auto last_rBearing = QFixed(); auto last_rBearing = QFixed();
auto last_rPadding = QFixed(); auto last_rPadding = QFixed();
for (auto &block : _blocks) { for (auto &block : _blocks) {
@ -453,21 +453,24 @@ void String::recountNaturalSize(
if (!lineHeight) { if (!lineHeight) {
lineHeight = blockHeight; lineHeight = blockHeight;
} }
const auto index = paragraphIndex(b); accumulate_max(maxWidth, width);
if (pindex != index) { accumulate_max(qmaxwidth, width);
_minHeight += ppadding.bottom();
if (paragraph) { const auto index = quoteIndex(b);
paragraph->maxWidth = pmaxwidth.ceil().toInt(); if (qindex != index) {
paragraph->minHeight = _minHeight - poldheight; _minHeight += qpadding.bottom();
if (quote) {
quote->maxWidth = qmaxwidth.ceil().toInt();
quote->minHeight = _minHeight - qoldheight;
} }
poldheight = _minHeight; qoldheight = _minHeight;
pindex = index; qindex = index;
paragraph = paragraphByIndex(pindex); quote = quoteByIndex(qindex);
ppadding = paragraphPadding(paragraph); qpadding = quotePadding(quote);
pminwidth = paragraphMinWidth(paragraph); qminwidth = quoteMinWidth(quote);
pmaxwidth = pminwidth; qmaxwidth = qminwidth;
_minHeight += ppadding.top(); _minHeight += qpadding.top();
ppadding.setTop(0); qpadding.setTop(0);
} }
if (initial) { if (initial) {
computeParagraphDirection(b->position()); computeParagraphDirection(b->position());
@ -480,9 +483,7 @@ void String::recountNaturalSize(
last_rBearing = 0;// b->f_rbearing(); (0 for newline) last_rBearing = 0;// b->f_rbearing(); (0 for newline)
last_rPadding = 0;// b->f_rpadding(); (0 for newline) last_rPadding = 0;// b->f_rpadding(); (0 for newline)
accumulate_max(maxWidth, width); width = qminwidth;
accumulate_max(pmaxwidth, width);
width = pminwidth;
// + (b->f_width() - last_rBearing); (0 for newline) // + (b->f_width() - last_rBearing); (0 for newline)
continue; continue;
} }
@ -497,7 +498,7 @@ void String::recountNaturalSize(
// for all the blocks to fit on their line we check each block, even the // for all the blocks to fit on their line we check each block, even the
// intermediate one with a large negative right bearing. // intermediate one with a large negative right bearing.
accumulate_max(maxWidth, width); accumulate_max(maxWidth, width);
accumulate_max(pmaxwidth, width); accumulate_max(qmaxwidth, width);
width += last_rBearing + (last_rPadding + b->f_width() - b__f_rbearing); width += last_rBearing + (last_rPadding + b->f_width() - b__f_rbearing);
lineHeight = qMax(lineHeight, blockHeight); lineHeight = qMax(lineHeight, blockHeight);
@ -513,17 +514,17 @@ void String::recountNaturalSize(
if (!lineHeight) { if (!lineHeight) {
lineHeight = CountBlockHeight(_blocks.back().get(), _st); lineHeight = CountBlockHeight(_blocks.back().get(), _st);
} }
_minHeight += ppadding.top() + lineHeight + ppadding.bottom(); _minHeight += qpadding.top() + lineHeight + qpadding.bottom();
accumulate_max(maxWidth, width); accumulate_max(maxWidth, width);
accumulate_max(pmaxwidth, width); accumulate_max(qmaxwidth, width);
} }
_maxWidth = maxWidth.ceil().toInt(); _maxWidth = maxWidth.ceil().toInt();
if (paragraph) { if (quote) {
paragraph->maxWidth = pmaxwidth.ceil().toInt(); quote->maxWidth = qmaxwidth.ceil().toInt();
paragraph->minHeight = _minHeight - poldheight; quote->minHeight = _minHeight - qoldheight;
_endsWithParagraphDetails = true; _endsWithQuote = true;
} else { } else {
_endsWithParagraphDetails = false; _endsWithQuote = false;
} }
} }
@ -674,7 +675,7 @@ bool String::updateSkipBlock(int width, int height) {
} }
_text.resize(block->position()); _text.resize(block->position());
_blocks.pop_back(); _blocks.pop_back();
} else if (_endsWithParagraphDetails) { } else if (_endsWithQuote) {
_text.push_back(QChar::LineFeed); _text.push_back(QChar::LineFeed);
_blocks.push_back(Block::Newline( _blocks.push_back(Block::Newline(
_st->font, _st->font,
@ -764,10 +765,10 @@ void String::enumerateLines(
Callback callback) const { Callback callback) const {
const auto width = QFixed(std::max(w, _minResizeWidth)); const auto width = QFixed(std::max(w, _minResizeWidth));
auto pindex = paragraphIndex(nullptr); auto qindex = quoteIndex(nullptr);
auto paragraph = paragraphByIndex(pindex); auto quote = quoteByIndex(qindex);
auto ppadding = paragraphPadding(paragraph); auto qpadding = quotePadding(quote);
auto widthLeft = width - ppadding.left() - ppadding.right(); auto widthLeft = width - qpadding.left() - qpadding.right();
auto lineHeight = 0; auto lineHeight = 0;
auto last_rBearing = QFixed(); auto last_rBearing = QFixed();
auto last_rPadding = QFixed(); auto last_rPadding = QFixed();
@ -780,15 +781,15 @@ void String::enumerateLines(
if (!lineHeight) { if (!lineHeight) {
lineHeight = blockHeight; lineHeight = blockHeight;
} }
lineHeight += ppadding.top(); lineHeight += qpadding.top();
const auto index = paragraphIndex(b.get()); const auto index = quoteIndex(b.get());
if (pindex != index) { if (qindex != index) {
lineHeight += ppadding.bottom(); lineHeight += qpadding.bottom();
pindex = index; qindex = index;
paragraph = paragraphByIndex(pindex); quote = quoteByIndex(qindex);
ppadding = paragraphPadding(paragraph); qpadding = quotePadding(quote);
} else { } else {
ppadding.setTop(0); qpadding.setTop(0);
} }
callback(width - widthLeft, lineHeight); callback(width - widthLeft, lineHeight);
@ -796,7 +797,7 @@ void String::enumerateLines(
lineHeight = 0; lineHeight = 0;
last_rBearing = 0;// b->f_rbearing(); (0 for newline) last_rBearing = 0;// b->f_rbearing(); (0 for newline)
last_rPadding = 0;// b->f_rpadding(); (0 for newline) last_rPadding = 0;// b->f_rpadding(); (0 for newline)
widthLeft = width - ppadding.left() - ppadding.right(); widthLeft = width - qpadding.left() - qpadding.right();
// - (b->f_width() - last_rBearing); (0 for newline) // - (b->f_width() - last_rBearing); (0 for newline)
longWordLine = true; longWordLine = true;
@ -858,15 +859,15 @@ void String::enumerateLines(
j_width = (j->f_width() >= 0) ? j->f_width() : -j->f_width(); j_width = (j->f_width() >= 0) ? j->f_width() : -j->f_width();
} }
callback(width - widthLeft, lineHeight + ppadding.top()); callback(width - widthLeft, lineHeight + qpadding.top());
ppadding.setTop(0); qpadding.setTop(0);
lineHeight = qMax(0, blockHeight); lineHeight = qMax(0, blockHeight);
last_rBearing = j->f_rbearing(); last_rBearing = j->f_rbearing();
last_rPadding = j->f_rpadding(); last_rPadding = j->f_rpadding();
widthLeft = width widthLeft = width
- ppadding.left() - qpadding.left()
- ppadding.right() - qpadding.right()
- (j_width - last_rBearing); - (j_width - last_rBearing);
longWordLine = !wordEndsHere; longWordLine = !wordEndsHere;
@ -877,15 +878,15 @@ void String::enumerateLines(
continue; continue;
} }
callback(width - widthLeft, lineHeight + ppadding.top()); callback(width - widthLeft, lineHeight + qpadding.top());
ppadding.setTop(0); qpadding.setTop(0);
lineHeight = qMax(0, blockHeight); lineHeight = qMax(0, blockHeight);
last_rBearing = b__f_rbearing; last_rBearing = b__f_rbearing;
last_rPadding = b->f_rpadding(); last_rPadding = b->f_rpadding();
widthLeft = width widthLeft = width
- ppadding.left() - qpadding.left()
- ppadding.right() - qpadding.right()
- (b->f_width() - last_rBearing); - (b->f_width() - last_rBearing);
longWordLine = true; longWordLine = true;
@ -894,7 +895,7 @@ void String::enumerateLines(
if (widthLeft < width) { if (widthLeft < width) {
callback( callback(
width - widthLeft, width - widthLeft,
lineHeight + ppadding.top() + ppadding.bottom()); lineHeight + qpadding.top() + qpadding.bottom());
} }
} }
@ -1096,60 +1097,60 @@ uint16 String::countBlockLength(
return countBlockEnd(i, e) - (*i)->position(); return countBlockEnd(i, e) - (*i)->position();
} }
ParagraphDetails *String::paragraphByIndex(int index) const { QuoteDetails *String::quoteByIndex(int index) const {
Expects(!index Expects(!index
|| (_extended && index <= _extended->paragraphs.size())); || (_extended && index <= _extended->quotes.size()));
return index ? &_extended->paragraphs[index - 1] : nullptr; return index ? &_extended->quotes[index - 1] : nullptr;
} }
int String::paragraphIndex(const AbstractBlock *block) const { int String::quoteIndex(const AbstractBlock *block) const {
Expects(!block || block->type() == TextBlockType::Newline); Expects(!block || block->type() == TextBlockType::Newline);
return block return block
? static_cast<const NewlineBlock*>(block)->paragraphIndex() ? static_cast<const NewlineBlock*>(block)->quoteIndex()
: _startParagraphIndex; : _startQuoteIndex;
} }
const style::ParagraphStyle &String::paragraphStyle( const style::QuoteStyle &String::quoteStyle(
not_null<ParagraphDetails*> info) const { not_null<QuoteDetails*> quote) const {
return info->pre ? _st->pre : _st->blockquote; return quote->pre ? _st->pre : _st->blockquote;
} }
QMargins String::paragraphPadding(ParagraphDetails *info) const { QMargins String::quotePadding(QuoteDetails *quote) const {
if (!info) { if (!quote) {
return {}; return {};
} }
const auto &st = paragraphStyle(info); const auto &st = quoteStyle(quote);
const auto skip = st.verticalSkip; const auto skip = st.verticalSkip;
const auto top = st.header; const auto top = st.header;
return st.padding + QMargins(0, top + skip, 0, skip); return st.padding + QMargins(0, top + skip, 0, skip);
} }
int String::paragraphMinWidth(ParagraphDetails *info) const { int String::quoteMinWidth(QuoteDetails *quote) const {
if (!info) { if (!quote) {
return 0; return 0;
} }
const auto ppadding = paragraphPadding(info); const auto qpadding = quotePadding(quote);
const auto &pheader = paragraphHeaderText(info); const auto &qheader = quoteHeaderText(quote);
const auto pst = info ? &paragraphStyle(info) : nullptr; const auto qst = quote ? &quoteStyle(quote) : nullptr;
return ppadding.left() return qpadding.left()
+ (pheader.isEmpty() ? 0 : _st->font->monospace()->width(pheader)) + (qheader.isEmpty() ? 0 : _st->font->monospace()->width(qheader))
+ std::max( + std::max(
ppadding.right(), qpadding.right(),
((pst && !pst->icon.empty()) ((qst && !qst->icon.empty())
? (pst->iconPosition.x() + pst->icon.width()) ? (qst->iconPosition.x() + qst->icon.width())
: 0)); : 0));
} }
const QString &String::paragraphHeaderText(ParagraphDetails *info) const { const QString &String::quoteHeaderText(QuoteDetails *quote) const {
static const auto kEmptyHeader = QString(); static const auto kEmptyHeader = QString();
static const auto kDefaultHeader = u"code"_q; static const auto kDefaultHeader = u"code"_q;
return (!info || !info->pre) return (!quote || !quote->pre)
? kEmptyHeader ? kEmptyHeader
: info->language.isEmpty() : quote->language.isEmpty()
? kDefaultHeader ? kDefaultHeader
: info->language; : quote->language;
} }
template < template <
@ -1478,7 +1479,7 @@ void String::clear() {
_blocks.clear(); _blocks.clear();
_extended = nullptr; _extended = nullptr;
_maxWidth = _minHeight = 0; _maxWidth = _minHeight = 0;
_startParagraphIndex = 0; _startQuoteIndex = 0;
_startParagraphLTR = false; _startParagraphLTR = false;
_startParagraphRTL = false; _startParagraphRTL = false;
} }

View file

@ -24,7 +24,7 @@ enum class type : uchar;
namespace style { namespace style {
struct TextStyle; struct TextStyle;
struct TextPalette; struct TextPalette;
struct ParagraphStyle; struct QuoteStyle;
} // namespace style } // namespace style
namespace Ui { namespace Ui {
@ -81,7 +81,7 @@ class AbstractBlock;
struct IsolatedEmoji; struct IsolatedEmoji;
struct OnlyCustomEmoji; struct OnlyCustomEmoji;
struct SpoilerData; struct SpoilerData;
struct ParagraphDetails; struct QuoteDetails;
struct ExtendedData; struct ExtendedData;
struct Modification { struct Modification {
@ -165,7 +165,7 @@ struct GeometryDescriptor {
bool elisionOneLine, bool elisionOneLine,
bool elisionBreakEverywhere); bool elisionBreakEverywhere);
struct BlockPaintCache { struct QuotePaintCache {
QImage corners; QImage corners;
QColor headerCached; QColor headerCached;
QColor bgCached; QColor bgCached;
@ -178,19 +178,19 @@ struct BlockPaintCache {
QColor icon; QColor icon;
}; };
void ValidateBlockPaintCache( void ValidateQuotePaintCache(
BlockPaintCache &cache, QuotePaintCache &cache,
const style::ParagraphStyle &st); const style::QuoteStyle &st);
struct SkipBlockPaintParts { struct SkipBlockPaintParts {
bool skipTop : 1 = false; bool skipTop : 1 = false;
bool skipBottom : 1 = false; bool skipBottom : 1 = false;
}; };
void FillBlockPaint( void FillQuotePaint(
QPainter &p, QPainter &p,
QRect rect, QRect rect,
const BlockPaintCache &cache, const QuotePaintCache &cache,
const style::ParagraphStyle &st, const style::QuoteStyle &st,
SkipBlockPaintParts parts = {}); SkipBlockPaintParts parts = {});
struct PaintContext { struct PaintContext {
@ -202,8 +202,8 @@ struct PaintContext {
QRect clip; QRect clip;
const style::TextPalette *palette = nullptr; const style::TextPalette *palette = nullptr;
BlockPaintCache *pre = nullptr; QuotePaintCache *pre = nullptr;
BlockPaintCache *blockquote = nullptr; QuotePaintCache *blockquote = nullptr;
std::span<SpecialColor> colors; std::span<SpecialColor> colors;
SpoilerMessCache *spoiler = nullptr; SpoilerMessCache *spoiler = nullptr;
crl::time now = 0; crl::time now = 0;
@ -375,16 +375,15 @@ private:
[[nodiscard]] uint16 countBlockLength( [[nodiscard]] uint16 countBlockLength(
const TextBlocks::const_iterator &i, const TextBlocks::const_iterator &i,
const TextBlocks::const_iterator &e) const; const TextBlocks::const_iterator &e) const;
[[nodiscard]] ParagraphDetails *paragraphByIndex(int index) const; [[nodiscard]] QuoteDetails *quoteByIndex(int index) const;
[[nodiscard]] const style::ParagraphStyle &paragraphStyle( [[nodiscard]] const style::QuoteStyle &quoteStyle(
not_null<ParagraphDetails*> info) const; not_null<QuoteDetails*> quote) const;
[[nodiscard]] QMargins paragraphPadding(ParagraphDetails *info) const; [[nodiscard]] QMargins quotePadding(QuoteDetails *quote) const;
[[nodiscard]] int paragraphMinWidth(ParagraphDetails *info) const; [[nodiscard]] int quoteMinWidth(QuoteDetails *quote) const;
[[nodiscard]] const QString &paragraphHeaderText( [[nodiscard]] const QString &quoteHeaderText(QuoteDetails *quote) const;
ParagraphDetails *info) const;
// block must be either nullptr or a pointer to a NewlineBlock. // block must be either nullptr or a pointer to a NewlineBlock.
[[nodiscard]] int paragraphIndex(const AbstractBlock *block) const; [[nodiscard]] int quoteIndex(const AbstractBlock *block) const;
// Template method for originalText(), originalTextWithEntities(). // Template method for originalText(), originalTextWithEntities().
template < template <
@ -425,7 +424,7 @@ private:
int _minResizeWidth = 0; int _minResizeWidth = 0;
int _maxWidth = 0; int _maxWidth = 0;
int _minHeight = 0; int _minHeight = 0;
uint16 _startParagraphIndex = 0; uint16 _startQuoteIndex = 0;
bool _startParagraphLTR : 1 = false; bool _startParagraphLTR : 1 = false;
bool _startParagraphRTL : 1 = false; bool _startParagraphRTL : 1 = false;
bool _hasCustomEmoji : 1 = false; bool _hasCustomEmoji : 1 = false;
@ -433,7 +432,7 @@ private:
bool _isOnlyCustomEmoji : 1 = false; bool _isOnlyCustomEmoji : 1 = false;
bool _hasNotEmojiAndSpaces : 1 = false; bool _hasNotEmojiAndSpaces : 1 = false;
bool _skipBlockAddedNewline : 1 = false; bool _skipBlockAddedNewline : 1 = false;
bool _endsWithParagraphDetails : 1 = false; bool _endsWithQuote : 1 = false;
friend class Parser; friend class Parser;
friend class Renderer; friend class Renderer;

View file

@ -107,15 +107,15 @@ public:
uint16 linkIndex, uint16 linkIndex,
uint16 colorIndex); uint16 colorIndex);
[[nodiscard]] uint16 paragraphIndex() const { [[nodiscard]] uint16 quoteIndex() const {
return _paragraphIndex; return _quoteIndex;
} }
[[nodiscard]] Qt::LayoutDirection paragraphDirection() const { [[nodiscard]] Qt::LayoutDirection paragraphDirection() const {
return UnpackParagraphDirection(_paragraphLTR, _paragraphRTL); return UnpackParagraphDirection(_paragraphLTR, _paragraphRTL);
} }
private: private:
uint16 _paragraphIndex = 0; uint16 _quoteIndex = 0;
bool _paragraphLTR : 1 = false; bool _paragraphLTR : 1 = false;
bool _paragraphRTL : 1 = false; bool _paragraphRTL : 1 = false;

View file

@ -43,7 +43,7 @@ struct SpoilerData {
bool revealed = false; bool revealed = false;
}; };
struct ParagraphDetails { struct QuoteDetails {
QString language; QString language;
ClickHandlerPtr copy; ClickHandlerPtr copy;
int copyWidth = 0; int copyWidth = 0;
@ -56,7 +56,7 @@ struct ParagraphDetails {
struct ExtendedData { struct ExtendedData {
std::vector<ClickHandlerPtr> links; std::vector<ClickHandlerPtr> links;
std::vector<ParagraphDetails> paragraphs; std::vector<QuoteDetails> quotes;
std::unique_ptr<SpoilerData> spoiler; std::unique_ptr<SpoilerData> spoiler;
std::vector<Modification> modifications; std::vector<Modification> modifications;
}; };

View file

@ -212,7 +212,7 @@ void Parser::createBlock(int32 skipBack) {
} else if (newline) { } else if (newline) {
push(&Block::Newline); push(&Block::Newline);
auto &newline = _t->_blocks.back().unsafe<NewlineBlock>(); auto &newline = _t->_blocks.back().unsafe<NewlineBlock>();
newline._paragraphIndex = _paragraphIndex; newline._quoteIndex = _quoteIndex;
} else { } else {
push(&Block::Text, _t->_minResizeWidth); push(&Block::Text, _t->_minResizeWidth);
} }
@ -233,7 +233,7 @@ void Parser::createNewlineBlock(bool fromOriginalText) {
createBlock(); createBlock();
} }
void Parser::ensureAtNewline(ParagraphDetails details) { void Parser::ensureAtNewline(QuoteDetails quote) {
createBlock(); createBlock();
const auto lastType = _t->_blocks.empty() const auto lastType = _t->_blocks.empty()
? TextBlockType::Newline ? TextBlockType::Newline
@ -243,15 +243,15 @@ void Parser::ensureAtNewline(ParagraphDetails details) {
createNewlineBlock(false); createNewlineBlock(false);
_customEmojiData = base::take(saved); _customEmojiData = base::take(saved);
} }
auto &paragraphs = _t->ensureExtended()->paragraphs; auto &quotes = _t->ensureExtended()->quotes;
paragraphs.push_back(std::move(details)); quotes.push_back(std::move(quote));
const auto index = _paragraphIndex = int(paragraphs.size()); const auto index = _quoteIndex = int(quotes.size());
if (_t->_blocks.empty()) { if (_t->_blocks.empty()) {
_t->_startParagraphIndex = index; _t->_startQuoteIndex = index;
} else { } else {
auto &last = _t->_blocks.back(); auto &last = _t->_blocks.back();
Assert(last->type() == TextBlockType::Newline); Assert(last->type() == TextBlockType::Newline);
last.unsafe<NewlineBlock>()._paragraphIndex = index; last.unsafe<NewlineBlock>()._quoteIndex = index;
} }
} }
@ -274,14 +274,14 @@ void Parser::finishEntities() {
if ((*flags) if ((*flags)
& (TextBlockFlag::Pre & (TextBlockFlag::Pre
| TextBlockFlag::Blockquote)) { | TextBlockFlag::Blockquote)) {
_paragraphIndex = 0; _quoteIndex = 0;
if (lastType != TextBlockType::Newline) { if (lastType != TextBlockType::Newline) {
_newlineAwaited = true; _newlineAwaited = true;
} else if (_t->_blocks.empty()) { } else if (_t->_blocks.empty()) {
_t->_startParagraphIndex = 0; _t->_startQuoteIndex = 0;
} else { } else {
auto &last = _t->_blocks.back(); auto &last = _t->_blocks.back();
last.unsafe<NewlineBlock>()._paragraphIndex = 0; last.unsafe<NewlineBlock>()._quoteIndex = 0;
} }
} }
if (IsMono(*flags)) { if (IsMono(*flags)) {

View file

@ -11,7 +11,7 @@
namespace Ui::Text { namespace Ui::Text {
struct ParagraphDetails; struct QuoteDetails;
class Parser { class Parser {
public: public:
@ -60,7 +60,7 @@ private:
void blockCreated(); void blockCreated();
void createBlock(int32 skipBack = 0); void createBlock(int32 skipBack = 0);
void createNewlineBlock(bool fromOriginalText); void createNewlineBlock(bool fromOriginalText);
void ensureAtNewline(ParagraphDetails details); void ensureAtNewline(QuoteDetails quote);
// Returns true if at least one entity was parsed in the current position. // Returns true if at least one entity was parsed in the current position.
bool checkEntities(); bool checkEntities();
@ -115,7 +115,7 @@ private:
uint16 _linkIndex = 0; uint16 _linkIndex = 0;
uint16 _colorIndex = 0; uint16 _colorIndex = 0;
uint16 _monoIndex = 0; uint16 _monoIndex = 0;
uint16 _paragraphIndex = 0; uint16 _quoteIndex = 0;
EmojiPtr _emoji = nullptr; // current emoji, if current word is an emoji, or zero EmojiPtr _emoji = nullptr; // current emoji, if current word is an emoji, or zero
int32 _blockStart = 0; // offset in result, from which current parsed block is started int32 _blockStart = 0; // offset in result, from which current parsed block is started
int32 _diacritics = 0; // diacritic chars skipped without good char int32 _diacritics = 0; // diacritic chars skipped without good char

View file

@ -179,8 +179,8 @@ void Renderer::draw(QPainter &p, const PaintContext &context) {
? _originalPen ? _originalPen
: _palette->selectFg->p; : _palette->selectFg->p;
_x = context.position.x(); _x = _startLeft = context.position.x();
_y = context.position.y(); _y = _startTop = context.position.y();
_yFrom = context.clip.isNull() ? 0 : context.clip.y(); _yFrom = context.clip.isNull() ? 0 : context.clip.y();
_yTo = context.clip.isNull() _yTo = context.clip.isNull()
? -1 ? -1
@ -206,8 +206,8 @@ void Renderer::draw(QPainter &p, const PaintContext &context) {
? (1. - _spoiler->revealAnimation.value( ? (1. - _spoiler->revealAnimation.value(
_spoiler->revealed ? 1. : 0.)) _spoiler->revealed ? 1. : 0.))
: 0.; : 0.;
_preBlockCache = context.pre; _quotePreCache = context.pre;
_blockquoteBlockCache = context.blockquote; _quoteBlockquoteCache = context.blockquote;
enumerate(); enumerate();
} }
@ -227,13 +227,10 @@ void Renderer::enumerate() {
} }
} }
_startLeft = _x.toInt();
_startTop = _y;
if ((*_t->_blocks.cbegin())->type() != TextBlockType::Newline) { if ((*_t->_blocks.cbegin())->type() != TextBlockType::Newline) {
initNextParagraph( initNextParagraph(
_t->_blocks.cbegin(), _t->_blocks.cbegin(),
_t->_startParagraphIndex, _t->_startQuoteIndex,
UnpackParagraphDirection( UnpackParagraphDirection(
_t->_startParagraphLTR, _t->_startParagraphLTR,
_t->_startParagraphRTL)); _t->_startParagraphRTL));
@ -262,9 +259,9 @@ void Renderer::enumerate() {
if (!_lineHeight) { if (!_lineHeight) {
_lineHeight = blockHeight; _lineHeight = blockHeight;
} }
const auto pindex = static_cast<const NewlineBlock*>(b)->paragraphIndex(); const auto qindex = static_cast<const NewlineBlock*>(b)->quoteIndex();
const auto changed = (_pindex != pindex); const auto changed = (_quoteIndex != qindex);
fillParagraphBg(changed ? _ppadding.bottom() : 0); fillParagraphBg(changed ? _quotePadding.bottom() : 0);
if (!drawLine((*i)->position(), i, e)) { if (!drawLine((*i)->position(), i, e)) {
return; return;
} }
@ -277,7 +274,7 @@ void Renderer::enumerate() {
initNextParagraph( initNextParagraph(
i + 1, i + 1,
pindex, qindex,
static_cast<const NewlineBlock*>(b)->paragraphDirection()); static_cast<const NewlineBlock*>(b)->paragraphDirection());
longWordLine = true; longWordLine = true;
@ -395,7 +392,7 @@ void Renderer::enumerate() {
continue; continue;
} }
if (_lineStart < _t->_text.size()) { if (_lineStart < _t->_text.size()) {
fillParagraphBg(_ppadding.bottom()); fillParagraphBg(_quotePadding.bottom());
if (!drawLine(_t->_text.size(), e, e)) { if (!drawLine(_t->_text.size(), e, e)) {
return; return;
} }
@ -407,30 +404,31 @@ void Renderer::enumerate() {
} }
void Renderer::fillParagraphBg(int paddingBottom) { void Renderer::fillParagraphBg(int paddingBottom) {
const auto cache = (!_p || !_paragraph) const auto cache = (!_p || !_quote)
? nullptr ? nullptr
: _paragraph->pre : _quote->pre
? _preBlockCache ? _quotePreCache
: _paragraph->blockquote : _quote->blockquote
? _blockquoteBlockCache ? _quoteBlockquoteCache
: nullptr; : nullptr;
if (cache) { if (cache) {
const auto &st = _t->paragraphStyle(_paragraph); const auto &st = _t->quoteStyle(_quote);
auto &valid = _paragraph->pre auto &valid = _quote->pre
? _preBlockCacheValid ? _quotePreValid
: _blockquoteBlockCacheValid; : _quoteBlockquoteValid;
if (!valid) { if (!valid) {
valid = true; valid = true;
ValidateBlockPaintCache(*cache, st); ValidateQuotePaintCache(*cache, st);
} }
const auto skip = st.verticalSkip; const auto skip = st.verticalSkip;
const auto isTop = (_y != _blockLineTop); const auto isTop = (_y != _quoteLineTop);
const auto isBottom = (paddingBottom != 0); const auto isBottom = (paddingBottom != 0);
const auto top = _blockLineTop + (isTop ? skip : 0); const auto left = _startLeft + _quoteShift;
const auto top = _quoteLineTop + (isTop ? skip : 0);
const auto fill = _y + _lineHeight + paddingBottom - top const auto fill = _y + _lineHeight + paddingBottom - top
- (isBottom ? skip : 0); - (isBottom ? skip : 0);
const auto rect = QRect(_startLeft, top, _startLineWidth, fill); const auto rect = QRect(left, top, _startLineWidth, fill);
FillBlockPaint(*_p, rect, *cache, st, { FillQuotePaint(*_p, rect, *cache, st, {
.skipTop = !isTop, .skipTop = !isTop,
.skipBottom = !isBottom, .skipBottom = !isBottom,
}); });
@ -442,10 +440,10 @@ void Renderer::fillParagraphBg(int paddingBottom) {
const auto baseline = position + QPoint(0, font->ascent); const auto baseline = position + QPoint(0, font->ascent);
_p->setFont(font); _p->setFont(font);
_p->setPen(_palette->monoFg->p); _p->setPen(_palette->monoFg->p);
_p->drawText(baseline, _t->paragraphHeaderText(_paragraph)); _p->drawText(baseline, _t->quoteHeaderText(_quote));
} }
} }
_blockLineTop = _y + _lineHeight + paddingBottom; _quoteLineTop = _y + _lineHeight + paddingBottom;
} }
StateResult Renderer::getState( StateResult Renderer::getState(
@ -484,27 +482,28 @@ void Renderer::initNextParagraph(
String::TextBlocks::const_iterator i, String::TextBlocks::const_iterator i,
int16 paragraphIndex, int16 paragraphIndex,
Qt::LayoutDirection direction) { Qt::LayoutDirection direction) {
_parDirection = (direction == Qt::LayoutDirectionAuto) _paragraphDirection = (direction == Qt::LayoutDirectionAuto)
? style::LayoutDirection() ? style::LayoutDirection()
: direction; : direction;
_parStartBlock = i; _paragraphStartBlock = i;
_paragraphWidthRemaining = 0; _paragraphWidthRemaining = 0;
if (_pindex != paragraphIndex) { if (_quoteIndex != paragraphIndex) {
_y += _ppadding.bottom(); _y += _quotePadding.bottom();
_pindex = paragraphIndex; _quoteIndex = paragraphIndex;
_paragraph = _t->paragraphByIndex(paragraphIndex); _quote = _t->quoteByIndex(paragraphIndex);
_ppadding = _t->paragraphPadding(_paragraph); _quotePadding = _t->quotePadding(_quote);
_blockLineTop = _y; _quoteLineTop = _y;
_y += _ppadding.top(); _y += _quotePadding.top();
_ppadding.setTop(0); _quotePadding.setTop(0);
_quoteDirection = _paragraphDirection;
} }
const auto e = _t->_blocks.cend(); const auto e = _t->_blocks.cend();
if (i == e) { if (i == e) {
_lineStart = _parStart = _t->_text.size(); _lineStart = _paragraphStart = _t->_text.size();
_lineStartBlock = _t->_blocks.size(); _lineStartBlock = _t->_blocks.size();
_parLength = 0; _paragraphLength = 0;
} else { } else {
_lineStart = _parStart = (*i)->position(); _lineStart = _paragraphStart = (*i)->position();
_lineStartBlock = i - _t->_blocks.cbegin(); _lineStartBlock = i - _t->_blocks.cbegin();
auto last_rPadding = QFixed(0); auto last_rPadding = QFixed(0);
@ -520,10 +519,13 @@ void Renderer::initNextParagraph(
- rBearing; - rBearing;
last_rBearing = rBearing; last_rBearing = rBearing;
} }
_parLength = ((i == e) ? _t->_text.size() : (*i)->position()) - _parStart; _paragraphLength = ((i == e)
? _t->_text.size()
: (*i)->position())
- _paragraphStart;
} }
_parAnalysis.resize(0); _paragraphAnalysis.resize(0);
_paragraphWidthRemaining += _ppadding.left() + _ppadding.right(); _paragraphWidthRemaining += _quotePadding.left() + _quotePadding.right();
initNextLine(); initNextLine();
} }
@ -533,31 +535,48 @@ void Renderer::initNextLine() {
.top = (_y - _startTop), .top = (_y - _startTop),
.width = _paragraphWidthRemaining.ceil().toInt(), .width = _paragraphWidthRemaining.ceil().toInt(),
}); });
_blockLineTop += _startTop + line.top - _y; _quoteLineTop += _startTop + line.top - _y;
_x = _startLeft + line.left + _ppadding.left(); _x = _startLeft + line.left + _quotePadding.left();
_y = _startTop + line.top; _y = _startTop + line.top;
_startLineWidth = line.width; _startLineWidth = line.width;
_lineWidth = _startLineWidth - _ppadding.left() - _ppadding.right(); _quoteShift = 0;
if (_quote && _quote->maxWidth < _startLineWidth) {
const auto delta = _startLineWidth - _quote->maxWidth;
_startLineWidth = _quote->maxWidth;
if (_align & Qt::AlignHCenter) {
_quoteShift = delta / 2;
} else if (((_align & Qt::AlignLeft)
&& (_quoteDirection == Qt::RightToLeft))
|| ((_align & Qt::AlignRight)
&& (_quoteDirection == Qt::LeftToRight))) {
_quoteShift = delta;
}
_x += _quoteShift;
}
_lineWidth = _startLineWidth
- _quotePadding.left()
- _quotePadding.right();
_wLeft = _lineWidth; _wLeft = _lineWidth;
_elidedLine = line.elided; _elidedLine = line.elided;
} }
void Renderer::initParagraphBidi() { void Renderer::initParagraphBidi() {
if (!_parLength || !_parAnalysis.isEmpty()) { if (!_paragraphLength || !_paragraphAnalysis.isEmpty()) {
return; return;
} }
String::TextBlocks::const_iterator i = _parStartBlock, e = _t->_blocks.cend(), n = i + 1; String::TextBlocks::const_iterator i = _paragraphStartBlock, e = _t->_blocks.cend(), n = i + 1;
bool ignore = false; bool ignore = false;
bool rtl = (_parDirection == Qt::RightToLeft); bool rtl = (_paragraphDirection == Qt::RightToLeft);
if (!ignore && !rtl) { if (!ignore && !rtl) {
ignore = true; ignore = true;
const ushort *start = reinterpret_cast<const ushort*>(_str) + _parStart; const ushort *start = reinterpret_cast<const ushort*>(_str) + _paragraphStart;
const ushort *curr = start; const ushort *curr = start;
const ushort *end = start + _parLength; const ushort *end = start + _paragraphLength;
while (curr < end) { while (curr < end) {
while (n != e && (*n)->position() <= _parStart + (curr - start)) { while (n != e && (*n)->position() <= _paragraphStart + (curr - start)) {
i = n; i = n;
++n; ++n;
} }
@ -572,21 +591,21 @@ void Renderer::initParagraphBidi() {
} }
} }
_parAnalysis.resize(_parLength); _paragraphAnalysis.resize(_paragraphLength);
QScriptAnalysis *analysis = _parAnalysis.data(); QScriptAnalysis *analysis = _paragraphAnalysis.data();
BidiControl control(rtl); BidiControl control(rtl);
_parHasBidi = false; _paragraphHasBidi = false;
if (ignore) { if (ignore) {
memset(analysis, 0, _parLength * sizeof(QScriptAnalysis)); memset(analysis, 0, _paragraphLength * sizeof(QScriptAnalysis));
if (rtl) { if (rtl) {
for (int i = 0; i < _parLength; ++i) for (int i = 0; i < _paragraphLength; ++i)
analysis[i].bidiLevel = 1; analysis[i].bidiLevel = 1;
_parHasBidi = true; _paragraphHasBidi = true;
} }
} else { } else {
_parHasBidi = eBidiItemize(analysis, control); _paragraphHasBidi = eBidiItemize(analysis, control);
} }
} }
@ -651,14 +670,17 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
auto x = _x; auto x = _x;
if (_align & Qt::AlignHCenter) { if (_align & Qt::AlignHCenter) {
x += (_wLeft / 2).toInt(); x += (_wLeft / 2).toInt();
} else if (((_align & Qt::AlignLeft) && _parDirection == Qt::RightToLeft) || ((_align & Qt::AlignRight) && _parDirection == Qt::LeftToRight)) { } else if (((_align & Qt::AlignLeft)
&& (_paragraphDirection == Qt::RightToLeft))
|| ((_align & Qt::AlignRight)
&& (_paragraphDirection == Qt::LeftToRight))) {
x += _wLeft; x += _wLeft;
} }
if (!_p) { if (!_p) {
if (_lookupX < x) { if (_lookupX < x) {
if (_lookupSymbol) { if (_lookupSymbol) {
if (_parDirection == Qt::RightToLeft) { if (_paragraphDirection == Qt::RightToLeft) {
_lookupResult.symbol = (_lineEnd > _lineStart) ? (_lineEnd - 1) : _lineStart; _lookupResult.symbol = (_lineEnd > _lineStart) ? (_lineEnd - 1) : _lineStart;
_lookupResult.afterSymbol = (_lineEnd > _lineStart) ? true : false; _lookupResult.afterSymbol = (_lineEnd > _lineStart) ? true : false;
// _lookupResult.uponSymbol = ((_lookupX >= _x) && (_lineEnd < _t->_text.size()) && (!_endBlock || _endBlock->type() != TextBlockType::Skip)) ? true : false; // _lookupResult.uponSymbol = ((_lookupX >= _x) && (_lineEnd < _t->_text.size()) && (!_endBlock || _endBlock->type() != TextBlockType::Skip)) ? true : false;
@ -674,7 +696,7 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
_lookupResult.uponSymbol = false; _lookupResult.uponSymbol = false;
return false; return false;
} else if (_lookupX >= x + (_lineWidth - _wLeft)) { } else if (_lookupX >= x + (_lineWidth - _wLeft)) {
if (_parDirection == Qt::RightToLeft) { if (_paragraphDirection == Qt::RightToLeft) {
_lookupResult.symbol = _lineStart; _lookupResult.symbol = _lineStart;
_lookupResult.afterSymbol = false; _lookupResult.afterSymbol = false;
// _lookupResult.uponSymbol = ((_lookupX < _x + _w) && (_lineStart > 0)) ? true : false; // _lookupResult.uponSymbol = ((_lookupX < _x + _w) && (_lineStart > 0)) ? true : false;
@ -700,14 +722,14 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
&& (_selection.from <= trimmedLineEnd) && (_selection.from <= trimmedLineEnd)
&& (!_endBlock || _endBlock->type() != TextBlockType::Skip); && (!_endBlock || _endBlock->type() != TextBlockType::Skip);
if ((selectFromStart && _parDirection == Qt::LeftToRight) if ((selectFromStart && _paragraphDirection == Qt::LeftToRight)
|| (selectTillEnd && _parDirection == Qt::RightToLeft)) { || (selectTillEnd && _paragraphDirection == Qt::RightToLeft)) {
if (x > _x) { if (x > _x) {
fillSelectRange({ _x, x }); fillSelectRange({ _x, x });
} }
} }
if ((selectTillEnd && _parDirection == Qt::LeftToRight) if ((selectTillEnd && _paragraphDirection == Qt::LeftToRight)
|| (selectFromStart && _parDirection == Qt::RightToLeft)) { || (selectFromStart && _paragraphDirection == Qt::RightToLeft)) {
if (x < _x + _wLeft) { if (x < _x + _wLeft) {
fillSelectRange({ x + _lineWidth - _wLeft, _x + _lineWidth }); fillSelectRange({ x + _lineWidth - _wLeft, _x + _lineWidth });
} }
@ -723,7 +745,7 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
_f = _t->_st->font; _f = _t->_st->font;
QStackTextEngine engine(lineText, _f->f); QStackTextEngine engine(lineText, _f->f);
engine.option.setTextDirection(_parDirection); engine.option.setTextDirection(_paragraphDirection);
_e = &engine; _e = &engine;
eItemize(); eItemize();
@ -813,7 +835,7 @@ bool Renderer::drawLine(uint16 _lineEnd, const String::TextBlocks::const_iterato
} }
if (_lookupSymbol) { if (_lookupSymbol) {
if (_type == TextBlockType::Skip) { if (_type == TextBlockType::Skip) {
if (_parDirection == Qt::RightToLeft) { if (_paragraphDirection == Qt::RightToLeft) {
_lookupResult.symbol = _lineStart; _lookupResult.symbol = _lineStart;
_lookupResult.afterSymbol = false; _lookupResult.afterSymbol = false;
} else { } else {
@ -1291,19 +1313,25 @@ void Renderer::elideSaveBlock(int32 blockIndex, const AbstractBlock *&_endBlock,
} }
void Renderer::setElideBidi(int32 elideStart, int32 elideLen) { void Renderer::setElideBidi(int32 elideStart, int32 elideLen) {
int32 newParLength = elideStart + elideLen - _parStart; int32 newParLength = elideStart + elideLen - _paragraphStart;
if (newParLength > _parAnalysis.size()) { if (newParLength > _paragraphAnalysis.size()) {
_parAnalysis.resize(newParLength); _paragraphAnalysis.resize(newParLength);
} }
for (int32 i = elideLen; i > 0; --i) { for (int32 i = elideLen; i > 0; --i) {
_parAnalysis[newParLength - i].bidiLevel = (_parDirection == Qt::RightToLeft) ? 1 : 0; _paragraphAnalysis[newParLength - i].bidiLevel
= (_paragraphDirection == Qt::RightToLeft) ? 1 : 0;
} }
} }
void Renderer::prepareElidedLine(QString &lineText, int32 lineStart, int32 &lineLength, const AbstractBlock *&_endBlock, int repeat) { void Renderer::prepareElidedLine(
QString &lineText,
int32 lineStart,
int32 &lineLength,
const AbstractBlock *&_endBlock,
int repeat) {
_f = _t->_st->font; _f = _t->_st->font;
QStackTextEngine engine(lineText, _f->f); QStackTextEngine engine(lineText, _f->f);
engine.option.setTextDirection(_parDirection); engine.option.setTextDirection(_paragraphDirection);
_e = &engine; _e = &engine;
eItemize(); eItemize();
@ -1318,7 +1346,10 @@ void Renderer::prepareElidedLine(QString &lineText, int32 lineStart, int32 &line
eShapeLine(line); eShapeLine(line);
auto elideWidth = _f->elidew; auto elideWidth = _f->elidew;
_wLeft = _lineWidth - _ppadding.left() - _ppadding.right() - elideWidth; _wLeft = _lineWidth
- _quotePadding.left()
- _quotePadding.right()
- elideWidth;
int firstItem = engine.findItem(line.from), lastItem = engine.findItem(line.from + line.length - 1); int firstItem = engine.findItem(line.from), lastItem = engine.findItem(line.from + line.length - 1);
int nItems = (firstItem >= 0 && lastItem >= firstItem) ? (lastItem - firstItem + 1) : 0, i; int nItems = (firstItem >= 0 && lastItem >= firstItem) ? (lastItem - firstItem + 1) : 0, i;
@ -1518,8 +1549,8 @@ void Renderer::eItemize() {
auto currentBlock = _t->_blocks[blockIndex].get(); auto currentBlock = _t->_blocks[blockIndex].get();
auto nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr; auto nextBlock = (++blockIndex < _blocksSize) ? _t->_blocks[blockIndex].get() : nullptr;
_e->layoutData->hasBidi = _parHasBidi; _e->layoutData->hasBidi = _paragraphHasBidi;
auto analysis = _parAnalysis.data() + (_localFrom - _parStart); auto analysis = _paragraphAnalysis.data() + (_localFrom - _paragraphStart);
{ {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
@ -1568,7 +1599,7 @@ void Renderer::eItemize() {
{ {
auto i_string = &_e->layoutData->string; auto i_string = &_e->layoutData->string;
auto i_analysis = _parAnalysis.data() + (_localFrom - _parStart); auto i_analysis = _paragraphAnalysis.data() + (_localFrom - _paragraphStart);
auto i_items = &_e->layoutData->items; auto i_items = &_e->layoutData->items;
blockIndex = _lineStartBlock; blockIndex = _lineStartBlock;
@ -1623,18 +1654,18 @@ QChar::Direction Renderer::eSkipBoundryNeutrals(
QChar::Direction dir = control.basicDirection(); QChar::Direction dir = control.basicDirection();
int level = sor > 0 ? analysis[sor - 1].bidiLevel : control.level; int level = sor > 0 ? analysis[sor - 1].bidiLevel : control.level;
while (sor <= _parLength) { while (sor <= _paragraphLength) {
while (i != _parStartBlock && (*i)->position() > _parStart + sor) { while (i != _paragraphStartBlock && (*i)->position() > _paragraphStart + sor) {
n = i; n = i;
--i; --i;
} }
while (n != e && (*n)->position() <= _parStart + sor) { while (n != e && (*n)->position() <= _paragraphStart + sor) {
i = n; i = n;
++n; ++n;
} }
TextBlockType _itype = (*i)->type(); TextBlockType _itype = (*i)->type();
if (eor == _parLength) if (eor == _paragraphLength)
dir = control.basicDirection(); dir = control.basicDirection();
else if (_itype == TextBlockType::Emoji else if (_itype == TextBlockType::Emoji
|| _itype == TextBlockType::CustomEmoji) || _itype == TextBlockType::CustomEmoji)
@ -1662,16 +1693,16 @@ bool Renderer::eBidiItemize(QScriptAnalysis *analysis, BidiControl &control) {
int sor = 0; int sor = 0;
int eor = -1; int eor = -1;
const ushort *unicode = reinterpret_cast<const ushort*>(_t->_text.unicode()) + _parStart; const ushort *unicode = reinterpret_cast<const ushort*>(_t->_text.unicode()) + _paragraphStart;
int current = 0; int current = 0;
QChar::Direction dir = rightToLeft ? QChar::DirR : QChar::DirL; QChar::Direction dir = rightToLeft ? QChar::DirR : QChar::DirL;
BidiStatus status; BidiStatus status;
String::TextBlocks::const_iterator i = _parStartBlock, e = _t->_blocks.cend(), n = i + 1; String::TextBlocks::const_iterator i = _paragraphStartBlock, e = _t->_blocks.cend(), n = i + 1;
QChar::Direction sdir; QChar::Direction sdir;
TextBlockType _stype = (*_parStartBlock)->type(); TextBlockType _stype = (*_paragraphStartBlock)->type();
if (_stype == TextBlockType::Emoji || _stype == TextBlockType::CustomEmoji) if (_stype == TextBlockType::Emoji || _stype == TextBlockType::CustomEmoji)
sdir = QChar::DirCS; sdir = QChar::DirCS;
else if (_stype == TextBlockType::Skip) else if (_stype == TextBlockType::Skip)
@ -1688,15 +1719,15 @@ bool Renderer::eBidiItemize(QScriptAnalysis *analysis, BidiControl &control) {
status.last = status.lastStrong; status.last = status.lastStrong;
status.dir = sdir; status.dir = sdir;
while (current <= _parLength) { while (current <= _paragraphLength) {
while (n != e && (*n)->position() <= _parStart + current) { while (n != e && (*n)->position() <= _paragraphStart + current) {
i = n; i = n;
++n; ++n;
} }
QChar::Direction dirCurrent; QChar::Direction dirCurrent;
TextBlockType _itype = (*i)->type(); TextBlockType _itype = (*i)->type();
if (current == (int)_parLength) if (current == (int)_paragraphLength)
dirCurrent = control.basicDirection(); dirCurrent = control.basicDirection();
else if (_itype == TextBlockType::Emoji else if (_itype == TextBlockType::Emoji
|| _itype == TextBlockType::CustomEmoji) || _itype == TextBlockType::CustomEmoji)
@ -2020,7 +2051,7 @@ bool Renderer::eBidiItemize(QScriptAnalysis *analysis, BidiControl &control) {
break; break;
} }
if (current >= (int)_parLength) break; if (current >= (int)_paragraphLength) break;
// set status.last as needed. // set status.last as needed.
switch (dirCurrent) { switch (dirCurrent) {

View file

@ -151,20 +151,25 @@ private:
int _indexOfElidedBlock = -1; // For spoilers. int _indexOfElidedBlock = -1; // For spoilers.
// current paragraph data // current paragraph data
String::TextBlocks::const_iterator _parStartBlock; String::TextBlocks::const_iterator _paragraphStartBlock;
Qt::LayoutDirection _parDirection = Qt::LayoutDirectionAuto; Qt::LayoutDirection _paragraphDirection = Qt::LayoutDirectionAuto;
int _parStart = 0; int _paragraphStart = 0;
int _parLength = 0; int _paragraphLength = 0;
bool _parHasBidi = false; bool _paragraphHasBidi = false;
QVarLengthArray<QScriptAnalysis, 4096> _parAnalysis; QVarLengthArray<QScriptAnalysis, 4096> _paragraphAnalysis;
ParagraphDetails *_paragraph = nullptr; QFixed _paragraphWidthRemaining = 0;
int _pindex = 0;
QMargins _ppadding; // current quote data
int _blockLineTop = 0; QuoteDetails *_quote = nullptr;
BlockPaintCache *_preBlockCache = nullptr; Qt::LayoutDirection _quoteDirection = Qt::LayoutDirectionAuto;
BlockPaintCache *_blockquoteBlockCache = nullptr; int _quoteShift = 0;
bool _preBlockCacheValid = false; int _quoteIndex = 0;
bool _blockquoteBlockCacheValid = false; QMargins _quotePadding;
int _quoteLineTop = 0;
QuotePaintCache *_quotePreCache = nullptr;
QuotePaintCache *_quoteBlockquoteCache = nullptr;
bool _quotePreValid = false;
bool _quoteBlockquoteValid = false;
// current line data // current line data
QTextEngine *_e = nullptr; QTextEngine *_e = nullptr;
@ -189,7 +194,6 @@ private:
int _localFrom = 0; int _localFrom = 0;
int _lineStartBlock = 0; int _lineStartBlock = 0;
QFixed _lineWidth = 0; QFixed _lineWidth = 0;
QFixed _paragraphWidthRemaining = 0;
// link and symbol resolve // link and symbol resolve
QFixed _lookupX = 0; QFixed _lookupX = 0;