diff --git a/core/src/html/layout.rs b/core/src/html/layout.rs
index 84c9db654..79bac3b64 100644
--- a/core/src/html/layout.rs
+++ b/core/src/html/layout.rs
@@ -13,7 +13,7 @@ use ruffle_render::shape_utils::DrawCommand;
use std::cmp::{max, min};
use std::fmt::{Debug, Formatter};
use std::mem;
-use std::ops::Deref;
+use std::ops::{Deref, Range};
use std::slice::Iter;
use std::sync::Arc;
use swf::{Point, Twips};
@@ -345,7 +345,7 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> {
line_bounds += Position::from((left_adjustment + align_adjustment, Twips::ZERO));
line_bounds += Size::from((Twips::ZERO, font_leading_adjustment));
- self.flush_line();
+ self.flush_line(end);
if let Some(eb) = &mut self.exterior_bounds {
*eb += line_bounds;
@@ -354,24 +354,39 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> {
}
}
- fn flush_line(&mut self) {
- if !self.boxes.is_empty() {
- let boxes = mem::take(&mut self.boxes);
- let bounds = boxes
- .iter()
- .fold(boxes[0].bounds, |bounds, b| bounds + b.bounds);
- self.lines.push(LayoutLine {
- index: self.current_line_index,
- bounds,
- boxes,
- });
- self.current_line_index += 1;
+ fn flush_line(&mut self, end: usize) {
+ if self.boxes.is_empty() {
+ return;
+ }
- if let Some(lb) = &mut self.bounds {
- *lb += bounds;
- } else {
- self.bounds = Some(bounds);
- }
+ let boxes = mem::take(&mut self.boxes);
+ let first_box = boxes.first().unwrap();
+ let start = first_box.start();
+ let bounds = boxes
+ .iter()
+ .fold(first_box.bounds, |bounds, b| bounds + b.bounds);
+
+ // Update last line's end position to take into account the delimiter.
+ // It's easier to do it here, but maybe after some refactors this update
+ // will not be needed, and the end position will be calculated correctly.
+ if let Some(last_line) = self.lines.last_mut() {
+ last_line.end = start;
+ }
+
+ self.lines.push(LayoutLine {
+ index: self.current_line_index,
+ bounds,
+ start,
+ end,
+ boxes,
+ });
+ self.current_line_index += 1;
+
+ // Update layout bounds
+ if let Some(lb) = &mut self.bounds {
+ *lb += bounds;
+ } else {
+ self.bounds = Some(bounds);
}
}
@@ -775,6 +790,13 @@ pub struct LayoutLine<'gc> {
#[collect(require_static)]
bounds: BoxBounds,
+ /// The start position of the line (inclusive).
+ start: usize,
+
+ /// The end position of the line (exclusive).
+ /// This position includes the line delimiter.
+ end: usize,
+
/// Layout boxes contained within this line.
boxes: Vec>,
}
@@ -788,6 +810,22 @@ impl<'gc> LayoutLine<'gc> {
self.bounds
}
+ pub fn start(&self) -> usize {
+ self.start
+ }
+
+ pub fn end(&self) -> usize {
+ self.end
+ }
+
+ pub fn len(&self) -> usize {
+ self.end() - self.start()
+ }
+
+ pub fn text_range(&self) -> Range {
+ self.start..self.end
+ }
+
pub fn offset_y(&self) -> Twips {
self.bounds().offset_y()
}