Add an internal representation of text spans.
Despite having HTML and CSS rendering capabilities, the Flash text field actually does not use HTML as it's internal representation. Instead, the text-span format implied by `getTextFormat` and `setTextFormat` is used to drive layout. You can see this by watching what happens to `htmlText`, *especially* when you add and remove stylesheets. The `LayoutBox` machinery will be adapted to consume text spans in a future commit. This would make the entire rendering pipeline: HTML/CSS -> Text Spans -> Layout Boxes -> Render commands.
This commit is contained in:
parent
850831181c
commit
1671fc6eba
|
@ -264,3 +264,185 @@ impl TextFormat {
|
|||
Ok(object.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the application of a `TextFormat` to a particular text span.
|
||||
///
|
||||
/// The actual string data is not stored here; a `TextSpan` is meaningless
|
||||
/// without it's underlying string content. Furthermore, the start position
|
||||
/// within the string is implicit in the sum of all previous text span's
|
||||
/// lengths. See `TextSpans` for more information.
|
||||
///
|
||||
/// This struct also contains a resolved version of the `TextFormat` structure
|
||||
/// listed above.
|
||||
#[derive(Clone, Debug, Collect)]
|
||||
#[collect(require_static)]
|
||||
pub struct TextSpan {
|
||||
/// How many characters are subsumed by this text span.
|
||||
///
|
||||
/// This value must not cause the resulting set of text spans to exceed the
|
||||
/// length of the underlying source string.
|
||||
span_length: usize,
|
||||
|
||||
font: String,
|
||||
size: f64,
|
||||
color: swf::Color,
|
||||
align: swf::TextAlign,
|
||||
bold: bool,
|
||||
italic: bool,
|
||||
underline: bool,
|
||||
left_margin: f64,
|
||||
right_margin: f64,
|
||||
indent: f64,
|
||||
block_indent: f64,
|
||||
kerning: bool,
|
||||
leading: f64,
|
||||
letter_spacing: f64,
|
||||
tab_stops: Vec<f64>,
|
||||
bullet: bool,
|
||||
url: String,
|
||||
target: String,
|
||||
}
|
||||
|
||||
impl TextSpan {
|
||||
/// Split the text span in two at a particular point relative to the
|
||||
/// current text span's start.
|
||||
///
|
||||
/// The second span is returned and should be inserted into the list of
|
||||
/// text spans appropriately. The first text span is changed in-line.
|
||||
///
|
||||
/// If the split point exceeds the size of the current span, then no span
|
||||
/// will be returned and no change will be made to the existing span.
|
||||
fn split_at(&mut self, split_point: usize) -> Option<Self> {
|
||||
if self.span_length <= split_point || split_point == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut new_span = self.clone();
|
||||
new_span.span_length = self.span_length - split_point;
|
||||
self.span_length = split_point;
|
||||
|
||||
Some(new_span)
|
||||
}
|
||||
|
||||
/// Determine if this and another span have identical text formats.
|
||||
///
|
||||
/// It is assumed that the two text spans being considered are adjacent;
|
||||
/// and we have no way of checking, so this function doesn't check that.
|
||||
#[allow(clippy::float_cmp)]
|
||||
fn can_merge(&self, rhs: &Self) -> bool {
|
||||
self.font == rhs.font
|
||||
&& self.size == rhs.size
|
||||
&& self.color == rhs.color
|
||||
&& self.align == rhs.align
|
||||
&& self.bold == rhs.bold
|
||||
&& self.italic == rhs.italic
|
||||
&& self.underline == rhs.underline
|
||||
&& self.left_margin == rhs.left_margin
|
||||
&& self.right_margin == rhs.right_margin
|
||||
&& self.indent == rhs.indent
|
||||
&& self.block_indent == rhs.block_indent
|
||||
&& self.kerning == rhs.kerning
|
||||
&& self.leading == rhs.leading
|
||||
&& self.letter_spacing == rhs.letter_spacing
|
||||
&& self.tab_stops == rhs.tab_stops
|
||||
&& self.bullet == rhs.bullet
|
||||
&& self.url == rhs.url
|
||||
&& self.target == rhs.target
|
||||
}
|
||||
|
||||
/// Merge two spans together.
|
||||
///
|
||||
/// This function assumes the two spans are adjacent; if they are not, this
|
||||
/// will break invariants of the text span system.
|
||||
///
|
||||
/// If the spans do not have identical text formatting, this function will
|
||||
/// refuse to merge them (see `can_merge`) and return the original `rhs`
|
||||
/// span. If it consumes the span, and yields None, then the merge
|
||||
/// completed successfully.
|
||||
fn merge(&mut self, rhs: Self) -> Option<Self> {
|
||||
if !self.can_merge(&rhs) {
|
||||
return Some(rhs);
|
||||
}
|
||||
|
||||
self.span_length += rhs.span_length;
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Apply a text format to this text span.
|
||||
///
|
||||
/// Properties marked `None` on the `TextFormat` will remain unchanged.
|
||||
fn set_text_format(&mut self, tf: &TextFormat) {
|
||||
if let Some(font) = &tf.font {
|
||||
self.font = font.clone();
|
||||
}
|
||||
|
||||
if let Some(size) = &tf.size {
|
||||
self.size = *size;
|
||||
}
|
||||
|
||||
if let Some(color) = &tf.color {
|
||||
self.color = color.clone();
|
||||
}
|
||||
|
||||
if let Some(align) = &tf.align {
|
||||
self.align = *align;
|
||||
}
|
||||
|
||||
if let Some(bold) = &tf.bold {
|
||||
self.bold = *bold;
|
||||
}
|
||||
|
||||
if let Some(italic) = &tf.italic {
|
||||
self.italic = *italic;
|
||||
}
|
||||
|
||||
if let Some(underline) = &tf.underline {
|
||||
self.underline = *underline;
|
||||
}
|
||||
|
||||
if let Some(left_margin) = &tf.left_margin {
|
||||
self.left_margin = *left_margin;
|
||||
}
|
||||
|
||||
if let Some(right_margin) = &tf.right_margin {
|
||||
self.right_margin = *right_margin;
|
||||
}
|
||||
|
||||
if let Some(indent) = &tf.indent {
|
||||
self.indent = *indent;
|
||||
}
|
||||
|
||||
if let Some(block_indent) = &tf.block_indent {
|
||||
self.block_indent = *block_indent;
|
||||
}
|
||||
|
||||
if let Some(kerning) = &tf.kerning {
|
||||
self.kerning = *kerning;
|
||||
}
|
||||
|
||||
if let Some(leading) = &tf.leading {
|
||||
self.leading = *leading;
|
||||
}
|
||||
|
||||
if let Some(letter_spacing) = &tf.letter_spacing {
|
||||
self.letter_spacing = *letter_spacing;
|
||||
}
|
||||
|
||||
if let Some(tab_stops) = &tf.tab_stops {
|
||||
self.tab_stops = tab_stops.clone();
|
||||
}
|
||||
|
||||
if let Some(bullet) = &tf.bullet {
|
||||
self.bullet = *bullet;
|
||||
}
|
||||
|
||||
if let Some(url) = &tf.url {
|
||||
self.url = url.clone();
|
||||
}
|
||||
|
||||
if let Some(target) = &tf.target {
|
||||
self.target = target.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue