Restore newline functionality (mostly...)

This commit is contained in:
David Wendt 2020-05-20 23:11:44 -04:00
parent 9f60567f66
commit 5fcaa52687
2 changed files with 56 additions and 46 deletions

View File

@ -174,24 +174,26 @@ impl<'gc> Font<'gc> {
size size
} }
/// Given a line of text, split it into the shortest number of lines that /// Given a line of text, find the first breakpoint within the text.
/// are shorter than `width`.
/// ///
/// This function assumes only `" "` is valid whitespace to split words on, /// This function assumes only `" "` is valid whitespace to split words on,
/// and will not attempt to break words that are longer than `width`. /// and will not attempt to break words that are longer than `width`, nor
/// will it break at newlines.
/// ///
/// The given `offset` determines the start of the initial line. /// The given `offset` determines the start of the initial line, while the
/// `width` indicates how long the line is supposed to be.
///
/// This function yields `None` if the line is not broken.
/// ///
/// TODO: This function and, more generally, this entire file will need to /// TODO: This function and, more generally, this entire file will need to
/// be internationalized to implement AS3 `flash.text.engine`. /// be internationalized to implement AS3 `flash.text.engine`.
pub fn split_wrapped_lines( pub fn wrap_line(
self, self,
text: &str, text: &str,
font_size: Twips, font_size: Twips,
width: Twips, width: Twips,
offset: Twips, offset: Twips,
) -> Vec<usize> { ) -> Option<usize> {
let mut result = vec![];
let mut current_width = width let mut current_width = width
.checked_sub(offset) .checked_sub(offset)
.unwrap_or_else(|| Twips::from_pixels(0.0)); .unwrap_or_else(|| Twips::from_pixels(0.0));
@ -200,29 +202,19 @@ impl<'gc> Font<'gc> {
for word in text.split(' ') { for word in text.split(' ') {
let measure = self.measure(word, font_size); let measure = self.measure(word, font_size);
let line_start = current_word.as_ptr() as usize - text.as_ptr() as usize; let line_start = current_word.as_ptr() as usize - text.as_ptr() as usize;
let line_end = if (line_start + current_word.len() + 1) < text.len() { let line_end = line_start + current_word.len();
line_start + current_word.len() + 1
} else {
line_start + current_word.len()
};
let word_start = word.as_ptr() as usize - text.as_ptr() as usize; let word_start = word.as_ptr() as usize - text.as_ptr() as usize;
let word_end = if (word_start + word.len() + 1) < text.len() { let word_end = word_start + word.len();
word_start + word.len() + 1
} else {
word_start + word.len()
};
if measure.0 > current_width && measure.0 > width { if measure.0 > current_width && measure.0 > width {
//Failsafe for if we get a word wider than the field. //Failsafe for if we get a word wider than the field.
if !current_word.is_empty() { if !current_word.is_empty() {
result.push(line_end); return Some(line_end);
} }
result.push(word_end); return Some(word_end);
current_word = &text[word_end..word_end];
current_width = width;
} else if measure.0 > current_width { } else if measure.0 > current_width {
if !current_word.is_empty() { if !current_word.is_empty() {
result.push(line_end); return Some(line_end);
} }
current_word = &text[word_start..word_end]; current_word = &text[word_start..word_end];
@ -233,7 +225,7 @@ impl<'gc> Font<'gc> {
} }
} }
result None
} }
pub fn descriptor(self) -> FontDescriptor { pub fn descriptor(self) -> FontDescriptor {

View File

@ -44,6 +44,12 @@ impl<'gc> LayoutContext<'gc> {
&mut self.cursor &mut self.cursor
} }
/// Adjust the text layout cursor down to the next line.
fn newline(&mut self, font_size: Twips) {
self.cursor.set_x(Twips::from_pixels(0.0));
self.cursor += (Twips::from_pixels(0.0), font_size).into();
}
fn font(&self) -> Option<Font<'gc>> { fn font(&self) -> Option<Font<'gc>> {
self.font self.font
} }
@ -217,36 +223,48 @@ impl<'gc> LayoutBox<'gc> {
for (start, _end, text, span) in fs.iter_spans() { for (start, _end, text, span) in fs.iter_spans() {
if let Some(font) = layout_context.resolve_font(context, movie.clone(), &span) { if let Some(font) = layout_context.resolve_font(context, movie.clone(), &span) {
let font_size = Twips::from_pixels(span.size); let font_size = Twips::from_pixels(span.size);
let breakpoint_list =
font.split_wrapped_lines(&text, font_size, bounds, layout_context.cursor().x());
let end = text.len();
let mut last_breakpoint = 0; let mut last_breakpoint = 0;
for breakpoint in breakpoint_list { while let Some(breakpoint) = font.wrap_line(
if last_breakpoint != breakpoint { &text[last_breakpoint..],
Self::append_text_fragment( font_size,
context.gc_context, bounds,
&mut layout_context, layout_context.cursor().x(),
&text[last_breakpoint..breakpoint], ) {
start + last_breakpoint, if breakpoint == last_breakpoint {
start + breakpoint, last_breakpoint += 1;
span, continue;
);
} }
Self::append_text_fragment(
context.gc_context,
&mut layout_context,
&text[last_breakpoint..breakpoint],
start + last_breakpoint,
start + breakpoint,
span,
);
last_breakpoint = breakpoint; last_breakpoint = breakpoint;
if last_breakpoint >= text.len() {
break;
}
layout_context.newline(font_size);
} }
Self::append_text_fragment( let span_end = text.len();
context.gc_context,
&mut layout_context, if last_breakpoint < span_end {
&text[last_breakpoint..end], Self::append_text_fragment(
start + last_breakpoint, context.gc_context,
start + end, &mut layout_context,
span, &text[last_breakpoint..span_end],
); start + last_breakpoint,
start + span_end,
span,
);
}
} }
} }