diff --git a/core/src/avm2/globals/flash/text/StyleSheet.as b/core/src/avm2/globals/flash/text/StyleSheet.as index 1b4b64e2d..0808eca02 100644 --- a/core/src/avm2/globals/flash/text/StyleSheet.as +++ b/core/src/avm2/globals/flash/text/StyleSheet.as @@ -1,6 +1,4 @@ package flash.text { - import __ruffle__.stub_method; - public dynamic class StyleSheet { // Shallow copies of the original style objects. Not used by Ruffle itself, just for getStyle() private var _styles: Object = {}; @@ -40,8 +38,82 @@ package flash.text { } public function transform(formatObject:Object):TextFormat { - stub_method("flash.text.StyleSheet", "transform"); - return null; + if (!formatObject) { + return null; + } + var result = new TextFormat(); + + if (formatObject.color) { + result.color = innerParseColor(formatObject.color); + } + + if (formatObject.display) { + result.display = formatObject.display; + } + + if (formatObject.fontFamily) { + result.font = innerParseFontFamily(formatObject.fontFamily); + } + + if (formatObject.fontSize) { + var size = parseInt(formatObject.fontSize); + if (size > 0) { + result.size = size; + } + } + + if (formatObject.fontStyle == "italic") { + result.italic = true; + } else if (formatObject.fontStyle == "normal") { + result.italic = false; + } + + if (formatObject.fontWeight == "bold") { + result.bold = true; + } else if (formatObject.fontWeight == "normal") { + result.bold = false; + } + + if (formatObject.kerning == "true") { + result.kerning = true; + } else if (formatObject.kerning == "false") { + result.kerning = false; + } else { + // Seems to always set, not just if defined + result.kerning = parseInt(formatObject.kerning); + } + + if (formatObject.leading) { + result.leading = parseInt(formatObject.leading); + } + + if (formatObject.letterSpacing) { + result.letterSpacing = parseFloat(formatObject.letterSpacing); + } + + if (formatObject.marginLeft) { + result.leftMargin = parseFloat(formatObject.marginLeft); + } + + if (formatObject.marginRight) { + result.rightMargin = parseFloat(formatObject.marginRight); + } + + if (formatObject.textAlign) { + result.align = formatObject.textAlign; + } + + if (formatObject.textDecoration == "underline") { + result.underline = true; + } else if (formatObject.textDecoration == "none") { + result.underline = false; + } + + if (formatObject.textIndent) { + result.indent = parseInt(formatObject.textIndent); + } + + return result; } private function _createShallowCopy(original: *): Object { @@ -54,5 +126,7 @@ package flash.text { // Avoid doing potentially expensive string parsing in AS :D private native function innerParseCss(css: String): Object; + private native function innerParseColor(color: String): Number; + private native function innerParseFontFamily(fontFamily: String): String; } } diff --git a/core/src/avm2/globals/flash/text/style_sheet.rs b/core/src/avm2/globals/flash/text/style_sheet.rs index 71c7e9723..28c5c4f3d 100644 --- a/core/src/avm2/globals/flash/text/style_sheet.rs +++ b/core/src/avm2/globals/flash/text/style_sheet.rs @@ -2,6 +2,7 @@ use crate::avm2::parameters::ParametersExt; use crate::avm2::{Activation, Error, Object, TObject, Value}; use crate::html::CssStream; use crate::string::AvmString; +use ruffle_wstr::{WStr, WString}; pub fn inner_parse_css<'gc>( activation: &mut Activation<'_, 'gc>, @@ -39,3 +40,69 @@ pub fn inner_parse_css<'gc>( Ok(Value::Object(result)) } + +pub fn inner_parse_color<'gc>( + activation: &mut Activation<'_, 'gc>, + _this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let input = args.get_string(activation, 0)?; + + if let Some(stripped) = input.strip_prefix(WStr::from_units(b"#")) { + if stripped.len() <= 6 { + if let Ok(number) = u32::from_str_radix(&stripped.to_string(), 16) { + return Ok(number.into()); + } + } + } + + Ok(0.into()) +} + +pub fn inner_parse_font_family<'gc>( + activation: &mut Activation<'_, 'gc>, + _this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let input = args.get_string(activation, 0)?; + let mut result = WString::new(); + + let mut pos = 0; + while pos < input.len() { + // Skip whitespace + while input.get(pos) == Some(' ' as u16) { + pos += 1; + } + + // Find the whole value + let start = pos; + while input.get(pos) != Some(',' as u16) && pos < input.len() { + pos += 1; + } + + let mut value = &input[start..pos]; + + if pos < input.len() { + pos += 1; // move past the comma + } + + // Transform some names + if value == WStr::from_units(b"mono") { + value = WStr::from_units(b"_typewriter"); + } else if value == WStr::from_units(b"sans-serif") { + value = WStr::from_units(b"_sans"); + } else if value == WStr::from_units(b"serif") { + value = WStr::from_units(b"_serif"); + } + + // Add it to the result (without any extra space) + if !value.is_empty() { + if !result.is_empty() { + result.push_char(','); + } + result.push_str(value); + } + } + + Ok(Value::String(AvmString::new(activation.gc(), result))) +} diff --git a/core/src/avm2/globals/flash/text/text_format.rs b/core/src/avm2/globals/flash/text/text_format.rs index 7d40446fc..6b6a0e571 100644 --- a/core/src/avm2/globals/flash/text/text_format.rs +++ b/core/src/avm2/globals/flash/text/text_format.rs @@ -4,8 +4,8 @@ use crate::avm2::object::{ArrayObject, Object, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; use crate::ecma_conversions::round_to_even; +use crate::html::TextDisplay; use crate::string::{AvmString, WStr}; -use crate::{avm2_stub_getter, avm2_stub_setter}; pub use crate::avm2::object::textformat_allocator as text_format_allocator; @@ -185,20 +185,51 @@ pub fn set_color<'gc>( } pub fn get_display<'gc>( - activation: &mut Activation<'_, 'gc>, - _this: Object<'gc>, + _activation: &mut Activation<'_, 'gc>, + this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_getter!(activation, "flash.text.TextFormat", "display"); - Ok("block".into()) + if let Some(text_format) = this.as_text_format() { + return Ok(text_format + .display + .as_ref() + .map_or(Value::Null, |display| match display { + TextDisplay::Block => "block".into(), + TextDisplay::Inline => "inline".into(), + TextDisplay::None => "none".into(), + })); + } + + Ok(Value::Undefined) } pub fn set_display<'gc>( activation: &mut Activation<'_, 'gc>, - _this: Object<'gc>, - _args: &[Value<'gc>], + this: Object<'gc>, + args: &[Value<'gc>], ) -> Result, Error<'gc>> { - avm2_stub_setter!(activation, "flash.text.TextFormat", "display"); + if let Some(mut text_format) = this.as_text_format_mut() { + let value = args.get(0).unwrap_or(&Value::Undefined); + let value = match value { + Value::Undefined | Value::Null => { + text_format.display = None; + return Ok(Value::Undefined); + } + value => value.coerce_to_string(activation)?, + }; + + text_format.display = if value == WStr::from_units(b"block") { + Some(TextDisplay::Block) + } else if value == WStr::from_units(b"inline") { + Some(TextDisplay::Inline) + } else if value == WStr::from_units(b"none") { + Some(TextDisplay::None) + } else { + // No error message for this, silently set it to None/null + None + }; + } + Ok(Value::Undefined) } diff --git a/core/src/avm2/object/textformat_object.rs b/core/src/avm2/object/textformat_object.rs index 6eeaaee20..f13b10f11 100644 --- a/core/src/avm2/object/textformat_object.rs +++ b/core/src/avm2/object/textformat_object.rs @@ -5,7 +5,7 @@ use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; -use crate::html::TextFormat; +use crate::html::{TextDisplay, TextFormat}; use core::fmt; use gc_arena::barrier::unlock; use gc_arena::lock::RefLock; @@ -21,7 +21,10 @@ pub fn textformat_allocator<'gc>( activation.gc(), TextFormatObjectData { base: RefLock::new(ScriptObjectData::new(class)), - text_format: Default::default(), + text_format: RefCell::new(TextFormat { + display: Some(TextDisplay::Block), + ..Default::default() + }), }, )) .into()) diff --git a/core/src/html.rs b/core/src/html.rs index ca49e943d..5a73b030b 100644 --- a/core/src/html.rs +++ b/core/src/html.rs @@ -9,7 +9,7 @@ pub use dimensions::BoxBounds; pub use dimensions::Position; pub use layout::{LayoutBox, LayoutContent, LayoutMetrics}; pub use stylesheet::CssStream; -pub use text_format::{FormatSpans, TextFormat, TextSpan}; +pub use text_format::{FormatSpans, TextDisplay, TextFormat, TextSpan}; mod stylesheet; #[cfg(test)] diff --git a/core/src/html/text_format.rs b/core/src/html/text_format.rs index c2a41207a..5036df48a 100644 --- a/core/src/html/text_format.rs +++ b/core/src/html/text_format.rs @@ -101,6 +101,14 @@ fn process_html_entity(src: &WStr) -> Option { Some(result_str) } +#[derive(Default, Clone, Debug, Eq, PartialEq)] +pub enum TextDisplay { + #[default] + Block, + Inline, + None, +} + /// A set of text formatting options to be applied to some part, or the whole /// of, a given text field. /// @@ -131,6 +139,7 @@ pub struct TextFormat { pub bullet: Option, pub url: Option, pub target: Option, + pub display: Option, } impl TextFormat { @@ -191,6 +200,7 @@ impl TextFormat { // TODO: These are probably empty strings by default url: Some(WString::new()), target: Some(WString::new()), + display: None, } } @@ -284,6 +294,11 @@ impl TextFormat { } else { None }, + display: if self.display == rhs.display { + self.display + } else { + None + }, } } @@ -311,6 +326,7 @@ impl TextFormat { bullet: self.bullet.or(rhs.bullet), url: self.url.or(rhs.url), target: self.target.or(rhs.target), + display: self.display.or(rhs.display), } } } @@ -542,6 +558,7 @@ impl TextSpan { bullet: Some(self.bullet), url: Some(self.url.clone()), target: Some(self.target.clone()), + display: None, // TODO } } } diff --git a/tests/tests/swfs/avm2/stylesheet_transform/Test.as b/tests/tests/swfs/avm2/stylesheet_transform/Test.as new file mode 100644 index 000000000..140bb29b2 --- /dev/null +++ b/tests/tests/swfs/avm2/stylesheet_transform/Test.as @@ -0,0 +1,277 @@ +package { + import flash.display.MovieClip; + import flash.text.StyleSheet; + import flash.text.TextFormat; + + + public class Test extends MovieClip { + // this is only relevant properties, some can't be set through css + var textFormatProperties = [ + "align", + "bold", + "color", + "font", + "indent", + "italic", + "kerning", + "leading", + "leftMargin", + "letterSpacing", + "rightMargin", + "size", + "underline", + "display" // undocumented! + ]; + + var interestingNumbers = [ + "", + "50", + "50.5 px", + "50 pt", + "50xx", + " 50", + "x50", + "0", + "-50", + "09" + ]; + + public function Test() { + var styleSheet: StyleSheet = new StyleSheet(); + + test("Empty", styleSheet, {}); + test("Null", styleSheet, null); + test("Undefined", styleSheet, undefined); + test("Number", styleSheet, 5); + + testSingleProperty("Color", styleSheet, "color", "color", [ + "red", + "", + "123", + "#", + "#1", + "#12", + "#123", + "#1234", + "#12345", + "#123456", + "#1234567", + "#red" + ]); + + testSingleProperty("Display", styleSheet, "display", "display", [ + "inline", + "block", + "none", + "invalid", + "" + ]); + + testSingleProperty("Font Family", styleSheet, "fontFamily", "font", [ + "", + "mono, sans-serif, serif", + "a b c, d e f , , g h", + "Times New Roman" + ]); + + testSingleProperty("Font Size", styleSheet, "fontSize", "size", interestingNumbers); + + testSingleProperty("Font Style", styleSheet, "fontStyle", "italic", [ + "", + "bold", + "italic", + "normal" + ]); + + testSingleProperty("Font Weight", styleSheet, "fontWeight", "bold", [ + "", + "bold", + "italic", + "normal" + ]); + + testSingleProperty("Kerning", styleSheet, "kerning", "kerning", [ + "", + "true", + "false", + "lots", + "50", + "0" + ]); + + testSingleProperty("Leading", styleSheet, "leading", "leading", interestingNumbers); + + testSingleProperty("Letter Spacing", styleSheet, "letterSpacing", "letterSpacing", interestingNumbers); + + testSingleProperty("Margin Left", styleSheet, "marginLeft", "leftMargin", interestingNumbers); + + testSingleProperty("Margin Right", styleSheet, "marginRight", "rightMargin", interestingNumbers); + + testSingleProperty("Text Align", styleSheet, "textAlign", "align", [ + "", + "invalid", + "left", + "right", + "justify", + "center" + ]); + + testSingleProperty("Text Decoration", styleSheet, "textDecoration", "underline", [ + "", + "bold", + "none", + "underline" + ]); + + testSingleProperty("Text Indent", styleSheet, "textIndent", "indent", interestingNumbers); + + test("Every property is valid", styleSheet, { + "color": "#FF0000", + "display": "block", + "fontFamily": "sans-serif", + "fontSize": "75px", + "fontStyle": "italic", + "fontWeight": "bold", + "kerning": "true", + "leading": "5", + "letterSpacing": "0", + "marginLeft": "0", + "marginRight": "0", + "textAlign": "justify", + "textDecoration": "underline", + "textIndent": "0" + }); + } + + function test(name: String, styleSheet: StyleSheet, style: *) { + trace("/// " + name); + dumpStyle("style", style); + trace(""); + try { + dumpFormat("format", styleSheet.transform(style)); + } catch (e) { + // [NA] The exact error message deviates at time of writing because of int vs Number + trace("! " + e.errorID); + } + trace(""); + } + + function testSingleProperty(name: String, styleSheet: StyleSheet, property: String, transformProperty: String, values: Array) { + trace("/// " + name); + + for each (var value in values) { + trace("// styleSheet.transform({" + escapeString(property) + ": " + escapeString(value) + "})"); + try { + var input = {}; + input[property] = value; + var result = styleSheet.transform(input); + dumpValue(transformProperty, result[transformProperty]); + } catch (e) { + trace("! " + e); + } + } + + trace(""); + } + + function dumpStyle(name: String, style: *) { + if (style === undefined) { + trace( name + " = undefined"); + } else if (style === null) { + trace( name + " = null"); + } else { + var first = true; + + // Sort is not deterministic + var sortedKeys = []; + for (var key in style) { + sortedKeys.push(key); + } + sortedKeys.sort(); + + for each (var key in sortedKeys) { + if (first) { + first = false; + trace(name + " = {"); + } + dumpValue(" " + escapeString(key), style[key]); + } + + if (first) { + trace(name + " = {}"); + } else { + trace("}"); + } + } + } + + function dumpFormat(name: String, format: *) { + if (format === undefined) { + trace( name + " = undefined"); + } else if (format === null) { + trace( name + " = null"); + } else { + var first = true; + + for each (var key in textFormatProperties) { + if (first) { + first = false; + trace(name + " = {"); + } + dumpValue(" " + escapeString(key), format[key]); + } + + if (first) { + trace(name + " = {}"); + } else { + trace("}"); + } + } + } + + function dumpValue(name: String, value: *) { + if (value === undefined) { + return; + } else if (value === null) { + trace(name + " = null"); + } else if (value is Number) { + trace(name + " = number " + value); + } else if (value is String) { + trace(name + " = string " + escapeString(value)); + } else if (value is Boolean) { + trace(name + " = boolean " + value); + } else if (value is Object) { + trace(name + " = object " + value); + } else { + trace(name + " = unknown " + value); + } + } + + function escapeString(input: String): String { + var output:String = "\""; + for (var i:int = 0; i < input.length; i++) { + var char:String = input.charAt(i); + switch (char) { + case "\\": + output += "\\\\"; + break; + case "\"": + output += "\\\""; + break; + case "\n": + output += "\\n"; + break; + case "\r": + output += "\\r"; + break; + case "\t": + output += "\\t"; + break; + default: + output += char; + } + } + return output + "\""; + } + } +} diff --git a/tests/tests/swfs/avm2/stylesheet_transform/output.txt b/tests/tests/swfs/avm2/stylesheet_transform/output.txt new file mode 100644 index 000000000..465d87de8 --- /dev/null +++ b/tests/tests/swfs/avm2/stylesheet_transform/output.txt @@ -0,0 +1,308 @@ +/// Empty +style = {} + +format = { + "align" = null + "bold" = null + "color" = null + "font" = null + "indent" = null + "italic" = null + "kerning" = boolean false + "leading" = null + "leftMargin" = null + "letterSpacing" = null + "rightMargin" = null + "size" = null + "underline" = null + "display" = string "block" +} + +/// Null +style = null + +format = null + +/// Undefined +style = undefined + +format = null + +/// Number +style = {} + +! 1069 + +/// Color +// styleSheet.transform({"color": "red"}) +color = number 0 +// styleSheet.transform({"color": ""}) +color = null +// styleSheet.transform({"color": "123"}) +color = number 0 +// styleSheet.transform({"color": "#"}) +color = number 0 +// styleSheet.transform({"color": "#1"}) +color = number 1 +// styleSheet.transform({"color": "#12"}) +color = number 18 +// styleSheet.transform({"color": "#123"}) +color = number 291 +// styleSheet.transform({"color": "#1234"}) +color = number 4660 +// styleSheet.transform({"color": "#12345"}) +color = number 74565 +// styleSheet.transform({"color": "#123456"}) +color = number 1193046 +// styleSheet.transform({"color": "#1234567"}) +color = number 0 +// styleSheet.transform({"color": "#red"}) +color = number 0 + +/// Display +// styleSheet.transform({"display": "inline"}) +display = string "inline" +// styleSheet.transform({"display": "block"}) +display = string "block" +// styleSheet.transform({"display": "none"}) +display = string "none" +// styleSheet.transform({"display": "invalid"}) +display = null +// styleSheet.transform({"display": ""}) +display = string "block" + +/// Font Family +// styleSheet.transform({"fontFamily": ""}) +font = null +// styleSheet.transform({"fontFamily": "mono, sans-serif, serif"}) +font = string "_typewriter,_sans,_serif" +// styleSheet.transform({"fontFamily": "a b c, d e f , , g h"}) +font = string "a b c,d e f ,g h" +// styleSheet.transform({"fontFamily": "Times New Roman"}) +font = string "Times New Roman" + +/// Font Size +// styleSheet.transform({"fontSize": ""}) +size = null +// styleSheet.transform({"fontSize": "50"}) +size = number 50 +// styleSheet.transform({"fontSize": "50.5 px"}) +size = number 50 +// styleSheet.transform({"fontSize": "50 pt"}) +size = number 50 +// styleSheet.transform({"fontSize": "50xx"}) +size = number 50 +// styleSheet.transform({"fontSize": " 50"}) +size = number 50 +// styleSheet.transform({"fontSize": "x50"}) +size = null +// styleSheet.transform({"fontSize": "0"}) +size = null +// styleSheet.transform({"fontSize": "-50"}) +size = null +// styleSheet.transform({"fontSize": "09"}) +size = number 9 + +/// Font Style +// styleSheet.transform({"fontStyle": ""}) +italic = null +// styleSheet.transform({"fontStyle": "bold"}) +italic = null +// styleSheet.transform({"fontStyle": "italic"}) +italic = boolean true +// styleSheet.transform({"fontStyle": "normal"}) +italic = boolean false + +/// Font Weight +// styleSheet.transform({"fontWeight": ""}) +bold = null +// styleSheet.transform({"fontWeight": "bold"}) +bold = boolean true +// styleSheet.transform({"fontWeight": "italic"}) +bold = null +// styleSheet.transform({"fontWeight": "normal"}) +bold = boolean false + +/// Kerning +// styleSheet.transform({"kerning": ""}) +kerning = boolean false +// styleSheet.transform({"kerning": "true"}) +kerning = boolean true +// styleSheet.transform({"kerning": "false"}) +kerning = boolean false +// styleSheet.transform({"kerning": "lots"}) +kerning = boolean false +// styleSheet.transform({"kerning": "50"}) +kerning = boolean true +// styleSheet.transform({"kerning": "0"}) +kerning = boolean false + +/// Leading +// styleSheet.transform({"leading": ""}) +leading = null +// styleSheet.transform({"leading": "50"}) +leading = number 50 +// styleSheet.transform({"leading": "50.5 px"}) +leading = number 50 +// styleSheet.transform({"leading": "50 pt"}) +leading = number 50 +// styleSheet.transform({"leading": "50xx"}) +leading = number 50 +// styleSheet.transform({"leading": " 50"}) +leading = number 50 +// styleSheet.transform({"leading": "x50"}) +leading = number -2147483648 +// styleSheet.transform({"leading": "0"}) +leading = number 0 +// styleSheet.transform({"leading": "-50"}) +leading = number -50 +// styleSheet.transform({"leading": "09"}) +leading = number 9 + +/// Letter Spacing +// styleSheet.transform({"letterSpacing": ""}) +letterSpacing = null +// styleSheet.transform({"letterSpacing": "50"}) +letterSpacing = number 50 +// styleSheet.transform({"letterSpacing": "50.5 px"}) +letterSpacing = number 50.5 +// styleSheet.transform({"letterSpacing": "50 pt"}) +letterSpacing = number 50 +// styleSheet.transform({"letterSpacing": "50xx"}) +letterSpacing = number 50 +// styleSheet.transform({"letterSpacing": " 50"}) +letterSpacing = number 50 +// styleSheet.transform({"letterSpacing": "x50"}) +letterSpacing = number NaN +// styleSheet.transform({"letterSpacing": "0"}) +letterSpacing = number 0 +// styleSheet.transform({"letterSpacing": "-50"}) +letterSpacing = number -50 +// styleSheet.transform({"letterSpacing": "09"}) +letterSpacing = number 9 + +/// Margin Left +// styleSheet.transform({"marginLeft": ""}) +leftMargin = null +// styleSheet.transform({"marginLeft": "50"}) +leftMargin = number 50 +// styleSheet.transform({"marginLeft": "50.5 px"}) +leftMargin = number 50 +// styleSheet.transform({"marginLeft": "50 pt"}) +leftMargin = number 50 +// styleSheet.transform({"marginLeft": "50xx"}) +leftMargin = number 50 +// styleSheet.transform({"marginLeft": " 50"}) +leftMargin = number 50 +// styleSheet.transform({"marginLeft": "x50"}) +leftMargin = number -2147483648 +// styleSheet.transform({"marginLeft": "0"}) +leftMargin = number 0 +// styleSheet.transform({"marginLeft": "-50"}) +leftMargin = number -50 +// styleSheet.transform({"marginLeft": "09"}) +leftMargin = number 9 + +/// Margin Right +// styleSheet.transform({"marginRight": ""}) +rightMargin = null +// styleSheet.transform({"marginRight": "50"}) +rightMargin = number 50 +// styleSheet.transform({"marginRight": "50.5 px"}) +rightMargin = number 50 +// styleSheet.transform({"marginRight": "50 pt"}) +rightMargin = number 50 +// styleSheet.transform({"marginRight": "50xx"}) +rightMargin = number 50 +// styleSheet.transform({"marginRight": " 50"}) +rightMargin = number 50 +// styleSheet.transform({"marginRight": "x50"}) +rightMargin = number -2147483648 +// styleSheet.transform({"marginRight": "0"}) +rightMargin = number 0 +// styleSheet.transform({"marginRight": "-50"}) +rightMargin = number -50 +// styleSheet.transform({"marginRight": "09"}) +rightMargin = number 9 + +/// Text Align +// styleSheet.transform({"textAlign": ""}) +align = null +// styleSheet.transform({"textAlign": "invalid"}) +! ArgumentError: Error #2008: Parameter align must be one of the accepted values. +// styleSheet.transform({"textAlign": "left"}) +align = string "left" +// styleSheet.transform({"textAlign": "right"}) +align = string "right" +// styleSheet.transform({"textAlign": "justify"}) +align = string "justify" +// styleSheet.transform({"textAlign": "center"}) +align = string "center" + +/// Text Decoration +// styleSheet.transform({"textDecoration": ""}) +underline = null +// styleSheet.transform({"textDecoration": "bold"}) +underline = null +// styleSheet.transform({"textDecoration": "none"}) +underline = boolean false +// styleSheet.transform({"textDecoration": "underline"}) +underline = boolean true + +/// Text Indent +// styleSheet.transform({"textIndent": ""}) +indent = null +// styleSheet.transform({"textIndent": "50"}) +indent = number 50 +// styleSheet.transform({"textIndent": "50.5 px"}) +indent = number 50 +// styleSheet.transform({"textIndent": "50 pt"}) +indent = number 50 +// styleSheet.transform({"textIndent": "50xx"}) +indent = number 50 +// styleSheet.transform({"textIndent": " 50"}) +indent = number 50 +// styleSheet.transform({"textIndent": "x50"}) +indent = number -2147483648 +// styleSheet.transform({"textIndent": "0"}) +indent = number 0 +// styleSheet.transform({"textIndent": "-50"}) +indent = number -50 +// styleSheet.transform({"textIndent": "09"}) +indent = number 9 + +/// Every property is valid +style = { + "color" = string "#FF0000" + "display" = string "block" + "fontFamily" = string "sans-serif" + "fontSize" = string "75px" + "fontStyle" = string "italic" + "fontWeight" = string "bold" + "kerning" = string "true" + "leading" = string "5" + "letterSpacing" = string "0" + "marginLeft" = string "0" + "marginRight" = string "0" + "textAlign" = string "justify" + "textDecoration" = string "underline" + "textIndent" = string "0" +} + +format = { + "align" = string "justify" + "bold" = boolean true + "color" = number 16711680 + "font" = string "_sans" + "indent" = number 0 + "italic" = boolean true + "kerning" = boolean true + "leading" = number 5 + "leftMargin" = number 0 + "letterSpacing" = number 0 + "rightMargin" = number 0 + "size" = number 75 + "underline" = boolean true + "display" = string "block" +} + diff --git a/tests/tests/swfs/avm2/stylesheet_transform/test.fla b/tests/tests/swfs/avm2/stylesheet_transform/test.fla new file mode 100644 index 000000000..7d775a4e9 Binary files /dev/null and b/tests/tests/swfs/avm2/stylesheet_transform/test.fla differ diff --git a/tests/tests/swfs/avm2/stylesheet_transform/test.swf b/tests/tests/swfs/avm2/stylesheet_transform/test.swf new file mode 100644 index 000000000..394759fa5 Binary files /dev/null and b/tests/tests/swfs/avm2/stylesheet_transform/test.swf differ diff --git a/tests/tests/swfs/avm2/stylesheet_transform/test.toml b/tests/tests/swfs/avm2/stylesheet_transform/test.toml new file mode 100644 index 000000000..67f15e863 --- /dev/null +++ b/tests/tests/swfs/avm2/stylesheet_transform/test.toml @@ -0,0 +1 @@ +num_ticks = 1 \ No newline at end of file