diff --git a/core/src/avm2.rs b/core/src/avm2.rs index 7743ab56f..f65e6cd7d 100644 --- a/core/src/avm2.rs +++ b/core/src/avm2.rs @@ -124,6 +124,7 @@ pub struct Avm2<'gc> { pub flash_utils_internal: Namespace<'gc>, pub flash_geom_internal: Namespace<'gc>, pub flash_events_internal: Namespace<'gc>, + pub flash_text_engine_internal: Namespace<'gc>, #[collect(require_static)] native_method_table: &'static [Option<(&'static str, NativeMethodImpl)>], @@ -190,6 +191,7 @@ impl<'gc> Avm2<'gc> { flash_utils_internal: Namespace::internal("flash.utils", context), flash_geom_internal: Namespace::internal("flash.geom", context), flash_events_internal: Namespace::internal("flash.events", context), + flash_text_engine_internal: Namespace::internal("flash.text.engine", context), native_method_table: Default::default(), native_instance_allocator_table: Default::default(), diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index b07528d6b..414d451c5 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -167,6 +167,7 @@ pub struct SystemClasses<'gc> { pub statusevent: ClassObject<'gc>, pub contextmenuevent: ClassObject<'gc>, pub font: ClassObject<'gc>, + pub textline: ClassObject<'gc>, } impl<'gc> SystemClasses<'gc> { @@ -293,6 +294,7 @@ impl<'gc> SystemClasses<'gc> { statusevent: object, contextmenuevent: object, font: object, + textline: object, } } } @@ -801,6 +803,7 @@ fn load_playerglobal<'gc>( ("flash.text", "TextFormat", textformat), ("flash.text", "TextField", textfield), ("flash.text", "TextLineMetrics", textlinemetrics), + ("flash.text.engine", "TextLine", textline), ("flash.filters", "BevelFilter", bevelfilter), ("flash.filters", "BitmapFilter", bitmapfilter), ("flash.filters", "BlurFilter", blurfilter), diff --git a/core/src/avm2/globals/flash/text/engine.rs b/core/src/avm2/globals/flash/text/engine.rs index e55c7d33f..0a6b2f5b7 100644 --- a/core/src/avm2/globals/flash/text/engine.rs +++ b/core/src/avm2/globals/flash/text/engine.rs @@ -1,4 +1,5 @@ //! `flash.text.engine` namespace +pub mod text_block; pub mod text_justifier; pub mod text_line; diff --git a/core/src/avm2/globals/flash/text/engine/ContentElement.as b/core/src/avm2/globals/flash/text/engine/ContentElement.as index b4f92caff..ec39fe4e6 100644 --- a/core/src/avm2/globals/flash/text/engine/ContentElement.as +++ b/core/src/avm2/globals/flash/text/engine/ContentElement.as @@ -3,6 +3,8 @@ package flash.text.engine { public class ContentElement { public static const GRAPHIC_ELEMENT:uint = 65007; public var userData; + + internal var _text:String = null; private var _elementFormat:ElementFormat; @@ -10,6 +12,10 @@ package flash.text.engine { // FIXME: `new ContentElement()` throws an error in Flash; see TextJustifier this._elementFormat = elementFormat; } + + public function get text():String { + return this._text; + } public function get elementFormat():ElementFormat { return this._elementFormat; diff --git a/core/src/avm2/globals/flash/text/engine/ElementFormat.as b/core/src/avm2/globals/flash/text/engine/ElementFormat.as index 0549b4565..c270f77a4 100644 --- a/core/src/avm2/globals/flash/text/engine/ElementFormat.as +++ b/core/src/avm2/globals/flash/text/engine/ElementFormat.as @@ -1,10 +1,200 @@ package flash.text.engine { public final class ElementFormat { + private var _alignmentBaseline:String; + + private var _alpha:Number; + + private var _baselineShift:Number; + + private var _breakOpportunity:String; + + private var _color:uint; + + private var _digitCase:String; + + private var _digitWidth:String; + + private var _dominantBaseline:String; + + private var _fontDescription:FontDescription; + + private var _fontSize:Number; + + private var _kerning:String; + + private var _ligatureLevel:String; + + private var _locale:String; + + private var _textRotation:String; + + private var _trackingLeft:Number; + + private var _trackingRight:Number; + + private var _typographicCase:String; + + public function ElementFormat(fontDescription:FontDescription = null, fontSize:Number = 12, color:uint = 0, alpha:Number = 1, textRotation:String = "auto", dominantBaseline:String = "roman", alignmentBaseline:String = "useDominantBaseline", baselineShift:Number = 0, kerning:String = "on", trackingRight:Number = 0, trackingLeft:Number = 0, locale:String = "en", breakOpportunity:String = "auto", digitCase:String = "default", digitWidth:String = "default", ligatureLevel:String = "common", - typographicCase:String = "default") {} + typographicCase:String = "default") { + this.fontDescription = (fontDescription != null) ? fontDescription : new FontDescription(); + + this.alignmentBaseline = alignmentBaseline; + this.alpha = alpha; + this.baselineShift = baselineShift; + this.breakOpportunity = breakOpportunity; + this.color = color; + this.digitCase = digitCase; + this.digitWidth = digitWidth; + this.dominantBaseline = dominantBaseline; + this.fontSize = fontSize; + this.kerning = kerning; + this.ligatureLevel = ligatureLevel; + this.locale = locale; + this.textRotation = textRotation; + this.trackingLeft = trackingLeft; + this.trackingRight = trackingRight; + this.typographicCase = typographicCase; + } + + public function get alignmentBaseline():String { + return this._alignmentBaseline; + } + + public function set alignmentBaseline(value:String):void { + this._alignmentBaseline = value; + } + + public function get alpha():Number { + return this._alpha; + } + + public function set alpha(value:Number):void { + this._alpha = value; + } + + public function get baselineShift():Number { + return this._baselineShift; + } + + public function set baselineShift(value:Number):void { + this._baselineShift = value; + } + + public function get breakOpportunity():String { + return this._breakOpportunity; + } + + public function set breakOpportunity(value:String):void { + this._breakOpportunity = value; + } + + public function get color():uint { + return this._color; + } + + public function set color(value:uint):void { + this._color = value; + } + + public function get digitCase():String { + return this._digitCase; + } + + public function set digitCase(value:String):void { + this._digitCase = value; + } + + public function get digitWidth():String { + return this._digitWidth; + } + + public function set digitWidth(value:String):void { + this._digitWidth = value; + } + + public function get dominantBaseline():String { + return this._dominantBaseline; + } + + public function set dominantBaseline(value:String):void { + this._dominantBaseline = value; + } + + public function get fontDescription():FontDescription { + return this._fontDescription; + } + + public function set fontDescription(value:FontDescription):void { + this._fontDescription = value; + } + + public function get fontSize():Number { + return this._fontSize; + } + + public function set fontSize(value:Number):void { + this._fontSize = value; + } + + public function get kerning():String { + return this._kerning; + } + + public function set kerning(value:String):void { + this._kerning = value; + } + + public function get ligatureLevel():String { + return this._ligatureLevel; + } + + public function set ligatureLevel(value:String):void { + this._ligatureLevel = value; + } + + public function get locale():String { + return this._locale; + } + + public function set locale(value:String):void { + this._locale = value; + } + + public function get textRotation():String { + return this._textRotation; + } + + public function set textRotation(value:String):void { + this._textRotation = value; + } + + public function get trackingLeft():Number { + return this._trackingLeft; + } + + public function set trackingLeft(value:Number):void { + this._trackingLeft = value; + } + + public function get trackingRight():Number { + return this._trackingRight; + } + + public function set trackingRight(value:Number):void { + this._trackingRight = value; + } + + public function get typographicCase():String { + return this._typographicCase; + } + + public function set typographicCase(value:String):void { + this._typographicCase = value; + } } } diff --git a/core/src/avm2/globals/flash/text/engine/FontDescription.as b/core/src/avm2/globals/flash/text/engine/FontDescription.as index 0ebe32480..12a5d6e0f 100644 --- a/core/src/avm2/globals/flash/text/engine/FontDescription.as +++ b/core/src/avm2/globals/flash/text/engine/FontDescription.as @@ -1,6 +1,75 @@ package flash.text.engine { public final class FontDescription { + private var _fontName:String; + + private var _fontWeight:String; + + private var _fontPosture:String; + + private var _fontLookup:String; + + private var _renderingMode:String; + + private var _cffHinting:String; + + + public function FontDescription(fontName:String = "_serif", fontWeight:String = "normal", fontPosture:String = "normal", - fontLookup:String = "device", renderingMode:String = "cff", cffHinting:String = "horizontalStem") {} + fontLookup:String = "device", renderingMode:String = "cff", cffHinting:String = "horizontalStem") { + this.fontName = fontName; + this.fontWeight = fontWeight; + this.fontPosture = fontPosture; + this.fontLookup = fontLookup; + this.renderingMode = renderingMode; + this.cffHinting = cffHinting; + } + + public function get fontName():String { + return this._fontName; + } + + public function set fontName(value:String):void { + this._fontName = value; + } + + public function get fontWeight():String { + return this._fontWeight; + } + + public function set fontWeight(value:String):void { + this._fontWeight = value; + } + + public function get fontPosture():String { + return this._fontPosture; + } + + public function set fontPosture(value:String):void { + this._fontPosture = value; + } + + public function get fontLookup():String { + return this._fontLookup; + } + + public function set fontLookup(value:String):void { + this._fontLookup = value; + } + + public function get renderingMode():String { + return this._renderingMode; + } + + public function set renderingMode(value:String):void { + this._renderingMode = value; + } + + public function get cffHinting():String { + return this._cffHinting; + } + + public function set cffHinting(value:String):void { + this._cffHinting = value; + } } } diff --git a/core/src/avm2/globals/flash/text/engine/FontMetrics.as b/core/src/avm2/globals/flash/text/engine/FontMetrics.as new file mode 100644 index 000000000..cb230565d --- /dev/null +++ b/core/src/avm2/globals/flash/text/engine/FontMetrics.as @@ -0,0 +1,39 @@ +package flash.text.engine { + import flash.geom.Rectangle; + + public final class FontMetrics { + public var emBox:Rectangle; + + public var strikethroughOffset:Number; + + public var strikethroughThickness:Number; + + public var underlineOffset:Number; + + public var underlineThickness:Number; + + public var subscriptOffset:Number; + + public var subscriptScale:Number; + + public var superscriptOffset:Number; + + public var superscriptScale:Number; + + public var lineGap:Number; + + public function FontMetrics(emBox:Rectangle, strikethroughOffset:Number, strikethroughThickness:Number, underlineOffset:Number, underlineThickness:Number, subscriptOffset:Number, subscriptScale:Number, superscriptOffset:Number, superscriptScale:Number, lineGap:Number = 0) { + this.emBox = emBox; + this.strikethroughOffset = strikethroughOffset; + this.strikethroughThickness = strikethroughThickness; + this.underlineOffset = underlineOffset; + this.underlineThickness = underlineThickness; + this.subscriptOffset = subscriptOffset; + this.subscriptScale = subscriptScale; + this.superscriptOffset = superscriptOffset; + this.superscriptScale = superscriptScale; + this.lineGap = lineGap; + } + } +} + diff --git a/core/src/avm2/globals/flash/text/engine/GroupElement.as b/core/src/avm2/globals/flash/text/engine/GroupElement.as new file mode 100644 index 000000000..66d7654f3 --- /dev/null +++ b/core/src/avm2/globals/flash/text/engine/GroupElement.as @@ -0,0 +1,11 @@ +package flash.text.engine { + import flash.events.EventDispatcher; + + public final class GroupElement extends ContentElement { + public function GroupElement(elements:Vector. = null, elementFormat:ElementFormat = null, eventMirror:EventDispatcher = null, textRotation:String = "rotate0") { + super(elementFormat, eventMirror, textRotation); + this.setElements(elements); + } + } +} + diff --git a/core/src/avm2/globals/flash/text/engine/SpaceJustifier.as b/core/src/avm2/globals/flash/text/engine/SpaceJustifier.as index c6c5698c1..d5fb1f291 100644 --- a/core/src/avm2/globals/flash/text/engine/SpaceJustifier.as +++ b/core/src/avm2/globals/flash/text/engine/SpaceJustifier.as @@ -1,18 +1,45 @@ package flash.text.engine { public final class SpaceJustifier extends TextJustifier { private var _letterSpacing:Boolean; + private var _minimumSpacing:Number = 0.5; + private var _optimumSpacing:Number = 1.0; + private var _maximumSpacing:Number = 1.5; public function SpaceJustifier(locale:String = "en", lineJustification:String = "unjustified", letterSpacing:Boolean = false) { super(locale, lineJustification); this._letterSpacing = letterSpacing; } - + public function get letterSpacing():Boolean { return this._letterSpacing; } - + public function set letterSpacing(value:Boolean):void { this._letterSpacing = value; } + + public function get minimumSpacing():Number { + return this._minimumSpacing; + } + + public function set minimumSpacing(value:Number):void { + this._minimumSpacing = value; + } + + public function get maximumSpacing():Number { + return this._maximumSpacing; + } + + public function set maximumSpacing(value:Number):void { + this._maximumSpacing = value; + } + + public function get optimumSpacing():Number { + return this._optimumSpacing; + } + + public function set optimumSpacing(value:Number):void { + this._optimumSpacing = value; + } } } diff --git a/core/src/avm2/globals/flash/text/engine/TextBlock.as b/core/src/avm2/globals/flash/text/engine/TextBlock.as index fdb23b2ca..0da3a4e16 100644 --- a/core/src/avm2/globals/flash/text/engine/TextBlock.as +++ b/core/src/avm2/globals/flash/text/engine/TextBlock.as @@ -1,7 +1,7 @@ package flash.text.engine { public final class TextBlock { public var userData; - + private var _applyNonLinearFontScaling:Boolean; private var _baselineFontDescription:FontDescription = null; private var _baselineFontSize:Number = 12; @@ -11,8 +11,11 @@ package flash.text.engine { private var _tabStops:Vector.; private var _textJustifier:TextJustifier; private var _content:ContentElement; - - + + internal var _textLineCreationResult:String = null; + internal var _firstLine:TextLine = null; + + public function TextBlock(content:ContentElement = null, tabStops:Vector. = null, textJustifier:TextJustifier = null, @@ -36,9 +39,9 @@ package flash.text.engine { } else { // This should creaate a new TextJustifier with locale "en", but we don't actually support creating TextJustifiers yet. } - + this.lineRotation = lineRotation; - + if (baselineZero) { this.baselineZero = baselineZero; } @@ -48,51 +51,51 @@ package flash.text.engine { } this.applyNonLinearFontScaling = applyNonLinearFontScaling; } - + public function get applyNonLinearFontScaling():Boolean { return this._applyNonLinearFontScaling; } - + public function set applyNonLinearFontScaling(value:Boolean):void { this._applyNonLinearFontScaling = value; } - + public function get baselineFontDescription():FontDescription { return this._baselineFontDescription; } - + public function set baselineFontDescription(value:FontDescription):void { this._baselineFontDescription = value; } - + public function get baselineFontSize():Number { return this._baselineFontSize; } - + public function set baselineFontSize(value:Number):void { this._baselineFontSize = value; } - + public function get baselineZero():String { return this._baselineZero; } - + public function set baselineZero(value:String):void { this._baselineZero = value; } - + public function get bidiLevel():int { return this._bidiLevel; } - + public function set bidiLevel(value:int):void { this._bidiLevel = value; } - + public function get lineRotation():String { return this._lineRotation; } - + public function set lineRotation(value:String):void { if (value == null) { throw new TypeError("Error #2007: Parameter lineRotation must be non-null.", 2007); @@ -100,31 +103,54 @@ package flash.text.engine { // TODO: This should validate that `value` is a member of TextRotation this._lineRotation = value; } - + // Note: FP returns a copy of the Vector passed to it, so modifying the returned Vector doesn't affect the actual internal representation public function get tabStops():Vector. { return this._tabStops; } - + // Note: FP makes a copy of the Vector passed to it, then sets its internal representation to that public function set tabStops(value:Vector.):void { this._tabStops = value; } - + public function get textJustifier():TextJustifier { return this._textJustifier; } - + public function set textJustifier(value:TextJustifier):void { this._textJustifier = value; } - + public function get content():ContentElement { return this._content; } - + public function set content(value:ContentElement):void { this._content = value; } + + public native function createTextLine(previousLine:TextLine = null, width:Number = 1000000, lineOffset:Number = 0, fitSomething:Boolean = false):TextLine; + + public function get textLineCreationResult():String { + return this._textLineCreationResult; + } + + public function get firstLine():TextLine { + return this._firstLine; + } + + public function get lastLine():TextLine { + return this._firstLine; + } + + public function releaseLines(start:TextLine, end:TextLine):void { + if (start != end || end != this._firstLine) { + stub_method("flash.text.engine.TextBlock", "releaseLines", "with start != end or multiple lines"); + return; + } + this._firstLine._validity = "invalid"; + this._firstLine._textBlock = null; + } } } diff --git a/core/src/avm2/globals/flash/text/engine/TextElement.as b/core/src/avm2/globals/flash/text/engine/TextElement.as index 3d5c0e099..f161e9398 100644 --- a/core/src/avm2/globals/flash/text/engine/TextElement.as +++ b/core/src/avm2/globals/flash/text/engine/TextElement.as @@ -1,6 +1,7 @@ package flash.text.engine { import flash.events.EventDispatcher; import __ruffle__.stub_setter; + import __ruffle__.stub_method; public final class TextElement extends ContentElement { public function TextElement(text:String = null, elementFormat:ElementFormat = null, eventMirror:EventDispatcher = null, textRotation:String = "rotate0") { @@ -9,7 +10,20 @@ package flash.text.engine { // Contrary to the documentation, TextElement does not implement a getter here. It inherits the getter from ContentElement. public function set text(value:String):void { - stub_setter("flash.text.engine.TextElement", "text"); + this._text = value; + } + + public function replaceText(beginIndex:int, endIndex:int, newText:String):void { + var realText:String = this.text; + if (realText == null) { + realText = ""; + } + + if (beginIndex < 0 || endIndex < 0 || beginIndex > realText.length || endIndex > realText.length) { + throw new RangeError("Error #2006: The supplied index is out of bounds.", 2006); + } + + this.text = realText.slice(0, beginIndex) + newText + realText.slice(endIndex, realText.length); } } } diff --git a/core/src/avm2/globals/flash/text/engine/TextLine.as b/core/src/avm2/globals/flash/text/engine/TextLine.as index 1f1bd23d2..4f022da38 100644 --- a/core/src/avm2/globals/flash/text/engine/TextLine.as +++ b/core/src/avm2/globals/flash/text/engine/TextLine.as @@ -1,14 +1,113 @@ package flash.text.engine { + import __ruffle__.stub_getter; + import __ruffle__.stub_setter; + import __ruffle__.stub_method; + import flash.display.DisplayObjectContainer; - + import flash.geom.Rectangle; + [Ruffle(NativeInstanceInit)] public final class TextLine extends DisplayObjectContainer { + internal var _specifiedWidth:Number = 0.0; + internal var _textBlock:TextBlock = null; + internal var _rawTextLength:int = 0; + internal var _validity:String = "valid"; + public static const MAX_LINE_WIDTH:int = 1000000; - + public var userData; - + public function TextLine() { throw new ArgumentError("Error #2012: TextLine$ class cannot be instantiated.", 2012); } + + public function get rawTextLength():int { + return this._rawTextLength; + } + + public function get textBlockBeginIndex():int { + stub_getter("flash.text.engine.TextLine", "textBlockBeginIndex"); + return 0; + } + + public function get specifiedWidth():Number { + return this._specifiedWidth; + } + + public function get textBlock():TextBlock { + return this._textBlock; + } + + public function get ascent():Number { + stub_getter("flash.text.engine.TextLine", "ascent"); + return 12.0; + } + + public function get descent():Number { + stub_getter("flash.text.engine.TextLine", "descent"); + return 3.0; + } + + public function get unjustifiedTextWidth():Number { + stub_getter("flash.text.engine.TextLine", "unjustifiedTextWidth"); + return this._specifiedWidth; + } + + public function get textWidth():Number { + stub_getter("flash.text.engine.TextLine", "textWidth"); + return this._specifiedWidth; + } + + public function get textHeight():Number { + stub_getter("flash.text.engine.TextLine", "textHeight"); + return 15.0; + } + + public function get validity():String { + stub_getter("flash.text.engine.TextLine", "validity"); + return this._validity; + } + + public function set validity(value:String):void { + stub_setter("flash.text.engine.TextLine", "validity"); + this._validity = value; + } + + public function get hasGraphicElement():Boolean { + stub_getter("flash.text.engine.TextLine", "hasGraphicElement"); + return false; + } + + public function get atomCount():int { + stub_getter("flash.text.engine.TextLine", "atomCount"); + return this._rawTextLength; + } + + public function get nextLine():TextLine { + return null; + } + + public function getBaselinePosition(baseline:String):Number { + stub_method("flash.text.engine.TextLine", "getBaselinePosition"); + return 0.0; + } + + public function hasTabs():Boolean { + stub_getter("flash.text.engine.TextLine", "hasTabs"); + return false; + } + + public function getAtomIndexAtPoint(stageX:Number, stageY:Number):int { + stub_method("flash.text.engine.TextLine", "getAtomIndexAtPoint"); + return -1; + } + + public function getAtomBounds(index:int):Rectangle { + stub_method("flash.text.engine.TextLine", "getAtomBounds"); + return new Rectangle(0, 0, 0, 0); + } + + // This function does nothing in Flash Player 32 + public function flushAtomData():void { } } } diff --git a/core/src/avm2/globals/flash/text/engine/text_block.rs b/core/src/avm2/globals/flash/text/engine/text_block.rs new file mode 100644 index 000000000..fbd79d27f --- /dev/null +++ b/core/src/avm2/globals/flash/text/engine/text_block.rs @@ -0,0 +1,147 @@ +use crate::avm2::activation::Activation; +use crate::avm2::error::Error; +use crate::avm2::globals::flash::display::display_object::initialize_for_allocator; +use crate::avm2::object::{Object, TObject}; +use crate::avm2::parameters::ParametersExt; +use crate::avm2::value::Value; +use crate::avm2::Multiname; +use crate::avm2_stub_method; +use crate::display_object::{EditText, TDisplayObject}; +use crate::html::TextFormat; +use crate::string::WStr; + +pub fn create_text_line<'gc>( + activation: &mut Activation<'_, 'gc>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + avm2_stub_method!(activation, "flash.text.TextBlock", "createTextLine"); + + let previous_text_line = args.try_get_object(activation, 0); + let width = args.get_f64(activation, 1)?; + + let content = this.get_public_property("content", activation)?; + + let content = if matches!(content, Value::Null) { + return Ok(Value::Null); + } else { + content.as_object().unwrap() + }; + + let text = match previous_text_line { + Some(_) => { + // Some SWFs rely on eventually getting `null` from createLineText. + this.set_property( + &Multiname::new( + activation.avm2().flash_text_engine_internal, + "_textLineCreationResult", + ), + "complete".into(), + activation, + )?; + return Ok(Value::Null); + } + // Get the content element's text property. + // TODO: GraphicElement and GroupElement + None => content + .get_public_property("text", activation) + .and_then(|o| { + if matches!(o, Value::Null) { + Ok("".into()) + } else { + o.coerce_to_string(activation) + } + }) + .unwrap_or("".into()), + }; + + let class = activation.avm2().classes().textline; + let movie = activation.context.swf.clone(); + + // FIXME: TextLine should be its own DisplayObject + let display_object: EditText = + EditText::new(&mut activation.context, movie, 0.0, 0.0, width, 15.0).into(); + + display_object.set_text(text.as_wstr(), &mut activation.context); + + let element_format = content + .get_public_property("elementFormat", activation)? + .as_object(); + + let new_height = apply_format(activation, display_object, text.as_wstr(), element_format)?; + + display_object.set_height(activation.gc(), new_height); + + let instance = initialize_for_allocator(activation, display_object.into(), class)?; + class.call_native_init(instance.into(), &[], activation)?; + + instance.set_property( + &Multiname::new(activation.avm2().flash_text_engine_internal, "_textBlock"), + this.into(), + activation, + )?; + + instance.set_property( + &Multiname::new( + activation.avm2().flash_text_engine_internal, + "_specifiedWidth", + ), + args.get_value(1), + activation, + )?; + + instance.set_property( + &Multiname::new( + activation.avm2().flash_text_engine_internal, + "_rawTextLength", + ), + text.len().into(), + activation, + )?; + + this.set_property( + &Multiname::new( + activation.avm2().flash_text_engine_internal, + "_textLineCreationResult", + ), + "success".into(), + activation, + )?; + + this.set_property( + &Multiname::new(activation.avm2().flash_text_engine_internal, "_firstLine"), + instance.into(), + activation, + )?; + + Ok(instance.into()) +} + +fn apply_format<'gc>( + activation: &mut Activation<'_, 'gc>, + display_object: EditText<'gc>, + text: &WStr, + element_format: Option>, +) -> Result> { + if let Some(element_format) = element_format { + let color = element_format + .get_public_property("color", activation)? + .coerce_to_u32(activation)?; + let size = element_format + .get_public_property("fontSize", activation)? + .coerce_to_number(activation)?; + + let format = TextFormat { + color: Some(swf::Color::from_rgb(color, 0xFF)), + size: Some(size), + ..TextFormat::default() + }; + + display_object.set_text_format(0, text.len(), format.clone(), &mut activation.context); + display_object.set_new_text_format(format, &mut activation.context); + + return Ok(size * 1.2 + 3.0); + } + + Ok(15.0) +} diff --git a/core/src/avm2/globals/globals.as b/core/src/avm2/globals/globals.as index 44f58b3f4..28fb39034 100644 --- a/core/src/avm2/globals/globals.as +++ b/core/src/avm2/globals/globals.as @@ -349,8 +349,10 @@ include "flash/text/engine/DigitWidth.as" include "flash/text/engine/ElementFormat.as" include "flash/text/engine/FontDescription.as" include "flash/text/engine/FontLookup.as" +include "flash/text/engine/FontMetrics.as" include "flash/text/engine/FontPosture.as" include "flash/text/engine/FontWeight.as" +include "flash/text/engine/GroupElement.as" include "flash/text/engine/JustificationStyle.as" include "flash/text/engine/Kerning.as" include "flash/text/engine/LigatureLevel.as"