You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by pi...@apache.org on 2014/11/28 01:20:44 UTC

[04/25] git commit: [flex-tlf] [refs/heads/develop] - Commit of table work

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/container/ContainerController.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/container/ContainerController.as b/textLayout/src/flashx/textLayout/container/ContainerController.as
index a4e63f1..2e375f4 100644
--- a/textLayout/src/flashx/textLayout/container/ContainerController.as
+++ b/textLayout/src/flashx/textLayout/container/ContainerController.as
@@ -48,6 +48,7 @@ package flashx.textLayout.container
 	import flashx.textLayout.compose.FlowDamageType;
 	import flashx.textLayout.compose.IFlowComposer;
 	import flashx.textLayout.compose.TextFlowLine;
+	import flashx.textLayout.compose.TextFlowTableBlock;
 	import flashx.textLayout.compose.TextLineRecycler;
 	import flashx.textLayout.debug.Debugging;
 	import flashx.textLayout.debug.assert;
@@ -56,6 +57,8 @@ package flashx.textLayout.container
 	import flashx.textLayout.edit.ISelectionManager;
 	import flashx.textLayout.edit.SelectionFormat;
 	import flashx.textLayout.elements.BackgroundManager;
+	import flashx.textLayout.elements.CellCoordinates;
+	import flashx.textLayout.elements.CellRange;
 	import flashx.textLayout.elements.Configuration;
 	import flashx.textLayout.elements.ContainerFormattedElement;
 	import flashx.textLayout.elements.FlowElement;
@@ -64,6 +67,10 @@ package flashx.textLayout.container
 	import flashx.textLayout.elements.InlineGraphicElement;
 	import flashx.textLayout.elements.LinkElement;
 	import flashx.textLayout.elements.ParagraphElement;
+	import flashx.textLayout.elements.TableBlockContainer;
+	import flashx.textLayout.elements.TableCellElement;
+	import flashx.textLayout.elements.TableElement;
+	import flashx.textLayout.elements.TableRowElement;
 	import flashx.textLayout.elements.TextFlow;
 	import flashx.textLayout.events.FlowElementMouseEvent;
 	import flashx.textLayout.events.FlowElementMouseEventManager;
@@ -112,7 +119,6 @@ package flashx.textLayout.container
 	public class ContainerController implements IInteractionEventHandler, ITextLayoutFormat, ISandboxSupport
 	{		
 		static tlf_internal var usesDiscretionaryHyphens:Boolean = true;
-		static tlf_internal var startComposeFromBeginning:Boolean = false;
 		
 		private var _textFlowCache:TextFlow;
 		private var _rootElement:ContainerFormattedElement;
@@ -178,6 +184,7 @@ package flashx.textLayout.container
 		
 		private var _linesInView:Array;	// lines that were in view according to the previous compose(). Empty if the lines have already been posted to the display list.
 		private var _updateStart:int;
+		private var _tableBlocksInView:Array; // // table blocks that were in view according to the previous compose(). Empty if the lines have already been posted to the display list.
 		
 		private var _composedFloats:Array;  // floats that were composed into the controller -- array of FloatCompositionData
 		private var _floatsInContainer:Array;  // floats are currently in view -- array of DisplayObject
@@ -267,6 +274,7 @@ package flashx.textLayout.container
 			
 			_shapeChildren = [ ];
 			_linesInView = [ ];
+			_tableBlocksInView = [];
 			
 			setCompositionSize(compositionWidth, compositionHeight);
 			format = _containerControllerInitialFormat;
@@ -397,7 +405,7 @@ package flashx.textLayout.container
 		/** 
 		 * Sets the width and height allowed for text in the container. Width and height can be specified in pixels or <code>NaN</code> can be used for either value.  <code>NaN</code> indicates measure that value. 
 		 * This can be used to find the widest line and/or the total height of all the content.  When NaN is specified as the width lines are broken with a maximum width of <code>TextLine.MAX_LINE_WIDTH</code>. 
-		 * When <code>NaN</code> is specified as the height the container is assumed to have unlimited height.  The actual measured values can be ready back in <code>getContentBounds</code>.  
+		 * When <code>NaN</code> is specified as the height the container is assumed to have unlimited height.  The actual measured values can be read back in <code>getContentBounds</code>.  
 		 * When the computed <code>blockProgression</code> property of <code>TextFlow</code>
 		 * is <code>BlockProgression.RL</code> the meanings of width and height are exchanged.
 		 *
@@ -415,7 +423,7 @@ package flashx.textLayout.container
 		 * @langversion 3.0
 		 */
 		
-		public function setCompositionSize(w:Number,h:Number):void
+		public function setCompositionSize(w:Number, h:Number):void
 		{
 		//	trace("setCompositionSize(" + w + ", " + h + ")");
 			
@@ -737,13 +745,19 @@ package flashx.textLayout.container
 				var curLine:TextFlowLine;
 				var textLine:TextLine;
 				var lineIndex:int;
+				var testRslt:*;
 				
 				//Use binary search when there is one single column
 				if(columnCount == 1)
 				{
 					// First just test the firstLine - normal unscrolled case
-					curLine = flowComposer.getLineAt(firstLine);	
-					textLine = testLineVisible(wmode, scrollAdjustXTW, scrollAdjustYTW, scrollAdjustWidthTW, scrollAdjustHeightTW, curLine, null) as TextLine;
+					var testPos:int = firstLine;
+					curLine = flowComposer.getLineAt(testPos++);
+					while(curLine && curLine is TextFlowTableBlock)
+						curLine = flowComposer.getLineAt(testPos++);
+					
+					testRslt = testLineVisible(wmode, scrollAdjustXTW, scrollAdjustYTW, scrollAdjustWidthTW, scrollAdjustHeightTW, curLine, null)
+					textLine = testRslt as TextLine;
 					firstLine++;	// its been tested
 					if (textLine)
 					{
@@ -759,10 +773,11 @@ package flashx.textLayout.container
 							var mid:int = (firstLine+hi)/2;
 							CONFIG::debug { assert(mid != 0,"ContainerController:gatherVisibleLines: bad mid"); }
 							curLine = flowComposer.getLineAt(mid);
-							var testRslt:* = testLineVisible(wmode, scrollAdjustXTW, scrollAdjustYTW, scrollAdjustWidthTW, scrollAdjustHeightTW, curLine, null);
-							textLine = testRslt as TextLine;
-							if (textLine)
+							testRslt = testLineVisible(wmode, scrollAdjustXTW, scrollAdjustYTW, scrollAdjustWidthTW, scrollAdjustHeightTW, curLine, null);
+							
+							if (testRslt && testRslt is TextLine)
 							{
+								textLine = testRslt as TextLine;
 								// note that we tested firstLine above so going to mid-1 is always valid
 								var tempLine:TextFlowLine = flowComposer.getLineAt(mid-1);
 								if (!(testLineVisible(wmode, scrollAdjustXTW, scrollAdjustYTW, scrollAdjustWidthTW, scrollAdjustHeightTW, tempLine, null) is TextLine))
@@ -776,6 +791,8 @@ package flashx.textLayout.container
 								}
 								testRslt = -1;	// past the start
 							}
+							// need to deal with TextFlowTableBlocks
+							
 							if (testRslt < 0 || testRslt == 2)
 								hi = mid-1;
 							else
@@ -785,8 +802,12 @@ package flashx.textLayout.container
 					
 					for (lineIndex = firstLine; lineIndex <= lastLine; lineIndex++)
 					{
-						curLine = flowComposer.getLineAt(lineIndex);	
-						textLine = testLineVisible(wmode, scrollAdjustXTW, scrollAdjustYTW, scrollAdjustWidthTW, scrollAdjustHeightTW, curLine, null) as TextLine;
+						curLine = flowComposer.getLineAt(lineIndex);
+						testRslt = testLineVisible(wmode, scrollAdjustXTW, scrollAdjustYTW, scrollAdjustWidthTW, scrollAdjustHeightTW, curLine, null);
+						
+						if(testRslt is TableBlockContainer)
+							continue;
+						textLine = testRslt as TextLine;
 						if (!textLine)
 							break;
 		
@@ -2811,6 +2832,42 @@ package flashx.textLayout.container
 			addSelectionChild(selObj);
 		}
 		
+		/** Add cell selection shapes to the displaylist. @private */
+		tlf_internal function addCellSelectionShapes(color:uint, tableBlock:TextFlowTableBlock, startCoords:CellCoordinates, endCoords:CellCoordinates): void
+		{
+			if(!tableBlock)
+				return;
+			if(!startCoords.isValid() || !endCoords.isValid())
+				return;
+			var cells:Vector.<TableCellElement> = tableBlock.getCellsInRange(startCoords,endCoords);
+			var selObj:Shape = new Shape();
+			selObj.graphics.beginFill(color);
+			for each( var cell:TableCellElement in cells)
+			{
+				var row:TableRowElement = cell.getRow();
+				var r:Rectangle = new Rectangle(cell.x, cell.y + tableBlock.y, cell.width, row.composedHeight);
+				selObj.graphics.drawRect(r.x,r.y,r.width,r.height);
+			}
+			addSelectionChild(selObj);
+		}
+		
+		/** 
+		 * Add cell selection shapes to the displaylist.
+		 * */
+		tlf_internal function addCellSelections(cells:Array, color:uint, tableBlock:TextFlowTableBlock): void
+		{
+			var shape:Shape = new Shape();
+			shape.graphics.beginFill(color);
+			
+			for each(var cell:TableCellElement in cells) {
+				var row:TableRowElement = cell.getRow();
+				var rectangle:Rectangle = new Rectangle(cell.x, cell.y + tableBlock.y, cell.width, row.composedHeight);
+				shape.graphics.drawRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+			}
+			
+			addSelectionChild(shape);
+		}
+		
 		/** Add selection shapes to the displaylist. @private */
 		tlf_internal function addSelectionShapes(selFormat:SelectionFormat, selectionAbsoluteStart:int, selectionAbsoluteEnd:int): void
 		{
@@ -2855,6 +2912,7 @@ package flashx.textLayout.container
 				{
 					nextLine = idx != flowComposer.numLines - 1 ? flowComposer.getLineAt(idx+1) : null;
 					
+					// 9-1-14 Harbs Do we draw a selection rect for tables? If yes, this needs special handling in TextFlowTableBlock
 					line.hiliteBlockSelection(selObj, selFormat, this._container,
 						selectionAbsoluteStart < line.absoluteStart ? line.absoluteStart : selectionAbsoluteStart,
 						selectionAbsoluteEnd > line.absoluteStart+line.textLength ? line.absoluteStart+line.textLength : selectionAbsoluteEnd, prevLine, nextLine);
@@ -2903,7 +2961,7 @@ package flashx.textLayout.container
 		{
 			// If there's no selectionSprite on this controller, we use the parent's.
 			// That means we have to translate the coordinates.
-			// TODO: this only supports one level of ntesting
+			// TODO: this only supports one level of nesting
 			var selectionSprite:DisplayObjectContainer = getSelectionSprite(true);
 			
 			if (selectionSprite == null)
@@ -2918,7 +2976,7 @@ package flashx.textLayout.container
 				selectionSprite.blendMode = curBlendMode;
 			
 			if (selectionSprite.alpha != curAlpha)
-				selectionSprite.alpha = curAlpha;
+				selectionSprite.alpha = 1;//curAlpha; testing remove this 
 			
 			if (selectionSprite.numChildren == 0)
 				addSelectionContainer(selectionSprite);
@@ -3042,10 +3100,13 @@ package flashx.textLayout.container
 		{
 			setTextLength(0); 
 			
-			for each (var textLine:TextLine in _shapeChildren)
+			for each (var line:* in _shapeChildren)
 			{
-				removeTextLine(textLine);
-				CONFIG::debug { Debugging.traceFTECall(null,_container,"removeTextLine",textLine); }
+				if(line is TextLine)
+					removeTextLine(line as TextLine);
+				else
+					removeTableBlock(line as TableBlockContainer);
+				CONFIG::debug { Debugging.traceFTECall(null,_container,"removeTextLine",line); }
 			}
 			_shapeChildren.length = 0;
 			_linesInView.length = 0;
@@ -3058,6 +3119,21 @@ package flashx.textLayout.container
 		
 		private static var scratchRectangle:Rectangle = new Rectangle();
 		
+		private function intersperseTableBlocks(targetArray:Array):void{
+			if(_tableBlocksInView.length == 0)
+				return;
+			var blockIdx:int = 0;
+			var startLoc:int = (_tableBlocksInView[0] as TableBlockContainer).userData.parentTable.getAbsoluteStart();
+			for(var i:int=0;i<targetArray.length;i++){
+				if( targetArray[i].userData.absoluteStart < startLoc )
+					continue;
+				targetArray.splice(i,0,_tableBlocksInView[blockIdx++]);
+				if(blockIdx == _tableBlocksInView.length)
+					break;
+			}
+			while(blockIdx < _tableBlocksInView.length)
+				targetArray.push(_tableBlocksInView[blockIdx++]);
+		}
 		/** Add DisplayObjects that were created by composition to the container. @private */
 		tlf_internal function updateCompositionShapes():void
 		{
@@ -3085,6 +3161,9 @@ package flashx.textLayout.container
 			fillShapeChildren();
 			var newShapeChildren:Array = _linesInView;
 			
+			// Add in table blocks
+			intersperseTableBlocks(newShapeChildren);
+			
 			var childIdx:int = getFirstTextLineChildIndex(); // index where the first text line must appear at in its container  
 			var newIdx:int = 0;		// offset into newShapeChildren
 			var shapeChildrenStartIdx:int = 0;	// starting offset into shapeChildren
@@ -3096,11 +3175,14 @@ package flashx.textLayout.container
 			// beginning as usual. This can happen if we're scrolled forward, and then edit the first visible line.
 			if (_updateStart > absoluteStart && newShapeChildren.length > 0)
 			{
-				var firstTextLine:TextLine = newShapeChildren[0];
-				var firstLine:TextFlowLine = TextFlowLine(firstTextLine.userData);
+				var firstLine:TextFlowLine = TextFlowLine(newShapeChildren[0].userData);
 				var prevLine:TextFlowLine = flowComposer.findLineAtPosition(firstLine.absoluteStart - 1);
-				var prevTextLine:TextLine = prevLine.peekTextLine(); 
-				shapeChildrenStartIdx = _shapeChildren.indexOf(prevTextLine);
+				if(prevLine is TextFlowTableBlock){
+					shapeChildrenStartIdx = _shapeChildren.indexOf((prevLine as TextFlowTableBlock).container);
+				} else {
+					var prevTextLine:TextLine = prevLine.peekTextLine(); 
+					shapeChildrenStartIdx = _shapeChildren.indexOf(prevTextLine);
+				}
 				if (shapeChildrenStartIdx >= 0)
 				{
 					shapeChildrenStartIdx++;
@@ -3113,7 +3195,7 @@ package flashx.textLayout.container
 			
 			while (newIdx != newShapeChildren.length)
 			{
-				var newChild:TextLine = newShapeChildren[newIdx];
+				var newChild:* = newShapeChildren[newIdx];
 				if (newChild == _shapeChildren[oldIdx])
 				{
 					// Same shape is in both lists, no change necessary, advance to next item in each list
@@ -3123,21 +3205,38 @@ package flashx.textLayout.container
 					oldIdx++;
 					continue;
 				}
-				
 				var newChildIdx:int = _shapeChildren.indexOf(newChild);
-				if (newChildIdx == -1)
-				{
-					// Shape is in the new list, but not in the old list, add it to the display list at the current location, and advance to next item
-					addTextLine(newChild, childIdx++);
-					CONFIG::debug { Debugging.traceFTECall(null,_container,"addTextLine",newChild); }
-					newIdx++;
-				}
-				else
-				{
+				if(newChild is TextLine){
+					if (newChildIdx == -1)
+					{
+						// Shape is in the new list, but not in the old list, add it to the display list at the current location, and advance to next item
+						addTextLine((newChild as TextLine), childIdx++);
+						CONFIG::debug { Debugging.traceFTECall(null,_container,"addTextLine",newChild); }
+						newIdx++;
+					}
+					else
+					{
 						// The shape is on both lists, but there are several intervening "old" shapes in between. We'll remove the old shapes that
-					// come before the new one we want to insert.
-					removeAndRecycleTextLines (oldIdx, newChildIdx);
-					oldIdx = newChildIdx;
+						// come before the new one we want to insert.
+						removeAndRecycleTextLines (oldIdx, newChildIdx);
+						oldIdx = newChildIdx;
+					}
+				} else {// it's a table block
+					if (newChildIdx == -1)
+					{
+						// Shape is in the new list, but not in the old list, add it to the display list at the current location, and advance to next item
+						addTableBlock((newChild as TableBlockContainer), childIdx++);
+						CONFIG::debug { Debugging.traceFTECall(null,_container,"addTableBlock",newChild); }
+						newIdx++;
+					}
+					else
+					{
+						// The shape is on both lists, but there are several intervening "old" shapes in between. We'll remove the old shapes that
+						// come before the new one we want to insert.
+						(newChild as TableBlockContainer).userData.updateCompositionShapes();
+						removeAndRecycleTextLines (oldIdx, newChildIdx);
+						oldIdx = newChildIdx;
+					}					
 				}
 			}
 			
@@ -3989,6 +4088,12 @@ package flashx.textLayout.container
 			var textBlock:TextBlock;
 			for (var index:int = beginIndex; index < endIndex; index++)
 			{
+				// we don't recycle table blocks
+				if( !(_shapeChildren[index] is TextLine) ){
+					removeTableBlock(_shapeChildren[index]);
+					child = null;
+					continue;
+				}
 				child = _shapeChildren[index];					
 				removeTextLine(child);
 				CONFIG::debug { Debugging.traceFTECall(null,_container,"removeTextLine",child); }
@@ -4013,6 +4118,10 @@ package flashx.textLayout.container
 			{
 				while (beginIndex < endIndex)
 				{
+					if( !(_shapeChildren[beginIndex] is TextLine) ){
+						beginIndex++;
+						continue;
+					}
 					child = _shapeChildren[beginIndex++];
 										
 					// Recycle if its not displayed and not connected to the textblock
@@ -4069,6 +4178,10 @@ package flashx.textLayout.container
 				{
 					break;
 				}
+				
+				if(_container.getChildAt(firstTextLine) is TableBlockContainer)
+					break;
+				
 			}
 			return firstTextLine;
 		}
@@ -4121,6 +4234,54 @@ package flashx.textLayout.container
 		}
 		
 		/**
+		 * Adds a <code>TableBlockContainer</code> object as a descendant of <code>container</code>.
+		 * The default implementation of this method, which may be overriden, adds the object
+		 * as a direct child of <code>container</code> at the specified index.
+		 * 
+		 * @param textLine the <code>TableBlockContainer</code> object to add
+		 * @param index insertion index of the text line in its parent 
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 * 
+		 * @see #container
+		 * 
+		 */	
+		protected function addTableBlock(block:TableBlockContainer, index:int):void
+		{ 
+			if ( index > _container.numChildren )
+				index = _container.numChildren;
+			_container.addChildAt(block, index);
+			block.userData.updateCompositionShapes();
+		}
+		
+		/**
+		 * Removes a <code>TableBlockContainer</code> object from its parent. 
+		 * The default implementation of this method, which may be overriden, removes the object
+		 * from <code>container</code> if it is a direct child of the latter.
+		 * 
+		 * This method may be called even if the object is not a descendant of <code>container</code>.
+		 * Any implementation of this method must ensure that no action is taken in this case.
+		 * 
+		 * @param textLine the <code>TableBlockContainer</code> object to remove 
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 * 
+		 * @see #container
+		 * 
+		 */	
+
+		protected function removeTableBlock(block:TableBlockContainer):void
+		{
+			if (_container.contains(block))
+				_container.removeChild(block);
+		}
+
+		
+		/**
 		 * Adds a <code>flash.display.Shape</code> object on which background shapes (such as background color) are drawn.
 		 * The default implementation of this method, which may be overriden, adds the object to <code>container</code>
 		 * just before the first <code>flash.text.engine.TextLine</code> child, if one exists, and after the last exisiting
@@ -4586,6 +4747,13 @@ package flashx.textLayout.container
 			// bounds than the getBounds. I've left the old code here for verification.
 			CONFIG::debug { assert(textFlowLine != null,"testLineVisible"); }
 			
+			if(textFlowLine is TextFlowTableBlock)
+			{
+				if(textFlowLine.controller == this)
+					return TextFlowTableBlock(textFlowLine).container;
+				return null;
+			}
+			
 			//Bug #2988852, scrolling in the application causes all text to disappear. When auto-size images make the line "after visible"
 			//It's "after visible", but it cannot return 1. Because if it were 1, the binary-search in gatherVisibleLines() would make all the lines invisible.
 			if(textFlowLine.controller == null)
@@ -4653,6 +4821,10 @@ package flashx.textLayout.container
 			// about the children, and also the bounds of visible glyphs. We decided that the logical bounds is close enough,
 			// and is much faster to obtain. However, there may be some lines, that get a different result using the logical 
 			// bounds than the getBounds. I've left the old code here for verification.
+			
+			if(textFlowLine is TextFlowTableBlock)
+				return null;
+
 			if (!textFlowLine.hasLineBounds())
 			{
 				if (!textLine)
@@ -4727,7 +4899,47 @@ package flashx.textLayout.container
 			}
 			return boundsRect;
 		}
-		
+		/** @private */
+		tlf_internal function findCellAtPosition(point:Point):CellCoordinates
+		{
+			point = point.clone();
+			for each(var chld:Object in _shapeChildren)
+			{
+				if( !(chld is TableBlockContainer) )
+					continue;
+				
+				var block:TableBlockContainer = chld as TableBlockContainer;
+				if(block.y > point.y)
+					continue;
+				if(block.x > point.x)
+					continue;
+				if(block.y + block.height < point.y)
+					continue;
+				if(block.x + block.getTableWidth() < point.x)
+					continue;
+				
+				point.x -= block.x;
+				point.y -= block.y;
+				
+				// the point falls out inside the block. Find the cell...
+				var cells:Vector.<TableCellElement> = block.userData.getTableCells();
+				for each (var cell:TableCellElement in  cells)
+				{
+					if(cell.x + cell.width < point.x)
+						continue;
+					if(cell.y + cell.getRow().composedHeight < point.y)
+						continue;
+					if(cell.x > point.x)
+						continue;
+					if(cell.y > point.y)
+						continue;
+					return new CellCoordinates(cell.rowIndex,cell.colIndex,cell.getTable());
+					
+				}
+			}
+			
+			return null;
+		}
 		/** @private */
 		tlf_internal function getPlacedTextLineBounds(textLine:TextLine):Rectangle
 		{
@@ -4781,13 +4993,25 @@ package flashx.textLayout.container
 		{
 			_linesInView.push(textLine);			
 		}
-		
+
+		/** @private */
+		tlf_internal function addComposedTableBlock(block:TableBlockContainer):void
+		{
+			var idx:int = _tableBlocksInView.indexOf(block);
+			if(idx >= 0)
+				_tableBlocksInView.splice(idx,1);
+			else
+				_tableBlocksInView.push(block);
+		}
+
 		/** @private Return the array. Client code may add lines to the array. */
 		tlf_internal function get composedLines():Array
 		{
 			if (!_linesInView)
 				_linesInView = [];
-			return _linesInView;
+			var arr:Array = _linesInView.slice();
+			intersperseTableBlocks(arr);
+			return arr;
 		}
 		
 		/** @private Empty out the linesInView, starting from the supplied text index. */
@@ -4802,6 +5026,17 @@ package flashx.textLayout.container
 				index++;
 			}
 			_linesInView.length = index;
+			
+			index = 0;
+			for each (var tbc:TableBlockContainer in _tableBlocksInView)
+			{
+				var tftb:TextFlowTableBlock = tbc.userData;
+				if(tbc.userData.absoluteStart >= pos)
+					break;
+				index++;
+			}
+			_tableBlocksInView.length = index;
+			
 			_updateStart = Math.min(_updateStart, pos);
 		}
 		

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutExporter.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutExporter.as b/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutExporter.as
index 6b88cc2..9e0e105 100644
--- a/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutExporter.as
+++ b/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutExporter.as
@@ -22,6 +22,7 @@ package flashx.textLayout.conversion
 	import flash.utils.getQualifiedClassName;
 	
 	import flashx.textLayout.TextLayoutVersion;
+	import flashx.textLayout.tlf_internal;
 	import flashx.textLayout.debug.assert;
 	import flashx.textLayout.elements.Configuration;
 	import flashx.textLayout.elements.ContainerFormattedElement;
@@ -31,34 +32,35 @@ package flashx.textLayout.conversion
 	import flashx.textLayout.elements.LinkElement;
 	import flashx.textLayout.elements.ParagraphFormattedElement;
 	import flashx.textLayout.elements.SpanElement;
+	import flashx.textLayout.elements.TableCellElement;
+	import flashx.textLayout.elements.TableElement;
+	import flashx.textLayout.elements.TableRowElement;
 	import flashx.textLayout.elements.TextFlow;
 	import flashx.textLayout.elements.TextRange;
 	import flashx.textLayout.formats.ITextLayoutFormat;
 	import flashx.textLayout.formats.TextLayoutFormat;
 	import flashx.textLayout.formats.WhiteSpaceCollapse;
 	import flashx.textLayout.property.Property;
-	import flashx.textLayout.tlf_internal;
+
 	use namespace tlf_internal;
 	
-	[ExcludeClass]
 	/** 
-	 * @private 
-	 * Export converter for TextLayout format. 
+	 * Base export converter for TextLayout format. 
 	 */
-	internal class BaseTextLayoutExporter extends ConverterBase implements ITextExporter
-	{	
-		private var _config:ImportExportConfiguration;
+	public class BaseTextLayoutExporter extends ConverterBase implements ITextExporter
+	{
 		private var _rootTag:XML;
 		private var _ns:Namespace;
-				
-		public function BaseTextLayoutExporter(ns:Namespace, rootTag:XML, config:ImportExportConfiguration)
+		
+		public function BaseTextLayoutExporter(ns:Namespace, rootTag:XML, configuration:ImportExportConfiguration)
 		{
-			_config = config;
+			config = configuration;
 			_ns = ns;
 			_rootTag = rootTag;
 		}
 		
-		/** @copy ITextExporter#export()
+		/** 
+		 * @copy ITextExporter#export()
 		 */
 		public function export(source:TextFlow, conversionType:String):Object
 		{
@@ -68,7 +70,9 @@ package flashx.textLayout.conversion
 			return conversionType == ConversionType.STRING_TYPE ? convertXMLToString(result) : result;
 		}
 		
-		/** Export text content of a TextFlow into XFL format.
+		/** 
+		 * Export text content of a TextFlow into XFL format.
+		 * 
 		 * @param source	the text to export
 		 * @return XML	the exported content
 		 */
@@ -89,7 +93,9 @@ package flashx.textLayout.conversion
 			return result;
 		}
 		
-		/** Export text content as a string
+		/** 
+		 * Export text content as a string
+		 * 
 		 * @param xml	the XML to convert
 		 * @return String	the exported content
 		 * @private
@@ -118,7 +124,9 @@ package flashx.textLayout.conversion
 		}
 
 	
-		/** Base functionality for exporting a FlowElement. 
+		/** 
+		 * Base functionality for exporting a FlowElement.
+		 *  
 		 * @param exporter	Root object for the export
 		 * @param flowElement	Element to export
 		 * @return XMLList	XML for the element
@@ -128,14 +136,16 @@ package flashx.textLayout.conversion
 			return exporter.exportFlowElement(flowElement);
 		}
 		
-		/** Overridable worker method for exporting a FlowElement. Creates the XMLList.
+		/** 
+		 * Overridable worker method for exporting a FlowElement. Creates the XMLList.
+		 * 
 		 * @param flowElement	Element to export
 		 * @return XMLList	XML for the element
 		 */
 		protected function exportFlowElement (flowElement:FlowElement):XMLList
 		{
 			var className:String = flash.utils.getQualifiedClassName(flowElement);
-			var elementName:String = _config.lookupName(className);	// NO PMD
+			var elementName:String = config.lookupName(className);	// NO PMD
 			var output:XML = <{elementName}/>;
 			output.setNamespace(_ns);
 			return XMLList(output);
@@ -199,8 +209,10 @@ package flashx.textLayout.conversion
 			}		
 		}  
 		
-		/** Base functionality for exporting a Span. Exports as a FlowElement,
+		/** 
+		 * Base functionality for exporting a Span. Exports as a FlowElement,
 		 * and exports the text of the span.
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param span	Element to export
 		 * @return XMLList	XML for the element
@@ -214,7 +226,8 @@ package flashx.textLayout.conversion
 		
 		static private const brRegEx:RegExp = /\u2028/;
 		
-		/** Gets the regex that specifies characters in span text to be replaced with XML elements
+		/** 
+		 * Gets the regex that specifies characters in span text to be replaced with XML elements.
 		 *  Note: Each match is a single character 
 		 */
 		protected function get spanTextReplacementRegex():RegExp
@@ -222,7 +235,8 @@ package flashx.textLayout.conversion
 			return brRegEx;
 		}
 
-		/** Gets the xml element used to represent a character in the export format
+		/** 
+		 * Gets the xml element used to represent a character in the export format
 		 */
 		protected function getSpanTextReplacementXML(ch:String):XML
 		{
@@ -232,8 +246,10 @@ package flashx.textLayout.conversion
 			return breakXML;
 		}
 		
-		/** Base functionality for exporting a FlowGroupElement. Exports as a FlowElement,
+		/** 
+		 * Base functionality for exporting a FlowGroupElement. Exports as a FlowElement,
 		 * and exports the children of a element.
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param flowBlockElement	Element to export
 		 * @return XMLList	XML for the element
@@ -241,20 +257,26 @@ package flashx.textLayout.conversion
 		static public function exportFlowGroupElement(exporter:BaseTextLayoutExporter, flowBlockElement:FlowGroupElement):XMLList
 		{
 			var output:XMLList = exportFlowElement(exporter, flowBlockElement);
+			var count:int = flowBlockElement.numChildren;
 			
 			// output each child
-			for(var childIter:int = 0; childIter < flowBlockElement.numChildren; ++childIter)
+			for(var index:int; index < count; ++index)
 			{
-				var flowChild:FlowElement = flowBlockElement.getChildAt(childIter);
+				var flowChild:FlowElement = flowBlockElement.getChildAt(index);
 				var childXML:XMLList = exporter.exportChild(flowChild);
-				if (childXML)
+				
+				if (childXML) {
 					output.appendChild(childXML);
+				}
 			}
+			
 			return output;
 		}
 
-		/** Base functionality for exporting a ParagraphFormattedElement. Exports as a FlowGroupElement,
+		/** 
+		 * Base functionality for exporting a ParagraphFormattedElement. Exports as a FlowGroupElement,
 		 * and exports paragraph attributes.
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param flowParagraph	Element to export
 		 * @return XMLList	XML for the element
@@ -264,22 +286,6 @@ package flashx.textLayout.conversion
 			return exporter.exportParagraphFormattedElement(flowParagraph);
 		}
 		
-		/** Overridable worker method for exporting a ParagraphFormattedElement. Creates the XMLList.
-		 * @param flowElement	Element to export
-		 * @return XMLList	XML for the element
-		 */
-		protected function exportParagraphFormattedElement(flowElement:FlowElement):XMLList
-		{
-			var rslt:XMLList = exportFlowElement(flowElement);
-			// output each child
-			for(var childIter:int = 0; childIter < ParagraphFormattedElement(flowElement).numChildren; ++childIter)
-			{
-				var flowChild:FlowElement = ParagraphFormattedElement(flowElement).getChildAt(childIter);
-				rslt.appendChild(exportChild(flowChild));
-			}
-			return rslt;
-		}
-		
 		static public function exportList(exporter:BaseTextLayoutExporter, flowParagraph:ParagraphFormattedElement):XMLList
 		{
 			return exporter.exportList(flowParagraph);
@@ -287,14 +293,17 @@ package flashx.textLayout.conversion
 		
 		protected function exportList(flowElement:FlowElement):XMLList
 		{
-			var rslt:XMLList = exportFlowElement(flowElement);
+			var result:XMLList = exportFlowElement(flowElement);
+			var count:int = FlowGroupElement(flowElement).numChildren;
+			
 			// output each child
-			for(var childIter:int = 0; childIter < FlowGroupElement(flowElement).numChildren; ++childIter)
+			for(var index:int; index < count; ++index)
 			{
-				var flowChild:FlowElement = FlowGroupElement(flowElement).getChildAt(childIter);
-				rslt.appendChild(exportChild(flowChild));
+				var flowChild:FlowElement = FlowGroupElement(flowElement).getChildAt(index);
+				result.appendChild(exportChild(flowChild));
 			}
-			return rslt;
+			
+			return result;
 		}
 		
 		static public function exportListItem(exporter:BaseTextLayoutExporter, flowParagraph:ParagraphFormattedElement):XMLList
@@ -304,18 +313,23 @@ package flashx.textLayout.conversion
 		
 		protected function exportListItem(flowElement:FlowElement):XMLList
 		{
-			var rslt:XMLList = exportFlowElement(flowElement);
+			var result:XMLList = exportFlowElement(flowElement);
+			var count:int = FlowGroupElement(flowElement).numChildren;
+			
 			// output each child
-			for(var childIter:int = 0; childIter < FlowGroupElement(flowElement).numChildren; ++childIter)
+			for(var index:int; index < count; ++index)
 			{
-				var flowChild:FlowElement = FlowGroupElement(flowElement).getChildAt(childIter);
-				rslt.appendChild(exportChild(flowChild));
+				var flowChild:FlowElement = FlowGroupElement(flowElement).getChildAt(index);
+				result.appendChild(exportChild(flowChild));
 			}
-			return rslt;
+			
+			return result;
 		}
 		
-		/** Base functionality for exporting a ContainerFormattedElement. Exports as a ParagraphFormattedElement,
+		/** 
+		 * Base functionality for exporting a ContainerFormattedElement. Exports as a ParagraphFormattedElement,
 		 * and exports container attributes.
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param container	Element to export
 		 * @return XMLList	XML for the element
@@ -325,7 +339,9 @@ package flashx.textLayout.conversion
 			return exporter.exportContainerFormattedElement(container);
 		}
 		
-		/** Overridable worker method for exporting a ParagraphFormattedElement. Creates the XMLList.
+		/** 
+		 * Overridable worker method for exporting a ParagraphFormattedElement. Creates the XMLList.
+		 * 
 		 * @param flowElement	Element to export
 		 * @return XMLList	XML for the element
 		 */
@@ -333,9 +349,126 @@ package flashx.textLayout.conversion
 		{
 			return exportParagraphFormattedElement(flowElement);
 		}
-
-		/** Base functionality for exporting a TextFlow. Exports as a ContainerElement,
+		
+		/** 
+		 * Base functionality for exporting a TableElement. Exports as a TableElement,
+		 * and exports table attributes.
+		 * 
+		 * @param exporter	Root object for the export
+		 * @param container	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		static public function exportTableElement(exporter:BaseTextLayoutExporter, table:TableElement):XMLList
+		{
+			return exporter.exportTableElement(table);
+		}
+		
+		/** 
+		 * Overridable worker method for exporting a TableElement. Creates the XMLList.
+		 * 
+		 * @param flowElement	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		protected function exportTableElement(tableElement:TableElement):XMLList
+		{
+			var result:XMLList = exportFlowElement(tableElement);
+			var count:int = tableElement.numRows;
+			
+			// output each child
+			for(var index:int = 0; index < count; ++index)
+			{
+				var flowChild:FlowElement = tableElement.getRowAt(index);
+				result.appendChild(exportChild(flowChild));
+			}
+			
+			return result;
+		}
+		
+		/** 
+		 * Base functionality for exporting a TableRowElement. Exports as a TableRowElement,
+		 * and exports table row attributes.
+		 * 
+		 * @param exporter	Root object for the export
+		 * @param container	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		static public function exportTableRowElement(exporter:BaseTextLayoutExporter, tableRow:TableRowElement):XMLList
+		{
+			return exporter.exportTableRowElement(tableRow);
+		}
+		
+		/** 
+		 * Overridable worker method for exporting a TableRowElement. Creates the XMLList.
+		 * 
+		 * @param flowElement	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		protected function exportTableRowElement(tableRowElement:TableRowElement):XMLList
+		{
+			var result:XMLList = exportFlowElement(tableRowElement);
+			var count:int = tableRowElement.numCells;
+			
+			// output each child
+			for(var index:int; index < count; ++index)
+			{
+				var flowChild:FlowElement = tableRowElement.getCellAt(index);
+				result.appendChild(exportChild(flowChild));
+			}
+			
+			return result;
+		}
+		
+		/** 
+		 * Base functionality for exporting a TableCellElement. Exports as a TableCellElement,
+		 * and exports table cell attributes.
+		 * 
+		 * @param exporter	Root object for the export
+		 * @param container	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		static public function exportTableCellElement(exporter:BaseTextLayoutExporter, tableCell:TableCellElement):XMLList
+		{
+			return exporter.exportTableCellElement(tableCell);
+		}
+		
+		/** 
+		 * Overridable worker method for exporting a TableCellElement. Creates the XMLList.
+		 * 
+		 * @param flowElement	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		protected function exportTableCellElement(tableCellElement:TableCellElement):XMLList
+		{
+			var result:XMLList = exportFlowElement(tableCellElement);
+			
+			return result;
+		}
+		
+		/** 
+		 * Overridable worker method for exporting a ParagraphFormattedElement. Creates the XMLList.
+		 * 
+		 * @param flowElement	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		protected function exportParagraphFormattedElement(flowElement:FlowElement):XMLList
+		{
+			var result:XMLList = exportFlowElement(flowElement);
+			var count:int = ParagraphFormattedElement(flowElement).numChildren;
+			
+			// output each child
+			for(var index:int; index < count; ++index)
+			{
+				var flowChild:FlowElement = ParagraphFormattedElement(flowElement).getChildAt(index);
+				result.appendChild(exportChild(flowChild));
+			}
+			
+			return result;
+		}
+		
+		/** 
+		 * Base functionality for exporting a TextFlow. Exports as a ContainerElement,
 		 * and exports container attributes.
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param textFlow	Element to export
 		 * @return XMLList	XML for the element
@@ -344,8 +477,10 @@ package flashx.textLayout.conversion
 		{
 			var output:XMLList = exportContainerFormattedElement(exporter, textFlow);
 			
-			// TextLayout will use PRESERVE on output
-			output.@[TextLayoutFormat.whiteSpaceCollapseProperty.name] = WhiteSpaceCollapse.PRESERVE;
+			if (exporter.config.whiteSpaceCollapse) {
+				// TextLayout will use PRESERVE on output
+				output.@[TextLayoutFormat.whiteSpaceCollapseProperty.name] = exporter.config.whiteSpaceCollapse;
+			}
 			
 			// TextLayout adds version information
 			output.@["version"] = TextLayoutVersion.getVersionString(TextLayoutVersion.CURRENT_VERSION);
@@ -354,8 +489,10 @@ package flashx.textLayout.conversion
 		}
 
 
-		/** Exports the object. It will find the appropriate exporter and use it to 
+		/** 
+		 * Exports the object. It will find the appropriate exporter and use it to 
 		 * export the object.
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param flowElement	Element to export
 		 * @return XMLList	XML for the flowElement
@@ -363,13 +500,15 @@ package flashx.textLayout.conversion
 		public function exportChild(flowElement:FlowElement):XMLList
 		{
 			var className:String = flash.utils.getQualifiedClassName(flowElement);
-			var info:FlowElementInfo = _config.lookupByClass(className);
+			var info:FlowElementInfo = config.lookupByClass(className);
 			if (info != null)
 				return info.exporter(this, flowElement);
 			return null;
 		}
 					
-		/** Helper function to export styles (core or user) in the form of xml attributes or xml children
+		/** 
+		 * Helper function to export styles (core or user) in the form of xml attributes or xml children.
+		 * 
 		 * @param xml object to which attributes/children are added 
 		 * @param sortableStyles an array of objects (xmlName,xmlVal) members that is sorted and exported.
 		 */
@@ -400,7 +539,6 @@ package flashx.textLayout.conversion
 		protected function get formatDescription():Object
 		{
 			return null;
-		}		
-
+		}
 	}
 }

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutImporter.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutImporter.as b/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutImporter.as
index 21317b3..3eb6ac3 100644
--- a/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutImporter.as
+++ b/textLayout/src/flashx/textLayout/conversion/BaseTextLayoutImporter.as
@@ -21,6 +21,7 @@ package flashx.textLayout.conversion
 	import flash.system.System;
 	
 	import flashx.textLayout.TextLayoutVersion;
+	import flashx.textLayout.tlf_internal;
 	import flashx.textLayout.debug.assert;
 	import flashx.textLayout.elements.BreakElement;
 	import flashx.textLayout.elements.Configuration;
@@ -36,15 +37,15 @@ package flashx.textLayout.conversion
 	import flashx.textLayout.elements.ParagraphFormattedElement;
 	import flashx.textLayout.elements.SpanElement;
 	import flashx.textLayout.elements.TabElement;
+	import flashx.textLayout.elements.TableCellElement;
 	import flashx.textLayout.elements.TextFlow;
 	import flashx.textLayout.property.Property;
-	import flashx.textLayout.tlf_internal;
+
 	use namespace tlf_internal;
 
-	[ExcludeClass]
 	/**
-	 * @private  
-	 * BaseTextLayoutImporter is a base class for handling the import/export of TextLayout text in the native format.
+	 * BaseTextLayoutImporter is a base class for handling the import/export of TextLayout text 
+	 * in the native format.
 	 */ 
 	internal class BaseTextLayoutImporter extends ConverterBase implements ITextImporter
 	{	
@@ -205,7 +206,9 @@ package flashx.textLayout.conversion
 			return importer.createTextFlowFromXML(xmlToParse, null);
 		}		
 		
-		/** Static method to parse the supplied XML into a paragrph. Parse the <p ...> tag and it's children.
+		/** 
+		 * Static method to parse the supplied XML into a paragrph. 
+		 * Parse the <p ...> tag and it's children.
 		 * 
 		 * @param importer	parser object
 		 * @param xmlToParse	content to parse
@@ -230,7 +233,8 @@ package flashx.textLayout.conversion
 			dst.id          = src.id;
 		}
 		
-		/** Static method for constructing a span from XML. Parse the <span> ... </span> tag. 
+		/** 
+		 * Static method for constructing a span from XML. Parse the <span> ... </span> tag. 
 		 * Insert the span into its parent
 		 * 
 		 * @param importer	parser object
@@ -296,7 +300,8 @@ package flashx.textLayout.conversion
 			}
 		}
 		
-		/** Static method for constructing a break element from XML. Validate the <br> ... </br> tag. 
+		/** 
+		 * Static method for constructing a break element from XML. Validate the <br> ... </br> tag. 
 		 * Use "\u2028" as the text; Insert the new element into its parent 
 		 * 
 		 * @param importer	parser object
@@ -308,9 +313,9 @@ package flashx.textLayout.conversion
 			var breakElem:BreakElement = importer.createBreakFromXML(xmlToParse);
 			importer.addChild(parent, breakElem);
 		}
-
 		
-		/** Static method for constructing a tab element from XML. Validate the <tab> ... </tab> tag. 
+		/** 
+		 * Static method for constructing a tab element from XML. Validate the <tab> ... </tab> tag. 
 		 * Use "\t" as the text; Insert the new element into its parent 
 		 * 
 		 * @param importer	parser object
@@ -323,7 +328,14 @@ package flashx.textLayout.conversion
 			if (tabElem)
 				importer.addChild(parent, tabElem);
 		}
-
+		
+		/** 
+		 * Static method for constructing a list element from XML. 
+		 * 
+		 * @param importer	parser object
+		 * @param xmlToParse	content to parse
+		 * @param parent 		the parent for the new content
+		 */
 		static public function parseList(importer:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void
 		{
 			var listElem:ListElement = importer.createListFromXML(xmlToParse);
@@ -332,7 +344,14 @@ package flashx.textLayout.conversion
 				importer.parseFlowGroupElementChildren(xmlToParse, listElem);
 			}
 		}
-
+		
+		/** 
+		 * Static method for constructing a list item from XML. 
+		 * 
+		 * @param importer	parser object
+		 * @param xmlToParse	content to parse
+		 * @param parent 		the parent for the new content
+		 */
 		static public function parseListItem(importer:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void
 		{
 			var listItem:ListItemElement = importer.createListItemFromXML(xmlToParse);
@@ -420,7 +439,9 @@ package flashx.textLayout.conversion
 			return workAttrs;
 		}	
 		
-		/** Parse XML and convert to  TextFlow.
+		/** 
+		 * Parse XML and convert to  TextFlow.
+		 * 
 		 * @param xmlToParse	content to parse
 		 * @param textFlow 		TextFlow we're parsing. If null, create or find a new TextFlow based on XML content
 		 * @return TextFlow	the new TextFlow created as a result of the parse
@@ -467,7 +488,9 @@ package flashx.textLayout.conversion
 			return new TabElement();
 		}
 		
-		/** Parse XML, convert to FlowElements and add to the parent.
+		/** 
+		 * Parse XML, convert to FlowElements and add to the parent.
+		 * 
 		 * @param xmlToParse	content to parse
 		 * @param parent 		the parent for the new content
 		 */
@@ -476,7 +499,9 @@ package flashx.textLayout.conversion
 			parseFlowGroupElementChildren(xmlToParse, parent);
 		}
 		
-		/** Parse XML, convert to FlowElements and add to the parent.
+		/** 
+		 * Parse XML, convert to FlowElements and add to the parent.
+		 * 
 		 * @param xmlToParse	content to parse
 		 * @param parent 		the parent for the new content
 		 * @param chainedParent whether parent actually corresponds to xmlToParse or has been chained (such as when xmlToParse is a formatting element) 
@@ -510,6 +535,54 @@ package flashx.textLayout.conversion
 				resetImpliedPara();
 		}
 		
+		/** 
+		 * Parse XML, convert XML to FlowElements and TextFlow and add to the parent table cell
+		 * 
+		 * @param xmlToParse	content to parse
+		 * @param parent 		the parent for the new content
+		 * @param chainedParent whether parent actually corresponds to xmlToParse or has been chained (such as when xmlToParse is a formatting element) 
+		 */
+		public function parseTableCellElementChildren(xmlToParse:XML, parent:FlowGroupElement, exceptionElements:Object = null, chainedParent:Boolean=false):void
+		{
+			var textFlow:TextFlow;
+			
+			for each (var child:XML in xmlToParse.children())
+			{
+				if (child.nodeKind() == "element")
+				{
+					if (child.name().localName=="p") {
+						textFlow = new TextFlow();
+						parseObject(child.name().localName, child, textFlow, exceptionElements);
+					}
+					else if (child.name().localName=="TextFlow") {
+						TableCellElement(parent).textFlow = createTextFlowFromXML(child);
+					}
+				}
+					// look for mixed content here
+				else if (child.nodeKind() == "text") 
+				{
+					var txt:String = child.toString();
+					// Strip whitespace-only text appearing as a child of a container-formatted element
+					var strip:Boolean = false;
+					if (parent is ContainerFormattedElement)
+					{
+						strip = txt.search(anyPrintChar) == -1;
+					}
+					
+					if (!strip) {
+						textFlow = new TextFlow();
+						parseObject(child.name().localName, child, textFlow, exceptionElements);
+						//addChild(textFlow, createImpliedSpan(txt));
+					}
+				}
+				
+				if (textFlow) {
+					TableCellElement(parent).textFlow = textFlow;
+					textFlow = null;
+				}
+			}
+		}
+		
 		/** create an implied span with specified text */
 		public function createImpliedSpan(text:String):SpanElement
 		{

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/conversion/ConverterBase.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/conversion/ConverterBase.as b/textLayout/src/flashx/textLayout/conversion/ConverterBase.as
index de22970..6924d21 100644
--- a/textLayout/src/flashx/textLayout/conversion/ConverterBase.as
+++ b/textLayout/src/flashx/textLayout/conversion/ConverterBase.as
@@ -34,6 +34,7 @@ package flashx.textLayout.conversion
 		private var _errors:Vector.<String> = null;
 		private var _throwOnError:Boolean = false;
 		private var _useClipboardAnnotations:Boolean = false;
+		private var _config:ImportExportConfiguration;
 
 		/** A converter that converts clipboard data into a TextFlow should use the MERGE_TO_NEXT_ON_PASTE property
 		 * to control how the elements are treated when they are merged into an existing TextFlow on paste. This is useful
@@ -111,5 +112,19 @@ package flashx.textLayout.conversion
 			_useClipboardAnnotations = value;
 		}
 		
+		/**
+		 * Returns the import and export configuration. 
+		 **/
+		public function get config():ImportExportConfiguration {
+			return _config;
+		}
+		
+		/**
+		 * @private
+		 **/
+		public function set config(value:ImportExportConfiguration):void {
+			_config = value;
+		}
+		
 	}
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/conversion/ITextExporter.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/conversion/ITextExporter.as b/textLayout/src/flashx/textLayout/conversion/ITextExporter.as
index 8b3a955..fc10128 100644
--- a/textLayout/src/flashx/textLayout/conversion/ITextExporter.as
+++ b/textLayout/src/flashx/textLayout/conversion/ITextExporter.as
@@ -94,6 +94,12 @@ package flashx.textLayout.conversion
 		 * @langversion 3.0
 		 */
 		function get useClipboardAnnotations():Boolean;
-		function set useClipboardAnnotations(value:Boolean):void;		
+		function set useClipboardAnnotations(value:Boolean):void;
+		
+		/**
+		 * Accesses the config options for the exporter. 
+		 **/
+		function get config():ImportExportConfiguration;
+		function set config(value:ImportExportConfiguration):void;		
 	}
 }

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/conversion/ImportExportConfiguration.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/conversion/ImportExportConfiguration.as b/textLayout/src/flashx/textLayout/conversion/ImportExportConfiguration.as
index 3406284..b9c996c 100644
--- a/textLayout/src/flashx/textLayout/conversion/ImportExportConfiguration.as
+++ b/textLayout/src/flashx/textLayout/conversion/ImportExportConfiguration.as
@@ -18,13 +18,16 @@
 ////////////////////////////////////////////////////////////////////////////////
 package flashx.textLayout.conversion
 {
-	import flashx.textLayout.debug.assert;
 	import flashx.textLayout.tlf_internal;
+	import flashx.textLayout.debug.assert;
+	import flashx.textLayout.formats.WhiteSpaceCollapse;
+
 	use namespace tlf_internal;
 
-	[ExcludeClass]
-	/** Configure for import/export of standard components.
-	 * Configures the import/export package so it can export all the standard FlowElements. 
+	/** 
+	 * Configure for import/export of standard components.
+	 * Configures the import/export package so it can export all the standard FlowElements.
+	 *  
 	 * @see flashx.textLayout.elements.Configuration
 	 * @playerversion Flash 10
 	 * @playerversion AIR 1.5
@@ -32,12 +35,22 @@ package flashx.textLayout.conversion
 	 */
 	public class ImportExportConfiguration 
 	{
-		/** array of FlowElementInfo objects (key = name, value = FlowElementInfo) */	
+		/** 
+		 * array of FlowElementInfo objects (key = name, value = FlowElementInfo) 
+		 * */	
 		tlf_internal var flowElementInfoList:Object = {};	
 		tlf_internal var flowElementClassList:Object= {};	
 		tlf_internal var classToNameMap:Object = {};
+		
+		/**
+		 * Whitespace collapse export setting
+		 * @default WhiteSpaceCollapse.PRESERVE
+		 **/
+		public var whiteSpaceCollapse:String = WhiteSpaceCollapse.PRESERVE;
 
-		/** Constructor.
+		/** 
+		 * Constructor.
+		 * 
 		* @playerversion Flash 10
 		* @playerversion AIR 1.5
 	 	* @langversion 3.0
@@ -46,8 +59,10 @@ package flashx.textLayout.conversion
 		{
 		}
 		
-		/** Add a parser for a new FlowElement type. This allows FlowElements to be added from outside the main system,
+		/** 
+		 * Add a parser for a new FlowElement type. This allows FlowElements to be added from outside the main system,
 		 * and still have the main system be able to import them from XML.
+		 * 
 		 * @param name		the name of the FlowElement class, as it appear in the XML
 		 * @param flowClass	the class of the FlowElement
 		 * @param parser	function fpr importing the XML into a FlowElement
@@ -71,7 +86,9 @@ package flashx.textLayout.conversion
 				classToNameMap[info.flowClassName] = name;
 		}
 		
-		/** Return the information being held about the FlowElement, as a FlowElementInfo.
+		/** 
+		 * Return the information being held about the FlowElement, as a FlowElementInfo.
+		 * 
 		 * @param name				the name of the FlowElement class, as it appears in the XML
 		 * @return FlowElementInfo	the information being held, as it was supplied to addParseInfo
 		 * @private
@@ -81,7 +98,9 @@ package flashx.textLayout.conversion
 			return flowElementInfoList[name];
 		}
 
-		/** Return the element name for the class
+		/** 
+		 * Return the element name for the class
+		 * 
 		 * @param classToMatch		fully qualified class name of the FlowElement
 		 * @return name				export name to use for class
 		 * @private
@@ -91,7 +110,9 @@ package flashx.textLayout.conversion
 			return classToNameMap[classToMatch];
 		}
 
-		/** Return the information being held about the FlowElement, as a FlowElementInfo.
+		/** 
+		 * Return the information being held about the FlowElement, as a FlowElementInfo.
+		 * 
 		 * @param classToMatch		fully qualified class name of the FlowElement
 		 * @return FlowElementInfo	the information being held, as it was supplied to addParseInfo
 		 * @private

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/conversion/TextLayoutExporter.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/conversion/TextLayoutExporter.as b/textLayout/src/flashx/textLayout/conversion/TextLayoutExporter.as
index 4965993..d4649ba 100644
--- a/textLayout/src/flashx/textLayout/conversion/TextLayoutExporter.as
+++ b/textLayout/src/flashx/textLayout/conversion/TextLayoutExporter.as
@@ -20,6 +20,7 @@ package flashx.textLayout.conversion
 {
 	import flash.utils.Dictionary;
 	
+	import flashx.textLayout.tlf_internal;
 	import flashx.textLayout.debug.assert;
 	import flashx.textLayout.elements.ContainerFormattedElement;
 	import flashx.textLayout.elements.DivElement;
@@ -33,6 +34,9 @@ package flashx.textLayout.conversion
 	import flashx.textLayout.elements.SpanElement;
 	import flashx.textLayout.elements.SubParagraphGroupElement;
 	import flashx.textLayout.elements.TCYElement;
+	import flashx.textLayout.elements.TableElement;
+	import flashx.textLayout.elements.TableCellElement;
+	import flashx.textLayout.elements.TableRowElement;
 	import flashx.textLayout.elements.TextFlow;
 	import flashx.textLayout.formats.FormatValue;
 	import flashx.textLayout.formats.ITextLayoutFormat;
@@ -40,13 +44,10 @@ package flashx.textLayout.conversion
 	import flashx.textLayout.formats.TextLayoutFormat;
 	import flashx.textLayout.formats.WhiteSpaceCollapse;
 	import flashx.textLayout.property.Property;
-	import flashx.textLayout.tlf_internal;
 	
 	use namespace tlf_internal;
 	
-	[ExcludeClass]
 	/** 
-	 * @private
 	 * Export filter for TextLayout format. 
 	 */
 	internal class TextLayoutExporter extends BaseTextLayoutExporter
@@ -87,8 +88,9 @@ package flashx.textLayout.conversion
 			return replacementXML;	
 		}
 		
-		/** Helper function to export styles (core or user) in the form of xml attributes or xml children
-		 * @private
+		/** 
+		 * Helper function to export styles (core or user) in the form of xml attributes or xml children
+		 * 
 		 */
 		tlf_internal function createStylesFromDescription(styles:Object, description:Object, includeUserStyles:Boolean, exclusions:Array):Array
 		{
@@ -170,7 +172,7 @@ package flashx.textLayout.conversion
 				exportStyles(rslt, sortableStyles );
 			}
 			
-			// export id and styleName
+			// export id and typeName
 			if (flowElement.id != null)
 				rslt.@["id"] = flowElement.id;
 			if (flowElement.typeName != flowElement.defaultTypeName)
@@ -179,8 +181,10 @@ package flashx.textLayout.conversion
 			return rslt;
 		}
 
-		/** Base functionality for exporting an Image. Exports as a FlowElement,
+		/** 
+		 * Base functionality for exporting an Image. Exports as a FlowElement,
 		 * and exports image properties.
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param image	Element to export
 		 * @return XMLList	XML for the element
@@ -203,8 +207,10 @@ package flashx.textLayout.conversion
 			return output;
 		}
 
-		/** Base functionality for exporting a LinkElement. Exports as a FlowGroupElement,
+		/** 
+		 * Base functionality for exporting a LinkElement. Exports as a FlowGroupElement,
 		 * and exports link properties.
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param link	Element to export
 		 * @return XMLList	XML for the element
@@ -222,7 +228,9 @@ package flashx.textLayout.conversion
 			return output;
 		}
 		
-		/** Base functionality for exporting a DivElement. Exports as a FlowContainerFormattedElement
+		/** 
+		 * Base functionality for exporting a DivElement. Exports as a FlowContainerFormattedElement
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param div	Element to export
 		 * @return XMLList	XML for the element
@@ -232,7 +240,9 @@ package flashx.textLayout.conversion
 			return exportContainerFormattedElement(exporter, div);
 		}
 		
-		/** Base functionality for exporting a SubParagraphGroupElement. Exports as a FlowGroupElement
+		/** 
+		 * Base functionality for exporting a SubParagraphGroupElement. Exports as a FlowGroupElement
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param elem	Element to export
 		 * @return XMLList	XML for the element
@@ -241,7 +251,9 @@ package flashx.textLayout.conversion
 		{
 			return exportFlowGroupElement(exporter, elem);
 		}
-		/** Base functionality for exporting a TCYElement. Exports as a FlowGroupElement
+		/** 
+		 * Base functionality for exporting a TCYElement. Exports as a FlowGroupElement
+		 * 
 		 * @param exporter	Root object for the export
 		 * @param tcy	Element to export
 		 * @return XMLList	XML for the element
@@ -251,6 +263,42 @@ package flashx.textLayout.conversion
 			return exportFlowGroupElement(exporter, tcy);
 		}
 		
+		/** 
+		 * Base functionality for exporting a TableElement. 
+		 * 
+		 * @param exporter	Root object for the export
+		 * @param table	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		static public function exportTable(exporter:BaseTextLayoutExporter, table:TableElement):XMLList
+		{
+			return exportTableElement(exporter, table);
+		}
+		
+		/** 
+		 * Base functionality for exporting a TableRowElement. 
+		 * 
+		 * @param exporter	Root object for the export
+		 * @param table	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		static public function exportTableRow(exporter:BaseTextLayoutExporter, tableRow:TableRowElement):XMLList
+		{
+			return exportTableRowElement(exporter, tableRow);
+		}
+		
+		/** 
+		 * Base functionality for exporting a TableCellElement. 
+		 * 
+		 * @param exporter	Root object for the export
+		 * @param table	Element to export
+		 * @return XMLList	XML for the element
+		 */
+		static public function exportTableCell(exporter:BaseTextLayoutExporter, tableCell:TableCellElement):XMLList
+		{
+			return exportTableCellElement(exporter, tableCell);
+		}
+		
 		override protected function get formatDescription():Object
 		{
 			return _formatDescription;

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/conversion/TextLayoutImporter.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/conversion/TextLayoutImporter.as b/textLayout/src/flashx/textLayout/conversion/TextLayoutImporter.as
index 9ebc61c..2cc9793 100644
--- a/textLayout/src/flashx/textLayout/conversion/TextLayoutImporter.as
+++ b/textLayout/src/flashx/textLayout/conversion/TextLayoutImporter.as
@@ -17,15 +17,19 @@
 //
 ////////////////////////////////////////////////////////////////////////////////
 package flashx.textLayout.conversion 
-{	
+{
 	import flash.display.Shape;
 	import flash.text.engine.TextRotation;
 	import flash.utils.Dictionary;
 	
 	import flashx.textLayout.TextLayoutVersion;
+	import flashx.textLayout.tlf_internal;
 	import flashx.textLayout.container.ContainerController;
 	import flashx.textLayout.debug.assert;
+	import flashx.textLayout.edit.EditManager;
+	import flashx.textLayout.edit.SelectionManager;
 	import flashx.textLayout.elements.BreakElement;
+	import flashx.textLayout.elements.ContainerFormattedElement;
 	import flashx.textLayout.elements.DivElement;
 	import flashx.textLayout.elements.FlowElement;
 	import flashx.textLayout.elements.FlowGroupElement;
@@ -40,16 +44,18 @@ package flashx.textLayout.conversion
 	import flashx.textLayout.elements.SubParagraphGroupElement;
 	import flashx.textLayout.elements.TCYElement;
 	import flashx.textLayout.elements.TabElement;
+	import flashx.textLayout.elements.TableCellElement;
+	import flashx.textLayout.elements.TableColElement;
+	import flashx.textLayout.elements.TableElement;
+	import flashx.textLayout.elements.TableRowElement;
 	import flashx.textLayout.elements.TextFlow;
 	import flashx.textLayout.formats.ITextLayoutFormat;
 	import flashx.textLayout.formats.ListMarkerFormat;
 	import flashx.textLayout.formats.TextLayoutFormat;
 	import flashx.textLayout.property.Property;
-	import flashx.textLayout.tlf_internal;
 	
 	use namespace tlf_internal;
 
-	[ExcludeClass]
 	/** 
 	 * @private
 	 * TextLayoutImporter converts from XML to TextLayout data structures and back.
@@ -82,6 +88,10 @@ package flashx.textLayout.conversion
 				_defaultConfiguration.addIEInfo("a", LinkElement,            TextLayoutImporter.parseLink, 			TextLayoutExporter.exportLink);
 	 			_defaultConfiguration.addIEInfo("div", DivElement,           TextLayoutImporter.parseDivElement, 	TextLayoutExporter.exportDiv);
 				_defaultConfiguration.addIEInfo("img", InlineGraphicElement, TextLayoutImporter.parseInlineGraphic, TextLayoutExporter.exportImage);	
+				_defaultConfiguration.addIEInfo("table", TableElement, 		 TextLayoutImporter.parseTable,     	TextLayoutExporter.exportTable);	
+				_defaultConfiguration.addIEInfo("tr", TableRowElement, 	     TextLayoutImporter.parseTableRow,	    TextLayoutExporter.exportTableRow);	
+				_defaultConfiguration.addIEInfo("th", TableCellElement, 	 TextLayoutImporter.parseTableCell,  	TextLayoutExporter.exportTableCell);	
+				_defaultConfiguration.addIEInfo("td", TableCellElement, 	 TextLayoutImporter.parseTableCell,  	TextLayoutExporter.exportTableCell);	
 				
 				// validate the defaultTypeName values.  They are to match the TLF format export xml names
 				CONFIG::debug 
@@ -251,6 +261,48 @@ package flashx.textLayout.conversion
 			return divElem;
 		}
 		
+		/**
+		 * Create a table element from XML
+		 **/
+		public function createTableFromXML(xmlToParse:XML):TableElement
+		{
+			// add the table element to the parent
+			var tableElement:TableElement = new TableElement();
+			
+			parseStandardFlowElementAttributes(tableElement, xmlToParse);
+
+			return tableElement;
+		}
+		
+		/**
+		 * Create a table row element from XML
+		 **/
+		public function createTableRowFromXML(xmlToParse:XML):TableRowElement
+		{
+			// add the table row element to the parent
+			var tableRowElement:TableRowElement = new TableRowElement();
+			
+			parseStandardFlowElementAttributes(tableRowElement, xmlToParse);
+			
+			return tableRowElement;
+		}
+		
+		/**
+		 * Create a table cell element from XML
+		 **/
+		public function createTableCellFromXML(xmlToParse:XML):TableCellElement
+		{
+			// add the table cell element to the parent
+			var tableCellElement:TableCellElement = new TableCellElement();
+			
+			parseStandardFlowElementAttributes(tableCellElement, xmlToParse);
+			
+			return tableCellElement;
+		}
+		
+		/**
+		 * Create a paragraph element from XML
+		 **/
 		public override function createParagraphFromXML(xmlToParse:XML):ParagraphElement
 		{
 			var paraElem:ParagraphElement = new ParagraphElement();
@@ -258,6 +310,9 @@ package flashx.textLayout.conversion
 			return paraElem;
 		}
 		
+		/**
+		 * Create a sub paragraph group element from XML
+		 **/
 		public function createSubParagraphGroupFromXML(xmlToParse:XML):SubParagraphGroupElement
 		{
 			var elem:SubParagraphGroupElement = new SubParagraphGroupElement();
@@ -265,6 +320,9 @@ package flashx.textLayout.conversion
 			return elem;
 		}
 		
+		/**
+		 * Create a tate chu yoko element from XML
+		 **/
 		public function createTCYFromXML(xmlToParse:XML):TCYElement
 		{
 			var tcyElem:TCYElement = new TCYElement();
@@ -272,7 +330,7 @@ package flashx.textLayout.conversion
 			return tcyElem;
 		}
 		
-			
+		
 		static internal const _linkDescription:Object = {
 			href : Property.NewStringProperty("href",null, false, null),
 			target : Property.NewStringProperty("target",null, false, null)
@@ -280,7 +338,8 @@ package flashx.textLayout.conversion
 		static private const _linkFormatImporter:TLFormatImporter = new TLFormatImporter(Dictionary,_linkDescription);
 		static private const _linkElementFormatImporters:Array = [ _linkFormatImporter, _formatImporter,_idImporter,_typeNameImporter,_customFormatImporter ];
 
-		/** Parse a LinkElement Block.
+		/** 
+		 * Parse a LinkElement Block.
 		 * 
 		 * @param - importFilter:BaseTextLayoutImporter - parser object
 		 * @param - xmlToParse:XML - the xml describing the Link
@@ -300,6 +359,9 @@ package flashx.textLayout.conversion
 			return linkElem;
 		}
 		
+		/**
+		 * Create a span element from XML
+		 **/
 		public override function createSpanFromXML(xmlToParse:XML):SpanElement
 		{
 			var spanElem:SpanElement = new SpanElement();
@@ -319,6 +381,9 @@ package flashx.textLayout.conversion
 		static private const _ilgFormatImporter:TLFormatImporter = new TLFormatImporter(Dictionary,_imageDescription);
 		static private const _ilgElementFormatImporters:Array = [ _ilgFormatImporter, _formatImporter, _idImporter, _typeNameImporter, _customFormatImporter ];
 
+		/**
+		 * Create an inline graphic from XML
+		 **/
 		public function createInlineGraphicFromXML(xmlToParse:XML):InlineGraphicElement
 		{				
 			var imgElem:InlineGraphicElement = new InlineGraphicElement();
@@ -341,6 +406,9 @@ package flashx.textLayout.conversion
 			return imgElem;
 		}
 	
+		/**
+		 * Create a list element from XML
+		 **/
 		public override function createListFromXML(xmlToParse:XML):ListElement
 		{
 			var rslt:ListElement = new ListElement;
@@ -348,6 +416,9 @@ package flashx.textLayout.conversion
 			return rslt;
 		}
 
+		/**
+		 * Create a list item element from XML
+		 **/
 		public override function createListItemFromXML(xmlToParse:XML):ListItemElement
 		{
 			var rslt:ListItemElement = new ListItemElement;
@@ -355,12 +426,16 @@ package flashx.textLayout.conversion
 			return rslt;
 		}
 		
+		/**
+		 * Extract text format attributes
+		 **/
 		public function extractTextFormatAttributesHelper(curAttrs:Object, importer:TLFormatImporter):Object
 		{
 			return extractAttributesHelper(curAttrs,importer);
 		}
 		
-		/** Parse an SPGE element
+		/** 
+		 * Parse an SPGE element
 		 * 
 		 * @param - importFilter:BaseTextLayoutImporter - parser object
 		 * @param - xmlToParse:XML - the xml describing the TCY Block
@@ -379,7 +454,8 @@ package flashx.textLayout.conversion
 			}
 		}
 
-		/** Parse a TCY Block.
+		/** 
+		 * Parse a TCY Block.
 		 * 
 		 * @param - importFilter:BaseTextLayoutImporter - parser object
 		 * @param - xmlToParse:XML - the xml describing the TCY Block
@@ -399,7 +475,8 @@ package flashx.textLayout.conversion
 		}
 		
 				
-		/** Parse a LinkElement Block.
+		/** 
+		 * Parse a LinkElement Block.
 		 * 
 		 * @param - importFilter:BaseTextLayoutImporter - parser object
 		 * @param - xmlToParse:XML - the xml describing the Link
@@ -456,7 +533,8 @@ package flashx.textLayout.conversion
 		static public function parseListMarkerFormat(importFilter:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void
 		{ parent.listMarkerFormat = TextLayoutImporter(importFilter).createListMarkerFormatDictionaryFromXML(xmlToParse); }
 
-		/** Parse the <div ...> tag and all its children
+		/** 
+		 * Parse the <div ...> tag and all its children
 		 * 
 		 * @param - importFilter:BaseTextLayoutImportFilter - parser object
 		 * @param - xmlToParse:XML - the xml describing the Div
@@ -474,7 +552,8 @@ package flashx.textLayout.conversion
 			}
 		}
 
-		/** Parse a leaf element, the <img ...>  tag.
+		/** 
+		 * Parse a leaf element, the <img ...>  tag.
 		 * 
 		 * @param - importFilter:BaseTextLayoutImporter - parser object
 		 * @param - xmlToParse:XML - the xml describing the InlineGraphic FlowElement
@@ -485,6 +564,115 @@ package flashx.textLayout.conversion
 			var ilg:InlineGraphicElement = TextLayoutImporter(importFilter).createInlineGraphicFromXML(xmlToParse);
 			importFilter.addChild(parent, ilg);
 		}
+		
+		/** 
+		 * Parse the <table ...> tag and all its children
+		 * 
+		 * @param - importFilter:BaseTextLayoutImportFilter - parser object
+		 * @param - xmlToParse:XML - the xml describing the Table
+		 * @param - parent:FlowBlockElement - the parent of the new Table
+		 */
+		static public function parseTable(importFilter:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void
+		{
+			var tableElement:TableElement = TextLayoutImporter(importFilter).createTableFromXML(xmlToParse);
+			
+			if (importFilter.addChild(parent, tableElement)) 
+			{
+				importFilter.parseFlowGroupElementChildren(xmlToParse, tableElement);
+				
+			}
+		}
+		
+		/** 
+		 * Parse the <tr ...> tag (TableRowElement) and all its children
+		 * 
+		 * @param - importFilter:BaseTextLayoutImportFilter - parser object
+		 * @param - xmlToParse:XML - the xml describing the Table
+		 * @param - parent:FlowBlockElement - the parent of the new Table
+		 */
+		static public function parseTableRow(importFilter:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void
+		{
+			var tableRowElement:TableRowElement = TextLayoutImporter(importFilter).createTableRowFromXML(xmlToParse);
+			var table:TableElement;
+			
+			if (importFilter.addChild(parent, tableRowElement))
+			{
+				
+				importFilter.parseFlowGroupElementChildren(xmlToParse, tableRowElement);
+				
+				table = tableRowElement.getTable();
+				
+				var columnCount:int = tableRowElement.getColumnCount();
+				
+				if (table.numColumns<columnCount) {
+					table.numColumns = columnCount;
+				}
+				
+				table.insertRow(tableRowElement, tableRowElement.mxmlChildren);
+				
+			}
+		}
+		
+		/** 
+		 * Parse the <td ...> or <th ...> tag (TableCellElement) and all its children
+		 * 
+		 * @param - importFilter:BaseTextLayoutImportFilter - parser object
+		 * @param - xmlToParse:XML - the xml describing the Table
+		 * @param - parent:FlowBlockElement - the parent of the new Table
+		 */
+		static public function parseTableCell(importFilter:BaseTextLayoutImporter, xmlToParse:XML, parent:FlowGroupElement):void
+		{
+			var tableCellElement:TableCellElement = TextLayoutImporter(importFilter).createTableCellFromXML(xmlToParse);
+			
+			if (importFilter.addChild(parent, tableCellElement))
+			{
+				importFilter.parseTableCellElementChildren(xmlToParse, tableCellElement);
+			}
+			
+			//tableCellElement.textFlow = getTextFlowContent("test cell");
+			
+			TableRowElement(parent).addCell(tableCellElement);
+			//TableRowElement(parent).getTable().addChild(tableCellElement);
+			//importFilter.parseFlowGroupElementChildren(xmlToParse, tableCellElement);
+			
+			// we can't have a <td> tag w/no children... so, add an empty text flow
+			//if (tableCellElement.numChildren == 0) {
+			//	tableCellElement.addChild(new TextFlow());
+			//}
+				
+		}
+		
+		/**
+		 * Creates default text flow from the text value passed in. Used for table cell text flows. 
+		 * Used for testing. May be removed in the future. 
+		 **/
+		static public function getTextFlowContent(text:String = null, selectable:Boolean = false, editable:Boolean = false):TextFlow {
+			var textFlowContent:TextFlow = new TextFlow();
+			var paragraph:ParagraphElement = new ParagraphElement();
+			var span:SpanElement = new SpanElement();
+			
+			if (text) {
+				span.text = text;
+			}
+			else {
+				span.text = "";
+			}
+			
+			paragraph.backgroundAlpha = 0.2;
+			paragraph.backgroundColor = 0xFF0000;
+			paragraph.addChild(span);
+			
+			if (editable) {
+				//textFlowContent.interactionManager = new EditManager(new UndoManager);
+			}
+			else if (selectable) {
+				//textFlowContent.interactionManager = new SelectionManager();
+			}
+			
+			textFlowContent.addChild(paragraph);
+			
+			return textFlowContent;
+		}
 	}
 }
 

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/edit/EditManager.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/edit/EditManager.as b/textLayout/src/flashx/textLayout/edit/EditManager.as
index 2b46e72..28a45c6 100644
--- a/textLayout/src/flashx/textLayout/edit/EditManager.as
+++ b/textLayout/src/flashx/textLayout/edit/EditManager.as
@@ -35,6 +35,7 @@ package flashx.textLayout.edit
 	import flash.ui.Keyboard;
 	import flash.utils.getQualifiedClassName;
 	
+	import flashx.textLayout.tlf_internal;
 	import flashx.textLayout.compose.IFlowComposer;
 	import flashx.textLayout.container.ContainerController;
 	import flashx.textLayout.debug.Debugging;
@@ -52,11 +53,12 @@ package flashx.textLayout.edit
 	import flashx.textLayout.elements.ParagraphElement;
 	import flashx.textLayout.elements.SubParagraphGroupElement;
 	import flashx.textLayout.elements.TCYElement;
-	import flashx.textLayout.elements.TableDataCellElement;
+	import flashx.textLayout.elements.TableCellElement;
 	import flashx.textLayout.elements.TableElement;
 	import flashx.textLayout.elements.TextFlow;
 	import flashx.textLayout.elements.TextRange;
 	import flashx.textLayout.events.FlowOperationEvent;
+	import flashx.textLayout.events.ModelChange;
 	import flashx.textLayout.formats.IListMarkerFormat;
 	import flashx.textLayout.formats.ITextLayoutFormat;
 	import flashx.textLayout.formats.TextLayoutFormat;
@@ -85,7 +87,6 @@ package flashx.textLayout.edit
 	import flashx.textLayout.operations.SplitElementOperation;
 	import flashx.textLayout.operations.SplitParagraphOperation;
 	import flashx.textLayout.operations.UndoOperation;
-	import flashx.textLayout.tlf_internal;
 	import flashx.textLayout.utils.CharacterUtil;
 	import flashx.textLayout.utils.GeometryUtil;
 	import flashx.textLayout.utils.NavigationUtil;
@@ -466,6 +467,23 @@ package flashx.textLayout.edit
 								doOperation(new CreateListOperation(new SelectionState(textFlow, element.getAbsoluteStart(), element.getAbsoluteStart() + element.textLength), listItem.parent));
 							}
 						}
+						else if (textFlow.nestedInTable()) {
+							var cell:TableCellElement;
+							
+							if (event.shiftKey) {
+								cell = (textFlow.parentElement as TableCellElement).getPreviousCell();
+							}
+							else {
+								cell = (textFlow.parentElement as TableCellElement).getNextCell();
+							}
+							
+							// select next cell in table
+							if (cell && cell.textFlow && cell.textFlow.interactionManager is EditManager) {
+								//cell.textFlow.interactionManager.selectLastPosition();
+								cell.textFlow.interactionManager.selectAll();
+								cell.textFlow.interactionManager.setFocus();
+							}
+						}
 						else
 						{
 							overwriteMode ? overwriteText(String.fromCharCode(event.charCode)) : insertText(String.fromCharCode(event.charCode));
@@ -829,8 +847,19 @@ package flashx.textLayout.edit
 				redrawListener = null;
 			}
 
+			var cellHeight:Number = 0;
 			if (textFlow.flowComposer)
 			{
+				if(superManager && superManager is IEditManager)
+				{
+					var controller:ContainerController = textFlow.flowComposer.getControllerAt(0);
+					if (controller)
+					{
+						cellHeight = controller.container.height;
+					}
+				}
+
+
 				 textFlow.flowComposer.updateAllControllers(); 
 
 				// Scroll to selection
@@ -840,6 +869,18 @@ package flashx.textLayout.edit
 					if (controllerIndex >= 0)
 						textFlow.flowComposer.getControllerAt(controllerIndex).scrollToRange(activePosition,anchorPosition);	
 				}
+				if(superManager && superManager is IEditManager)
+				{
+					if(controller.container.height != cellHeight)
+					{
+						var setFormat:String = selectionFormatState;
+						var table:TableElement = (textFlow.parentElement as TableCellElement).getTable();
+						table.modelChanged(ModelChange.ELEMENT_MODIFIED, table, 0, table.textLength);
+						(superManager as IEditManager).updateAllControllers();
+						if(setFormat == SelectionFormatState.FOCUSED)
+							setFocus();
+					}
+				}
 			}
 
 			selectionChanged(true, false);
@@ -1259,12 +1300,14 @@ package flashx.textLayout.edit
 			if (!operationState)
 				return;
 
+			/*
+			This should not be necessary...
 			// mjzhang : fix for table
 			var leaf:FlowLeafElement = textFlow.findLeaf(operationState.absoluteStart);
 			var para:ParagraphElement = leaf.getParagraph();
 			if ( para.isInTable() )
 				return;
-			
+			*/
 			// Delete the next character if it's a caret selection, and allow adejacent delete next's to merge
 			// If it's a range selection, delete the range and disallow merge
 			var deleteOp:DeleteTextOperation;
@@ -1369,10 +1412,12 @@ package flashx.textLayout.edit
 				}
 				if(movePara)
 				{
+					/*
+					should not be necessary...
 					// mjzhang: fix for table feature
 					if ( para.isInTable() )
 						return;
-					
+					*/
 					var source:FlowGroupElement;
 					var target:FlowGroupElement;
 					var numElementsToMove:int;

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/edit/ISelectionManager.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/edit/ISelectionManager.as b/textLayout/src/flashx/textLayout/edit/ISelectionManager.as
index abe6f29..30eb446 100644
--- a/textLayout/src/flashx/textLayout/edit/ISelectionManager.as
+++ b/textLayout/src/flashx/textLayout/edit/ISelectionManager.as
@@ -25,9 +25,12 @@ package flashx.textLayout.edit
 	import flash.events.MouseEvent;
 	import flash.events.TextEvent;
 	
+	import flashx.textLayout.elements.CellCoordinates;
+	import flashx.textLayout.elements.CellRange;
+	import flashx.textLayout.elements.TableElement;
 	import flashx.textLayout.elements.TextFlow;
-	import flashx.textLayout.formats.TextLayoutFormat;
 	import flashx.textLayout.elements.TextRange;
+	import flashx.textLayout.formats.TextLayoutFormat;
 
 	/** 
 	 * The ISelectionManager interface defines the interface for handling text selection.
@@ -64,6 +67,23 @@ package flashx.textLayout.edit
 		function get textFlow():TextFlow;
 		function set textFlow(flow:TextFlow):void;
 		
+		function get currentTable():TableElement;
+		function set currentTable(table:TableElement):void;
+		function hasCellRangeSelection():Boolean;
+		
+		function selectCellRange(anchorCoords:CellCoordinates,activeCoords:CellCoordinates):void;
+		
+		function getCellRange():CellRange;
+		function setCellRange(range:CellRange):void;
+
+		/** Anchor point of the current cell selection, as coordinates within the table. */
+		function get anchorCellPosition():CellCoordinates;
+		function set anchorCellPosition(value:CellCoordinates):void;
+		
+		/** Active end of the current cell selection, as coordinates within the table. */
+		function get activeCellPosition():CellCoordinates;
+		function set activeCellPosition(value:CellCoordinates):void;
+
 		/** 
 		 * The text position of the start of the selection, as an offset from the start of the text flow.
 		 *  
@@ -113,6 +133,33 @@ package flashx.textLayout.edit
 		 */
 		function selectAll() : void
 		
+		/**
+		 * Selects the last position in the entire flow.
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+ 		 * @langversion 3.0
+		 */
+		function selectLastPosition() : void
+		
+		/**
+		 * Selects the first position in the entire flow.
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+ 		 * @langversion 3.0
+		 */
+		function selectFirstPosition() : void
+
+		/**
+		 * Removes any selection from the text flow
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		function deselect() : void
+
 		/** 
 		 * The anchor point of the selection. 
 		 * 
@@ -140,7 +187,7 @@ package flashx.textLayout.edit
 		function get activePosition() : int;
 		
 		/**
-		 * Indicates whether there is a selection. 
+		 * Indicates whether there is a text selection. 
 		 * 
 		 * <p>Returns <code>true</code> if there is either a range selection or a point selection. 
 		 * By default, when a selection manager is first set up, there is no selection (the start and end are -1).</p>
@@ -152,6 +199,34 @@ package flashx.textLayout.edit
  		 * @langversion 3.0
 		 */
 		function hasSelection():Boolean;
+
+		/**
+		 * Indicates whether there is a text or cell selection. 
+		 * 
+		 * <p>Returns <code>true</code> if there is either a range selection or a point selection. 
+		 * By default, when a selection manager is first set up, there is no selection (the start and end are -1).</p>
+		 * 
+		 * @includeExample examples\SelectionManager_hasSelection.as -noswf
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		function hasAnySelection():Boolean;
+
+		/**
+		 * Indicates the type of selection. 
+		 * 
+		 * <p>The <code>selectionType</code> describes the kind of selection. 
+		 * It can either be <code>SelectionType.TEXT</code> or <code>SelectionType.CELLS</code>
+		 * 
+		 * @see flashx.textLayout.edit.SelectionType
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		function get selectionType() : String;
 		
 		/**
 		 * Indicates whether the selection covers a range of text.
@@ -201,6 +276,14 @@ package flashx.textLayout.edit
 		 */	
 		function refreshSelection():void;
 
+		/** 
+		 * Clears the selection shapes. 
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+ 		 * @langversion 3.0
+		 */	
+		function clearSelection():void;
 
 		/** 
 		 * Gives the focus to the first container in the selection.
@@ -250,6 +333,19 @@ package flashx.textLayout.edit
 		 */
 		function get currentSelectionFormat():SelectionFormat;
 
+		/** 
+		 * The current Cell SelectionFormat object.
+		 * 
+		 * <p>The current cell SelectionFormat object is chosen from the SelectionFormat objects assigned to the 
+		 * <code>unfocusedCellSelectionFormat</code>, <code>inactiveCellSelectionFormat</code> and <code>focusedCellSelectionFormat</code> 
+		 * properties based on the current state of the <code>windowActive</code> and <code>focused</code> properties.</p> 
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */
+		function get currentCellSelectionFormat():SelectionFormat;
+
 		/**
 		 * Gets the character format attributes that are common to all characters in the specified text range or current selection.
 		 * 
@@ -346,7 +442,38 @@ package flashx.textLayout.edit
 		 */		 		 
 		 function get inactiveSelectionFormat():SelectionFormat;
 		 function set inactiveSelectionFormat(val:SelectionFormat):void;		 		 
-		
+
+		 /**
+		  * The SelectionFormat object used to draw cell selections in a focused container. 
+		  * 
+		  * @playerversion Flash 10
+		  * @playerversion AIR 1.5
+		  * @langversion 3.0
+		  */		 
+		 function get focusedCellSelectionFormat():SelectionFormat;
+		 function set focusedCellSelectionFormat(val:SelectionFormat):void;
+		 
+		 /**
+		  * The SelectionFormat object used to draw cell selections when they are not in a focused container, but are in
+		  * the active window.
+		  * 
+		  * @playerversion Flash 10
+		  * @playerversion AIR 1.5
+		  * @langversion 3.0
+		  */		 		 
+		 function get unfocusedCellSelectionFormat():SelectionFormat;
+		 function set unfocusedCellSelectionFormat(val:SelectionFormat):void;
+		 
+		 /**
+		  * The SelectionFormat object used to draw cell selections when they are not in the active window.
+		  * 
+		  * @playerversion Flash 10
+		  * @playerversion AIR 1.5
+		  * @langversion 3.0
+		  */		 		 
+		 function get inactiveCellSelectionFormat():SelectionFormat;
+		 function set inactiveCellSelectionFormat(val:SelectionFormat):void;		 		 
+
 		/**
 		 * Executes any pending FlowOperations. 
 		 * 
@@ -379,6 +506,25 @@ package flashx.textLayout.edit
  	 	 * @langversion 3.0
 		 */
 		function notifyInsertOrDelete(absolutePosition:int, length:int):void		 
-		 	
+		 
+		/**
+		 * The ISelectionManager object used to for cell selections nested within the TextFlow managed by this ISelectionManager.
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */		 		 
+		function get subManager():ISelectionManager;
+		function set subManager(value:ISelectionManager):void;
+		
+		/**
+		 * The ISelectionManager object used to manage the parent TextFlow of this ISelectionManager (i.e. for cell ISelectionManagers).
+		 * 
+		 * @playerversion Flash 10
+		 * @playerversion AIR 1.5
+		 * @langversion 3.0
+		 */		 		 
+		function get superManager():ISelectionManager;
+		function set superManager(value:ISelectionManager):void;
 	}
 }

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/edit/ModelEdit.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/edit/ModelEdit.as b/textLayout/src/flashx/textLayout/edit/ModelEdit.as
index cdddb3b..b18f55f 100644
--- a/textLayout/src/flashx/textLayout/edit/ModelEdit.as
+++ b/textLayout/src/flashx/textLayout/edit/ModelEdit.as
@@ -516,7 +516,7 @@ class JoinMemento extends BaseMemento implements IMemento
 		
 		var element1Mark:ElementMark = new ElementMark(element1,0);
 		var element2Mark:ElementMark = new ElementMark(element2,0);
-		performInternal(textFlow, element1Mark, element2Mark);		
+		performInternal(textFlow, element1Mark, element2Mark);
 		var removeParentChain:IMemento = TextFlowEdit.removeEmptyParentChain(element2);
 
 		if (createMemento)

http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/edit/ParaEdit.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/edit/ParaEdit.as b/textLayout/src/flashx/textLayout/edit/ParaEdit.as
index 974eba2..09ee41b 100644
--- a/textLayout/src/flashx/textLayout/edit/ParaEdit.as
+++ b/textLayout/src/flashx/textLayout/edit/ParaEdit.as
@@ -93,9 +93,13 @@ package flashx.textLayout.edit
 					break;
 				}
 			}
-				
 			// adjust the flow so that we are in a span for the insertion
 			var insertSpan:SpanElement = sibling as SpanElement;
+			
+			// use the terminator span if it's empty
+			if(paragraph.terminatorSpan.textLength == 1 && paragraph.terminatorSpan == insertSpan)
+				createNewSpan = false;
+			
 			if (!insertSpan || createNewSpan)
 			{
 				var newSpan:SpanElement = new SpanElement();
@@ -111,7 +115,15 @@ package flashx.textLayout.edit
 							sibling.splitAtPosition(relativeStart);		// we'll insert between the two elements
 					}
 				}
-				insertParent.replaceChildren(siblingIndex, siblingIndex, newSpan);
+				var nextLeaf:FlowLeafElement = paragraph.findLeaf(paraSelBegIdx);
+				if(nextLeaf && nextLeaf.textLength == 1 && nextLeaf == paragraph.terminatorSpan)
+				{
+					// use the terminator span instead of inserting a new one.
+					newSpan = SpanElement(nextLeaf);
+				}
+				else {
+					insertParent.replaceChildren(siblingIndex, siblingIndex, newSpan);
+				}
 				var formatElem:FlowLeafElement = newSpan.getPreviousLeaf(paragraph);
 				if (formatElem == null)
 					newSpan.format = newSpan.getNextLeaf(paragraph).format;