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
}
/// Given a line of text, split it into the shortest number of lines that
/// are shorter than `width`.
/// Given a line of text, find the first breakpoint within the text.
///
/// 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
/// be internationalized to implement AS3 `flash.text.engine`.
pub fn split_wrapped_lines(
pub fn wrap_line(
self,
text: &str,
font_size: Twips,
width: Twips,
offset: Twips,
) -> Vec<usize> {
let mut result = vec![];
) -> Option<usize> {
let mut current_width = width
.checked_sub(offset)
.unwrap_or_else(|| Twips::from_pixels(0.0));
@ -200,29 +202,19 @@ impl<'gc> Font<'gc> {
for word in text.split(' ') {
let measure = self.measure(word, font_size);
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() {
line_start + current_word.len() + 1
} else {
line_start + current_word.len()
};
let line_end = line_start + current_word.len();
let word_start = word.as_ptr() as usize - text.as_ptr() as usize;
let word_end = if (word_start + word.len() + 1) < text.len() {
word_start + word.len() + 1
} else {
word_start + word.len()
};
let word_end = word_start + word.len();
if measure.0 > current_width && measure.0 > width {
//Failsafe for if we get a word wider than the field.
if !current_word.is_empty() {
result.push(line_end);
return Some(line_end);
}
result.push(word_end);
current_word = &text[word_end..word_end];
current_width = width;
return Some(word_end);
} else if measure.0 > current_width {
if !current_word.is_empty() {
result.push(line_end);
return Some(line_end);
}
current_word = &text[word_start..word_end];
@ -233,7 +225,7 @@ impl<'gc> Font<'gc> {
}
}
result
None
}
pub fn descriptor(self) -> FontDescriptor {

View File

@ -44,6 +44,12 @@ impl<'gc> LayoutContext<'gc> {
&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>> {
self.font
}
@ -217,36 +223,48 @@ impl<'gc> LayoutBox<'gc> {
for (start, _end, text, span) in fs.iter_spans() {
if let Some(font) = layout_context.resolve_font(context, movie.clone(), &span) {
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;
for breakpoint in breakpoint_list {
if last_breakpoint != breakpoint {
Self::append_text_fragment(
context.gc_context,
&mut layout_context,
&text[last_breakpoint..breakpoint],
start + last_breakpoint,
start + breakpoint,
span,
);
while let Some(breakpoint) = font.wrap_line(
&text[last_breakpoint..],
font_size,
bounds,
layout_context.cursor().x(),
) {
if breakpoint == last_breakpoint {
last_breakpoint += 1;
continue;
}
Self::append_text_fragment(
context.gc_context,
&mut layout_context,
&text[last_breakpoint..breakpoint],
start + last_breakpoint,
start + breakpoint,
span,
);
last_breakpoint = breakpoint;
if last_breakpoint >= text.len() {
break;
}
layout_context.newline(font_size);
}
Self::append_text_fragment(
context.gc_context,
&mut layout_context,
&text[last_breakpoint..end],
start + last_breakpoint,
start + end,
span,
);
let span_end = text.len();
if last_breakpoint < span_end {
Self::append_text_fragment(
context.gc_context,
&mut layout_context,
&text[last_breakpoint..span_end],
start + last_breakpoint,
start + span_end,
span,
);
}
}
}