avm2: Basic TLF rendering support
This commit is contained in:
parent
94009e4b1a
commit
597e4e8b9b
|
@ -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(),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//! `flash.text.engine` namespace
|
||||
|
||||
pub mod text_block;
|
||||
pub mod text_justifier;
|
||||
pub mod text_line;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package flash.text.engine {
|
||||
import flash.events.EventDispatcher;
|
||||
|
||||
public final class GroupElement extends ContentElement {
|
||||
public function GroupElement(elements:Vector.<ContentElement> = null, elementFormat:ElementFormat = null, eventMirror:EventDispatcher = null, textRotation:String = "rotate0") {
|
||||
super(elementFormat, eventMirror, textRotation);
|
||||
this.setElements(elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.<TabStop>;
|
||||
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.<TabStop> = 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.<TabStop> {
|
||||
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.<TabStop>):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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Value<'gc>, 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<Object<'gc>>,
|
||||
) -> Result<f64, Error<'gc>> {
|
||||
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)
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue