You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ha...@apache.org on 2017/03/16 13:37:35 UTC

[15/42] flex-asjs git commit: And here’s TLF…

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/ParagraphFormattedElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/ParagraphFormattedElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/ParagraphFormattedElement.as
new file mode 100644
index 0000000..aff7df7
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/ParagraphFormattedElement.as
@@ -0,0 +1,49 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements {
+
+	
+
+	
+	/** The ParagraphFormattedElement class is an abstract base class for FlowElement classes that have paragraph properties.
+	*
+	* <p>You cannot create a ParagraphFormattedElement object directly. Invoking <code>new ParagraphFormattedElement()</code> 
+	* throws an error exception.</p> 
+	*
+	* @playerversion Flash 10
+	* @playerversion AIR 1.5
+	* @langversion 3.0
+	*
+	* @see ContainerFormattedElement
+	* @see ParagraphElement
+	* 
+	*/
+	public class ParagraphFormattedElement extends FlowGroupElement implements IParagraphFormattedElement
+	{
+		/** @private TODO: DELETE THIS CLASS */
+		public override function shallowCopy(startPos:int = 0, endPos:int = -1):IFlowElement
+		{
+			return super.shallowCopy(startPos, endPos) as ParagraphFormattedElement;
+		}
+		override public function get className():String{
+			return "ParagraphFormattedElement";
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SpanElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SpanElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SpanElement.as
new file mode 100644
index 0000000..57887f2
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SpanElement.as
@@ -0,0 +1,608 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+	import org.apache.flex.text.engine.GroupElement;
+	import org.apache.flex.text.engine.TextElement;
+	
+	import org.apache.flex.textLayout.container.IContainerController;
+	import org.apache.flex.textLayout.debug.Debugging;
+	import org.apache.flex.textLayout.debug.assert;
+	import org.apache.flex.textLayout.events.ModelChange;
+	import org.apache.flex.textLayout.formats.FormatValue;
+	import org.apache.flex.textLayout.formats.ITextLayoutFormat;
+	import org.apache.flex.textLayout.formats.TextLayoutFormat;
+	import org.apache.flex.textLayout.formats.WhiteSpaceCollapse;
+
+	import org.apache.flex.textLayout.utils.CharacterUtil;
+	
+
+			
+	[DefaultProperty("mxmlChildren")]
+	
+	/** 
+	* The SpanElement class represents a run of text that has a single set of formatting attributes applied. SpanElement 
+	* objects contain the text in a paragraph. A simple paragraph (ParagraphElement) includes one or more SpanElement objects. 
+	*
+	* <p>A ParagraphElement will have a single SpanElement object if all the text in the paragraph shares the same set of 
+	* attributes. It has multiple SpanElement objects if the text in the paragraph has multiple formats.</p>
+	*
+	* @playerversion Flash 10
+	* @playerversion AIR 1.5
+	* @langversion 3.0
+	*
+	* @see FlowElement
+	* @see ParagraphElement
+	* @see TextFlow
+     	*/
+	public class SpanElement extends FlowLeafElement implements ISpanElement
+	{	
+		
+		/** Constructor - creates a SpanElement object to hold a run of text in a paragraph.
+		*
+		* @playerversion Flash 10
+		* @playerversion AIR 1.5
+	 	* @langversion 3.0
+	 	*/
+	 	
+		public function SpanElement()
+		{
+			super();
+		}
+		override public function get className():String
+		{
+			return "SpanElement";
+		}
+		
+		/** @private */
+		override public function createContentElement():void
+		{
+			if (_blockElement && _blockElement.textBlock)
+				return;
+			
+			calculateComputedFormat();	// BEFORE creating the element
+			_blockElement = new TextElement(_text,null);			
+			CONFIG::debug { Debugging.traceFTECall(_blockElement,null,"new TextElement()"); }
+			CONFIG::debug { Debugging.traceFTEAssign(_blockElement, "text", _text); }
+			super.createContentElement();
+		}
+		
+		/** @private */
+		public override function shallowCopy(startPos:int = 0, endPos:int = -1):IFlowElement
+		{
+			if (endPos == -1)
+				endPos = textLength;
+				
+			// Note to callers: If you are calling this function outside a try/catch, do ensure that the 
+			// state of the model is coherent before the call.
+			var retFlow:SpanElement = super.shallowCopy(startPos, endPos) as SpanElement;
+						
+			var startSpan:int = 0;
+			var endSpan:int = startSpan + textLength;
+			
+			var leafElStartPos:int = startSpan >= startPos ? startSpan : startPos;
+			var leafElEndPos:int =  endSpan < endPos ? endSpan : endPos;
+			if (leafElEndPos == textLength && hasParagraphTerminator)
+				--leafElEndPos;
+				
+			if (leafElStartPos > leafElEndPos)
+				throw RangeError(GlobalSettings.resourceStringFunction("badShallowCopyRange"));
+			
+			if (((leafElStartPos != endSpan) && CharacterUtil.isLowSurrogate(_text.charCodeAt(leafElStartPos))) ||
+				((leafElEndPos != 0) && CharacterUtil.isHighSurrogate(_text.charCodeAt(leafElEndPos-1))))
+					throw RangeError(GlobalSettings.resourceStringFunction("badSurrogatePairCopy"));
+			
+			if (leafElStartPos != leafElEndPos)
+				retFlow.replaceText(0, retFlow.textLength,  _text.substring(leafElStartPos, leafElEndPos));
+			
+			return retFlow;
+		}	
+	
+		/** @private */
+		override protected function get abstract():Boolean
+		{ return false; }		
+		
+		/** @private */
+		public override function get defaultTypeName():String
+		{ return "span"; }
+
+		/** @private */
+		public override function get text():String
+		{
+			// test textLength cause this is a property and the debugger may run this calculation in intermediate states
+			if (textLength == 0)
+				return "";
+			
+			return hasParagraphTerminator ? _text.substr(0,textLength-1) : _text;
+		}
+		/** 
+		 * Receives the String of text that this SpanElement object holds.
+		 *
+		 * <p>The text of a span does not include the carriage return (CR) at the end of the paragraph
+		 * but it is included in the value of <code>textLength</code>.</p>
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 */
+	 	
+//TODO this is only override because we temporarily added a setter to FlowLeafElement
+	 	override public function set text(textValue:String):void
+		{
+			//original code stripped breaking and tab characters.  new code moved to collapseWhitevar newLineTabPattern:RegExp = /[\n\r\t]/g;
+			replaceText(0,textLength, textValue); 
+		} 
+		
+		/** @private */
+		public override function getText(relativeStart:int=0, relativeEnd:int=-1, paragraphSeparator:String="\n"):String
+		{
+			if (relativeEnd == -1)
+				relativeEnd = textLength;
+			
+			if (textLength && relativeEnd == textLength && hasParagraphTerminator)
+				--relativeEnd;		// don't include terminator
+			return _text ? _text.substring(relativeStart, relativeEnd) : "";
+		}
+
+		[RichTextContent]
+		/** 
+		 * Sets text based on content within span tags; always deletes existing children.
+		 * This property is intended for use during MXML compiled import in Flex. Flash Professional ignores this property.
+         * When TLF markup elements have other
+		 * TLF markup elements as children, the children are assigned to this property.
+		 *
+		 * @throws TypeError If array element is not a SpecialCharacterElement or a String.
+		 * @param array - an array of elements within span tags. Each element of array must be a SpecialCharacterElement or a String.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 */
+		public function get mxmlChildren():Array
+		{
+			return [ text ];
+		}
+		public function set mxmlChildren(array:Array):void
+		{
+			/* NOTE: all FlowElement implementers and overrides of mxmlChildren must specify [RichTextContent] metadata */
+
+			var str:String = ElementHelper.getSpanText(array);
+			replaceText(0,textLength, str); 
+		}
+		
+		
+		/** 
+		 * Specifies whether this SpanElement object terminates the paragraph. The SpanElement object that terminates a 
+		 * paragraph has an extra, hidden character at the end. This character is added automatically by the component and is
+		 * included in the value of the <code>textLength</code> property.
+		 * 
+		 * @private */
+		 
+		public function get hasParagraphTerminator():Boolean
+		{
+			var p:IParagraphElement = getParagraph();
+			return (p && p.getLastLeaf() == this); 
+		}
+		
+		/** @private */
+		CONFIG::debug public function verifyParagraphTerminator():void
+		{
+			assert(_text && _text.length && _text.charAt(_text.length-1) == ElementConstants.kParagraphTerminator,
+				"attempting to remove para terminator when it doesn't exist");
+		}
+		
+		
+		/**
+		 * Makes a shallow copy of this SpanElement between 2 character positions
+		 * and returns it as a FlowElement.  Unlike deepCopy, shallowCopy does
+		 * not copy any of the children of this SpanElement.
+		 * 
+		 */
+		 
+		 // If I have a sequence of different sorts of spaces (e.g., en quad, hair space), would I want them converted down to one space? Probably not.
+		 // For now, u0020 is the only space character we consider for eliminating duplicates, though u00A0 (non-breaking space) is potentially eligible. 
+		 private static const _dblSpacePattern:RegExp = /[\u0020]{2,}/g;
+		 // Tab, line feed, and carriage return
+//TODO regex
+		 private static const _newLineTabPattern:RegExp = /foo/g;
+		//  private static const _newLineTabPattern:RegExp = /[\u0009\u000a\u000d]/g;
+		 private static const _tabPlaceholderPattern:RegExp = /\uE000/g;
+		 
+		 // static private const anyPrintChar:RegExp = /[^\s]/g;
+		 // Consider only tab, line feed, carriage return, and space as characters used for pretty-printing. 
+		 // While debatable, this is consistent with what CSS does. 
+//TODO regex
+		 static private const anyPrintChar:RegExp = /foo/g; 
+//		 static private const anyPrintChar:RegExp = /[^\u0009\u000a\u000d\u0020]/g; 
+
+		 /** @private */
+		public override function applyWhiteSpaceCollapse(collapse:String):void
+		{
+			var ffc:ITextLayoutFormat = this.formatForCascade;
+			var wsc:* = ffc ? ffc.whiteSpaceCollapse : undefined;
+			if (wsc !== undefined && wsc != FormatValue.INHERIT)
+				collapse = wsc;
+				
+			var origTxt:String = text;
+			var tempTxt:String = origTxt;
+				
+			if (!collapse /* null == default value == COLLAPSE */ || collapse == WhiteSpaceCollapse.COLLAPSE)
+			{
+				// The span was added automatically when a String was passed to replaceChildren.
+				// If it contains only whitespace, we remove the text.
+				if (impliedElement && parent != null)
+				{
+					// var matchArray:Array = tempTxt.search(anyPrintChar);
+					if (tempTxt.search(anyPrintChar) == -1)
+					{
+						parent.removeChild(this);
+						return;
+					}
+				}
+				
+				// For now, replace the newlines and tabs inside the element with a space.
+				// This is necessary for support of compiled mxml files that have newlines and tabs, because
+				// these are most likely not intended to be part of the text content, but only there so the
+				// text can be conveniently edited in the mxml file. Later on we need to add standalone elements
+				// for <br/> and <tab/>. Note that tab character is not supported in HTML.	
+				tempTxt = tempTxt.replace(_newLineTabPattern, " ");
+
+				// Replace sequences of 2 or more whitespace characters with single space
+				tempTxt = tempTxt.replace(_dblSpacePattern, " ");
+			}
+			
+			// Replace tab placeholders (used for tabs that are expected to survive whitespace collapse) with '\t'
+			tempTxt = tempTxt.replace(_tabPlaceholderPattern, '\t');
+			if (tempTxt != origTxt)
+				replaceText(0, textLength, tempTxt);
+
+			super.applyWhiteSpaceCollapse(collapse);
+		}
+		
+		/** 
+		 * Updates the text in text span based on the specified start and end positions. To insert text, set the end position
+		 * equal to the start position. To append text to the existing text in the span, set the start position and the
+		 * end position equal to the length of the existing text.
+		 *
+		 * <p>The replaced text includes the start character and up to but not including the end character.</p>
+		 * 
+		 *  @param relativeStartPosition The index position of the beginning of the text to be replaced, 
+		 *   relative to the start of the span. The first character in the span is at position 0.
+		 *  @param relativeEndPosition The index one position after the last character of the text to be replaced, 
+		 *   relative to the start of the span. Set this value equal to <code>relativeStartPos</code>
+		 *   for an insert. 
+		 *  @param textValue The replacement text or the text to add, as the case may be.
+		 * 
+		 *  @throws RangeError The <code>relativeStartPosition</code> or <code>relativeEndPosition</code> specified is out of 
+		 * range or a surrogate pair is being split as a result of the replace.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 *
+		 */
+		 
+		public function replaceText(relativeStartPosition:int, relativeEndPosition:int, textValue:String):void
+		{
+			// Note to callers: If you are calling this function outside a try/catch, do ensure that the 
+			// state of the model is coherent before the call.
+			if (relativeStartPosition < 0 || relativeEndPosition > textLength || relativeEndPosition < relativeStartPosition)
+				throw RangeError(GlobalSettings.resourceStringFunction("invalidReplaceTextPositions"));	
+
+
+			if ((relativeStartPosition != 0 && relativeStartPosition != textLength && CharacterUtil.isLowSurrogate(_text.charCodeAt(relativeStartPosition))) ||
+				(relativeEndPosition != 0 && relativeEndPosition != textLength && CharacterUtil.isHighSurrogate(_text.charCodeAt(relativeEndPosition-1))))
+					throw RangeError (GlobalSettings.resourceStringFunction("invalidSurrogatePairSplit"));
+				
+			if (hasParagraphTerminator)
+			{
+				CONFIG::debug { assert(textLength > 0,"invalid span"); }
+				if (relativeStartPosition == textLength)
+					relativeStartPosition--;
+				if (relativeEndPosition == textLength)
+					relativeEndPosition--;
+			}
+			
+			if (relativeEndPosition != relativeStartPosition)
+				modelChanged(ModelChange.TEXT_DELETED,this,relativeStartPosition,relativeEndPosition-relativeStartPosition);
+			
+			replaceTextInternal(relativeStartPosition,relativeEndPosition,textValue);
+			
+			if (textValue && textValue.length)
+				modelChanged(ModelChange.TEXT_INSERTED,this,relativeStartPosition,textValue.length);
+		}
+		private function replaceTextInternal(startPos:int, endPos:int, textValue:String):void
+		{			
+			var textValueLength:int = textValue == null ? 0 : textValue.length;
+			var deleteTotal:int = endPos-startPos;
+			var deltaChars:int =  textValueLength - deleteTotal;
+			if (_blockElement)
+			{
+				(_blockElement as TextElement).replaceText(startPos,endPos,textValue);
+				_text = _blockElement.rawText;
+				CONFIG::debug { Debugging.traceFTECall(null,_blockElement as TextElement,"replaceText",startPos,endPos,textValue); }
+			}
+			else if (_text)
+			{
+				if (textValue)
+					_text = _text.slice(0, startPos) + textValue + _text.slice(endPos, _text.length);
+				else
+					_text = _text.slice(0, startPos) + _text.slice(endPos, _text.length);
+			}
+			else
+				_text = textValue;
+			
+			if (deltaChars != 0)
+			{
+				updateLengths(getAbsoluteStart() + startPos, deltaChars, true);
+				deleteContainerText(endPos,deleteTotal);
+				
+				if (textValueLength != 0)
+				{
+					var enclosingContainer:IContainerController = getEnclosingController(startPos);
+					if (enclosingContainer)
+						enclosingContainer.setTextLength(enclosingContainer.textLength + textValueLength);
+				}
+			}
+
+			CONFIG::debug { 
+				assert(textLength == (_text ? _text.length : 0),"span textLength doesn't match the length of the text property, text property length is " + _text.length.toString() + " textLength property is " + textLength.toString());
+				assert(_blockElement == null || _blockElement.rawText == _text,"mismatched text");
+			}
+		}
+	
+		/** @private */
+		public function addParaTerminator():void
+		{
+			CONFIG::debug 
+			{ 
+				// TODO: Is this assert valid? Do we prevent users from adding para terminators themselves? 
+				if (_blockElement && _blockElement.rawText && _blockElement.rawText.length)
+					assert(_blockElement.rawText.charAt(_blockElement.rawText.length-1) != ElementConstants.kParagraphTerminator,"adding para terminator twice");
+			}
+
+			if(_text && _text.substr(-1) == ElementConstants.kParagraphTerminator)// terminator exists. Bail out.
+				return;
+			replaceTextInternal(textLength,textLength,ElementConstants.kParagraphTerminator);
+			
+			CONFIG::debug 
+			{ 
+				// TODO: Is this assert valid? Do we prevent users from adding para terminators themselves? 
+				if (_blockElement)
+					assert(_blockElement.rawText.charAt(_blockElement.rawText.length-1) == ElementConstants.kParagraphTerminator,"adding para terminator failed");
+			}			
+			
+			modelChanged(ModelChange.TEXT_INSERTED,this,textLength-1,1);
+		}
+		/** @private */
+		public function removeParaTerminator():void
+		{
+			CONFIG::debug 
+			{ 
+				assert(_text && _text.length && _text.charAt(_text.length-1) == ElementConstants.kParagraphTerminator,
+					"attempting to remove para terminator when it doesn't exist");
+			}
+			if(!_text || _text.substr(-1) != ElementConstants.kParagraphTerminator)// no terminator exists. Bail out.
+				return;
+
+			replaceTextInternal(textLength-1,textLength,"");
+			modelChanged(ModelChange.TEXT_DELETED,this,textLength > 0 ? textLength-1 : 0,1);
+		}
+		// **************************************** 
+		// Begin tree modification support code
+		// ****************************************
+
+		/** 
+		 * Splits this SpanElement object at the specified position and returns a new SpanElement object for the content
+		 * that follows the specified position. 
+		 *
+		 * <p>This method throws an error if you attempt to split a surrogate pair. In Unicode UTF-16, a surrogate pair is a pair of 
+		 * 16-bit code units (a high code unit and a low code unit) that represent one of the abstract Unicode characters 
+		 * that cannot be represented in a single 16-bit word. The 16-bit high code unit is in the range of D800 to DBFF. The
+		 * 16-bit low code unit is in the range of DC00 to DFFF.</p>
+		 * 
+		 * @param relativePosition - relative position in the span to create the split
+		 * @return - the newly created span. 
+		 * @throws RangeError <code>relativePosition</code> is less than 0 or greater than textLength or a surrogate pair is being split.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 * 
+	 	 * @private
+	 	 */
+	 	 
+		public override function splitAtPosition(relativePosition:int):IFlowElement
+		{
+			// Note to callers: If you are calling this function outside a try/catch, do ensure that the 
+			// state of the model is coherent before the call.
+			if (relativePosition < 0 || relativePosition > textLength)
+				throw RangeError(GlobalSettings.resourceStringFunction("invalidSplitAtPosition"));
+			
+			if ((relativePosition < textLength) && CharacterUtil.isLowSurrogate(String(text).charCodeAt(relativePosition)))
+				throw RangeError (GlobalSettings.resourceStringFunction("invalidSurrogatePairSplit"));
+			
+			var newSpan:ISpanElement = new SpanElement();
+			// clone styling information
+			newSpan.id = this.id;
+			newSpan.typeName = this.typeName;			
+			
+			if (parent)
+			{
+				var newBlockElement:TextElement;
+				var newSpanLength:int = textLength - relativePosition;
+				if (_blockElement)
+				{
+					// optimized version leverages player APIs
+					// TODO: Jeff to add split on TextElement so we don't have to go find a group every time
+					var group:GroupElement = parent.createContentAsGroup(getElementRelativeStart(parent));
+					
+					var elementIndex:int = group.getElementIndex(_blockElement);
+					
+					CONFIG::debug { assert(elementIndex == parent.getChildIndex(this),"bad group index"); }
+					CONFIG::debug { assert(elementIndex != -1 && elementIndex < group.elementCount,"bad span split"); }
+					//trace("GROUP BEFORE: " + group.rawText);
+					//trace("BLOCK BEFORE: " + group.block.content.rawText);
+					//trace("calling group.splitTextElement("+elementIndex.toString()+","+relativePosition.toString()+")");
+					group.splitTextElement(elementIndex, relativePosition);
+					CONFIG::debug { Debugging.traceFTECall(null,group,"splitTextElement",elementIndex,relativePosition); }
+
+					//trace("GROUP AFTER: " + group.rawText);
+					//trace("BLOCK AFTER: " + group.block.content.rawText);
+					
+					// no guarantee on how the split works
+					_blockElement = group.getElementAt(elementIndex);
+					_text = _blockElement.rawText;
+					CONFIG::debug { Debugging.traceFTECall(_blockElement,group,"getElementAt",elementIndex); }
+					newBlockElement = group.getElementAt(elementIndex+1) as TextElement;
+					CONFIG::debug { Debugging.traceFTECall(newBlockElement,group,"getElementAt",elementIndex+1); }
+				}
+				else if (relativePosition < textLength)
+				{
+					newSpan.text = _text.substr(relativePosition);
+					_text = _text.substring(0, relativePosition);
+				}
+
+				// Split this span at the offset, into two equivalent spans
+				modelChanged(ModelChange.TEXT_DELETED,this,relativePosition,newSpanLength);
+				newSpan.quickInitializeForSplit(this, newSpanLength, newBlockElement);
+
+				setTextLength(relativePosition);
+			
+				// slices it in, sets the parent and the start
+				parent.addChildAfterInternal(this,newSpan);	
+				
+				var p:IParagraphElement = this.getParagraph();
+				p.updateTerminatorSpan(this,newSpan);
+				
+				parent.modelChanged(ModelChange.ELEMENT_ADDED,newSpan,newSpan.parentRelativeStart,newSpan.textLength);
+			}
+			else
+			{
+				// this version also works if para is non-null but may not be as efficient.
+				newSpan.format = format;
+
+				// could be we are splitting 
+				if (relativePosition < textLength)
+				{
+					newSpan.text = String(this.text).substr(relativePosition);
+					replaceText(relativePosition,textLength,null);
+				}
+			}
+			
+			return newSpan;
+		}
+		
+		/** @private */
+		public override function normalizeRange(normalizeStart:uint,normalizeEnd:uint):void
+		{
+			if (this.textLength == 1 && !bindableElement)
+			{
+				var p:IParagraphElement = getParagraph();
+				if (p && p.getLastLeaf() == this)
+				{
+					var prevLeaf:IFlowLeafElement = getPreviousLeaf(p);
+					if (prevLeaf)
+					{
+						if (!TextLayoutFormat.isEqual(this.format, prevLeaf.format))
+							this.format = prevLeaf.format;
+					}
+				}
+			}
+			super.normalizeRange(normalizeStart,normalizeEnd);
+		}
+
+		/** @private */
+		public override function mergeToPreviousIfPossible():Boolean
+		{
+			if (parent && !bindableElement)
+			{
+				var myidx:int = parent.getChildIndex(this);
+				if (myidx != 0)
+				{
+					var sib:SpanElement = parent.getChildAt(myidx-1) as SpanElement;
+					
+					// If the element we're checking for merge has only the terminator, and the previous element
+					// is not a Span, then we always merge with the previous span (NOT the previous sib). 
+					// We just remove this span, and add the terminator to the previous span.
+					if (!sib && this.textLength == 1 && this.hasParagraphTerminator)
+					{
+						var p:IParagraphElement = getParagraph();
+						if (p)
+						{
+							var prevLeaf:IFlowLeafElement = getPreviousLeaf(p) as SpanElement;
+							if (prevLeaf)
+							{
+								parent.removeChildAt(myidx);
+								return true;
+							}
+						}
+					}
+
+					if (sib == null)
+						return false;
+					
+					
+					// If this has an active event mirror do not merge
+					if (this.hasActiveEventMirror())
+						return false;
+					var thisIsSimpleTerminator:Boolean = textLength == 1 && hasParagraphTerminator;
+					// if sib has an active event mirror still merge if this is a simple terminator span
+					if (sib.hasActiveEventMirror() && !thisIsSimpleTerminator)
+						return false;
+					
+					// always merge if this is just a terminator
+					if (thisIsSimpleTerminator || equalStylesForMerge(sib))
+					{
+						CONFIG::debug { assert(this.parent == sib.parent, "Should never merge two spans with different parents!"); }
+						CONFIG::debug { assert(TextLayoutFormat.isEqual(this.formatForCascade,sib.formatForCascade) || (this.textLength == 1 && this.hasParagraphTerminator), "Bad merge!"); }
+
+						// Merge the spans
+						var siblingInsertPosition:int = sib.textLength;
+						sib.replaceText(siblingInsertPosition, siblingInsertPosition, this.text);
+						parent.removeChildAt(myidx);
+						return true;
+					}
+				}
+			} 
+			return false;
+		}
+		
+		// **************************************** 
+		// Begin debug support code
+		// ****************************************	
+		
+		/** @private */
+		CONFIG::debug public override function debugCheckFlowElement(depth:int = 0, extraData:String = ""):int
+		{
+			// debugging function that asserts if the flow element tree is in an invalid state
+			
+			var rslt:int = super.debugCheckFlowElement(depth,"text:"+String(text).substr(0,32)+" "+extraData);
+
+			assert(_blockElement == null || _blockElement.rawText == _text,"debugCheckFlowElement: mismatched text");
+			var textLen:int = textLength;
+			if (_text)
+				rslt += assert(textLen == _text.length,"span is different than its textElement, span text length is " + _text.length.toString() + " expecting " + textLen.toString());
+			else	
+				rslt += assert(textLen == 0,"span is different than its textElement, span text length is null expecting " + textLen.toString());
+			rslt += assert(this != getParagraph().getLastLeaf() || (_text.length >= 1 && _text.substr(_text.length-1,1) == ElementConstants.kParagraphTerminator),"last span in paragraph must end with terminator");
+			return rslt;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SpecialCharacterElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SpecialCharacterElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SpecialCharacterElement.as
new file mode 100644
index 0000000..d63a065
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SpecialCharacterElement.as
@@ -0,0 +1,96 @@
+// //////////////////////////////////////////////////////////////////////////////
+//
+// 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 org.apache.flex.textLayout.elements
+{
+	import org.apache.flex.textLayout.formats.TextLayoutFormat;
+	import org.apache.flex.textLayout.formats.WhiteSpaceCollapse;
+	import org.apache.flex.textLayout.debug.assert;
+
+	/** The SpecialCharacterElement class is an abstract base class for elements that represent special characters.
+	 *
+	 * <p>You cannot create a SpecialCharacterElement object directly. Invoking <code>new SpecialCharacterElement()</code>
+	 * throws an error exception.</p>
+	 *
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 * @see BreakElement
+	 * @see TabElement
+	 */
+	public class SpecialCharacterElement extends SpanElement implements ISpecialCharacterElement
+	{
+		/**  
+		 * Base class - invoking <code>new SpecialCharacterElement()</code> throws an error exception.
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0 
+		 */
+		public function SpecialCharacterElement()
+		{
+			super();
+			// blockElement = new TextElement(null, null);
+
+			// Set WhiteSpaceCollapse.PRESERVE to prevent merging with a sibling span with WhiteSpaceCollapse.COLLAPSE setting
+			// (during normalization). Otherwise the '\t' will be removed during the call to applyWhiteSpaceCollapse (following normalization).
+			// Once applyWhiteSpaceCollapse has been called, we can allow merging.
+			whiteSpaceCollapse = WhiteSpaceCollapse.PRESERVE;
+		}
+		override public function get className():String{
+			return "SpecialCharacterElement";
+		}
+
+		/**
+		 *  @private
+		 * @flexjsignorecoercion org.apache.flex.textLayout.elements.ISpanElement
+		 */
+		public override function mergeToPreviousIfPossible():Boolean
+		{
+			if (parent)
+			{
+				var myidx:int = parent.getChildIndex(this);
+				if (myidx != 0)
+				{
+					var sib:ISpanElement = parent.getChildAt(myidx - 1) as ISpanElement;
+					if (sib != null && (sib is SpanElement) && TextLayoutFormat.isEqual(sib.format, format))
+					{
+						CONFIG::debug
+						{
+							assert(this.parent == sib.parent, "Should never merge two spans with different parents!"); }
+
+						// Merge them in the Player's TextBlock structure
+						var siblingInsertPosition:int = sib.textLength;
+						sib.replaceText(siblingInsertPosition, siblingInsertPosition, this.text);
+						parent.replaceChildren(myidx, myidx + 1);
+						return true;
+					}
+				}
+				// make a span and replace ourself
+				var newSib:ISpanElement = ElementHelper.getSpan();
+				newSib.text = this.text;
+				newSib.format = format;
+				parent.replaceChildren(myidx, myidx + 1, newSib);
+				newSib.normalizeRange(0, newSib.textLength);
+				return false;
+			}
+			return false;
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SubParagraphGroupElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SubParagraphGroupElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SubParagraphGroupElement.as
new file mode 100644
index 0000000..816d1e3
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SubParagraphGroupElement.as
@@ -0,0 +1,95 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+
+	
+
+	
+	/** 
+     * The SubParagraphGroupElement is a grouping element for FlowLeafElements and other classes that extend SubParagraphGroupElementBase.
+	 *
+     * @see org.apache.flex.textLayout.elements.SubParagraphGroupElement
+     * @see org.apache.flex.textLayout.elements.SubParagraphGroupElementBase
+     * @see org.apache.flex.textLayout.elements.FlowLeafElement
+     *
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 */
+	public final class SubParagraphGroupElement extends SubParagraphGroupElementBase implements ISubParagraphGroupElement
+	{
+        /** Constructor. 
+         * For information on using this class, see <a href='http://blogs.adobe.com/tlf/2011/01/tlf-2-0-changes-subparagraphgroupelements-and-typename-applied-to-textfieldhtmlimporter-and-cssformatresolver.html'>TLF 2.0 SubParagraphGroupElement and typeName</a>.
+		 *
+		 * @playerversion Flash 10
+	 	 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 *
+	 	 */
+		public function SubParagraphGroupElement()
+		{ super(); }
+		override public function get className():String{
+			return "SubParagraphGroupElement";
+		}
+		
+		/** @private */
+		override protected function get abstract():Boolean
+		{ return false; }
+		
+		/** @private */
+		public override function get defaultTypeName():String
+		{ return "g"; }
+		
+		/** @private Lowest level of precedence. */
+		public override function get precedence():uint 
+		{ return kMinSPGEPrecedence; }
+		
+		/** @private */
+		override public function get allowNesting():Boolean
+		{ return true; }
+		
+		/** @private */
+		public override function mergeToPreviousIfPossible():Boolean
+		{
+			if (parent && !bindableElement && !hasActiveEventMirror())
+			{
+				var myidx:int = parent.getChildIndex(this);
+				if (myidx != 0)
+				{
+					var sib:SubParagraphGroupElement = parent.getChildAt(myidx-1) as SubParagraphGroupElement;
+					// if only one element has an event mirror use that event mirror
+					// for the merged element; if both have active mirrors, do not merge
+					if (sib == null || sib.hasActiveEventMirror())
+						return false;
+					
+					if (equalStylesForMerge(sib))
+					{						
+						parent.removeChildAt(myidx);
+						if (numChildren > 0)
+							sib.replaceChildren(sib.numChildren,sib.numChildren,this.mxmlChildren);
+						return true;
+					}
+				}
+			} 
+			return false;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SubParagraphGroupElementBase.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SubParagraphGroupElementBase.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SubParagraphGroupElementBase.as
new file mode 100644
index 0000000..7e22474
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/SubParagraphGroupElementBase.as
@@ -0,0 +1,387 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+	import org.apache.flex.events.IEventDispatcher;
+	import org.apache.flex.text.engine.ContentElement;
+	import org.apache.flex.text.engine.GroupElement;
+	import org.apache.flex.textLayout.debug.Debugging;
+	import org.apache.flex.textLayout.debug.assert;
+	import org.apache.flex.textLayout.events.FlowElementEventDispatcher;
+	import org.apache.flex.textLayout.events.ModelChange;
+	
+
+	
+
+	
+	/** 
+	 * The SubParagraphGroupElementBase class groups FlowLeafElements together. A SubParagraphGroupElementBase is a child of a 
+	 * ParagraphElement object and it can contain one or more FlowLeafElement objects as children.
+	 *
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 * 
+	 * @see FlowLeafElement
+	 * @see LinkElement
+	 * @see ParagraphElement
+	 * @see TCYElement
+	 */
+	public class SubParagraphGroupElementBase extends FlowGroupElement implements ISubParagraphGroupElementBase
+	{
+		private var _groupElement:GroupElement;
+		
+		/** Maximum precedence value @private */
+		public static const kMaxSPGEPrecedence:uint = 1000;
+		/** Minimum precedence value @private */
+		public static const kMinSPGEPrecedence:uint = 0;
+		
+		/** @private the event dispatcher that acts as an event mirror */
+		public var _eventMirror:FlowElementEventDispatcher = null;
+
+		/** Constructor - creates a new SubParagraphGroupElementBase instance.
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		 
+		public function SubParagraphGroupElementBase()
+		{ super(); }
+
+		/** @private */
+		override public function createContentElement():void
+		{
+			if (_groupElement)
+				return;
+				
+			calculateComputedFormat();	// BEFORE creating the element
+			_groupElement = new GroupElement(null);
+			CONFIG::debug { Debugging.traceFTECall(_groupElement,null,"new GroupElement",null); }  
+			for (var i:int = 0; i < numChildren; i++)
+			{
+				var child:IFlowElement = getChildAt(i);
+				child.createContentElement();
+			}			
+			if (parent)
+				parent.insertBlockElement(this, _groupElement);
+		}
+		
+		/** @private */
+		override public function releaseContentElement():void
+		{
+			if (_groupElement == null)
+				return;
+			for (var i:int = 0; i < numChildren; i++)
+			{
+				var child:IFlowElement = getChildAt(i);
+				child.releaseContentElement();
+			}			
+			_groupElement = null;
+			_computedFormat = null;
+		}
+		
+		/**
+		 * @public getter to return the precedence value of this SubParagraphGroupElementBase
+		 * Precedence is used to determine which SPGE element will be the container element
+		 * when two or more SPGEs of the same textLength are inside one another.
+		 * 
+		 * Precedence is used to determine which SubParagraphGroupElementBase is the owner when two or 
+		 * more elements have the same text and are embedded within each other.
+		 * 
+		 * Note: model permits any order and does not enforce precedence.  This is only a feature used by the EditManager
+		 * 
+		 * Example: SPGEs A(precedence 900), B(precedence 400), C(precedence 600)
+		 * Editing Result when all wrap SpanElement "123"
+		 * 
+		 * <A><C><B>123</B></C></A>
+		 * 
+		 * If two or more SPGE's have the same precedence value, then the alphabetic order is used:
+		 * Example: SPGE A(precedence 400), B(precedence 400), C(precedence 600)
+		 * 
+		 * <C><A><B>123</B></A></C>
+		 * 
+		 * Current values for SubParagraphGroupElementBase are:
+		 * 	LinkElement - 800
+		 * 	TCYElement - 100
+		 * 
+		 * If the value is not overriden by descendents of SPGE, then value is kMaxSPGEPrecedence;
+		 * @private
+		 */
+		public function get precedence():uint 
+		{ return kMaxSPGEPrecedence; }
+		
+		 
+		/** @private */
+		public function get groupElement():GroupElement
+		{ return _groupElement; }
+		
+		/** @private
+		 * Gets the EventDispatcher associated with this FlowElement.  Use the functions
+		 * of EventDispatcher such as <code>setEventHandler()</code> and <code>removeEventHandler()</code> 
+		 * to capture events that happen over this FlowLeafElement object.  The
+		 * event handler that you specify will be called after this FlowElement object does
+		 * the processing it needs to do.
+		 * 
+		 * Note that the event dispatcher will only dispatch FlowElementMouseEvent events.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 *
+		 * @see org.apache.flex.events.EventDispatcher
+		 * @see org.apache.flex.textLayout.events.FlowElementMouseEvent
+		 */
+		public override function getEventMirror():IEventDispatcher
+		{
+			if (!_eventMirror)
+				_eventMirror = new FlowElementEventDispatcher(this);
+			return _eventMirror;
+		}
+		
+		/** @private
+		 * Checks whether an event dispatcher is attached, and if so, if the event dispatcher
+		 * has any active listeners.
+		 */
+		public override function hasActiveEventMirror():Boolean
+		{ return _eventMirror && (_eventMirror._listenerCount != 0); }
+		
+		
+		/** @private This is done so that the TextContainerManager can discover EventMirrors in a TextFlow. */
+		public override function appendElementsForDelayedUpdate(tf:ITextFlow, changeType:String):void
+		{ 
+			if (changeType == ModelChange.ELEMENT_ADDED)
+			{
+				if (this.hasActiveEventMirror())
+				{
+					tf.incInteractiveObjectCount();
+					getParagraph().incInteractiveChildrenCount() ;
+				}
+			}
+			else if (changeType == ModelChange.ELEMENT_REMOVAL)
+			{
+				if (this.hasActiveEventMirror())
+				{
+					tf.decInteractiveObjectCount();
+					getParagraph().decInteractiveChildrenCount() ;
+				}
+			}
+			super.appendElementsForDelayedUpdate(tf,changeType);
+		}
+		
+		/** @private */
+		public override function createContentAsGroup(pos:int=0):GroupElement
+		{ return groupElement; }
+
+		/** @private */
+		public override function removeBlockElement(child:IFlowElement, block:ContentElement):void
+		{
+			var idx:int = this.getChildIndex(child);
+			groupElement.replaceElements(idx,idx+1,null);
+			CONFIG::debug { Debugging.traceFTECall(null,groupElement,"replaceElements",idx,idx+1,null); }
+		}
+		
+		/** @private */
+		public override function insertBlockElement(child:IFlowElement, block:ContentElement):void
+		{
+			if (groupElement)
+			{
+				var idx:int = this.getChildIndex(child);
+				var gc:Vector.<ContentElement> = new Vector.<ContentElement>();
+				CONFIG::debug { Debugging.traceFTECall(gc,null,"new Vector.<ContentElement>()"); }
+				gc.push(block);
+				CONFIG::debug { Debugging.traceFTECall(null,gc,"push",block); }
+				groupElement.replaceElements(idx,idx,gc);
+				CONFIG::debug { Debugging.traceFTECall(null,groupElement,"replaceElements",idx,idx,gc); }
+			}
+			else
+			{
+				child.releaseContentElement();
+				
+				var para:IParagraphElement = getParagraph();
+				if (para)
+					para.createTextBlock();
+			}
+		}
+		
+
+		/** @private */
+		public override function hasBlockElement():Boolean
+		{ return groupElement != null; }
+		
+		/** @private */
+		override public function setParentAndRelativeStart(newParent:IFlowGroupElement,newStart:int):void
+		{
+			if (newParent == parent)
+				return;
+		
+			// remove textElement from the parent content
+			if (parent && parent.hasBlockElement() && groupElement)
+				parent.removeBlockElement(this,groupElement);
+			if (newParent && !newParent.hasBlockElement() && groupElement)
+				newParent.createContentElement();
+					
+			super.setParentAndRelativeStart(newParent,newStart);
+			
+			// Update the FTE ContentElement structure. If the parent has FTE elements, then create FTE elements for the leaf node 
+			// if it doesn't already have them, and add them in. If the parent does not have FTE elements, release the leaf's FTE
+			// elements also so they match.
+			if (parent && parent.hasBlockElement())
+			{
+				if (!groupElement)
+					createContentElement();
+				else
+					parent.insertBlockElement(this,groupElement);
+			}
+		}
+		
+		/** @private */
+		public override function replaceChildren(beginChildIndex:int,endChildIndex:int,...rest):void
+		{
+				
+			var applyParams:Array = [beginChildIndex, endChildIndex];
+//TODO fix super
+			super.replaceChildren.apply(this, applyParams.concat(rest));
+			
+			var p:IParagraphElement = this.getParagraph();
+			if (p)
+				p.ensureTerminatorAfterReplace();
+		}
+		
+		/** @private */
+		public override function normalizeRange(normalizeStart:uint,normalizeEnd:uint):void
+		{
+			var idx:int = findChildIndexAtPosition(normalizeStart);
+			if (idx != -1 && idx < numChildren)
+			{
+				var child:IFlowElement = getChildAt(idx);
+				normalizeStart = normalizeStart-child.parentRelativeStart;
+				
+				CONFIG::debug { assert(normalizeStart >= 0, "bad normalizeStart in normalizeRange"); }
+				for (;;)
+				{
+					// watch out for changes in the length of the child
+					var origChildEnd:int = child.parentRelativeStart+child.textLength;
+					child.normalizeRange(normalizeStart,normalizeEnd-child.parentRelativeStart);
+					var newChildEnd:int = child.parentRelativeStart+child.textLength;
+					normalizeEnd += newChildEnd-origChildEnd;	// adjust
+					
+					// no zero length children
+					if (child.textLength == 0 && !child.bindableElement)
+						replaceChildren(idx,idx+1);
+					else if (child.mergeToPreviousIfPossible())
+					{
+						var prevElement:IFlowElement = this.getChildAt(idx-1);
+						// possibly optimize the start to the length of prevelement before the merge
+						prevElement.normalizeRange(0,prevElement.textLength);
+					}
+					else
+						idx++;
+
+					if (idx == numChildren)
+						break;
+					
+					// next child
+					child = getChildAt(idx);
+					
+					if (child.parentRelativeStart > normalizeEnd)
+						break;
+						
+					normalizeStart = 0;		// for the next child	
+				}
+			}
+			ElementHelper.normalizeSubParagraphRange(this);
+		}
+
+		/** @private 
+		 * SubParagraphGroupElement allow deep nesting, but LinkElements and TCYElements do not allow nesting (you can't have a link inside another
+		 * link no matter how many group elements are in between). This function is called only from within the class hierarchy to find out whether 
+		 * a sub-class allows nesting or not. */
+		public function get allowNesting():Boolean
+		{
+			return false;
+		}
+		
+		/** A LinkElement cannot be nested in another LinkElement, regardless of what elements are in between in the hierarchy.
+		 * Likewise a TCYElemen may not be nested. This function checks an incoming element to see if any of its children would
+		 * be disallowed if added to this. */
+		private function checkForNesting(element:SubParagraphGroupElementBase):Boolean
+		{
+			if (element)
+			{
+				if (!element.allowNesting)
+				{
+					if (this.className == element.className || this.getParentByType(element.className))
+						return false;
+				}
+				for (var i:int = element.numChildren - 1; i >= 0; --i)
+					if (!checkForNesting(element.getChildAt(i) as SubParagraphGroupElementBase))
+						return false;
+			}
+			return true;
+		}
+		
+		/** @private */
+		public override function canOwnFlowElement(elem:IFlowElement):Boolean
+		{
+			// Only allow sub-paragraph group elements (with restrictions) and leaf elements 
+			if (elem is IFlowLeafElement)
+				return true;
+			
+			if (elem is SubParagraphGroupElementBase && checkForNesting(elem as SubParagraphGroupElementBase))
+				return true;
+			
+			return false;
+		}
+		
+		/** Helper function for determination of where text should be inserted.  In the case of LinkElements,
+		 * text inserted before the LinkElement and text inserted after the LinkElement should not become
+		 * par of the link.  However, for most other SubParagraphGroupElementBase, inserted text should become
+		 * part of the SubParagraphGroupElementBase.
+		 * @private
+		 * */
+		public function acceptTextBefore():Boolean 
+		{ return true; }
+		
+		/** Helper function for determination of where text should be inserted.  In the case of LinkElements,
+		 * text inserted before the LinkElement and text inserted after the LinkElement should not become
+		 * par of the link.  However, for most other SubParagraphGroupElementBase, inserted text should become
+		 * part of the SubParagraphGroupElementBase.
+		 * @private
+		 * */
+		public function acceptTextAfter():Boolean
+		{ return true; }
+		
+		/** @private */
+		CONFIG::debug public override function debugCheckFlowElement(depth:int = 0, extraData:String = ""):int
+		{
+			// debugging function that asserts if the flow element tree is in an invalid state
+			var rslt:int = super.debugCheckFlowElement(depth," fte:"+getDebugIdentity(groupElement)+" "+extraData);
+			rslt += assert(getParagraph() != null && (parent is IParagraphElement || parent is SubParagraphGroupElementBase), "SubParagraphGroupElementBase must be nested in a pargraph");
+			
+			//groupElement can be null if the Paragraph is overset or not yet composed.  Don't check elementCount - Watson 2283828
+			if(this.groupElement)
+				rslt += assert(this.groupElement.elementCount == this.numChildren,"Bad element count in SubParagraphGroupElementBase");
+				
+			if (parent is IParagraphElement)
+				rslt += assert(this.groupElement != IParagraphElement(parent).getTextBlock().content,"Bad group");
+			return rslt; 
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TCYElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TCYElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TCYElement.as
new file mode 100644
index 0000000..3139c0b
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TCYElement.as
@@ -0,0 +1,141 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+	import org.apache.flex.text.engine.TextRotation;
+	import org.apache.flex.textLayout.debug.Debugging;
+	import org.apache.flex.textLayout.formats.BlockProgression;
+	
+	/** 
+	 * The TCYElement (Tatechuuyoko - ta-tae-chu-yo-ko) class is a subclass of SubParagraphGroupElementBase that causes
+	 * text to draw horizontally within a vertical line.  Traditionally, it is used to make small
+	 * blocks of non-Japanese text or numbers, such as dates, more readable.  TCY can be applied to 
+	 * horizontal text, but has no effect on drawing style unless and until it is turned vertically.
+	 * 
+	 * TCY blocks which contain no text will be removed from the text flow during the normalization process.
+	 * <p>
+	 * In the example below, the image on the right shows TCY applied to the number 57, while the
+	 * image on the left has no TCY formatting.</p>
+	 * <p><img src="../../../images/textLayout_TCYElement.png" alt="TCYElement" border="0"/>
+	 * </p>
+	 *
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 * @see TextFlow
+	 * @see ParagraphElement
+	 * @see SpanElement
+	 */
+	public final class TCYElement extends SubParagraphGroupElementBase implements ITCYElement
+	{
+		/** Constructor - creates a new TCYElement instance.
+		 *
+		 * @playerversion Flash 10
+	 	 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 *
+	 	 */
+		public function TCYElement()
+		{
+			super();
+		}
+		override public function get className():String{
+			return "TCYElement";
+		}
+		
+		/** @private */
+		override public function createContentElement():void
+		{
+			super.createContentElement();
+			updateTCYRotation();
+		}
+		
+		/** @private */
+		override protected function get abstract():Boolean
+		{ return false; }
+		
+		/** @private */
+		public override function get defaultTypeName():String
+		{ return "tcy"; }
+		
+		/** @private */
+        public override function get precedence():uint { return 100; }
+		
+		/** @private */
+		public override function mergeToPreviousIfPossible():Boolean
+		{	
+			if (parent && !bindableElement)
+			{
+				var myidx:int = parent.getChildIndex(this);
+				if (myidx != 0)
+				{
+					var prevEl:TCYElement = parent.getChildAt(myidx - 1) as TCYElement;
+					if(prevEl)
+					{
+						while(this.numChildren > 0)
+						{
+							var xferEl:IFlowElement = this.getChildAt(0);
+							replaceChildren(0, 1);
+							prevEl.replaceChildren(prevEl.numChildren, prevEl.numChildren, xferEl);
+						}
+						parent.replaceChildren(myidx, myidx + 1);								
+						return true;
+					}		
+				}
+			}
+			
+			return false;
+		}
+		
+		/** @private */
+		public override function acceptTextBefore():Boolean 
+		{ 
+			return false; 
+		}
+		
+		/** @private */
+		public override function setParentAndRelativeStart(newParent:IFlowGroupElement,newStart:int):void
+		{
+			super.setParentAndRelativeStart(newParent,newStart);
+			updateTCYRotation();
+		}
+		
+		/** @private */
+		public override function formatChanged(notifyModelChanged:Boolean = true):void
+		{
+			super.formatChanged(notifyModelChanged);
+			updateTCYRotation();
+		}
+		
+		
+		/** @private */
+		private function updateTCYRotation():void
+		{
+			var contElement:IContainerFormattedElement = getAncestorWithContainer();
+			if (groupElement)
+			{
+				groupElement.textRotation = (contElement && contElement.computedFormat.blockProgression == BlockProgression.RL) ? TextRotation.ROTATE_270 : TextRotation.ROTATE_0;
+				CONFIG::debug { Debugging.traceFTEAssign(groupElement,"textRotation",groupElement.textRotation); }
+			}
+		}
+	}
+	
+	
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TabElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TabElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TabElement.as
new file mode 100644
index 0000000..2879cae
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TabElement.as
@@ -0,0 +1,69 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{	
+
+
+	
+	/** 
+	 * The TabElement class represents a &lt;tab/&gt; in the text flow. You assign tab stops as an array of TabStopFormat objects to the 
+	 * <code>ParagraphElement.tabStops</code> property.
+	 * 
+	 * <p><strong>Note</strong>:This class exists primarily to support &lt;tab/&gt; in MXML markup. You can add tab characters (\t) directly 
+	 * into the text like this:</p>
+	 *
+	 * <listing version="3.0" >
+	 * spanElement1.text += '\t';
+	 * </listing>
+	 *
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 * @see org.apache.flex.textLayout.formats.TabStopFormat
+	 * @see FlowElement#tabStops
+	 * @see SpanElement
+	 */
+	 
+	public final class TabElement extends SpecialCharacterElement
+	{
+		/** Constructor - creates a new TabElement instance. 
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function TabElement()
+		{
+			super();
+			this.text = '\t';
+		}
+		override public function get className():String{
+			return "TabElement";
+		}
+		
+		/** @private */
+		override protected function get abstract():Boolean
+		{ return false; }
+
+		/** @private */
+		public override function get defaultTypeName():String
+		{ return "tab"; }
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableBlockContainer.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableBlockContainer.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableBlockContainer.as
new file mode 100644
index 0000000..5f3f39c
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableBlockContainer.as
@@ -0,0 +1,50 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+	import org.apache.flex.core.UIBase;
+	import org.apache.flex.textLayout.compose.ITextFlowTableBlock;
+	
+	/**
+	 * The sprite that contains the table cells. 
+	 **/
+	public class TableBlockContainer extends UIBase
+	{
+//TODO this should probably be an interface to support multiple UI implementations.
+// It's probably not going to work with either SVG or Canvas without hacks.
+		
+		public function TableBlockContainer()
+		{
+			super();
+		}
+		
+		/**
+		 * A reference to the TextFlowTableBlock
+		 **/
+		public var userData:ITextFlowTableBlock;
+		public function getTableWidth():Number
+		{
+			if(!userData)
+				return NaN;
+			if(!userData.parentTable)
+				return NaN;
+			return userData.parentTable.width;
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableBodyElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableBodyElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableBodyElement.as
new file mode 100644
index 0000000..4268118
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableBodyElement.as
@@ -0,0 +1,63 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+
+	
+
+	
+	/** 
+	 * <p> TableBodyElement is an item in a TableElement. It most commonly contains one or more TableRowElement objects, 
+	 * A TableBodyElement always appears within a TableElement.</p>
+	 *
+	 * 
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 */
+	public final class TableBodyElement extends TableFormattedElement
+	{		
+		override public function get className():String{
+			return "TableBodyElement";
+		}
+		public var height:Number;
+		
+		/** @private */
+		override protected function get abstract():Boolean
+		{ return false; }
+		
+		/** @private */
+		public override function get defaultTypeName():String
+		{ return "tbody"; }
+		
+		/** @private */
+		public override function canOwnFlowElement(elem:IFlowElement):Boolean
+		{
+			return (elem is ITableRowElement);
+		}
+		
+		/** @private if its in a numbered list expand the damage to all list items - causes the numbers to be regenerated */
+		public override function modelChanged(changeType:String, elem:IFlowElement, changeStart:int, changeLen:int, needNormalize:Boolean = true, bumpGeneration:Boolean = true):void
+		{
+			super.modelChanged(changeType,elem,changeStart,changeLen,needNormalize,bumpGeneration);
+		}
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableCellElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableCellElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableCellElement.as
new file mode 100644
index 0000000..45f0de5
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableCellElement.as
@@ -0,0 +1,457 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+	import org.apache.flex.textLayout.container.ContainerUtil;
+	import org.apache.flex.textLayout.factory.TLFFactory;
+	import org.apache.flex.textLayout.factory.ITLFFactory;
+	import org.apache.flex.reflection.getDefinitionByName;
+	import org.apache.flex.reflection.getQualifiedClassName;
+	
+	import org.apache.flex.textLayout.compose.ITextFlowLine;
+	import org.apache.flex.textLayout.container.IContainerController;
+	import org.apache.flex.textLayout.events.DamageEvent;
+	import org.apache.flex.textLayout.formats.BlockProgression;
+
+	
+
+	
+	/** 
+	 * TableCellElement is an item in a TableElement. It most commonly contains one or more ParagraphElement objects.
+	 *
+	 * 
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 */
+	public final class TableCellElement extends TableFormattedElement implements ITableCellElement
+	{		
+		private var _width:Number;
+		private var _height:Number;
+
+		private var _parcelIndex:int;
+		private var _container:CellContainer;
+		private var _enableIME:Boolean = true;
+		private var _damaged:Boolean = true;
+		private var _controller:IContainerController;
+
+		private var _rowSpan:uint = 1;
+		private var _columnSpan:uint = 1;
+		private var _rowIndex:int = -1;
+		private var _colIndex:int = -1;
+		private var _includeDescentInCellBounds:Boolean;
+		
+		public function TableCellElement()
+		{
+			super();
+			_controller = ContainerUtil.getController(container, NaN, NaN);
+		}
+		override public function get className():String{
+			return "TableCellElement";
+		}
+
+		/** @private */
+		override protected function get abstract():Boolean
+		{ return false; }
+		
+		/** @private */
+		public override function get defaultTypeName():String
+		{ return "td"; }
+		
+		/** @private */
+		public override function canOwnFlowElement(elem:IFlowElement):Boolean
+		{// Table cells have no TLF children. Instead it contains its own TextFlow.
+			return (elem is IFlowElement);
+		}
+
+		public function isDamaged():Boolean {
+			return _damaged || (_textFlow && _textFlow.flowComposer.isPotentiallyDamaged(_textFlow.textLength));
+		}
+		
+		private var _savedPaddingTop:Number = 0;
+		private var _savedPaddingBottom:Number = 0;
+		private var _savedPaddingLeft:Number = 0;
+		private var _savedPaddingRight:Number = 0;
+		
+		public function compose():Boolean {
+			
+			var pt:Number = getEffectivePaddingTop();
+			var pb:Number = getEffectivePaddingBottom();
+			var pl:Number = getEffectivePaddingLeft();
+			var pr:Number = getEffectivePaddingRight();
+
+			if(pt != _savedPaddingTop)
+			{
+				_controller.paddingTop = _savedPaddingTop = pt;
+			}
+			if(pb != _savedPaddingBottom)
+			{
+				_controller.paddingBottom = _savedPaddingBottom = pb;
+			}
+			if(pl != _savedPaddingLeft)
+			{
+				_controller.paddingLeft = _savedPaddingLeft = pl;
+			}
+			if(pr != _savedPaddingRight)
+			{
+				_controller.paddingRight = _savedPaddingRight = pr;
+			}
+
+			var table:ITableElement = this.table;
+			
+			_damaged = false;
+			
+			var compWidth:Number = 0;
+			for(var i:int=0;i<columnSpan;i++)
+			{
+				if (table && table.getColumnAt(colIndex+i)) {
+					compWidth += table.getColumnAt(colIndex+i).columnWidth;
+				}
+				
+			}
+			width = compWidth;
+
+			if (_textFlow && _textFlow.flowComposer) {
+				return _textFlow.flowComposer.compose();
+			}
+			
+			return false;
+		}
+		
+		public function update():Boolean
+		{
+			if(_textFlow && _textFlow.flowComposer){
+				return _textFlow.flowComposer.updateAllControllers();
+			}
+			return false;
+		}
+		
+		public function get parcelIndex():int
+		{
+			return _parcelIndex;
+		}
+		
+		public function set parcelIndex(value:int):void
+		{
+			_parcelIndex = value;
+		}
+		
+		public function get rowIndex():int
+		{
+			return _rowIndex;
+		}
+		
+		public function set rowIndex(value:int):void
+		{
+			_rowIndex = value;
+		}
+		
+		public function get colIndex():int
+		{
+			return _colIndex;
+		}
+		
+		public function set colIndex(value:int):void
+		{
+			_colIndex = value;
+		}
+		
+		protected var _textFlow:ITextFlow;
+		
+		public function get textFlow():ITextFlow {
+			
+			if (_textFlow == null) {
+				var tf:ITextFlow = getTextFlow();
+				var tlfFactory:ITLFFactory;
+				if(tf)
+					tlfFactory = tf.tlfFactory;
+
+				var flow:ITextFlow = ElementHelper.getDefaultTextFlow(tlfFactory);
+				
+				if (table && table.getTextFlow() && table.getTextFlow().interactionManager) {
+					flow.interactionManager = _textFlow.interactionManager.copy(true);
+				}
+				else if(table && table.getTextFlow() && table.getTextFlow().interactionManager) {
+					var im:Class = getDefinitionByName(getQualifiedClassName(table.getTextFlow().interactionManager)) as Class;
+					flow.interactionManager = new im();
+				}
+				else {
+					flow.normalize();
+				}
+				
+				_textFlow = flow;
+
+			}
+			
+			return _textFlow;
+		}
+		
+		public function set textFlow(value:ITextFlow):void
+		{
+			if (_textFlow) {
+				_textFlow.removeEventListener(DamageEvent.DAMAGE, handleCellDamage);
+				_textFlow.flowComposer.removeAllControllers();
+			}
+			
+			_textFlow = value;
+			_textFlow.parentElement = this;
+			_textFlow.flowComposer.addController(_controller);
+			_textFlow.addEventListener(DamageEvent.DAMAGE, handleCellDamage);
+			
+		}
+		
+		public function get controller():IContainerController {
+			return _controller;
+		}
+		
+		private function handleCellDamage(ev:DamageEvent):void{
+			damage();
+		}
+
+		public function get enableIME():Boolean
+		{
+			return _enableIME;
+		}
+
+		public function set enableIME(value:Boolean):void
+		{
+			_enableIME = value;
+		}
+		
+		public function get container():CellContainer{
+			if(!_container){
+				_container = new CellContainer(enableIME);
+				_container.cellElement = this;
+			}
+			
+			return _container;
+		}
+
+		/**
+		 * Gets the width.
+		 **/
+		public function get width():Number
+		{
+			return _width;
+		}
+
+		/**
+		 * @private
+		 **/
+		public function set width(value:Number):void
+		{
+			if(_width != value) {
+				_damaged = true;
+			}
+			
+			_width = value;
+			
+			_controller.setCompositionSize(_width, _controller.compositionHeight);
+		}
+		
+		/**
+		 * Returns the height of the cell. 
+		 **/
+		public function get height():Number
+		{
+			//return getRowHeight(); not sure if we should always use row height
+			return _height;
+		}
+
+		/**
+		 * @private
+		 **/
+		public function set height(value:Number):void
+		{
+			if (_height != value) {
+				_damaged = true;
+			}
+			
+			_height = value;
+			
+			_controller.setCompositionSize(_controller.compositionWidth, _height);
+		}
+		
+		public function getComposedHeight():Number
+		{
+			var descent:Number = 0;
+			if(!includeDescentInCellBounds)
+			{
+				if(_textFlow.flowComposer && _textFlow.flowComposer.numLines)
+				{
+					var lastLine:ITextFlowLine = _textFlow.flowComposer.getLineAt(_textFlow.flowComposer.numLines-1);
+					if(lastLine)
+						descent = lastLine.descent;
+				}
+			}
+			return (_controller.getContentBounds().height - descent);
+		}
+		
+		public function getRowHeight():Number
+		{
+			return getRow() ? getRow().composedHeight : NaN;
+		}
+
+		public function get rowSpan():uint
+		{
+			return _rowSpan;
+		}
+
+		public function set rowSpan(value:uint):void
+		{
+			if(value >= 1)
+				_rowSpan = value;
+		}
+
+		public function get columnSpan():uint
+		{
+			return _columnSpan;
+		}
+
+		public function set columnSpan(value:uint):void
+		{
+			if(value >= 1)
+				_columnSpan = value;
+		}
+		
+		public function updateCompositionShapes():void{
+			_controller.updateCompositionShapes();
+		}
+		
+		/**
+		 * Return the row that this cell is part of or null 
+		 * if not part of a row.
+		 **/
+		public function getRow():ITableRowElement
+		{
+			return table ? table.getRowAt(rowIndex) : null;
+		}
+		
+		/**
+		 * Returns the next cell in the table or null if not part of a
+		 * table or no cells exist after this cell.
+		 **/
+		public function getNextCell():ITableCellElement {
+			return table ? table.getNextCell(this) : null;
+		}
+		
+		/**
+		 * Returns the previous cell in the table or null if not part of a
+		 * table or no cells exist before this cell.
+		 **/
+		public function getPreviousCell():ITableCellElement {
+			return table ? table.getPreviousCell(this) : null;
+		}
+
+		public function get x():Number
+		{
+			return container.x;
+		}
+
+		public function set x(value:Number):void
+		{
+			container.x = value;
+		}
+
+		public function get y():Number
+		{
+			return container.y;
+		}
+
+		public function set y(value:Number):void
+		{
+			container.y = value;
+		}
+
+		public function damage():void
+		{
+			if (table) {
+				table.hasCellDamage = true;
+			}
+			
+			_damaged = true;
+		}
+		
+		/**
+		 * Adds in the table cell spacing, border stroke width. 
+		 * We may be able to set this value when the format changes. 
+		 * For now we just want to get it to work. 
+		 **/
+		public function getTotalPaddingWidth():Number {
+			var paddingAmount:Number = 0;
+			
+			// no textflow is no padding
+			if (!textFlow) {
+				return 0;
+			}
+			
+			if (table && table.cellSpacing!=undefined) {
+				paddingAmount += table.cellSpacing;
+			}
+			
+			if (textFlow.computedFormat.blockProgression == BlockProgression.RL) {
+				paddingAmount += Math.max(getEffectivePaddingTop() + getEffectivePaddingBottom(), getEffectiveBorderTopWidth() + getEffectiveBorderBottomWidth());
+			}
+			else {
+				paddingAmount += Math.max(getEffectivePaddingLeft() + getEffectivePaddingRight(), getEffectiveBorderLeftWidth() + getEffectiveBorderRightWidth());
+			}
+			
+			return paddingAmount;
+		}
+		
+		/**
+		 * Adds in the table cell spacing, border stroke height. 
+		 * We may be able to set this value when the format changes. 
+		 **/
+		public function getTotalPaddingHeight():Number {
+			var paddingAmount:Number = 0;
+			
+			// no textflow is no padding
+			if (!textFlow) {
+				return 0;
+			}
+			
+			if (table && table.cellSpacing!=undefined) {
+				paddingAmount += table.cellSpacing;
+			}
+			
+			if (textFlow.computedFormat.blockProgression == BlockProgression.RL) {
+				paddingAmount += Math.max(getEffectivePaddingLeft() + getEffectivePaddingRight(), getEffectiveBorderLeftWidth() + getEffectiveBorderRightWidth());
+			}
+			else {
+				paddingAmount += Math.max(getEffectivePaddingTop() + getEffectivePaddingBottom(), getEffectiveBorderTopWidth() + getEffectiveBorderBottomWidth());
+			}
+			
+			return paddingAmount;
+		}
+
+		public function get includeDescentInCellBounds():Boolean
+		{
+			return _includeDescentInCellBounds;
+		}
+
+		public function set includeDescentInCellBounds(value:Boolean):void
+		{
+			_includeDescentInCellBounds = value;
+		}
+
+		
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableColElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableColElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableColElement.as
new file mode 100644
index 0000000..449d1a3
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableColElement.as
@@ -0,0 +1,116 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+	import org.apache.flex.textLayout.formats.ITextLayoutFormat;
+
+	
+
+	
+	/** 
+	 * <p> TableColElement is an item in a TableElement. It only contains the information of the column formats, 
+	 * A TableColElement always appears within a TableElement, TableColGroupElement.</p>
+	 *
+	 * 
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 */
+	public final class TableColElement extends TableFormattedElement implements ITableColElement
+	{		
+		// public var height:Number;
+		private var _x:Number;
+		private var _colIndex:int;
+		
+		public function TableColElement(format:ITextLayoutFormat=null)
+		{
+			super();
+			if(format)
+				this.format = format;
+		}
+
+		override public function get className():String{
+			return "TableColElement";
+		}
+		/** @private */
+		override protected function get abstract():Boolean
+		{ return false; }
+		
+		/** @private */
+		public override function get defaultTypeName():String
+		{ return "col"; }
+		
+		/** @private */
+		public override function canOwnFlowElement(elem:IFlowElement):Boolean
+		{
+			return false;
+		}
+		
+		/** @private if its in a numbered list expand the damage to all list items - causes the numbers to be regenerated */
+		public override function modelChanged(changeType:String, elem:IFlowElement, changeStart:int, changeLen:int, needNormalize:Boolean = true, bumpGeneration:Boolean = true):void
+		{
+			super.modelChanged(changeType,elem,changeStart,changeLen,needNormalize,bumpGeneration);
+		}
+		
+		/**
+		 * Get a Vector of cells or null if the column contains no cells
+		 **/
+		public function get cells():Vector.<ITableCellElement> {
+			
+			if (!table) {
+				return null;
+			}
+			
+			return table.getCellsForColumn(this);
+		}
+		
+		/**
+		 * Returns the number of cells in this column. 
+		 **/
+		public function get numCells():int {
+			
+			if (!table) {
+				return 0;
+			}
+			
+			return table.getCellsForColumn(this).length;
+		}
+
+		public function get x():Number
+		{
+			return _x;
+		}
+
+		public function set x(x:Number):void
+		{
+			this._x = x;
+		}
+
+		public function get colIndex():int
+		{
+			return _colIndex;
+		}
+
+		public function set colIndex(colIndex:int):void
+		{
+			this._colIndex = colIndex;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableColGroupElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableColGroupElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableColGroupElement.as
new file mode 100644
index 0000000..92f3770
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableColGroupElement.as
@@ -0,0 +1,63 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+
+	
+
+	
+	/** 
+	 * <p> TableColGroupElement is an item in a TableElement. It most commonly contains one or more ParagraphElement objects, 
+	 * A TableRowElement always appears within a TableElement.</p>
+	 *
+	 * 
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 */
+	public final class TableColGroupElement extends TableFormattedElement
+	{
+		override public function get className():String{
+			return "TableColGroupElement";
+		}
+		public var height:Number;
+		
+		/** @private */
+		override protected function get abstract():Boolean
+		{ return false; }
+		
+		/** @private */
+		public override function get defaultTypeName():String
+		{ return "colgroup"; }
+		
+		/** @private */
+		public override function canOwnFlowElement(elem:IFlowElement):Boolean
+		{
+			return (elem is ITableColElement);
+		}
+		
+		/** @private if its in a numbered list expand the damage to all list items - causes the numbers to be regenerated */
+		public override function modelChanged(changeType:String, elem:IFlowElement, changeStart:int, changeLen:int, needNormalize:Boolean = true, bumpGeneration:Boolean = true):void
+		{
+			super.modelChanged(changeType,elem,changeStart,changeLen,needNormalize,bumpGeneration);
+		}
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableDataCellElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableDataCellElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableDataCellElement.as
new file mode 100644
index 0000000..c31435b
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/TableDataCellElement.as
@@ -0,0 +1,126 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 org.apache.flex.textLayout.elements
+{
+	
+
+	
+
+	
+	/** 
+	 * <p> TableDataCellElement is an item in a TableRowElement. It most commonly contains one or more IParagraphElement objects, 
+	 * A TableDataCellElement always appears within a TableRowElement.</p>
+	 *
+	 * 
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 */
+	public final class TableDataCellElement extends TableFormattedElement
+	{		
+		public var x:Number;
+		public var y:Number;
+		public var width:Number;
+		public var height:Number;
+		private var _parcelIndex:int;
+		
+		private var _rowIndex:int;
+		private var _colIndex:int;
+
+		override public function get className():String{
+			return "TableDataCellElement";
+		}
+		
+		/** @private */
+		override protected function get abstract():Boolean
+		{ return false; }
+		
+		/** @private */
+		public override function get defaultTypeName():String
+		{ return "td"; }
+		
+		/** @private if its in a numbered list expand the damage to all list items - causes the numbers to be regenerated */
+		public override function modelChanged(changeType:String, elem:IFlowElement, changeStart:int, changeLen:int, needNormalize:Boolean = true, bumpGeneration:Boolean = true):void
+		{
+			super.modelChanged(changeType,elem,changeStart,changeLen,needNormalize,bumpGeneration);
+		}
+		
+		/** @private ListItems must begin with zero or more divs with a paragraph */
+		public function normalizeNeedsInitialParagraph():Boolean
+		{
+			var p:FlowGroupElement = this;
+			while (p)
+			{
+				p = p.getChildAt(0) as FlowGroupElement;
+				if (p is IParagraphElement)
+					return false;
+				if (!(p is IDivElement))
+					return true;
+			}
+			return true;
+		}
+		
+		/** @private */
+		public override function normalizeRange(normalizeStart:uint,normalizeEnd:uint):void
+		{
+			super.normalizeRange(normalizeStart,normalizeEnd);
+			
+			// A TableDataCellElement must have a Paragraph at the start. 
+			// note not all browsers behave this way.
+			if (normalizeNeedsInitialParagraph())
+			{
+				var p:IParagraphElement = ElementHelper.getParagraph();
+				replaceChildren(0,0,p);	
+				p.normalizeRange(0,p.textLength);	
+			}
+		}
+		
+		public function get parcelIndex():int
+		{
+			return _parcelIndex;
+		}
+		
+		public function set parcelIndex(value:int):void
+		{
+			_parcelIndex = value;
+		}
+		
+		public function get rowIndex():int
+		{
+			return _rowIndex;
+		}
+		
+		public function set rowIndex(value:int):void
+		{
+			_rowIndex = value;
+		}
+		
+		public function get colIndex():int
+		{
+			return _colIndex;
+		}
+		
+		public function set colIndex(value:int):void
+		{
+			_colIndex = value;
+		}
+		
+	}
+}