core: Add methods for introspecting text metrics on an `EditText`.

This commit is contained in:
David Wendt 2022-10-15 14:44:06 -04:00 committed by kmeisthax
parent c0b6496b96
commit 1efa29baa6
5 changed files with 96 additions and 4 deletions

View File

@ -112,6 +112,7 @@ pub struct SystemClasses<'gc> {
pub ioerror: ClassObject<'gc>, pub ioerror: ClassObject<'gc>,
pub eoferror: ClassObject<'gc>, pub eoferror: ClassObject<'gc>,
pub uncaughterrorevents: ClassObject<'gc>, pub uncaughterrorevents: ClassObject<'gc>,
pub textlinemetrics: ClassObject<'gc>,
} }
impl<'gc> SystemClasses<'gc> { impl<'gc> SystemClasses<'gc> {
@ -191,6 +192,7 @@ impl<'gc> SystemClasses<'gc> {
ioerror: object, ioerror: object,
eoferror: object, eoferror: object,
uncaughterrorevents: object, uncaughterrorevents: object,
textlinemetrics: object,
} }
} }
} }
@ -730,6 +732,7 @@ fn load_playerglobal<'gc>(
("flash.geom", "Transform", transform), ("flash.geom", "Transform", transform),
("flash.geom", "ColorTransform", colortransform), ("flash.geom", "ColorTransform", colortransform),
("flash.utils", "ByteArray", bytearray), ("flash.utils", "ByteArray", bytearray),
("flash.text", "TextLineMetrics", textlinemetrics),
] ]
); );

View File

@ -19,7 +19,7 @@ use crate::display_object::{DisplayObjectBase, DisplayObjectPtr, TDisplayObject}
use crate::drawing::Drawing; use crate::drawing::Drawing;
use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode}; use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode};
use crate::font::{round_down_to_pixel, Glyph, TextRenderSettings}; use crate::font::{round_down_to_pixel, Glyph, TextRenderSettings};
use crate::html::{BoxBounds, FormatSpans, LayoutBox, LayoutContent, TextFormat}; use crate::html::{BoxBounds, FormatSpans, LayoutBox, LayoutContent, LayoutMetrics, TextFormat};
use crate::prelude::*; use crate::prelude::*;
use crate::string::{utils as string_utils, AvmString, WStr, WString}; use crate::string::{utils as string_utils, AvmString, WStr, WString};
use crate::tag_utils::SwfMovie; use crate::tag_utils::SwfMovie;
@ -1383,6 +1383,78 @@ impl<'gc> EditText<'gc> {
), ),
} }
} }
/// Count the number of lines in the text box's layout.
pub fn layout_lines(self) -> usize {
self.0.read().line_data.len()
}
/// Calculate the layout metrics for a given line.
///
/// Returns None if the line does not exist or there is not enough data
/// about the line to calculate metrics with.
pub fn layout_metrics(self, line: usize) -> Option<LayoutMetrics> {
let line = self.0.read().line_data.get(line).copied()?;
let mut union_bounds = None;
let mut font = None;
let mut text_format = None;
let read = self.0.read();
for layout_box in read.layout.iter() {
if layout_box.bounds().offset_y() < line.offset
|| layout_box.bounds().extent_y() > line.extent
{
continue;
}
log::error!("{:?}", layout_box);
if let Some(bounds) = &mut union_bounds {
*bounds += layout_box.bounds();
} else {
union_bounds = Some(layout_box.bounds());
}
if font.is_none() {
match layout_box.content() {
LayoutContent::Text {
font: box_font,
text_format: box_text_format,
..
} => {
font = Some(box_font);
text_format = Some(box_text_format);
}
LayoutContent::Bullet {
font: box_font,
text_format: box_text_format,
..
} => {
font = Some(box_font);
text_format = Some(box_text_format);
}
LayoutContent::Drawing { .. } => {}
}
}
}
let union_bounds = union_bounds?;
let font = font?;
let size = Twips::from_pixels(text_format?.size?);
let ascent = font.get_baseline_for_height(size);
let descent = font.get_descent_for_height(size);
let leading = font.get_leading_for_height(size);
Some(LayoutMetrics {
ascent,
descent,
leading,
width: union_bounds.width(),
height: ascent + descent + leading,
x: union_bounds.offset_x() + Twips::from_pixels(EditText::INTERNAL_PADDING),
})
}
} }
impl<'gc> TDisplayObject<'gc> for EditText<'gc> { impl<'gc> TDisplayObject<'gc> for EditText<'gc> {

View File

@ -88,7 +88,6 @@ struct FontData {
/// The distance from the baseline of the font to the bottom of each glyph, /// The distance from the baseline of the font to the bottom of each glyph,
/// in EM-square coordinates. /// in EM-square coordinates.
#[allow(dead_code)]
descent: u16, descent: u16,
/// The distance between the bottom of any one glyph and the top of /// The distance between the bottom of any one glyph and the top of
@ -227,6 +226,13 @@ impl<'gc> Font<'gc> {
Twips::new((self.0.ascent as f32 * scale) as i32) Twips::new((self.0.ascent as f32 * scale) as i32)
} }
/// Get the descent from the baseline to the bottom of the glyph at a given height.
pub fn get_descent_for_height(&self, height: Twips) -> Twips {
let scale = height.get() as f32 / self.scale();
Twips::new((self.0.descent as f32 * scale) as i32)
}
/// Returns whether this font contains kerning information. /// Returns whether this font contains kerning information.
pub fn has_kerning_info(&self) -> bool { pub fn has_kerning_info(&self) -> bool {
!self.0.kerning_pairs.is_empty() !self.0.kerning_pairs.is_empty()

View File

@ -8,7 +8,7 @@ mod text_format;
pub use dimensions::BoxBounds; pub use dimensions::BoxBounds;
pub use dimensions::Position; pub use dimensions::Position;
pub use dimensions::Size; pub use dimensions::Size;
pub use layout::{LayoutBox, LayoutContent}; pub use layout::{LayoutBox, LayoutContent, LayoutMetrics};
pub use text_format::{FormatSpans, TextFormat, TextSpan}; pub use text_format::{FormatSpans, TextFormat, TextSpan};
#[cfg(test)] #[cfg(test)]

View File

@ -555,7 +555,7 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> {
#[derive(Clone, Debug, Collect)] #[derive(Clone, Debug, Collect)]
#[collect(no_drop)] #[collect(no_drop)]
pub struct LayoutBox<'gc> { pub struct LayoutBox<'gc> {
/// The rectangle corresponding to the outer boundaries of the /// The rectangle corresponding to the outer boundaries of the content box.
bounds: BoxBounds<Twips>, bounds: BoxBounds<Twips>,
/// What content is contained by the content box. /// What content is contained by the content box.
@ -841,3 +841,14 @@ impl<'gc> LayoutBox<'gc> {
matches!(&self.content, LayoutContent::Bullet { .. }) matches!(&self.content, LayoutContent::Bullet { .. })
} }
} }
pub struct LayoutMetrics {
pub ascent: Twips,
pub descent: Twips,
pub leading: Twips,
pub width: Twips,
pub height: Twips,
pub x: Twips,
}