You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by ah...@apache.org on 2019/12/23 06:52:39 UTC

[royale-asjs] 01/09: FormItemSkin clean compilation. But will it work?

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

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

commit 8047afb888a484e5d71dc4663536ba0a1611d9eb
Author: Alex Harui <ah...@apache.org>
AuthorDate: Tue Dec 10 11:43:59 2019 -0800

    FormItemSkin clean compilation.  But will it work?
---
 .../org/apache/royale/html/beads/ContainerView.as  |   28 +-
 .../MXRoyale/src/main/resources/defaults.css       |    1 +
 .../MXRoyale/src/main/royale/MXRoyaleClasses.as    |    3 +
 .../royale/mx/containers/errors/ConstraintError.as |   58 +
 .../containers/utilityClasses/ConstraintColumn.as  |    6 +-
 .../mx/containers/utilityClasses/ConstraintRow.as  |    6 +-
 .../MXRoyale/src/main/royale/mx/controls/Button.as |   11 -
 .../src/main/royale/mx/core/ILayoutElement.as      |    5 +-
 .../src/main/royale/mx/core/UIComponent.as         |   70 +-
 .../SparkRoyale/src/main/resources/defaults.css    |   12 +-
 .../src/main/resources/spark-royale-manifest.xml   |    4 +
 .../src/main/royale/SparkRoyaleClasses.as          |    5 +
 .../src/main/royale/spark/components/Label.as      |   11 +-
 .../components/beads/SkinnableContainerView.as     |   26 +-
 ...nableContainerView.as => SparkContainerView.as} |    9 +-
 .../components/beads/SparkSkinScrollingViewport.as |  168 ++
 .../spark/components/supportClasses/ButtonBase.as  |    9 -
 .../supportClasses/SkinnableComponent.as           |    6 +-
 .../components/supportClasses/SkinnableTextBase.as |   16 +-
 .../spark/components/supportClasses/TextBase.as    |   13 +-
 .../main/royale/spark/layouts/ConstraintLayout.as  | 1984 ++++++++++++++++++++
 .../main/royale/spark/layouts/FormItemLayout.as    |   10 +-
 .../src/main/royale/spark/layouts/FormLayout.as    |    6 +-
 .../royale/spark/skins/spark/FormItemSkin.mxml     |  188 ++
 .../main/royale/spark/skins/spark/FormSkin.mxml    |   97 +
 25 files changed, 2651 insertions(+), 101 deletions(-)

diff --git a/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/beads/ContainerView.as b/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/beads/ContainerView.as
index fae6a90..0d242a6 100644
--- a/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/beads/ContainerView.as
+++ b/frameworks/projects/Basic/src/main/royale/org/apache/royale/html/beads/ContainerView.as
@@ -136,12 +136,17 @@ package org.apache.royale.html.beads
 
             createViewport();
 
-			var chost:IContainer = host as IContainer;
-			chost.strandChildren.addElement(viewport.contentView);
+            addViewport();
 
 			super.strand = value;
 		}
 
+        protected function addViewport():void
+        {
+            var chost:IContainer = host as IContainer;
+            chost.strandChildren.addElement(viewport.contentView);            
+        }
+        
 		/**
 		 * Called when the host is ready to complete its setup (usually after its size has been
 		 * determined).
@@ -368,14 +373,19 @@ package org.apache.royale.html.beads
 				_viewport = loadBeadFromValuesManager(IViewport, "iViewport", _strand) as IViewport;
 			
 			if (_viewport) {
-				var chost:IContainer = host as IContainer;
-				// add the viewport's contentView to this host ONLY if
-				// the contentView is not the host itself, which is likely
-				// most situations.
-				if (chost != null && chost != _viewport.contentView) {
-					chost.addElement(_viewport.contentView);
-				}
+                addViewport();
 			}
 		}
+        
+        protected function addViewport():void
+        {
+            var chost:IContainer = host as IContainer;
+            // add the viewport's contentView to this host ONLY if
+            // the contentView is not the host itself, which is likely
+            // most situations.
+            if (chost != null && chost != _viewport.contentView) {
+                chost.addElement(_viewport.contentView);
+            }            
+        }
 	}
 }
diff --git a/frameworks/projects/MXRoyale/src/main/resources/defaults.css b/frameworks/projects/MXRoyale/src/main/resources/defaults.css
index a1dea0c..be9e88f 100644
--- a/frameworks/projects/MXRoyale/src/main/resources/defaults.css
+++ b/frameworks/projects/MXRoyale/src/main/resources/defaults.css
@@ -124,6 +124,7 @@ Alert
 Button
 {
     IBeadModel: ClassReference("org.apache.royale.html.beads.models.ImageAndTextModel");
+	font-weight: bold;
 }
 
 Canvas
diff --git a/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as b/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as
index c001742..77e4881 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/MXRoyaleClasses.as
@@ -57,6 +57,9 @@ internal class MXRoyaleClasses
 	import mx.containers.beads.CanvasLayout; CanvasLayout;
     import mx.containers.beads.layouts.BasicLayout; BasicLayout;
 	import mx.controls.beads.AlertView; AlertView;
+    import mx.containers.errors.ConstraintError; ConstraintError;
+    import mx.containers.utilityClasses.ConstraintColumn; ConstraintColumn;
+    import mx.containers.utilityClasses.ConstraintRow; ConstraintRow;
 	import mx.containers.gridClasses.GridColumnInfo; GridColumnInfo;
 	import mx.containers.gridClasses.GridRowInfo; GridRowInfo;
 	import mx.events.CloseEvent; CloseEvent;
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/containers/errors/ConstraintError.as b/frameworks/projects/MXRoyale/src/main/royale/mx/containers/errors/ConstraintError.as
new file mode 100644
index 0000000..da029e5
--- /dev/null
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/containers/errors/ConstraintError.as
@@ -0,0 +1,58 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 mx.containers.errors
+{
+
+/**
+ *  This error is thrown when a constraint expression is not configured properly;
+ *  for example, if the GridColumn reference is invalid.
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class ConstraintError extends Error
+{
+//    include "../../core/Version.as";
+
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Constructor.
+	 *
+	 *  @param message A message providing information about the error cause.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function ConstraintError(message:String)
+    {
+        super(message);
+    }
+}
+
+}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/containers/utilityClasses/ConstraintColumn.as b/frameworks/projects/MXRoyale/src/main/royale/mx/containers/utilityClasses/ConstraintColumn.as
index 4e8de23..527b0af 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/containers/utilityClasses/ConstraintColumn.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/containers/utilityClasses/ConstraintColumn.as
@@ -27,13 +27,13 @@ import flash.events.Event;
 import flash.events.IEventDispatcher;
 */
 import mx.core.IInvalidating;
-/*
 import mx.core.mx_internal;
+/*
 import mx.core.IMXMLObject;
 import flash.events.EventDispatcher;
 
-use namespace mx_internal;
 */
+use namespace mx_internal;
 
 /**
  *  The ConstraintColumn class partitions an absolutely
@@ -76,7 +76,7 @@ public class ConstraintColumn extends EventDispatcher //implements IMXMLObject
 	//  Variables
 	//
 	//--------------------------------------------------------------------------
-	protected var contentSize:Boolean = false;
+	mx_internal var contentSize:Boolean = false;
 	
 	//--------------------------------------------------------------------------
 	//
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/containers/utilityClasses/ConstraintRow.as b/frameworks/projects/MXRoyale/src/main/royale/mx/containers/utilityClasses/ConstraintRow.as
index 706a69e..92ef5a3 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/containers/utilityClasses/ConstraintRow.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/containers/utilityClasses/ConstraintRow.as
@@ -27,12 +27,12 @@ import flash.events.Event;
 import flash.events.IEventDispatcher;
 */
 import mx.core.IInvalidating;
-/*
 import mx.core.mx_internal;
+use namespace mx_internal;
+/*
 import mx.core.IMXMLObject;
 import flash.events.EventDispatcher;
 
-use namespace mx_internal;
 */
 	
 /**
@@ -75,7 +75,7 @@ public class ConstraintRow extends EventDispatcher //implements IMXMLObject
 	//  Variables
 	//
 	//--------------------------------------------------------------------------
-	protected var contentSize:Boolean = false;
+	mx_internal var contentSize:Boolean = false;
 	
 	
 	//--------------------------------------------------------------------------
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/Button.as b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/Button.as
index 75baacb..e97663f 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/controls/Button.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/controls/Button.as
@@ -277,17 +277,6 @@ public class Button extends UIComponent implements IDataRenderer
 	}
 	
 	// ------------------------------------------------
-	//  fontStyle
-	// ------------------------------------------------
-	
-	public function get fontStyle():String
-	{
-		return "BOLD";
-	}
-	public function set fontStyle(value:String):void
-	{
-	}
-	// ------------------------------------------------
 	//  icon
 	// ------------------------------------------------
 	
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/core/ILayoutElement.as b/frameworks/projects/MXRoyale/src/main/royale/mx/core/ILayoutElement.as
index 786b73b..ecb8ec3 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/core/ILayoutElement.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/core/ILayoutElement.as
@@ -224,13 +224,14 @@ public interface ILayoutElement extends IEventDispatcher
      *  @playerversion Flash 10
      *  @playerversion AIR 1.5
      *  @productversion Flex 4
-    function get baseline():Object;
      */
+    function get baseline():Object;
+     
     
     /**
      *  @private
-    function set baseline(value:Object):void;
      */
+    function set baseline(value:Object):void;
 
     /**
      *  The y-coordinate of the baseline
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/core/UIComponent.as b/frameworks/projects/MXRoyale/src/main/royale/mx/core/UIComponent.as
index 8494e90..12d7914 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/core/UIComponent.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/core/UIComponent.as
@@ -3112,7 +3112,12 @@ COMPILE::JS
         addEventListener("stateChangeComplete", stateChangeCompleteHandler);
         dispatchEvent(event);
     }
-
+    
+    public function setCurrentState(stateName:String, playTransition:Boolean=true):void
+    {
+        currentState = stateName;
+    }
+    
     private function stateChangeCompleteHandler(event:Event):void
     {
         callLater(dispatchUpdateComplete); 
@@ -4679,6 +4684,52 @@ COMPILE::JS
     {
         this._uid = uid;
     }
+    
+    /*	  
+    *  @langversion 3.0
+    *  @playerversion Flash 9
+    *  @playerversion AIR 1.1
+    *  @productversion Flex 3
+    */
+    public function get showErrorSkin():Object
+    {
+        return ValuesManager.valuesImpl.getValue(this, "showErrorSkin");
+    }
+    public function set showErrorSkin(value:Object):void
+    {
+        setStyle("showErrorSkin", value);
+    }
+
+    /*	  
+    *  @langversion 3.0
+    *  @playerversion Flash 9
+    *  @playerversion AIR 1.1
+    *  @productversion Flex 3
+    */
+    public function get showErrorTip():Object
+    {
+        return ValuesManager.valuesImpl.getValue(this, "showErrorTip");
+    }
+    public function set showErrorTip(value:Object):void
+    {
+        setStyle("showErrorTip", value);
+    }
+    
+    /*	  
+    *  @langversion 3.0
+    *  @playerversion Flash 9
+    *  @playerversion AIR 1.1
+    *  @productversion Flex 3
+    */
+    public function get baseline():Object
+    {
+        return ValuesManager.valuesImpl.getValue(this, "baseline");
+    }
+    public function set baseline(value:Object):void
+    {
+        setStyle("baseline", value);
+    }
+    
 	[Inspectable(category="General")]
 	
 	/*	  
@@ -4695,6 +4746,23 @@ COMPILE::JS
     {
         setStyle("fontSize", value);
     }
+    [Inspectable(category="General")]
+    
+    /*	  
+    *  @langversion 3.0
+    *  @playerversion Flash 9
+    *  @playerversion AIR 1.1
+    *  @productversion Flex 3
+    */
+    public function get fontStyle():Object
+    {
+        return ValuesManager.valuesImpl.getValue(this, "fontStyle");
+    }
+    public function set fontStyle(value:Object):void
+    {
+        setStyle("fontStyle", value);
+    }
+    
 	[Inspectable(category="General")]
 	
 	/*	  
diff --git a/frameworks/projects/SparkRoyale/src/main/resources/defaults.css b/frameworks/projects/SparkRoyale/src/main/resources/defaults.css
index b28ab14..48705da 100644
--- a/frameworks/projects/SparkRoyale/src/main/resources/defaults.css
+++ b/frameworks/projects/SparkRoyale/src/main/resources/defaults.css
@@ -117,9 +117,19 @@ DropDownList
 	border: 1px solid #333333
 }
 
+Form
+{
+	skinClass: ClassReference("spark.skins.spark.FormSkin");
+}
+
+FormItem
+{
+	skinClass: ClassReference("spark.skins.spark.FormItemSkin");
+}
+
 List
 {
-	IBeadView: ClassReference("spark.components.beads.SkinnableContainerView");
+	IBeadView: ClassReference("spark.components.beads.SparkContainerView");
 	IBeadLayout: ClassReference("spark.layouts.supportClasses.SparkLayoutBead");
 	IViewport: ClassReference("org.apache.royale.html.supportClasses.ScrollingViewport");
 	IViewportModel: ClassReference("org.apache.royale.html.beads.models.ViewportModel");
diff --git a/frameworks/projects/SparkRoyale/src/main/resources/spark-royale-manifest.xml b/frameworks/projects/SparkRoyale/src/main/resources/spark-royale-manifest.xml
index 265edde..6918347 100644
--- a/frameworks/projects/SparkRoyale/src/main/resources/spark-royale-manifest.xml
+++ b/frameworks/projects/SparkRoyale/src/main/resources/spark-royale-manifest.xml
@@ -75,6 +75,9 @@
 	<component id="HorizontalLayout" class="spark.layouts.HorizontalLayout"/>
 	<component id="TileLayout" class="spark.layouts.TileLayout"/>
     <component id="Module" class="spark.modules.Module" />
+    <component id="FormItemLayout" class="spark.layouts.FormItemLayout"/>
+    <component id="ConstraintColumn" class="mx.containers.utilityClasses.ConstraintColumn" lookupOnly="true"/>
+    <component id="ConstraintRow" class="mx.containers.utilityClasses.ConstraintRow" lookupOnly="true"/>
 
     <component id="ArrayCollection" class="mx.collections.ArrayCollection" lookupOnly="true"/>
 
@@ -115,6 +118,7 @@
     <component id="TabBarView" class="spark.components.beads.TabBarView"/>
     <component id="MXAdvancedDataGridItemRenderer" class="spark.controls.advancedDataGridClasses.MXAdvancedDataGridItemRenderer"/>
     <component id="SparkTextButtonItemRenderer" class="spark.components.supportClasses.SparkTextButtonItemRenderer"/>
+    <component id="Skin" class="spark.components.supportClasses.Skin"/>
 
 	
 </componentPackage>
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as b/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as
index 82ec840..bea2c7f 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as
@@ -36,8 +36,12 @@ internal class SparkRoyaleClasses
     import spark.skins.spark.TitleWindowCloseButtonSkin; TitleWindowCloseButtonSkin; 
 	import spark.skins.spark.ComboBoxButtonSkin; ComboBoxButtonSkin; 
 	import spark.skins.spark.ComboBoxTextInputSkin; ComboBoxTextInputSkin; 
+    import spark.skins.spark.FormSkin; FormSkin; 
+    import spark.skins.spark.FormItemSkin; FormItemSkin; 
 	
 	import spark.layouts.supportClasses.SparkLayoutBead; SparkLayoutBead;
+    import spark.layouts.FormLayout; FormLayout;
+    import spark.layouts.FormItemLayout; FormItemLayout;
 	
 	import spark.components.supportClasses.RegExPatterns; RegExPatterns;
 	
@@ -77,6 +81,7 @@ internal class SparkRoyaleClasses
     import spark.components.beads.PanelView; PanelView;
     import spark.components.beads.GroupView; GroupView;
     import spark.components.beads.SkinnableContainerView; SkinnableContainerView;
+    import spark.components.beads.SparkSkinScrollingViewport; SparkSkinScrollingViewport;
     import spark.components.beads.DropDownListView; DropDownListView;
     import spark.components.beads.TitleWindowView; TitleWindowView;
     import spark.components.beads.controllers.DropDownListController; DropDownListController;
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Label.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Label.as
index cf07f26..f1faad0 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Label.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Label.as
@@ -419,16 +419,7 @@ public class Label extends TextBase
     {
         
     }
-	
-	public function get fontStyle():String
-    {
-        return "";
-    }
-    public function set fontStyle(value:String):void
-    {
-        
-    }
-    
+	    
     public function get textDecoration():String
     {
         return "";
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SkinnableContainerView.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SkinnableContainerView.as
index f02ae43..ca63c80 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SkinnableContainerView.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SkinnableContainerView.as
@@ -22,18 +22,19 @@ package spark.components.beads
 
 import spark.components.SkinnableContainer;
 import spark.components.supportClasses.GroupBase;
+import spark.components.supportClasses.SkinnableComponent;
 
 import org.apache.royale.core.IBead;
+import org.apache.royale.core.IContainer;
 import org.apache.royale.core.ILayoutChild;
 import org.apache.royale.core.IStrand;
 import org.apache.royale.core.UIBase;
-import org.apache.royale.html.beads.ContainerView;
 
 /**
  *  @private
  *  The SkinnableContainerView for emulation.
  */
-public class SkinnableContainerView extends ContainerView
+public class SkinnableContainerView extends SparkContainerView
 {
 	//--------------------------------------------------------------------------
 	//
@@ -54,22 +55,15 @@ public class SkinnableContainerView extends ContainerView
 		super();
 	}
 
-    /**
-     */
-    override public function set strand(value:IStrand):void
+    override protected function addViewport():void
     {
-        super.strand = value;
-        var host:SkinnableContainer = _strand as SkinnableContainer;
-        var g:GroupBase = (contentView as GroupBase);
-        g.layout = host.layout;
-        
-        if (!host.isWidthSizedToContent())
-            g.percentWidth = 100;
-        if (!host.isHeightSizedToContent())
-            g.percentHeight = 100;
-
+        var chost:IContainer = host as IContainer;
+        var skinhost:SkinnableComponent = host as SkinnableComponent;
+        if (chost != null && chost != viewport.contentView) {
+            chost.addElement(skinhost.skin);
+        }            
     }
-    
+
 }
 
 }
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SkinnableContainerView.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SparkContainerView.as
similarity index 92%
copy from frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SkinnableContainerView.as
copy to frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SparkContainerView.as
index f02ae43..e27a832 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SkinnableContainerView.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SparkContainerView.as
@@ -24,6 +24,7 @@ import spark.components.SkinnableContainer;
 import spark.components.supportClasses.GroupBase;
 
 import org.apache.royale.core.IBead;
+import org.apache.royale.core.IContainer;
 import org.apache.royale.core.ILayoutChild;
 import org.apache.royale.core.IStrand;
 import org.apache.royale.core.UIBase;
@@ -31,9 +32,9 @@ import org.apache.royale.html.beads.ContainerView;
 
 /**
  *  @private
- *  The SkinnableContainerView for emulation.
+ *  The SparkContainerView for emulation.
  */
-public class SkinnableContainerView extends ContainerView
+public class SparkContainerView extends ContainerView
 {
 	//--------------------------------------------------------------------------
 	//
@@ -49,7 +50,7 @@ public class SkinnableContainerView extends ContainerView
 	 *  @playerversion AIR 1.1
 	 *  @productversion Flex 3
 	 */
-	public function SkinnableContainerView()
+	public function SparkContainerView()
 	{
 		super();
 	}
@@ -69,7 +70,7 @@ public class SkinnableContainerView extends ContainerView
             g.percentHeight = 100;
 
     }
-    
+
 }
 
 }
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SparkSkinScrollingViewport.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SparkSkinScrollingViewport.as
new file mode 100644
index 0000000..d2fa6cf
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/beads/SparkSkinScrollingViewport.as
@@ -0,0 +1,168 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.components.beads
+{
+
+import mx.core.mx_internal;
+use namespace mx_internal;
+
+import spark.components.supportClasses.GroupBase;
+import spark.components.supportClasses.SkinnableComponent;
+
+import org.apache.royale.core.IBead;
+import org.apache.royale.core.IContentView;
+import org.apache.royale.core.IStrand;
+import org.apache.royale.core.IUIBase;
+import org.apache.royale.core.IViewport;
+import org.apache.royale.core.UIBase;
+import org.apache.royale.core.ValuesManager;
+import org.apache.royale.geom.Size;
+
+COMPILE::SWF
+{
+    import flash.geom.Rectangle;
+}
+
+/**
+ *  @private
+ *  The viewport that loads a Spark Skin.
+ */
+public class SparkSkinScrollingViewport implements IViewport
+{
+	//--------------------------------------------------------------------------
+	//
+	//  Constructor
+	//
+	//--------------------------------------------------------------------------
+
+	/**
+	 *  Constructor.
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 9
+	 *  @playerversion AIR 1.1
+	 *  @productversion Flex 3
+	 */
+	public function SparkSkinScrollingViewport()
+	{
+		super();
+	}
+
+    protected var contentArea:UIBase;
+    
+    /**
+     * Get the actual parent of the container's content.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Royale 0.0
+     */
+    public function get contentView():IUIBase
+    {
+        return contentArea;
+    }
+    
+    protected var host:SkinnableComponent;
+    
+    /**
+     */
+    public function set strand(value:IStrand):void
+    {
+        host = value as SkinnableComponent;
+        
+        var c:Class = ValuesManager.valuesImpl.getValue(value, "skinClass") as Class;
+        host.setSkin(new c());
+        
+        contentArea = host.skin["contentGroup"];
+        
+        COMPILE::JS
+        {
+            setScrollStyle();
+        }
+        
+    }
+    
+    /**
+     * Subclasses override this method to change scrolling behavior
+     */
+    COMPILE::JS
+    protected function setScrollStyle():void
+    {
+        contentArea.element.style.overflow = "auto";
+    }
+    
+    /**
+     * @copy org.apache.royale.core.IViewport#setPosition()
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Royale 0.0
+     */
+    public function setPosition(x:Number, y:Number):void
+    {
+        COMPILE::SWF {
+            contentArea.x = x;
+            contentArea.y = y;
+        }
+    }
+    
+    /**
+     * @copy org.apache.royale.core.IViewport#layoutViewportBeforeContentLayout()
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Royale 0.0
+     */
+    public function layoutViewportBeforeContentLayout(width:Number, height:Number):void
+    {
+        COMPILE::SWF {
+            if (!isNaN(width))
+                contentArea.width = width;
+            if (!isNaN(height))
+                contentArea.height = height;
+        }
+    }
+    
+    /**
+     * @copy org.apache.royale.core.IViewport#layoutViewportAfterContentLayout()
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10.2
+     *  @playerversion AIR 2.6
+     *  @productversion Royale 0.0
+     */
+    public function layoutViewportAfterContentLayout(contentSize:Size):void
+    {
+        COMPILE::SWF {
+            var hostWidth:Number = UIBase(host).width;
+            var hostHeight:Number = UIBase(host).height;
+            
+            var rect:flash.geom.Rectangle = new flash.geom.Rectangle(0, 0, hostWidth, hostHeight);
+            contentArea.scrollRect = rect;
+            
+            return;
+        }
+    }
+}
+
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/ButtonBase.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/ButtonBase.as
index 7338e2f..9393500 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/ButtonBase.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/ButtonBase.as
@@ -451,15 +451,6 @@ public class ButtonBase extends SkinnableComponent implements IFocusManagerCompo
         return element;
     }
 
-	public function set fontStyle(value:String):void
-    {
-       
-    }
-	public function get fontStyle():String          
-    {
-        return "NORMAL";
-    }
-    
     public function get lineThrough():Boolean
     {
 	return true;
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/SkinnableComponent.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/SkinnableComponent.as
index e6fb4ba..e96269f 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/SkinnableComponent.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/SkinnableComponent.as
@@ -32,16 +32,16 @@ import flash.utils.*;
 import mx.core.FlexVersion;
 import mx.core.ILayoutElement;
 import mx.core.IVisualElement;
-import mx.core.mx_internal;
 import mx.events.PropertyChangeEvent;
 
 import spark.events.SkinPartEvent;
 import spark.utils.FTETextUtil;
 
-use namespace mx_internal;
 */
 import mx.core.IFactory;
+import mx.core.mx_internal;
 import mx.collections.IList;
+use namespace mx_internal;
 
 import mx.core.UIComponent;
 import spark.components.DataGroup;
@@ -282,7 +282,7 @@ public class SkinnableComponent extends UIComponent
      *  Setter for the skin instance.  This is so the bindable event
      *  is dispatched
      */ 
-    private function setSkin(value:UIComponent):void
+    mx_internal function setSkin(value:UIComponent):void
     {
         if (value === _skin)
            return;
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/SkinnableTextBase.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/SkinnableTextBase.as
index 8f6f098..521a5d2 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/SkinnableTextBase.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/SkinnableTextBase.as
@@ -940,21 +940,7 @@ public class SkinnableTextBase extends SkinnableComponent
         
         invalidateProperties();
     } */
-    
-    //----------------------------------
-    //  fontStyle
-    //----------------------------------
-	
-	public function get fontStyle():String
-    {
-        return "";
-    } 
-  
-     public function set fontStyle(value:String):void
-    {
-    
-    }
-    
+        
     //----------------------------------
     //  typicalText
     //----------------------------------
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/TextBase.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/TextBase.as
index 9274153..aaed390 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/TextBase.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/TextBase.as
@@ -32,7 +32,6 @@ import mx.core.IFlexModuleFactory;
 import mx.resources.IResourceManager;
 import mx.resources.ResourceManager;
 
-import spark.core.IDisplayText;
 import spark.utils.TextUtil;
 
 */
@@ -58,6 +57,8 @@ import org.apache.royale.core.ITextModel;
 
 use namespace mx_internal;
 
+import spark.core.IDisplayText;
+
 //--------------------------------------
 //  Styles
 //--------------------------------------
@@ -113,9 +114,9 @@ use namespace mx_internal;
  *  @royalesuppresspublicvarwarning
 */
 
-public class TextBase extends UIComponent 
-{ //implements IDisplayText
+public class TextBase extends UIComponent implements IDisplayText
 
+{ 
   //  include "../../core/Version.as";
 
     //--------------------------------------------------------------------------
@@ -343,7 +344,7 @@ public class TextBase extends UIComponent
      *  @private
 	 *  Storage for the isTruncated property.
      */
-    //private var _isTruncated:Boolean = false;
+    private var _isTruncated:Boolean = false;
         
     /**
 	 *  A read-only property reporting whether the text has been truncated.
@@ -377,12 +378,12 @@ public class TextBase extends UIComponent
      *  @playerversion AIR 1.5
      *  @productversion Royale 0.9.4
      */
-	/* public function get isTruncated():Boolean
+	public function get isTruncated():Boolean
     {
 		// For some reason, the compiler needs an explicit cast to Boolean
 		// to avoid a warning even though at runtime "is Boolean" is true.
 		return Boolean(_isTruncated);
-    } */
+    }
     
     /**
      *  @private
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/ConstraintLayout.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/ConstraintLayout.as
new file mode 100644
index 0000000..069c55f
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/ConstraintLayout.as
@@ -0,0 +1,1984 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.layouts
+{
+COMPILE::SWF
+{
+    import flash.utils.Dictionary;
+}
+
+import mx.containers.errors.ConstraintError;
+import mx.containers.utilityClasses.ConstraintColumn;
+import mx.containers.utilityClasses.ConstraintRow;
+import mx.containers.utilityClasses.Flex;
+import mx.core.ILayoutElement;
+import mx.core.mx_internal;
+import mx.resources.ResourceManager;
+
+import spark.components.supportClasses.GroupBase;
+import spark.layouts.supportClasses.LayoutBase;
+import spark.layouts.supportClasses.LayoutElementHelper;
+
+import org.apache.royale.geom.Point;
+
+use namespace mx_internal;
+
+//[ResourceBundle("layout")]
+
+/**
+ *  The ConstraintLayout class arranges the layout elements based on their individual
+ *  settings and a set of constraint regions defined by constraint columns and
+ *  constraint rows. Although you can use all of the properties and constraints from
+ *  BasicLayout to position and size elements, ConstraintLayout gives you the ability
+ *  to create sibling-relative layouts by constraining elements to the specified
+ *  columns and rows. 
+ *
+ *  <p><b>Note: </b>The Spark list-based controls (the Spark List control and its subclasses
+ *  such as ButtonBar, ComboBox, DropDownList, and TabBar) do not support the ConstraintLayout class. 
+ *  Do not use ConstraintLayout with the Spark list-based controls.</p>
+ *
+ *  <p>Per-element supported constraints are <code>left</code>, <code>right</code>, 
+ *  <code>top</code>, <code>bottom</code>, <code>baseline</code>,
+ *  <code>percentWidth</code>, and <code>percentHeight</code>.
+ *  Element's minimum and maximum sizes will always be respected.</p>
+ * 
+ *  <p>Columns and rows may have an explicit size or content size (no explicit size). 
+ *  Explicit size regions will be fixed at their specified size, while content size
+ *  regions will stretch to fit only the elements constrained to them. If multiple
+ *  content size regions are spanned by an element, the space will be divided
+ *  equally among the content size regions.</p>
+ *
+ *  <p>The measured size of the container is calculated from the elements, their
+ *  constraints, their preferred sizes, and the sizes of the rows and columns.
+ *  The size of each row and column is just big enough to hold all of the elements
+ *  constrained to it at their preferred sizes with constraints satisfied. The measured
+ *  size of the container is big enough to hold all of the columns and rows as well as
+ *  any other elements left at their preferred sizes with constraints satisfied. </p>
+ *
+ *  <p>During a call to the <code>updateDisplayList()</code> method, 
+ *  the element's size is determined according to
+ *  the rules in the following order of precedence (the element's minimum and
+ *  maximum sizes are always respected):</p>
+ *  <ul>
+ *    <li>If the element has <code>percentWidth</code> or <code>percentHeight</code> set, 
+ *    then its size is calculated as a percentage of the available size, where the available
+ *    size is the region or container size minus any <code>left</code>, <code>right</code>,
+ *    <code>top</code>, or <code>bottom</code> constraints.</li>
+ *
+ *    <li>If the element has both left and right constraints, it's width is
+ *    set to be the region's or container's width minus the <code>left</code> 
+ *    and <code>right</code> constraints.</li>
+ * 
+ *    <li>If the element has both <code>top</code> and <code>bottom</code> constraints, 
+ *    it's height is set to be the container's height minus the <code>top</code>
+ *    and <code>bottom</code> constraints.</li>
+ *
+ *    <li>The element is set to its preferred width and/or height.</li>
+ *  </ul>
+ * 
+ *  <p>The element's position is determined according to the rules in the following
+ *  order of precedence:</p>
+ *  <ul>
+ *    <li>If element's baseline is specified, then the element is positioned in
+ *    the vertical direction such that its <code>baselinePosition</code> (usually the base line
+ *    of its first line of text) is aligned with <code>baseline</code> constraint.</li>
+ *
+ *    <li>If element's <code>top</code> or <code>left</code> constraints
+ *    are specified, then the element is
+ *    positioned such that the top-left corner of the element's layout bounds is
+ *    offset from the top-left corner of the container by the specified values.</li>
+ *
+ *    <li>If element's <code>bottom</code> or <code>right</code> constraints are specified,
+ *    then the element is positioned such that the bottom-right corner 
+ *    of the element's layout bounds is
+ *    offset from the bottom-right corner of the container by the specified values.</li>
+ * 
+ *    <li>When no constraints determine the position in the horizontal or vertical
+ *    direction, the element is positioned according to its x and y coordinates.</li>
+ *  </ul>
+ *
+ *  <p>The content size of the container is calculated as the maximum of the
+ *  coordinates of the bottom-right corner of all the layout elements and 
+ *  constraint regions.</p>
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 1.5
+ *  @productversion Flex 4.5
+ */
+public class ConstraintLayout extends LayoutBase
+{
+
+    //See FLEX-33311 for more details on why this is used
+    private var constraintCacheNeeded:int = 0;
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     * 
+     *  @return true if the constraints determine the element's width;
+     */
+    private static function constraintsDetermineWidth(elementInfo:ElementConstraintInfo):Boolean
+    {
+        return !isNaN(elementInfo.left) && !isNaN(elementInfo.right);
+    }
+    
+    /**
+     *  @private
+     * 
+     *  @return true if the constraints determine the element's height;
+     */
+    private static function constraintsDetermineHeight(elementInfo:ElementConstraintInfo):Boolean
+    {
+        return !isNaN(elementInfo.top) && !isNaN(elementInfo.bottom);
+    }
+    
+    /**
+     *  @private
+     *  @return Returns the maximum value for an element's dimension so that the component doesn't
+     *  spill out of the container size. Calculations are based on the layout rules.
+     *  Pass in unscaledWidth, left, right, childX to get a maxWidth value.
+     *  Pass in unscaledHeight, top, bottom, childY to get a maxHeight value.
+     */
+    private static function maxSizeToFitIn(totalSize:Number,
+                                           lowConstraint:Number,
+                                           highConstraint:Number,
+                                           position:Number):Number
+    {
+        if (!isNaN(lowConstraint))
+        {
+            // childWidth + left <= totalSize
+            return totalSize - lowConstraint;
+        }
+        else if (!isNaN(highConstraint))
+        {
+            // childWidth + right <= totalSize
+            return totalSize - highConstraint;
+        }
+        else
+        {
+            // childWidth + childX <= totalSize
+            return totalSize - position;
+        }
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  Constructor.
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 1.5
+     *  @productversion Flex 4.5
+     */
+    public function ConstraintLayout()
+    {
+        super();
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Variables
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     *  Vectors that keep track of children spanning
+     *  content size columns or rows or whether the 
+     *  elements don't use columns or rows at all.
+     */
+    private var colSpanElements:Vector.<ElementConstraintInfo> = null;
+    private var rowSpanElements:Vector.<ElementConstraintInfo> = null;
+    private var otherElements:Vector.<ElementConstraintInfo> = null;
+    
+    /**
+     *  @private
+     *  Vectors to store the baseline property of the rows, and
+     *  the maximum ascent of the elements in each row.
+     *  
+     *  In rowBaselines, the value is stored as
+     *  [value, maxAscent] if the baseline is maxAscent:value, 
+     *  and [value, null] if the baseline is just a value.
+     */
+    private var rowBaselines:Vector.<Array> = null;
+    private var rowMaxAscents:Vector.<Number> = null;
+    
+    /**
+     *  @private
+     *  Hashtable that maps elements to their constraint
+     *  information. The mapping has type:
+     *  ILayoutElement -> ElementConstraintInfo
+     * 
+     *  This cache is always discarded after measure() or
+     *  updateDisplayList() because the constraints may have changed.
+     */
+    COMPILE::JS
+    private var constraintCache:Object = null;
+    COMPILE::SWF
+    private var constraintCache:Dictionary = null;
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+    
+    //----------------------------------
+    //  constraintColumns
+    //----------------------------------
+    
+    private var _constraintColumns:Vector.<ConstraintColumn> = new Vector.<ConstraintColumn>(0, true);
+    // An associative array of column id --> column index
+    private var columnsObject:Object = {};
+    
+    /**
+     *  A Vector of ConstraintColumn instances that partition the target container.
+     *  The ConstraintColumn instance at index 0 is the left-most column;
+     *  indices increase from left to right. 
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 1.5
+     *  @productversion Flex 4.5
+     */
+    public function get constraintColumns():Vector.<ConstraintColumn>
+    {
+        // make defensive copy
+        return _constraintColumns.slice();
+    }
+    
+    /**
+     *  @private
+     */
+    public function set constraintColumns(value:Vector.<ConstraintColumn>):void
+    {   
+        // clear constraintColumns
+        if (value == null)
+        {
+            _constraintColumns = new Vector.<ConstraintColumn>(0, true);
+            columnsObject = {};
+            return;
+        }
+        
+        var n:int = value.length;
+        var col:ConstraintColumn;
+        var temp:Vector.<ConstraintColumn> = value.slice();
+        var obj:Object = {};
+        
+        for (var i:int = 0; i < n; i++)
+        {
+            col = temp[i];
+            col.container = this.target;
+            obj[col.id] = i;
+        }
+        
+        _constraintColumns = temp;
+        columnsObject = obj;
+        
+        if (target)
+        {
+            target.invalidateSize();
+            target.invalidateDisplayList();
+        }
+    }
+    
+    //----------------------------------
+    //  constraintRows
+    //----------------------------------
+    
+    private var _constraintRows:Vector.<ConstraintRow> = new Vector.<ConstraintRow>(0, true);
+    // An associative array of row id --> row index
+    private var rowsObject:Object = {};
+    
+    /**
+     *  A Vector of ConstraintRow instances that partition the target container.
+     *  The ConstraintRow instance at index 0 is the top-most column;
+     *  indices increase from top to bottom. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 1.5
+     *  @productversion Flex 4.5
+     */
+    public function get constraintRows():Vector.<ConstraintRow> 
+    {
+        return _constraintRows.slice();
+    }
+    
+    /**
+     *  @private
+     */
+    public function set constraintRows(value:Vector.<ConstraintRow>):void
+    {
+        // clear constraintRows
+        if (value == null)
+        {
+            _constraintRows = new Vector.<ConstraintRow>(0, true);
+            rowsObject = {};
+            return;
+        }
+        
+        var n:int = value.length;
+        var row:ConstraintRow;
+        var temp:Vector.<ConstraintRow> = value.slice();
+        var obj:Object = {};
+        rowBaselines = new Vector.<Array>();
+        
+        for (var i:int = 0; i < n; i++)
+        {
+            row = temp[i];
+            row.container = this.target;
+            obj[row.id] = i;
+            rowBaselines[i] = LayoutElementHelper.parseConstraintExp(row.baseline);
+            
+            var maxAscentStr:String = rowBaselines[i][1];
+            if (maxAscentStr && maxAscentStr != "maxAscent")
+                throw new Error(ResourceManager.getInstance().getString("layout", "invalidBaselineOnRow",
+                                                                        [ row.id, row.baseline ]));
+        }
+        
+        _constraintRows = temp;
+        rowsObject = obj;
+        
+        if (target)
+        {
+            target.invalidateSize();
+            target.invalidateDisplayList();
+        }
+    }
+    
+    /**
+     *  @private
+     *  Resets the target on the constraintColumns and constraintRows.
+     */
+    override public function set target(value:GroupBase):void
+    {
+        super.target = value;
+        
+        // setting a new target means we need to reset the targets of
+        // our columns and rows
+        var i:int;
+        var n:int = _constraintColumns.length;
+
+        for (i = 0; i < n; i++)
+        {
+            _constraintColumns[i].container = value;
+        }
+        
+        n = _constraintRows.length;
+        for (i = 0; i < n; i++)
+        {
+            _constraintRows[i].container = value;
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden Methods: LayoutBase
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     * 
+     *  1) Parse each element constraint and populate the constraintCache
+     *  2) Measure the columns and rows based on only the elements that use them
+     *     and get the sum of the column widths and row heights.
+     *  3) Measure the size of this container based on elements that don't use
+     *     either columns or rows or both.
+     *  4) Take the max of 2 and 3 to find the measuredWidth.
+     */
+    override public function measure():void
+    {
+        checkUseVirtualLayout();
+        super.measure();
+        
+        var layoutTarget:GroupBase = target;
+        if (!layoutTarget)
+            return;
+
+        var width:Number = 0;
+        var height:Number = 0;
+        var minWidth:Number = 0;
+        var minHeight:Number = 0;
+        
+        parseConstraints();
+        
+        // Find preferred column widths and row heights.
+        var colWidths:Vector.<Number> = measureColumns();
+        var rowHeights:Vector.<Number> = measureRows();
+        var n:Number;
+        
+        for each (n in colWidths)
+        {
+            width += n;
+        }
+
+        for each (n in rowHeights)
+        {
+            height += n;
+        }
+        
+        // Find minimum measured width/height by passing in 0 for the constrained size.
+        // This means that percent size regions will be set to their min size.
+        constrainPercentRegionSizes(colWidths, 0, true);
+        for each (n in colWidths)
+        {
+            minWidth += n;
+        }
+        
+        constrainPercentRegionSizes(rowHeights, 0, false);
+        for each (n in rowHeights)
+        {
+            minHeight += n;
+        }
+        
+        if (otherElements)
+        {
+            var vec:Vector.<Number> = measureOtherContent();
+            
+            width = Math.max(width, vec[0]);
+            height = Math.max(height, vec[1]);
+            minWidth = Math.max(minWidth, vec[2]);
+            minHeight = Math.max(minHeight, vec[3]);
+        }
+
+        layoutTarget.measuredWidth = Math.ceil(width);
+        layoutTarget.measuredHeight = Math.ceil(height);
+        layoutTarget.measuredMinWidth = Math.ceil(minWidth);
+        layoutTarget.measuredMinHeight = Math.ceil(minHeight);
+        
+        // clear out cache
+        clearConstraintCache();
+    }
+    
+    /**
+     *  @private
+     * 
+     *  1) Re-parse element constraints because they may have changed.
+     *  2) Resize and reposition the columns and rows based on new constraints.
+     *  3) Size and position the elements in the available space.
+     */
+    override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+        checkUseVirtualLayout();
+        super.updateDisplayList(unscaledWidth, unscaledHeight);
+        
+        var layoutTarget:GroupBase = target;
+        if (!layoutTarget)
+            return;
+        
+        // Need to measure in case of explicit width and height on target.
+        // Also need to reparse constraints in case of something changing.
+        measureAndPositionColumnsAndRows(unscaledWidth, unscaledHeight);
+        
+        layoutContent(unscaledWidth, unscaledHeight);
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Methods: Used by FormItemLayout
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  Lays out the elements of the layout target using the current
+     *  widths and heights of the columns and rows. Used by FormItemLayout
+     *  after setting new column widths to lay elements using those new widths.
+     *
+     *  @param unscaledWidth Specifies the width of the component, in pixels,
+     *  in the component's coordinates, regardless of the value of the
+     *  <code>scaleX</code> property of the component.
+     *
+     *  @param unscaledHeight Specifies the height of the component, in pixels,
+     *  in the component's coordinates, regardless of the value of the
+     *  <code>scaleY</code> property of the component.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 1.5
+     *  @productversion Flex 4.5
+     */ 
+    protected function layoutContent(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+        var layoutTarget:GroupBase = target;
+        if (!layoutTarget)
+            return;
+        
+        var count:int = layoutTarget.numElements;
+        var layoutElement:ILayoutElement;
+        
+        var maxX:Number = 0;
+        var maxY:Number = 0;
+        
+        // update children
+        for (var i:int = 0; i < count; i++)
+        {
+            layoutElement = layoutTarget.getElementAt(i) as ILayoutElement;
+            if (!layoutElement || !layoutElement.includeInLayout)
+                continue;
+            
+            applyConstraintsToElement(unscaledWidth, unscaledHeight, layoutElement);
+            
+            // update content limits
+            maxX = Math.max(maxX, layoutElement.getLayoutBoundsX() +
+                            layoutElement.getLayoutBoundsWidth());
+            maxY = Math.max(maxY, layoutElement.getLayoutBoundsY() +
+                            layoutElement.getLayoutBoundsHeight());
+        }
+        
+        // Make sure that if the content spans partially over a pixel to the right/bottom,
+        // the content size includes the whole pixel.
+        layoutTarget.setContentSize(Math.ceil(maxX), Math.ceil(maxY));
+        
+        // clear out cache
+        clearConstraintCache();
+    }
+    
+    /**
+     *  Used by FormItemLayout to measure and set new column widths
+     *  and row heights before laying out the elements.
+     *  
+     *  @param constrainedWidth The total width available for columns to stretch
+     *  or shrink their percent width columns. If NaN, percent width columns
+     *  are unconstrained and fit to their content.
+     *  @param constrainedHeight The total height available for rows to stretch
+     *  or shrink their percent height rows. If NaN, percent height rows
+     *  are unconstrained and fit to their content.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 1.5
+     *  @productversion Flex 4.5
+     */
+    protected function measureAndPositionColumnsAndRows(constrainedWidth:Number = NaN, constrainedHeight:Number = NaN):void
+    {
+        parseConstraints();
+        setColumnWidths(measureColumns(constrainedWidth));
+        setRowHeights(measureRows(constrainedHeight));
+    }
+    
+    /**
+     *  @private
+     *  This function is mx_internal so that FormItemLayout can use it
+     *  in its updateDisplayList.
+     */
+    mx_internal function checkUseVirtualLayout():void
+    {
+        if (useVirtualLayout)
+            throw new Error(ResourceManager.getInstance().getString("layout", "constraintLayoutNotVirtualized"));
+    }
+    
+    /**
+     *  @private
+     */
+    override mx_internal function get virtualLayoutSupported():Boolean
+    {
+        return false;
+    }
+    
+    /**
+     *  @private
+     *  Used to set new column widths before laying out the elements.
+     *  Used by FormItemLayout to set column widths provided by the
+     *  Form.
+     */ 
+    mx_internal function setColumnWidths(value:Vector.<Number>):void
+    {
+        if (value == null)
+            return;
+        
+        var constraintColumns:Vector.<ConstraintColumn> = this._constraintColumns;
+        var numCols:int = constraintColumns.length;
+        var totalWidth:Number = 0;
+        
+        for (var i:int = 0; i < numCols; i++)
+        {
+            constraintColumns[i].setActualWidth(value[i]);
+            constraintColumns[i].x = totalWidth;
+            totalWidth += value[i];
+        }
+    }
+    
+    /**
+     *  @private
+     *  Used to set new row heights before laying out the elements.
+     */ 
+    mx_internal function setRowHeights(value:Vector.<Number>):void
+    {
+        if (value == null)
+            return;
+        
+        var constraintRows:Vector.<ConstraintRow> = this._constraintRows;
+        var numRows:int = constraintRows.length;
+        var totalHeight:Number = 0;
+        
+        for (var i:int = 0; i < numRows; i++)
+        {
+            constraintRows[i].setActualHeight(value[i]);
+            constraintRows[i].y = totalHeight;
+            totalHeight += value[i];
+        }
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------
+
+    private var constraintElementId:int = 0;
+    
+    /**
+     *  @private
+     *  Sizes and positions the element based on the given size of the container
+     *  and the element's constraints.
+     * 
+     *  1) Retrieves element constraints from the constraint cache.
+     *  2) Determines the x and y boundaries of each side.
+     *  3) Sizes the element based on constraints and its preferred
+     *     size. The precedence for sizing is as follows: percent, 
+     *     top and bottom constraints, preferred size.
+     *  4) Positions the element based on its constraints. The precedence
+     *     for positioning is as follows: baseline, left and top, right and bottom,
+     *     x and y.  
+     */
+    private function applyConstraintsToElement(unscaledWidth:Number,
+                                               unscaledHeight:Number,
+                                               layoutElement:ILayoutElement):void
+    {
+        COMPILE::JS
+        {                
+        if (layoutElement['constraintElementId'] == null)
+            layoutElement['constraintElementId'] = constraintElementId.toString();
+        var elementInfo:ElementConstraintInfo = constraintCache[layoutElement['constraintElementId']];
+        }
+        COMPILE::SWF
+        {
+        var elementInfo:ElementConstraintInfo = constraintCache[layoutElement];
+        }
+        
+        var left:Number = elementInfo.left;
+        var right:Number = elementInfo.right;
+        var top:Number = elementInfo.top;
+        var bottom:Number = elementInfo.bottom;
+        var baseline:Number = elementInfo.baseline;
+        
+        var leftBoundary:String = elementInfo.leftBoundary;
+        var rightBoundary:String = elementInfo.rightBoundary;
+        var topBoundary:String = elementInfo.topBoundary;
+        var bottomBoundary:String = elementInfo.bottomBoundary;
+        var baselineBoundary:String = elementInfo.baselineBoundary;
+        
+        var percentWidth:Number = layoutElement.percentWidth;
+        var percentHeight:Number = layoutElement.percentHeight;
+        
+        var availableWidth:Number;
+        var availableHeight:Number;
+        
+        var elementWidth:Number = NaN;
+        var elementHeight:Number = NaN;
+        var elementMaxWidth:Number = NaN;
+        var elementMaxHeight:Number = NaN;
+        var elementX:Number = 0;
+        var elementY:Number = 0;
+        
+        var leftHolder:Number = 0;
+        var rightHolder:Number = unscaledWidth;
+        var topHolder:Number = 0;
+        var bottomHolder:Number = unscaledHeight;
+        var baselineHolder:Number = 0;
+        
+        var i:Number;
+        
+        var col:ConstraintColumn;
+        var row:ConstraintRow;
+        
+        if (leftBoundary)
+        {
+            col = _constraintColumns[elementInfo.colSpanLeftIndex];
+            leftHolder = col.x;
+        }
+        
+        if (rightBoundary)
+        {
+            col = _constraintColumns[elementInfo.colSpanRightIndex];
+            rightHolder = col.x + col.width;
+        }
+        
+        if (topBoundary)
+        {
+            row = _constraintRows[elementInfo.rowSpanTopIndex];
+            topHolder = row.y;
+        }
+        
+        if (bottomBoundary)
+        {
+            row = _constraintRows[elementInfo.rowSpanBottomIndex];
+            bottomHolder = row.y + row.height;
+        }
+        
+        if (baselineBoundary)
+        {
+            var baselineIndex:Number = elementInfo.baselineIndex;
+            var rowBaseline:Array = rowBaselines[baselineIndex];
+            row = _constraintRows[baselineIndex];
+            
+            // add baseline offset from row.
+            baselineHolder = row.y + Number(rowBaseline[0]);
+            
+            // add maxAscent. maxAscent defaults to 0 if not specified.
+            if (rowMaxAscents)
+                baselineHolder += rowMaxAscents[baselineIndex];
+            
+            // If bottom doesn't exist, then the bottom should be restricted to the
+            // baseline row.
+            if (isNaN(bottom))
+                bottomHolder = row.y + row.height;
+        }
+        
+        // available width
+        availableWidth = Math.round(rightHolder - leftHolder);
+        
+        // cases are baseline with top and bottom, 
+        // baseline with top, baseline with bottom, no baseline
+        if (!isNaN(baseline) && (isNaN(top) || isNaN(bottom)))
+            availableHeight = Math.round(bottomHolder - baselineHolder);
+        else
+            availableHeight = Math.round(bottomHolder - topHolder);
+        
+        // set width
+        if (!isNaN(percentWidth))
+        {
+            if (!isNaN(left))
+                availableWidth -= left;
+            if (!isNaN(right))
+                availableWidth -= right;
+            
+            elementWidth = Math.round(availableWidth * Math.min(percentWidth * 0.01, 1));
+            elementMaxWidth = Math.min(layoutElement.getMaxBoundsWidth(),
+                maxSizeToFitIn(unscaledWidth, left, right, layoutElement.getLayoutBoundsX()));
+        }
+        else if (!isNaN(left) && !isNaN(right))
+        {
+            elementWidth = availableWidth - left - right;
+        }
+        
+        // set height
+        if (!isNaN(percentHeight))
+        {
+            if (!isNaN(top))
+                availableHeight -= top;
+            if (!isNaN(bottom))
+                availableHeight -= bottom;    
+            
+            elementHeight = Math.round(availableHeight * Math.min(percentHeight * 0.01, 1));
+            elementMaxHeight = Math.min(layoutElement.getMaxBoundsHeight(),
+                maxSizeToFitIn(unscaledHeight, top, bottom, layoutElement.getLayoutBoundsY()));
+        }
+        else if (!isNaN(top) && !isNaN(bottom))
+        {
+            elementHeight = availableHeight - top - bottom;
+        }
+        
+        // Apply min and max constraints, make sure min is applied last. In the cases
+        // where elementWidth and elementHeight are NaN, setLayoutBoundsSize will use preferredSize
+        // which is already constrained between min and max.
+        if (!isNaN(elementWidth))
+        {
+            if (isNaN(elementMaxWidth))
+                elementMaxWidth = layoutElement.getMaxBoundsWidth();
+            elementWidth = Math.max(layoutElement.getMinBoundsWidth(), Math.min(elementMaxWidth, elementWidth));
+        }
+        
+        if (!isNaN(elementHeight))
+        {
+            if (isNaN(elementMaxHeight))
+                elementMaxHeight = layoutElement.getMaxBoundsHeight();
+            elementHeight = Math.max(layoutElement.getMinBoundsHeight(), Math.min(elementMaxHeight, elementHeight));
+        }
+        
+        layoutElement.setLayoutBoundsSize(elementWidth, elementHeight);
+        // update temp variables
+        elementWidth = layoutElement.getLayoutBoundsWidth();
+        elementHeight = layoutElement.getLayoutBoundsHeight();
+        
+        // Horizontal Position
+        if (!isNaN(left))
+            elementX = leftHolder + left;
+        else if (!isNaN(right))
+            elementX = rightHolder - right - elementWidth;
+        else
+            elementX = layoutElement.getLayoutBoundsX();
+        
+        // Vertical Position
+        if (!isNaN(baseline))
+            elementY = baselineHolder + baseline - layoutElement.baselinePosition;
+        else if (!isNaN(top))
+            elementY = topHolder + top;
+        else if (!isNaN(bottom))
+            elementY = bottomHolder - bottom - elementHeight;
+        else
+            elementY = layoutElement.getLayoutBoundsY();
+        
+        layoutElement.setLayoutBoundsPosition(elementX, elementY);
+    }
+    
+    /**
+     *  @private
+     *  Updates the widths of content size and percent size columns that are spanned
+     *  by the specified element. This method updates the provided column widths 
+     *  vector in place. The algorithm is as follows:
+     * 
+     *  1) Determine the space needed by the element to satisfy its constraints
+     *     and be at its preferred size.
+     * 
+     *  2) Calculate the number of columns the element will span.
+     * 
+     *  3) If the element causes a column to expand, update the column width to match.
+     *     a) For the single spanning case, we only need to check if this element's 
+     *        required width is larger than the column's current width.
+     *     b) For the multiple spanning case, we distribute the remaining width after 
+     *        subtracting the fixed size columns across the content/percent size columns.
+     *        Then, we only update a column's width if the new divided width would cause
+     *        the column's width to expand.
+     * 
+     *  @param elementInfo The constraint information of the element.
+     *  @param colWidths The vector of column widths to update.
+     */
+    private function updateColumnWidthsForElement(colWidths:Vector.<Number>, elementInfo:ElementConstraintInfo):void
+    {
+        var layoutElement:ILayoutElement = elementInfo.layoutElement;
+        var numCols:int = _constraintColumns.length;
+        var col:ConstraintColumn;
+        
+        var leftIndex:int = -1;
+        var rightIndex:int = -1;
+        var span:int;
+        
+        var extX:Number = 0;
+        var preferredWidth:Number = layoutElement.getPreferredBoundsWidth();
+        var maxExtent:Number;
+        var remainingWidth:Number;
+        
+        var j:int;
+        var colWidth:Number = 0;
+        
+        // 1) Determine how much space the element needs to satisfy its
+        //    constraints and be at its preferred width.
+        if (!isNaN(elementInfo.left))
+        {
+            extX += elementInfo.left;
+            if (elementInfo.leftBoundary)
+                leftIndex = elementInfo.colSpanLeftIndex;
+            else
+                leftIndex = 0; // constrained to parent
+        }
+        
+        if (!isNaN(elementInfo.right))
+        {
+            extX += elementInfo.right;
+            if (elementInfo.rightBoundary)
+                rightIndex = elementInfo.colSpanRightIndex;
+            else
+                rightIndex = numCols - 1; // constrained to parent
+        }
+        
+        maxExtent = extX + preferredWidth;
+        remainingWidth = maxExtent;
+        
+        // 2) If either the left or the right constraint doesn't exist,
+        //    we must find the span of the element. We do this by
+        //    determining the index of the last column that the element
+        //    occupies in the unconstrained direction.
+        if (leftIndex < 0 || rightIndex < 0)
+        {
+            var isLeft:Boolean = leftIndex < 0;
+            var startIndex:int = isLeft ? rightIndex : leftIndex;
+            var endIndex:int = isLeft ? -1 : numCols;
+            var increment:int = isLeft ? -1 : 1;
+            
+            if (isLeft) // defaults to 0
+                leftIndex = 0;
+            else // defaults to numCols - 1
+                rightIndex = numCols - 1;
+            
+            for (j = startIndex; j != endIndex ; j += increment)
+            {
+                col = _constraintColumns[j];
+                
+                // subtract fixed columns
+                if (!isNaN(col.explicitWidth))
+                    remainingWidth -= col.explicitWidth;
+                
+                if ((col.contentSize || !isNaN(col.percentWidth)) || remainingWidth < 0)
+                {
+                    if (isLeft)
+                        leftIndex = j;
+                    else
+                        rightIndex = j;
+                    break;
+                }
+            }
+        }
+        // always 1 or positive.
+        span = rightIndex - leftIndex + 1;
+        
+        // 3) If the element causes a column to expand, update the column width to match.
+        if (span == 1)
+        {
+            // a) For the single spanning case, we only need to check if this element's 
+            //    required width is larger than the column's current width.
+            col = _constraintColumns[leftIndex];
+            
+            if (col.contentSize || !isNaN(col.percentWidth))
+            {   
+                colWidth = Math.max(colWidths[leftIndex], extX + preferredWidth);
+                
+                if (constraintsDetermineWidth(elementInfo))
+                    colWidth = Math.max(colWidth, extX + layoutElement.getMinBoundsWidth());
+                
+                // bound with max width of column
+                if (!isNaN(col.maxWidth))
+                    colWidth = Math.min(colWidth, col.maxWidth);
+                
+                colWidths[leftIndex] = Math.ceil(colWidth);
+            }
+        }
+        else
+        {
+            // b) multiple spanning case when span >= 2.
+            //    1) start from leftIndex and subtract fixed columns.
+            //    2) divide space evenly into content/percent size columns.
+            var contentCols:Vector.<ConstraintColumn> = new Vector.<ConstraintColumn>();
+            var contentColsIndices:Vector.<int> = new Vector.<int>();
+            
+            remainingWidth = maxExtent;
+            for (j = leftIndex; j <= rightIndex; j++)
+            {
+                col = _constraintColumns[j];
+                
+                if (!isNaN(col.explicitWidth))
+                {
+                    if (remainingWidth < col.width)
+                        break;
+                    
+                    remainingWidth -= col.width;
+                }
+                else if (col.contentSize || !isNaN(col.percentWidth))
+                {
+                    contentCols.push(col);
+                    contentColsIndices.push(j);
+                }
+            }
+            
+            var numContentCols:Number = contentCols.length;
+            if (numContentCols > 0)
+            {
+                var splitWidth:Number = remainingWidth / numContentCols;
+                
+                for (j = 0; j < numContentCols; j++)
+                {
+                    col = contentCols[j];
+                    
+                    colWidth = Math.max(colWidths[contentColsIndices[j]], splitWidth);
+                    if (!isNaN(col.maxWidth))
+                        colWidth = Math.min(colWidth, col.maxWidth);
+                    
+                    colWidths[contentColsIndices[j]] = Math.ceil(colWidth);
+                }
+            }
+        }
+    }
+    
+    /**
+     *  Adjusts the sizes of percent size columns or rows to fill the constrainedSize.
+     *  This method updates the provided column widths or row heights vector in place.
+     *  
+     *  The term, "region", refers to a column or row.
+     *  The percent size region sizes are first reset to their minimum size. 
+     *  If the given region sizes from the content and fixed size regions already
+     *  fill the available space, then the percent size region sizes stay at their
+     *  minimum size. Otherwise, the remaining space is distributed to the percent 
+     *  size regions based on the ratio of its percent size to the sum of all the 
+     *  percent sizes.
+     */
+    private function constrainPercentRegionSizes(sizes:Vector.<Number>, constrainedSize:Number, isColumns:Boolean):void
+    {
+        var col:ConstraintColumn;
+        var row:ConstraintRow;
+        var numSizes:int = isColumns ? _constraintColumns.length : _constraintRows.length;
+        
+        var childInfoArray:Array /* of ConstraintRegionFlexChildInfo */ = [];
+        var childInfo:ConstraintRegionFlexChildInfo;
+        var remainingSpace:Number = constrainedSize;
+        var percentMinSizes:Number = 0;
+        var totalPercent:Number = 0;
+        
+        // Set percent size regions back to minSize and
+        // find the remaining space.
+        for (var i:int = 0; i < numSizes; i++)
+        {
+            var percentSize:Number;
+            var minSize:Number;
+            var maxSize:Number;
+            
+            if (isColumns)
+            {
+                col = _constraintColumns[i];
+                percentSize = col.percentWidth;
+                minSize = col.minWidth;
+                maxSize = col.maxWidth;
+            }
+            else
+            {
+                row = _constraintRows[i];
+                percentSize = row.percentHeight;
+                minSize = row.minHeight;
+                maxSize = row.maxHeight;
+            }
+
+            if (!isNaN(percentSize))
+            {
+                sizes[i] = (!isNaN(minSize)) ? Math.ceil(Math.max(minSize, 0)) : 0;
+                percentMinSizes += sizes[i];
+                totalPercent += percentSize;
+                
+                // Fill childInfoArray for distributing the width.
+                childInfo = new ConstraintRegionFlexChildInfo();
+                childInfo.index = i;
+                childInfo.percent = percentSize;
+                childInfo.min = minSize;
+                childInfo.max = maxSize;
+                childInfoArray.push(childInfo);
+            }
+            else
+            {
+                remainingSpace -= sizes[i];
+            }
+        }
+        
+        // If there's space remaining, distribute the width to the percent size
+        // columns based on their ratio of percentWidth to sum of all the percentWidths.
+        if (remainingSpace > percentMinSizes)
+        {            
+            Flex.flexChildrenProportionally(constrainedSize, 
+                                            remainingSpace,
+                                            totalPercent,
+                                            childInfoArray);
+            
+            var roundOff:Number = 0;
+            for each (childInfo in childInfoArray)
+            {
+                // Make sure the calculated widths are rounded to pixel boundaries
+                var size:Number = Math.round(childInfo.size + roundOff);
+                roundOff += childInfo.size - size;
+                
+                sizes[childInfo.index] = size;
+                
+                // remainingSpace -= size;
+            }
+            // TODO (klin): What do we do if there's remainingSpace after all this?
+        }
+    }
+    
+    /** 
+     *  @private
+     *  This function measures the ConstraintColumns partitioning
+     *  the target and returns their new widths. The calculations
+     *  are based on the current constraintCache and other derived
+     *  data structures. To update the constraintCache, one needs to
+     *  call the parseConstraints() method.
+     *  
+     *  The widths are measured with the following requirements:
+     *  1. Fixed size columns honor their pixel values.
+     *  
+     *  2. Content size columns whose children only span that column
+     *     assumes the width of the widest child.
+     *  
+     *  3. Content size columns whose children span more than one column
+     *     assumes the widest width possible when the child's size is divided
+     *     among the spanned columns.
+     *     a. Each child divides its preferred width among the content size
+     *        columns that it spans. A child also always honors fixed size
+     *        columns that it spans.
+     *     b. The column takes the widest width given by its children.
+     *  
+     *  4. Percent size columns measure exactly like content size columns
+     *     at first, but after measurement, if availableWidth is provided,
+     *     the percent size columns are remeasured to allow the columns to
+     *     fit exactly in the remaining width in accordance with their given
+     *     percentage.
+     *     a. The percentages given are treated as ratios for how the width
+     *        should be divided among the percent size columns.
+     *     b. If no remaining space is available or the measured size of all
+     *        the content and fixed size columns are greater than the 
+     *        constrainedWidth, percent size columns are set to their minimum.
+     *  
+     *  5. Columns always honor their max and min widths.
+     *  
+     *  6. If constrainedWidth is not specified, sum the column widths to find
+     *     the total measured width of the target.
+     * 
+     *  @param constrainedWidth The constraining width to be used when measuring
+     *  percent size columns. The default is NaN.
+     *  
+     *  @return A vector of the new column widths.
+     */
+    mx_internal function measureColumns(constrainedWidth:Number = NaN):Vector.<Number>
+    {
+        // TODO (klin): Parameterize this to work for both columns and rows.
+        // This may mean we need to add some mx_internal properties to 
+        // the columns for "major size", etc... Question is, what about
+        // 1-D properties like baseline? What parts can we parameterize and
+        // what parts aren't possible.
+        
+        // Parse constraints if it hasn't been done yet, make sure to clear 
+        // the cache afterwards.
+        var clearCache:Boolean = false;
+        if (!constraintCache)
+        {
+            parseConstraints();
+            clearCache = true;
+        }
+        
+        if (_constraintColumns.length <= 0)
+            return new Vector.<Number>();
+        
+        var measuredWidth:Number = 0;
+        var i:Number;
+        var numCols:Number = _constraintColumns.length;
+        var col:ConstraintColumn;
+        var hasContentSize:Boolean = false;
+        var hasPercentSize:Boolean = false;
+        var colWidths:Vector.<Number> = new Vector.<Number>(numCols);
+        
+        // Start column widths at the minWidth of each column or
+        // its explicit width.
+        for (i = 0; i < numCols; i++)
+        {
+            col = _constraintColumns[i];
+            
+            if (col.contentSize || !isNaN(col.percentWidth))
+            {
+                hasContentSize ||= col.contentSize;
+                hasPercentSize ||= !isNaN(col.percentWidth);
+                
+                if (!isNaN(col.minWidth))
+                    colWidths[i] = Math.ceil(Math.max(col.minWidth, 0));
+                else
+                    colWidths[i] = 0;
+            }
+            else if (!isNaN(col.explicitWidth))
+            {
+                var w:Number = col.explicitWidth;
+                
+                if (!isNaN(col.minWidth))
+                    w = Math.max(w, col.minWidth);
+                
+                if (!isNaN(col.maxWidth))
+                    w = Math.min(w, col.maxWidth);
+                
+                colWidths[i] = Math.ceil(w);
+            }
+        }
+        
+        // Assumption: elements in colSpanElements have one or more constraints touching a column.
+        // This is enforced in parseElementConstraints().
+        if (colSpanElements && (hasContentSize || hasPercentSize))
+        {
+            // Measure content/percent size columns.
+            for each (var elementInfo:ElementConstraintInfo in colSpanElements)
+            {
+                updateColumnWidthsForElement(colWidths, elementInfo);
+            }
+        }
+        
+        // Adjust percent size columns to account for constraining width.
+        if (!isNaN(constrainedWidth) && hasPercentSize)
+        {
+            constrainPercentRegionSizes(colWidths, constrainedWidth, true);
+        }
+        
+        // Clear the cache only if we created it just for this method call.
+        if (clearCache)
+            clearConstraintCache();
+        
+        return colWidths;
+    }
+    
+    /**
+     *  @private
+     *  Updates the heights of content size and percent size rows that are spanned
+     *  by the specified element. This method updates the provided row heights 
+     *  vector in place. The algorithm is as follows:
+     * 
+     *  1) Determine the space needed by the element to satisfy its constraints
+     *     and be at its preferred size.
+     * 
+     *  2) Calculate the number of rows the element will span.
+     * 
+     *  3) If the element causes a row to expand, update the row height to match.
+     *     a) For the single spanning case, we only need to check if this element's 
+     *        required height is larger than the row's current height.
+     *     b) For the multiple spanning case, we distribute the remaining height after 
+     *        subtracting the fixed size rows across the content/percent size rows.
+     *        Then, we only update a row's height if the new divided height would cause
+     *        the row's height to expand.
+     * 
+     *  @param elementInfo The constraint information of the element.
+     *  @param colWidths The vector of column widths to update.
+     */
+    private function updateRowHeightsForElement(rowHeights:Vector.<Number>, elementInfo:ElementConstraintInfo):void
+    {
+        var layoutElement:ILayoutElement = elementInfo.layoutElement;
+        var numRows:int = _constraintRows.length;
+        var row:ConstraintRow;
+        
+        var topIndex:int = -1;
+        var bottomIndex:int = -1;
+        var span:int;
+        
+        var extY:Number = 0;
+        var preferredHeight:Number = layoutElement.getPreferredBoundsHeight();
+        var maxExtent:Number;
+        var remainingHeight:Number;
+        
+        var j:int;
+        var rowHeight:Number = 0;
+        
+        // 1) Determine how much space the element needs to satisfy its
+        //    constraints and be at its preferred height.
+        if (!isNaN(elementInfo.top))
+        {
+            extY += elementInfo.top;
+            if (elementInfo.topBoundary)
+                topIndex = elementInfo.rowSpanTopIndex;
+            else
+                topIndex = 0; // constrained to parent
+        }
+        
+        if (!isNaN(elementInfo.bottom))
+        {
+            extY += elementInfo.bottom;
+            if (elementInfo.bottomBoundary)
+                bottomIndex = elementInfo.rowSpanBottomIndex;
+            else
+                bottomIndex = numRows - 1; // constrained to parent
+        }
+        
+        // Only include baseline if at least one of top or bottom don't
+        // exist.
+        if (!isNaN(elementInfo.baseline) && (topIndex < 0 || bottomIndex < 0))
+        {
+            extY += elementInfo.baseline - layoutElement.baselinePosition;
+            
+            if (!isNaN(elementInfo.top))
+                extY -= elementInfo.top;
+            
+            if (elementInfo.baselineBoundary)
+            {
+                topIndex = elementInfo.baselineIndex;
+                
+                // add baseline offset.
+                extY += Number(rowBaselines[topIndex][0]); 
+                
+                // add maxAscent. maxAscent is 0 if not specified on the row.
+                if (rowMaxAscents)
+                    extY += rowMaxAscents[topIndex];
+            }
+            else
+            {
+                topIndex = 0;
+            }
+        }
+        
+        maxExtent = extY + preferredHeight;
+        remainingHeight = maxExtent;
+            
+        // 2) If either the top or the bottom constraint doesn't exist,
+        //    we must find the span of the element. We do this by
+        //    determining the index of the last row that the element
+        //    occupies in the unconstrained direction.
+        if (topIndex < 0 || bottomIndex < 0)
+        {
+            var isTop:Boolean = topIndex < 0;
+            var startIndex:int = isTop ? bottomIndex : topIndex;
+            var endIndex:int = isTop ? -1 : numRows;
+            var increment:int = isTop ? -1 : 1;
+            
+            if (isTop) // defaults to 0
+                topIndex = 0;
+            else // defaults to numRows - 1
+                bottomIndex = numRows - 1;
+            
+            for (j = startIndex; j != endIndex ; j += increment)
+            {
+                row = _constraintRows[j];
+                
+                // subtract fixed rows
+                if (!isNaN(row.explicitHeight))
+                    remainingHeight -= row.explicitHeight;
+                
+                if ((row.contentSize || !isNaN(row.percentHeight)) || remainingHeight < 0)
+                {
+                    if (isTop)
+                        topIndex = j;
+                    else
+                        bottomIndex = j;
+                    break;
+                }
+            }
+        }
+        // always 1 or positive.
+        span = bottomIndex - topIndex + 1;
+        
+        // 3) If the element causes a row to expand, update the row height to match.
+        if (span == 1)
+        {
+            // a) For the single spanning case, we only need to check if this element's 
+            //    required height is larger than the row's current height.
+            row = _constraintRows[topIndex];
+            
+            if (row.contentSize || !isNaN(row.percentHeight))
+            {   
+                rowHeight = Math.max(rowHeights[topIndex], extY + preferredHeight);
+                
+                if (constraintsDetermineHeight(elementInfo))
+                    rowHeight = Math.max(rowHeight, extY + layoutElement.getMinBoundsHeight());
+                
+                // bound with max height of row
+                if (!isNaN(row.maxHeight))
+                    rowHeight = Math.min(rowHeight, row.maxHeight);
+                
+                rowHeights[topIndex] = Math.ceil(rowHeight);
+            }
+        }
+        else
+        {
+            // b) multiple spanning case. span >= 2.
+            //    1) start from topIndex and subtract fixed rows
+            //    2) divide space evenly into content/percent size rows.
+            var contentRows:Vector.<ConstraintRow> = new Vector.<ConstraintRow>();
+            var contentRowsIndices:Vector.<int> = new Vector.<int>();
+            
+            remainingHeight = maxExtent;
+            for (j = topIndex; j <= bottomIndex; j++)
+            {
+                row = _constraintRows[j];
+                
+                if (!isNaN(row.explicitHeight))
+                {
+                    if (remainingHeight < row.height)
+                        break;
+                    
+                    remainingHeight -= row.height;
+                }
+                else if (row.contentSize || !isNaN(row.percentHeight))
+                {
+                    contentRows.push(row);
+                    contentRowsIndices.push(j);
+                }
+            }
+            
+            var numContentRows:Number = contentRows.length;
+            if (numContentRows > 0)
+            {
+                var splitHeight:Number = remainingHeight / numContentRows;
+                
+                for (j = 0; j < numContentRows; j++)
+                {
+                    row = contentRows[j];
+                    
+                    rowHeight = Math.max(rowHeights[contentRowsIndices[j]], splitHeight);
+                    if (!isNaN(row.maxHeight))
+                        rowHeight = Math.min(rowHeight, row.maxHeight);
+                    
+                    rowHeights[contentRowsIndices[j]] = Math.ceil(rowHeight);
+                }
+            }
+        }
+    }
+    
+    /**
+     *  @private
+     *  Synonymous to measureColumns(), but with added baseline constraint.
+     *  Baseline is only included in the measurement if at least one of the element's
+     *  top or bottom constraint doesn't exist. The calculations are based on the
+     *  current constraintCache. To update the constraintCache, one needs to call
+     *  the parseConstraints() method.
+     */
+    private function measureRows(constrainedHeight:Number = NaN):Vector.<Number>
+    {
+        if (_constraintRows.length <= 0)
+            return new Vector.<Number>();
+        
+        var measuredHeight:Number = 0;
+        var i:Number;
+        var numRows:Number = _constraintRows.length;
+        var row:ConstraintRow;
+        var hasContentSize:Boolean = false;
+        var hasPercentSize:Boolean = false;
+        var rowHeights:Vector.<Number> = new Vector.<Number>(numRows);
+        
+        // Start row heights at the minHeight of each row or
+        // its explicit height.
+        for (i = 0; i < numRows; i++)
+        {
+            row = _constraintRows[i];
+            
+            if (row.contentSize || !isNaN(row.percentHeight))
+            {
+                hasContentSize ||= row.contentSize;
+                hasPercentSize ||= !isNaN(row.percentHeight);
+                
+                if (!isNaN(row.minHeight))
+                    rowHeights[i] = Math.ceil(Math.max(row.minHeight, 0));
+                else
+                    rowHeights[i] = 0;
+            }
+            else if (!isNaN(row.explicitHeight))
+            {
+                var h:Number = row.explicitHeight;
+                
+                if (!isNaN(row.minHeight))
+                    h = Math.max(h, row.minHeight);
+                
+                if (!isNaN(row.maxHeight))
+                    h = Math.min(h, row.maxHeight);
+                
+                rowHeights[i] = Math.ceil(h);
+            }
+        }
+        
+        // Assumption: elements in rowSpanElements have one or more constraints touching a row.
+        // This is enforced in parseElementConstraints().
+        if (rowSpanElements && (hasContentSize || hasPercentSize))
+        {
+            // Measure content/percent size columns.
+            for each (var elementInfo:ElementConstraintInfo in rowSpanElements)
+            {
+                updateRowHeightsForElement(rowHeights, elementInfo);
+            }
+        }
+        
+        // Adjust percent size rows to account for constraining height.
+        if (!isNaN(constrainedHeight) && hasPercentSize)
+        {
+            constrainPercentRegionSizes(rowHeights, constrainedHeight, false);
+        }
+        
+        return rowHeights;
+    }
+    
+    /**
+     *  @private
+     *  Measures the size of target based on content not included in the columns and rows.
+     *  Basically, applies BasicLayout to other content to determine measured size.
+     *  Returns a vector with the measured [width, height, minWidth, minHeight].
+     */
+    private function measureOtherContent():Vector.<Number>
+    {
+        var width:Number = 0;
+        var height:Number = 0;
+        var minWidth:Number = 0;
+        var minHeight:Number = 0;
+        var count:int = otherElements.length;
+        
+        for (var i:int = 0; i < count; i++)
+        {
+            var elementInfo:ElementConstraintInfo = otherElements[i];
+            var layoutElement:ILayoutElement = elementInfo.layoutElement;
+            
+            // Only measure width if not constrained to columns.
+            if (!elementInfo.leftBoundary && !elementInfo.rightBoundary)
+            {
+                var left:Number = elementInfo.left;
+                var right:Number = elementInfo.right;
+                var extX:Number;
+                
+                if (!isNaN(left) && !isNaN(right))
+                {
+                    // If both left & right are set, then the extents is always
+                    // left + right so that the element is resized to its preferred
+                    // size (if it's the one that pushes out the default size of the container).
+                    extX = left + right;                
+                }
+                else if (!isNaN(left) || !isNaN(right))
+                {
+                    extX = isNaN(left) ? 0 : left;
+                    extX += isNaN(right) ? 0 : right;
+                }
+                else
+                {
+                    extX = layoutElement.getBoundsXAtSize(NaN, NaN);
+                }
+                
+                var preferredWidth:Number = layoutElement.getPreferredBoundsWidth();
+                width = Math.max(width, extX + preferredWidth);
+                
+                // Find the minimum default extents, we take the minimum height only
+                // when the element size is determined by the parent size
+                var elementMinWidth:Number =
+                    constraintsDetermineWidth(elementInfo) ? layoutElement.getMinBoundsWidth() :
+                    preferredWidth;
+                
+                minWidth = Math.max(minWidth, extX + elementMinWidth);
+            }
+            
+            // only measure height if not constrained to rows.
+            var noVerticalBoundaries:Boolean = !elementInfo.topBoundary && !elementInfo.bottomBoundary;
+            var noBaselineBoundary:Boolean = !elementInfo.baselineBoundary;
+            
+            if (noVerticalBoundaries || noBaselineBoundary)
+            {
+                var top:Number;
+                var bottom:Number;
+                var baseline:Number;
+                var extY:Number;
+                
+                if (noVerticalBoundaries)
+                {
+                    top = elementInfo.top;
+                    bottom = elementInfo.bottom;
+                }
+                
+                if (noBaselineBoundary)
+                    baseline = elementInfo.baseline;
+                
+                if (!isNaN(top) && !isNaN(bottom))
+                {
+                    // If both top & bottom are set, then the extents is always
+                    // top + bottom so that the element is resized to its preferred
+                    // size (if it's the one that pushes out the default size of the container).
+                    extY = top + bottom;                
+                }
+                else if (!isNaN(baseline))
+                {
+                    extY = Math.round(baseline - layoutElement.baselinePosition);
+                }
+                else if (!isNaN(top) || !isNaN(bottom))
+                {
+                    extY = isNaN(top) ? 0 : top;
+                    extY += isNaN(bottom) ? 0 : bottom;
+                }
+                else
+                {
+                    extY = layoutElement.getBoundsYAtSize(NaN, NaN);
+                }
+                
+                var preferredHeight:Number = layoutElement.getPreferredBoundsHeight();
+                height = Math.max(height, extY + preferredHeight);
+                
+                // Find the minimum default extents, we take the minimum height only
+                // when the element size is determined by the parent size
+                var elementMinHeight:Number =
+                    constraintsDetermineHeight(elementInfo) ? layoutElement.getMinBoundsHeight() : 
+                    preferredHeight;
+                
+                minHeight = Math.max(minHeight, extY + elementMinHeight);
+            }
+        }
+        
+        var vec:Vector.<Number> = new Vector.<Number>(4, true);
+        vec[0] = Math.max(width, minWidth);
+        vec[1] = Math.max(height, minHeight);
+        vec[2] = minWidth;
+        vec[3] = minHeight;
+        
+        return vec;
+    }
+    
+    /**
+     *  @private
+     *  Iterates over elements and calls parseElementConstraints on each.
+     */
+    private function parseConstraints():void
+    {
+        var layoutTarget:GroupBase = target;
+        if (!layoutTarget)
+            return;
+
+        constraintCacheNeeded++;
+
+        var count:Number = layoutTarget.numElements;
+        var layoutElement:ILayoutElement;
+        
+        COMPILE::SWF
+        {
+            var cache:Dictionary = new Dictionary(true);
+        }
+        COMPILE::JS
+        {
+            var cache:Object = {};
+        }
+        var i:int;
+        
+        // Populate rowBaselines with baseline information from rows.
+        var n:int = _constraintRows.length;
+        var row:ConstraintRow;
+
+        if (rowBaselines == null)
+            rowBaselines = new Vector.<Array>();
+        else
+            rowBaselines.length = 0;
+        
+        for (i = 0; i < n; i++)
+        {
+            row = _constraintRows[i];
+            rowBaselines[i] = LayoutElementHelper.parseConstraintExp(row.baseline);
+            
+            var maxAscentStr:String = rowBaselines[i][1];
+            if (maxAscentStr && maxAscentStr != "maxAscent")
+                throw new Error(ResourceManager.getInstance().getString("layout", "invalidBaselineOnRow",
+                    [ row.id, row.baseline ]));
+        }
+        
+        for (i = 0; i < count; i++)
+        {
+            layoutElement = layoutTarget.getElementAt(i) as ILayoutElement;
+            if (!layoutElement || !layoutElement.includeInLayout)
+                continue;
+            
+            parseElementConstraints(layoutElement, cache);
+        }
+        
+        this.constraintCache = cache;
+        constraintCacheNeeded--;
+    }
+    
+    /**
+     *  @private
+     *  This function parses the constraints of a single element, creates an
+     *  ElementConstraintInfo object for the element, and throws errors if the
+     *  columns or rows are not found for each constraint.
+     */
+    private function parseElementConstraints(layoutElement:ILayoutElement, constraintCache:Object /*Dictionary*/):void
+    {
+        // Variables to track the offsets
+        var left:Number;
+        var right:Number;
+        var top:Number;
+        var bottom:Number;
+        var baseline:Number;
+        
+        // Variables to track the boundaries from which
+        // the offsets are calculated from. If null, the 
+        // boundary is the parent container edge.
+        var leftBoundary:String;
+        var rightBoundary:String;
+        var topBoundary:String;
+        var bottomBoundary:String;
+        var baselineBoundary:String;
+        
+        var message:String;
+        
+        var temp:Array = LayoutElementHelper.parseConstraintExp(layoutElement.left);
+        left = temp[0];
+        leftBoundary = temp[1];
+        
+        temp = LayoutElementHelper.parseConstraintExp(layoutElement.right, temp);
+        right = temp[0];
+        rightBoundary = temp[1];
+        
+        temp = LayoutElementHelper.parseConstraintExp(layoutElement.top, temp);
+        top = temp[0];
+        topBoundary = temp[1];
+        
+        temp = LayoutElementHelper.parseConstraintExp(layoutElement.bottom, temp);
+        bottom = temp[0];
+        bottomBoundary = temp[1];
+        
+        temp = LayoutElementHelper.parseConstraintExp(layoutElement.baseline, temp);
+        baseline = temp[0];
+        baselineBoundary = temp[1];
+        
+        // save values into a Dictionary based on element name.
+        var elementInfo:ElementConstraintInfo = new ElementConstraintInfo(layoutElement,
+            left, right, top, bottom, baseline,
+            leftBoundary, rightBoundary,
+            topBoundary, bottomBoundary, baselineBoundary);
+        COMPILE::SWF
+        {
+            constraintCache[layoutElement] = elementInfo;                
+        }
+        COMPILE::JS
+        {
+            constraintCache[layoutElement['constraintElementId']] = elementInfo;                
+            
+        }
+        
+        
+        // If some pair of boundaries don't exist, we will need to measure
+        // the container size based on the element's other properties like
+        // x, y, width, height.
+        var i:Number;
+        if ((!leftBoundary && !rightBoundary) ||
+            (!topBoundary && !bottomBoundary) ||
+            !baselineBoundary)
+        {
+            if (!otherElements)
+                otherElements = new Vector.<ElementConstraintInfo>();
+            
+            otherElements.push(elementInfo);
+        }
+        
+        // match columns
+        if (leftBoundary || rightBoundary)
+        {
+            var numColumns:Number = _constraintColumns.length;
+            var colIndex:Object;
+
+            if (!colSpanElements)
+                colSpanElements = new Vector.<ElementConstraintInfo>();
+            
+            colSpanElements.push(elementInfo);
+            
+            if (leftBoundary)
+            {
+                colIndex = columnsObject[leftBoundary];
+                
+                if (colIndex != null)
+                    elementInfo.colSpanLeftIndex = int(colIndex);
+                
+                // throw error if no match.
+                if (elementInfo.colSpanLeftIndex < 0)
+                {
+                    message = ResourceManager.getInstance().getString(
+                        "layout", "columnNotFound", [ leftBoundary ]);
+                    throw new ConstraintError(message);
+                }
+            }
+            
+            // can we assume rightIndex >= leftIndex?
+            if (rightBoundary)
+            {
+                colIndex = columnsObject[rightBoundary];
+                
+                if (colIndex != null)
+                    elementInfo.colSpanRightIndex = int(colIndex);
+                
+                // throw error if no match.
+                if (elementInfo.colSpanRightIndex < 0)
+                {
+                    message = ResourceManager.getInstance().getString(
+                        "layout", "columnNotFound", [ rightBoundary ]);
+                    throw new ConstraintError(message);
+                }
+            }
+        }
+        
+        // match rows.
+        if (topBoundary || bottomBoundary || baselineBoundary)
+        {
+            var rowIndex:Object;
+            
+            if (!rowSpanElements)
+                rowSpanElements = new Vector.<ElementConstraintInfo>();
+            
+            rowSpanElements.push(elementInfo);
+            
+            if (topBoundary)
+            {
+                rowIndex = rowsObject[topBoundary];
+                
+                if (rowIndex != null)
+                    elementInfo.rowSpanTopIndex = int(rowIndex);
+                
+                // throw error if no match.
+                if (elementInfo.rowSpanTopIndex < 0)
+                {
+                    message = ResourceManager.getInstance().getString(
+                        "layout", "rowNotFound", [ topBoundary ]);
+                    throw new ConstraintError(message);
+                }
+            }
+            
+            if (bottomBoundary)
+            {
+                rowIndex = rowsObject[bottomBoundary];
+                
+                if (rowIndex != null)
+                    elementInfo.rowSpanBottomIndex = int(rowIndex);
+                
+                // throw error if no match.
+                if (elementInfo.rowSpanBottomIndex < 0)
+                {
+                    message = ResourceManager.getInstance().getString(
+                        "layout", "rowNotFound", [ bottomBoundary ]);
+                    throw new ConstraintError(message);
+                }
+            }
+            
+            if (baselineBoundary)
+            {
+                rowIndex = rowsObject[baselineBoundary];
+                
+                if (rowIndex != null)
+                    elementInfo.baselineIndex = int(rowIndex);
+                
+                // throw error if no match.
+                if (elementInfo.baselineIndex < 0)
+                {
+                    message = ResourceManager.getInstance().getString(
+                        "layout", "rowNotFound", [ baselineBoundary ]);
+                    throw new ConstraintError(message);
+                }
+                
+                // when using maxAscent, calculate maximum baselinePosition for this row.
+                var bIndex:int = elementInfo.baselineIndex;
+                var numRows:Number = _constraintRows.length;
+                
+                if (rowBaselines[bIndex][1])
+                {
+                    // maxAscents will all default to 0.
+                    if (!rowMaxAscents)
+                        rowMaxAscents = new Vector.<Number>(numRows, true);
+
+                    rowMaxAscents[bIndex] = Math.max(rowMaxAscents[bIndex], layoutElement.baselinePosition);
+                }
+            }
+        }
+    }
+    
+    /**
+     *  @private
+     */
+    private function clearConstraintCache():void
+    {
+        if(!constraintCacheNeeded)
+        {
+            colSpanElements = null;
+            rowSpanElements = null;
+            otherElements = null;
+            rowBaselines = null;
+            rowMaxAscents = null;
+            constraintCache = null;
+        }
+    }
+}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Helper class: ElementConstraintInfo
+//
+////////////////////////////////////////////////////////////////////////////////
+
+import mx.core.ILayoutElement;
+
+class ElementConstraintInfo
+{
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    public function ElementConstraintInfo(
+        layoutElement:ILayoutElement,
+        left:Number, right:Number,
+        top:Number, bottom:Number,
+        baseline:Number, leftBoundary:String = null,
+        rightBoundary:String = null,
+        topBoundary:String = null, bottomBoundary:String = null,
+        baselineBoundary:String = null,
+        colSpanLeftIndex:int = -1, colSpanRightIndex:int = -1,
+        rowSpanTopIndex:int = -1, rowSpanBottomIndex:int = -1,
+        baselineIndex:int = -1):void
+    {
+        super();
+        
+        // pointer to element
+        this.layoutElement = layoutElement;
+        
+        // offsets
+        this.left = left;
+        this.right = right;
+        this.top = top;
+        this.bottom = bottom;
+        this.baseline = baseline;
+        
+        // boundaries (ie: parent, column or row edge)
+        this.leftBoundary = leftBoundary;
+        this.rightBoundary = rightBoundary;
+        this.topBoundary = topBoundary;
+        this.bottomBoundary = bottomBoundary;
+        this.baselineBoundary = baselineBoundary;
+        
+        this.colSpanLeftIndex = colSpanLeftIndex;
+        this.colSpanRightIndex = colSpanRightIndex;
+        this.rowSpanTopIndex = rowSpanTopIndex;
+        this.rowSpanBottomIndex = rowSpanBottomIndex;
+        this.baselineIndex = baselineIndex;
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+    
+    public var layoutElement:ILayoutElement;
+    
+    public var left:Number;
+    public var right:Number;
+    public var top:Number;
+    public var bottom:Number;
+    public var baseline:Number;
+    public var leftBoundary:String;
+    public var rightBoundary:String;
+    public var topBoundary:String;
+    public var bottomBoundary:String;
+    public var baselineBoundary:String;
+    
+    public var colSpanLeftIndex:int;
+    public var colSpanRightIndex:int;
+    public var rowSpanTopIndex:int;
+    public var rowSpanBottomIndex:int;
+    public var baselineIndex:int;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Helper class: ConstraintRegionFlexChildInfo
+//
+////////////////////////////////////////////////////////////////////////////////
+
+import mx.containers.utilityClasses.FlexChildInfo;
+
+class ConstraintRegionFlexChildInfo extends FlexChildInfo
+{
+    public var index:int
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/FormItemLayout.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/FormItemLayout.as
index 58778ac..b2586d1 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/FormItemLayout.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/FormItemLayout.as
@@ -35,7 +35,7 @@ package spark.layouts
 	 *  @playerversion AIR 2.5
 	 *  @productversion Flex 4.5
 	 */ 
-	public class FormItemLayout //extends ConstraintLayout
+	public class FormItemLayout extends ConstraintLayout
 	{
 		//--------------------------------------------------------------------------
 		//
@@ -62,7 +62,7 @@ package spark.layouts
 		 *  @private
 		 *  Only resize columns and rows if setLayoutColumnWidths hasn't been called.
 		 */
-		/*override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+		override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
 		{
 			checkUseVirtualLayout();
 			
@@ -77,7 +77,7 @@ package spark.layouts
 				setColumnWidths(layoutColumnWidths);
 			
 			layoutContent(unscaledWidth, unscaledHeight);
-		}*/
+		}
 		
 		/**
 		 *  @private
@@ -85,7 +85,7 @@ package spark.layouts
 		 */
 		public function getMeasuredColumnWidths():Vector.<Number>
 		{
-			return null; //measureColumns();
+			return measureColumns();
 		}
 		
 		/**
@@ -98,7 +98,7 @@ package spark.layouts
 			// apply new measurements and position the columns again.
 			layoutColumnWidths = value;
 			
-			// setColumnWidths(layoutColumnWidths);
+			setColumnWidths(layoutColumnWidths);
 			
 			// target.invalidateDisplayList();
 		}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/FormLayout.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/FormLayout.as
index 5de74d7..5d6a474 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/FormLayout.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/FormLayout.as
@@ -369,7 +369,7 @@ package spark.layouts
 		 *  percent widths.
 		 */
 		private function constrainPercentColumnWidths(colWidths:Vector.<Number>, constrainedWidth:Number, formItems:Vector.<ILayoutElement>):void
-		{/*
+		{
 			if (formItems.length == 0)
 				return;
 			
@@ -378,7 +378,7 @@ package spark.layouts
 			const constraintColumns:Vector.<ConstraintColumn> = fiLayout.constraintColumns;
 			const numCols:int = constraintColumns.length;
 			var col:ConstraintColumn;
-			var childInfoArray:Array*/ /* of ColumnFlexChildInfo *//* = [];
+			var childInfoArray:Array /* of ColumnFlexChildInfo */ = [];
 			var childInfo:ColumnFlexChildInfo;
 			var remainingWidth:Number = constrainedWidth;
 			var percentMinWidths:Number = 0;
@@ -430,7 +430,7 @@ package spark.layouts
 					remainingWidth -= colWidth;
 				}
 				// TODO (klin): What do we do if there's remainingWidth after all this?
-			}*/
+			}
 		}
 	}
 }
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/skins/spark/FormItemSkin.mxml b/frameworks/projects/SparkRoyale/src/main/royale/spark/skins/spark/FormItemSkin.mxml
new file mode 100644
index 0000000..f562d6a
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/skins/spark/FormItemSkin.mxml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+
+<!--- The default skin class for the Spark FormItem component.  
+
+@see spark.components.FormItem
+
+@langversion 3.0
+@playerversion Flash 10
+@playerversion AIR 1.5
+@productversion Flex 4.5
+-->
+<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
+        xmlns:s="library://ns.apache.org/royale/spark" 
+        alpha.disabledStates=".5" creationComplete="init()">  
+    
+    <!-- host component -->
+    <fx:Metadata>
+        <![CDATA[ 
+        /** 
+        * @copy spark.skins.spark.ApplicationSkin#hostComponent
+        */
+        [HostComponent("spark.components.FormItem")]
+        ]]>
+    </fx:Metadata>
+    
+    <fx:Script>
+        <![CDATA[			
+			public function init():void {
+				requiredToolTip = resourceManager.getString("components","formItemRequired");
+			}
+			
+			private var _requiredToolTip:String;
+			/**
+			 *  The tooltip of the label showing when the component is required but nothing has been entered.
+			 *  Subclasses can set or override this property to customize the selected label.
+			 *  
+			 *  @langversion 3.0
+			 *  @playerversion AIR 3
+			 *  @productversion Flex 4.11
+			 */
+			[Bindable]
+			protected function get requiredToolTip():String 
+			{
+				return _requiredToolTip;
+			}
+			
+			protected function set requiredToolTip(value:String):void
+			{
+				_requiredToolTip = value;
+			}
+			
+            /**
+             *  @private
+             */
+            override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
+            {
+                // Push backgroundColor and backgroundAlpha directly.
+                // Handle undefined backgroundColor by hiding the background object.
+                if (isNaN(getStyle("backgroundColor")))
+                {
+                    background.visible = false;
+                }
+                else
+                {
+                    background.visible = true;
+                    bgFill.color = getStyle("backgroundColor");
+                    bgFill.alpha = getStyle("backgroundAlpha");
+                }
+                
+                var indicatorSource:Object;
+                if (currentState == "error" || currentState == "requiredAndError")
+                    indicatorSource = getStyle("errorIndicatorSource");
+                else if (currentState == "required" || "requiredAndDisabled")
+                    indicatorSource = getStyle("requiredIndicatorSource");
+                
+                if (indicatorSource && indicatorDisplay)
+                {
+                    indicatorDisplay.source = indicatorSource;
+                }
+                
+                super.updateDisplayList(unscaledWidth, unscaledHeight);
+            }
+            
+            /**
+             *  @private
+             */
+            override public function setCurrentState(stateName:String, playTransition:Boolean=true):void
+            {
+                super.setCurrentState(stateName, playTransition);
+                invalidateDisplayList();
+            }
+        ]]>        
+    </fx:Script>
+    
+    <s:states>
+        <s:State name="normal" />
+        <s:State name="disabled" stateGroups="disabledStates"/> 
+        <s:State name="error" stateGroups="errorStates"/>   
+        <s:State name="required" stateGroups="requiredStates"/> 
+        <s:State name="requiredAndDisabled" stateGroups="requiredStates, disabledStates"/>
+        <s:State name="requiredAndError" stateGroups="requiredStates, errorStates"/>    
+    </s:states>
+    
+    <s:layout>
+        <s:FormItemLayout>
+            <s:constraintColumns>
+                <!--- The column containing the sequence label. -->
+                <s:ConstraintColumn id="sequenceCol" />
+                <!--- The column containing the FormItem's label. -->
+                <s:ConstraintColumn id="labelCol" />
+                <!--- The column containing the FormItem's content. -->
+                <s:ConstraintColumn id="contentCol" width="100%"/>
+                <!--- The column containing the FormItem's help content. -->
+                <s:ConstraintColumn id="helpCol" maxWidth="200"/>
+            </s:constraintColumns>         
+            <s:constraintRows>
+                <!--- @private -->
+                <s:ConstraintRow id="row1" baseline="maxAscent:10" height="100%"/>
+            </s:constraintRows>  
+        </s:FormItemLayout>
+    </s:layout>
+            
+    <!--- Defines the appearance of the FormItem's background. -->
+    <s:Rect id="background" left="0" right="0" top="0" bottom="0">
+        <s:fill>
+            <!--- @private -->
+            <s:SolidColor id="bgFill" color="#FFFFFF"/>
+        </s:fill>
+    </s:Rect>
+    
+    <!--- @copy spark.components.FormItem#sequenceLabelDisplay -->
+    <s:Label id="sequenceLabelDisplay" 
+             fontWeight="bold"
+             left="sequenceCol:10" right="sequenceCol:5"
+             bottom="row1:10" baseline="row1:0"/>
+    <!--- @copy spark.components.FormItem#labelDisplay -->
+    <s:Label id="labelDisplay"
+             fontWeight="bold"
+             left="labelCol:0" right="labelCol:5" 
+             bottom="row1:10" baseline="row1:0"/>  
+    <!--- @copy spark.components.SkinnableContainer#contentGroup -->
+    <!-- Don't show the error tip on the content elements -->
+    <s:Group id="contentGroup" showErrorTip="false" showErrorSkin="true"
+             left="contentCol:0" right="contentCol:1" 
+             baseline="row1:0" bottom="row1:10">
+        <s:layout>
+            <s:VerticalLayout/>
+        </s:layout>
+    </s:Group>
+    <!-- Don't include the indicator in layout since we position it ourselves -->
+    <s:Group x="{contentGroup.x + contentGroup.contentWidth + 4}" y="{contentGroup.y}"
+             height="{Math.max(indicatorDisplay.height, contentGroup.contentHeight)}" includeInLayout="false">
+        <!--- @private -->
+        <s:Image id="indicatorDisplay" verticalCenter="0"
+                       toolTip="{requiredToolTip}" toolTip.errorStates=""
+                       includeIn="requiredStates,errorStates"/>
+    </s:Group>
+        
+    <!--- @copy spark.components.FormItem#helpContentGroup -->
+    <s:Group id="helpContentGroup" excludeFrom="errorStates"
+             fontStyle="italic" fontWeight="normal" color="0x666666"
+             left="helpCol:27" right="helpCol:10"
+             bottom="row1:10" baseline="row1:0"/>
+    <!--- @copy spark.components.FormItem#errorTextDisplay -->
+    <s:RichText id="errorTextDisplay" includeIn="errorStates"
+                fontStyle="italic" fontWeight="normal" color="0xFE0000"
+                left="helpCol:27" right="helpCol:10"
+                bottom="row1:10" baseline="row1:0" 
+                maxDisplayedLines="-1"/>    
+ </s:Skin>
\ No newline at end of file
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/skins/spark/FormSkin.mxml b/frameworks/projects/SparkRoyale/src/main/royale/spark/skins/spark/FormSkin.mxml
new file mode 100644
index 0000000..e5da8cb
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/skins/spark/FormSkin.mxml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+
+<!--- The default skin class for a Spark Form container.  
+
+This skin defines a contentGroup for the Form container with a 
+FormLayout as its layout object. The FormLayout is a VerticalLayout
+that has additional logic to align the columns of FormItems.
+
+@see spark.components.Form
+@see spark.layouts.FormLayout
+
+@langversion 3.0
+@playerversion Flash 10
+@playerversion AIR 1.5
+@productversion Flex 4.5
+-->
+<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
+        xmlns:s="library://ns.apache.org/royale/spark" 
+        alpha.disabled="0.5">
+    
+    <fx:Metadata>
+        <![CDATA[ 
+        /** 
+        * @copy spark.skins.spark.ApplicationSkin#hostComponent
+        */
+        [HostComponent("spark.components.Form")]
+        ]]>
+    </fx:Metadata> 
+    <fx:Script >
+    
+        <![CDATA[         
+            /**
+             *  @private
+             */
+            override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
+            {
+                // Push backgroundColor and backgroundAlpha directly.
+                // Handle undefined backgroundColor by hiding the background object.
+                if (isNaN(getStyle("backgroundColor")))
+                {
+                    background.visible = false;
+                }
+                else
+                {
+                    background.visible = true;
+                    bgFill.color = getStyle("backgroundColor");
+                    bgFill.alpha = getStyle("backgroundAlpha");
+                }
+                
+                super.updateDisplayList(unscaledWidth, unscaledHeight);
+            }
+        ]]>        
+    </fx:Script>
+    
+    <s:states>
+        <s:State name="normal" />
+        <s:State name="error" />
+        <s:State name="disabled" />
+    </s:states>
+    
+    <!--- Defines the appearance of the Form class's background. -->
+    <s:Rect id="background" left="0" right="0" top="0" bottom="0">
+        <s:fill>
+            <!--- @private -->
+            <s:SolidColor id="bgFill" color="#FFFFFF"/>
+        </s:fill>
+    </s:Rect>
+    <!--- @copy spark.components.SkinnableContainer#contentGroup -->
+    <!-- We set Form's showErrorTip and showErrorSkin to false, so we set them back 
+         to true for the Form's elements -->
+    <s:Group id="contentGroup" showErrorSkin="true" showErrorTip="true" 
+             left="10" right="10" top="10" bottom="10">
+        <s:layout>
+            <s:FormLayout gap="7"/>
+        </s:layout>
+    </s:Group>
+    
+    
+</s:Skin>