Fix br alignment reset behaviour
This commit is contained in:
@@ -22,6 +22,10 @@ struct BlockStyle {
|
|||||||
int16_t textIndent = 0;
|
int16_t textIndent = 0;
|
||||||
bool textIndentDefined = false; // true if text-indent was explicitly set in CSS
|
bool textIndentDefined = false; // true if text-indent was explicitly set in CSS
|
||||||
bool textAlignDefined = false; // true if text-align was explicitly set in CSS
|
bool textAlignDefined = false; // true if text-align was explicitly set in CSS
|
||||||
|
// Set when this block was created by a <br> element. Used by startNewTextBlock to inject
|
||||||
|
// a full line-height gap when the <br> block stays empty (section-break use case).
|
||||||
|
// NOT propagated through getCombinedBlockStyle so it can't leak into sibling blocks.
|
||||||
|
bool fromBrElement = false;
|
||||||
|
|
||||||
// Combined horizontal insets (margin + padding)
|
// Combined horizontal insets (margin + padding)
|
||||||
[[nodiscard]] int16_t leftInset() const { return marginLeft + paddingLeft; }
|
[[nodiscard]] int16_t leftInset() const { return marginLeft + paddingLeft; }
|
||||||
@@ -58,6 +62,9 @@ struct BlockStyle {
|
|||||||
combinedBlockStyle.alignment = alignment;
|
combinedBlockStyle.alignment = alignment;
|
||||||
combinedBlockStyle.textAlignDefined = textAlignDefined;
|
combinedBlockStyle.textAlignDefined = textAlignDefined;
|
||||||
}
|
}
|
||||||
|
// fromBrElement is never propagated — it is consumed by startNewTextBlock
|
||||||
|
// when the empty <br> block is merged with the following paragraph.
|
||||||
|
combinedBlockStyle.fromBrElement = false;
|
||||||
return combinedBlockStyle;
|
return combinedBlockStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,21 @@ void ChapterHtmlSlimParser::startNewTextBlock(const BlockStyle& blockStyle) {
|
|||||||
// Merge with existing block style to accumulate CSS styling from parent block elements.
|
// Merge with existing block style to accumulate CSS styling from parent block elements.
|
||||||
// This handles cases like <div style="margin-bottom:2em"><h1>text</h1></div> where the
|
// This handles cases like <div style="margin-bottom:2em"><h1>text</h1></div> where the
|
||||||
// div's margin should be preserved, even though it has no direct text content.
|
// div's margin should be preserved, even though it has no direct text content.
|
||||||
currentTextBlock->setBlockStyle(currentTextBlock->getBlockStyle().getCombinedBlockStyle(blockStyle));
|
BlockStyle incoming = blockStyle;
|
||||||
|
const bool brGapPending = currentTextBlock->getBlockStyle().fromBrElement;
|
||||||
|
if (brGapPending) {
|
||||||
|
// The empty block was created by a <br> section separator. Inject a full line of
|
||||||
|
// blank space before the following paragraph so the scene/section break is visible.
|
||||||
|
// This only fires when the <br> block stayed empty (i.e. no inline text was added).
|
||||||
|
const int16_t lineHeight = static_cast<int16_t>(renderer.getLineHeight(fontId) * lineCompression + 0.5f);
|
||||||
|
incoming.marginTop = static_cast<int16_t>(incoming.marginTop + lineHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockStyle merged = currentTextBlock->getBlockStyle().getCombinedBlockStyle(incoming);
|
||||||
|
// Preserve only whether the current empty block still represents <br> separators.
|
||||||
|
// This lets consecutive <br> accumulate one line each without leaking the flag to real content blocks.
|
||||||
|
merged.fromBrElement = blockStyle.fromBrElement;
|
||||||
|
currentTextBlock->setBlockStyle(merged);
|
||||||
|
|
||||||
if (!pendingAnchorId.empty()) {
|
if (!pendingAnchorId.empty()) {
|
||||||
anchorData.push_back({std::move(pendingAnchorId), static_cast<uint16_t>(completedPageCount)});
|
anchorData.push_back({std::move(pendingAnchorId), static_cast<uint16_t>(completedPageCount)});
|
||||||
@@ -574,7 +588,16 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
// flush word preceding <br/> to currentTextBlock before calling startNewTextBlock
|
// flush word preceding <br/> to currentTextBlock before calling startNewTextBlock
|
||||||
self->flushPartWordBuffer();
|
self->flushPartWordBuffer();
|
||||||
}
|
}
|
||||||
self->startNewTextBlock(self->currentTextBlock->getBlockStyle());
|
// Build a neutral <br> style that keeps inline alignment/indent context but avoids
|
||||||
|
// carrying cumulative margins from previous empty blocks (which can force spurious page breaks).
|
||||||
|
const BlockStyle& currentStyle = self->currentTextBlock->getBlockStyle();
|
||||||
|
BlockStyle brStyle;
|
||||||
|
brStyle.alignment = currentStyle.alignment;
|
||||||
|
brStyle.textAlignDefined = currentStyle.textAlignDefined;
|
||||||
|
brStyle.textIndent = currentStyle.textIndent;
|
||||||
|
brStyle.textIndentDefined = currentStyle.textIndentDefined;
|
||||||
|
brStyle.fromBrElement = true;
|
||||||
|
self->startNewTextBlock(brStyle);
|
||||||
} else {
|
} else {
|
||||||
self->currentCssStyle = cssStyle;
|
self->currentCssStyle = cssStyle;
|
||||||
self->startNewTextBlock(userAlignmentBlockStyle);
|
self->startNewTextBlock(userAlignmentBlockStyle);
|
||||||
@@ -986,11 +1009,15 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n
|
|||||||
// Margins/padding are preserved so parent element spacing still accumulates correctly.
|
// Margins/padding are preserved so parent element spacing still accumulates correctly.
|
||||||
if (self->currentTextBlock && self->currentTextBlock->isEmpty()) {
|
if (self->currentTextBlock && self->currentTextBlock->isEmpty()) {
|
||||||
auto style = self->currentTextBlock->getBlockStyle();
|
auto style = self->currentTextBlock->getBlockStyle();
|
||||||
style.textAlignDefined = false;
|
// Keep alignment for synthetic empty <br> separator blocks so following inline
|
||||||
style.alignment = (self->paragraphAlignment == static_cast<uint8_t>(CssTextAlign::None))
|
// text after <br/> inside centered/right-aligned containers preserves alignment.
|
||||||
? CssTextAlign::Justify
|
if (!style.fromBrElement) {
|
||||||
: static_cast<CssTextAlign>(self->paragraphAlignment);
|
style.textAlignDefined = false;
|
||||||
self->currentTextBlock->setBlockStyle(style);
|
style.alignment = (self->paragraphAlignment == static_cast<uint8_t>(CssTextAlign::None))
|
||||||
|
? CssTextAlign::Justify
|
||||||
|
: static_cast<CssTextAlign>(self->paragraphAlignment);
|
||||||
|
self->currentTextBlock->setBlockStyle(style);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user