From 579d140ee91404814b421d062a49c3419fb54a99 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Sat, 7 Mar 2026 10:52:31 +0100 Subject: [PATCH] Some fixes according to review --- lib/Epub/Epub/hyphenation/Hyphenator.cpp | 35 +++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/Epub/Epub/hyphenation/Hyphenator.cpp b/lib/Epub/Epub/hyphenation/Hyphenator.cpp index c0fdb85e..18f4eddb 100644 --- a/lib/Epub/Epub/hyphenation/Hyphenator.cpp +++ b/lib/Epub/Epub/hyphenation/Hyphenator.cpp @@ -160,6 +160,15 @@ std::vector Hyphenator::breakOffsets(const std::string& w trimSurroundingPunctuationAndFootnote(cps); const auto* hyphenator = cachedHyphenator_; + // Detect apostrophe-like separators early; used by both branches below. + bool hasApostropheLikeSeparator = false; + for (const auto& cp : cps) { + if (isApostrophe(cp.value)) { + hasApostropheLikeSeparator = true; + break; + } + } + // Explicit hyphen markers (soft or hard) take precedence over language breaks. auto explicitBreakInfos = buildExplicitBreakInfos(cps); if (!explicitBreakInfos.empty()) { @@ -179,26 +188,26 @@ std::vector Hyphenator::breakOffsets(const std::string& w // Result: 6 sorted break points; the line-breaker picks the widest prefix that fits. if (hyphenator) { appendSegmentPatternBreaks(cps, *hyphenator, /*includeFallback=*/false, explicitBreakInfos); - // Merge explicit and pattern breaks into ascending byte-offset order. - sortAndDedupeBreakInfos(explicitBreakInfos); } + // Also add apostrophe contraction breaks when present (e.g. "l'état-major" + // has both an explicit hyphen and an apostrophe that can independently break). + if (hasApostropheLikeSeparator) { + appendApostropheContractionBreaks(cps, explicitBreakInfos); + } + // Merge all break points into ascending byte-offset order. + sortAndDedupeBreakInfos(explicitBreakInfos); return explicitBreakInfos; } // Apostrophe-like separators split compounds into alphabetic segments; run Liang on each segment. // This allows words like "all'improvviso" to hyphenate within "improvviso" instead of becoming - // completely unsplittable due to the apostrophe punctuation. - bool hasApostropheLikeSeparator = false; - for (const auto& cp : cps) { - if (isApostrophe(cp.value)) { - hasApostropheLikeSeparator = true; - break; - } - } - - if (hyphenator && hasApostropheLikeSeparator) { + // completely unsplittable due to the apostrophe punctuation. Apostrophe contraction breaks are + // applied regardless of whether a language hyphenator is available. + if (hasApostropheLikeSeparator) { std::vector segmentedBreaks; - appendSegmentPatternBreaks(cps, *hyphenator, includeFallback, segmentedBreaks); + if (hyphenator) { + appendSegmentPatternBreaks(cps, *hyphenator, includeFallback, segmentedBreaks); + } appendApostropheContractionBreaks(cps, segmentedBreaks); sortAndDedupeBreakInfos(segmentedBreaks); return segmentedBreaks;