scaffold.libs_as.feathers.controls.text.TextFieldTextRenderer.as Maven / Gradle / Ivy
/*
Feathers
Copyright 2012-2015 Bowler Hat LLC. All Rights Reserved.
This program is free software. You can redistribute and/or modify it in
accordance with the terms of the accompanying license agreement.
*/
package feathers.controls.text
{
import feathers.core.FeathersControl;
import feathers.core.IStateContext;
import feathers.core.IStateObserver;
import feathers.core.ITextRenderer;
import feathers.core.IToggle;
import feathers.events.FeathersEventType;
import feathers.skins.IStyleProvider;
import feathers.utils.geom.matrixToScaleX;
import feathers.utils.geom.matrixToScaleY;
import flash.display.BitmapData;
import flash.display3D.Context3DProfile;
import flash.filters.BitmapFilter;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.AntiAliasType;
import flash.text.GridFitType;
import flash.text.StyleSheet;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import starling.core.Starling;
import starling.display.Image;
import starling.events.Event;
import starling.rendering.Painter;
import starling.textures.ConcreteTexture;
import starling.textures.Texture;
import starling.utils.MathUtil;
/**
* Renders text with a native flash.text.TextField
and draws
* it to BitmapData
before uploading it to a texture on the
* GPU. Textures are managed internally by this component, and they will be
* automatically disposed when the component is disposed.
*
* For longer passages of text, this component will stitch together
* multiple individual textures both horizontally and vertically, as a grid,
* if required. This may require quite a lot of texture memory, possibly
* exceeding the limits of some mobile devices, so use this component with
* caution when displaying a lot of text.
*
* The following example shows how to use
* TextFieldTextRenderer
with a Label
:
*
*
* var label:Label = new Label();
* label.text = "I am the very model of a modern Major General";
* label.textRendererFactory = function():ITextRenderer
* {
* return new TextFieldTextRenderer();
* };
* this.addChild( label );
*
* @see ../../../../help/text-renderers.html Introduction to Feathers text renderers
* @see ../../../../help/text-field-text-renderer.html How to use the Feathers TextFieldTextRenderer component
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html flash.text.TextField
*/
public class TextFieldTextRenderer extends FeathersControl implements ITextRenderer, IStateObserver
{
/**
* @private
*/
private static const HELPER_POINT:Point = new Point();
/**
* @private
*/
private static const HELPER_MATRIX:Matrix = new Matrix();
/**
* @private
*/
private static const HELPER_RECTANGLE:Rectangle = new Rectangle();
/**
* The default IStyleProvider
for all TextFieldTextRenderer
* components.
*
* @default null
* @see feathers.core.FeathersControl#styleProvider
*/
public static var globalStyleProvider:IStyleProvider;
/**
* Constructor.
*/
public function TextFieldTextRenderer()
{
super();
this.isQuickHitAreaEnabled = true;
}
/**
* The TextField instance used to render the text before taking a
* texture snapshot.
*/
protected var textField:TextField;
/**
* An image that displays a snapshot of the native TextField
* in the Starling display list when the editor doesn't have focus.
*/
protected var textSnapshot:Image;
/**
* If multiple snapshots are needed due to texture size limits, the
* snapshots appearing after the first are stored here.
*/
protected var textSnapshots:Vector.;
/**
* @private
*/
protected var _textSnapshotOffsetX:Number = 0;
/**
* @private
*/
protected var _textSnapshotOffsetY:Number = 0;
/**
* @private
*/
protected var _previousActualWidth:Number = NaN;
/**
* @private
*/
protected var _previousActualHeight:Number = NaN;
/**
* @private
*/
protected var _snapshotWidth:int = 0;
/**
* @private
*/
protected var _snapshotHeight:int = 0;
/**
* @private
*/
protected var _snapshotVisibleWidth:int = 0;
/**
* @private
*/
protected var _snapshotVisibleHeight:int = 0;
/**
* @private
*/
protected var _needsNewTexture:Boolean = false;
/**
* @private
*/
protected var _hasMeasured:Boolean = false;
/**
* @private
*/
override protected function get defaultStyleProvider():IStyleProvider
{
return TextFieldTextRenderer.globalStyleProvider;
}
/**
* @private
*/
protected var _text:String = "";
/**
* @inheritDoc
*
* In the following example, the text is changed:
*
*
* textRenderer.text = "Lorem ipsum";
*
* @default ""
*
* @see #isHTML
*/
public function get text():String
{
return this._text;
}
/**
* @private
*/
public function set text(value:String):void
{
if(this._text == value)
{
return;
}
if(value === null)
{
//flash.text.TextField won't accept a null value
value = "";
}
this._text = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
/**
* @private
*/
protected var _isHTML:Boolean = false;
/**
* Determines if the TextField should display the text as HTML or not.
*
* In the following example, the text is displayed as HTML:
*
*
* textRenderer.isHTML = true;
* textRenderer.text = "<span class='heading'>hello</span> world!";
*
* @default false
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#htmlText flash.text.TextField.htmlText
* @see #text
*/
public function get isHTML():Boolean
{
return this._isHTML;
}
/**
* @private
*/
public function set isHTML(value:Boolean):void
{
if(this._isHTML == value)
{
return;
}
this._isHTML = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
/**
* @private
*/
protected var currentTextFormat:TextFormat;
/**
* @private
*/
protected var _textFormatForState:Object;
/**
* @private
*/
protected var _textFormat:TextFormat;
/**
* The font and styles used to draw the text.
*
* In the following example, the text format is changed:
*
*
* textRenderer.textFormat = new TextFormat( "Source Sans Pro" );
*
* @default null
*
* @see #setTextFormatForState()
* @see #disabledTextFormat
* @see #selectedTextFormat
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextFormat.html flash.text.TextFormat
*/
public function get textFormat():TextFormat
{
return this._textFormat;
}
/**
* @private
*/
public function set textFormat(value:TextFormat):void
{
if(this._textFormat == value)
{
return;
}
this._textFormat = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _disabledTextFormat:TextFormat;
/**
* The font and styles used to draw the text when the component is
* disabled.
*
* In the following example, the disabled text format is changed:
*
*
* textRenderer.isEnabled = false;
* textRenderer.disabledTextFormat = new TextFormat( "Source Sans Pro" );
*
* @default null
*
* @see #textFormat
* @see #selectedTextFormat
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextFormat.html flash.text.TextFormat
*/
public function get disabledTextFormat():TextFormat
{
return this._disabledTextFormat;
}
/**
* @private
*/
public function set disabledTextFormat(value:TextFormat):void
{
if(this._disabledTextFormat == value)
{
return;
}
this._disabledTextFormat = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _selectedTextFormat:TextFormat;
/**
* The font and styles used to draw the text when the
* stateContext
implements the IToggle
* interface, and it is selected.
*
* In the following example, the selected text format is changed:
*
*
* textRenderer.selectedTextFormat = new TextFormat( "Source Sans Pro" );
*
* @default null
*
* @see #stateContext
* @see feathers.core.IToggle
* @see #textFormat
* @see #disabledTextFormat
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextFormat.html flash.text.TextFormat
*/
public function get selectedTextFormat():TextFormat
{
return this._selectedTextFormat;
}
/**
* @private
*/
public function set selectedTextFormat(value:TextFormat):void
{
if(this._selectedTextFormat == value)
{
return;
}
this._selectedTextFormat = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _styleSheet:StyleSheet;
/**
* The StyleSheet
object to pass to the TextField.
*
* In the following example, a style sheet is applied:
*
*
* var style:StyleSheet = new StyleSheet();
* var heading:Object = new Object();
* heading.fontWeight = "bold";
* heading.color = "#FF0000";
*
* var body:Object = new Object();
* body.fontStyle = "italic";
*
* style.setStyle(".heading", heading);
* style.setStyle("body", body);
*
* textRenderer.styleSheet = style;
* textRenderer.isHTML = true;
* textRenderer.text = "<body><span class='heading'>Hello</span> World...</body>";
*
* @default null
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#styleSheet Full description of flash.text.TextField.styleSheet in Adobe's Flash Platform API Reference
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/StyleSheet.html flash.text.StyleSheet
* @see #isHTML
*/
public function get styleSheet():StyleSheet
{
return this._styleSheet;
}
/**
* @private
*/
public function set styleSheet(value:StyleSheet):void
{
if(this._styleSheet == value)
{
return;
}
this._styleSheet = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _embedFonts:Boolean = false;
/**
* Determines if the TextField should use an embedded font or not. If
* the specified font is not embedded, the text is not displayed.
*
* In the following example, the font is embedded:
*
*
* textRenderer.embedFonts = true;
*
* @default false
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#embedFonts Full description of flash.text.TextField.embedFonts in Adobe's Flash Platform API Reference
*/
public function get embedFonts():Boolean
{
return this._embedFonts;
}
/**
* @private
*/
public function set embedFonts(value:Boolean):void
{
if(this._embedFonts == value)
{
return;
}
this._embedFonts = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @inheritDoc
*/
public function get baseline():Number
{
if(!this.textField)
{
return 0;
}
var gutterDimensionsOffset:Number = 0;
if(this._useGutter)
{
gutterDimensionsOffset = 2;
}
return gutterDimensionsOffset + this.textField.getLineMetrics(0).ascent;
}
/**
* @private
*/
protected var _wordWrap:Boolean = false;
/**
* @inheritDoc
*
* In the following example, word wrap is enabled:
*
*
* textRenderer.wordWrap = true;
*
* @default false
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#wordWrap Full description of flash.text.TextField.wordWrap in Adobe's Flash Platform API Reference
*/
public function get wordWrap():Boolean
{
return this._wordWrap;
}
/**
* @private
*/
public function set wordWrap(value:Boolean):void
{
if(this._wordWrap == value)
{
return;
}
this._wordWrap = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
private var _antiAliasType:String = AntiAliasType.ADVANCED;
/**
* The type of anti-aliasing used for this text field, defined as
* constants in the flash.text.AntiAliasType
class. You can
* control this setting only if the font is embedded (with the
* embedFonts
property set to true).
*
* In the following example, the anti-alias type is changed:
*
*
* textRenderer.antiAliasType = AntiAliasType.NORMAL;
*
* @default flash.text.AntiAliasType.ADVANCED
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#antiAliasType Full description of flash.text.TextField.antiAliasType in Adobe's Flash Platform API Reference
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/AntiAliasType.html flash.text.AntiAliasType
*/
public function get antiAliasType():String
{
return this._antiAliasType;
}
/**
* @private
*/
public function set antiAliasType(value:String):void
{
if(this._antiAliasType == value)
{
return;
}
this._antiAliasType = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
private var _background:Boolean = false;
/**
* Specifies whether the text field has a background fill. Use the
* backgroundColor
property to set the background color of
* a text field.
*
* In the following example, the background is enabled:
*
*
* textRenderer.background = true;
* textRenderer.backgroundColor = 0xff0000;
*
* @default false
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#background Full description of flash.text.TextField.background in Adobe's Flash Platform API Reference
* @see #backgroundColor
*/
public function get background():Boolean
{
return this._background;
}
/**
* @private
*/
public function set background(value:Boolean):void
{
if(this._background == value)
{
return;
}
this._background = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
private var _backgroundColor:uint = 0xffffff;
/**
* The color of the text field background that is displayed if the
* background
property is set to true
.
*
* In the following example, the background color is changed:
*
*
* textRenderer.background = true;
* textRenderer.backgroundColor = 0xff000ff;
*
* @default 0xffffff
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#backgroundColor Full description of flash.text.TextField.backgroundColor in Adobe's Flash Platform API Reference
* @see #background
*/
public function get backgroundColor():uint
{
return this._backgroundColor;
}
/**
* @private
*/
public function set backgroundColor(value:uint):void
{
if(this._backgroundColor == value)
{
return;
}
this._backgroundColor = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
private var _border:Boolean = false;
/**
* Specifies whether the text field has a border. Use the
* borderColor
property to set the border color.
*
* Note: this property cannot be used when the useGutter
* property is set to false
(the default value!).
*
* In the following example, the border is enabled:
*
*
* textRenderer.border = true;
* textRenderer.borderColor = 0xff0000;
*
* @default false
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#border Full description of flash.text.TextField.border in Adobe's Flash Platform API Reference
* @see #borderColor
*/
public function get border():Boolean
{
return this._border;
}
/**
* @private
*/
public function set border(value:Boolean):void
{
if(this._border == value)
{
return;
}
this._border = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
private var _borderColor:uint = 0x000000;
/**
* The color of the text field border that is displayed if the
* border
property is set to true
.
*
* In the following example, the border color is changed:
*
*
* textRenderer.border = true;
* textRenderer.borderColor = 0xff00ff;
*
* @default 0x000000
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#borderColor Full description of flash.text.TextField.borderColor in Adobe's Flash Platform API Reference
* @see #border
*/
public function get borderColor():uint
{
return this._borderColor;
}
/**
* @private
*/
public function set borderColor(value:uint):void
{
if(this._borderColor == value)
{
return;
}
this._borderColor = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
private var _condenseWhite:Boolean = false;
/**
* A boolean value that specifies whether extra white space (spaces,
* line breaks, and so on) in a text field with HTML text is removed.
*
* In the following example, whitespace is condensed:
*
*
* textRenderer.condenseWhite = true;
*
* @default false
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#condenseWhite Full description of flash.text.TextField.condenseWhite in Adobe's Flash Platform API Reference
* @see #isHTML
*/
public function get condenseWhite():Boolean
{
return this._condenseWhite;
}
/**
* @private
*/
public function set condenseWhite(value:Boolean):void
{
if(this._condenseWhite == value)
{
return;
}
this._condenseWhite = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
private var _displayAsPassword:Boolean = false;
/**
* Specifies whether the text field is a password text field that hides
* the input characters using asterisks instead of the actual
* characters.
*
* In the following example, the text is displayed as a password:
*
*
* textRenderer.displayAsPassword = true;
*
* @default false
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#displayAsPassword Full description of flash.text.TextField.displayAsPassword in Adobe's Flash Platform API Reference
*/
public function get displayAsPassword():Boolean
{
return this._displayAsPassword;
}
/**
* @private
*/
public function set displayAsPassword(value:Boolean):void
{
if(this._displayAsPassword == value)
{
return;
}
this._displayAsPassword = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
private var _gridFitType:String = GridFitType.PIXEL;
/**
* Determines whether Flash Player forces strong horizontal and vertical
* lines to fit to a pixel or subpixel grid, or not at all using the
* constants defined in the flash.text.GridFitType
class.
* This property applies only if the antiAliasType
property
* of the text field is set to flash.text.AntiAliasType.ADVANCED
.
*
* In the following example, the grid fit type is changed:
*
*
* textRenderer.gridFitType = GridFitType.SUBPIXEL;
*
* @default flash.text.GridFitType.PIXEL
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#gridFitType Full description of flash.text.TextField.gridFitType in Adobe's Flash Platform API Reference
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/GridFitType.html flash.text.GridFitType
* @see #antiAliasType
*/
public function get gridFitType():String
{
return this._gridFitType;
}
/**
* @private
*/
public function set gridFitType(value:String):void
{
if(this._gridFitType == value)
{
return;
}
this._gridFitType = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
private var _sharpness:Number = 0;
/**
* The sharpness of the glyph edges in this text field. This property
* applies only if the antiAliasType
property of the text
* field is set to flash.text.AntiAliasType.ADVANCED
. The
* range for sharpness
is a number from -400
* to 400
.
*
* In the following example, the sharpness is changed:
*
*
* textRenderer.sharpness = 200;
*
* @default 0
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#sharpness Full description of flash.text.TextField.sharpness in Adobe's Flash Platform API Reference
* @see #antiAliasType
*/
public function get sharpness():Number
{
return this._sharpness;
}
/**
* @private
*/
public function set sharpness(value:Number):void
{
if(this._sharpness == value)
{
return;
}
this._sharpness = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
/**
* @private
*/
private var _thickness:Number = 0;
/**
* The thickness of the glyph edges in this text field. This property
* applies only if the antiAliasType
property is set to
* flash.text.AntiAliasType.ADVANCED
. The range for
* thickness
is a number from -200
to
* 200
.
*
* In the following example, the thickness is changed:
*
*
* textRenderer.thickness = 100;
*
* @default 0
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html#thickness Full description of flash.text.TextField.thickness in Adobe's Flash Platform API Reference
* @see #antiAliasType
*/
public function get thickness():Number
{
return this._thickness;
}
/**
* @private
*/
public function set thickness(value:Number):void
{
if(this._thickness == value)
{
return;
}
this._thickness = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
/**
* @private
*/
protected var _maxTextureDimensions:int = 2048;
/**
* The maximum size of individual textures that are managed by this text
* renderer. Must be a power of 2. A larger value will create fewer
* individual textures, but a smaller value may use less overall texture
* memory by incrementing over smaller powers of two.
*
* In the following example, the maximum size of the textures is
* changed:
*
*
* renderer.maxTextureDimensions = 4096;
*
* @default 2048
*/
public function get maxTextureDimensions():int
{
return this._maxTextureDimensions;
}
/**
* @private
*/
public function set maxTextureDimensions(value:int):void
{
//check if we can use rectangle textures or not
if(Starling.current.profile == Context3DProfile.BASELINE_CONSTRAINED)
{
value = MathUtil.getNextPowerOfTwo(value);
}
if(this._maxTextureDimensions == value)
{
return;
}
this._maxTextureDimensions = value;
this._needsNewTexture = true;
this.invalidate(INVALIDATION_FLAG_SIZE);
}
/**
* @private
*/
protected var _nativeFilters:Array;
/**
* Native filters to pass to the flash.text.TextField
* before creating the texture snapshot.
*
* In the following example, the native filters are changed:
*
*
* renderer.nativeFilters = [ new GlowFilter() ];
*
* @default null
*
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#filters Full description of flash.display.DisplayObject.filters in Adobe's Flash Platform API Reference
*/
public function get nativeFilters():Array
{
return this._nativeFilters;
}
/**
* @private
*/
public function set nativeFilters(value:Array):void
{
if(this._nativeFilters == value)
{
return;
}
this._nativeFilters = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _useGutter:Boolean = false;
/**
* Determines if the 2-pixel gutter around the edges of the
* flash.text.TextField
will be used in measurement and
* layout. To visually align with other text renderers and text editors,
* it is often best to leave the gutter disabled.
*
* In the following example, the gutter is enabled:
*
*
* textEditor.useGutter = true;
*
* @default false
*/
public function get useGutter():Boolean
{
return this._useGutter;
}
/**
* @private
*/
public function set useGutter(value:Boolean):void
{
if(this._useGutter == value)
{
return;
}
this._useGutter = value;
this.invalidate(INVALIDATION_FLAG_STYLES);
}
/**
* @private
*/
protected var _stateContext:IStateContext;
/**
* When the text renderer observes a state context, the text renderer
* may change its TextFormat
based on the current state of
* that context. Typically, a relevant component will automatically
* assign itself as the state context of a text renderer, so this
* property is typically meant for internal use only.
*
* @default null
*
* @see #setTextFormatForState()
*/
public function get stateContext():IStateContext
{
return this._stateContext;
}
/**
* @private
*/
public function set stateContext(value:IStateContext):void
{
if(this._stateContext === value)
{
return;
}
if(this._stateContext)
{
this._stateContext.removeEventListener(FeathersEventType.STATE_CHANGE, stateContext_stateChangeHandler);
}
this._stateContext = value;
if(this._stateContext)
{
this._stateContext.addEventListener(FeathersEventType.STATE_CHANGE, stateContext_stateChangeHandler);
}
this.invalidate(INVALIDATION_FLAG_STATE);
}
/**
* @private
*/
protected var _lastGlobalScaleX:Number = 0;
/**
* @private
*/
protected var _lastGlobalScaleY:Number = 0;
/**
* @private
*/
protected var _updateSnapshotOnScaleChange:Boolean = false;
/**
* Refreshes the texture snapshot every time that the text renderer is
* scaled. Based on the scale in global coordinates, so scaling the
* parent will require a new snapshot.
*
* Warning: setting this property to true may result in reduced
* performance because every change of the scale requires uploading a
* new texture to the GPU. Use with caution. Consider setting this
* property to false temporarily during animations that modify the
* scale.
*
* In the following example, the snapshot will be updated when the
* text renderer is scaled:
*
*
* textRenderer.updateSnapshotOnScaleChange = true;
*
* @default false
*/
public function get updateSnapshotOnScaleChange():Boolean
{
return this._updateSnapshotOnScaleChange;
}
/**
* @private
*/
public function set updateSnapshotOnScaleChange(value:Boolean):void
{
if(this._updateSnapshotOnScaleChange == value)
{
return;
}
this._updateSnapshotOnScaleChange = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
/**
* @private
*/
protected var _useSnapshotDelayWorkaround:Boolean = false;
/**
* Fixes an issue where flash.text.TextField
renders
* incorrectly when drawn to BitmapData
by waiting one
* frame.
*
* Warning: enabling this workaround may cause slight flickering
* after the text
property is changed.
*
* In the following example, the workaround is enabled:
*
*
* textRenderer.useSnapshotDelayWorkaround = true;
*
* @default false
*/
public function get useSnapshotDelayWorkaround():Boolean
{
return this._useSnapshotDelayWorkaround;
}
/**
* @private
*/
public function set useSnapshotDelayWorkaround(value:Boolean):void
{
if(this._useSnapshotDelayWorkaround == value)
{
return;
}
this._useSnapshotDelayWorkaround = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
/**
* @private
*/
override public function dispose():void
{
if(this.textSnapshot)
{
this.textSnapshot.texture.dispose();
this.removeChild(this.textSnapshot, true);
this.textSnapshot = null;
}
if(this.textSnapshots)
{
var snapshotCount:int = this.textSnapshots.length;
for(var i:int = 0; i < snapshotCount; i++)
{
var snapshot:Image = this.textSnapshots[i];
snapshot.texture.dispose();
this.removeChild(snapshot, true);
}
this.textSnapshots = null;
}
//this isn't necessary, but if a memory leak keeps the text renderer
//from being garbage collected, freeing up the text field may help
//ease major memory pressure from native filters
this.textField = null;
this.stateContext = null;
this._previousActualWidth = NaN;
this._previousActualHeight = NaN;
this._needsNewTexture = false;
this._snapshotWidth = 0;
this._snapshotHeight = 0;
super.dispose();
}
/**
* @private
*/
override public function render(painter:Painter):void
{
if(this.textSnapshot)
{
this.getTransformationMatrix(this.stage, HELPER_MATRIX);
if(this._updateSnapshotOnScaleChange)
{
var globalScaleX:Number = matrixToScaleX(HELPER_MATRIX);
var globalScaleY:Number = matrixToScaleY(HELPER_MATRIX);
if(globalScaleX != this._lastGlobalScaleX || globalScaleY != this._lastGlobalScaleY)
{
//the snapshot needs to be updated because the scale has
//changed since the last snapshot was taken.
this.invalidate(INVALIDATION_FLAG_SIZE);
this.validate();
}
}
var scaleFactor:Number = Starling.current.contentScaleFactor;
if(!this._nativeFilters || this._nativeFilters.length === 0)
{
var offsetX:Number = 0;
var offsetY:Number = 0;
}
else
{
offsetX = this._textSnapshotOffsetX / scaleFactor;
offsetY = this._textSnapshotOffsetY / scaleFactor;
}
var snapshotIndex:int = -1;
var totalBitmapWidth:Number = this._snapshotWidth;
var totalBitmapHeight:Number = this._snapshotHeight;
var xPosition:Number = offsetX;
var yPosition:Number = offsetY;
do
{
var currentBitmapWidth:Number = totalBitmapWidth;
if(currentBitmapWidth > this._maxTextureDimensions)
{
currentBitmapWidth = this._maxTextureDimensions;
}
do
{
var currentBitmapHeight:Number = totalBitmapHeight;
if(currentBitmapHeight > this._maxTextureDimensions)
{
currentBitmapHeight = this._maxTextureDimensions;
}
if(snapshotIndex < 0)
{
var snapshot:Image = this.textSnapshot;
}
else
{
snapshot = this.textSnapshots[snapshotIndex];
}
snapshot.x = xPosition / scaleFactor;
snapshot.y = yPosition / scaleFactor;
if(this._updateSnapshotOnScaleChange)
{
snapshot.x /= this._lastGlobalScaleX;
snapshot.y /= this._lastGlobalScaleX;
}
snapshotIndex++;
yPosition += currentBitmapHeight;
totalBitmapHeight -= currentBitmapHeight;
}
while(totalBitmapHeight > 0)
xPosition += currentBitmapWidth;
totalBitmapWidth -= currentBitmapWidth;
yPosition = offsetY;
totalBitmapHeight = this._snapshotHeight;
}
while(totalBitmapWidth > 0)
}
super.render(painter);
}
/**
* @inheritDoc
*/
public function measureText(result:Point = null):Point
{
if(!result)
{
result = new Point();
}
var needsWidth:Boolean = this._explicitWidth !== this._explicitWidth; //isNaN
var needsHeight:Boolean = this._explicitHeight !== this._explicitHeight; //isNaN
if(!needsWidth && !needsHeight)
{
result.x = this._explicitWidth;
result.y = this._explicitHeight;
return result;
}
//if a parent component validates before we're added to the stage,
//measureText() may be called before initialization, so we need to
//force it.
if(!this._isInitialized)
{
this.initializeInternal();
}
this.commit();
result = this.measure(result);
return result;
}
/**
* Sets the TextFormat
to be used by the text renderer when
* the currentState
property of the
* stateContext
matches the specified state value.
*
* If an TextFormat
is not defined for a specific
* state, the value of the textFormat
property will be
* used instead.
*
* If the disabledTextFormat
property is not
* null
and the isEnabled
property is
* false
, all other text formats will be ignored.
*
* @see #stateContext
* @see #textFormat
*/
public function setTextFormatForState(state:String, textFormat:TextFormat):void
{
if(textFormat)
{
if(!this._textFormatForState)
{
this._textFormatForState = {};
}
this._textFormatForState[state] = textFormat;
}
else
{
delete this._textFormatForState[state];
}
//if the context's current state is the state that we're modifying,
//we need to use the new value immediately.
if(this._stateContext && this._stateContext.currentState === state)
{
this.invalidate(INVALIDATION_FLAG_STATE);
}
}
/**
* @private
*/
override protected function initialize():void
{
if(!this.textField)
{
this.textField = new TextField();
var scaleFactor:Number = Starling.contentScaleFactor;
this.textField.scaleX = scaleFactor;
this.textField.scaleY = scaleFactor;
this.textField.mouseEnabled = this.textField.mouseWheelEnabled = false;
this.textField.selectable = false;
this.textField.multiline = true;
}
}
/**
* @private
*/
override protected function draw():void
{
var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE);
this.commit();
this._hasMeasured = false;
sizeInvalid = this.autoSizeIfNeeded() || sizeInvalid;
this.layout(sizeInvalid);
}
/**
* @private
*/
protected function commit():void
{
var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES);
var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA);
var stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE);
if(stylesInvalid || stateInvalid)
{
this.refreshTextFormat();
}
if(stylesInvalid)
{
this.textField.antiAliasType = this._antiAliasType;
this.textField.background = this._background;
this.textField.backgroundColor = this._backgroundColor;
this.textField.border = this._border;
this.textField.borderColor = this._borderColor;
this.textField.condenseWhite = this._condenseWhite;
this.textField.displayAsPassword = this._displayAsPassword;
this.textField.gridFitType = this._gridFitType;
this.textField.sharpness = this._sharpness;
this.textField.thickness = this._thickness;
this.textField.filters = this._nativeFilters;
}
if(dataInvalid || stylesInvalid || stateInvalid)
{
this.textField.wordWrap = this._wordWrap;
this.textField.embedFonts = this._embedFonts;
if(this._styleSheet)
{
this.textField.styleSheet = this._styleSheet;
}
else
{
this.textField.styleSheet = null;
this.textField.defaultTextFormat = this.currentTextFormat;
}
if(this._isHTML)
{
this.textField.htmlText = this._text;
}
else
{
this.textField.text = this._text;
}
}
}
/**
* @private
*/
protected function measure(result:Point = null):Point
{
if(!result)
{
result = new Point();
}
var needsWidth:Boolean = this._explicitWidth !== this._explicitWidth; //isNaN
var needsHeight:Boolean = this._explicitHeight !== this._explicitHeight; //isNaN
this.textField.autoSize = TextFieldAutoSize.LEFT;
this.textField.wordWrap = false;
var scaleFactor:Number = Starling.contentScaleFactor;
var gutterDimensionsOffset:Number = 4;
if(this._useGutter)
{
gutterDimensionsOffset = 0;
}
var newWidth:Number = this._explicitWidth;
if(needsWidth)
{
//yes, this value is never used. this is a workaround for a bug
//in AIR for iOS where getting the value for textField.width the
//first time results in an incorrect value, but if you query it
//again, for some reason, it reports the correct width value.
var hackWorkaround:Number = this.textField.width;
newWidth = (this.textField.width / scaleFactor) - gutterDimensionsOffset;
if(newWidth < this._explicitMinWidth)
{
newWidth = this._explicitMinWidth;
}
else if(newWidth > this._maxWidth)
{
newWidth = this._maxWidth;
}
}
//and this is a workaround for an issue where flash.text.TextField
//will wrap the last word when you pass the value returned by the
//width getter (when TextFieldAutoSize.LEFT is used) to the width
//setter. In other words, the value technically isn't changing, but
//TextField behaves differently.
if(!needsWidth || ((this.textField.width / scaleFactor) - gutterDimensionsOffset) > newWidth)
{
this.textField.width = newWidth + gutterDimensionsOffset;
this.textField.wordWrap = this._wordWrap;
}
var newHeight:Number = this._explicitHeight;
if(needsHeight)
{
newHeight = (this.textField.height / scaleFactor) - gutterDimensionsOffset;
if(newHeight < this._explicitMinHeight)
{
newHeight = this._explicitMinHeight;
}
else if(newHeight > this._maxHeight)
{
newHeight = this._maxHeight;
}
}
this.textField.autoSize = TextFieldAutoSize.NONE;
//put the width and height back just in case we measured without
//a full validation
this.textField.width = this.actualWidth + gutterDimensionsOffset;
this.textField.height = this.actualHeight + gutterDimensionsOffset;
result.x = newWidth;
result.y = newHeight;
this._hasMeasured = true;
return result;
}
/**
* @private
*/
protected function layout(sizeInvalid:Boolean):void
{
var stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES);
var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA);
var stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE);
var scaleFactor:Number = Starling.contentScaleFactor;
var gutterDimensionsOffset:Number = 4;
if(this._useGutter)
{
gutterDimensionsOffset = 0;
}
//if measure() isn't called, we need to apply the same workaround
//for the flash.text.TextField bug with wordWrap.
if(!this._hasMeasured && this._wordWrap)
{
this.textField.autoSize = TextFieldAutoSize.LEFT;
this.textField.wordWrap = false;
if(((this.textField.width / scaleFactor) - gutterDimensionsOffset) > this.actualWidth)
{
this.textField.wordWrap = true;
}
this.textField.autoSize = TextFieldAutoSize.NONE;
this.textField.width = this.actualWidth + gutterDimensionsOffset;
}
if(sizeInvalid)
{
this.textField.width = this.actualWidth + gutterDimensionsOffset;
this.textField.height = this.actualHeight + gutterDimensionsOffset;
//these are getting put into an int later, so we don't want it
//to possibly round down and cut off part of the text.
var rectangleSnapshotWidth:Number = Math.ceil(this.actualWidth * scaleFactor);
var rectangleSnapshotHeight:Number = Math.ceil(this.actualHeight * scaleFactor);
if(this._updateSnapshotOnScaleChange)
{
this.getTransformationMatrix(this.stage, HELPER_MATRIX);
rectangleSnapshotWidth *= matrixToScaleX(HELPER_MATRIX);
rectangleSnapshotHeight *= matrixToScaleY(HELPER_MATRIX);
}
if(rectangleSnapshotWidth >= 1 && rectangleSnapshotHeight >= 1 &&
this._nativeFilters && this._nativeFilters.length > 0)
{
HELPER_MATRIX.identity();
HELPER_MATRIX.scale(scaleFactor, scaleFactor);
var bitmapData:BitmapData = new BitmapData(rectangleSnapshotWidth, rectangleSnapshotHeight, true, 0x00ff00ff);
bitmapData.draw(this.textField, HELPER_MATRIX, null, null, HELPER_RECTANGLE);
this.measureNativeFilters(bitmapData, HELPER_RECTANGLE);
bitmapData.dispose();
bitmapData = null;
this._textSnapshotOffsetX = HELPER_RECTANGLE.x;
this._textSnapshotOffsetY = HELPER_RECTANGLE.y;
rectangleSnapshotWidth = HELPER_RECTANGLE.width;
rectangleSnapshotHeight = HELPER_RECTANGLE.height;
}
var canUseRectangleTexture:Boolean = Starling.current.profile != Context3DProfile.BASELINE_CONSTRAINED;
if(canUseRectangleTexture)
{
if(rectangleSnapshotWidth > this._maxTextureDimensions)
{
this._snapshotWidth = int(rectangleSnapshotWidth / this._maxTextureDimensions) * this._maxTextureDimensions + (rectangleSnapshotWidth % this._maxTextureDimensions);
}
else
{
this._snapshotWidth = rectangleSnapshotWidth;
}
}
else
{
if(rectangleSnapshotWidth > this._maxTextureDimensions)
{
this._snapshotWidth = int(rectangleSnapshotWidth / this._maxTextureDimensions) * this._maxTextureDimensions + MathUtil.getNextPowerOfTwo(rectangleSnapshotWidth % this._maxTextureDimensions);
}
else
{
this._snapshotWidth = MathUtil.getNextPowerOfTwo(rectangleSnapshotWidth);
}
}
if(canUseRectangleTexture)
{
if(rectangleSnapshotHeight > this._maxTextureDimensions)
{
this._snapshotHeight = int(rectangleSnapshotHeight / this._maxTextureDimensions) * this._maxTextureDimensions + (rectangleSnapshotHeight % this._maxTextureDimensions);
}
else
{
this._snapshotHeight = rectangleSnapshotHeight;
}
}
else
{
if(rectangleSnapshotHeight > this._maxTextureDimensions)
{
this._snapshotHeight = int(rectangleSnapshotHeight / this._maxTextureDimensions) * this._maxTextureDimensions + MathUtil.getNextPowerOfTwo(rectangleSnapshotHeight % this._maxTextureDimensions);
}
else
{
this._snapshotHeight = MathUtil.getNextPowerOfTwo(rectangleSnapshotHeight);
}
}
var textureRoot:ConcreteTexture = this.textSnapshot ? this.textSnapshot.texture.root : null;
this._needsNewTexture = this._needsNewTexture || !this.textSnapshot ||
(textureRoot && (textureRoot.scale != scaleFactor ||
this._snapshotWidth != textureRoot.nativeWidth || this._snapshotHeight != textureRoot.nativeHeight));
this._snapshotVisibleWidth = rectangleSnapshotWidth;
this._snapshotVisibleHeight = rectangleSnapshotHeight;
}
//instead of checking sizeInvalid, which will often be triggered by
//changing maxWidth or something for measurement, we check against
//the previous actualWidth/Height used for the snapshot.
if(stylesInvalid || dataInvalid || stateInvalid || this._needsNewTexture ||
this.actualWidth != this._previousActualWidth ||
this.actualHeight != this._previousActualHeight)
{
this._previousActualWidth = this.actualWidth;
this._previousActualHeight = this.actualHeight;
var hasText:Boolean = this._text.length > 0;
if(hasText)
{
if(this._useSnapshotDelayWorkaround)
{
//we need to wait a frame for the TextField to render
//properly. sometimes two, and this is a known issue.
this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
else
{
this.refreshSnapshot();
}
}
if(this.textSnapshot)
{
this.textSnapshot.visible = hasText && this._snapshotWidth > 0 && this._snapshotHeight > 0;
}
}
}
/**
* If the component's dimensions have not been set explicitly, it will
* measure its content and determine an ideal size for itself. If the
* explicitWidth
or explicitHeight
member
* variables are set, those value will be used without additional
* measurement. If one is set, but not the other, the dimension with the
* explicit value will not be measured, but the other non-explicit
* dimension will still need measurement.
*
* Calls setSizeInternal()
to set up the
* actualWidth
and actualHeight
member
* variables used for layout.
*
* Meant for internal use, and subclasses may override this function
* with a custom implementation.
*/
protected function autoSizeIfNeeded():Boolean
{
var needsWidth:Boolean = this._explicitWidth !== this._explicitWidth; //isNaN
var needsHeight:Boolean = this._explicitHeight !== this._explicitHeight; //isNaN
if(!needsWidth && !needsHeight)
{
return false;
}
this.measure(HELPER_POINT);
return this.setSizeInternal(HELPER_POINT.x, HELPER_POINT.y, false);
}
/**
* @private
*/
protected function measureNativeFilters(bitmapData:BitmapData, result:Rectangle = null):Rectangle
{
if(!result)
{
result = new Rectangle();
}
var resultX:Number = 0;
var resultY:Number = 0;
var resultWidth:Number = 0;
var resultHeight:Number = 0;
var filterCount:int = this._nativeFilters.length;
for(var i:int = 0; i < filterCount; i++)
{
var filter:BitmapFilter = this._nativeFilters[i];
var filterRect:Rectangle = bitmapData.generateFilterRect(bitmapData.rect, filter);
var filterX:Number = filterRect.x;
var filterY:Number = filterRect.y;
var filterWidth:Number = filterRect.width;
var filterHeight:Number = filterRect.height;
if(resultX > filterX)
{
resultX = filterX;
}
if(resultY > filterY)
{
resultY = filterY;
}
if(resultWidth < filterWidth)
{
resultWidth = filterWidth;
}
if(resultHeight < filterHeight)
{
resultHeight = filterHeight;
}
}
result.setTo(resultX, resultY, resultWidth, resultHeight);
return result;
}
/**
* @private
*/
protected function refreshTextFormat():void
{
var textFormat:TextFormat;
if(this._stateContext && this._textFormatForState)
{
var currentState:String = this._stateContext.currentState;
if(currentState in this._textFormatForState)
{
textFormat = TextFormat(this._textFormatForState[currentState]);
}
}
if(!textFormat && !this._isEnabled && this._disabledTextFormat)
{
textFormat = this._disabledTextFormat;
}
if(!textFormat && this._selectedTextFormat &&
this._stateContext is IToggle && IToggle(this._stateContext).isSelected)
{
textFormat = this._selectedTextFormat;
}
if(!textFormat)
{
//let's fall back to using Starling's embedded mini font if no
//text format has been specified
if(!this._textFormat)
{
this._textFormat = new TextFormat();
}
textFormat = this._textFormat;
}
this.currentTextFormat = textFormat;
}
/**
* @private
*/
protected function createTextureOnRestoreCallback(snapshot:Image):void
{
var self:TextFieldTextRenderer = this;
var texture:Texture = snapshot.texture;
texture.root.onRestore = function():void
{
var scaleFactor:Number = Starling.contentScaleFactor;
HELPER_MATRIX.identity();
HELPER_MATRIX.scale(scaleFactor, scaleFactor);
var bitmapData:BitmapData = self.drawTextFieldRegionToBitmapData(
snapshot.x, snapshot.y, texture.nativeWidth, texture.nativeHeight);
texture.root.uploadBitmapData(bitmapData);
bitmapData.dispose();
};
}
/**
* @private
*/
protected function drawTextFieldRegionToBitmapData(textFieldX:Number, textFieldY:Number,
bitmapWidth:Number, bitmapHeight:Number, bitmapData:BitmapData = null):BitmapData
{
var scaleFactor:Number = Starling.contentScaleFactor;
var clipWidth:Number = this._snapshotVisibleWidth - textFieldX;
var clipHeight:Number = this._snapshotVisibleHeight - textFieldY;
if(!bitmapData || bitmapData.width != bitmapWidth || bitmapData.height != bitmapHeight)
{
if(bitmapData)
{
bitmapData.dispose();
}
bitmapData = new BitmapData(bitmapWidth, bitmapHeight, true, 0x00ff00ff);
}
else
{
//clear the bitmap data and reuse it
bitmapData.fillRect(bitmapData.rect, 0x00ff00ff);
}
var gutterPositionOffset:Number = 2 * scaleFactor;
if(this._useGutter)
{
gutterPositionOffset = 0;
}
HELPER_MATRIX.tx = -(textFieldX + gutterPositionOffset) - this._textSnapshotOffsetX;
HELPER_MATRIX.ty = -(textFieldY + gutterPositionOffset) - this._textSnapshotOffsetY;
HELPER_RECTANGLE.setTo(0, 0, clipWidth, clipHeight);
bitmapData.draw(this.textField, HELPER_MATRIX, null, null, HELPER_RECTANGLE);
return bitmapData;
}
/**
* @private
*/
protected function refreshSnapshot():void
{
if(this._snapshotWidth <= 0 || this._snapshotHeight <= 0)
{
return;
}
var scaleFactor:Number = Starling.contentScaleFactor;
if(this._updateSnapshotOnScaleChange)
{
this.getTransformationMatrix(this.stage, HELPER_MATRIX);
var globalScaleX:Number = matrixToScaleX(HELPER_MATRIX);
var globalScaleY:Number = matrixToScaleY(HELPER_MATRIX);
}
HELPER_MATRIX.identity();
HELPER_MATRIX.scale(scaleFactor, scaleFactor);
if(this._updateSnapshotOnScaleChange)
{
HELPER_MATRIX.scale(globalScaleX, globalScaleY);
}
var totalBitmapWidth:Number = this._snapshotWidth;
var totalBitmapHeight:Number = this._snapshotHeight;
var xPosition:Number = 0;
var yPosition:Number = 0;
var bitmapData:BitmapData;
var snapshotIndex:int = -1;
do
{
var currentBitmapWidth:Number = totalBitmapWidth;
if(currentBitmapWidth > this._maxTextureDimensions)
{
currentBitmapWidth = this._maxTextureDimensions;
}
do
{
var currentBitmapHeight:Number = totalBitmapHeight;
if(currentBitmapHeight > this._maxTextureDimensions)
{
currentBitmapHeight = this._maxTextureDimensions;
}
bitmapData = this.drawTextFieldRegionToBitmapData(xPosition, yPosition,
currentBitmapWidth, currentBitmapHeight, bitmapData);
var newTexture:Texture;
if(!this.textSnapshot || this._needsNewTexture)
{
//skip Texture.fromBitmapData() because we don't want
//it to create an onRestore function that will be
//immediately discarded for garbage collection.
newTexture = Texture.empty(bitmapData.width / scaleFactor, bitmapData.height / scaleFactor,
true, false, false, scaleFactor);
newTexture.root.uploadBitmapData(bitmapData);
}
var snapshot:Image = null;
if(snapshotIndex >= 0)
{
if(!this.textSnapshots)
{
this.textSnapshots = new [];
}
else if(this.textSnapshots.length > snapshotIndex)
{
snapshot = this.textSnapshots[snapshotIndex]
}
}
else
{
snapshot = this.textSnapshot;
}
if(!snapshot)
{
snapshot = new Image(newTexture);
this.addChild(snapshot);
}
else
{
if(this._needsNewTexture)
{
snapshot.texture.dispose();
snapshot.texture = newTexture;
snapshot.readjustSize();
}
else
{
//this is faster, if we haven't resized the bitmapdata
var existingTexture:Texture = snapshot.texture;
existingTexture.root.uploadBitmapData(bitmapData);
}
}
if(newTexture)
{
this.createTextureOnRestoreCallback(snapshot);
}
if(snapshotIndex >= 0)
{
this.textSnapshots[snapshotIndex] = snapshot;
}
else
{
this.textSnapshot = snapshot;
}
snapshot.x = xPosition / scaleFactor;
snapshot.y = yPosition / scaleFactor;
if(this._updateSnapshotOnScaleChange)
{
snapshot.scaleX = 1 / globalScaleX;
snapshot.scaleY = 1 / globalScaleY;
snapshot.x /= globalScaleX;
snapshot.y /= globalScaleY;
}
snapshotIndex++;
yPosition += currentBitmapHeight;
totalBitmapHeight -= currentBitmapHeight;
}
while(totalBitmapHeight > 0)
xPosition += currentBitmapWidth;
totalBitmapWidth -= currentBitmapWidth;
yPosition = 0;
totalBitmapHeight = this._snapshotHeight;
}
while(totalBitmapWidth > 0)
bitmapData.dispose();
if(this.textSnapshots)
{
var snapshotCount:int = this.textSnapshots.length;
for(var i:int = snapshotIndex; i < snapshotCount; i++)
{
snapshot = this.textSnapshots[i];
snapshot.texture.dispose();
snapshot.removeFromParent(true);
}
if(snapshotIndex == 0)
{
this.textSnapshots = null;
}
else
{
this.textSnapshots.length = snapshotIndex;
}
}
if(this._updateSnapshotOnScaleChange)
{
this._lastGlobalScaleX = globalScaleX;
this._lastGlobalScaleY = globalScaleY;
}
this._needsNewTexture = false;
}
/**
* @private
*/
protected function enterFrameHandler(event:Event):void
{
this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
this.refreshSnapshot();
}
/**
* @private
*/
protected function stateContext_stateChangeHandler(event:Event):void
{
this.invalidate(INVALIDATION_FLAG_STATE);
}
}
}