You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by al...@apache.org on 2018/05/17 07:21:12 UTC

[royale-asjs] branch feature/MXRoyale updated: Spark Label.as Added

This is an automated email from the ASF dual-hosted git repository.

alinakazi pushed a commit to branch feature/MXRoyale
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git


The following commit(s) were added to refs/heads/feature/MXRoyale by this push:
     new 817ba11  Spark Label.as Added
817ba11 is described below

commit 817ba11ffbc785507cf6376dded12563010fc67d
Author: alinakazi <AL...@GMAIL.COM>
AuthorDate: Thu May 17 00:21:10 2018 -0700

    Spark Label.as Added
---
 .../src/main/royale/spark/components/Label.as      | 1649 ++++++++++++++++++++
 1 file changed, 1649 insertions(+)

diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Label.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Label.as
new file mode 100644
index 0000000..ba1bc95
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Label.as
@@ -0,0 +1,1649 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 spark.components
+{
+
+/* import flash.display.DisplayObject;
+import flash.display.DisplayObjectContainer;
+import flash.display.Graphics;
+import flash.display.Shape;
+import flash.geom.Rectangle;
+import flash.text.TextFormat;
+import flash.text.engine.EastAsianJustifier;
+import flash.text.engine.ElementFormat;
+import flash.text.engine.FontDescription;
+import flash.text.engine.FontLookup;
+import flash.text.engine.FontMetrics;
+import flash.text.engine.Kerning;
+import flash.text.engine.LineJustification;
+import flash.text.engine.SpaceJustifier;
+import flash.text.engine.TextBaseline;
+import flash.text.engine.TextBlock;
+import flash.text.engine.TextElement;
+import flash.text.engine.TextLine;
+import flash.text.engine.TypographicCase;
+
+import flashx.textLayout.compose.ISWFContext;
+import flashx.textLayout.compose.TextLineRecycler;
+import flashx.textLayout.formats.BaselineShift;
+import flashx.textLayout.formats.TLFTypographicCase; */
+
+//import mx.core.IEmbeddedFontRegistry;
+//import mx.core.IFlexModuleFactory;
+import mx.core.IUIComponent;
+//import mx.core.Singleton;
+import mx.core.mx_internal;
+
+import spark.components.supportClasses.TextBase;
+//import spark.utils.TextUtil;
+
+use namespace mx_internal;
+
+//--------------------------------------
+//  Styles
+//--------------------------------------
+
+//include "../styles/metadata/BasicInheritingTextStyles.as"
+//include "../styles/metadata/BasicNonInheritingTextStyles.as"
+
+//--------------------------------------
+//  Other metadata
+//--------------------------------------
+
+[DefaultProperty("text")]
+
+//[IconFile("Label.png")]
+
+/**
+ *  Label is a low-level UIComponent that can render
+ *  one or more lines of uniformly-formatted text.
+ *  The text to be displayed is determined by the
+ *  <code>text</code> property inherited from TextBase.
+ *  The formatting of the text is specified by the element's CSS styles,
+ *  such as <code>fontFamily</code> and <code>fontSize</code>.
+ *
+ *  <p>Label uses of the 
+ *  Flash Text Engine (FTE) in Flash Player to provide high-quality
+ *  international typography.
+ *  Because Label is fast and lightweight, it is especially suitable
+ *  for use cases that involve rendering many small pieces of non-interactive
+ *  text, such as item renderers and labels in Button skins.</p>
+ *
+ *  <p>The Spark architecture provides three text "primitives" -- 
+ *  Label, RichText, and RichEditableText --
+ *  as part of its pay-only-for-what-you-need philosophy.
+ *  Label is the fastest and most lightweight,
+ *  but is limited in its capabilities: no complex formatting,
+ *  no scrolling, no selection, no editing, and no hyperlinks.
+ *  RichText and RichEditableText are built on the Text Layout
+ *  Framework (TLF) library, rather than on FTE.
+ *  RichText adds the ability to render rich HTML-like text
+ *  with complex formatting, but is still completely non-interactive.
+ *  RichEditableText is the slowest and heaviest,
+ *  but can do it all: it supports scrolling with virtualized TextLines,
+ *  selection, editing, hyperlinks, and images loaded from URLs.
+ *  You should use the fastest one that meets your needs.</p>
+ *
+ *  <p>The Spark Label control is similar to the MX Label control, mx.controls.Label.
+ *  The most important differences are:
+ *  <ul>
+ *    <li>Spark Label uses FTE, the player's new text engine,
+ *        while MX Label uses the TextField class.</li>
+ *    <li>Spark Label offers better typography, and better support
+ *        for international languages, than MX Label.</li>
+ *    <li>Spark Label can display multiple lines, which MX Label cannot.</li>
+ *    <li>MX Label can display a limited subset of HTML,
+ *        while Spark Label can only display text with uniform formatting.</li>
+ *    <li>MX Label can be made selectable, while Spark Label cannot.</li>
+ *  </ul></p>
+ *
+ *  <p>In Spark Label, three character sequences are recognized
+ *  as explicit line breaks: CR (<code>"\r"</code>), LF (<code>"\n"</code>),
+ *  and CR+LF (<code>"\r\n"</code>).</p>
+ *
+ *  <p>If you don't specify any kind of width for a Label,
+ *  then the longest line, as determined by these explicit line breaks,
+ *  determines the width of the Label.</p>
+ *
+ *  <p>If you do specify some kind of width, then the specified text is
+ *  word-wrapped at the right edge of the component's bounds, because the
+ *  default value of the <code>lineBreak</code> style is <code>"toFit"</code>.
+ *  If the text extends below the bottom of the component,
+ *  it is clipped.</p>
+ *
+ *  <p>To disable this automatic wrapping, set the <code>lineBreak</code>
+ *  style to <code>"explicit"</code>. Then lines are broken only where
+ *  the <code>text</code> contains an explicit line break,
+ *  and the ends of lines extending past the right edge is clipped.</p>
+ *
+ *  <p>If you have more text than you have room to display it,
+ *  Label can truncate the text for you.
+ *  Truncating text means replacing excess text
+ *  with a truncation indicator such as "...".
+ *  See the inherited properties <code>maxDisplayedLines</code>
+ *  and <code>isTruncated</code>.</p>
+ *
+ *  <p>You can control the line spacing with the <code>lineHeight</code> style.
+ *  You can horizontally and vertically align the text within the element's
+ *  bounds using the <code>textAlign</code>, <code>textAlignLast</code>,
+ *  and <code>verticalAlign</code> styles.
+ *  You can inset the text from the element's edges using the
+ *  <code>paddingLeft</code>, <code>paddingTop</code>, 
+ *  <code>paddingRight</code>, and <code>paddingBottom</code> styles.</p>
+ *
+ *  <p>By default a Label has no background,
+ *  but you can draw one using the <code>backgroundColor</code>
+ *  and <code>backgroundAlpha</code> styles.
+ *  Borders are not supported.
+ *  If you need a border, or a more complicated background, use a separate
+ *  graphic element, such as a Rect, behind the Label.</p>
+ *
+ *  <p>Label supports displaying left-to-right (LTR) text such as French,
+ *  right-to-left (RTL) text such as Arabic, and bidirectional text
+ *  such as a French phrase inside of an Arabic paragraph.
+ *  If the predominant text direction is right-to-left,
+ *  set the <code>direction</code> style to <code>"rtl"</code>.
+ *  The <code>textAlign</code> style defaults to <code>"start"</code>,
+ *  which makes the text left-aligned when <code>direction</code>
+ *  is <code>"ltr"</code> and right-aligned when <code>direction</code>
+ *  is <code>"rtl"</code>.
+ *  To get the opposite alignment,
+ *  set <code>textAlign</code> to <code>"end"</code>.</p>
+ *
+ *  <p>Label uses the TextBlock class in the Flash Text Engine
+ *  to create one or more TextLine objects to statically display
+ *  its text String in the format determined by its CSS styles.
+ *  For performance, its TextLines do not contain information
+ *  about individual glyphs; for more info, see
+ *  flash.text.engine.TextLineValidity.STATIC.</p>
+ *
+ *  <p>The Label control has the following default characteristics:</p>
+ *  <table class="innertable">
+ *     <tr><th>Characteristic</th><th>Description</th></tr>
+ *     <tr><td>Default size</td><td>0 pixels wide by 12 pixels high if it contains no text, 
+ *        and large enough ti display the text if it does</td></tr>
+ *     <tr><td>Minimum size</td><td>0 pixels</td></tr>
+ *     <tr><td>Maximum size</td><td>10000 pixels wide and 10000 pixels high</td></tr>
+ *  </table>
+ *
+ *  @mxml <p>The <code>&lt;s:Label&gt;</code> tag inherits all of the tag 
+ *  attributes of its superclass and adds the following tag attributes:</p>
+ *
+ *  <pre>
+ *  &lt;s:Label 
+ *    <strong>Styles</strong>
+ *    alignmentBaseline="baseline"
+ *    baselineShift="0"
+ *    cffHinting="0.0"
+ *    color="0x000000"
+ *    digitCase="default"
+ *    digitWidth="default"
+ *    direction="ltr"
+ *    dominantBaseline="auto"
+ *    fontFamily="Arial"
+ *    fontLookup="embeddedCFF"
+ *    fontSize="12"
+ *    fontStyle="normal"
+ *    fontWeight="normal"
+ *    justificationRule="auto"
+ *    justificationStyle="auto"
+ *    kerning="false"
+ *    ligatureLevel="common"
+ *    lineBreak="toFit"
+ *    lineHeight="120%"
+ *    lineThrough="false"
+ *    locale="en"
+ *    paddingBottom="0"
+ *    paddingLeft="0"
+ *    paddingRight="0"
+ *    paddingTop="0"
+ *    renderingMode="cff"
+ *    textAlign="start"
+ *    textAlignLast="start"
+ *    textAlpha="1"
+ *    textDecoration="start"
+ *    textJustify="interWord"
+ *    trackingLeft="0"
+ *    trackingRight="00"
+ *    typographicCase="default"
+ *    verticalAlign="top"
+ *  /&gt;
+ *  </pre>
+ *
+ *  @see spark.components.RichEditableText
+ *  @see spark.components.RichText
+ *  @see flash.text.engine.TextLineValidity#STATIC
+ *
+ *  @includeExample examples/LabelExample.mxml
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 1.5
+ *  @productversion Royale 0.9.4
+ */
+public class Label extends TextBase
+{
+   // include "../core/Version.as";
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class initialization
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    /* private static function initClass():void
+    {
+        staticTextBlock = new TextBlock();
+        
+        staticTextElement = new TextElement();
+        
+        staticSpaceJustifier = new SpaceJustifier();
+        
+        staticEastAsianJustifier = new EastAsianJustifier();
+        
+        if ("recreateTextLine" in staticTextBlock)
+            recreateTextLine = staticTextBlock["recreateTextLine"];
+    }
+    
+    initClass(); */
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class variables
+    //
+    //--------------------------------------------------------------------------
+        
+    // 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;
+
+    /**
+     *  @private
+     */
+   // private static var staticTextElement:TextElement;
+
+    /**
+     *  @private
+     */
+  //  private static var staticSpaceJustifier:SpaceJustifier;
+
+    /**
+     *  @private
+     */
+  //  private static var staticEastAsianJustifier:EastAsianJustifier;
+    
+    /**
+     *  @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;
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class properties
+    //
+    //--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  embeddedFontRegistry
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the _embeddedFontRegistry property.
+     *  Note: This gets initialized on first access,
+     *  not when this class is initialized, in order to ensure
+     *  that the Singleton registry has already been initialized.
+     */
+ //   private static var _embeddedFontRegistry:IEmbeddedFontRegistry;
+
+    /**
+     *  @private
+     *  A reference to the embedded font registry.
+     *  Single registry in the system.
+     *  Used to look up the moduleFactory of a font.
+     */
+	/* private static function get embeddedFontRegistry():IEmbeddedFontRegistry
+    {
+        if (!_embeddedFontRegistry)
+        {
+            _embeddedFontRegistry = IEmbeddedFontRegistry(
+                Singleton.getInstance("mx.core::IEmbeddedFontRegistry"));
+        }
+
+        return _embeddedFontRegistry;
+    } */
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class methods
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+   /*  private static function getNumberOrPercentOf(value:Object,
+                                                 n:Number):Number
+    {
+        // If 'value' is a Number like 10.5, return it.
+        if (value is Number)
+            return Number(value);
+
+        // If 'value' is a percentage String like "10.5%",
+        // return that percentage of 'n'.
+        if (value is String)
+        {
+            var len:int = String(value).length;
+            if (len >= 1 && value.charAt(len - 1) == "%")
+            {
+                var percent:Number = Number(value.substring(0, len - 1));
+                return percent / 100 * n;
+            }
+        }
+
+        // Otherwise, return NaN.
+        return NaN;
+    } */
+
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Constructor. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 1.5
+     *  @productversion Royale 0.9.4
+     */
+    public function Label()
+    {
+        super();
+		
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Variables
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Holds the last recorded value of the module factory
+     *  used to create the font.
+     */
+    //private var embeddedFontContext:IFlexModuleFactory;
+    
+    /**
+     *  @private
+     *  When we render the text using FTE, this object represents the formatting 
+     *  for our text element(s). Every time format related styles change, this 
+     *  object is released because it is invalid. It is regenerated just in time 
+     *  to render the text.
+     */
+    //private var elementFormat:ElementFormat;
+
+    //--------------------------------------------------------------------------
+    //
+    //  Overidden Methods: ISimpleStyleClient
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    /* override public function stylesInitialized():void
+    {
+        super.stylesInitialized();
+        elementFormat = null;
+    } */
+    
+    /**
+     *  @private
+     */
+    /* override public function styleChanged(styleProp:String):void
+    {
+        super.styleChanged(styleProp);
+        elementFormat = null;
+    } */
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden methods: TextBase
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     *  This helper method is used by measure() and updateDisplayList().
+     *  It composes TextLines to render the 'text' String,
+     *  using the staticTextBlock as a factory,
+     *  and using the 'width' and 'height' parameters to define the size
+     *  of the composition rectangle, with NaN meaning "no limit".
+     *  It stops composing when the composition rectangle has been filled.
+     *  Returns true if all lines were composed, otherwise false.
+     */
+    /* override mx_internal function composeTextLines(width:Number = NaN,
+                                                   height:Number = NaN):Boolean
+    {
+        super.composeTextLines(width, height);
+        
+        if (!elementFormat)
+            elementFormat = createElementFormat(); 
+            
+        // Set the composition bounds to be used by createTextLines().
+        // If the width or height is NaN, it will be computed by this method
+        // by the time it returns.
+        // The bounds are then used by the addTextLines() method
+        // to determine the isOverset flag.
+        // The composition bounds are also reported by the measure() method.
+        bounds.x = 0;
+        bounds.y = 0;
+        bounds.width = width;
+        bounds.height = height;
+
+        // Remove the TextLines from the container and then release them for
+        // reuse, if supported by the player.
+        removeTextLines();
+        releaseTextLines();
+        
+        // Create the TextLines.
+        var allLinesComposed:Boolean = createTextLines(elementFormat);
+        
+        // Need truncation if all the following are true
+        // - there is text (even if there is no text there is may be padding
+        //       which may not fit and the text would be reported as truncated)
+        // - truncation options exist (0=no trunc, -1=fill up bounds then trunc,
+        //      n=n lines then trunc)
+        // - compose width is specified
+        // - content doesn't fit
+        var lb:String = getStyle("lineBreak");
+        if (text != null && text.length > 0 &&
+            maxDisplayedLines &&
+            !doesComposedTextFit(height, width, allLinesComposed, maxDisplayedLines, lb))
+        {
+            truncateText(width, height, lb);
+        }
+        
+        // Detach the TextLines from the TextBlock that created them.
+        releaseLinesFromTextBlock();
+                                                       
+        // Add the new text lines to the container.
+        addTextLines();
+
+        // Figure out if a scroll rect is needed.
+        isOverset = isTextOverset(width, height);
+        
+        // Just recomposed so reset.
+        invalidateCompose = false;     
+        
+        return allLinesComposed;           
+    } */
+
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Creates an ElementFormat (and its FontDescription)
+     *  based on the Label's CSS styles.
+     *  These must be recreated each time because FTE
+     *  does not allow them to be reused.
+     *  As a side effect, this method also sets embeddedFontContext
+     *  so that we know which SWF should be used to create TextLines.
+     *  (TextLines using an embedded font must be created in the SWF
+     *  where the font is.)
+     */
+    /* private function createElementFormat():ElementFormat
+    {
+        // When you databind to a text formatting style on a Label,
+        // as in <Label fontFamily="{fontCombo.selectedItem}"/>
+        // the databinding can cause the style to be set to null.
+        // Setting null values for properties in an FTE FontDescription
+        // or ElementFormat throw an error, so the following code does
+        // null-checking on the problematic properties.
+
+        var s:String;
+        
+        // If the CSS styles for this component specify an embedded font,
+        // embeddedFontContext will be set to the module factory that
+        // should create TextLines (since they must be created in the
+        // SWF where the embedded font is.)
+        // Otherwise, this will be null.
+        embeddedFontContext = getEmbeddedFontContext();
+
+        // Fill out a FontDescription based on the CSS styles.
+        
+        var fontDescription:FontDescription = new FontDescription();
+        
+        s = getStyle("cffHinting");
+        if (s != null)
+            fontDescription.cffHinting = s;
+        
+        s = getStyle("fontLookup");
+        if (s != null)
+        {
+            // FTE understands only "device" and "embeddedCFF"
+            // for fontLookup. But Flex allows this style to be
+            // set to "auto", in which case we automatically
+            // determine it based on whether the CSS styles
+            // specify an embedded font.
+            if (s == "auto")
+            {
+                s = embeddedFontContext ?
+                    FontLookup.EMBEDDED_CFF :
+                    FontLookup.DEVICE;
+            }
+            else if (s == FontLookup.EMBEDDED_CFF && !embeddedFontContext)
+            {
+                // If the embedded font isn't found, fall back to device font,
+                // before falling back to the player's default font.
+                s = FontLookup.DEVICE;
+            }
+            fontDescription.fontLookup = s;
+        }
+        
+        s = getStyle("fontFamily");
+        if (s != null)
+            fontDescription.fontName = s;
+        
+        s = getStyle("fontStyle");
+        if (s != null)
+            fontDescription.fontPosture = s;
+        
+        s = getStyle("fontWeight");
+        if (s != null)
+            fontDescription.fontWeight = s;
+            
+        s = getStyle("renderingMode");
+        if (s != null)
+            fontDescription.renderingMode = s;
+        
+        // Fill our an ElementFormat based on the CSS styles.
+        
+        var elementFormat:ElementFormat = new ElementFormat();
+        
+        // Out of order so it can be used by baselineShift.
+        elementFormat.fontSize = getStyle("fontSize");
+        
+        s = getStyle("alignmentBaseline");
+        if (s != null)
+            elementFormat.alignmentBaseline = s;
+            
+        elementFormat.alpha = getStyle("textAlpha");
+            
+        setBaselineShift(elementFormat);
+        
+        // Note: Label doesn't support a breakOpportunity style,
+        // so we leave elementFormat.breakOpportunity with its
+        // default value of "auto".
+            
+        elementFormat.color = getStyle("color");
+        
+        s = getStyle("digitCase");
+        if (s != null)
+            elementFormat.digitCase = s;
+            
+        s = getStyle("digitWidth");
+        if (s != null)
+            elementFormat.digitWidth = s;
+            
+        s = getStyle("dominantBaseline");
+        if (s != null)
+        {
+            // TLF adds the concept of a locale-based "auto" setting for
+            // dominantBaseline, so we support that in Label as well
+            // so that "auto" can be used in the global selector.
+            // TLF's rule is that "auto" means "ideographicCenter"
+            // for Japanese and Chinese locales and "roman" for other locales.
+            // (See TLF's LocaleUtil, which we avoid linking in here.)
+            if (s == "auto")
+            {
+                s = TextBaseline.ROMAN;
+                var locale:String = getStyle("locale");
+                if (locale != null)
+                {
+                    var lowercaseLocale:String = locale.toLowerCase();
+                    if (lowercaseLocale.indexOf("ja") == 0 ||
+                        lowercaseLocale.indexOf("zh") == 0)
+                    {
+                        s = TextBaseline.IDEOGRAPHIC_CENTER;
+                    }
+                }
+            }
+            elementFormat.dominantBaseline = s;
+        }
+            
+        elementFormat.fontDescription = fontDescription;
+        
+        setKerning(elementFormat);
+
+        s = getStyle("ligatureLevel");
+        if (s != null)
+            elementFormat.ligatureLevel = s;
+        
+        s = getStyle("locale");
+        if (s != null)
+            elementFormat.locale = s;
+        
+        setTracking(elementFormat);
+
+        setTypographicCase(elementFormat);
+        
+        return elementFormat;
+    } */
+
+    /**
+     *  @private
+     */
+    /* private function setBaselineShift(elementFormat:ElementFormat):void
+    {
+        var baselineShift:* = getStyle("baselineShift");
+        var fontSize:Number = elementFormat.fontSize;
+        
+        if (baselineShift == BaselineShift.SUPERSCRIPT || 
+            baselineShift == BaselineShift.SUBSCRIPT)
+        {
+            var fontMetrics:FontMetrics;
+            if (embeddedFontContext)
+                fontMetrics = embeddedFontContext.callInContext(elementFormat.getFontMetrics, elementFormat, null);
+            else
+                fontMetrics = elementFormat.getFontMetrics();
+            if (baselineShift == BaselineShift.SUPERSCRIPT)
+            {
+                elementFormat.baselineShift = 
+                    fontMetrics.superscriptOffset * fontSize;
+                elementFormat.fontSize = fontMetrics.superscriptScale * fontSize;
+            }
+            else // it's subscript
+            {
+                elementFormat.baselineShift = 
+                    fontMetrics.subscriptOffset * fontSize;
+                elementFormat.fontSize = fontMetrics.subscriptScale * fontSize;
+            }
+        }			
+        else
+        {
+            // TLF will throw a range error if percentage not between
+            // -1000% and 1000%.  Label does not.
+            baselineShift = 
+                getNumberOrPercentOf(baselineShift, fontSize);
+            if (!isNaN(baselineShift))
+                elementFormat.baselineShift = -baselineShift;
+                    // Note: The negative sign is because, as in TLF,
+                    // we want a positive number to shift the baseline up,
+                    // whereas FTE does it the opposite way.
+                    // In FTE, a positive baselineShift increases
+                    // the y coordinate of the baseline, which is
+                    // mathematically appropriate, but unintuitive.    
+        }
+    } */
+    
+    /**
+     *  @private
+     */
+    /* private function setKerning(elementFormat:ElementFormat):void
+    {
+        var kerning:Object = getStyle("kerning");
+        
+        // In Halo components based on TextField,
+        // kerning is supposed to be true or false.
+        // The default in TextField and Flex 3 is false
+        // because kerning doesn't work for device fonts
+        // and is slow for embedded fonts.
+        // In Spark components based on TLF and FTE,
+        // kerning is "auto", "on", or, "off".
+        // The default in TLF and FTE is "auto"
+        // (which means kern non-Asian characters)
+        // because kerning works even on device fonts
+        // and has miminal performance impact.
+        // Since a CSS selector or parent container
+        // can affect both Halo and Spark components,
+        // we need to map true to "on" and false to "off"
+        // here and in Label.
+        // For Halo components, UITextField and UIFTETextField
+        // do the opposite mapping
+        // of "auto" and "on" to true and "off" to false.
+        // We also support a value of "default"
+        // (which we set in the global selector)
+        // to mean "auto" for Spark and false for Halo
+        // to get the recommended behavior in both sets of components.
+        if (kerning === "default")
+            kerning = Kerning.AUTO;
+        else if (kerning === true)
+            kerning = Kerning.ON;
+        else if (kerning === false)
+            kerning = Kerning.OFF;
+        
+        if (kerning != null)
+           elementFormat.kerning = String(kerning);
+    } */
+
+    /**
+     *  @private
+     */
+    /* private function setTracking(elementFormat:ElementFormat):void
+    {
+        var trackingLeft:Object = getStyle("trackingLeft");
+        var trackingRight:Object = getStyle("trackingRight");
+        
+        var value:Number;
+        var fontSize:Number = elementFormat.fontSize;
+       
+        value = getNumberOrPercentOf(trackingLeft, fontSize);
+        if (!isNaN(value))
+            elementFormat.trackingLeft = value;
+
+        value = getNumberOrPercentOf(trackingRight, fontSize);
+        if (!isNaN(value))
+            elementFormat.trackingRight = value;
+    } */
+
+    /**
+     *  @private
+     */
+    /* private function setTypographicCase(elementFormat:ElementFormat):void
+    {
+        var s:String = getStyle("typographicCase");
+        if (s != null)
+        {
+            switch (s)
+            {
+                case TLFTypographicCase.LOWERCASE_TO_SMALL_CAPS:
+                {
+                    elementFormat.typographicCase = 
+                        TypographicCase.CAPS_AND_SMALL_CAPS;
+                    break;
+                }
+                case TLFTypographicCase.CAPS_TO_SMALL_CAPS:
+                {
+                    elementFormat.typographicCase = TypographicCase.SMALL_CAPS;
+                    break;
+                }
+                default:
+                {
+                    // Others map directly so handle it in the default case.
+                    elementFormat.typographicCase = s;
+                    break;
+                }
+            }
+        }        
+    } */
+
+    
+    /**
+     *  @private
+     *  Stuffs the specified 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(elementFormat:ElementFormat):Boolean
+    {
+        // Get CSS styles that affect a TextBlock and its justifier.
+        var direction:String = getStyle("direction");
+        var justificationRule:String = getStyle("justificationRule");
+        var justificationStyle:String = getStyle("justificationStyle");
+        var textAlign:String = getStyle("textAlign");
+        var textAlignLast:String = getStyle("textAlignLast");
+        var textJustify:String = getStyle("textJustify");
+
+        // TLF adds the concept of a locale-based "auto" setting for
+        // justificationRule and justificationStyle, so we support
+        // that in Label as well so that "auto" can be used
+        // in the global selector.
+        // TLF's rule is that "auto" for justificationRule means "eastAsian"
+        // for Japanese and Chinese locales and "space" for other locales,
+        // and that "auto" for justificationStyle (which only affects
+        // the EastAsianJustifier) always means "pushInKinsoku".
+        // (See TLF's LocaleUtil, which we avoid linking in here.)
+        if (justificationRule == "auto")
+        {
+            justificationRule = "space";
+            var locale:String = getStyle("locale");
+            if (locale != null)
+            {
+                var lowercaseLocale:String = locale.toLowerCase();
+                if (lowercaseLocale.indexOf("ja") == 0 ||
+                    lowercaseLocale.indexOf("zh") == 0)
+                {
+                    justificationRule = "eastAsian";
+                }
+            }
+        }
+        if (justificationStyle == "auto")
+            justificationStyle = "pushInKinsoku";
+
+        // 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 = text != null && text.length > 0 ? text : "\u2029";
+        staticTextElement.elementFormat = elementFormat;
+        staticTextBlock.content = staticTextElement;
+
+        // And its bidiLevel.
+        staticTextBlock.bidiLevel = direction == "ltr" ? 0 : 1;
+
+        // And its justifier.
+        var lineJustification:String;
+        if (textAlign == "justify")
+        {
+            lineJustification = textAlignLast == "justify" ?
+                                LineJustification.ALL_INCLUDING_LAST :
+                                LineJustification.ALL_BUT_LAST;
+        }
+        else
+        {
+            lineJustification = LineJustification.UNJUSTIFIED;
+        }
+        if (justificationRule == "space")
+        {
+            staticSpaceJustifier.lineJustification = lineJustification;
+            staticSpaceJustifier.letterSpacing = textJustify == "distribute";
+            staticTextBlock.textJustifier = staticSpaceJustifier;
+        }
+        else
+        {
+            staticEastAsianJustifier.lineJustification = lineJustification;
+            staticEastAsianJustifier.justificationStyle = justificationStyle;
+            
+            staticTextBlock.textJustifier = staticEastAsianJustifier;
+        }
+                
+        // Then create TextLines using this TextBlock.
+        return createTextLinesFromTextBlock(staticTextBlock, textLines, bounds);
+    } */
+
+    /**
+     *  @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.  This must be done after truncation
+     *  so that the composed lines can be broken into atoms to figure out
+     *  where the truncation indicator should be placed.
+     * 
+     *  Returns true if all the text was composed into textLines.
+     */
+    /* private function createTextLinesFromTextBlock(textBlock:TextBlock,
+                                                  textLines:Vector.<DisplayObject>,
+                                                  bounds:Rectangle):Boolean
+    {
+        // Start with 0 text lines.
+        releaseTextLines(textLines);
+           
+        // Get CSS styles for formats that we have to apply ourselves.
+        var direction:String = getStyle("direction");
+        var lineBreak:String = getStyle("lineBreak");
+        var lineHeight:Object = getStyle("lineHeight");
+        var lineThrough:Boolean = getStyle("lineThrough");
+        var paddingBottom:Number = getStyle("paddingBottom");
+        var paddingLeft:Number = getStyle("paddingLeft");
+        var paddingRight:Number = getStyle("paddingRight");
+        var paddingTop:Number = getStyle("paddingTop");
+        var textAlign:String = getStyle("textAlign");
+        var textAlignLast:String = getStyle("textAlignLast");
+        var textDecoration:String = getStyle("textDecoration");
+        var verticalAlign:String = getStyle("verticalAlign");
+
+        var innerWidth:Number = bounds.width - paddingLeft - paddingRight;
+        var innerHeight:Number = bounds.height - paddingTop - paddingBottom;
+                
+        var measureWidth:Boolean = isNaN(innerWidth);
+        if (measureWidth)
+            innerWidth = maxWidth;
+        
+        var maxLineWidth:Number = lineBreak == "explicit" ?
+                                  TextLine.MAX_LINE_WIDTH :
+                                  innerWidth;
+        
+        if (innerWidth < 0 || innerHeight < 0 || !textBlock)
+        {
+            bounds.width = 0;
+            bounds.height = 0;
+            return false;
+        }
+
+        var fontSize:Number = staticTextElement.elementFormat.fontSize;
+        var actualLineHeight:Number;
+        if (lineHeight is Number)
+        {
+            actualLineHeight = Number(lineHeight);
+        }
+        else if (lineHeight is String)
+        {
+            var len:int = lineHeight.length;
+            var percent:Number =
+                Number(String(lineHeight).substring(0, len - 1));
+            actualLineHeight = percent / 100 * fontSize;
+        }
+        if (isNaN(actualLineHeight))
+            actualLineHeight = 1.2 * fontSize;
+        
+        var maxTextWidth:Number = 0;
+        var totalTextHeight:Number = 0;
+        var n:int = 0;
+        var nextTextLine:TextLine;
+        var nextY:Number = 0;
+        var textLine:TextLine;
+        
+        var swfContext:ISWFContext = ISWFContext(embeddedFontContext);
+                    
+        // For truncation, need to know if all lines have been composed.
+        var createdAllLines:Boolean = false;
+        // sometimes we need to create an extra line in order to compute
+        // truncation
+        var extraLine:Boolean;
+        
+        // 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 top-left alignment.
+        while (true)
+        {
+            var recycleLine:TextLine = TextLineRecycler.getLineForReuse();
+            if (recycleLine)
+            {
+                if (swfContext)
+                {
+                    nextTextLine = swfContext.callInContext(
+                        textBlock["recreateTextLine"], textBlock,
+                        [ recycleLine, textLine, maxLineWidth ]);       
+                }        
+                else
+                {
+                    nextTextLine = recreateTextLine(
+                        recycleLine, textLine, maxLineWidth);
+                }  
+            }
+            else
+            {
+                if (swfContext)
+                {
+                    nextTextLine = swfContext.callInContext(
+                        textBlock.createTextLine, textBlock,
+                        [ textLine, maxLineWidth ]);
+                }
+                else
+                {
+                    nextTextLine = textBlock.createTextLine(
+                        textLine, maxLineWidth);
+                }
+            }
+            
+            if (!nextTextLine)
+            {
+                createdAllLines = !extraLine;
+                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.
+            nextY += (n == 0 ? nextTextLine.ascent : actualLineHeight);
+            
+            // If verticalAlign is top and the next line is completely outside 
+            // the rectangle, we're done.  If verticalAlign is middle or bottom
+            // then we need to compose all the lines so the alignment is done
+            // correctly.
+            if (verticalAlign == "top" && 
+                nextY - nextTextLine.ascent > innerHeight)
+            {
+                // make an extra line so we can compute truncation
+                if (!extraLine) 
+                    extraLine = true;
+                else
+                    break;
+            }
+
+            // We'll keep this line. Put it into the textLines array.
+            textLine = nextTextLine;
+            textLines[n++] = textLine;
+
+            // Assign its location based on left/top alignment.
+            // Its x position is 0 by default.
+            textLine.y = nextY;
+            
+            // Keep track of the maximum textWidth 
+            // and the accumulated textHeight of the TextLines.
+            maxTextWidth = Math.max(maxTextWidth, textLine.textWidth);
+            totalTextHeight += textLine.textHeight;
+
+            if (lineThrough || textDecoration == "underline")
+            {
+                // FTE doesn't render strikethroughs or 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 elementFormat:ElementFormat =
+                    TextElement(textBlock.content).elementFormat;
+                var fontMetrics:FontMetrics;
+                if (embeddedFontContext)
+                    fontMetrics = embeddedFontContext.callInContext(elementFormat.getFontMetrics, elementFormat, null);
+                else
+                    fontMetrics = elementFormat.getFontMetrics();
+                
+                var shape:Shape = new Shape();
+                var g:Graphics = shape.graphics;
+                if (lineThrough)
+                {
+                    g.lineStyle(fontMetrics.strikethroughThickness, 
+                                elementFormat.color, elementFormat.alpha);
+                    g.moveTo(0, fontMetrics.strikethroughOffset);
+                    g.lineTo(textLine.textWidth, fontMetrics.strikethroughOffset);
+                }
+                if (textDecoration == "underline")
+                {
+                    g.lineStyle(fontMetrics.underlineThickness, 
+                                elementFormat.color, elementFormat.alpha);
+                    g.moveTo(0, fontMetrics.underlineOffset);
+                    g.lineTo(textLine.textWidth, fontMetrics.underlineOffset);
+                }
+                
+                textLine.addChild(shape);
+            }
+        }
+
+        // At this point, n is the number of lines that fit
+        // and textLine is the last line that fit.
+
+        if (n == 0)
+        {
+            bounds.width = paddingLeft + paddingRight;
+            bounds.height = paddingTop + paddingBottom;
+            return false;
+        }
+        
+        // If not measuring the width, innerWidth remains the same since 
+        // alignment is done over the innerWidth not over the width of the
+        // text that was just composed.
+        if (measureWidth)
+            innerWidth = maxTextWidth;
+
+        if (isNaN(bounds.height))
+            innerHeight = textLine.y + textLine.descent;
+        
+        // Ensure we snap for consistent results.
+        innerWidth = Math.ceil(innerWidth);
+        innerHeight = Math.ceil(innerHeight);
+        
+        var leftAligned:Boolean = 
+            textAlign == "start" && direction == "ltr" ||
+            textAlign == "end" && direction == "rtl" ||
+            textAlign == "left" ||
+            textAlign == "justify";
+        var centerAligned:Boolean = textAlign == "center";
+        var rightAligned:Boolean =
+            textAlign == "start" && direction == "rtl" ||
+            textAlign == "end" && direction == "ltr" ||
+            textAlign == "right"; 
+
+        // Calculate loop constants for horizontal alignment.
+        var leftOffset:Number = bounds.left + paddingLeft;
+        var centerOffset:Number = leftOffset + innerWidth / 2;
+        var rightOffset:Number =  leftOffset + innerWidth;
+        
+        // Calculate loop constants for vertical alignment.
+        var topOffset:Number = bounds.top + paddingTop;
+        var bottomOffset:Number = innerHeight - (textLine.y + textLine.descent);
+        var middleOffset:Number = bottomOffset / 2;
+        bottomOffset += topOffset;
+        middleOffset += topOffset;
+        var leading:Number = (innerHeight - totalTextHeight) / (n - 1);
+        
+        var previousTextLine:TextLine;
+        var y:Number = 0;
+
+        var lastLineIsSpecial:Boolean =
+            textAlign == "justify" && createdAllLines;
+
+        var minX:Number = innerWidth;
+        var minY:Number = innerHeight;
+        var maxX:Number = 0;
+        
+        var clipping:Boolean = (n) ? (textLines[n - 1].y + TextLine(textLines[n - 1]).descent > innerHeight) : false;
+
+        // Reposition each line if necessary.
+        // based on the horizontal and vertical alignment.
+        for (var i:int = 0; i < n; i++)
+        {
+            textLine = TextLine(textLines[i]);
+
+            // If textAlign is "justify" and there is more than one line,
+            // the last one (if we created it) gets horizontal aligned
+            // according to textAlignLast.
+            if (lastLineIsSpecial && i == n - 1)
+            {
+                leftAligned = 
+                    textAlignLast == "start" && direction == "ltr" ||
+                    textAlignLast == "end" && direction == "rtl" ||
+                    textAlignLast == "left" ||
+                    textAlignLast == "justify";
+                centerAligned = textAlignLast == "center";
+                rightAligned =
+                    textAlignLast == "start" && direction == "rtl" ||
+                    textAlignLast == "end" && direction == "ltr" ||
+                    textAlignLast == "right";
+            } 
+
+            if (leftAligned)
+                textLine.x = leftOffset;
+            else if (centerAligned)
+                textLine.x = centerOffset - textLine.textWidth / 2;
+            else if (rightAligned)
+                textLine.x = rightOffset - textLine.textWidth;            
+            
+            if (verticalAlign == "top" || !createdAllLines || clipping)
+            {
+                textLine.y += topOffset;
+            }
+            else if (verticalAlign == "middle")
+            {
+                textLine.y += middleOffset;
+            }
+            else if (verticalAlign == "bottom")
+            {
+                textLine.y += bottomOffset;
+            }
+            else if (verticalAlign == "justify")
+            {
+                // 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.
+                y += i == 0 ?
+                     topOffset + textLine.ascent :
+                     previousTextLine.descent + leading + textLine.ascent;
+            
+                textLine.y = y;
+                previousTextLine = textLine;
+            }
+
+            // Upper left corner of bounding box may not be 0,0 after
+            // styles are applied or rounding error from minY calculation.
+            // y is one decimal place and ascent isn't rounded so minY can be 
+            // slightly less than zero. 
+            minX = Math.min(minX, textLine.x);             
+            minY = Math.min(minY, textLine.y - textLine.ascent);
+            maxX = Math.max(maxX, textLine.x + textLine.textWidth); 
+        }
+
+        bounds.x = minX - paddingLeft;
+        bounds.y = minY - paddingTop;
+        bounds.right = maxX + paddingRight;
+        bounds.bottom = textLine.y + textLine.descent + paddingBottom;
+        
+        return createdAllLines;
+    } */
+ 
+    /**
+     *  @private
+     *  Create textLine using paragraph terminator "\u2029" so it creates one
+     *  text line that we can use to get the baseline.  The height is 
+     *  important if the text is vertically aligned.
+     */ 
+    /* override mx_internal function createEmptyTextLine(height:Number=NaN):void
+    {
+        staticTextElement.text = "\u2029";
+        
+        bounds.width = NaN;
+        bounds.height = height;
+        
+        createTextLinesFromTextBlock(staticTextBlock, textLines, bounds);
+        
+        releaseLinesFromTextBlock();
+    } */
+    
+    /**
+     *  @private
+     *  Determines if the composed text fits in the given height and 
+     *  line count limit. 
+     */ 
+    /* private function doesComposedTextFit(height:Number, width:Number,
+                                         createdAllLines:Boolean,
+                                         lineCountLimit:int, lineBreak:String):Boolean
+    {
+        // Not all text composed because it didn't fit within bounds.
+        if (!createdAllLines)
+            return false;
+                    
+        // More text lines than allowed lines.                    
+        if (lineCountLimit != -1 && textLines.length > lineCountLimit)
+            return false;
+        
+        if (lineBreak == "explicit")
+        {
+            // if explicit, if the right edge of any lines go outside the
+            // desired width
+            if (bounds.right > width)
+                return false;
+        }
+
+        // No lines or one line or no height restriction.  We don't truncate away
+        // the one and only line just because height is too small.  Clipping
+        // will take care of it later
+        if (textLines.length <= 1 || isNaN(height))
+            return true;
+                                             
+        // Does the bottom of the last line fall within the bounds?                                                    
+        var lastLine:TextLine = TextLine(textLines[textLines.length - 1]);        
+        var lastLineExtent:Number = lastLine.y + lastLine.descent;
+        
+        return lastLineExtent <= height;
+    } */
+
+    /**
+     *  @private
+     *  width and height are the ones used to do the compose, not the measured
+     *  results resulting from the compose.
+     * 
+     *  Adapted from justification code in TLF's
+     *  TextLineFactory.textLinesFromString().
+     */
+    /* private function truncateText(width:Number, height:Number, lineBreak:String):void
+    {
+        var lineCountLimit:int = maxDisplayedLines;
+        var somethingFit:Boolean = false;
+        var truncLineIndex:int = 0;    
+
+        if (lineBreak == "explicit")
+        {
+            truncateExplicitLineBreakText(width, height);
+            return;
+        }
+
+        // Compute the truncation line.
+        truncLineIndex = computeLastAllowedLineIndex(height, lineCountLimit);
+        
+        // Add extra line in case we wordwrapped some characters
+        // onto extra lines.  If we truncate in the middle of the last word
+        // it may then fit on the line above.
+        var extraLine:Boolean;
+        if (truncLineIndex + 1 < textLines.length)
+        {
+            truncLineIndex++;
+            extraLine = true;
+        }
+                                             
+        if (truncLineIndex >= 0)
+        {
+            // Estimate the initial truncation position using the following 
+            // steps. 
+            
+            // 1. Measure the space that the truncation indicator will take
+            // by composing the truncation resource using the same bounds
+            // and formats.  The measured indicator lines could be cached but
+            // as well as being dependent on the indicator string, they are 
+            // dependent on the given width.            
+            staticTextElement.text = truncationIndicatorResource;
+            var indicatorLines:Vector.<DisplayObject> =
+                new Vector.<DisplayObject>();
+            var indicatorBounds:Rectangle = new Rectangle(0, 0, width, NaN);
+    
+            var indicatorFits:Boolean = createTextLinesFromTextBlock(staticTextBlock, 
+                                                                     indicatorLines, 
+                                                                     indicatorBounds);
+                                               
+            releaseLinesFromTextBlock();
+                                                                                                         
+            // 2. Move target line for truncation higher by as many lines 
+            // as the number of full lines taken by the truncation 
+            // indicator. Indicator should also be able to fit.
+            truncLineIndex -= (indicatorLines.length - 1);
+            if (truncLineIndex >= 0 && indicatorFits)
+            {
+                // 3. Calculate allowed width (width left over from the 
+                // last line of the truncation indicator).
+                var measuredTextLine:TextLine = 
+                    TextLine(indicatorLines[indicatorLines.length - 1]);      
+                var allowedWidth:Number = 
+                    measuredTextLine.specifiedWidth -
+                    measuredTextLine.unjustifiedTextWidth;                          
+                                        
+                measuredTextLine = null;                                        
+                releaseTextLines(indicatorLines);
+                                                        
+                // 4. Get the initial truncation position on the target 
+                // line given this allowed width. 
+                var truncateAtCharPosition:int = getTruncationPosition(
+                    TextLine(textLines[truncLineIndex]), allowedWidth, extraLine);
+
+                // The following loop executes repeatedly composing text until 
+                // it fits.  In each iteration, an atoms's worth of characters 
+                // of original content is dropped
+                do
+                {
+                    // Replace all content starting at the inital truncation 
+                    // position with the truncation indicator.
+                    var truncText:String = text.slice(0, truncateAtCharPosition) +
+                                           truncationIndicatorResource;
+
+                    // (Re)-initialize bounds for next compose.
+                    bounds.x = 0;
+                    bounds.y = 0;
+                    bounds.width = width;
+                    bounds.height = height;
+                                                                                    
+                    staticTextElement.text = truncText;
+                    
+                    var createdAllLines:Boolean = createTextLinesFromTextBlock(
+                        staticTextBlock, textLines, bounds);
+        
+                    if (doesComposedTextFit(height, width,
+                                            createdAllLines, 
+                                            lineCountLimit, lineBreak))
+
+                    {
+                        somethingFit = true;
+                        break; 
+                    }       
+                    
+                     // No original content left to make room for 
+                     // truncation indicator.
+                    if (truncateAtCharPosition == 0)
+                        break;
+                    
+                    // sometimes the player decides there isn't enough
+                    // room to render anything so bail
+                    if (textLines.length == 0)
+                        break;
+                    
+                    // Try again by truncating at the beginning of the 
+                    // preceding atom.
+                    var oldCharPosition:int = truncateAtCharPosition;
+                    truncateAtCharPosition = getNextTruncationPosition(
+                        truncLineIndex, truncateAtCharPosition);  
+                    // check to see if we've run out of chars
+                    if (oldCharPosition == truncateAtCharPosition)
+                        break;
+                }
+                while (true);
+            }
+        }
+
+        // If nothing fit, return no lines and bounds that just contains
+        // padding.
+        if (!somethingFit)
+        {
+            releaseTextLines();
+
+            var paddingBottom:Number = getStyle("paddingBottom");
+            var paddingLeft:Number = getStyle("paddingLeft");
+            var paddingRight:Number = getStyle("paddingRight");
+            var paddingTop:Number = getStyle("paddingTop");
+            
+            bounds.x = 0;
+            bounds.y = 0;
+            bounds.width = paddingLeft + paddingRight;
+            bounds.height = paddingTop + paddingBottom;
+        }
+        
+        // The text was truncated.
+        setIsTruncated(true);
+    } */
+        
+    /**
+     *  @private
+     *  width and height are the ones used to do the compose, not the measured
+     *  results resulting from the compose.
+     */
+    /* private function truncateExplicitLineBreakText(width:Number, height:Number):void
+    {
+        // 1. Measure the space that the truncation indicator will take
+        // by composing the truncation resource using the same bounds
+        // and formats.  The measured indicator lines could be cached but
+        // as well as being dependent on the indicator string, they are 
+        // dependent on the given width.            
+        staticTextElement.text = truncationIndicatorResource;
+        var indicatorLines:Vector.<DisplayObject> =
+            new Vector.<DisplayObject>();
+        var indicatorBounds:Rectangle = new Rectangle(0, 0, width, NaN);
+
+        createTextLinesFromTextBlock(staticTextBlock, 
+                                     indicatorLines, 
+                                     indicatorBounds);
+                                           
+        releaseLinesFromTextBlock();
+
+        // check each line to see if it needs truncation
+        var n:int = textLines.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            var line:TextLine = textLines[i] as TextLine;
+            // if the line is wider than bounds or off the left side
+            // TODO (aharui): What if text runs off left side because of
+            // alignment or direction?
+            if ((line.x + line.width) > width)
+            {
+                // clip this line
+                var lineLength:int = line.rawTextLength;
+                // start chopping from the end until it fits
+                while (--lineLength > 0)
+                {
+                    var lineStr:String = text.substr(line.textBlockBeginIndex, lineLength);
+                    lineStr += truncationIndicatorResource;
+                    staticTextElement.text = lineStr;
+                    var clippedLines:Vector.<DisplayObject> =
+                        new Vector.<DisplayObject>();
+
+                    createTextLinesFromTextBlock(staticTextBlock, 
+                                                 clippedLines, 
+                                                 indicatorBounds);
+                                           
+                    releaseLinesFromTextBlock();
+                    if (clippedLines.length == 1 && 
+                        (clippedLines[0].x + clippedLines[0].width) <= width)
+                    {
+                        // replace with the clipped line
+                        clippedLines[0].x = line.x;
+                        clippedLines[0].y = line.y;
+                        textLines[i] = clippedLines[0];
+                        break;
+                    }
+                    
+                }
+            }
+        }
+    } */
+
+    /** 
+     *  @private
+     *  Calculates the last line that fits in the given height and line count 
+     *  limit.
+     */
+    /* private function computeLastAllowedLineIndex(height:Number,
+                                                 lineCountLimit:int):int
+    {           
+        var truncationLineIndex:int = textLines.length - 1;
+        // return -1 if no textLines (usually because zero size)
+        if (truncationLineIndex < 0)
+            return truncationLineIndex;
+        
+        if (!isNaN(height))
+        {
+            // Search in reverse order since truncation near the end is the 
+            // more common use case.
+            do
+            {
+                var textLine:TextLine = TextLine(textLines[truncationLineIndex]);
+                if (textLine.y + textLine.descent <= height)
+                    break;
+                                
+                truncationLineIndex--;
+            }
+            while (truncationLineIndex >= 0);
+        }   
+    
+        // if line count limit is smaller, use that
+        if (lineCountLimit != -1 && lineCountLimit <= truncationLineIndex)
+            truncationLineIndex = lineCountLimit - 1;            
+            
+        return truncationLineIndex;            
+    } */
+
+    /** 
+     *  @private
+     *  Gets the initial truncation position on a line.
+     * 
+     *  If there is an extra line, start at the first word boundary since
+     *  truncating characters in this word may make it fit on the line above.
+     * 
+     *  If there is not an extra line, start at the allowed width.
+     * 
+     *  - Must be at an atom boundary.
+     *  - Must scan the line for atoms in logical order, not physical position 
+     *    order.
+     *  For example, given bi-di text ABאבCD
+     *  atoms must be scanned in this order: 
+     *  A, B, א
+     *  ג, C, D  
+     */
+    /* private function getTruncationPosition(line:TextLine, 
+                                           allowedWidth:Number, 
+                                           extraLine:Boolean):int
+    {           
+        var consumedWidth:Number = 0;
+        var charPosition:int = line.textBlockBeginIndex;
+        
+        while (charPosition < line.textBlockBeginIndex + line.rawTextLength)
+        {
+            var atomIndex:int = line.getAtomIndexAtCharIndex(charPosition);
+            if (extraLine)
+            {
+                // Skip the initial word boundary.
+                if (charPosition != line.textBlockBeginIndex &&
+                    line.getAtomWordBoundaryOnLeft(atomIndex))
+                {
+                    break;
+                }
+            }
+            else
+            {
+                var atomBounds:Rectangle = line.getAtomBounds(atomIndex); 
+                consumedWidth += atomBounds.width;
+                if (consumedWidth > allowedWidth)
+                    break;
+            }
+
+            charPosition = line.getAtomTextBlockEndIndex(atomIndex);
+        }
+                
+        return charPosition;
+    } */
+        
+    /** 
+     *  @private
+     *  Gets the next truncation position by shedding an atom's worth of 
+     *  characters.
+     */
+    /* private function getNextTruncationPosition(truncationLineIndex:int,
+                                               truncateAtCharPosition:int):int
+    {
+        // 1. Get the position of the last character of the preceding atom
+        // truncateAtCharPosition-1, because truncateAtCharPosition is an 
+        // atom boundary.
+        truncateAtCharPosition--; 
+        
+        // 2. Find the new target line (i.e., the line that has the new 
+        // truncation position).  If the last truncation position was at the 
+        // beginning of the target line, the new position may have moved to a 
+        // previous line.  It is also possible for this position to be found 
+        // in the next line because the truncation indicator may have combined 
+        // with original content to form a word that may not have afforded a 
+        // suitable break opportunity.  In any case, the new truncation 
+        // position lies in the vicinity of the previous target line, so a 
+        // linear search suffices.
+        var line:TextLine = TextLine(textLines[truncationLineIndex]);
+        do
+        {
+            if (truncateAtCharPosition >= line.textBlockBeginIndex && 
+                truncateAtCharPosition < line.textBlockBeginIndex + line.rawTextLength)
+            {
+                break;
+            }
+            
+            if (truncateAtCharPosition < line.textBlockBeginIndex)
+            {
+                truncationLineIndex--;
+                // if we run out of chars, just return the same
+                // position to warn the caller to stop
+                if (truncationLineIndex < 0)
+                    return truncateAtCharPosition;
+            }
+            else
+            {
+                truncationLineIndex++;
+                // if we run out of chars, just return the same
+                // position to warn the caller to stop
+                if (truncationLineIndex >= textLines.length)
+                    return truncateAtCharPosition;
+            }
+                
+            line = TextLine(textLines[truncationLineIndex]);
+        }
+        while (true);
+
+        // 3. Get the line atom index at this position          
+        var atomIndex:int = 
+                        line.getAtomIndexAtCharIndex(truncateAtCharPosition);
+        
+        // 4. Get the char index for this atom index
+        var nextTruncationPosition:int = 
+                        line.getAtomTextBlockBeginIndex(atomIndex);
+                
+        return nextTruncationPosition;
+    } */
+    
+    /**
+     *  @private
+     *  Cleans up and sets the validity of the lines associated 
+     *  with the TextBlock to TextLineValidity.INVALID.
+     */
+    /* private function releaseLinesFromTextBlock():void
+    {
+        var firstLine:TextLine = staticTextBlock.firstLine;
+        var lastLine:TextLine = staticTextBlock.lastLine;
+        
+        if (firstLine)
+            staticTextBlock.releaseLines(firstLine, lastLine);        
+     } */
+}
+
+}

-- 
To stop receiving notification emails like this one, please contact
alinakazi@apache.org.