diff --git a/lib/Epub/Epub/ParsedText.cpp b/lib/Epub/Epub/ParsedText.cpp index 193b320e..e348270b 100644 --- a/lib/Epub/Epub/ParsedText.cpp +++ b/lib/Epub/Epub/ParsedText.cpp @@ -652,6 +652,11 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const renderer.getSpaceAdvance(fontId, lastCodepoint(words[lastBreakAt + wordIdx - 1]), firstCodepoint(words[lastBreakAt + wordIdx]), wordStyles[lastBreakAt + wordIdx - 1]); } else if (wordIdx > 0 && continuesVec[lastBreakAt + wordIdx]) { + // Non-breaking space tokens (" " with continues=true) are visible, stretchable spaces — + // count them as justifiable gaps so justifyExtra is distributed to them too. + if (words[lastBreakAt + wordIdx] == " ") { + actualGapCount++; + } // Cross-boundary kerning for continuation words (e.g. nonbreaking spaces, attached punctuation) totalNaturalGaps += renderer.getKerning(fontId, lastCodepoint(words[lastBreakAt + wordIdx - 1]), @@ -693,6 +698,11 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const advance += renderer.getKerning(fontId, lastCodepoint(words[lastBreakAt + wordIdx]), firstCodepoint(words[lastBreakAt + wordIdx + 1]), wordStyles[lastBreakAt + wordIdx]); + // Non-breaking space tokens are stretchable — expand them during justification like normal spaces. + if (words[lastBreakAt + wordIdx] == " " && continuesVec[lastBreakAt + wordIdx] && + blockStyle.alignment == CssTextAlign::Justify && !isLastLine) { + advance += justifyExtra; + } xpos += advance; } else { int gap = 0;