fix: keep list item bullet inline with nested paragraph text (#2589)

This commit is contained in:
Jan Steinke
2026-07-13 12:06:43 +03:00
committed by GitHub
parent bfa1d706b1
commit 552b2683e6
4 changed files with 87 additions and 1 deletions
@@ -225,6 +225,7 @@ void ChapterHtmlSlimParser::flushPartWordBuffer() {
currentTextBlock->addWord(partWordBuffer, fontStyle, false, nextWordContinues);
partWordBufferIndex = 0;
nextWordContinues = false;
listItemBulletOnly = false;
}
// start a new text block if needed
@@ -254,6 +255,17 @@ void ChapterHtmlSlimParser::startNewTextBlock(const BlockStyle& blockStyle) {
return;
}
// <li> added a bullet as the first word, making the block non-empty. When a nested
// block-level child (<p>, <div>, etc.) opens, reuse the block instead of flushing
// the bullet to its own line. The bullet stays inline with the child's text.
if (listItemBulletOnly) {
const auto style = currentTextBlock->getBlockStyle();
currentTextBlock->setBlockStyle(style.getCombinedBlockStyle(blockStyle, BlockStyle::CombineAxis::Vertical));
listItemBulletOnly = false;
flushPendingAnchor();
return;
}
makePages();
}
// If the pending anchor is a TOC chapter boundary, force a page break after the previous
@@ -261,6 +273,7 @@ void ChapterHtmlSlimParser::startNewTextBlock(const BlockStyle& blockStyle) {
flushPendingAnchor();
currentTextBlock.reset(new ParsedText(extraParagraphSpacing, hyphenationEnabled, focusReadingEnabled, blockStyle));
wordsExtractedInBlock = 0;
listItemBulletOnly = false;
}
void ChapterHtmlSlimParser::emitHorizontalRule(const BlockStyle& blockStyle) {
@@ -880,6 +893,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
if (strcmp(name, "li") == 0) {
self->currentTextBlock->addWord("\xe2\x80\xa2", EpdFontFamily::REGULAR);
self->listItemBulletOnly = true;
}
}
} else if (matches(name, UNDERLINE_TAGS, std::size(UNDERLINE_TAGS))) {
@@ -1286,6 +1300,13 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n
}
self->blockStyleStack.pop_back();
}
// </li> closes: if the bullet never got inline text (empty <li> or <li> with only
// block children that were flushed), clear the flag so the next sibling doesn't
// merge into this block.
if (strcmp(name, "li") == 0) {
self->listItemBulletOnly = false;
}
}
}
@@ -80,6 +80,7 @@ class ChapterHtmlSlimParser {
int tableDepth = 0;
int tableRowIndex = 0;
int tableColIndex = 0;
bool listItemBulletOnly = false; // true when currentTextBlock has only the <li> bullet
// Anchor-to-page mapping: tracks which page each HTML id attribute lands on
int completedPageCount = 0;