diff --git a/CHANGELOG.md b/CHANGELOG.md index 32e2bc492..942351be1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This release has an [MSRV] of 1.88. #### Parley +- `complex-scripts` Cargo feature to enable dictionary-based line and word breaking for complex scripts (CJK, Thai, Khmer, Lao, Myanmar). When disabled, the lightweight segmenter is used (no change in default behavior). - `PlainEditor`, `Layout`, `LayoutAccessibility`, and `Generation` now implement `Debug`. ([#615][] by [@NandishwarSingh][]) Note: The `Layout` implementation provides a compact summary by default; the alternate form (`{:#?}`) formats the full underlying data. diff --git a/parley/Cargo.toml b/parley/Cargo.toml index 00c96c358..a5decdfb0 100644 --- a/parley/Cargo.toml +++ b/parley/Cargo.toml @@ -23,6 +23,9 @@ libm = ["fontique/libm", "peniko/libm", "skrifa/libm", "dep:core_maths"] # Enables support for system font backends system = ["std", "fontique/system"] accesskit = ["dep:accesskit"] +# Enables dictionary-based line and word breaking for complex scripts (CJK, Thai, Khmer, Lao, Myanmar). +# When disabled, a lightweight segmenter is used that falls back to character-level breaks for those scripts. +complex-scripts = [] [dependencies] skrifa = { workspace = true } diff --git a/parley/src/analysis/mod.rs b/parley/src/analysis/mod.rs index 460e78d96..c34998759 100644 --- a/parley/src/analysis/mod.rs +++ b/parley/src/analysis/mod.rs @@ -43,32 +43,33 @@ impl AnalysisDataSources { #[inline(always)] fn word_segmenter(&self) -> WordSegmenterBorrowed<'static> { - const { WordSegmenter::new_for_non_complex_scripts(WordBreakInvariantOptions::default()) } + #[cfg(feature = "complex-scripts")] + { + WordSegmenter::new_dictionary(WordBreakInvariantOptions::default()) + } + #[cfg(not(feature = "complex-scripts"))] + { + const { WordSegmenter::new_for_non_complex_scripts(WordBreakInvariantOptions::default()) } + } } #[inline(always)] fn line_segmenter(&self, word_break_strength: WordBreak) -> LineSegmenterBorrowed<'static> { match word_break_strength { WordBreak::Normal => { - const { - let mut opt = LineBreakOptions::default(); - opt.word_option = Some(LineBreakWordOption::Normal); - LineSegmenter::new_for_non_complex_scripts(opt) - } + let mut opt = LineBreakOptions::default(); + opt.word_option = Some(LineBreakWordOption::Normal); + line_segmenter_impl(opt) } WordBreak::BreakAll => { - const { - let mut opt = LineBreakOptions::default(); - opt.word_option = Some(LineBreakWordOption::BreakAll); - LineSegmenter::new_for_non_complex_scripts(opt) - } + let mut opt = LineBreakOptions::default(); + opt.word_option = Some(LineBreakWordOption::BreakAll); + line_segmenter_impl(opt) } WordBreak::KeepAll => { - const { - let mut opt = LineBreakOptions::default(); - opt.word_option = Some(LineBreakWordOption::KeepAll); - LineSegmenter::new_for_non_complex_scripts(opt) - } + let mut opt = LineBreakOptions::default(); + opt.word_option = Some(LineBreakWordOption::KeepAll); + line_segmenter_impl(opt) } } } @@ -94,6 +95,18 @@ impl AnalysisDataSources { } } +#[cfg(feature = "complex-scripts")] +#[inline(always)] +fn line_segmenter_impl(opt: LineBreakOptions<'_>) -> LineSegmenterBorrowed<'static> { + LineSegmenter::new_dictionary(opt) +} + +#[cfg(not(feature = "complex-scripts"))] +#[inline(always)] +fn line_segmenter_impl(opt: LineBreakOptions<'_>) -> LineSegmenterBorrowed<'static> { + LineSegmenter::new_for_non_complex_scripts(opt) +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) struct CharInfo { /// The line/word breaking boundary classification of this character.