Mirrored list markers for RTL rich pages.

This commit is contained in:
John Preston
2026-07-16 01:56:07 +04:00
parent 054f7950bb
commit e4e86348cb
4 changed files with 40 additions and 16 deletions
@@ -3576,6 +3576,7 @@ private:
void invalidateGeometry();
[[nodiscard]] const style::Markdown &layoutStyle() const;
[[nodiscard]] bool contentRtl() const;
[[nodiscard]] MarkdownArticleScrollOwnerIdentity scrollOwnerIdentity(
const LaidOutBlock &block,
const std::vector<int> &preparedPath) const;
@@ -3887,6 +3888,7 @@ void MarkdownArticle::Impl::updatePreparedLeaf(
}
auto context = LayoutContext();
context.rtl = contentRtl();
context.syntaxHighlightTracker = this;
context.repaint = _textRepaint;
context.repaintRect = _textRepaintRect;
@@ -5233,6 +5235,10 @@ const style::Markdown &MarkdownArticle::Impl::layoutStyle() const {
return _style;
}
bool MarkdownArticle::Impl::contentRtl() const {
return _content.richPage && _content.richPage->rtl;
}
MarkdownArticleScrollOwnerIdentity MarkdownArticle::Impl::scrollOwnerIdentity(
const LaidOutBlock &block,
const std::vector<int> &preparedPath) const {
@@ -5738,7 +5744,7 @@ void MarkdownArticle::Impl::finalizeRelayout(int heightBottom) {
_laidOutWidth = std::min(
_width,
std::max(
ArticleContentMaxRight(_blocks, layoutStyle()) + page.right(),
ArticleContentMaxRight(_blocks, layoutStyle(), contentRtl()) + page.right(),
page.left() + page.right() + 1));
pruneTaskMarkerRuntimes();
prunePlaceholderRuntimes();
@@ -5786,6 +5792,7 @@ void MarkdownArticle::Impl::relayout(int width) {
.mediaPixelScale = _mediaPixelScale,
.useArticleBands = true,
.editMode = _content.editMode,
.rtl = contentRtl(),
.syntaxHighlightTracker = this,
.cachedTextLeafs = &_cachedTextLeafs,
.repaint = _textRepaint,
@@ -5874,6 +5881,7 @@ void MarkdownArticle::Impl::relayoutRetained(int width) {
.mediaPixelScale = _mediaPixelScale,
.useArticleBands = true,
.editMode = _content.editMode,
.rtl = contentRtl(),
.syntaxHighlightTracker = this,
.cachedTextLeafs = &_cachedTextLeafs,
.repaint = _textRepaint,
@@ -317,6 +317,7 @@ struct LayoutContext {
bool tightList = false;
bool useArticleBands = false;
bool editMode = false;
bool rtl = false;
bool hideEmptyQuoteAuthor = false;
bool allowAsyncSyntaxHighlighting = true;
CodeBlockSyntaxHighlightTracker *syntaxHighlightTracker = nullptr;
@@ -2823,7 +2823,9 @@ int LayoutBlocks(
currentScrollOwner,
logicalWidth);
block->markerWidth = std::max(list.markerWidth, markerTextWidth);
const auto bodyLeft = left + block->markerWidth + list.markerSkip;
const auto bodyLeft = context.rtl
? left
: (left + block->markerWidth + list.markerSkip);
const auto bodyWidth = std::max(
width - block->markerWidth - list.markerSkip,
1);
@@ -2872,13 +2874,18 @@ int LayoutBlocks(
(bodyLineHeight - markerTextHeight) / 2,
0);
if (task) {
const auto markerLeft = context.rtl
? (left + width - list.taskCheck.diameter)
: left;
block->markerRect = QRect(
left,
markerLeft,
markerTop,
list.taskCheck.diameter,
list.taskCheck.diameter);
} else if (ordered) {
const auto markerLeft = left + block->markerWidth - markerTextWidth;
const auto markerLeft = context.rtl
? (left + width - block->markerWidth)
: (left + block->markerWidth - markerTextWidth);
const auto markerLeafBaseline = LeafFirstLineBaseline(
block->marker,
QRect(0, 0, markerTextWidth, markerTextHeight),
@@ -2889,7 +2896,10 @@ int LayoutBlocks(
markerTextWidth,
markerTextHeight);
} else {
block->markerCenter = BulletMarkerCenter(left, markerBaseline, st);
const auto center = BulletMarkerCenter(left, markerBaseline, st);
block->markerCenter = context.rtl
? QPoint(left + width - (center.x() - left), center.y())
: center;
}
block->contentRect = QRect(bodyLeft, top, bodyWidth, rowHeight);
block->horizontalScrollMax = scrollOwner
@@ -2943,7 +2953,7 @@ int LayoutBlocks(
const auto markerColumn = context.listItemContentShift;
const auto step = std::max(st.textPadding.left(), markerColumn);
const auto indent = depthDelta * step - markerColumn;
const auto listLeft = left + indent;
const auto listLeft = context.rtl ? left : (left + indent);
const auto listWidth = std::max(width - indent, 1);
const auto currentScrollOwner = NextActiveScrollOwner(
analysis,
@@ -3746,7 +3756,8 @@ int LayoutBlocks(
[[nodiscard]] int BlockContentMaxRight(
const LaidOutBlock &block,
const style::Markdown &st) {
const style::Markdown &st,
bool rtl) {
const auto outerRight = block.outer.x() + block.outer.width();
const auto textRight = [&] {
const auto &leaf = block.placeholderLeaf.isEmpty()
@@ -3760,7 +3771,7 @@ int LayoutBlocks(
const auto childrenRight = [&] {
auto result = 0;
for (const auto &child : block.children) {
result = std::max(result, BlockContentMaxRight(child, st));
result = std::max(result, BlockContentMaxRight(child, st, rtl));
}
return result;
};
@@ -3821,11 +3832,13 @@ int LayoutBlocks(
case PreparedBlockKind::List:
return std::min(childrenRight(), outerRight);
case PreparedBlockKind::ListItem:
return std::min(
std::max(
block.outer.x() + block.markerWidth,
childrenRight()),
outerRight);
return rtl
? outerRight
: std::min(
std::max(
block.outer.x() + block.markerWidth,
childrenRight()),
outerRight);
case PreparedBlockKind::Quote:
return block.pullquote
? outerRight
@@ -4026,7 +4039,8 @@ std::optional<int> RecountLaidOutBlocks(
int ArticleContentMaxRight(
const std::vector<LaidOutBlock> &blocks,
const style::Markdown &st) {
const style::Markdown &st,
bool rtl) {
auto result = 0;
for (const auto &block : blocks) {
const auto bandPadding = UsesMediaBand(block.kind)
@@ -4034,7 +4048,7 @@ int ArticleContentMaxRight(
: st.textPadding;
result = std::max(
result,
BlockContentMaxRight(block, st) - bandPadding.left());
BlockContentMaxRight(block, st, rtl) - bandPadding.left());
}
return result;
}
@@ -35,6 +35,7 @@ namespace Iv::Markdown {
LayoutContext context);
[[nodiscard]] int ArticleContentMaxRight(
const std::vector<LaidOutBlock> &blocks,
const style::Markdown &st);
const style::Markdown &st,
bool rtl);
} // namespace Iv::Markdown