flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ha...@apache.org
Subject [19/42] flex-asjs git commit: And here’s TLF…
Date Thu, 16 Mar 2017 13:37:39 GMT
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowGroupElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowGroupElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowGroupElement.as
new file mode 100644
index 0000000..671876a
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowGroupElement.as
@@ -0,0 +1,1111 @@
+// //////////////////////////////////////////////////////////////////////////////
+//
+// 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.ContentElement;
+	import org.apache.flex.text.engine.GroupElement;
+	import org.apache.flex.textLayout.compose.FlowDamageType;
+	import org.apache.flex.textLayout.container.IContainerController;
+	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;
+
+	[DefaultProperty("mxmlChildren")]
+	/** 
+	 * The FlowGroupElement class is the base class for FlowElement objects that can have an array of children. These classes include
+	 * TextFlow, ParagraphElement, DivElement, and LinkElement.
+	 *
+	 * <p>You cannot create a FlowGroupElement object directly. Invoking <code>new FlowGroupElement()</code> throws an error 
+	 * exception.</p>
+	 *
+	 * @playerversion Flash 10
+	 * @playerversion AIR 1.5
+	 * @langversion 3.0
+	 *
+	 * @see DivElement
+	 * @see LinkElement
+	 * @see ParagraphElement
+	 * @see TextFlow
+	 */
+	public class FlowGroupElement extends FlowElement implements IFlowGroupElement
+	{
+		/** children of the FlowGroupElement.  They must all be FlowElements. Depending on _numChildren either store a single child in _singleChild or multiple children in the array. */
+		private var _childArray:Array;
+		private var _singleChild:IFlowElement;
+		private var _numChildren:int;
+
+		/** Base class - invoking <code>new FlowGroupElement()</code> throws an error exception.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function FlowGroupElement()
+		{
+			_numChildren = 0;
+		}
+
+		override public function get className():String
+		{
+			return "FlowGroupElement";
+		}
+
+		/**
+		 *  @private 
+		 *  @flexjsignorecoercion org.apache.flex.textLayout.elements.IFlowGroupElement
+		 */
+		public override function deepCopy(startPos:int = 0, endPos:int = -1):IFlowElement
+		{
+			if (endPos == -1)
+				endPos = textLength;
+
+			var retFlow:IFlowGroupElement = shallowCopy(startPos, endPos) as IFlowGroupElement;
+			var newFlowElement:IFlowElement;
+			for (var idx:int = 0; idx < _numChildren; idx++)
+			{
+				var child:IFlowElement = getChildAt(idx);
+				if (((startPos - child.parentRelativeStart) < child.textLength) && ((endPos - child.parentRelativeStart) > 0))
+				{
+					// child is in Selected area
+					newFlowElement = child.deepCopy(startPos - child.parentRelativeStart, endPos - child.parentRelativeStart);
+					retFlow.replaceChildren(retFlow.numChildren, retFlow.numChildren, newFlowElement);
+					if (retFlow.numChildren > 1)
+					{
+						var possiblyEmptyFlowElement:IFlowElement = retFlow.getChildAt(retFlow.numChildren - 2);
+						if (possiblyEmptyFlowElement.textLength == 0)
+						{
+							retFlow.replaceChildren(retFlow.numChildren - 2, retFlow.numChildren - 1);
+						}
+					}
+				}
+			}
+			return retFlow;
+		}
+
+		/* @private */
+		public override function getText(relativeStart:int = 0, relativeEnd:int = -1, paragraphSeparator:String = "\n"):String
+		{
+			var text:String = super.getText();
+			return FlowGroupHelper.getText(this, text, relativeStart, relativeEnd, paragraphSeparator);
+		}
+
+		// ****************************************
+		// Begin TextLayoutFormat Related code
+		// ****************************************
+		/** @private */
+		public override function formatChanged(notifyModelChanged:Boolean = true):void
+		{
+			super.formatChanged(notifyModelChanged);
+			for (var idx:int = 0; idx < _numChildren; idx++)
+			{
+				var child:IFlowElement = getChildAt(idx);
+				child.formatChanged(false);
+			}
+		}
+
+		/** This gets called when an element has changed its style selection related attributes. This may happen because an
+		 * ancestor element changed it attributes.
+		 * @private 
+		 */
+		public override function styleSelectorChanged():void
+		{
+			super.styleSelectorChanged();
+			formatChanged(false);
+		}
+
+
+		// ****************************************
+		// End TLFFormat Related code
+		// ****************************************
+		// ****************************************
+		// Begin import helper code
+		// ****************************************
+		[RichTextContent]
+		/** 
+		 * Appends an array of children to this object. Uses the <code>replaceChildren()</code> method to append each 
+		 * element in the array. Intended for use during an mxml compiled import.
+		 * 
+		 * @throws TypeError if array element is not a FlowElement or String
+		 * @param array - array of children to attach.  Each element of the array must be a FlowElement object or a String.
+		 * @see FlowGroupElement#replaceChildren()
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0 
+		 */
+		public function get mxmlChildren():Array
+		{
+			return _numChildren == 0 ? null : (_numChildren == 1 ? [this._singleChild] : _childArray.slice() );
+		}
+
+		public function set mxmlChildren(array:Array):void
+		{
+			FlowGroupHelper.setMxmlChildren(this, array);
+		}
+
+		// ****************************************
+		// End import helper code
+		// ****************************************
+		// ****************************************
+		// Begin tree navigation code
+		// ****************************************
+		/** 
+		 * Returns the number of FlowElement children that this FlowGroupElement object has.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function get numChildren():int
+		{
+			return _numChildren;
+		}
+
+		/** 
+		 * Searches in children for the specified FlowElement object and returns its index position.
+		 *
+		 * @param child	The FlowElement object item to locate among the children.
+		 * @return The index position of the specified chilc.  If <code>child</code> is not found, returns -1.
+		 *  
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function getChildIndex(child:IFlowElement):int
+		{
+			var hi:int = _numChildren - 1;
+			// one hole here - if child is null and this has no children then we'll return 0
+			if (hi <= 0)
+				return _singleChild == child ? 0 : -1;
+
+			var lo:int = 0;
+			while (lo <= hi)
+			{
+				var mid:int = (lo + hi) / 2;
+				var p:IFlowElement = _childArray[mid];
+				if (p.parentRelativeStart == child.parentRelativeStart)
+				{
+					// during intermediate caluclations there are zero length elements lurking about
+					if (p == child)
+					{
+						CONFIG::debug
+						{
+							assert(_childArray.indexOf(child) == mid, "Bad getChildIndex"); }
+						return mid;
+					}
+					var testmid:int;
+					if (p.textLength == 0)
+					{
+						// look forward for a match
+						for (testmid = mid; testmid < _numChildren; testmid++)
+						{
+							p = _childArray[testmid];
+							if (p == child)
+							{
+								CONFIG::debug
+								{
+									assert(_childArray.indexOf(child) == testmid, "Bad getChildIndex"); }
+								return testmid;
+							}
+							if (p.textLength != 0)
+								break;
+						}
+					}
+
+					// look backwards
+					while (mid > 0)
+					{
+						mid--;
+						p = _childArray[mid];
+						if (p == child)
+						{
+							CONFIG::debug
+							{
+								assert(_childArray.indexOf(child) == mid, "Bad getChildIndex"); }
+							return mid;
+						}
+						if (p.textLength != 0)
+							break;
+					}
+					CONFIG::debug
+					{
+						assert(_childArray.indexOf(child) == -1, "Bad getChildIndex"); }
+					return -1;
+				}
+				if (p.parentRelativeStart < child.parentRelativeStart)
+					lo = mid + 1;
+				else
+					hi = mid - 1;
+			}
+			CONFIG::debug
+			{
+				assert(_childArray.indexOf(child) == -1, "Bad getChildIndex"); }
+			return -1;
+		}
+
+		/** 
+		 * Returns the FlowElement child at the specified index.
+		 * 
+		 * @param index the position at which to find the FlowElement object.
+		 *
+		 * @return  the child FlowElement object at the specified position.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function getChildAt(index:int):IFlowElement
+		{
+			if (_numChildren > 1)
+				return _childArray[index];
+			return index == 0 ? _singleChild : null;
+		}
+
+		/** @private */
+		public function getNextLeafHelper(limitElement:IFlowGroupElement, child:IFlowElement):IFlowLeafElement
+		{
+			var idx:int = getChildIndex(child);
+			if (idx == -1)
+				return null;	// bug?
+
+			if (idx == _numChildren - 1)
+			{
+				if (limitElement == this || !parent)
+					return null;
+
+				return parent.getNextLeafHelper(limitElement, this);
+			}
+
+			var childFlowElement:IFlowElement = getChildAt(idx + 1);
+			return (childFlowElement is IFlowLeafElement) ? IFlowLeafElement(childFlowElement) : FlowGroupElement(childFlowElement).getFirstLeaf();
+		}
+
+		/** @private */
+		public function getPreviousLeafHelper(limitElement:IFlowGroupElement, child:IFlowElement):IFlowLeafElement
+		{
+			var idx:int = getChildIndex(child);
+			if (idx == -1)
+				return null;	// bug?
+
+			if (idx == 0)
+			{
+				if (limitElement == this || !parent)
+					return null;
+
+				return parent.getPreviousLeafHelper(limitElement, this);
+			}
+
+			var childFlowElement:IFlowElement = getChildAt(idx - 1);
+			return (childFlowElement is IFlowLeafElement) ? IFlowLeafElement(childFlowElement) : FlowGroupElement(childFlowElement).getLastLeaf();
+		}
+
+		/**
+		 * Given a relative text position, find the leaf element that contains the position. 
+		 *
+		 * <p>Looks down the flow element hierarchy to find the IFlowLeafElement that 
+		 * contains the specified position. The specified position 
+		 * is relative to this FlowElement object.</p>
+		 *
+		 * @param relativePosition	relative text index to look up.
+		 * @return	the leaf element containing the relative position.
+		 *
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function findLeaf(relativePosition:int):IFlowLeafElement
+		{
+			var found:IFlowLeafElement = null;
+			var childIdx:int = findChildIndexAtPosition(relativePosition);
+			if (childIdx != -1)
+			{
+				// childIdx is index of the first child containing pos. Many of its following siblings
+				// may also contain pos if their respective previous siblings are zero-length.
+				// Check them all until a leaf containing pos is found.
+				do
+				{
+					var child:IFlowElement = this.getChildAt(childIdx++);
+					if (!child)
+						break;
+
+					var childRelativePos:int = relativePosition - child.parentRelativeStart;
+					if (child is FlowGroupElement)
+						found = IFlowGroupElement(child).findLeaf(childRelativePos);
+					else
+					{
+						// if its not a FlowGroupElement than it must be a FlowLeafElement
+						CONFIG::debug
+						{
+							assert(child is IFlowLeafElement, "Invalid child in FlowGroupElement.findLeaf"); }
+						if (childRelativePos >= 0 && childRelativePos < child.textLength || (child.textLength == 0 && _numChildren == 1))
+							found = IFlowLeafElement(child);
+					}
+				} while (!found && !child.textLength);
+			}
+			return found;
+		}
+
+		/**
+		 * Given a relative text position, find the index of the first child FlowElement that contains the relative position. 
+		 * More than one child can contain relative position because of zero length FlowElements.
+		 *  
+		 * <p>Examine the children to find the FlowElement that contains the relative position. The supplied relative position 
+		 * is relative to this FlowElement.</p>
+		 *
+		 * @param relativePosition 	the position relative to this element
+		 * @return 	index of first child element containing <code>relativePosition</code>
+		 *
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function findChildIndexAtPosition(relativePosition:int):int
+		{
+			var lo:int = 0;
+			var hi:int = _numChildren - 1;
+			while (lo <= hi)
+			{
+				var mid:int = (lo + hi) / 2;
+				var child:IFlowElement = getChildAt(mid);
+				if (child.parentRelativeStart <= relativePosition)
+				{
+					// always return the first zero length element in the list
+					if (child.parentRelativeStart == relativePosition)
+					{
+						while (mid != 0)
+						{
+							child = getChildAt(mid - 1);
+							if (child.textLength != 0)
+								break;
+							mid--;
+						}
+						return mid;
+					}
+					if (child.parentRelativeStart + child.textLength > relativePosition)
+						return mid;
+					lo = mid + 1;
+				}
+				else
+					hi = mid - 1;
+			}
+			return -1;
+		}
+
+		/**
+		 * Returns the first FlowLeafElement descendant of this group.
+		 *
+		 * @return the first FlowLeafElement object.
+		 *
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function getFirstLeaf():IFlowLeafElement
+		{
+			if (_numChildren > 1)
+			{
+				for (var idx:int = 0; idx < _numChildren; idx++)
+				{
+					var child:IFlowElement = _childArray[idx];
+					var leaf:IFlowLeafElement = (child is FlowGroupElement) ? FlowGroupElement(child).getFirstLeaf() : IFlowLeafElement(child);
+					if (leaf)
+						return leaf;
+				}
+				return null;
+			}
+			return _numChildren == 0 ? null : ((_singleChild is FlowGroupElement) ? FlowGroupElement(_singleChild).getFirstLeaf() : IFlowLeafElement(_singleChild));
+		}
+
+		/**
+		 * Returns the last FlowLeafElement descendent of this group.
+		 *
+		 * @return the last FlowLeafElement object.
+		 *
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function getLastLeaf():IFlowLeafElement
+		{
+			if (_numChildren > 1)
+			{
+				for (var idx:int = _numChildren; idx != 0; idx--)
+				{
+					var child:IFlowElement = _childArray[idx - 1];
+					var leaf:IFlowLeafElement = (child is FlowGroupElement) ? FlowGroupElement(child).getLastLeaf() : IFlowLeafElement(child) ;
+					if (leaf)
+						return leaf;
+				}
+				return null;
+			}
+			return _numChildren == 0 ? null : ((_singleChild is FlowGroupElement) ? FlowGroupElement(_singleChild).getLastLeaf() : IFlowLeafElement(_singleChild));
+		}
+
+		/** @private */
+		public override function getCharAtPosition(relativePosition:int):String
+		{
+			var leaf:IFlowLeafElement = findLeaf(relativePosition);
+			return leaf ? leaf.getCharAtPosition(relativePosition - leaf.getElementRelativeStart(this)) : "";
+		}
+
+		/** @private apply func to all elements until func says stop */
+		public override function applyFunctionToElements(func:Function):Boolean
+		{
+			if (func(this))
+				return true;
+			for (var idx:int = 0; idx < _numChildren; idx++)
+			{
+				if (getChildAt(idx).applyFunctionToElements(func))
+					return true;
+			}
+			return false;
+		}
+
+		// ****************************************
+		// End tree navigation code
+		// ****************************************
+		// ****************************************
+		// Begin tree modification support code
+		// ****************************************
+		/** @private */
+		public function removeBlockElement(child:IFlowElement, block:ContentElement):void
+		{
+			// when Image's are moved into ParagraphElement's this assertion should always fire
+			CONFIG::debug
+			{
+				assert(child is InlineGraphicElement, "invalid call to removeBlockElement"); }
+		}
+
+		/** @private */
+		public function insertBlockElement(child:IFlowElement, block:ContentElement):void
+		{
+			// when Image's are moved into ParagraphElement's this assertion should always fire
+			CONFIG::debug
+			{
+				assert(child is InlineGraphicElement, "invalid call to insertBlockElement"); }
+		}
+
+		/** @private 
+		 * True if there is a corresponding FTE data structure currently instantiated.
+		 */
+		public function hasBlockElement():Boolean
+		{
+			CONFIG::debug
+			{
+				assert(false, "invalid call to hasBlockElement"); }
+			return false;
+		}
+
+		/** @private */
+		public function createContentAsGroup(pos:int = 0):GroupElement
+		{
+			CONFIG::debug
+			{
+				assert(false, "invalid call to createContentAsGroup"); }
+			return null;
+		}
+
+		/** @private This is only called from SpanElement.splitAtPosition */
+		public function addChildAfterInternal(child:IFlowElement, newChild:IFlowElement):void
+		{
+			// this function was kept for efficiency purposes. It is used by splitForChange
+			// which in turn is used by applyCharacterFormat, when changing the
+			// attributes applied to characters.  In the end, the length of the document
+			// will be the same. So, without this fnction, we would be creating a new
+			// span, updating the lengths, and then removing a part of the span and updating
+			// the lengths again (getting the same exact lengths we had before). This can be
+			// inefficient. So, this function does everything addChildAfter does, without
+			// updating the lengths. This is an internal function since the user really has
+			// to know what they're doing and will not be exposed as a public API
+			CONFIG::debug
+			{
+				assert(_numChildren != 0, "addChildAfter must have children"); }
+			CONFIG::debug
+			{
+				assert(getChildIndex(child) != -1, "addChildAfter: before child must be in array"); }
+			if (_numChildren > 1)
+			{
+				// TODO: binary search for indexOf child
+				CONFIG::debug
+				{
+					assert(_childArray.indexOf(child) != -1, "Bad call to addChildAfterInternal"); }
+				_childArray.splice(_childArray.indexOf(child) + 1, 0, newChild);
+			}
+			else
+			{
+				// not found returns above returns -1 so behave the same
+				CONFIG::debug
+				{
+					assert(_singleChild == child, "Bad call to addChildAfterInternal"); }
+				_childArray = [_singleChild, newChild];
+				_singleChild = null;
+			}
+			_numChildren++;
+			newChild.setParentAndRelativeStartOnly(this, child.parentRelativeEnd);
+		}
+
+		/**
+		 * Helper for replaceChildren.  Determines if elem can legally be a child of this.
+		 * @return true --> ok, false--> not a legal child
+		 * @private 
+		 */
+		public function canOwnFlowElement(elem:IFlowElement):Boolean
+		{
+			return !(elem is ITextFlow) && !(elem is IFlowLeafElement) && !(elem is ISubParagraphGroupElementBase) && !(elem is IListItemElement) && !(elem is ITableElement);
+		}
+
+		/** @private */
+		private static function getNestedArgCount(obj:Object):uint
+		{
+			return (obj is Array) ? obj.length : 1;
+		}
+
+		/** @private */
+		private static function getNestedArg(obj:Object, index:uint):FlowElement
+		{
+			CONFIG::debug
+			{
+				assert(index < getNestedArgCount(obj), "bad index to getNestedArg"); }
+			return ((obj is Array) ? obj[index] : obj) as FlowElement;
+		}
+
+		/**
+		 * Replaces child elements in the group with the specified new elements. Use the <code>beginChildIndex</code> and
+		 * <code>endChildIndex</code> parameters to govern the operation as follows:
+		 * <p><ul>
+		 * <li>To delete elements, do not pass any replacement elements.</li>
+		 * <li>To insert elements, pass the same value for <code>beginChildIndex</code> and <code>endChildIndex</code>.  
+		 * The new elements is inserted before the specified index.</li>
+		 * <li>To append elements, pass <code>numChildren</code> for <code>beginChildIndex</code> and <code>endChildIndex</code>.</li>
+		 * </ul></p>
+		 * <p>Otherwise, this method replaces the specified elements, starting with the element at <code>beginChildIndex</code> 
+		 * and up to but not including <code>endChildIndex</code>.</p>
+		 * 
+		 * @param beginChildIndex The index value for the start position of the replacement range in the children array.
+		 * @param endChildIndex The index value following the end position of the replacement range in the children array.
+		 * @param rest The elements to replace the specified range of elements. Can be a sequence containing flow elements or
+		 * arrays or vectors thereof.
+		 *	 
+		 * @throws RangeError The <code>beginChildIndex</code> or <code>endChildIndex</code> specified is out of range.
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function replaceChildren(beginChildIndex:int, endChildIndex:int, ...rest):void
+		{
+			if (beginChildIndex > _numChildren || endChildIndex > _numChildren)
+				throw RangeError(GlobalSettings.resourceStringFunction("badReplaceChildrenIndex"));
+
+			var thisAbsStart:int = getAbsoluteStart();
+			var absStartIdx:int = thisAbsStart + (beginChildIndex == _numChildren ? textLength : getChildAt(beginChildIndex).parentRelativeStart);
+			var relStartIdx:int = beginChildIndex == _numChildren ? textLength : getChildAt(beginChildIndex).parentRelativeStart;
+
+			// deletion phase
+			if (beginChildIndex < endChildIndex)
+			{
+				var child:IFlowElement;	// scratch variable
+				var len:int = 0;
+
+				while (beginChildIndex < endChildIndex)
+				{
+					child = this.getChildAt(beginChildIndex);
+					this.modelChanged(ModelChange.ELEMENT_REMOVAL, child, child.parentRelativeStart, child.textLength);
+					child.removed();
+					len += child.textLength;
+
+					child.setParentAndRelativeStart(null, 0);
+					if (_numChildren == 1)
+					{
+						_singleChild = null;
+						_numChildren = 0;
+					}
+					else
+					{
+						_childArray.splice(beginChildIndex, 1);
+						_numChildren--;
+						if (_numChildren == 1)
+						{
+							_singleChild = _childArray[0];
+							_childArray = null;
+						}
+					}
+					endChildIndex--;
+				}
+				if (len)
+				{
+					// TODO: this code should move into updateLengths.  updateLengths needs a rewrite
+					// as it assumes that any element that is removed has its length set to zero and updateLengths
+					// is called on that element first.  replaceChildren doesn't do that - it just removes the element
+
+					// until rewrite reuse endChildIndex and update start of all following elements
+					while (endChildIndex < _numChildren)
+					{
+						child = getChildAt(endChildIndex);
+						child.setParentRelativeStart(child.parentRelativeStart - len);
+						endChildIndex++;
+					}
+
+					// update lengths
+					updateLengths(absStartIdx, -len, true);
+
+					deleteContainerText(relStartIdx + len, len);
+				}
+			}
+			CONFIG::debug
+			{
+				assert(thisAbsStart == getAbsoluteStart(), "replaceChildren: Bad thisAbsStart"); }
+			var childrenToAdd:int = 0;		// number of children to add
+			var flatNewChildList:Array;		// stores number of children when > 1
+			var newChildToAdd:IFlowElement;	// stores a single child to add - avoids creating an Array for the 99% case
+
+			var newChild:IFlowElement; 		// scratch
+			var idx:int;					// scratch
+
+			for each (var obj:Object in rest)
+			{
+				if (!obj)
+					continue;
+
+				var numNestedArgs:int = getNestedArgCount(obj);
+				for (idx = 0; idx < numNestedArgs; idx++)
+				{
+					newChild = getNestedArg(obj, idx);
+					if (newChild)
+					{
+						var newChildParent:IFlowGroupElement = newChild.parent;
+						if (newChildParent)
+						{
+							if (newChildParent == this)
+							{
+								// special handling in this case
+								var childIndex:int = getChildIndex(newChild);
+								newChildParent.removeChild(newChild);
+								thisAbsStart = getAbsoluteStart();	// is it in the same flow?
+								if (childIndex <= beginChildIndex)
+								{
+									beginChildIndex--;
+									absStartIdx = thisAbsStart + (beginChildIndex == _numChildren ? textLength : getChildAt(beginChildIndex).parentRelativeStart);
+									relStartIdx = beginChildIndex == _numChildren ? textLength : getChildAt(beginChildIndex).parentRelativeStart;
+								}
+							}
+							else
+							{
+								newChildParent.removeChild(newChild);
+								thisAbsStart = getAbsoluteStart();	// is it in the same flow?
+								absStartIdx = thisAbsStart + (beginChildIndex == _numChildren ? textLength : getChildAt(beginChildIndex).parentRelativeStart);
+								relStartIdx = beginChildIndex == _numChildren ? textLength : getChildAt(beginChildIndex).parentRelativeStart;
+							}
+						}
+
+						if (!canOwnFlowElement(newChild))
+						{
+							throw ArgumentError(GlobalSettings.resourceStringFunction("invalidChildType") + ". " + defaultTypeName + " cannot own " + newChild.defaultTypeName);
+						}
+
+						// manage as an array or a single child
+						if (childrenToAdd == 0)
+							newChildToAdd = newChild;
+						else if (childrenToAdd == 1)
+							flatNewChildList = [newChildToAdd, newChild];
+						else
+							flatNewChildList.push(newChild);
+						childrenToAdd++;
+					}
+				}
+			}
+
+			if (childrenToAdd)
+			{
+				// TODO-9/18/2008-ideally, do the following in one shot, but insertBlockElement
+				// called from setParentAndRelativeStart in the loop below has different behavior
+				// based on the size of _children (zero vs. non-zero)
+				// _children.splice(beginChildIndex,0,flatNewChildList);
+				var addedTextLength:uint = 0;
+				for (idx = 0; idx < childrenToAdd; idx++)
+				{
+					newChild = childrenToAdd == 1 ? newChildToAdd : flatNewChildList[idx];
+
+					if (_numChildren == 0)
+						_singleChild = newChild;
+					else if (_numChildren > 1)
+						_childArray.splice(beginChildIndex, 0, newChild);
+					else
+					{
+						_childArray = beginChildIndex == 0 ? [newChild, _singleChild] : [_singleChild, newChild];
+						_singleChild = null;
+					}
+					_numChildren++;
+					newChild.setParentAndRelativeStart(this, relStartIdx + addedTextLength);
+					addedTextLength += newChild.textLength;
+					beginChildIndex++;	// points to the next slot
+				}
+				CONFIG::debug
+				{
+					assert(thisAbsStart == getAbsoluteStart(), "replaceChildren: Bad thisAbsStart"); }
+				if (addedTextLength)
+				{
+					// update following elements - see comment above.
+					// it would be best if this loop only ran once
+					while (beginChildIndex < _numChildren)
+					{
+						child = getChildAt(beginChildIndex++);
+						child.setParentRelativeStart(child.parentRelativeStart + addedTextLength);
+					}
+					updateLengths(absStartIdx, addedTextLength, true);
+					var enclosingContainer:IContainerController = getEnclosingController(relStartIdx);
+					if (enclosingContainer)
+						enclosingContainer.setTextLength(enclosingContainer.textLength + addedTextLength);
+				}
+				for (idx = 0; idx < childrenToAdd; idx++)
+				{
+					newChild = childrenToAdd == 1 ? newChildToAdd : flatNewChildList[idx];
+					this.modelChanged(ModelChange.ELEMENT_ADDED, newChild, newChild.parentRelativeStart, newChild.textLength);
+				}
+			}
+			else
+			{
+				var tFlow:ITextFlow = getTextFlow();
+				if (tFlow != null)
+				{
+					// beginChildIndex points to the next element
+					// use scratch idx as "damageStart"
+					if (beginChildIndex < _numChildren)
+					{
+						// first, look for the next element and damage the beginning.
+						idx = thisAbsStart + getChildAt(beginChildIndex).parentRelativeStart;
+					}
+					else if (beginChildIndex > 1)
+					{
+						// damage the end of the previous element
+						newChild = getChildAt(beginChildIndex - 1);
+						idx = thisAbsStart + newChild.parentRelativeStart + newChild.textLength - 1;
+					}
+					else
+					{
+						// damage the very end of the textFlow
+						idx = thisAbsStart;
+						if (idx >= tFlow.textLength)
+							idx--;
+					}
+					tFlow.damage(idx, 1, FlowDamageType.INVALID, false);
+				}
+			}
+		}
+
+		/** 
+		 * Appends a child FlowElement object. The new child is added to the end of the children list.
+		 * 
+		 * @param child The child element to append.
+		 *
+		 * @return  the added child FlowElement 
+		 * 
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function addChild(child:IFlowElement):IFlowElement
+		{
+			replaceChildren(_numChildren, _numChildren, child);
+			return child;
+		}
+
+		/** 
+		 * Adds a child FlowElement object at the specified index position.
+		 *
+		 * @param The index of the position at which to add the child element, with the first position being 0.
+		 * @param child The child element to add.
+		 * @throws RangeError The <code>index</code> is out of range.
+		 *
+		 * @return  the added child FlowElement 
+		 *
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 *
+		 */
+		public function addChildAt(index:uint, child:IFlowElement):IFlowElement
+		{
+			replaceChildren(index, index, child);
+			return child;
+		}
+
+		/** 
+		 * Removes the specified child FlowElement object from the group.
+		 *
+		 * @param child The child element to remove.
+		 * @throws ArgumentError The <code>child</code> is not found.
+		 *
+		 * @return  the removed child FlowElement object 
+		 *
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 *
+		 */
+		public function removeChild(child:IFlowElement):IFlowElement
+		{
+			var index:int = getChildIndex(child);
+			if (index == -1)
+				throw ArgumentError(GlobalSettings.resourceStringFunction("badRemoveChild"));
+
+			removeChildAt(index);
+			return child;
+		}
+
+		/** 
+		 * Removes the child FlowElement object at the specified index position.
+		 *
+		 * @param index position at which to remove the child element.
+		 * @throws RangeError The <code>index</code> is out of range.
+		 *
+		 * @return  the child FlowElement object removed from the specified position.
+		 *
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function removeChildAt(index:uint):IFlowElement
+		{
+			var childToReplace:IFlowElement = getChildAt(index);
+			replaceChildren(index, index + 1);
+			return childToReplace;
+		}
+
+		/** 
+		 * Splits this object at the position specified by the <code>childIndex</code> parameter. If this group element has 
+		 * a parent, creates a shallow copy of this object and replaces its children with the elements up to the index. Moves 
+		 * elements following <code>childIndex</code> into the copy.
+		 * 
+		 * @return the new FlowGroupElement object.
+		 * @throws RangeError if <code>childIndex</code> is greater than the length of the children.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		public function splitAtIndex(childIndex:int):IFlowGroupElement
+		{
+			if (childIndex > _numChildren)
+				throw RangeError(GlobalSettings.resourceStringFunction("invalidSplitAtIndex"));
+
+			var newSibling:FlowGroupElement = shallowCopy() as FlowGroupElement;
+
+			var numChildrenToMove:int = _numChildren - childIndex;
+			if (numChildrenToMove == 1)
+				newSibling.addChild(removeChildAt(childIndex));
+			else if (numChildrenToMove != 0)
+			{
+				var childArray:Array = _childArray.slice(childIndex);
+				this.replaceChildren(childIndex, _numChildren - 1);
+				newSibling.replaceChildren(0, 0, childArray);
+			}
+
+			if (parent)
+			{
+				var myidx:int = parent.getChildIndex(this);
+				parent.replaceChildren(myidx + 1, myidx + 1, newSibling);
+			}
+
+			// This causes errors in operations that assume zero children. Normalizing makes this assumption not valid.
+			// newSibling.normalizeRange(0,newSibling.textLength);
+			return newSibling;
+		}
+
+		/** 
+		 * Splits this object at the position specified by the <code>relativePosition</code> parameter, where 
+		 * the relative position is a relative text position in this element.
+		 * 
+		 * @throws RangeError if relativePosition is greater than textLength, or less than 0.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 * 
+		 * @private
+		 */
+		public override function splitAtPosition(relativePosition:int):IFlowElement
+		{
+			// Creates a shallowCopy of this and adds it to parent after this.
+			// Moves elements from characterIndex forward into the copy
+			// returns the new shallowCopy
+			if ((relativePosition < 0) || (relativePosition > textLength))
+				throw RangeError(GlobalSettings.resourceStringFunction("invalidSplitAtPosition"));
+
+			var curElementIdx:int;
+
+			if (relativePosition == textLength)
+				curElementIdx = _numChildren;
+			else
+			{
+				curElementIdx = findChildIndexAtPosition(relativePosition);
+				var curFlowElement:IFlowElement = getChildAt(curElementIdx);
+
+				if (curFlowElement.parentRelativeStart != relativePosition)
+				{
+					if (curFlowElement.className == "FlowGroupElement")
+					{
+						FlowGroupElement(curFlowElement).splitAtPosition(relativePosition - curFlowElement.parentRelativeStart);
+					}
+					else
+					{
+						// I would imagine that it has to be a span.  That's the only non-FlowGroupElement
+						// type that can take up more than a textLength of 1.
+						CONFIG::debug
+						{
+							assert(curFlowElement.className == "SpanElement", "SpanElements are the only leaf elements that can currently have > 1 textLength");	}
+						ISpanElement(curFlowElement).splitAtPosition(relativePosition - curFlowElement.parentRelativeStart);
+					}
+					// increase by one. It's the new element that we want to move over.
+					curElementIdx++;
+				}
+			}
+
+			// increase by one. It's the new element that we want to move over.
+			return splitAtIndex(curElementIdx);
+		}
+
+		/** @private */
+		public override function normalizeRange(normalizeStart:uint, normalizeEnd:uint):void
+		{
+			var idx:int = findChildIndexAtPosition(normalizeStart);
+			if (idx != -1 && idx < _numChildren)
+			{
+				// backup over zero length children
+				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
+						idx++;
+
+					if (idx == _numChildren)
+						break;
+
+					// next child
+					child = getChildAt(idx);
+
+					if (child.parentRelativeStart > normalizeEnd)
+						break;
+
+					normalizeStart = 0;		// for the next child
+				}
+			}
+		}
+
+		/** @private */
+		public override function applyWhiteSpaceCollapse(collapse:String):void
+		{
+			if (collapse == null)
+				collapse = this.computedFormat.whiteSpaceCollapse;	// top of the cascade?
+			else
+			{
+				var ffc:ITextLayoutFormat = this.formatForCascade;
+				var wsc:* = ffc ? ffc.whiteSpaceCollapse : undefined;
+				if (wsc !== undefined && wsc != FormatValue.INHERIT)
+					collapse = wsc;
+			}
+			for (var idx:int = 0; idx < _numChildren;)
+			{
+				var child:IFlowElement = getChildAt(idx);
+				child.applyWhiteSpaceCollapse(collapse);
+				if (child.parent == this)	// check to see if child was removed (could have been
+					++idx;
+			}
+
+			// If the element was added automatically, it may now have no content and needs to be removed
+			// This can happen with whitespace between paragraphs that is added by set mxmlChildren
+			if (textLength == 0 && impliedElement && parent != null)
+				parent.removeChild(this);
+
+			super.applyWhiteSpaceCollapse(collapse);
+		}
+
+		/** @private */
+		public override function appendElementsForDelayedUpdate(tf:ITextFlow, changeType:String):void
+		{
+			for (var idx:int = 0; idx < _numChildren; idx++)
+			{
+				var child:IFlowElement = getChildAt(idx);
+				child.appendElementsForDelayedUpdate(tf, changeType);
+			}
+		}
+		// ****************************************
+		// End tree modification support code
+		// ****************************************
+		// ****************************************
+		// Begin debug support code
+		// ****************************************
+		/** @private */
+		CONFIG::debug
+		public override function debugCheckFlowElement(depth:int = 0, extraData:String = ""):int
+		{
+			var rslt:int = super.debugCheckFlowElement(depth, extraData);
+
+			// debugging function that asserts if the flow element is in an invalid state
+			var totalChildLength:int = 0;
+			if (_numChildren)
+			{
+				for (var childIndex:int = 0; childIndex < _numChildren; ++childIndex)
+				{
+					var child:IFlowElement = getChildAt(childIndex);
+					rslt += assert(child.parent == this, "child doesn't point to parent");
+
+					// totalChildLength is relative offset to child
+					rslt += assert(child.parentRelativeStart == totalChildLength, "child start offset wrong");
+					rslt += child.debugCheckFlowElement(depth + 1);
+					totalChildLength += child.textLength;
+				}
+			}
+			else
+			{
+				// only spans may own text
+				rslt += assert(this is ISpanElement || textLength == 0, "only spans may have text");
+				totalChildLength = textLength;
+			}
+			assert(totalChildLength == textLength, "child total textLength wrong");
+			return rslt;
+		}
+		// **************************************** 
+		// End debug support code
+		// ****************************************
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowGroupHelper.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowGroupHelper.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowGroupHelper.as
new file mode 100644
index 0000000..195458f
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowGroupHelper.as
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.reflection.getQualifiedClassName;
+	
+	public class FlowGroupHelper
+	{
+		public static function setMxmlChildren(group:IFlowGroupElement,array:Array):void
+		{
+						/* NOTE: all FlowElement implementers and overrides of mxmlChildren must specify [RichTextContent] metadata */
+
+			// remove all existing children
+			group.replaceChildren(0,group.numChildren);
+			
+			// In the text model, non-ParagraphFormattedElements (i.e. spans, images, links, TCY) cannot be children of a ContainerFormattedElement (TextFlow, IDivElement etc.)
+			// They can only be children of paragraphs or subparagraph blocks. 
+			// In XML, however, <p> elements can be implied (for example, a <span> may appear as a direct child of <flow>).  
+			// So, while parsing the XML, if we enounter a non-ParagraphFormattedElement child of a ContainerFormattedElement 
+			// 1. an explicitly created paragraph is used as the parent instead
+			// 2. such explicitly created paragraphs are shared by adjacent flow elements provided there isn't an intervening ParagraphFormattedElement
+			var effectiveParent:IFlowGroupElement = group; 
+			
+			// append them on the end		
+			for each (var child:Object in array)
+			{
+				if (child is IFlowElement)
+				{
+					if (child is IParagraphFormattedElement)
+					{
+						// Reset due to possibly intervening FlowParagrpahElement; See note 2. above
+						effectiveParent = group; 
+					}
+					else if (effectiveParent is IContainerFormattedElement)
+					{
+						// See note 1. above
+						effectiveParent = ElementHelper.getParagraph();	// NO PMD
+						effectiveParent.impliedElement = true;
+						group.replaceChildren(group.numChildren, group.numChildren, effectiveParent);
+					}
+					if ( (child is ISpanElement) || (child is ISubParagraphGroupElementBase))
+						child.bindableElement = true;
+					effectiveParent.replaceChildren(effectiveParent.numChildren, effectiveParent.numChildren, IFlowElement(child) );
+				}
+				else if (child is String)
+				{
+					var s:ISpanElement = ElementHelper.getSpan();	// NO PMD
+					s.text = String(child);
+					s.bindableElement = true;
+					s.impliedElement = true;
+					
+					if (effectiveParent is IContainerFormattedElement)
+					{
+						// See note 1. above
+	 					effectiveParent = ElementHelper.getParagraph();	// No PMD
+						group.replaceChildren(group.numChildren, group.numChildren, effectiveParent);
+						effectiveParent.impliedElement = true;
+					}
+					effectiveParent.replaceChildren(effectiveParent.numChildren, effectiveParent.numChildren, s);
+				}
+				else if (child != null)
+					throw new TypeError(GlobalSettings.resourceStringFunction("badMXMLChildrenArgument",[ getQualifiedClassName(child) ]));	// NO PMD
+			}
+		}
+		public static function getText(group:IFlowGroupElement,text:String,relativeStart:int=0, relativeEnd:int=-1, paragraphSeparator:String="\n"):String{
+			if (relativeEnd == -1 || relativeEnd >group. textLength)
+				relativeEnd = group.textLength;
+			
+			if (relativeStart < 0)
+				relativeStart = 0;
+				
+			var pos:int = relativeStart;
+			for (var idx:int = group.findChildIndexAtPosition(relativeStart); idx >= 0 && idx < group.numChildren && pos < relativeEnd; idx++)
+			{
+				var child:IFlowElement = group.getChildAt(idx);
+				var copyStart:int = pos - child.parentRelativeStart;
+				var copyEnd:int = Math.min(relativeEnd - child.parentRelativeStart, child.textLength);
+				text += child.getText(copyStart, copyEnd, paragraphSeparator);
+				pos += copyEnd - copyStart;
+				if (paragraphSeparator && child is IParagraphFormattedElement && pos < relativeEnd)
+					text += paragraphSeparator;
+			}
+			return text;
+			
+		}
+	}
+}
\ 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/FlowLeafElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowLeafElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowLeafElement.as
new file mode 100644
index 0000000..891ee35
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowLeafElement.as
@@ -0,0 +1,441 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.elements.utils.GeometricElementUtils;
+	import org.apache.flex.graphics.PathBuilder;
+	import org.apache.flex.graphics.SolidColorStroke;
+	import org.apache.flex.graphics.SolidColor;
+	import org.apache.flex.graphics.ICompoundGraphic;
+	import org.apache.flex.events.IEventDispatcher;
+	import org.apache.flex.geom.Rectangle;
+	import org.apache.flex.text.engine.ContentElement;
+	import org.apache.flex.text.engine.ElementFormat;
+	import org.apache.flex.text.engine.FontDescription;
+	import org.apache.flex.text.engine.FontMetrics;
+	import org.apache.flex.text.engine.ITextLine;
+	import org.apache.flex.text.engine.TextBaseline;
+	import org.apache.flex.text.engine.TextElement;
+	import org.apache.flex.text.engine.TextRotation;
+	import org.apache.flex.text.engine.TypographicCase;
+	import org.apache.flex.textLayout.compose.ISWFContext;
+	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;
+	import org.apache.flex.textLayout.formats.BackgroundColor;
+	import org.apache.flex.textLayout.formats.BaselineShift;
+	import org.apache.flex.textLayout.formats.BlockProgression;
+	import org.apache.flex.textLayout.formats.ColorName;
+	import org.apache.flex.textLayout.formats.FormatValue;
+	import org.apache.flex.textLayout.formats.IMEStatus;
+	import org.apache.flex.textLayout.formats.ITextLayoutFormat;
+	import org.apache.flex.textLayout.formats.TLFTypographicCase;
+	import org.apache.flex.textLayout.formats.TextDecoration;
+	import org.apache.flex.textLayout.formats.TextLayoutFormat;
+
+	import org.apache.flex.textLayout.utils.CharacterUtil;
+	import org.apache.flex.textLayout.utils.LocaleUtil;
+
+
+		
+	
+	/** Base class for FlowElements that appear at the lowest level of the flow hierarchy. FlowLeafElement objects have
+	* no children and include InlineGraphicElement objects and SpanElement objects.
+	*
+	* @playerversion Flash 10
+	* @playerversion AIR 1.5
+	* @langversion 3.0
+	*
+	* @see InlineGraphicElement
+	* @see SpanElement
+	*/
+	public class FlowLeafElement extends FlowElement implements IFlowLeafElement	{				
+		/** Holds the content of the leaf @private */
+		protected var _blockElement:ContentElement;
+		
+		/** @private
+		 * Holds the text for the leaf element - unless there's a valid blockElement, 
+		 * in which case the text is in the rawText field of the blockElement.
+		 */
+		protected var _text:String;	// holds the text property if the blockElement is null
+		private var _hasAttachedListeners:Boolean;	// true if FTE eventMirror may be in use
+		
+		/** @private The event dispatcher that acts as an event mirror */
+		public var _eventMirror:FlowElementEventDispatcher = null;
+		
+		/** 
+		 * Base class - invoking new FlowLeafElement() throws an error exception. 
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 * 
+		 */
+		public function FlowLeafElement()
+		{
+			_hasAttachedListeners = false;
+			super();
+		}
+		override public function get className():String
+		{
+			return "FlowLeafElement";
+		}
+
+		//TODO this should not be here!
+		public function set text(value:String):void{
+			// do nothing        
+		}
+		
+		/** @private */
+		override public function createContentElement():void
+		{
+			CONFIG::debug { assert(_blockElement != null, "_blockElement not allocated in derived class"); }
+			if (_computedFormat)
+			{
+				_blockElement.elementFormat = computeElementFormat();
+				CONFIG::debug { Debugging.traceFTEAssign(_blockElement,"elementFormat",_blockElement.elementFormat); }
+			}
+			if (parent)
+				parent.insertBlockElement(this,_blockElement);
+		}
+		/** @private */
+		override public function releaseContentElement():void
+		{
+			_blockElement = null;
+			_computedFormat = null;
+		}
+		
+//		private function blockElementExists():Boolean
+//		{
+//			return _blockElement != null;
+//		}
+
+		/** @private */
+		public function getBlockElement():ContentElement
+		{ 
+			if (!_blockElement)
+				createContentElement();
+			return _blockElement; 
+		}
+		
+		/** @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);
+		}
+		
+		/**
+		 * The text associated with the FlowLeafElement:
+		 * <p><ul>
+		 * <li>The value for SpanElement subclass will be one character less than <code>textLength</code> if this is the last span in a ParagraphELement.</li>
+		 * <li>The value for BreakElement subclass is a U+2028</li>
+		 * <li>The value for TabElement subclass is a tab</li>
+		 * <li>The value for InlineGraphicElement subclass is U+FDEF</li>
+		 * </ul></p>
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 *
+	 	 * @see org.apache.flex.textLayout.elements.SpanElement#replaceText()
+		 */
+		public function get text():String
+		{
+			return _text;
+		}
+		
+		/** @private */
+		public function getElementFormat():ElementFormat
+		{ 			
+			if (!_blockElement)
+				createContentElement();
+			return _blockElement.elementFormat; 
+ 		}
+		
+		/** @private */
+		public override function setParentAndRelativeStart(newParent:IFlowGroupElement,newStart:int):void
+		{
+			if (newParent == parent)
+				return;
+		
+			var hasBlock:Boolean = _blockElement != null;
+			
+			if (_blockElement && parent && parent.hasBlockElement())	// remove textElement from the parent content
+				parent.removeBlockElement(this,_blockElement);
+			if (newParent && !newParent.hasBlockElement() && _blockElement)
+				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)
+			{
+				if (parent.hasBlockElement())
+				{
+					if (!_blockElement)
+						createContentElement();
+					else if (hasBlock)	// don't do this if the _blockElement was constructed as side-effect of setParentAndRelativeStart; in that case, it's already attached
+						parent.insertBlockElement(this,_blockElement);
+				}
+				else if (_blockElement)
+					releaseContentElement();
+			}
+		}
+	
+		/** @private Only used by SpanElement.splitAtPosition */
+		public function quickInitializeForSplit(sibling:FlowLeafElement,newSpanLength:int,newSpanTextElement:TextElement):void
+		{
+			setTextLength(newSpanLength);
+			_blockElement = newSpanTextElement;
+			if (_blockElement)
+				_text = _blockElement.text;
+			quickCloneTextLayoutFormat(sibling);
+			var tf:ITextFlow = sibling.getTextFlow();
+			if (tf == null || tf.formatResolver == null)
+			{
+				_computedFormat = sibling._computedFormat;
+				if (_blockElement)
+					_blockElement.elementFormat = sibling.getElementFormat();
+			}
+		}
+		
+		/**
+		 * Returns the next FlowLeafElement object.  
+		 * 
+		 * @param limitElement	Specifies FlowGroupElement on whose last leaf to stop looking. A value of null (default) 
+		 * 	means search till no more elements.
+		 * @return 	next FlowLeafElement or null if at the end
+		 *
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 *
+		 */
+		 
+		 public function getNextLeaf(limitElement:IFlowGroupElement=null):IFlowLeafElement
+		{
+			if (!parent)
+				return null;
+			return parent.getNextLeafHelper(limitElement,this);
+		}
+		
+		/**
+		 * Returns the previous FlowLeafElement object.  
+		 * 
+		 * @param limitElement	Specifies the FlowGroupElement on whose first leaf to stop looking.   null (default) means search till no more elements.
+		 * @return 	previous leafElement or null if at the end
+		 *
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 *
+		 */
+		 
+		public function getPreviousLeaf(limitElement:IFlowGroupElement=null):IFlowLeafElement
+		{
+			if (!parent)
+				return null;
+			return parent.getPreviousLeafHelper(limitElement,this);
+		}
+		
+		/** @private */
+		public override function getCharAtPosition(relativePosition:int):String
+		{
+			return _text ?  _text.charAt(relativePosition) : "";
+		} 
+		
+		/** @private */
+		public override function normalizeRange(normalizeStart:uint,normalizeEnd:uint):void
+		{
+			// this does the cascade - potential optimization to skip it if the _blockElement isn't attached
+			if (_blockElement)
+				calculateComputedFormat();
+		}
+		
+		/** Returns the FontMetrics object for the span. The properties of the FontMetrics object describe the 
+		 * emBox, strikethrough position, strikethrough thickness, underline position, 
+		 * and underline thickness for the specified font. 
+		 *
+ 		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 *
+		 * @see org.apache.flex.text.engine.FontMetrics
+		 * @see org.apache.flex.text.engine.ElementFormat#getFontMetrics()
+		 *
+		 * @return font metrics associated with the span
+		 */
+		public function getComputedFontMetrics():FontMetrics
+		{
+			if (!_blockElement)
+				createContentElement();
+			if(!_blockElement)
+				return null;
+			var ef:ElementFormat = _blockElement.elementFormat;
+			if (!ef)
+				return null;
+				
+			var tf:ITextFlow = getTextFlow();
+			if (tf && tf.flowComposer && tf.flowComposer.swfContext)
+				return tf.flowComposer.swfContext.callInContext(ef.getFontMetrics,ef,null,true);
+			return ef.getFontMetrics();
+		}
+		
+
+		/** @private */
+		public function computeElementFormat():ElementFormat
+		{
+			CONFIG::debug { assert(_computedFormat != null,"bad call to computeElementFormat"); }
+
+			var tf:ITextFlow = getTextFlow();
+			return GeometricElementUtils.computeElementFormatHelper (_computedFormat, getParagraph(), tf && tf.flowComposer ? tf.flowComposer.swfContext : null);
+		}
+		
+		
+		/** 
+		 * The computed text format attributes that are in effect for this element.
+		 * Takes into account the inheritance of attributes.
+		 *
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+	 	 * @langversion 3.0
+	 	 *
+		 * @see org.apache.flex.textLayout.formats.ITextLayoutFormat
+		 */
+		public override function get computedFormat():ITextLayoutFormat
+		{		
+			if (!_computedFormat)
+			{
+				_computedFormat = doComputeTextLayoutFormat();
+
+				if (_blockElement)
+				{
+					_blockElement.elementFormat = computeElementFormat();
+					CONFIG::debug { Debugging.traceFTEAssign(_blockElement,"elementFormat",_blockElement.elementFormat); }
+				}
+
+			}
+			return _computedFormat;
+		}
+		
+		/** Returns the calculated lineHeight from this element's properties.  @private */
+		public function getEffectiveLineHeight(blockProgression:String):Number
+		{
+			//ignore the leading on a TCY Block. If the element is in a TCYBlock, it has no leading
+			if (blockProgression == BlockProgression.RL && (parent.className == "TCYElement"))
+				return 0;
+			CONFIG::debug { assert(_computedFormat != null,"Missing _computedFormat in FlowLeafElement.getEffectiveLineHeight"); }
+			return TextLayoutFormat.lineHeightProperty.computeActualPropertyValue(computedFormat.lineHeight, getEffectiveFontSize());
+		}
+		
+		/** @private 
+		 * Get the "inline box" for the element as defined by the CSS visual formatting model (http://www.w3.org/TR/CSS2/visuren.html)
+		 * @param	blockProgression	Block progression
+		 * @param	textLine			The containing text line
+		 * @param	para				The containing para. Only used for resolving AUTO dominantBaseline value. 
+		 * 								May be null, in which case the AUTO dominantBaseline value is resolved based on other attributes (such as the element's computed locale). 	
+		 * @param	swfContext			The SWF context in which certain method calls (such as the one used to get font metrics) are made
+		 * 								May be null in which case the current SWF context is used.
+		 * @return 						Null if the element is not "inline"
+		 * 								Otherwise, a rectangle representing the inline box. Top and Bottom are relative to the line's Roman baseline. Left and Right are ignored.
+		 */
+		public function getCSSInlineBox(blockProgression:String, textLine:ITextLine, para:IParagraphElement=null, swfContext:ISWFContext=null):Rectangle
+		{
+			// TODO-9/27/10: TCYs typically don't affect leading, but this may not be appropriate for LeadingModel.BOX 
+			if (blockProgression == BlockProgression.RL && (parent.className == "TCYElement"))
+				return null;
+			
+			return GeometricElementUtils.getCSSInlineBoxHelper (computedFormat, getComputedFontMetrics(), textLine, para);
+		}
+		
+		/** Returns the fontSize from this element's properties.  @private */
+		public function getEffectiveFontSize():Number
+		{
+			return Number(computedFormat.fontSize);
+		}
+
+		/** @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(_blockElement)+" "+extraData);
+			
+			// TODO: eventually these tests will be valid for InlineGraphicElement elements as well
+			if (!(IFlowLeafElement is InlineGraphicElement))
+			{
+				rslt += assert(textLength != 0 || bindableElement || (parent is ISubParagraphGroupElementBase && parent.numChildren == 1), "FlowLeafElement with zero textLength must be deleted"); 
+				rslt += assert(parent is IParagraphElement || parent is ISubParagraphGroupElementBase, "FlowLeafElement must have a ParagraphElement or SubParagraphGroupElementBase parent");
+			}
+			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/FlowValueHolder.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowValueHolder.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowValueHolder.as
new file mode 100644
index 0000000..8e73d6f
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/FlowValueHolder.as
@@ -0,0 +1,71 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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;
+
+	
+
+
+	// [ExcludeClass]
+	/** This class extends TextLayoutFormat and add capabilities to hold privateData and userStyles.  @private */
+	public class FlowValueHolder extends TextLayoutFormat
+	{
+		private var _privateData:Object;
+		
+		public function FlowValueHolder(initialValues:FlowValueHolder = null)
+		{
+			super(initialValues);
+			initialize(initialValues);
+		}
+		
+		private function initialize(initialValues:FlowValueHolder):void
+		{
+			if (initialValues)
+			{
+				var s:String;
+				for (s in initialValues.privateData)
+					setPrivateData(s, initialValues.privateData[s]);
+			}
+		}
+
+
+		public function get privateData():Object
+		{ return _privateData; }
+		public function set privateData(val:Object):void
+		{ _privateData = val; }
+
+		public function getPrivateData(styleProp:String):*
+		{ return _privateData ? _privateData[styleProp] : undefined; }
+
+		public function setPrivateData(styleProp:String,newValue:*):void
+		{
+			if (newValue === undefined)
+			{
+				if (_privateData)
+					delete _privateData[styleProp];
+			}
+			else
+			{
+				if (_privateData == null)
+					_privateData = {};
+				_privateData[styleProp] = newValue;
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/GlobalSettings.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/GlobalSettings.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/GlobalSettings.as
new file mode 100644
index 0000000..87f21dc
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/GlobalSettings.as
@@ -0,0 +1,245 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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
+{
+
+
+    
+    /** Configuration that applies to all TextFlow objects.
+     * @playerversion Flash 10
+     * @playerversion AIR 1.5
+     */
+    public class GlobalSettings 
+    {
+        /** 
+        * Specifies the callback used for font mapping.
+        * The callback takes a <code>org.apache.flex.text.engine.FontDescription</code> object and updates it as needed.
+        * 
+        * After setting a new font mapping callback, or changing the behavior of the exisiting font mapping callback, 
+        * the client must explicitly call <code>org.apache.flex.textLayout.elements.TextFlow.invalidateAllFormats</code> for each impacted text flow.
+        * This ensures that whenever a leaf element in the text flow is next recomposed, the FontDescription applied to it is recalculated, and the the callback is invoked. 
+        * 
+        * @see org.apache.flex.text.engine.FontDescription FontDescription
+        * @see TextFlow.invalidateAllFormats invalidateAllFormats
+        * 
+        * @playerversion Flash 10
+        * @playerversion AIR 1.5
+        * @langversion 3.0
+        */
+        public static function get fontMapperFunction():Function
+        { 
+            return _fontMapperFunction; 
+        }
+        public static function set fontMapperFunction(val:Function):void
+        {
+            _fontMapperFunction = val;
+        }
+        
+        private static var _fontMapperFunction:Function;
+        
+        /** Controls whether the text will be visible to a search engine indexer. Defaults to <code>true</code>.
+         * 
+         * @playerversion Flash 10
+         * @playerversion AIR 1.5
+         * @langversion 3.0
+         */
+        public static function get enableSearch():Boolean
+        {
+            return _enableSearch;
+        }
+        public static function set enableSearch(value:Boolean):void
+        {
+            _enableSearch = value;
+        }
+        
+        private static var _enableSearch:Boolean = true;
+    
+        /** 
+         * Specifies the callback used for changing the FontLookup based on swfcontext.  The function will be called each time an ElementFormat is computed.
+         * It gives the client the opportunity to modify the FontLookup setting.  The function is called with two parameters an ISWFContext and an ITextLayoutFormat.
+         * It must return a valid FontLookup.
+         * 
+         * @see org.apache.flex.textLayout.compose.ISWFContext
+         * @see org.apache.flex.textLayout.formats.ITextLayoutFormat
+         * @see org.apache.flex.text.engine.ElementFormat
+         * @see org.apache.flex.text.engine.FontLookup
+         * 
+         * @playerversion Flash 10
+         * @playerversion AIR 1.5
+         * @langversion 3.0
+         */
+        public static function get resolveFontLookupFunction():Function
+        { 
+            return _resolveFontLookupFunction; 
+        }
+        public static function set resolveFontLookupFunction(val:Function):void
+        {
+            _resolveFontLookupFunction = val;
+        }
+        private static var _resolveFontLookupFunction:Function;
+        
+        /** Function that takes two parameters, a resource id and an optional array of parameters to substitute into the string.
+         * The string is of form "Content {0} more content {1}".  The parameters are read from the optional array and substituted for the bracketed substrings.
+         * TLF provides a default implementation with
+         * default strings.  Clients may replace this function with their own implementation for localization.
+         * 
+         * @playerversion Flash 10
+         * @playerversion AIR 1.5
+         * @langversion 3.0
+         */
+        public static function get resourceStringFunction():Function
+        { 
+            return _resourceStringFunction; 
+        }
+        public static function set resourceStringFunction(val:Function):void
+        {
+            _resourceStringFunction = val;
+        }
+        
+        private static var _resourceStringFunction:Function = defaultResourceStringFunction;
+        
+        /** @private */
+        
+        private static const resourceDict:Object = 
+        {
+            missingStringResource:          "No string for resource {0}",
+            // core errors
+            invalidFlowElementConstruct:    "Attempted construct of invalid FlowElement subclass",
+            invalidSplitAtPosition:         "Invalid parameter to splitAtPosition",
+            badMXMLChildrenArgument:        "Bad element of type {0} passed to mxmlChildren",
+            badReplaceChildrenIndex:        "Out of range index to FlowGroupElement.replaceChildren",
+            invalidChildType:               "NewElement not of a type that this can be parent of",
+            badRemoveChild:                 "Child to remove not found",
+            invalidSplitAtIndex:            "Invalid parameter to splitAtIndex",
+            badShallowCopyRange:            "Bad range in shallowCopy",
+            badSurrogatePairCopy:           "Copying only half of a surrogate pair in SpanElement.shallowCopy",
+            invalidReplaceTextPositions:    "Invalid positions passed to SpanElement.replaceText",
+            invalidSurrogatePairSplit:      "Invalid splitting of a surrogate pair",
+            badPropertyValue:               "Property {0} value {1} is out of range",
+            // selection/editing
+            illegalOperation:               "Illegal attempt to execute {0} operation",
+            // shared import errors
+            unexpectedXMLElementInSpan:     "Unexpected element {0} within a span",
+            unexpectedNamespace:            "Unexpected namespace {0}",
+            unknownElement:                 "Unknown element {0}",
+            unknownAttribute:               "Attribute {0} not permitted in element {1}",
+            // html format import errors
+            malformedTag:                   "Malformed tag {0}",
+            malformedMarkup:                "Malformed markup {0}",
+            // textlayoutformat import errors
+            missingTextFlow:                "No TextFlow to parse",
+            expectedExactlyOneTextLayoutFormat: "Expected one and only one TextLayoutFormat in {0}",    
+            expectedExactlyOneListMarkerFormat: "Expected one and only one ListMarkerFormat in {0}",
+            unsupportedVersion:         "Version {0} is unsupported",
+            // shared import/export errors
+            unsupportedProperty:            "Property {0} is unsupported"
+        };
+        
+        /** @private */
+        public static function defaultResourceStringFunction(resourceName:String, parameters:Array = null):String
+        {
+            var value:String = String(resourceDict[resourceName]);
+            
+            if (value == null)
+            {
+                value = String(resourceDict["missingStringResource"]);
+                parameters = [ resourceName ];
+            }
+            
+            if (parameters)
+                value = substitute(value, parameters);
+            
+            return value;
+        }
+        
+        /** @private */
+        public static function substitute(str:String, ... rest):String
+        {
+            if (str == null) 
+                return '';
+            
+            // Replace all of the parameters in the msg string.
+            var len:uint = rest.length;
+            var args:Array;
+            if (len == 1 && rest[0] is Array)
+            {
+                args = rest[0] as Array;
+                len = args.length;
+            }
+            else
+            {
+                args = rest;
+            }
+            
+            for (var i:int = 0; i < len; i++)
+            {
+                str = str.replace(new RegExp("\\{"+i+"\\}", "g"), args[i]);
+            }
+            
+            return str;
+        }
+        
+
+        private static var _enableDefaultTabStops:Boolean = false;
+        /** 
+         * @private Player versions prior to 10.1 do not set up any default tabStops. As a workaround, if enableDefaultTabs
+         * is true, TLF will set up default tabStops in the case where there are no tabs defined.
+         * 
+         */     
+        public static function get enableDefaultTabStops():Boolean
+        {
+            return _enableDefaultTabStops;
+        }
+        /** 
+         * @private 
+         */         
+        public static function set enableDefaultTabStops(val:Boolean):void
+        {
+            _enableDefaultTabStops = val;
+        }
+		
+		private static var _alwaysCalculateWhitespaceBounds:Boolean = false;
+		/** 
+		 * @private If this is true, we will always calculate whitespace width in line bounds.
+		 * if this is false, we will see if lineBreak="explicit" or when the logical width is NaN, 
+		 * the content bounds includes the spaces at the end of the line. With lineBreak="toFit" 
+		 * the spaces are not included. 
+		 * 
+		 */     
+		public static function get alwaysCalculateWhitespaceBounds():Boolean
+		{
+			return _alwaysCalculateWhitespaceBounds;
+		}
+		/** 
+		 * @private 
+		 */         
+		public static function set alwaysCalculateWhitespaceBounds(val:Boolean):void
+		{
+			_alwaysCalculateWhitespaceBounds = val;
+		}
+		
+		//		static public const playerEnablesSpicyFeatures:Boolean = versionIsAtLeast(10,2) && (new Sprite).hasOwnProperty("needsSoftKeyboard"); 
+//		static public const hasTouchScreen:Boolean = playerEnablesArgoFeatures && Capabilities["touchScreenType"] != "none";
+
+//TODO make these meaningful. How???
+		static public const playerEnablesSpicyFeatures:Boolean = false; 
+		static public const hasTouchScreen:Boolean = false;
+		
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/IBackgroundManager.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/IBackgroundManager.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/IBackgroundManager.as
new file mode 100644
index 0000000..eab6d06
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/IBackgroundManager.as
@@ -0,0 +1,54 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.elements.IFlowElement;
+	import org.apache.flex.geom.Rectangle;
+	import org.apache.flex.textLayout.container.IContainerController;
+	import org.apache.flex.text.engine.ITextLine;
+	import org.apache.flex.textLayout.elements.IFlowLeafElement;
+	import org.apache.flex.textLayout.compose.ITextFlowLine;
+	import org.apache.flex.textLayout.elements.ITextFlow;
+	import org.apache.flex.graphics.IGraphicShape;
+
+	public interface IBackgroundManager
+	{
+		function clearBlockRecord():void;
+
+		function addBlockRect(elem:IFlowElement, r:Rectangle, cc:IContainerController = null, style:String = null):void;
+
+		function addBlockElement(elem:IFlowElement):void;
+
+		function addRect(tl:ITextLine, fle:IFlowLeafElement, r:Rectangle, color:uint, alpha:Number):void;
+
+		function addNumberLine(tl:ITextLine, numberLine:ITextLine):void;
+
+		function finalizeLine(line:ITextFlowLine):void;
+
+		function getEntry(line:ITextLine):*;
+
+		function drawAllRects(textFlow:ITextFlow, bgShape:IGraphicShape, constrainWidth:Number, constrainHeight:Number):void;
+
+		function removeLineFromCache(tl:ITextLine):void;
+
+		function onUpdateComplete(controller:IContainerController):void;
+
+		function getShapeRectArray():Array;
+	}
+}
\ 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/IBreakElement.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/IBreakElement.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/IBreakElement.as
new file mode 100644
index 0000000..f7098b2
--- /dev/null
+++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/elements/IBreakElement.as
@@ -0,0 +1,24 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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
+{
+	public interface IBreakElement extends ISpecialCharacterElement
+	{
+	}
+}
\ No newline at end of file


Mime
View raw message