import { InteractiveObject } from "../display/InteractiveObject"; import { assert, release, notImplemented, somewhatImplemented, warning } from "../../base/utilities/Debug"; import { AntiAliasType } from "./AntiAliasType"; import { TextFieldAutoSize } from "./TextFieldAutoSize"; import { GridFitType } from "./GridFitType"; import { TextInteractionMode } from "./TextInteractionMode"; import { TextFieldType } from "./TextFieldType"; import { TextFormat } from "./TextFormat"; import { Font, FontSymbol } from "./Font"; import { TextFormatAlign } from "./TextFormatAlign"; import { DisplaySymbol, SymbolData } from "../symbol"; import { Bounds, isNullOrUndefined } from "../../base/utilities"; import { DisplayObjectDirtyFlags, DisplayObject } from "../display/DisplayObject"; import { DataBuffer } from "@awayjs/graphics"; import { axCoerceString } from "../../avm2/run/axCoerceString"; import { Errors } from "../../avm2/errors"; import { clamp } from "../../base/utilities/NumberUtilities"; import { TextRecordFlags, TextRecord, TextFlags, TextTag } from "../../../parsers/utils/SWFTags" import { Rectangle } from "../geom/Rectangle"; import { TextLineMetrics } from "./TextLineMetrics"; import { ISecurityDomain } from "../../avm2/nat/ISecurityDomain"; import { ASArray } from "../../avm2/nat/ASArray"; import { LoaderInfo } from "../display/LoaderInfo"; import { StaticText } from "./StaticText"; import { Matrix } from "../geom/Matrix"; /** * Copyright 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Class: TextField export class TextField extends InteractiveObject { static classSymbols: string [] = null; static instanceSymbols: string [] = null; static classInitializer: any = null; _symbol: TextSymbol; applySymbol() { this._initializeFields(); release || assert(this._symbol); var symbol = this._symbol; this._setFillAndLineBoundsFromSymbol(symbol); var defaultTextFormat = this._textContent.defaultTextFormat; defaultTextFormat.color = symbol.color; defaultTextFormat.size = (symbol.size / 20) | 0; defaultTextFormat.font = symbol.face; defaultTextFormat.bold = symbol.bold; defaultTextFormat.italic = symbol.italic; defaultTextFormat.align = symbol.align; defaultTextFormat.leftMargin = (symbol.leftMargin / 20) | 0; defaultTextFormat.rightMargin = (symbol.rightMargin / 20) | 0; defaultTextFormat.indent = (symbol.indent / 20) | 0; defaultTextFormat.leading = (symbol.leading / 20) | 0; this._multiline = symbol.multiline; this._embedFonts = symbol.embedFonts; this._selectable = symbol.selectable; this._displayAsPassword = symbol.displayAsPassword; this._type = symbol.type; this._maxChars = symbol.maxChars; if (symbol.border) { this.background = true; this.border = true; } if (symbol.html) { this.htmlText = symbol.initialText; } else { this.text = symbol.initialText; } this.wordWrap = symbol.wordWrap; this.autoSize = symbol.autoSize; } constructor() { super(); if (!this._fieldsInitialized) { this._initializeFields(); } if (!this._symbol) { this._setFillAndLineBoundsFromWidthAndHeight(100 * 20, 100 * 20); } } protected _initializeFields(): void { super._initializeFields(); this._alwaysShowSelection = false; this._antiAliasType = AntiAliasType.NORMAL; this._autoSize = TextFieldAutoSize.NONE; this._background = false; this._backgroundColor = 0xffffffff; this._border = false; this._borderColor = 0x000000ff; this._bottomScrollV = 1; this._caretIndex = 0; this._condenseWhite = false; this._embedFonts = false; this._gridFitType = GridFitType.PIXEL; this._htmlText = ''; this._length = 0; this._textInteractionMode = TextInteractionMode.NORMAL; this._maxChars = 0; this._maxScrollH = 0; this._maxScrollV = 1; this._mouseWheelEnabled = false; this._multiline = false; this._numLines = 1; this._displayAsPassword = false; this._restrict = null; this._selectable = true; this._selectedText = ''; this._selectionBeginIndex = 0; this._selectionEndIndex = 0; this._sharpness = 0; this._styleSheet = null; this._textColor = null; this._textHeight = 0; this._textWidth = 0; this._thickness = 0; this._type = TextFieldType.DYNAMIC; this._useRichTextClipboard = false; this._lineMetricsData = null; var defaultTextFormat = new TextFormat( Font.axClass.DEFAULT_FONT_SERIF, 12, 0, false, false, false, '', '', TextFormatAlign.LEFT ); defaultTextFormat.letterSpacing = 0; defaultTextFormat.kerning = 0; console.log("80pro todo: TextContent"); //this._textContent = new TextContent(this.sec, defaultTextFormat); } _setFillAndLineBoundsFromSymbol(symbol: DisplaySymbol) { super._setFillAndLineBoundsFromSymbol(symbol); this._textContent.bounds = this._lineBounds; this._invalidateContent(); } _setFillAndLineBoundsFromWidthAndHeight(width: number, height: number) { super._setFillAndLineBoundsFromWidthAndHeight(width, height); this._textContent.bounds = this._lineBounds; this._invalidateContent(); } _canHaveTextContent(): boolean { return true; } _getTextContent(): any/*TextContent*/ { return this._textContent; } _getContentBounds(includeStrokes: boolean = true): Bounds { this._ensureLineMetrics(); return super._getContentBounds(includeStrokes); } _containsPointDirectly(localX: number, localY: number, globalX: number, globalY: number): boolean { // If this override is reached, the content bounds have already been checked, which is all // we need to do. release || assert(this._getContentBounds().contains(localX, localY)); return true; } private _invalidateContent() { console.log("80pro todo: _invalidateContent"); /* if (this._textContent.flags & TextContentFlag.Dirty) { this._setDirtyFlags(DisplayObjectDirtyFlags.DirtyTextContent); }*/ } _textContent: any;//TextContent; _lineMetricsData: DataBuffer; // JS -> AS Bindings //selectedText: string; //appendText: (newText: string) => void; //getXMLText: (beginIndex: number /*int*/ = 0, endIndex: number /*int*/ = 2147483647) => // string; //insertXMLText: (beginIndex: number /*int*/, endIndex: number /*int*/, richText: string, // pasting: boolean = false) => void; copyRichText: () => string; pasteRichText: (richText: // string) => boolean; // AS -> JS Bindings static isFontCompatible(fontName: string, fontStyle: string): boolean { fontName = axCoerceString(fontName); fontStyle = axCoerceString(fontStyle); var font = Font.getByNameAndStyle(fontName, fontStyle); if (!font) { return false; } return font.fontStyle === fontStyle; } _alwaysShowSelection: boolean; _antiAliasType: string; _autoSize: string; _background: boolean; _backgroundColor: number /*uint*/; _border: boolean; _borderColor: number /*uint*/; _bottomScrollV: number /*int*/; _caretIndex: number /*int*/; _condenseWhite: boolean; _embedFonts: boolean; _gridFitType: string; _htmlText: string; _length: number /*int*/; _textInteractionMode: string; _maxChars: number /*int*/; _maxScrollH: number /*int*/; _maxScrollV: number /*int*/; _mouseWheelEnabled: boolean; _multiline: boolean; _numLines: number /*int*/; _displayAsPassword: boolean; _restrict: string; _scrollH: number /*int*/; _scrollV: number /*int*/; _selectable: boolean; _selectedText: string; _selectionBeginIndex: number /*int*/; _selectionEndIndex: number /*int*/; _sharpness: number; _styleSheet: StyleSheet; _textColor: number /*uint*/; _textHeight: number; _textWidth: number; _thickness: number; _type: string; _wordWrap: boolean; _useRichTextClipboard: boolean; get alwaysShowSelection(): boolean { return this._alwaysShowSelection; } set alwaysShowSelection(value: boolean) { this._alwaysShowSelection = !!value; } get antiAliasType(): string { return this._antiAliasType; } set antiAliasType(antiAliasType: string) { if (isNullOrUndefined(antiAliasType)) { this.sec.throwError('TypeError', Errors.NullPointerError, 'antiAliasType'); } antiAliasType = axCoerceString(antiAliasType); if (AntiAliasType.toNumber(antiAliasType) < 0) { this.sec.throwError("ArgumentError", Errors.InvalidParamError, "antiAliasType"); } this._antiAliasType = antiAliasType; } get autoSize(): string { return this._autoSize; } set autoSize(value: string) { if (isNullOrUndefined(value)) { this.sec.throwError('TypeError', Errors.NullPointerError, 'autoSize'); } value = axCoerceString(value); if (value === this._autoSize) { return; } if (TextFieldAutoSize.toNumber(value) < 0) { this.sec.throwError("ArgumentError", Errors.InvalidParamError, "autoSize"); } this._autoSize = value; this._textContent.autoSize = TextFieldAutoSize.toNumber(value); this._invalidateContent(); this._ensureLineMetrics(); } get background(): boolean { return this._background; } set background(value: boolean) { value = !!value; if (value === this._background) { return; } this._background = value; this._textContent.backgroundColor = value ? this._backgroundColor : 0; this._setDirtyFlags(DisplayObjectDirtyFlags.DirtyTextContent); } get backgroundColor(): number /*uint*/ { return this._backgroundColor >> 8; } set backgroundColor(value: number /*uint*/) { value = ((value << 8) | 0xff) >>> 0; if (value === this._backgroundColor) { return; } this._backgroundColor = value; if (this._background) { this._textContent.backgroundColor = value; this._setDirtyFlags(DisplayObjectDirtyFlags.DirtyTextContent); } } get border(): boolean { return this._border; } set border(value: boolean) { value = !!value; if (value === this._border) { return; } this._border = value; this._textContent.borderColor = value ? this._borderColor : 0; this._setDirtyFlags(DisplayObjectDirtyFlags.DirtyTextContent); } get borderColor(): number /*uint*/ { return this._borderColor >> 8; } set borderColor(value: number /*uint*/) { value = ((value << 8) | 0xff) >>> 0; if (value === this._borderColor) { return; } this._borderColor = value; if (this._border) { this._textContent.borderColor = value; this._setDirtyFlags(DisplayObjectDirtyFlags.DirtyTextContent); } } // Returns bottommost line that is currently visible. get bottomScrollV(): number /*int*/ { return this._bottomScrollV; } get caretIndex(): number /*int*/ { release || notImplemented("public flash.text.TextField::get caretIndex"); return; // return this._caretIndex; } get condenseWhite(): boolean { return this._condenseWhite; } set condenseWhite(value: boolean) { this._condenseWhite = !!value; } get defaultTextFormat(): TextFormat { return this._textContent.defaultTextFormat.clone(); } set defaultTextFormat(format: TextFormat) { if (isNullOrUndefined(format)) { this.sec.throwError('TypeError', Errors.NullPointerError, 'format'); } var defaultTextFormat = this._textContent.defaultTextFormat; defaultTextFormat.merge(format); if (defaultTextFormat.color === null) { defaultTextFormat.color = this._textColor; } else { this._textColor = +defaultTextFormat.color; } } get embedFonts(): boolean { return this._embedFonts; } set embedFonts(value: boolean) { this._embedFonts = !!value; } get gridFitType(): string { return this._gridFitType; } set gridFitType(gridFitType: string) { if (isNullOrUndefined(gridFitType)) { this.sec.throwError('TypeError', Errors.NullPointerError, 'gridFitType'); } gridFitType = axCoerceString(gridFitType); release || assert (GridFitType.toNumber(gridFitType) >= 0); this._gridFitType = gridFitType; } get htmlText(): string { return this._htmlText; } set htmlText(value: string) { if (isNullOrUndefined(value)) { this.sec.throwError('TypeError', Errors.NullPointerError, 'value'); } value = axCoerceString(value); // Flash resets the bold and italic flags when an html value is set on a text field created // from a symbol. if (this._symbol) { this._textContent.defaultTextFormat.bold = false; this._textContent.defaultTextFormat.italic = false; } this._textContent.parseHtml(value, this._styleSheet, this._multiline); this._htmlText = value; this._invalidateContent(); this._ensureLineMetrics(); } get length(): number /*int*/ { return this._length; } get textInteractionMode(): string { release || notImplemented("public flash.text.TextField::get textInteractionMode"); return; // return this._textInteractionMode; } get maxChars(): number /*int*/ { return this._maxChars; } set maxChars(value: number /*int*/) { this._maxChars = value | 0; } get maxScrollH(): number /*int*/ { this._ensureLineMetrics(); return this._maxScrollH; } get maxScrollV(): number /*int*/ { this._ensureLineMetrics(); return this._maxScrollV; } get mouseWheelEnabled(): boolean { return this._mouseWheelEnabled; } set mouseWheelEnabled(value: boolean) { release || somewhatImplemented("public flash.text.TextField::set mouseWheelEnabled"); this._mouseWheelEnabled = !!value; } get multiline(): boolean { return this._multiline; } set multiline(value: boolean) { this._multiline = !!value; } get numLines(): number /*int*/ { return this._numLines; } get displayAsPassword(): boolean { return this._displayAsPassword; } set displayAsPassword(value: boolean) { release || somewhatImplemented("public flash.text.TextField::set displayAsPassword"); this._displayAsPassword = !!value; } get restrict(): string { return this._restrict; } set restrict(value: string) { release || somewhatImplemented("public flash.text.TextField::set restrict"); this._restrict = axCoerceString(value); } // Returns the current vertical scrolling position in lines. get scrollH(): number /*int*/ { return this._textContent.scrollH; } set scrollH(value: number /*int*/) { value = value | 0; this._ensureLineMetrics(); this._textContent.scrollH = clamp(Math.abs(value), 0, this._maxScrollH); this._invalidateContent(); } // Returns the current horizontal scrolling position in pixels. get scrollV(): number /*int*/ { return this._textContent.scrollV; } set scrollV(value: number /*int*/) { value = value | 0; this._ensureLineMetrics(); this._textContent.scrollV = clamp(value, 1, this._maxScrollV); this._invalidateContent(); } get selectable(): boolean { return this._selectable; } set selectable(value: boolean) { this._selectable = !!value; } get selectedText(): string { return this._textContent.plainText.substring(this._selectionBeginIndex, this._selectionEndIndex); } get selectionBeginIndex(): number /*int*/ { return this._selectionBeginIndex; } get selectionEndIndex(): number /*int*/ { return this._selectionEndIndex; } get sharpness(): number { return this._sharpness; } set sharpness(value: number) { this._sharpness = clamp(+value, -400, 400); } get styleSheet(): StyleSheet { return this._styleSheet; } set styleSheet(value: StyleSheet) { this._styleSheet = value; } get text(): string { return this._textContent.plainText; } set text(value: string) { if (isNullOrUndefined(value)) { this.sec.throwError('TypeError', Errors.NullPointerError, 'value'); } value = axCoerceString(value) || ''; if (value === this._textContent.plainText) { return; } this._textContent.plainText = value; this._invalidateContent(); this._ensureLineMetrics(); } get textColor(): number /*uint*/ { return this._textColor === null ? +this._textContent.defaultTextFormat.color : this._textColor; } set textColor(value: number /*uint*/) { this._textColor = this._textContent.defaultTextFormat.color = value >>> 0; } get textHeight(): number { this._ensureLineMetrics(); return (this._textHeight / 20) | 0; } get textWidth(): number { this._ensureLineMetrics(); return (this._textWidth / 20) | 0; } get thickness(): number { return this._thickness; } set thickness(value: number) { this._thickness = clamp(+value, -200, 200); } get type(): string { return this._type; } set type(value: string) { this._type = axCoerceString(value); } get wordWrap(): boolean { return this._textContent.wordWrap; } set wordWrap(value: boolean) { value = !!value; if (value === this._textContent.wordWrap) { return; } this._textContent.wordWrap = !!value; this._invalidateContent(); } get useRichTextClipboard(): boolean { release || notImplemented("public flash.text.TextField::get useRichTextClipboard"); return; // return this._useRichTextClipboard; } set useRichTextClipboard(value: boolean) { value = !!value; release || notImplemented("public flash.text.TextField::set useRichTextClipboard"); return; // this._useRichTextClipboard = value; } copyRichText() { release || notImplemented("public flash.text.TextField::copyRichText"); } pasteRichText(richText: string) { richText = axCoerceString(richText); release || notImplemented("public flash.text.TextField::pasteRichText"); } getXMLText(beginIndex: number, endIndex: number = 2147483647): string { beginIndex = +beginIndex; endIndex = +endIndex; release || notImplemented("public flash.text.TextField::getXMLText"); return ""; } insertXMLText(beginIndex: number, endIndex: number, richText: String, pasting: Boolean): void { beginIndex = +beginIndex; endIndex = +endIndex; richText = axCoerceString(richText); pasting = !!pasting; release || notImplemented("public flash.text.TextField::insertXMLText"); } private _ensureLineMetrics() { if (!this._hasDirtyFlags(DisplayObjectDirtyFlags.DirtyTextContent)) { return; } var serializer = this.sec.player; var lineMetricsData = serializer.syncDisplayObject(this, false); var textWidth = lineMetricsData.readInt(); var textHeight = lineMetricsData.readInt(); var offsetX = lineMetricsData.readInt(); var bounds = this._lineBounds; if (this._autoSize !== TextFieldAutoSize.NONE) { bounds.xMin = offsetX; bounds.xMax = offsetX + textWidth + 80; bounds.yMax = bounds.yMin + textHeight + 80; } this._textWidth = textWidth; this._textHeight = textHeight; this._numLines = lineMetricsData.readInt(); this._lineMetricsData = lineMetricsData; if (this._textHeight > bounds.height) { var maxScrollV = 1; var bottomScrollV = 1; lineMetricsData.position = 16; var y = 0; for (var i = 0; i < this._numLines; i++) { lineMetricsData.position += 8; var ascent = lineMetricsData.readInt(); var descent = lineMetricsData.readInt(); var leading = lineMetricsData.readInt(); var height = ascent + descent + leading; if (y > bounds.height / 20) { maxScrollV++; } else { bottomScrollV++; } y += height; } this._maxScrollV = maxScrollV; this._bottomScrollV = bottomScrollV; } if (this._textWidth > bounds.width) { this._maxScrollH = (((this._textWidth + 80) - bounds.width) / 20) | 0; } else { this._maxScrollH = 0; } } appendText(newText: string) { this._textContent.appendText(axCoerceString(newText)); } getCharBoundaries(charIndex: number /*int*/): Rectangle { charIndex = charIndex | 0; release || somewhatImplemented("public flash.text.TextField::getCharBoundaries"); var fakeCharHeight = this.textHeight, fakeCharWidth = fakeCharHeight * 0.75; return new Rectangle(charIndex * fakeCharWidth, 0, fakeCharWidth, fakeCharHeight); } getCharIndexAtPoint(x: number, y: number): number /*int*/ { x = +x; y = +y; release || notImplemented("public flash.text.TextField::getCharIndexAtPoint"); return; } getFirstCharInParagraph(charIndex: number /*int*/): number /*int*/ { charIndex = charIndex | 0; release || notImplemented("public flash.text.TextField::getFirstCharInParagraph"); return; } getLineIndexAtPoint(x: number, y: number): number /*int*/ { x = +x; y = +y; release || notImplemented("public flash.text.TextField::getLineIndexAtPoint"); return; } getLineIndexOfChar(charIndex: number /*int*/): number /*int*/ { charIndex = charIndex | 0; release || notImplemented("public flash.text.TextField::getLineIndexOfChar"); return; } getLineLength(lineIndex: number /*int*/): number /*int*/ { lineIndex = lineIndex | 0; release || notImplemented("public flash.text.TextField::getLineLength"); return; } getLineMetrics(lineIndex: number /*int*/): TextLineMetrics { lineIndex = lineIndex | 0; if (lineIndex < 0 || lineIndex > this._numLines - 1) { this.sec.throwError('RangeError', Errors.ParamRangeError); } this._ensureLineMetrics(); var lineMetricsData = this._lineMetricsData; lineMetricsData.position = 16 + lineIndex * 20; // The lines left position includes the gutter widths (it should also include the the margin // and indent, which we don't support yet). var x = lineMetricsData.readInt() + this._lineBounds.xMin + 2; var width = lineMetricsData.readInt(); var ascent = lineMetricsData.readInt(); var descent = lineMetricsData.readInt(); var leading = lineMetricsData.readInt(); var height = ascent + descent + leading; return new TextLineMetrics(x, width, height, ascent, descent, leading); } getLineOffset(lineIndex: number /*int*/): number /*int*/ { lineIndex = lineIndex | 0; var lines = this._textContent.plainText.split('\r'); if (lineIndex < 0 || lineIndex >= lines.length) { this.sec.throwError('RangeError', Errors.ParamRangeError); } var offset = 0; for (var i = 0; i < lineIndex; i++) { offset += lines[i].length + 1; // Length + `\r` } // TODO: I've tried modifying the width of the text field so that lines wrap, but this doesn't seem // to have any effect on how line offsets are computed. I'm leaving in the |somewhatImplemented| call // since this is not fully tested. release || release || somewhatImplemented("public flash.text.TextField::getLineOffset"); return offset; } getLineText(lineIndex: number /*int*/): string { lineIndex = lineIndex | 0; var lines = this._textContent.plainText.split('\r'); if (lineIndex < 0 || lineIndex >= lines.length) { this.sec.throwError('RangeError', Errors.ParamRangeError); } return lines[lineIndex]; } getParagraphLength(charIndex: number /*int*/): number /*int*/ { charIndex = charIndex | 0; release || notImplemented("public flash.text.TextField::getParagraphLength"); return; } /** * Returns a TextFormat object that contains the intersection of formatting information for the * range of text between |beginIndex| and |endIndex|. */ getTextFormat(beginIndex: number /*int*/ = -1, endIndex: number /*int*/ = -1): TextFormat { beginIndex = beginIndex | 0; endIndex = endIndex | 0; var plainText = this._textContent.plainText; var maxIndex = plainText.length; if (beginIndex < 0) { beginIndex = 0; if (endIndex < 0) { endIndex = maxIndex; } } else { if (endIndex < 0) { endIndex = beginIndex + 1; } } if (endIndex <= beginIndex || endIndex > maxIndex) { this.sec.throwError('RangeError', Errors.ParamRangeError); } var format: TextFormat; var textRuns = this._textContent.textRuns; for (var i = 0; i < textRuns.length; i++) { var run = textRuns[i]; if (run.intersects(beginIndex, endIndex)) { if (format) { format.intersect(run.textFormat); } else { format = run.textFormat.clone(); } } } return format; } getTextRuns(beginIndex: number /*int*/ = 0, endIndex: number /*int*/ = 2147483647): ASArray { var textRuns = this._textContent.textRuns; var result = []; for (var i = 0; i < textRuns.length; i++) { var textRun = textRuns[i]; if (textRun.beginIndex >= beginIndex && textRun.endIndex <= endIndex) { result.push(textRun.clone()); } } return this.sec.createArrayUnsafe(result); } getRawText(): string { release || notImplemented("public flash.text.TextField::getRawText"); return; } replaceSelectedText(value: string): void { value = "" + value; this.replaceText(this._selectionBeginIndex, this._selectionEndIndex, value); } replaceText(beginIndex: number /*int*/, endIndex: number /*int*/, newText: string): void { beginIndex = beginIndex | 0; endIndex = endIndex | 0; newText = "" + newText; if (beginIndex < 0 || endIndex < 0) { return; } this._textContent.replaceText(beginIndex, endIndex, newText); this._invalidateContent(); this._ensureLineMetrics(); } setSelection(beginIndex: number /*int*/, endIndex: number /*int*/): void { this._selectionBeginIndex = beginIndex | 0; this._selectionEndIndex = endIndex | 0; } setTextFormat(format: TextFormat, beginIndex: number /*int*/ = -1, endIndex: number /*int*/ = -1): void { format = format; beginIndex = beginIndex | 0; endIndex = endIndex | 0; var plainText = this._textContent.plainText; var maxIndex = plainText.length; if (beginIndex < 0) { beginIndex = 0; if (endIndex < 0) { endIndex = maxIndex; } } else { if (endIndex < 0) { endIndex = beginIndex + 1; } } if (beginIndex > maxIndex || endIndex > maxIndex) { this.sec.throwError('RangeError', Errors.ParamRangeError); } if (endIndex <= beginIndex) { return; } var subText = plainText.substring(beginIndex, endIndex); this._textContent.replaceText(beginIndex, endIndex, subText, format); this._invalidateContent(); this._ensureLineMetrics(); } getImageReference(id: string): DisplayObject { //id = "" + id; release || notImplemented("public flash.text.TextField::getImageReference"); return; } } export class TextSymbol extends DisplaySymbol { color: number = 0; size: number = 0; face: string = ""; bold: boolean = false; italic: boolean = false; align: string = TextFormatAlign.LEFT; leftMargin: number = 0; rightMargin: number = 0; indent: number = 0; leading: number = 0; multiline: boolean = false; wordWrap: boolean = false; embedFonts: boolean = false; selectable: boolean = true; border: boolean = false; initialText: string = ""; html: boolean = false; displayAsPassword: boolean = false; type: string = TextFieldType.DYNAMIC; maxChars: number = 0; autoSize: string = TextFieldAutoSize.NONE; variableName: string = null; textContent: any/*TextContent*/ = null; constructor(data: SymbolData, sec: ISecurityDomain) { super(data, TextField.axClass, true); } static FromTextData(data: any, loaderInfo: LoaderInfo): TextSymbol { var sec = loaderInfo.sec; var symbol = new TextSymbol(data, sec); symbol._setBoundsFromData(data); var tag = data.tag; if (data.static) { symbol.dynamic = false; symbol.symbolClass = StaticText.axClass; if (tag.initialText) { console.log("80pro todo: TextContent"); /* var textContent = new TextContent(sec); textContent.bounds = symbol.lineBounds; textContent.parseHtml(tag.initialText, null, false); textContent.matrix = new Matrix(); textContent.matrix.copyFromUntyped(data.matrix); textContent.coords = data.coords; symbol.textContent = textContent;*/ } } if (tag.flags & TextFlags.HasColor) { symbol.color = tag.color >>> 8; } if (tag.flags & TextFlags.HasFont) { symbol.size = tag.fontHeight; // Requesting the font symbol guarantees that it's loaded and initialized. var fontSymbol = loaderInfo.getSymbolById(tag.fontId); if (fontSymbol) { symbol.face = tag.flags & TextFlags.UseOutlines ? fontSymbol.name : 'swffont' + fontSymbol.syncId; symbol.bold = fontSymbol.bold; symbol.italic = fontSymbol.italic; } else { warning("Font " + tag.fontId + " is not defined."); } } if (tag.flags & TextFlags.HasLayout) { symbol.align = TextFormatAlign.fromNumber(tag.align); symbol.leftMargin = tag.leftMargin; symbol.rightMargin = tag.rightMargin; symbol.indent = tag.indent; symbol.leading = tag.leading; } symbol.multiline = !!(tag.flags & TextFlags.Multiline); symbol.wordWrap = !!(tag.flags & TextFlags.WordWrap); symbol.embedFonts = !!(tag.flags & TextFlags.UseOutlines); symbol.selectable = !(tag.flags & TextFlags.NoSelect); symbol.border = !!(tag.flags & TextFlags.Border); if (tag.flags & TextFlags.HasText) { symbol.initialText = tag.initialText; } symbol.html = !!(tag.flags & TextFlags.Html); symbol.displayAsPassword = !!(tag.flags & TextFlags.Password); symbol.type = tag.flags & TextFlags.ReadOnly ? TextFieldType.DYNAMIC : TextFieldType.INPUT; if (tag.flags & TextFlags.HasMaxLength) { symbol.maxChars = tag.maxLength; } symbol.autoSize = tag.flags & TextFlags.AutoSize ? TextFieldAutoSize.LEFT : TextFieldAutoSize.NONE; symbol.variableName = tag.variableName; return symbol; } /** * Turns raw DefineLabel tag data into an object that's consumable as a text symbol and then * passes that into `FromTextData`, returning the resulting TextSymbol. * * This has to be done outside the SWF parser because it relies on any used fonts being * available as symbols, which isn't the case in the SWF parser. */ static FromLabelData(data: any, loaderInfo: LoaderInfo): TextSymbol { var bounds = data.fillBounds; var records: TextRecord[] = data.records; var coords = data.coords = []; var htmlText = ''; var size = 12; var face = 'Times Roman'; var bold = false; var italic = false; var color = 0; var x = 0; var y = 0; var codes: number[]; for (var i = 0; i < records.length; i++) { var record = records[i]; if (record.flags & TextRecordFlags.HasFont) { var fontSymbol = loaderInfo.getSymbolById(record.fontId); if (fontSymbol) { codes = fontSymbol.codes; size = record.fontHeight; if (!fontSymbol.originalSize) { size /= 20; } face = fontSymbol.metrics ? 'swffont' + fontSymbol.syncId : fontSymbol.name; bold = fontSymbol.bold; italic = fontSymbol.italic; } else { warning('Label ' + data.id + 'refers to undefined font symbol ' + record.fontId); } } if (record.flags & TextRecordFlags.HasColor) { color = record.color >>> 8; } if (record.flags & TextRecordFlags.HasMoveX) { x = record.moveX; } if (record.flags & TextRecordFlags.HasMoveY) { y = record.moveY; } var text = ''; var entries = record.entries; var j = 0; var entry; while ((entry = entries[j++])) { var code = codes[entry.glyphIndex]; release || assert(code, 'undefined label glyph'); var char = String.fromCharCode(code); text += charEscapeMap[char] || char; coords.push(x, y); x += entry.advance; } if (italic) { text = '' + text + ''; } if (bold) { text = '' + text + ''; } htmlText += '' + text + ''; } data.tag.initialText = htmlText; return TextSymbol.FromTextData(data, loaderInfo); } } var charEscapeMap = {'<': '<', '>': '>', '&' : '&'};