Avoid hypehnation at page breaks

This commit is contained in:
jpirnay
2026-04-05 10:47:05 +02:00
parent 1398454ad8
commit 1509af8729
4 changed files with 132 additions and 29 deletions
@@ -1091,7 +1091,11 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
: self->viewportWidth;
self->currentTextBlock->layoutAndExtractLines(
self->renderer, self->fontId, effectiveWidth,
[self](const std::shared_ptr<TextBlock>& textBlock) { self->addLineToPage(textBlock); }, false);
[self](const std::shared_ptr<TextBlock>& textBlock, const bool lineEndsWithHyphenatedWord,
const bool suppressHyphenationRetry) {
return self->addLineToPage(textBlock, lineEndsWithHyphenatedWord, suppressHyphenationRetry);
},
false);
}
}
@@ -1371,7 +1375,9 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
return true;
}
void ChapterHtmlSlimParser::addLineToPage(std::shared_ptr<TextBlock> line) {
ParsedText::LineProcessResult ChapterHtmlSlimParser::addLineToPage(std::shared_ptr<TextBlock> line,
const bool lineEndsWithHyphenatedWord,
const bool suppressHyphenationRetry) {
const int lineHeight = renderer.getLineHeight(fontId) * lineCompression;
if (!currentPage) {
@@ -1387,6 +1393,13 @@ void ChapterHtmlSlimParser::addLineToPage(std::shared_ptr<TextBlock> line) {
currentPageNextY = 0;
}
const bool noRoomForAnotherLine =
currentPageNextY + lineHeight <= viewportHeight && currentPageNextY + (lineHeight * 2) > viewportHeight;
if (lineEndsWithHyphenatedWord && !suppressHyphenationRetry && noRoomForAnotherLine) {
LOG_DBG("EHP", "Requesting line rerender without hyphenation to avoid page-break split word");
return ParsedText::LineProcessResult::RetryWithoutHyphenation;
}
// Track cumulative words to assign footnotes to the page containing their anchor
wordsExtractedInBlock += line->wordCount();
auto footnoteIt = pendingFootnotes.begin();
@@ -1400,6 +1413,7 @@ void ChapterHtmlSlimParser::addLineToPage(std::shared_ptr<TextBlock> line) {
const int16_t xOffset = line->getBlockStyle().leftInset();
currentPage->elements.push_back(std::make_shared<PageLine>(line, xOffset, currentPageNextY));
currentPageNextY += lineHeight;
return ParsedText::LineProcessResult::Accepted;
}
void ChapterHtmlSlimParser::makePages() {
@@ -1431,7 +1445,10 @@ void ChapterHtmlSlimParser::makePages() {
currentTextBlock->layoutAndExtractLines(
renderer, fontId, effectiveWidth,
[this](const std::shared_ptr<TextBlock>& textBlock) { addLineToPage(textBlock); });
[this](const std::shared_ptr<TextBlock>& textBlock, const bool lineEndsWithHyphenatedWord,
const bool suppressHyphenationRetry) {
return addLineToPage(textBlock, lineEndsWithHyphenatedWord, suppressHyphenationRetry);
});
// Fallback: transfer any remaining pending footnotes to current page.
// Normally addLineToPage handles this via word-index tracking, but this catches
@@ -151,7 +151,8 @@ class ChapterHtmlSlimParser {
~ChapterHtmlSlimParser() = default;
bool parseAndBuildPages();
void addLineToPage(std::shared_ptr<TextBlock> line);
ParsedText::LineProcessResult addLineToPage(std::shared_ptr<TextBlock> line, bool lineEndsWithHyphenatedWord,
bool suppressHyphenationRetry);
const std::vector<std::pair<std::string, uint16_t>>& getAnchors() const { return anchorData; }
const std::vector<uint16_t>& getParagraphIndexPerPage() const { return paragraphIndexPerPage; }
};