Replaced line-breaker.
Fixed raw emoji segments breaking.
This commit is contained in:
parent
f3ae54ab7a
commit
2e409fe347
|
@ -95,7 +95,7 @@ font-kit = "0.11"
|
||||||
unic-langid = { version = "0.9", features = ["serde"] }
|
unic-langid = { version = "0.9", features = ["serde"] }
|
||||||
unicase = "2"
|
unicase = "2"
|
||||||
harfbuzz_rs = "2"
|
harfbuzz_rs = "2"
|
||||||
xi-unicode = "0.3"
|
unicode-linebreak = "0.1"
|
||||||
pathfinder_geometry = "0.5"
|
pathfinder_geometry = "0.5"
|
||||||
hyphenation = { version = "0.8", default-features = false }
|
hyphenation = { version = "0.8", default-features = false }
|
||||||
regex = "1"
|
regex = "1"
|
||||||
|
|
|
@ -4,7 +4,6 @@ use crate::{context::LayoutDirection, crate_util::FxHashMap};
|
||||||
|
|
||||||
use super::Txt;
|
use super::Txt;
|
||||||
use unicode_bidi::BidiInfo;
|
use unicode_bidi::BidiInfo;
|
||||||
use xi_unicode::LineBreakIterator;
|
|
||||||
|
|
||||||
/// The type of a text segment.
|
/// The type of a text segment.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
|
||||||
|
@ -182,42 +181,46 @@ impl SegmentedText {
|
||||||
let text_str: &str = &text;
|
let text_str: &str = &text;
|
||||||
let bidi = BidiInfo::new(text_str, Some(base_direction.into()));
|
let bidi = BidiInfo::new(text_str, Some(base_direction.into()));
|
||||||
|
|
||||||
for (offset, hard_break) in LineBreakIterator::new(text_str) {
|
for (offset, kind) in unicode_linebreak::linebreaks(text_str) {
|
||||||
// a hard-break is a '\n', '\r', "\r\n".
|
match kind {
|
||||||
if hard_break {
|
// a hard-break is a '\n', '\r', "\r\n" or text end.
|
||||||
// start of this segment.
|
unicode_linebreak::BreakOpportunity::Mandatory => {
|
||||||
let start = segs.last().map(|s| s.end).unwrap_or(0);
|
// start of this segment.
|
||||||
|
let start = segs.last().map(|s| s.end).unwrap_or(0);
|
||||||
|
|
||||||
// The segment can have other characters before the line-break character(s).
|
// The segment can have other characters before the line-break character(s).
|
||||||
|
|
||||||
let seg = &text_str[start..offset];
|
let seg = &text_str[start..offset];
|
||||||
let break_start = if seg.ends_with("\r\n") {
|
|
||||||
// the break was a "\r\n"
|
|
||||||
offset - 2
|
|
||||||
} else {
|
|
||||||
debug_assert!(
|
|
||||||
seg.ends_with('\n') || seg.ends_with('\r') || seg.ends_with('\u{85}'),
|
|
||||||
"seg: {seg:#?}"
|
|
||||||
);
|
|
||||||
// the break was a '\n', '\r' or NEL
|
|
||||||
offset - 1
|
|
||||||
};
|
|
||||||
|
|
||||||
if break_start > start {
|
let break_start = if seg.ends_with("\r\n") {
|
||||||
// the segment has more characters than the line-break character(s).
|
// the break was a "\r\n"
|
||||||
Self::push_seg(text_str, &bidi, &mut segs, break_start);
|
offset - 2
|
||||||
|
} else if seg.ends_with('\n') || seg.ends_with('\r') || seg.ends_with('\u{85}') {
|
||||||
|
// the break was a '\n', '\r' or NEL
|
||||||
|
offset - 1
|
||||||
|
} else {
|
||||||
|
// "break" at end of string
|
||||||
|
debug_assert_eq!(offset, text_str.len());
|
||||||
|
offset
|
||||||
|
};
|
||||||
|
|
||||||
|
if break_start > start {
|
||||||
|
// the segment has more characters than the line-break character(s).
|
||||||
|
Self::push_seg(text_str, &bidi, &mut segs, break_start);
|
||||||
|
}
|
||||||
|
if break_start < offset {
|
||||||
|
// the line break character(s).
|
||||||
|
segs.push(TextSegment {
|
||||||
|
kind: TextSegmentKind::LineBreak,
|
||||||
|
end: offset,
|
||||||
|
level: bidi.levels[break_start],
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if break_start < offset {
|
_ => {
|
||||||
// the line break character(s).
|
// soft break, handled by our own segmentation
|
||||||
segs.push(TextSegment {
|
Self::push_seg(text_str, &bidi, &mut segs, offset);
|
||||||
kind: TextSegmentKind::LineBreak,
|
|
||||||
end: offset,
|
|
||||||
level: bidi.levels[break_start],
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// is a soft-break, an opportunity to break the line if needed
|
|
||||||
Self::push_seg(text_str, &bidi, &mut segs, offset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SegmentedText {
|
SegmentedText {
|
||||||
|
|
|
@ -2105,7 +2105,7 @@ impl<'a> ShapedSegment<'a> {
|
||||||
&full_text[start..end]
|
&full_text[start..end]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the insert index in the string that is nearest to `x`.
|
/// Gets the insert index in the segment text that is nearest to `x`.
|
||||||
pub fn nearest_char_index(&self, x: Px, full_text: &str) -> usize {
|
pub fn nearest_char_index(&self, x: Px, full_text: &str) -> usize {
|
||||||
let x = x.0 as f32;
|
let x = x.0 as f32;
|
||||||
let q = self
|
let q = self
|
||||||
|
|
Loading…
Reference in New Issue