Add support for explicit tabs and newlines.

This commit is contained in:
David Wendt 2020-06-06 17:55:15 -04:00
parent 153ab675e9
commit 2caaa6875d
1 changed files with 100 additions and 48 deletions

View File

@ -194,6 +194,14 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> {
}
}
/// Adjust the text layout cursor down to the next line in response to an
/// explicit newline.
fn explicit_newline(&mut self, mc: MutationContext<'gc, '_>) {
self.newline(mc);
self.is_first_line = true;
}
/// Adjust the text layout cursor down to the next line.
///
/// This function will also adjust any layout boxes on the current line to
@ -212,6 +220,30 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> {
self.has_line_break = true;
}
/// Adjust the text layout cursor in response to a tab.
///
/// Tabs can do two separate things in Flash, depending on whether or not
/// tab stops have been manually determined. If they have been, then the
/// text cursor goes to the next closest tab stop that has not yet been
/// passed, or if no such stop exists, tabs do nothing. If no tab stops
/// exist, then the cursor is advanced to some position modulo the natural
/// tab index.
fn tab(&mut self) {
if self.current_line_span.tab_stops.is_empty() {
let modulo_factor = Twips::from_pixels(self.current_line_span.size * 2.75);
let stop_modulo_tab =
((self.cursor.x().get() / modulo_factor.get()) + 1) * modulo_factor.get();
self.cursor.set_x(Twips::new(stop_modulo_tab));
} else {
for stop in self.current_line_span.tab_stops.iter() {
let twips_stop = Twips::from_pixels(*stop);
if twips_stop > self.cursor.x() {
self.cursor.set_x(twips_stop);
}
}
}
}
/// Enter a new span.
fn newspan(&mut self, first_span: &TextSpan) {
if self.current_line.is_none() {
@ -435,12 +467,31 @@ impl<'gc> LayoutBox<'gc> {
) -> (Option<GcCell<'gc, LayoutBox<'gc>>>, BoxBounds<Twips>) {
let mut layout_context = LayoutContext::new(bounds, fs.text());
for (start, _end, text, span) in fs.iter_spans() {
for (span_start, _end, span_text, span) in fs.iter_spans() {
if let Some(font) = layout_context.resolve_font(context, movie.clone(), &span) {
layout_context.newspan(span);
let font_size = Twips::from_pixels(span.size);
let letter_spacing = Twips::from_pixels(span.letter_spacing);
for text in span_text.split(&['\n', '\t'][..]) {
let slice_start = text.as_ptr() as usize - span_text.as_ptr() as usize;
let delimiter = if slice_start > 0 {
span_text
.get(slice_start - 1..)
.and_then(|s| s.chars().next())
} else {
None
};
match delimiter {
Some('\n') => layout_context.explicit_newline(context.gc_context),
Some('\t') => layout_context.tab(),
_ => {}
}
let start = span_start + slice_start;
let mut last_breakpoint = 0;
if is_word_wrap {
@ -508,6 +559,7 @@ impl<'gc> LayoutBox<'gc> {
}
}
}
}
layout_context.end_layout(context.gc_context)
}