             elementFormat.trackingRight = value;
     }
 
-    /**
-     *  @private
-     */
-    private function setTabStops(textBlockComposer:TextBlockComposer):void
-    {
-        var value:* = getStyle("tabStops");
-        var tabStops:Vector.<TabStop>;
-        
-        if (value is Vector.<TabStop>)
+	/**
+	 *  @private
+	 *  Stuffs the specified text and formatting info into a TextBlock
+     *  and uses it to create as many TextLines as fit into the bounds.
+	 */
+	private function createTextLines(elementFormat:ElementFormat):void
+	{
+		// 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 tabStops:* = getStyle("tabStops");
+        var textAlign:String = getStyle("textAlign");
+        var textAlignLast:String = getStyle("textAlignLast");
+        var textJustify:String = getStyle("textJustify");
+
+		// Set the TextBlock's content.
+        staticTextElement.text = text;
+		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
         {
-            tabStops = value;
+			lineJustification = LineJustification.UNJUSTIFIED;
         }
-        else if (value is Array)
+		if (justificationRule == "space")
+		{
+            staticSpaceJustifier.lineJustification = lineJustification;
+			staticSpaceJustifier.letterSpacing = textJustify == "distribute";
+            staticTextBlock.textJustifier = staticSpaceJustifier;
+		}
+		else
+		{
+            staticEastAsianJustifier.lineJustification = lineJustification;
+            staticEastAsianJustifier.justificationStyle = justificationStyle;
+			
+            staticTextBlock.textJustifier = staticEastAsianJustifier;
+		}
+        				
+		// And its tabStops.
+		var tabStopsVector:Vector.<TabStop>;
+        if (tabStops is Vector.<TabStop>)
         {
-            var n:int = value.length;
-            tabStops = new Vector.<TabStop>(n);
+            tabStopsVector = tabStops;
+        }
+        else if (tabStops is Array)
+        {
+            var n:int = tabStops.length;
+            tabStopsVector = new Vector.<TabStop>(n);
             for (var i:int = 0; i < n; i++)
             {
-                tabStops[i] = value[i];
+                tabStopsVector[i] = tabStops[i];
             }
         }
         else
         {
-            tabStops = new Vector.<TabStop>();
+            tabStopsVector = new Vector.<TabStop>();
         }   
-
-        textBlockComposer.tabStops = tabStops;
-    }
+		staticTextBlock.tabStops = tabStopsVector;
+        
+		// Then create TextLines using this TextBlock.
+		createTextLinesFromTextBlock(staticTextBlock);
+	}
+
+	/**
+	 *  @private
+	 */
+	private function createTextLinesFromTextBlock(textBlock:TextBlock):void
+	{
+		// Clear any previously generated TextLines from the textLines Array.
+		mx_internal::textLines.length = 0;
+				
+		// 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 bounds:Rectangle = mx_internal::bounds;
+
+		var innerWidth:Number = bounds.width - paddingLeft - paddingRight;
+		var innerHeight:Number = bounds.height - paddingTop - paddingBottom;
+		
+		if (isNaN(innerWidth))
+			innerWidth = TextLine.MAX_LINE_WIDTH;
+
+        var maxLineWidth:Number = lineBreak == "explicit" ?
+                                  TextLine.MAX_LINE_WIDTH :
+                                  innerWidth;
+		
+		if (innerWidth < 0 || innerHeight < 0 || !textBlock)
+		{
+			bounds.width = 0;
+			bounds.height = 0;
+			return;
+		}
+
+		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 createdAllLines:Boolean = false;
+		
+		// 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)
+		{
+			nextTextLine = textBlock.createTextLine(textLine, maxLineWidth);
+			if (!nextTextLine)
+            {
+				createdAllLines = true;
+                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 it is completely outside the rectangle, we're done.
+			if (nextY - nextTextLine.ascent > innerHeight)
+				break;
+
+			// We'll keep this line. Put it into the textLines array.
+			textLine = nextTextLine;
+			mx_internal::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 = 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;
+		}
+		
+		if (isNaN(bounds.width))
+            bounds.width = paddingLeft + maxTextWidth + paddingRight;
+        if (isNaN(bounds.height))
+            bounds.height = paddingTop + textLine.y +
+							textLine.descent + paddingBottom;
+		
+		innerWidth = bounds.width - paddingLeft - paddingRight;
+		innerHeight = bounds.height - paddingTop - paddingBottom;
+
+        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;
+
+		// Make each line static (which decouples it from the TextBlock
+		// that created it and makes it consume less memory)
+		// and reposition each line if necessary
+		// based on the horizontal and vertical alignment.
+		for (var i:int = 0; i < n; i++)
+		{
+			textLine = TextLine(mx_internal::textLines[i]);
+
+			textLine.validity = TextLineValidity.STATIC;
+
+			// 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")
+			{
+				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;
+			}
+		}
+	}
 }
 
 }

{
    include "../core/Version.as";

    //--------------------------------------------------------------------------
    //
    //  Class methods

{

import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.Shape;
import flash.geom.Rectangle;
import flash.text.engine.EastAsianJustifier;
import flash.text.engine.ElementFormat;
import flash.text.engine.FontDescription;
import flash.text.engine.FontMetrics;
import flash.text.engine.Kerning;
import flash.text.engine.LineJustification;
import flash.text.engine.TabStop;
import flash.text.engine.SpaceJustifier;
import flash.text.engine.TextBlock;
import flash.text.engine.TextElement;
import flash.text.engine.TextLine;
import flash.text.engine.TextLineValidity;

import mx.core.mx_internal;
import mx.graphics.baseClasses.TextGraphicElement;

[DefaultProperty("text")]
