diff --git a/lib/Epub/Epub/ParsedText.cpp b/lib/Epub/Epub/ParsedText.cpp index d4d66144..b66b36ee 100644 --- a/lib/Epub/Epub/ParsedText.cpp +++ b/lib/Epub/Epub/ParsedText.cpp @@ -261,10 +261,18 @@ void ParsedText::addWord(std::string word, const EpdFontFamily::Style fontStyle, } } -int ParsedText::resolveFirstLineIndent(const bool isFirstLine) const { - if (isFirstLine && blockStyle.textIndentDefined && (blockStyle.textIndent < 0 || !extraParagraphSpacing) && - isNaturalAlign) { - return blockStyle.textIndent; +int ParsedText::resolveFirstLineIndent(const bool isFirstLine, const GfxRenderer& renderer, const int fontId) const { + if (!isFirstLine || !isNaturalAlign) { + return 0; + } + if (blockStyle.textIndentDefined) { + if (blockStyle.textIndent < 0 || !extraParagraphSpacing) { + return blockStyle.textIndent; + } + return 0; + } + if (!extraParagraphSpacing) { + return renderer.getSpaceWidth(fontId, EpdFontFamily::REGULAR) * 3; } return 0; } @@ -293,9 +301,6 @@ void ParsedText::layoutAndExtractLines(const GfxRenderer& renderer, const int fo blockStyle.alignment == CssTextAlign::Justify || (blockStyle.isRtl ? blockStyle.alignment == CssTextAlign::Right : blockStyle.alignment == CssTextAlign::Left); - // Apply fixed transforms before any per-line layout work. - applyParagraphIndent(); - // Ensure SD card font glyph metrics are loaded before measuring word widths. // For flash-based fonts isSdCardFont() returns false and this block is skipped // entirely — no heap allocation. For SD card fonts this reads glyph metadata @@ -356,7 +361,7 @@ std::vector ParsedText::computeLineBreaks(const GfxRenderer& renderer, c return {}; } - const int firstLineIndent = resolveFirstLineIndent(true); + const int firstLineIndent = resolveFirstLineIndent(true, renderer, fontId); // Ensure any word that would overflow even as the first entry on a line is split using fallback hyphenation. for (size_t i = 0; i < wordWidths.size(); ++i) { @@ -462,25 +467,11 @@ std::vector ParsedText::computeLineBreaks(const GfxRenderer& renderer, c return lineBreakIndices; } -void ParsedText::applyParagraphIndent() { - if (extraParagraphSpacing || words.empty()) { - return; - } - - if (blockStyle.textIndentDefined) { - // CSS text-indent is explicitly set (even if 0) - don't use fallback EmSpace - // The actual indent positioning is handled in extractLine() - } else if (isNaturalAlign) { - // No CSS text-indent defined - use EmSpace fallback for visual indent - words.front().insert(0, "\xe2\x80\x83"); - } -} - // Builds break indices while opportunistically splitting the word that would overflow the current line. std::vector ParsedText::computeHyphenatedLineBreaks(const GfxRenderer& renderer, const int fontId, const int pageWidth, std::vector& wordWidths, std::vector& continuesVec) { - const int firstLineIndent = resolveFirstLineIndent(true); + const int firstLineIndent = resolveFirstLineIndent(true, renderer, fontId); std::vector lineBreakIndices; size_t currentIndex = 0; @@ -643,7 +634,7 @@ void ParsedText::extractLine(const size_t breakIndex, const int pageWidth, const const size_t lastBreakAt = breakIndex > 0 ? lineBreakIndices[breakIndex - 1] : 0; const size_t lineWordCount = lineBreak - lastBreakAt; - const int firstLineIndent = resolveFirstLineIndent(breakIndex == 0); + const int firstLineIndent = resolveFirstLineIndent(breakIndex == 0, renderer, fontId); // Build line data by moving from the original vectors using index range std::vector lineWords; diff --git a/lib/Epub/Epub/ParsedText.h b/lib/Epub/Epub/ParsedText.h index df5dd3f1..9c3af7cb 100644 --- a/lib/Epub/Epub/ParsedText.h +++ b/lib/Epub/Epub/ParsedText.h @@ -30,8 +30,7 @@ class ParsedText { std::vector reorderedFocusSuffixScratch; std::vector visualOrderScratch; - void applyParagraphIndent(); - int resolveFirstLineIndent(bool isFirstLine) const; + int resolveFirstLineIndent(bool isFirstLine, const GfxRenderer& renderer, int fontId) const; std::vector computeLineBreaks(const GfxRenderer& renderer, int fontId, int pageWidth, std::vector& wordWidths, std::vector& continuesVec); std::vector computeHyphenatedLineBreaks(const GfxRenderer& renderer, int fontId, int pageWidth, diff --git a/lib/Epub/Epub/blocks/BlockStyle.h b/lib/Epub/Epub/blocks/BlockStyle.h index 23ed790b..fbc18d42 100644 --- a/lib/Epub/Epub/blocks/BlockStyle.h +++ b/lib/Epub/Epub/blocks/BlockStyle.h @@ -115,7 +115,7 @@ struct BlockStyle { blockStyle.paddingRight = std::min(cssStyle.paddingRight.toPixelsInt16(emSize, vw), maxHorizontalInsetPx); // For textIndent: if it's a percentage we can't resolve (no viewport width), - // leave textIndentDefined=false so the EmSpace fallback in applyParagraphIndent() is used + // leave textIndentDefined=false so the space-width fallback in resolveFirstLineIndent() is used if (cssStyle.hasTextIndent() && cssStyle.textIndent.isResolvable(vw)) { blockStyle.textIndent = cssStyle.textIndent.toPixelsInt16(emSize, vw); blockStyle.textIndentDefined = true; diff --git a/lib/Epub/Epub/blocks/TextBlock.cpp b/lib/Epub/Epub/blocks/TextBlock.cpp index 96c96f51..9260fa32 100644 --- a/lib/Epub/Epub/blocks/TextBlock.cpp +++ b/lib/Epub/Epub/blocks/TextBlock.cpp @@ -61,31 +61,14 @@ void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int if (!scanning && (currentStyle & EpdFontFamily::UNDERLINE) != 0) { const std::string& w = words[i]; - const int fullWordWidth = renderer.getTextWidth(fontId, w.c_str(), currentStyle, baseDir); - // y is the top of the text line; add ascender to reach baseline, then offset 2px below + int underlineWidth = renderer.getTextWidth(fontId, w.c_str(), currentStyle, baseDir); const int underlineY = wordY + ascender + 2; - int startX = wordX; - int underlineWidth = fullWordWidth; - - // if word starts with em-space ("\xe2\x80\x83"), account for the additional indent before drawing the line - if (w.size() >= 3 && static_cast(w[0]) == 0xE2 && static_cast(w[1]) == 0x80 && - static_cast(w[2]) == 0x83) { - const char* visiblePtr = w.c_str() + 3; - const int prefixWidth = renderer.getTextAdvanceX(fontId, "\xe2\x80\x83", currentStyle); - const int visibleWidth = renderer.getTextWidth(fontId, visiblePtr, currentStyle, baseDir); - startX = wordX + prefixWidth; - underlineWidth = visibleWidth; - } - - // SUP/SUB words are rendered at 50% glyph scale (see the baseline comment - // above and drawText), but getTextWidth reports the full-size width, so the - // underline would be drawn ~2x too long. Halve it to match the scaled glyphs. if ((currentStyle & (EpdFontFamily::SUP | EpdFontFamily::SUB)) != 0) { underlineWidth = (underlineWidth + 1) / 2; } - renderer.drawLine(startX, underlineY, startX + underlineWidth, underlineY, true); + renderer.drawLine(wordX, underlineY, wordX + underlineWidth, underlineY, true); } } }