blob: e6f336ee250fcf934e5d48221161e4d9e4c3f7b1 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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.
//
////////////////////////////////////////////////////////////////////////////////
package helpers
{
import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TextEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.StyleSheet;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.text.TextLineMetrics;
import flash.text.engine.ElementFormat;
import flash.text.engine.FontDescription;
import flash.text.engine.FontLookup;
import flash.text.engine.FontMetrics;
import flash.text.engine.FontPosture;
import flash.text.engine.FontWeight;
import flash.text.engine.Kerning;
import flash.text.engine.LineJustification;
import flash.text.engine.SpaceJustifier;
import flash.text.engine.TextBlock;
import flash.text.engine.TextElement;
import flash.text.engine.TextLine;
import flashx.textLayout.compose.ISWFContext;
import flashx.textLayout.compose.TextLineRecycler;
import flashx.textLayout.container.TextContainerManager;
import flashx.textLayout.conversion.ConversionType;
import flashx.textLayout.conversion.ITextExporter;
import flashx.textLayout.conversion.ITextImporter;
import flashx.textLayout.conversion.TextConverter;
import flashx.textLayout.edit.EditingMode;
import flashx.textLayout.elements.Configuration;
import flashx.textLayout.elements.LinkElement;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.events.FlowElementMouseEvent;
import flashx.textLayout.events.StatusChangeEvent;
import flashx.textLayout.factory.TextFlowTextLineFactory;
import flashx.textLayout.formats.ITextLayoutFormat;
import flashx.textLayout.formats.LeadingModel;
import flashx.textLayout.formats.LineBreak;
import flashx.textLayout.formats.TextDecoration;
import flashx.textLayout.formats.TextLayoutFormat;
import mx.core.FTETextField;
import mx.core.FlexGlobals;
import mx.core.IFlexModuleFactory;
import mx.core.IFontContextComponent;
import mx.core.mx_internal;
use namespace mx_internal;
use namespace mx_internal;
/**
* FTETextField is a Sprite which displays text by using the new
* Flash Text Engine to implement the old TextField API.
*
* @see flash.text.TextField
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public class FTETextField41 extends Sprite
{
// Current slot count: 21
// (1 for every type except 2 for Number)
//--------------------------------------------------------------------------
//
// Class initialization
//
//--------------------------------------------------------------------------
/**
* @private
*/
private static function initClass():void
{
var format:TextLayoutFormat;
var config:Configuration;
// Create an importer for plain text.
plainTextImporter =
TextConverter.getImporter(TextConverter.PLAIN_TEXT_FORMAT);
// Create an exporter for plain text.
plainTextExporter =
TextConverter.getExporter(TextConverter.PLAIN_TEXT_FORMAT);
// Create an importer for TEXT_FIELD_HTML_FORMAT that collapses whitespace.
// Note: We have to make a copy of the textFlowInitialFormat,
// which has various formats set to "inherit",
// and then modify it and set it back.
config = new Configuration();
format = new TextLayoutFormat(config.textFlowInitialFormat);
format.whiteSpaceCollapse = "collapse";
config.textFlowInitialFormat = format;
collapsingHTMLImporter =
TextConverter.getImporter(TextConverter.TEXT_FIELD_HTML_FORMAT, config);
collapsingHTMLImporter.throwOnError = false;
// Create an importer for TEXT_FIELD_HTML_FORMAT that preserves whitespace.
// Note: We have to make a copy of the textFlowInitialFormat,
// which has various formats set to "inherit",
// and then modify it and set it back.
config = new Configuration();
format = new TextLayoutFormat(config.textFlowInitialFormat);
format.whiteSpaceCollapse = "preserve";
config.textFlowInitialFormat = format;
preservingHTMLImporter =
TextConverter.getImporter(TextConverter.TEXT_FIELD_HTML_FORMAT, config);
preservingHTMLImporter.throwOnError = false;
// Create an exporter for TEXT_FIELD_HTML_FORMAT.
htmlExporter =
TextConverter.getExporter(TextConverter.TEXT_FIELD_HTML_FORMAT);
if ("recreateTextLine" in staticTextBlock)
recreateTextLine = staticTextBlock["recreateTextLine"];
}
initClass();
//--------------------------------------------------------------------------
//
// Class constants
//
//--------------------------------------------------------------------------
/**
* @private
* TextField has fixed 2-pixel padding.
*/
mx_internal static const PADDING_LEFT:Number = 2;
mx_internal static const PADDING_TOP:Number = 2;
mx_internal static const PADDING_RIGHT:Number = 2;
mx_internal static const PADDING_BOTTOM:Number = 2;
/**
* @private
* This regular expression is used to replace LF with CR
* when the text property is set.
*/
private static const ALL_LINEFEEDS:RegExp = /\n/g;
/**
* @private
* Masks for bits inside the 'flags' var
* which store the state of Boolean TextField properties.
*/
private static const FLAG_BACKGROUND:uint = 1 << 0;
private static const FLAG_BORDER:uint = 1 << 1;
private static const FLAG_CONDENSE_WHITE:uint = 1 << 2;
private static const FLAG_EMBED_FONTS:uint = 1 << 3;
private static const FLAG_MULTILINE:uint = 1 << 4;
private static const FLAG_WORD_WRAP:uint = 1 << 5;
/**
* @private
* Masks for bits inside the 'flags' var
* which control what work validateNow() needs to do.
*/
private static const FLAG_TEXT_SET:uint = 1 << 6;
private static const FLAG_HTML_TEXT_SET:uint = 1 << 7;
private static const FLAG_TEXT_LINES_INVALID:uint = 1 << 8;
private static const FLAG_GRAPHICS_INVALID:uint = 1 << 9;
/**
* @private
* Masks for bits inside the 'flags' var
* tracking misc boolean variables.
*/
private static const FLAG_EFFECTIVE_CONDENSE_WHITE:uint = 1 << 10;
private static const FLAG_VALIDATE_IN_PROGRESS:uint = 1 << 11;
private static const FLAG_HAS_SCROLL_RECT:uint = 1 << 12;
// TODO (gosmith): Does TextField maintain
// an internal vs. external concept of scrollRect?
/**
* @private
*/
private static const ALL_INVALIDATION_FLAGS:uint =
FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID;
/**
* @private
* If htmlText is set, composeHtmlText is called each time the text lines
* are invalidated. The setters for many of the properties invalidate
* the text lines. So although _htmlText is set to null, if there is no
* styleSheet, to indicate to the htmlText getter that it needs to import
* the html from the textFlow, we need the orginal htmlText for the cases
* where we need to regenerate the html text lines.
*/
private var explicitHTMLText:String = null;
//--------------------------------------------------------------------------
//
// Class variables
//
//--------------------------------------------------------------------------
/**
* @private
* Used for initializing _defaultTextFormat.
*/
private static var textField:TextField = new TextField();
/**
* @private
*/
private static var plainTextImporter:ITextImporter;
/**
* @private
*/
private static var plainTextExporter:ITextExporter;
/**
* @private
*/
private static var collapsingHTMLImporter:ITextImporter;
/**
* @private
*/
private static var preservingHTMLImporter:ITextImporter;
/**
* @private
*/
private static var htmlExporter:ITextExporter;
/**
* @private
*/
private static var factory:TextFlowTextLineFactory =
new TextFlowTextLineFactory();
// We can re-use single instances of a few FTE classes over and over,
// since they just serve as a factory for the TextLines that we care about.
/**
* @private
*/
private static var staticTextBlock:TextBlock = new TextBlock();
/**
* @private
*/
private static var staticTextElement:TextElement = new TextElement();
/**
* @private
*/
private static var staticSpaceJustifier:SpaceJustifier =
new SpaceJustifier();
/**
* @private
* A reference to the recreateTextLine() method in staticTextBlock,
* if it exists. This method was added in player 10.1.
* It allows better performance by making it possible to reuse
* existing TextLines instead of having to create new ones.
*/
private static var recreateTextLine:Function;
/**
* @private
* This is the max textLine.x + textLine.textWidth of all the composed
* lines. It is used to determine whether the text must be clipped.
*/
private var clipWidth:Number;
//--------------------------------------------------------------------------
//
// Class methods
//
//--------------------------------------------------------------------------
/**
* @private
*/
private static function rint(x:Number):Number
{
var i:Number = Math.round(x);
if (i - 0.5 == x && i & 1)
--i;
return i;
}
/**
* @private
*/
private static function cloneTextFormat(
textFormat:TextFormat):TextFormat
{
var newTextFormat:TextFormat = new TextFormat(
textFormat.font, textFormat.size, textFormat.color,
textFormat.bold, textFormat.italic, textFormat.underline,
textFormat.url, textFormat.target, textFormat.align,
textFormat.leftMargin, textFormat.rightMargin, textFormat.indent,
textFormat.leading);
newTextFormat.blockIndent = textFormat.blockIndent;
newTextFormat.bullet = textFormat.bullet;
newTextFormat.kerning = textFormat.kerning;
newTextFormat.letterSpacing = textFormat.letterSpacing;
newTextFormat.tabStops = textFormat.tabStops;
return newTextFormat;
}
/**
* @private
*/
private static function applyTextFormat(src:TextFormat, dst:TextFormat):void
{
if (src.align != null)
dst.align = src.align;
if (src.blockIndent != null)
dst.blockIndent = src.blockIndent;
if (src.bold != null)
dst.bold = src.bold;
if (src.bullet != null)
dst.bullet = src.bullet;
if (src.color != null)
dst.color = src.color;
if (src.font != null)
dst.font = src.font;
if (src.indent != null)
dst.indent = src.indent;
if (src.italic != null)
dst.italic = src.italic;
if (src.kerning != null)
dst.kerning != src.kerning;
if (src.leading != null)
dst.leading = src.leading;
if (src.leftMargin != null)
dst.leftMargin = src.leftMargin;
if (src.letterSpacing != null)
dst.letterSpacing = src.letterSpacing;
if (src.rightMargin != null)
dst.rightMargin = src.rightMargin;
if (src.size != null)
dst.size = src.size;
if (src.tabStops != null)
dst.tabStops = src.tabStops;
if (src.target != null)
dst.target = src.target;
if (src.underline != null)
dst.underline = src.underline;
if (src.url != null)
dst.url = src.url;
}
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function FTETextField41()
{
super();
// The mouse should not be aware of the TextLines.
// Otherwise, FTETextField will dispatch mouseOver and mouseOut
// events over each line, thich TextField doesn't do.
mouseChildren = false;
// Use a static TextField to initialize the defaultTextFormat.
// This should be faster than creating a TextFormat object
// and filling it out.
// It will also take care of setting the 'font' field,
// which is platform-dependent.
_defaultTextFormat = textField.defaultTextFormat;
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
* Apps are likely to create thousands of instances of FTETextField,
* so in order to minimize memory usage we store flags as 1 bit
* inside a uint instead of making each one a 4-byte Boolean var.
*/
private var flags:uint = 0;
/**
* @private
* When we render the text using FTE,
* this object represents the formatting for FTE.
* Every time the defaultTextFormat is set,
* this object is released because it is invalid.
* It is regenerated just in time to render the text.
*/
private var elementFormat:ElementFormat;
/**
* @private
* When we render the htmlText using TLF,
* this object represents the formatting for TLF.
* Every time the defaultTextFormat is set,
* this object is released because it is invalid.
* It is regenerated just in time to render the htmlText.
*/
private var hostFormat:ITextLayoutFormat;
/**
* @private
* When we render the htmlText using TLF,
* this object represents the rich text to be displayed.
* It is created by using TLF's HTML importer to import the htmlText.
*/
private var textFlow:TextFlow;
/**
* @private
* When we render the htmlText using TLF,
* this object composes the textFlow
* (with the hostFormat applied to it)
* to create TextLines in this Sprite.
*/
private var textContainerManager:TextContainerManager;
//--------------------------------------------------------------------------
//
// Overridden properties: DisplayObject
//
//--------------------------------------------------------------------------
//----------------------------------
// height
//----------------------------------
/**
* @private
*/
private var _height:Number = 100;
/**
* @private
*/
override public function get height():Number
{
// If we're autosizing, _height may be invalid.
// For example, the 'text' may have been set
// but the TextLines for that text haven't
// been created yet.
if (autoSize != TextFieldAutoSize.NONE)
validateNow();
return _height;
}
/**
* @private
*/
override public function set height(value:Number):void
{
// TextField ignores NaN and negative values.
if (isNaN(value) || value < 0)
return;
if (value == _height)
return;
_height = value;
// The TextLines may need to be recreated
// and the border and background may need to be redrawn.
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// scrollRect
//----------------------------------
/*
* Workaround for a Flash Player problem.
* Don't read the <code>scrollRect</code> property if its value has not been set,
* because this will cause a large memory allocation.
* And ignore attempts to reset the scrollRect property to null
* (its default value) if we've never set it.
*/
/**
* @private
*/
override public function get scrollRect():Rectangle
{
return testFlag(FLAG_HAS_SCROLL_RECT) ? super.scrollRect : null;
}
/**
* @private
*/
override public function set scrollRect(value:Rectangle):void
{
if (!testFlag(FLAG_HAS_SCROLL_RECT) && !value)
return;
setFlag(FLAG_HAS_SCROLL_RECT);
super.scrollRect = value;
}
//----------------------------------
// width
//----------------------------------
/**
* @private
*/
private var _width:Number = 100;
/**
* @private
*/
override public function get width():Number
{
// If we're autosizing, _width may be invalid.
// For example, the 'text' may have been set
// but the TextLines for that text haven't
// been created yet.
if (autoSize != TextFieldAutoSize.NONE)
validateNow();
return _width;
}
/**
* @private
*/
override public function set width(value:Number):void
{
// TextField ignores NaN and negative values.
if (isNaN(value) || value < 0)
return;
if (value == _width)
return;
_width = value;
// The TextLines may need to be recreated
// and the border and background may need to be redrawn.
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//--------------------------------------------------------------------------
//
// Properties: TextField
//
//--------------------------------------------------------------------------
//----------------------------------
// alwaysShowSelection
//----------------------------------
/**
* This property is not implemented in FTETextField
* because FTETextField does not support selection.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#alwaysShowSelection
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get alwaysShowSelection():Boolean
{
throw new Error(notImplemented("alwaysShowSelection"));
}
/**
* @private
*/
public function set alwaysShowSelection(value:Boolean):void
{
throw new Error(notImplemented("alwaysShowSelection"));
}
//----------------------------------
// antiAliasType
//----------------------------------
/**
* This property has no effect in FTETextField
* because FTE uses a newer font renderer than TextField.
* Getting it will always return <code>null</code>
* and setting it will do nothing.
*
* @see flash.text.TextField#antiAliasType
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get antiAliasType():String
{
return null;
}
/**
* @private
*/
public function set antiAliasType(value:String):void
{
}
//----------------------------------
// autoSize
//----------------------------------
/**
* @private
*/
private var _autoSize:String = TextFieldAutoSize.NONE;
/**
* @copy flash.text.TextField#autoSize
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get autoSize():String
{
return _autoSize;
}
/**
* @private
*/
public function set autoSize(value:String):void
{
// TextField throws this RTE when invalid values are set.
if (value != TextFieldAutoSize.NONE &&
value != TextFieldAutoSize.LEFT &&
value != TextFieldAutoSize.CENTER &&
value != TextFieldAutoSize.RIGHT)
{
var message:String = getErrorMessage("badParameter", "autoSize");
throw new ArgumentError(message);
}
if (value == autoSize)
return;
_autoSize = value;
// The TextLines may need to be recreated
// and the border and background may need to be redrawn.
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// background
//----------------------------------
/**
* @copy flash.text.TextField#background
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get background():Boolean
{
return testFlag(FLAG_BACKGROUND);
}
/**
* @private
*/
public function set background(value:Boolean):void
{
if (value == background)
return;
setFlagToValue(FLAG_BACKGROUND, value);
// The border and background need to be redrawn.
setFlag(FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// backgroundColor
//----------------------------------
/**
* @private
*/
private var _backgroundColor:uint = 0xFFFFFF;
/**
* @copy flash.text.TextField#backgroundColor
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get backgroundColor():uint
{
return _backgroundColor;
}
/**
* @private
*/
public function set backgroundColor(value:uint):void
{
if (value == _backgroundColor)
return;
_backgroundColor = value;
// The border and background need to be redrawn.
setFlag(FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// border
//----------------------------------
/**
* @copy flash.text.TextField#border
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get border():Boolean
{
return testFlag(FLAG_BORDER);
}
/**
* @private
*/
public function set border(value:Boolean):void
{
if (value == border)
return;
setFlagToValue(FLAG_BORDER,value);
// The border and background need to be redrawn.
setFlag(FLAG_GRAPHICS_INVALID);
// The border increases the width and height by 1 pixel, so if there
// is a scrollRect, it has to be modified as well.
if (testFlag(FLAG_TEXT_SET | FLAG_HTML_TEXT_SET))
setFlag(FLAG_TEXT_LINES_INVALID);
invalidate();
}
//----------------------------------
// borderColor
//----------------------------------
/**
* @private
*/
private var _borderColor:uint = 0x000000;
/**
* @copy flash.text.TextField#borderColor
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get borderColor():uint
{
return _borderColor;
}
/**
* @private
*/
public function set borderColor(value:uint):void
{
if (value == _borderColor)
return;
_borderColor = value;
// The border and background need to be redrawn.
setFlag(FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// bottomScrollV
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support scrolling.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#bottomScrollV
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get bottomScrollV():int
{
throw new Error(notImplemented("bottomScrollV"));
}
//----------------------------------
// caretIndex
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support editing.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#caretIndex
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get caretIndex():int
{
throw new Error(notImplemented("caretIndex"));
}
//----------------------------------
// condenseWhite
//----------------------------------
/**
* @copy flash.text.TextField#condenseWhite
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get condenseWhite():Boolean
{
return testFlag(FLAG_CONDENSE_WHITE);
}
/**
* @private
*/
public function set condenseWhite(value:Boolean):void
{
setFlagToValue(FLAG_CONDENSE_WHITE, value);
// Note: There is nothing else to do immediately;
// the new value doesn't have any effect
// until 'htmlText' is set later.
}
//----------------------------------
// defaultTextFormat
//----------------------------------
/**
* @private
* Storage for the defaultTextFormat property.
* This variable is initialized in the constructor
* to a TextFormat instance filled with default values.
* The setter applies non-null incoming formats
* to the object stored here.
* The getter returns a copy of the object stored here.
* Note that No field of this TextFormat will ever be null.
*/
mx_internal var _defaultTextFormat:TextFormat;
/**
* @copy flash.text.TextField#defaultTextFormat
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get defaultTextFormat():TextFormat
{
// TextField returns a new TextFormat instance each time
// you access defaultTextFormat; the proof is that
// textField.defaultTextFormat != textField.defaultTextFormat
// is true.
return cloneTextFormat(_defaultTextFormat);
}
/**
* @private
*/
public function set defaultTextFormat(value:TextFormat):void
{
// TextField throws this RTE if a null value is set.
if (!value)
{
var message:String = getErrorMessage("nullParameter", "format");
throw new TypeError(message);
}
// Apply non-null formats in the incoming TextFormat
// to the defaultTextFormat.
applyTextFormat(value, _defaultTextFormat);
// These FTE and TLF formatting objects are now invalid
// and must be recreated when needed.
elementFormat = null;
hostFormat = null;
// Note: Setting this does NOT cause already-rendered text
// to change its format.
// If establishes the formatting for text set or added later.
}
//----------------------------------
// displayAsPassword
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support editing.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#displayAsPassword
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get displayAsPassword():Boolean
{
throw new Error(notImplemented("displayAsPassword"));
}
/**
* @private
*/
public function set displayAsPassword(value:Boolean):void
{
throw new Error(notImplemented("displayAsPassword"));
}
//----------------------------------
// embedFonts
//----------------------------------
/**
* @copy flash.text.TextField#embedFonts
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get embedFonts():Boolean
{
return testFlag(FLAG_EMBED_FONTS);
}
/**
* @private
*/
public function set embedFonts(value:Boolean):void
{
if (value == embedFonts)
return;
setFlagToValue(FLAG_EMBED_FONTS, value);
// These FTE and TLF formatting objects are now invalid
// and must be recreated when needed.
elementFormat = null;
hostFormat = null;
// The TextLines may need to be recreated
// and the border and background may need to be redrawn.
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// gridFitType
//----------------------------------
/**
* This property has no effect in FTETextField
* because FTE uses a newer font renderer than TextField.
* Getting it will always return <code>null</code>
* and setting it will do nothing.
*
* @see flash.text.TextField#gridFitType
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get gridFitType():String
{
return null;
}
/**
* @private
*/
public function set gridFitType(value:String):void
{
}
//----------------------------------
// htmlText
//----------------------------------
/**
* @private
*/
private var _htmlText:String = null;
/**
* @copy flash.text.TextField#htmlText
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get htmlText():String
{
// When you set the htmlText and then get it,
// what you get is not necessarily what you set.
// The easiest way to handle this is to make sure
// that the text is composed (which will null out _htmlText
// if there is no styleSheet) and then execute the code
// below to export HTML from the TextFlow.
validateNow();
// When 'text' is set, _htmlText is nulled out
// to indicate that it is invalid
// and must be recalculated.
if (_htmlText == null)
{
// We can optimize the default case
// that there is no text or hmtlText.
if (_text == "")
{
_htmlText = "";
}
else
{
// Import the plain text into a TextFlow,
// and then export the TextFlow into HTML.
if (!textFlow)
textFlow = plainTextImporter.importToFlow(_text);
_htmlText = String(htmlExporter.export(
textFlow, ConversionType.STRING_TYPE));
}
}
return _htmlText;
}
/**
* @private
*/
public function set htmlText(value:String):void
{
// TextField throws this RTE if a null value is set.
// It seems like this should say
// "Parameter htmlText must be non-null",
// but that's not what TextField does.
if (value == null)
{
var message:String = getErrorMessage("nullParameter", "text");
throw new TypeError(message);
}
// Note: We don't return early if value == _htmlText
// because the defaultTextFormat may have changed
// in which case we need to recompose.
// Remember the value of condenseWhite at the time
// that htmlText is set, because it could be changed
// before the TextLines are rendered.
setFlagToValue(FLAG_EFFECTIVE_CONDENSE_WHITE,
testFlag(FLAG_CONDENSE_WHITE));
_htmlText = value;
explicitHTMLText = value;
// _text is now invalid and will get regenerated on demand.
_text = null;
clearFlag(FLAG_TEXT_SET);
setFlag(FLAG_HTML_TEXT_SET |
FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
// NOTE: With hmtlText, what you set is NOT what you get.
// You can set incomplete (or no) markup
// and get back complete markup.
}
//----------------------------------
// length
//----------------------------------
/**
* @copy flash.text.TextField#length
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get length():int
{
return text.length;
}
//----------------------------------
// maxChars
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support editing.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#maxChars
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get maxChars():int
{
throw new Error(notImplemented("maxChars"));
}
/**
* @private
*/
public function set maxChars(value:int):void
{
throw new Error(notImplemented("maxChars"));
}
//----------------------------------
// maxScrollH
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support scrolling.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#maxScrollH
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get maxScrollH():int
{
throw new Error(notImplemented("maxScrollH"));
}
//----------------------------------
// maxScrollV
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support scrolling.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#maxScrollV
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get maxScrollV():int
{
throw new Error(notImplemented("maxScrollV"));
}
//----------------------------------
// mouseWheelEnabled
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support scrolling.
* Getting it will always return <code>false</code>
* and setting it will do nothing.
*
* @see flash.text.TextField#mouseWheelEnabled
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get mouseWheelEnabled():Boolean
{
return false;
}
/**
* @private
*/
public function set mouseWheelEnabled(value:Boolean):void
{
}
//----------------------------------
// multiline
//----------------------------------
/**
* This property has no effect in FTETextField
* because FTETextField does not support editing.
* However, you can get and set it.
*
* @see flash.text.TextField#multiline
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get multiline():Boolean
{
return testFlag(FLAG_MULTILINE);
}
/**
* @private
*/
public function set multiline(value:Boolean):void
{
setFlagToValue(FLAG_MULTILINE, value);
}
//----------------------------------
// numLines
//----------------------------------
/**
* @copy flash.text.TextField#numLines
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get numLines():int
{
validateNow();
// All the of the children of this Sprite are TextLines,
// so the number of lines is the number of children.
// TextContainerManager can create Shapes as well,
// but only when using TLF's backgroundColor and backgroundAlpha
// formatting on spans, which FTETextField doesn't use.
return numChildren;
}
//----------------------------------
// restrict
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support scrolling.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#restrict
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get restrict():String
{
throw new Error(notImplemented("restrict"));
}
/**
* @private
*/
public function set restrict(value:String):void
{
throw new Error(notImplemented("restrict"));
}
//----------------------------------
// scrollH
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support scrolling.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#scrollH
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get scrollH():int
{
throw new Error(notImplemented("scrollH"));
}
/**
* @private
*/
public function set scrollH(value:int):void
{
throw new Error(notImplemented("scrollH"));
}
//----------------------------------
// scrollV
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support scrolling.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#scrollV
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get scrollV():int
{
throw new Error(notImplemented("scrollV"));
}
/**
* @private
*/
public function set scrollV(value:int):void
{
throw new Error(notImplemented("scrollV"));
}
//----------------------------------
// selectable
//----------------------------------
/**
* Setting this property has no effect in FTETextField
* because FTETextField does not support selection.
* If you get it, it will always be <code>false</code>.
*
* @see flash.text.TextField#selectable
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get selectable():Boolean
{
return false;
}
/**
* @private
*/
public function set selectable(value:Boolean):void
{
}
//----------------------------------
// selectionBeginIndex
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support selection.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#selectionBeginIndex
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get selectionBeginIndex():int
{
throw new Error(notImplemented("selectionBeginIndex"));
}
//----------------------------------
// selectionEndIndex
//----------------------------------
/**
* This property has not been implemented in FTETextField
* because FTETextField does not support selection.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#selectionEndIndex
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get selectionEndIndex():int
{
throw new Error(notImplemented("selectionEndIndex"));
}
//----------------------------------
// sharpness
//----------------------------------
/**
* This property has no effect in FTETextField.
* because FTE uses a newer font renderer than TextField.
* Getting it will always return <code>NaN</code>
* and setting it will do nothing.
*
* @see flash.text.TextField#sharpness
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get sharpness():Number
{
return NaN;
}
/**
* @private
*/
public function set sharpness(value:Number):void
{
}
//----------------------------------
// styleSheet
//----------------------------------
/**
* @private
*/
private var _styleSheet:StyleSheet = null;
/**
* @copy flash.text.TextField#styleSheet
*
* @see flash.text.StyleSheet
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get styleSheet():StyleSheet
{
// Note: TextField does NOT return a copy of the StyleSheet.
return _styleSheet;
}
/**
* @private
*/
public function set styleSheet(value:StyleSheet):void
{
// TextField allows a null value to be set;
// in fact, this is the default.
// Note: We don't return early if value == _styleSheet
// because the same StyleSheet instance could be coming
// in again but might have new values in it.
_styleSheet = value;
if (textFlow && textFlow.formatResolver)
textFlow.formatResolver = null;
// The TextLines may need to be recreated
// and the border and background may need to be redrawn.
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// text
//----------------------------------
/**
* @private
*/
private var _text:String = "";
/**
* @copy flash.text.TextField#text
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get text():String
{
// When 'htmlText' is set, _text is nulled out
// to indicate that it is invalid
// and must be rexported from the TextFlow.
if (_text == null)
{
// If we don't already have a TextFlow,
// create one by importing the htmlText.
if (!textFlow)
textFlow = htmlImporter.importToFlow(_htmlText);
// Export plain text from the TextFlow.
_text = String(plainTextExporter.export(
textFlow, ConversionType.STRING_TYPE));
// Convert the LF characters that TLF exports
// into CR characters.
_text = _text.replace(ALL_LINEFEEDS, "\r");
}
return _text;
}
/**
* @private
*/
public function set text(value:String):void
{
// TextField throws this RTE if a null value is set.
if (value == null)
{
var message:String = getErrorMessage("nullParameter", "text");
throw new TypeError(message);
}
// Note: We don't return early if value == _text
// because the defaultTextFormat may have changed
// in which case we need to recompose.
// TextField turns all LF characters into CR characters,
// including treating the Windows line-ending-sequence
// CR+LF as two CRs.
_text = value.replace(ALL_LINEFEEDS, "\r");
// _htmlText is now invalid and will get regenerated on demand
_htmlText = null;
explicitHTMLText = null;
clearFlag(FLAG_HTML_TEXT_SET);
setFlag(FLAG_TEXT_SET |
FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// textColor
//----------------------------------
/**
* @copy flash.text.TextField#textColor
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get textColor():uint
{
// textColor is not an independent format in TextField;
// getting textColor simply returns the color
// in the defaultTextFormat.
return uint(_defaultTextFormat.color);
}
/**
* @private
* Setting the textColor changes the color in the defaultTextFormat
* and redraws the text in the new color.
*/
public function set textColor(value:uint):void
{
if (value == textColor)
return;
_defaultTextFormat.color = value;
// These FTE and TLF formatting objects are now invalid
// and must be recreated when needed.
elementFormat = null;
hostFormat = null;
setFlag(FLAG_TEXT_LINES_INVALID);
invalidate();
}
//----------------------------------
// textHeight
//----------------------------------
/**
* @private
*/
private var _textHeight:Number = 0;
/**
* @copy flash.text.TextField#textHeight
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get textHeight():Number
{
validateNow();
return _textHeight;
}
//----------------------------------
// textWidth
//----------------------------------
/**
* @private
*/
private var _textWidth:Number = 0;
/**
* @copy flash.text.TextField#textWidth
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get textWidth():Number
{
validateNow();
return _textWidth;
}
//----------------------------------
// thickness
//----------------------------------
/**
* This property has no effect in FTETextField
* because FTE uses a newer font renderer than TextField.
* Getting it will always return <code>NaN</code>
* and setting it will do nothing.
*
* @see flash.text.TextField#thickness
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get thickness():Number
{
return NaN;
}
/**
* @private
*/
public function set thickness(value:Number):void
{
}
//----------------------------------
// type
//----------------------------------
/**
* @copy flash.text.TextField#type
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get type():String
{
return TextFieldType.DYNAMIC;
}
/**
* @private
*/
public function set type(value:String):void
{
var message:String;
// TextField throws this RTE when invalid values are set.
if (value != TextFieldType.DYNAMIC &&
value != TextFieldType.INPUT)
{
message = getErrorMessage("badParameter", "type");
throw new ArgumentError(message);
}
if (value == TextFieldType.INPUT)
{
message = getErrorMessage("unsupportedTypeInFTETextField");
throw new Error(message);
}
}
//----------------------------------
// useRichTextClipboard
//----------------------------------
/**
* This property is not implemented in FTETextField
* because FTETextField does not support selection
* or clipboard operations.
* Accessing it will throw a runtime error.
*
* @see flash.text.TextField#useRichTextClipboard
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get useRichTextClipboard():Boolean
{
throw new Error(notImplemented("useRichTextClipboard"));
}
/**
* @private
*/
public function set useRichTextClipboard(value:Boolean):void
{
throw new Error(notImplemented("useRichTextClipboard"));
}
//----------------------------------
// wordWrap
//----------------------------------
/**
* @copy flash.text.TextField#wordWrap
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get wordWrap():Boolean
{
return testFlag(FLAG_WORD_WRAP);
}
/**
* @private
*/
public function set wordWrap(value:Boolean):void
{
if (value == wordWrap)
return;
setFlagToValue(FLAG_WORD_WRAP, value);
// These FTE and TLF formatting objects are now invalid
// and must be recreated when needed.
elementFormat = null;
hostFormat = null;
// The TextLines may need to be recreated
// and the border and background may need to be redrawn.
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// direction
//----------------------------------
/**
* @private
* Storage for the direction property.
*/
private var _direction:String = "ltr";
/**
* The directionality of the text displayed by the FTETextField.
*
* <p>The allowed values are <code>"ltr"</code> for left-to-right text,
* as in Latin-style scripts,
* and <code>"rtl"</code> for right-to-left text,
* as in Arabic and Hebrew.</p>
*
* <p><strong>Note:</strong> This property does not exist in the
* flash.text.TextField API.</p>
*
* @default "ltr"
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get direction():String
{
return _direction;
}
/**
* @private
*/
public function set direction(value:String):void
{
if (value != "ltr" && value != "rtl")
{
var message:String = getErrorMessage("badParameter", "direction");
throw new ArgumentError(message);
}
if (value == _direction)
return;
_direction = value;
// These FTE and TLF formatting objects are now invalid
// and must be recreated when needed.
elementFormat = null;
hostFormat = null;
// The TextLines may need to be recreated
// and the border and background may need to be redrawn.
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// fontContext
//----------------------------------
/**
* @private
* Storage for the fontContext property.
*/
private var _fontContext:ISWFContext;
/**
* The ISWFContext instance that FTETextField
* uses for creating TextLine objects.
*
* <p>Set this if you need lines to be created in a different
* SWF context than the one containing the TLF code.</p>
*
* <p><strong>Note:</strong> This property does not exist in the
* flash.text.TextField API.</p>
*
* @default null
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function get fontContext():ISWFContext
{
return _fontContext;
}
/**
* @private
*/
public function set fontContext(value:ISWFContext):void
{
// FTETextField allows a null value to be set;
// in fact, this is the default.
if (value == _fontContext)
return;
_fontContext = value;
// The TextLines may need to be recreated
// and the border and background may need to be redrawn.
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//----------------------------------
// locale
//----------------------------------
/**
* @private
* Storage for the locale property.
*/
private var _locale:String = "en";
/**
* The locale of the text displayed by FTETextField.
*
* <p>FTE and TLF use this locale to map Unicode characters
* to font glyphs and to find fallback fonts.</p>
*/
public function get locale():String
{
return _locale;
}
/**
* @private
*/
public function set locale(value:String):void
{
if (value == _locale)
return;
_locale = value;
// These FTE and TLF formatting objects are now invalid
// and must be recreated when needed.
elementFormat = null;
hostFormat = null;
// The TextLines may need to be recreated
// and the border and background may need to be redrawn.
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
//--------------------------------------------------------------------------
//
// Properties: Private helpers
//
//--------------------------------------------------------------------------
//----------------------------------
// htmlImporter
//----------------------------------
/**
* @private
*/
private function get htmlImporter():ITextImporter
{
// Note that which importer we return depends on the value
// of condenseWhite was at the time that htmlText was set,
// not on the current value of condenseWhite,
// since it could change between htmlText being set
// and the TextLines being composed.
return testFlag(FLAG_EFFECTIVE_CONDENSE_WHITE) ?
collapsingHTMLImporter :
preservingHTMLImporter;
}
//--------------------------------------------------------------------------
//
// Methods: TextField
//
//--------------------------------------------------------------------------
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param newText n/a
*
* @see flash.text.TextField#appendText()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function appendText(newText:String):void
{
throw new Error(notImplemented("appendText()"));
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param charIndex n/a
*
* @return n/a
*
* @see flash.text.TextField#getCharBoundaries()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getCharBoundaries(charIndex:int):Rectangle
{
throw new Error(notImplemented("getCharBoundaries()"));
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param x n/a
* @param y n/a
*
* @return n/a
*
* @see flash.text.TextField#getCharIndexAtPoint()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getCharIndexAtPoint(x:Number, y:Number):int
{
throw new Error(notImplemented("getCharIndexAtPoint()"));
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param charIndex n/a
*
* @return n/a
*
* @see flash.text.TextField#getFirstCharInParagraph()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getFirstCharInParagraph(charIndex:int):int
{
throw new Error(notImplemented("getFirstCharInParagraph()"));
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param x n/a
*
* @param y n/a
*
* @return n/a
*
* @see flash.text.TextField#getLineIndexAtPoint()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getLineIndexAtPoint(x:Number, y:Number):int
{
throw new Error(notImplemented("getLineIndexAtPoint()"));
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param charIndex n/a
*
* @return n/a
*
* @see flash.text.TextField#getLineIndexOfChar()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getLineIndexOfChar(charIndex:int):int
{
throw new Error(notImplemented("getLineIndexOfChar()"));
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param lineIndex n/a
*
* @return n/a
*
* @see flash.text.TextField#getLineLength()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getLineLength(lineIndex:int):int
{
throw new Error(notImplemented("getLineLength()"));
}
/**
* @copy flash.text.TextField#getLineMetrics()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getLineMetrics(lineIndex:int):TextLineMetrics
{
validateNow();
// TextField throws this RTE when invalid values are set.
if (lineIndex < 0 || lineIndex >= numChildren)
{
var message:String = getErrorMessage("badIndex");
throw new RangeError(message);
}
// The nth line is the nth child.
var textLine:TextLine = TextLine(getChildAt(lineIndex));
// Convert textLine.x to the global coordinate space. The new point
// x is relative to textLine.x.
var x:Number = Math.round(textLine.localToGlobal(new Point(0, 0)).x);
var width:Number = Math.round(textLine.textWidth);
// TextField computes ascent and descent differently than FTE does.
// Adding FTE's ascent and descent produces
// a reasonable approximation of TextField's ascent.
// TextField's ascent, descent, and leading are always rounded.
// Rounding FTE's ascent and descent separately, then adding,
// produces a "TextField ascent" of 12 + 3 or 15 for Arial 12
// (Flex's default font) on Windows, exactly matching a real
// TextField's ascent in this most-common case.
var ascent:Number = Math.round(textLine.ascent) + Math.round(textLine.descent)
var descent:Number = Math.round(textLine.descent);
var leading:Number = Math.round(Number(_defaultTextFormat.leading));
var height:Number = ascent + descent + leading;
return new TextLineMetrics(x, width, height, ascent, descent, leading);
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param lineIndex n/a
*
* @return n/a
*
* @see flash.text.TextField#getLineOffset()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getLineOffset(lineIndex:int):int
{
throw new Error(notImplemented("getLineOffset()"));
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param lineIndex n/a
*
* @return n/a
*
* @see flash.text.TextField#getLineText()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getLineText(lineIndex:int):String
{
throw new Error(notImplemented("getLineText()"));
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param charIndex n/a
*
* @return n/a
*
* @see flash.text.TextField#getParagraphLength()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getParagraphLength(charIndex:int):int
{
throw new Error(notImplemented("getParagraphLength()"));
}
/**
* This method has been implemented in FTETextField
* to simply return a copy of the <code>defaultTextFormat</code>,
* because FTETextField does not support formatting a range.
*
* @param beginIndex n/a
*
* @param endIndex n/a
*
* @return n/a
*
* @see flash.text.TextField#getTextFormat()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getTextFormat(beginIndex:int = -1,
endIndex:int = -1):TextFormat
{
// TextField returns a new TextFormat instance each time
// you call getTextFormat(); the proof is that
// textField.getTextFormat() != textField.getTextFormat()
// is true.
return cloneTextFormat(_defaultTextFormat);
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param value n/a
*
* @see flash.text.TextField#replaceSelectedText()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function replaceSelectedText(value:String):void
{
throw new Error(notImplemented("replaceSelectedText()"));
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param beginIndex n/a
*
* @param endIndex n/a
*
* @param newText n/a
*
* @see flash.text.TextField#replaceText()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function replaceText(beginIndex:int, endIndex:int,
newText:String):void
{
throw new Error(notImplemented("replaceText()"));
}
/**
* This method has not been implemented in FTETextField
* because FTETextField does not support selection.
* It will throw a runtime error if called.
*
* @param beginIndex n/a
*
* @param endIndex n/a
*
* @see flash.text.TextField#setSelection()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function setSelection(beginIndex:int, endIndex:int):void
{
throw new Error(notImplemented("setSelection()"));
}
/**
* This method has no effect on a FTETextField if <code>beginIndex</code>
* or <code>endIndex</code> does not equal -1
* because FTETextField does not support formatting a range.
*
* @param format n/a
*
* @param beginIndex n/a
*
* @param endIndex n/a
*
* @see flash.text.TextField#setTextFormat()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function setTextFormat(format:TextFormat,
beginIndex:int = -1,
endIndex:int = -1):void
{
if (beginIndex == -1 && endIndex == -1)
{
defaultTextFormat = format;
// The format changed. Some of the attributes such as indent
// and blockIndent require the text to be regenerated.
setFlag(FLAG_TEXT_LINES_INVALID | FLAG_GRAPHICS_INVALID);
validateNow();
}
}
/**
* This method has not been implemented in FTETextField
* because very few components use it in TextField.
* It will throw a runtime error if called.
*
* @param id n/a
*
* @return n/a
*
* @see flash.text.TextField#getImageReference()
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*/
public function getImageReference(id:String):DisplayObject
{
throw new Error(notImplemented("getImageReference()"));
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @private
*/
private function testFlag(mask:uint):Boolean
{
return (flags & mask) != 0;
}
/**
* @private
*/
private function setFlag(mask:uint):void
{
flags |= mask;
}
/**
* @private
*/
private function clearFlag(mask:uint):void
{
flags &= ~mask;
}
/**
* @private
*/
private function setFlagToValue(mask:uint, value:Boolean):void
{
if (value)
flags |= mask;
else
flags &= ~mask;
}
/**
* @private
* This method will cause a 'render' event later,
* in response to which validateNow() will get called.
*/
private function invalidate():void
{
if (stage)
stage.invalidate();
addEventListener(Event.RENDER, renderHandler);
}
/**
* @private
* This method is the workhorse of FTETextField.
* It puts it into a state where all properties are consistent
* with each other and where it is rendering what the properties
* specify.
*/
private function validateNow():void
{
// TODO (gosmith): When do we get recursive validateNow()?
if (!testFlag(ALL_INVALIDATION_FLAGS) ||
testFlag(FLAG_VALIDATE_IN_PROGRESS))
{
return;
}
setFlag(FLAG_VALIDATE_IN_PROGRESS);
if (testFlag(FLAG_TEXT_LINES_INVALID))
{
// Remove the previous TextLines
// (and recycle them, if supported by the player).
removeTextLines();
// Determine the composition width and height.
var compositionWidth:Number = NaN;
var compositionHeight:Number = NaN;
if (_autoSize == TextFieldAutoSize.NONE)
{
compositionWidth = _width;
compositionHeight = _height;
}
else if (wordWrap)
{
compositionWidth = _width;
}
if (testFlag(FLAG_HTML_TEXT_SET))
{
if (!hostFormat)
createHostFormat();
composeHTMLText(compositionWidth, compositionHeight);
}
else
{
if (!elementFormat)
createElementFormat();
composeText(compositionWidth, compositionHeight);
}
var origX:Number = x;
var origWidth:Number = _width;
var origHeight:Number = _height;
if (_autoSize != TextFieldAutoSize.NONE)
{
_height = _textHeight + PADDING_TOP + PADDING_BOTTOM;
if (!wordWrap)
{
_width = _textWidth + PADDING_LEFT + PADDING_RIGHT;
var blockIndent:Number = Number(_defaultTextFormat.blockIndent);
var indent:Number = Number(_defaultTextFormat.indent);
var leftMargin:Number = Number(_defaultTextFormat.leftMargin);
var rightMargin:Number = Number(_defaultTextFormat.rightMargin);
// Factor in indents and margins if the combined total
// is positive.
if (blockIndent + indent + leftMargin > 0)
_width += blockIndent + indent + leftMargin;
// Right margin seems to always be considered but if its
// negative the width can't get smaller than the text width.
_width += rightMargin;
if (rightMargin > 0)
{
clipWidth = _width;
}
else
{
if (_width - PADDING_LEFT - PADDING_RIGHT < _textWidth )
_width = _textWidth + PADDING_LEFT + PADDING_RIGHT;
// force clipping
clipWidth = origWidth + 1;
}
// adjust x for CENTER and RIGHT cases
if (_autoSize == TextFieldAutoSize.RIGHT)
x += origWidth - _width;
else if (_autoSize == TextFieldAutoSize.CENTER)
x += (origWidth - _width) / 2;
}
if (_height != origHeight || _width != origWidth || x != origX)
setFlag(FLAG_GRAPHICS_INVALID);
}
if (clipWidth > origWidth || _textHeight > origHeight)
{
// need to clip
//trace("clip", "_textWidth", _textWidth, "origWidth", origWidth);
var r:Rectangle = scrollRect;
if (!r)
r = new Rectangle();
r.left = 0;
r.top = 0;
r.right = _width;
r.bottom = _height;
// Expand scrollRect by one pixel so the bottom and right
// borders are not cliped. See note below.
if (testFlag(FLAG_GRAPHICS_INVALID) && border)
{
r.width++;
r.height++;
}
scrollRect = r;
}
else
{
// don't need to clip
//trace("don't clip", "_textWidth", _textWidth, "origWidth", origWidth);
scrollRect = null;
}
}
// Draw the border and background last,
// once the width and height are known.
if (testFlag(FLAG_GRAPHICS_INVALID))
{
var g:Graphics = graphics;
g.clear();
// First draw the background, then draw the border.
// This is because TextField actually does something strange --- it expands itselft 1 pixel right and down when drawing a border
// and fill without the stroke with the required stroking path does not match the "background sans border" behavior of TextField.
// Width/Height rounding differences between TextField and FTETextField...
// For width or height of the form E.5 where E is a positive even integer, Flash 10 on Windows seems to
// "round to even", i.e., round the dimension down to E rather than up to E+1. However we currently just
// round consistently up to E+1 using Math.round() here since for now are willing to live with this difference.
var w:Number = rint(_width);
var h:Number = rint(_height);
// Even if no background is requested, we fill the bounds
// with alpha=0 pixels so that mouse events are generated.
g.beginFill(backgroundColor, background ? 1.0 : 0.0);
g.drawRect(0, 0, w, h);
g.endFill();
if (border)
{
g.lineStyle(1, borderColor);
g.drawRect(0.5, 0.5, _width, _height); // TextField actually expands by a pixel down and to the right when it has a border!
}
}
clearFlag(ALL_INVALIDATION_FLAGS | FLAG_VALIDATE_IN_PROGRESS);
}
/**
* @private
*/
private function createElementFormat():void
{
var fontDescription:FontDescription = new FontDescription();
fontDescription.fontLookup = embedFonts ?
FontLookup.EMBEDDED_CFF :
FontLookup.DEVICE;
fontDescription.fontName = _defaultTextFormat.font;
fontDescription.fontPosture = _defaultTextFormat.italic ?
FontPosture.ITALIC :
FontPosture.NORMAL;
fontDescription.fontWeight = _defaultTextFormat.bold ?
FontWeight.BOLD :
FontWeight.NORMAL;
elementFormat = new ElementFormat();
elementFormat.color = uint(_defaultTextFormat.color);
elementFormat.fontDescription = fontDescription;
elementFormat.fontSize = Number(_defaultTextFormat.size);
elementFormat.kerning = _defaultTextFormat.kerning ?
Kerning.AUTO :
Kerning.OFF;
elementFormat.locale = locale;
elementFormat.trackingRight = Number(_defaultTextFormat.letterSpacing);
}
/**
* @private
*/
private function createHostFormat():void
{
hostFormat = new FTETextFieldHostFormat(this);
}
/**
* @private
*/
private function removeTextLines():void
{
var n:int = numChildren;
for (var i:int = 0; i < n; i++)
{
// Repeatedly removing the 0th child is supposed
// to be the fastest way to remove all children.
var textLine:TextLine = TextLine(removeChildAt(0));
// TLF provides a TextLine cache,
// for use with recreateTextLine().
TextLineRecycler.addLineForReuse(textLine);
}
_textWidth = 0;
_textHeight = 0;
clipWidth = 0;
}
/**
* @private
*/
private function composeText(compositionWidth:Number,
compositionHeight:Number):void
{
var innerWidth:Number =
compositionWidth - PADDING_LEFT - PADDING_RIGHT;
var innerHeight:Number =
compositionHeight - PADDING_TOP - PADDING_BOTTOM;
// FTE's emBox's top gives the ascent and its bottom gives the descent.
// TextField computes ascent and descent differently than FTE does.
// Adding FTE's ascent and descent produces
// a reasonable approximation of TextField's ascent.
// TextField's ascent, descent, and leading are always rounded.
// Rounding FTE's ascent and descent separately, then adding,
// produces a "TextField ascent" of 12 + 3 or 15 for Arial 12
// (Flex's default font) on Windows, exactly matching a real
// TextField's ascent in this most-common case.
var emBox:Rectangle = elementFormat.getFontMetrics().emBox;
var ascent:int = Math.round(-emBox.top) + Math.round(emBox.bottom);
var descent:int = Math.round(emBox.bottom);
var leading:Number = Math.round(Number(_defaultTextFormat.leading));
// Break the text into paragraphs at CR characters.
// (Each LF character has already been turned into a CR.)
// We could use split(), but that would create a temporary Array.
var paragraphY:int = 0;
var n:int = text.length;
var i:int = 0;
do
{
var j:int = text.indexOf("\r", i);
if (j == -1)
j = n;
var paragraphText:String = i == 0 && j == n ?
text :
text.substring(i, j);
// Use an FTE TextBlock to compose TextLines
// for one paragraph of the text, keeping track
// of how far down we've composed.
paragraphY = createTextLines(innerWidth, innerHeight,
paragraphText, paragraphY,
ascent, descent);
// TextField puts the same leading between paragraphs
// as between lines in a paragraph.
paragraphY += leading;
i = j + 1;
}
while (j < n);
// At this point, all TextLines have been composed
// and have the correct spacing, but are all left-aligned
// starting at (0, 0).
// This method will adjust their x and y so that they
// are correctly aligned and inset by the left and top padding and
// indent and margins.
alignTextLines(innerWidth);
_textWidth = Math.round(_textWidth);
_textHeight = Math.round(
numChildren * (ascent + descent) +
(numChildren - 1) * Number(_defaultTextFormat.leading));
clipWidth = Math.round(clipWidth);
}
/**
* @private
* Stuffs the specified paragraph text and formatting info into a TextBlock
* and uses it to create as many TextLines as fit into the bounds.
* Returns true if all the text was composed into textLines.
*/
private function createTextLines(innerWidth:Number,
innerHeight:Number,
paragraphText:String,
paragraphY:int,
ascent:int, descent:int):int
{
// Set the TextBlock's content.
// Note: If there is no text, we do what TLF does and compose
// a paragraph terminator character, so that a TextLine
// gets created and we can measure it.
// It will have a width of 0 but a height equal
// to the font's ascent plus descent.
staticTextElement.text = paragraphText.length > 0 ?
paragraphText :
"\u2029";
staticTextElement.elementFormat = elementFormat;
staticTextBlock.content = staticTextElement;
// And its bidiLevel.
staticTextBlock.bidiLevel = direction == "ltr" ? 0 : 1;
// And its justifier.
staticSpaceJustifier.lineJustification =
_defaultTextFormat.align == "justify" ?
LineJustification.ALL_BUT_LAST :
LineJustification.UNJUSTIFIED;;
staticTextBlock.textJustifier = staticSpaceJustifier;
// Then create and add TextLines using this TextBlock.
paragraphY = createTextLinesFromTextBlock(
innerWidth, innerHeight,
staticTextBlock, paragraphY,
ascent, descent);
// Cleans up and sets the validity of the lines associated
// with the TextBlock to TextLineValidity.INVALID.
var firstLine:TextLine = staticTextBlock.firstLine;
var lastLine:TextLine = staticTextBlock.lastLine;
if (firstLine)
staticTextBlock.releaseLines(firstLine, lastLine);
return paragraphY;
}
/**
* @private
* Compose into textLines. bounds on input is size of composition
* area and on output is the size of the composed content.
* The caller must call releaseLinesFromTextBlock() to release the
* textLines from the TextBlock.
*
* Returns true if all the text was composed into textLines.
*/
private function createTextLinesFromTextBlock(innerWidth:Number,
innerHeight:Number,
textBlock:TextBlock,
paragraphY:int,
ascent:int,
descent:int):int
{
if (innerWidth < 0 || innerHeight < 0)
return paragraphY;
var blockIndent:Number = Number(_defaultTextFormat.blockIndent);
var indent:Number = Number(_defaultTextFormat.indent);
var leftMargin:Number = Number(_defaultTextFormat.leftMargin);
var rightMargin:Number = Number(_defaultTextFormat.rightMargin);
var maxLineWidthBeforeIndent:Number =
wordWrap ? innerWidth : TextLine.MAX_LINE_WIDTH;
var maxLineWidth:Number = maxLineWidthBeforeIndent;
var n:int = 0;
var nextTextLine:TextLine;
var nextY:int = paragraphY;
var textLine:TextLine;
// TextField seems to do this. You can see it with wordWrap and
// indent > width or when rightMargin > width. In the former case,
// the first line is visually empty but contains a character which is
// clipped and the second line starts with the second letter.
// The clipped first line serves as a placeholder so that the rest
// of the lines which may be visible are composed.
var fitSomething:Boolean = true;
// Generate TextLines, stopping when we run out of text
// or reach the bottom of the requested bounds.
// In this loop the lines are positioned within the rectangle
// (0, 0, innerWidth, innerHeight), with left alignment.
while (true)
{
// Adjust the compose width for indents and margins.
if (n <= 1)
{
var totalIndent:Number = blockIndent + leftMargin;
if (n == 0)
totalIndent += indent;
if (totalIndent < 0)
totalIndent = 0;
else if (totalIndent > _width - PADDING_LEFT - PADDING_RIGHT)
totalIndent = _width - PADDING_LEFT - PADDING_RIGHT;
if (!wordWrap)
rightMargin = 0;
maxLineWidth =
maxLineWidthBeforeIndent - totalIndent - rightMargin;
// Stay within the bounds to avoid exception. Since
// fitSomething is true it is okay if maxLineWidth is < 0.
if (maxLineWidth > TextLine.MAX_LINE_WIDTH)
maxLineWidth = TextLine.MAX_LINE_WIDTH;
}
var recycleLine:TextLine = TextLineRecycler.getLineForReuse();
if (recycleLine)
{
if (fontContext)
{
nextTextLine = fontContext.callInContext(
textBlock["recreateTextLine"], textBlock,
[ recycleLine, textLine, maxLineWidth, 0.0, fitSomething ]);
}
else
{
nextTextLine = recreateTextLine(
recycleLine, textLine, maxLineWidth, 0.0, fitSomething);
}
}
else
{
if (fontContext)
{
nextTextLine = fontContext.callInContext(
textBlock.createTextLine, textBlock,
[ textLine, maxLineWidth, 0.0, fitSomething ]);
}
else
{
nextTextLine = textBlock.createTextLine(
textLine, maxLineWidth, 0.0, fitSomething);
}
}
if (!nextTextLine)
break;
// Determine the natural baseline position for this line.
// Note: The y coordinate of a TextLine is the location
// of its baseline, not of its "top".
if (n == 0)
nextY += ascent;
else
nextY += descent + _defaultTextFormat.leading + ascent;
// We'll keep this line.
textLine = nextTextLine;
n++;
// Assign its location based on left/top alignment.
// Its x position is 0 by default.
textLine.y = nextY;
// Adjust for positive indent/left margin. Do it here rather
// than at the end when alignment is done so the first
// line of each paragraph is indented properly.
textLine.x = totalIndent;
if (_defaultTextFormat.underline)
{
// FTE doesn't render underlines,
// but it can tell us where to draw them.
// You can't draw in a TextLine but it can have children,
// so we create a child Shape to draw them in.
var fontMetrics:FontMetrics = elementFormat.getFontMetrics();
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
g.lineStyle(fontMetrics.underlineThickness,
elementFormat.color, elementFormat.alpha);
g.moveTo(0, fontMetrics.underlineOffset);
g.lineTo(textLine.textWidth, fontMetrics.underlineOffset);
textLine.addChild(shape);
}
addChild(textLine);
}
return nextY + descent;
}
/**
* @private
* Returns with _textWidth and clipWidth set.
*/
private function alignTextLines(innerWidth:Number):void
{
// This is only the case when we are auto sizing. In this case
// we don't want to do any alignment.
if (isNaN(innerWidth))
innerWidth = 0;
var rightMargin:Number = Number(_defaultTextFormat.rightMargin);
var align:String = _defaultTextFormat.align;
var leftAligned:Boolean =
align == "left" && direction == "ltr" ||
align == "right" && direction == "rtl" ||
align == "justify";
var centerAligned:Boolean = align == "center";
var rightAligned:Boolean =
align == "left" && direction == "rtl" ||
align == "right" && direction == "ltr";
// Calculate loop constants for horizontal alignment.
var leftOffset:Number = PADDING_LEFT;
var centerOffset:Number = leftOffset + innerWidth / 2;
var rightOffset:Number = leftOffset + innerWidth;
// Reposition each line if necessary.
// based on the horizontal alignment,
// and adjusting for the padding.
var n:int = numChildren;
for (var i:int = 0; i < n; i++)
{
var textLine:TextLine = TextLine(getChildAt(i));
_textWidth = Math.max(_textWidth, textLine.textWidth);
var width:Number = textLine.x + textLine.textWidth + rightMargin;
// Only align if there is width to do so.
if (leftAligned || width >= innerWidth)
textLine.x += leftOffset;
else if (centerAligned)
textLine.x += centerOffset - width / 2;
else if (rightAligned)
textLine.x += rightOffset - width;
clipWidth = Math.max(clipWidth, textLine.x + textLine.textWidth);
textLine.y += PADDING_TOP;
}
}
/**
* @private
*/
private function composeHTMLText(compositionWidth:Number,
compositionHeight:Number):void
{
textFlow = htmlImporter.importToFlow(explicitHTMLText);
// Unless there is a styleSheet, _htmlText is now invalid
// and needs to be regenerated on demand,
// because with htmlText what-you-set-is-not-what-you-get.
if (!styleSheet)
_htmlText = null;
if (!textFlow)
return;
textFlow.addEventListener(MouseEvent.CLICK, linkClickHandler);
textFlow.addEventListener(
StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGE,
inlineGraphicStatusChangeHandler);
if (!textContainerManager)
textContainerManager = new FTETextFieldTextContainerManager(this);
textContainerManager.compositionWidth = compositionWidth;
textContainerManager.compositionHeight = compositionHeight;
textContainerManager.editingMode = EditingMode.READ_ONLY;
textContainerManager.hostFormat = hostFormat;
textContainerManager.swfContext = fontContext;
textContainerManager.setTextFlow(textFlow)
// Add a formatResolver if there is a style sheet. Force a flow
// composer to be created, if there isn't one, so the format resolver
// will be used.
if (_styleSheet && !textFlow.formatResolver)
{
textFlow.formatResolver = new FTETextFieldStyleResolver(_styleSheet);
textContainerManager.beginInteraction();
textContainerManager.endInteraction();
}
textContainerManager.updateContainer();
var bounds:Rectangle = textContainerManager.getContentBounds();
_textWidth = Math.round(bounds.width);
_textHeight = Math.round(bounds.height);
// TLF takes care of clipping so none should be needed here.
clipWidth = _textWidth;
}
/**
* @private
* Provides RTE messages.
* FTETextField is deliberately kept independent
* of the rest of the Flex framework.
* Therefore it doesn't have access to localized resource strings
* in the ResourceManager and simply has hard-coded English Strings.
* However, framework subclasses such as UIFTETextField override
* this method to provide localized messages from ResourceManager.
*/
mx_internal function getErrorMessage(key:String, param:String = null):String
{
var message:String = "";
switch (key)
{
case "badParameter":
{
// This message matches the one in Flash Player.
message = "Parameter " + param + " must be one of the accepted values.";
break;
}
case "nullParameter":
{
// This message matches the one in Flash Player.
message = "Parameter " + param + " must be non-null.";
break;
}
case "badIndex":
{
// This message matches the one in Flash Player.
message = "The supplied index is out of bounds.";
break;
}
case "notImplementedInFTETextField":
{
message = "'" + param + "' is not implemented in FTETextField.";
break;
}
case "unsupportedTypeInFTETextField":
{
message = "FTETextField does not support setting type to \"input\".";
break;
}
}
return message;
}
/**
* @private
*/
private function notImplemented(name:String):String
{
return getErrorMessage("notImplementedInFTETextField", name);
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* @private
*/
private function addedToStageHandler(event:Event):void
{
invalidate();
}
/**
* @private
*/
private function renderHandler(event:Event):void
{
validateNow();
removeEventListener(Event.RENDER, renderHandler);
}
/**
* @private
*/
private function linkClickHandler(event:FlowElementMouseEvent):void
{
// Need to remove the event: portion of the href if it has one.
// Only dispatch the event if it has the event portion.
var href:String = LinkElement(event.flowElement).href;
if (href.indexOf("event:") == 0)
{
var textEvent:TextEvent = new TextEvent(TextEvent.LINK);
textEvent.text = href.substring(6);
dispatchEvent(textEvent);
}
}
/**
* @private
*/
private function inlineGraphicStatusChangeHandler(
event:StatusChangeEvent):void
{
setFlag(FLAG_TEXT_LINES_INVALID |
FLAG_GRAPHICS_INVALID);
invalidate();
}
}
}
import flash.display.Sprite;
import flash.text.engine.FontLookup;
import flash.text.engine.FontPosture;
import flash.text.engine.FontWeight;
import flash.text.StyleSheet;
import flash.text.engine.Kerning;
import flashx.textLayout.container.TextContainerManager;
import flashx.textLayout.elements.FlowElement;
import flashx.textLayout.elements.IConfiguration;
import flashx.textLayout.elements.IFormatResolver;
import flashx.textLayout.formats.ITextLayoutFormat;
import flashx.textLayout.elements.LinkElement;
import flashx.textLayout.elements.ParagraphElement;
import flashx.textLayout.elements.SpanElement;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.formats.LeadingModel;
import flashx.textLayout.formats.LineBreak;
import flashx.textLayout.formats.TextDecoration;
import flashx.textLayout.formats.TextLayoutFormat;
import mx.core.FTETextField;
import mx.core.mx_internal;
use namespace mx_internal;
/**
* @private
*/
class FTETextFieldTextContainerManager extends TextContainerManager
{
/**
* @private
*/
public function FTETextFieldTextContainerManager(container:Sprite, configuration:IConfiguration = null)
{
super(container, configuration);
}
/**
* @private
*/
override public function drawBackgroundAndSetScrollRect(scrollX:Number, scrollY:Number):Boolean
{
return true;
}
}
import helpers.FTETextField41
/**
* @private
*/
class FTETextFieldHostFormat extends TextLayoutFormat
{
public function FTETextFieldHostFormat(textField:FTETextField41)
{
super();
this.textField = textField;
}
private var textField:FTETextField41;
public override function get color():*
{
return textField._defaultTextFormat.color;
}
public override function get direction():*
{
return textField.direction;
}
public override function get fontFamily():*
{
return textField._defaultTextFormat.font;
}
public override function get fontLookup():*
{
return textField.embedFonts ?
FontLookup.EMBEDDED_CFF :
FontLookup.DEVICE;
}
public override function get fontSize():*
{
return textField._defaultTextFormat.size;
}
public override function get fontStyle():*
{
return textField._defaultTextFormat.italic ?
FontPosture.ITALIC :
FontPosture.NORMAL;
}
public override function get fontWeight():*
{
return textField._defaultTextFormat.bold ?
FontWeight.BOLD :
FontWeight.NORMAL;
}
public override function get kerning():*
{
return textField._defaultTextFormat.kerning ?
Kerning.AUTO :
Kerning.OFF;
}
public override function get leadingModel():*
{
return LeadingModel.APPROXIMATE_TEXT_FIELD;
}
public override function get lineBreak():*
{
return textField.wordWrap ?
LineBreak.TO_FIT :
LineBreak.EXPLICIT;
}
public override function get lineHeight():*
{
return textField._defaultTextFormat.leading;
}
public override function get locale():*
{
return textField.locale;
}
public override function get paddingBottom():*
{
return FTETextField.PADDING_BOTTOM;
}
public override function get paddingLeft():*
{
return FTETextField.PADDING_LEFT;
}
public override function get paddingRight():*
{
return FTETextField.PADDING_RIGHT;
}
public override function get paddingTop():*
{
return FTETextField.PADDING_TOP;
}
public override function get paragraphEndIndent():*
{
return textField._defaultTextFormat.rightMargin;
}
public override function get paragraphStartIndent():*
{
return textField._defaultTextFormat.leftMargin;
}
public override function get textAlign():*
{
return textField._defaultTextFormat.align;
}
public override function get textAlignLast():*
{
return textField._defaultTextFormat.align;
}
public override function get textDecoration():*
{
return textField._defaultTextFormat.underline ?
TextDecoration.UNDERLINE :
TextDecoration.NONE;
}
public override function get textIndent():*
{
return textField._defaultTextFormat.indent;
}
public override function get trackingRight():*
{
return textField._defaultTextFormat.letterSpacing;
}
}
/**
* @private
* To attach TextField styling via a style sheet to a TextFlow.
*/
class FTETextFieldStyleResolver implements IFormatResolver
{
//--------------------------------------------------------------------------
//
// Class variables
//
//--------------------------------------------------------------------------
/**
* Map of TextField StyleSheet CSS properties to their equivalent
* TLF properties. This is only the styles which have different names.
*/
private static const textFieldToTLFStyleMap:Object =
{
"leading": "lineHeight",
"letterSpacing": "trackingRight",
"marginLeft": "paragraphStartIndent",
"marginRight": "paragraphEndIndent"
};
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
public function FTETextFieldStyleResolver(styleSheet:StyleSheet):void
{
_styleSheet = styleSheet;
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* The TextField style sheet that will be used to create the TLF style
* objects.
*/
private var _styleSheet:StyleSheet;
//--------------------------------------------------------------------------
//
// IFormatResolver
//
//--------------------------------------------------------------------------
/**
* Given a FlowElement or ContainerController object, return any format
* settings for it.
*
* Return format settings for the specified object.
*/
public function resolveFormat(elem:Object):ITextLayoutFormat
{
var attr:TextLayoutFormat = null;
// ContainerController will inherit via the container so it is not
// handled here. Map HTML <body> to TextFlow, HTML <p> to
// ParagraphElement and HTML <span> to SpanElement.
if (elem is FlowElement)
{
if (elem is TextFlow)
attr = addStyleAttributes(attr, "body");
else if (elem is ParagraphElement)
attr = addStyleAttributes(attr, "p");
else if (elem is SpanElement)
attr = addStyleAttributes(attr, "span");
// Apply class selector over any format from above.
if (elem.styleName != null)
attr = addStyleAttributes(attr, "." + elem.styleName);
}
return attr;
}
/**
* Given a FlowElement or ContainerController object and the name of a
* format property, return the format value or undefined if
* the value is not found.
*
* Return the value of the specified format for the specified object.
*/
public function resolveUserFormat(elem:Object,userStyle:String):*
{
var flowElem:FlowElement = elem as FlowElement;
var attr:TextLayoutFormat;
// support non-tlf styles
if (flowElem)
{
if (flowElem.styleName)
{
attr = addStyleAttributes(null, "." + flowElem.styleName);
}
else if (flowElem is LinkElement)
{
if (userStyle == "linkNormalFormat")
attr = addStyleAttributes(null, "a:link");
else if (userStyle == "linkHoverFormat")
attr = addStyleAttributes(null, "a:hover");
else if (userStyle == "linkActiveFormat")
attr = addStyleAttributes(null, "a:active");
}
else
{
attr = addStyleAttributes(null, userStyle);
}
}
return attr != null ? attr : undefined;
}
/**
* Invalidates any cached formatting information for a TextFlow so that
* formatting must be recomputed.
*/
public function invalidateAll(tf:TextFlow):void
{
}
/**
* Invalidates cached formatting information on this element because, for
* example, the parent changed, or the id or the styleName changed.
*/
public function invalidate(target:Object):void
{
}
/**
* Return the format resolver for the copy of the TextFlow.
*/
public function getResolverForNewFlow(oldFlow:TextFlow,newFlow:TextFlow):IFormatResolver
{
return this;
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* Look up the styleSelector in the TextField style sheet and build the
* object of corresponding TLF styles and values. Return null if the
* styleSelector is not found in the style sheet.
*/
private function addStyleAttributes(
attr:TextLayoutFormat,
styleSelector:String):TextLayoutFormat
{
var foundStyle:Object = _styleSheet.getStyle(styleSelector);
if (foundStyle != null)
{
for (var p:* in foundStyle)
{
var propStyle:Object = foundStyle[p];
if (attr == null)
attr = new TextLayoutFormat();
if (textFieldToTLFStyleMap[p])
{
// different name, same values
var tlfProp:String = textFieldToTLFStyleMap[p];
attr[tlfProp] = propStyle;
}
else if (p == "color")
{
// convert from "#000000" to "0x000000" format
var color:String = String(propStyle);
if (color && color.charAt(0) == "#")
attr.color = "0x"+color.substring(1);
}
else if (p == "display")
{
// TODO(cframpto): if we decide to support this.
}
else if (p == "kerning")
{
// convert from true/false to on/off
if (Boolean(propStyle))
attr.kerning = flash.text.engine.Kerning.ON;
else
attr.kerning = flash.text.engine.Kerning.OFF;
}
else
{
// same name, same values
attr[p] = propStyle;
}
}
}
return attr;
}
}