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

harbs pushed a commit to branch feature/layout-optimization
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git

commit 6461d5b1b40570c18277899c159ee2101f7d9f8f
Author: Harbs <[email protected]>
AuthorDate: Sat Mar 24 23:52:15 2018 +0300

    Major performance increase
    
    I’m seeing about a 5 *times* performance improvement with this
    (~150 ms layout now takes ~30 ms)
---
 .../royale/org/apache/royale/core/LayoutBase.as    | 51 +++++++------
 .../royale/org/apache/royale/core/LayoutManager.as | 84 ++++++++++++++++++++++
 .../main/royale/org/apache/royale/core/UIBase.as   | 35 +++++++++
 .../royale/org/apache/royale/core/UIButtonBase.as  | 31 ++++++++
 .../projects/Core/src/main/royale/CoreClasses.as   |  1 +
 .../royale/org/apache/royale/core/ILayoutChild.as  | 24 +++++++
 .../org/apache/royale/utils/measureComponent.as    | 27 +++++++
 7 files changed, 232 insertions(+), 21 deletions(-)

diff --git 
a/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/LayoutBase.as
 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/LayoutBase.as
index 97ac19a..7a4f95f 100644
--- 
a/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/LayoutBase.as
+++ 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/LayoutBase.as
@@ -30,10 +30,12 @@ package org.apache.royale.core
     import org.apache.royale.core.IUIBase;
     import org.apache.royale.core.layout.EdgeData;
     import org.apache.royale.core.layout.MarginData;
+       import org.apache.royale.core.LayoutManager;
        import org.apache.royale.core.ValuesManager;
        import org.apache.royale.events.IEventDispatcher;
        import org.apache.royale.events.Event;
     import org.apache.royale.utils.CSSUtils;
+       import org.apache.royale.utils.measureComponent;
 
     /**
      *  This class is the base class for most, if not all, layouts. 
@@ -302,6 +304,8 @@ package org.apache.royale.core
          *  @playerversion Flash 10.2
          *  @playerversion AIR 2.6
          *  @productversion Royale 0.8
+                * @royaleignorecoercion org.apache.royale.core.ILayoutParent
+                * @royaleignorecoercion org.apache.royale.core.UIBase
                 */
                public function performLayout():void
                {
@@ -309,31 +313,36 @@ package org.apache.royale.core
                        if (isLayoutRunning) return;
                        
                        isLayoutRunning = true;
-
-                       var oldWidth:Number = host.width;
-                       var oldHeight:Number = host.height;
+                       LayoutManager.addMeasurement(host);
+                       // measureComponent(host);
+                       // var oldWidth:Number = host.measuredWidth;
+                       // var oldHeight:Number = host.measuredHeight;
                        
                        var viewBead:ILayoutHost = (host as 
ILayoutParent).getLayoutHost();
                        
                        viewBead.beforeLayout();
-                       
-                       if (layout()) {
-                               viewBead.afterLayout();
-                       }
-                       
-                       isLayoutRunning = false;
-                       
-                       IEventDispatcher(host).dispatchEvent(new 
Event("layoutComplete"));
-                       
-                       // check sizes to see if layout changed the size or not
-                       // and send an event to re-layout parent of host
-                       if (host.width != oldWidth ||
-                           host.height != oldHeight)
-                       {
-                               isLayoutRunning = true;
-                               host.dispatchEvent(new Event("sizeChanged"));
-                               isLayoutRunning = false;
-                       }
+                       LayoutManager.addLayout(
+                               function ():void
+                               {
+                                       if (layout()) {
+                                               viewBead.afterLayout();
+                                       }
+                                       
+                                       isLayoutRunning = false;
+                                       
+                                       
IEventDispatcher(host).dispatchEvent(new Event("layoutComplete"));
+                                       
+                                       // check sizes to see if layout changed 
the size or not
+                                       // and send an event to re-layout 
parent of host
+                                       if (host.width != host.measuredWidth ||
+                                               host.height != 
host.measuredHeight)
+                                       {
+                                               isLayoutRunning = true;
+                                               host.dispatchEvent(new 
Event("sizeChanged"));
+                                               isLayoutRunning = false;
+                                       }
+                               }
+                       );
 
                }
 
diff --git 
a/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/LayoutManager.as
 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/LayoutManager.as
new file mode 100644
index 0000000..ce6b8ad
--- /dev/null
+++ 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/LayoutManager.as
@@ -0,0 +1,84 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 "Licens"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package org.apache.royale.core
+{
+    COMPILE::SWF
+    {
+        import flash.utils.setTimeout;
+    }
+    import org.apache.royale.utils.measureComponent;
+
+    public class LayoutManager
+    {
+        static private var layoutPending:Boolean;
+        static private var measurementPending:Boolean;
+        static private var measurements:Array = [];
+        static public function addMeasurement(component:ILayoutChild):void
+        {
+            measurements.push(component);
+            COMPILE::SWF
+            {
+                if(!measurementPending)
+                {
+                    measurementPending = true;
+                    setTimeout(executeMeasurements, 0);
+                }
+            }
+
+            COMPILE::JS
+            {
+                if(!measurementPending)
+                {
+                    measurementPending = true;
+                    requestAnimationFrame(executeMeasurements);
+                }
+            }
+        }
+        static private var pendingLayouts:Array = [];
+        static public function addLayout(callback:Function):void
+        {
+            pendingLayouts.push(callback);
+            if(!layoutPending && !measurementPending)
+            {
+                layoutPending = true;
+                setTimeout(executeLayouts, 0);
+            }
+        }
+        static private function executeMeasurements():void
+        {
+            
+            measurementPending = false;
+            while(measurements.length)
+            {
+                var component:ILayoutChild = measurements.shift();
+                measureComponent(component);
+            }
+            executeLayouts();
+        }
+        static private function executeLayouts():void
+        {
+            while(pendingLayouts.length)
+            {
+                var callback:Function  = pendingLayouts.shift();
+                callback();
+            }
+            layoutPending = false;
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/UIBase.as 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/UIBase.as
index 77ed10b..2e2c777 100644
--- a/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/UIBase.as
+++ b/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/UIBase.as
@@ -395,6 +395,8 @@ package org.apache.royale.core
         COMPILE::JS
         public function get width():Number
         {
+            if(!isNaN(_explicitWidth))
+                return _explicitWidth;
             var pixels:Number;
             var strpixels:String = element.style.width as String;
             if(strpixels == null)
@@ -487,6 +489,8 @@ package org.apache.royale.core
         COMPILE::JS
         public function get height():Number
         {
+            if(!isNaN(_explicitHeight))
+                return _explicitHeight;
             var pixels:Number;
             var strpixels:String = element.style.height as String;
             if(strpixels == null)
@@ -589,6 +593,37 @@ package org.apache.royale.core
                     dispatchEvent(new Event("widthChanged"));
             }
         }
+
+        /**
+         * @private
+         * Used by layout to prevent causing unnecessary reflows when 
measuring.
+         */
+        private var _measuredWidth:Number;
+
+               public function get measuredWidth():Number
+               {
+                       return _measuredWidth;
+               }
+
+               public function set measuredWidth(value:Number):void
+               {
+                       _measuredWidth = value;
+               }
+        /**
+         * @private
+         * Used by layout to prevent causing unnecessary reflows when 
measuring.
+         */
+        private var _measuredHeight:Number;
+
+               public function get measuredHeight():Number
+               {
+                       return _measuredHeight;
+               }
+
+               public function set measuredHeight(value:Number):void
+               {
+                       _measuredHeight = value;
+               }
         
         /**
          *  @copy org.apache.royale.core.ILayoutChild#setWidthAndHeight
diff --git 
a/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/UIButtonBase.as
 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/UIButtonBase.as
index 75c68ef..51492cf 100644
--- 
a/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/UIButtonBase.as
+++ 
b/frameworks/projects/Basic/src/main/royale/org/apache/royale/core/UIButtonBase.as
@@ -394,6 +394,37 @@ package org.apache.royale.core
                }
 
         /**
+         * @private
+         * Used by layout to prevent causing unnecessary reflows when 
measuring.
+         */
+        private var _measuredWidth:Number;
+
+               public function get measuredWidth():Number
+               {
+                       return _measuredWidth;
+               }
+
+               public function set measuredWidth(value:Number):void
+               {
+                       _measuredWidth = value;
+               }
+        /**
+         * @private
+         * Used by layout to prevent causing unnecessary reflows when 
measuring.
+         */
+        private var _measuredHeight:Number;
+
+               public function get measuredHeight():Number
+               {
+                       return _measuredHeight;
+               }
+
+               public function set measuredHeight(value:Number):void
+               {
+                       _measuredHeight = value;
+               }
+
+        /**
          *  @copy org.apache.royale.core.IUIBase#setHeight
          *  
          *  @langversion 3.0
diff --git a/frameworks/projects/Core/src/main/royale/CoreClasses.as 
b/frameworks/projects/Core/src/main/royale/CoreClasses.as
index 2ec8859..22b0c3e 100644
--- a/frameworks/projects/Core/src/main/royale/CoreClasses.as
+++ b/frameworks/projects/Core/src/main/royale/CoreClasses.as
@@ -235,6 +235,7 @@ internal class CoreClasses
        import org.apache.royale.debugging.notNull; notNull;
        import org.apache.royale.debugging.throwError; throwError;
 
+       import org.apache.royale.utils.measureComponent; measureComponent;
        import org.apache.royale.utils.loadBeadFromValuesManager; 
loadBeadFromValuesManager;
 
        import org.apache.royale.utils.array.rangeCheck; rangeCheck;
diff --git 
a/frameworks/projects/Core/src/main/royale/org/apache/royale/core/ILayoutChild.as
 
b/frameworks/projects/Core/src/main/royale/org/apache/royale/core/ILayoutChild.as
index 439190b..8d39cc4 100755
--- 
a/frameworks/projects/Core/src/main/royale/org/apache/royale/core/ILayoutChild.as
+++ 
b/frameworks/projects/Core/src/main/royale/org/apache/royale/core/ILayoutChild.as
@@ -81,6 +81,30 @@ package org.apache.royale.core
          */
         function get explicitHeight():Number;
         function set explicitHeight(value:Number):void;
+
+        /**
+         *  The measured width of this component 
+         *  This value can be cached by layouts to prevent reflow caused by 
measuring
+         *  
+         *  @langversion 3.0
+         *  @playerversion Flash 10.2
+         *  @playerversion AIR 2.6
+         *  @productversion Royale 0.9.3
+         */
+        function get measuredWidth():Number;
+        function set measuredWidth(value:Number):void;
+        
+        /**
+         *  The measured height of this component 
+         *  This value can be cached by layouts to prevent reflow caused by 
measuring
+         *  
+         *  @langversion 3.0
+         *  @playerversion Flash 10.2
+         *  @playerversion AIR 2.6
+         *  @productversion Royale 0.9.3
+         */
+        function get measuredHeight():Number;
+        function set measuredHeight(value:Number):void;
         
         /**
          * Sets the height of the component without
diff --git 
a/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/measureComponent.as
 
b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/measureComponent.as
new file mode 100644
index 0000000..3132eec
--- /dev/null
+++ 
b/frameworks/projects/Core/src/main/royale/org/apache/royale/utils/measureComponent.as
@@ -0,0 +1,27 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 "Licens"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package org.apache.royale.utils
+{
+    import org.apache.royale.core.ILayoutChild
+    public function measureComponent(component:ILayoutChild):void
+    {
+        component.measuredWidth = component.width;
+        component.measuredHeight = component.height;
+    }
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to