Add a bunch of necessary fixes to default text formatting and HTML format extraction.
This also replaces the `edittext_html_defaults` test with a more robust test that checks the default format and global format of SWF-based, text, and HTML test vectors.
This commit is contained in:
parent
4f3d4c82fb
commit
8628261dc8
|
@ -174,7 +174,7 @@ impl<'gc> EditText<'gc> {
|
||||||
},
|
},
|
||||||
font_id: None,
|
font_id: None,
|
||||||
font_class_name: None,
|
font_class_name: None,
|
||||||
height: Some(Twips::from_pixels(height)),
|
height: Some(Twips::from_pixels(12.0)),
|
||||||
color: Some(swf::Color {
|
color: Some(swf::Color {
|
||||||
r: 0,
|
r: 0,
|
||||||
g: 0,
|
g: 0,
|
||||||
|
|
|
@ -142,26 +142,30 @@ impl TextFormat {
|
||||||
let font_class = et
|
let font_class = et
|
||||||
.font_class_name
|
.font_class_name
|
||||||
.clone()
|
.clone()
|
||||||
.or_else(|| font.map(|font| font.descriptor().class().to_string()));
|
.or_else(|| font.map(|font| font.descriptor().class().to_string()))
|
||||||
|
.unwrap_or_else(|| "Times New Roman".to_string());
|
||||||
let align = et.layout.clone().map(|l| l.align);
|
let align = et.layout.clone().map(|l| l.align);
|
||||||
let left_margin = et.layout.clone().map(|l| l.left_margin.to_pixels());
|
let left_margin = et.layout.clone().map(|l| l.left_margin.to_pixels());
|
||||||
let right_margin = et.layout.clone().map(|l| l.right_margin.to_pixels());
|
let right_margin = et.layout.clone().map(|l| l.right_margin.to_pixels());
|
||||||
let indent = et.layout.clone().map(|l| l.indent.to_pixels());
|
let indent = et.layout.clone().map(|l| l.indent.to_pixels());
|
||||||
let leading = et.layout.map(|l| l.leading.to_pixels());
|
let leading = et.layout.map(|l| l.leading.to_pixels());
|
||||||
|
|
||||||
|
// TODO: Text fields that don't specify a font are assumed to be 12px
|
||||||
|
// Times New Roman non-bold, non-italic. This will need to be revised
|
||||||
|
// when we start supporting device fonts.
|
||||||
Self {
|
Self {
|
||||||
font: font_class,
|
font: Some(font_class),
|
||||||
size: et.height.map(|h| h.to_pixels()),
|
size: et.height.map(|h| h.to_pixels()),
|
||||||
color: et.color,
|
color: et.color,
|
||||||
align,
|
align,
|
||||||
bold: font.map(|font| font.descriptor().bold()),
|
bold: Some(font.map(|font| font.descriptor().bold()).unwrap_or(false)),
|
||||||
italic: font.map(|font| font.descriptor().italic()),
|
italic: Some(font.map(|font| font.descriptor().italic()).unwrap_or(false)),
|
||||||
underline: None, // TODO: What is this by default? False?
|
underline: Some(false),
|
||||||
left_margin,
|
left_margin,
|
||||||
right_margin,
|
right_margin,
|
||||||
indent,
|
indent,
|
||||||
block_indent: Some(0.0), // TODO: This isn't specified by the tag itself
|
block_indent: Some(0.0), // TODO: This isn't specified by the tag itself
|
||||||
kerning: Some(true), // TODO: this isn't specified by the tag itself
|
kerning: Some(false),
|
||||||
leading,
|
leading,
|
||||||
letter_spacing: Some(0.0), // TODO: This isn't specified by the tag itself
|
letter_spacing: Some(0.0), // TODO: This isn't specified by the tag itself
|
||||||
tab_stops: Some(vec![]), // TODO: Are there default tab stops?
|
tab_stops: Some(vec![]), // TODO: Are there default tab stops?
|
||||||
|
@ -259,6 +263,21 @@ impl TextFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(letter_spacing) =
|
||||||
|
node.attribute_value(&XMLName::from_str("letterSpacing"))
|
||||||
|
{
|
||||||
|
tf.letter_spacing = letter_spacing.parse().ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
tf.kerning = match node
|
||||||
|
.attribute_value(&XMLName::from_str("kerning"))
|
||||||
|
.as_deref()
|
||||||
|
{
|
||||||
|
Some("1") => Some(true),
|
||||||
|
Some("0") => Some(false),
|
||||||
|
_ => tf.kerning,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(name) if name == XMLName::from_str("b") => {
|
Some(name) if name == XMLName::from_str("b") => {
|
||||||
tf.bold = Some(true);
|
tf.bold = Some(true);
|
||||||
|
@ -1143,6 +1162,7 @@ impl FormatSpans {
|
||||||
/// presentational markup and CSS stylesheets.
|
/// presentational markup and CSS stylesheets.
|
||||||
pub fn lower_from_html<'gc>(&mut self, tree: XMLDocument<'gc>) {
|
pub fn lower_from_html<'gc>(&mut self, tree: XMLDocument<'gc>) {
|
||||||
let mut format_stack = vec![self.default_format.clone()];
|
let mut format_stack = vec![self.default_format.clone()];
|
||||||
|
let mut last_successful_format = None;
|
||||||
|
|
||||||
self.text = "".to_string();
|
self.text = "".to_string();
|
||||||
self.spans = vec![];
|
self.spans = vec![];
|
||||||
|
@ -1167,9 +1187,15 @@ impl FormatSpans {
|
||||||
&node.node_value().unwrap(),
|
&node.node_value().unwrap(),
|
||||||
format_stack.last(),
|
format_stack.last(),
|
||||||
);
|
);
|
||||||
|
last_successful_format = format_stack.last().cloned();
|
||||||
}
|
}
|
||||||
Step::Out(node) if node.tag_name().unwrap().node_name().as_str() == "p" => {
|
Step::Out(node) if node.tag_name().unwrap().node_name().as_str() == "p" => {
|
||||||
self.replace_text(self.text.len(), self.text.len(), "\n", format_stack.last());
|
self.replace_text(
|
||||||
|
self.text.len(),
|
||||||
|
self.text.len(),
|
||||||
|
"\n",
|
||||||
|
last_successful_format.as_ref(),
|
||||||
|
);
|
||||||
format_stack.pop();
|
format_stack.pop();
|
||||||
}
|
}
|
||||||
Step::Out(_) => {
|
Step::Out(_) => {
|
||||||
|
|
|
@ -198,7 +198,7 @@ swf_tests! {
|
||||||
(as1_constructor_v7, "avm1/as1_constructor_v7", 1),
|
(as1_constructor_v7, "avm1/as1_constructor_v7", 1),
|
||||||
(issue_710, "avm1/issue_710", 1),
|
(issue_710, "avm1/issue_710", 1),
|
||||||
(edittext_font_size, "avm1/edittext_font_size", 1),
|
(edittext_font_size, "avm1/edittext_font_size", 1),
|
||||||
(edittext_html_defaults, "avm1/edittext_html_defaults", 1),
|
(edittext_default_format, "avm1/edittext_default_format", 1),
|
||||||
(edittext_leading, "avm1/edittext_leading", 1),
|
(edittext_leading, "avm1/edittext_leading", 1),
|
||||||
#[ignore] (edittext_newlines, "avm1/edittext_newlines", 1),
|
#[ignore] (edittext_newlines, "avm1/edittext_newlines", 1),
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,222 @@
|
||||||
|
//Global text format parameters of a SWF-derived text field
|
||||||
|
//tf.align
|
||||||
|
left
|
||||||
|
//tf.blockIndent
|
||||||
|
0
|
||||||
|
//tf.bold
|
||||||
|
false
|
||||||
|
//tf.bullet
|
||||||
|
false
|
||||||
|
//tf.color
|
||||||
|
0
|
||||||
|
//tf.font
|
||||||
|
Noto Sans
|
||||||
|
//tf.indent
|
||||||
|
0
|
||||||
|
//tf.italic
|
||||||
|
false
|
||||||
|
//tf.kerning
|
||||||
|
true
|
||||||
|
//tf.leading
|
||||||
|
2
|
||||||
|
//tf.leftMargin
|
||||||
|
0
|
||||||
|
//tf.letterSpacing
|
||||||
|
0
|
||||||
|
//tf.rightMargin
|
||||||
|
0
|
||||||
|
//tf.size
|
||||||
|
12
|
||||||
|
//tf.tabStops.join(',')
|
||||||
|
|
||||||
|
//tf.target
|
||||||
|
|
||||||
|
//tf.underline
|
||||||
|
false
|
||||||
|
//tf.url
|
||||||
|
|
||||||
|
//Default text format parameters of a SWF-derived text field
|
||||||
|
//tf.align
|
||||||
|
left
|
||||||
|
//tf.blockIndent
|
||||||
|
0
|
||||||
|
//tf.bold
|
||||||
|
false
|
||||||
|
//tf.bullet
|
||||||
|
false
|
||||||
|
//tf.color
|
||||||
|
0
|
||||||
|
//tf.font
|
||||||
|
Noto Sans
|
||||||
|
//tf.indent
|
||||||
|
0
|
||||||
|
//tf.italic
|
||||||
|
false
|
||||||
|
//tf.kerning
|
||||||
|
false
|
||||||
|
//tf.leading
|
||||||
|
2
|
||||||
|
//tf.leftMargin
|
||||||
|
0
|
||||||
|
//tf.letterSpacing
|
||||||
|
0
|
||||||
|
//tf.rightMargin
|
||||||
|
0
|
||||||
|
//tf.size
|
||||||
|
12
|
||||||
|
//tf.tabStops.join(',')
|
||||||
|
|
||||||
|
//tf.target
|
||||||
|
|
||||||
|
//tf.underline
|
||||||
|
false
|
||||||
|
//tf.url
|
||||||
|
|
||||||
|
//Global text format parameters of a dynamic text field
|
||||||
|
//tf.align
|
||||||
|
left
|
||||||
|
//tf.blockIndent
|
||||||
|
0
|
||||||
|
//tf.bold
|
||||||
|
false
|
||||||
|
//tf.bullet
|
||||||
|
false
|
||||||
|
//tf.color
|
||||||
|
0
|
||||||
|
//tf.font
|
||||||
|
Times New Roman
|
||||||
|
//tf.indent
|
||||||
|
0
|
||||||
|
//tf.italic
|
||||||
|
false
|
||||||
|
//tf.kerning
|
||||||
|
false
|
||||||
|
//tf.leading
|
||||||
|
0
|
||||||
|
//tf.leftMargin
|
||||||
|
0
|
||||||
|
//tf.letterSpacing
|
||||||
|
0
|
||||||
|
//tf.rightMargin
|
||||||
|
0
|
||||||
|
//tf.size
|
||||||
|
12
|
||||||
|
//tf.tabStops.join(',')
|
||||||
|
|
||||||
|
//tf.target
|
||||||
|
|
||||||
|
//tf.underline
|
||||||
|
false
|
||||||
|
//tf.url
|
||||||
|
|
||||||
|
//Default text format parameters of a dynamic text field
|
||||||
|
//tf.align
|
||||||
|
left
|
||||||
|
//tf.blockIndent
|
||||||
|
0
|
||||||
|
//tf.bold
|
||||||
|
false
|
||||||
|
//tf.bullet
|
||||||
|
false
|
||||||
|
//tf.color
|
||||||
|
0
|
||||||
|
//tf.font
|
||||||
|
Times New Roman
|
||||||
|
//tf.indent
|
||||||
|
0
|
||||||
|
//tf.italic
|
||||||
|
false
|
||||||
|
//tf.kerning
|
||||||
|
false
|
||||||
|
//tf.leading
|
||||||
|
0
|
||||||
|
//tf.leftMargin
|
||||||
|
0
|
||||||
|
//tf.letterSpacing
|
||||||
|
0
|
||||||
|
//tf.rightMargin
|
||||||
|
0
|
||||||
|
//tf.size
|
||||||
|
12
|
||||||
|
//tf.tabStops.join(',')
|
||||||
|
|
||||||
|
//tf.target
|
||||||
|
|
||||||
|
//tf.underline
|
||||||
|
false
|
||||||
|
//tf.url
|
||||||
|
|
||||||
|
//Global text format parameters of a dynamic HTML field
|
||||||
|
//tf.align
|
||||||
|
left
|
||||||
|
//tf.blockIndent
|
||||||
|
0
|
||||||
|
//tf.bold
|
||||||
|
false
|
||||||
|
//tf.bullet
|
||||||
|
false
|
||||||
|
//tf.color
|
||||||
|
0
|
||||||
|
//tf.font
|
||||||
|
Times New Roman
|
||||||
|
//tf.indent
|
||||||
|
0
|
||||||
|
//tf.italic
|
||||||
|
false
|
||||||
|
//tf.kerning
|
||||||
|
false
|
||||||
|
//tf.leading
|
||||||
|
0
|
||||||
|
//tf.leftMargin
|
||||||
|
0
|
||||||
|
//tf.letterSpacing
|
||||||
|
0
|
||||||
|
//tf.rightMargin
|
||||||
|
0
|
||||||
|
//tf.size
|
||||||
|
12
|
||||||
|
//tf.tabStops.join(',')
|
||||||
|
|
||||||
|
//tf.target
|
||||||
|
|
||||||
|
//tf.underline
|
||||||
|
false
|
||||||
|
//tf.url
|
||||||
|
|
||||||
|
//Default text format parameters of a dynamic HTML field
|
||||||
|
//tf.align
|
||||||
|
left
|
||||||
|
//tf.blockIndent
|
||||||
|
0
|
||||||
|
//tf.bold
|
||||||
|
false
|
||||||
|
//tf.bullet
|
||||||
|
false
|
||||||
|
//tf.color
|
||||||
|
0
|
||||||
|
//tf.font
|
||||||
|
Times New Roman
|
||||||
|
//tf.indent
|
||||||
|
0
|
||||||
|
//tf.italic
|
||||||
|
false
|
||||||
|
//tf.kerning
|
||||||
|
false
|
||||||
|
//tf.leading
|
||||||
|
0
|
||||||
|
//tf.leftMargin
|
||||||
|
0
|
||||||
|
//tf.letterSpacing
|
||||||
|
0
|
||||||
|
//tf.rightMargin
|
||||||
|
0
|
||||||
|
//tf.size
|
||||||
|
12
|
||||||
|
//tf.tabStops.join(',')
|
||||||
|
|
||||||
|
//tf.target
|
||||||
|
|
||||||
|
//tf.underline
|
||||||
|
false
|
||||||
|
//tf.url
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,37 +0,0 @@
|
||||||
//Text format parameters of Noto Sans text field with HTML:
|
|
||||||
//tf.align
|
|
||||||
left
|
|
||||||
//tf.blockIndent
|
|
||||||
0
|
|
||||||
//tf.bold
|
|
||||||
false
|
|
||||||
//tf.bullet
|
|
||||||
false
|
|
||||||
//tf.color
|
|
||||||
0
|
|
||||||
//tf.font
|
|
||||||
Noto Sans
|
|
||||||
//tf.indent
|
|
||||||
0
|
|
||||||
//tf.italic
|
|
||||||
false
|
|
||||||
//tf.kerning
|
|
||||||
true
|
|
||||||
//tf.leading
|
|
||||||
2
|
|
||||||
//tf.leftMargin
|
|
||||||
0
|
|
||||||
//tf.letterSpacing
|
|
||||||
0
|
|
||||||
//tf.rightMargin
|
|
||||||
0
|
|
||||||
//tf.size
|
|
||||||
12
|
|
||||||
//tf.tabStops.join(',')
|
|
||||||
|
|
||||||
//tf.target
|
|
||||||
|
|
||||||
//tf.underline
|
|
||||||
false
|
|
||||||
//tf.url
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue