SVGHMI: attempt to optimize for webkit, because of really slow style recompute in svg:use : "unlink clones" (as in inkscape) but stop deep-copy when meeting a widget, and create a new clone instead. svghmi
authorEdouard Tisserant
Fri, 21 Feb 2020 16:22:44 +0100
branchsvghmi
changeset 2842 2f73f001955a
parent 2841 7c6050cde9e3
child 2843 94696b3f69fb
SVGHMI: attempt to optimize for webkit, because of really slow style recompute in svg:use : "unlink clones" (as in inkscape) but stop deep-copy when meeting a widget, and create a new clone instead.
svghmi/gen_index_xhtml.xslt
svghmi/gen_index_xhtml.ysl2
--- a/svghmi/gen_index_xhtml.xslt	Fri Feb 21 16:18:53 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Fri Feb 21 16:22:44 2020 +0100
@@ -102,8 +102,8 @@
   </xsl:template>
   <xsl:template mode="inline_svg" match="svg:svg/@width"/>
   <xsl:template mode="inline_svg" match="svg:svg/@height"/>
-  <xsl:template mode="inline_svg" match="svg:svg">
-    <xsl:copy>
+  <xsl:template xmlns="http://www.w3.org/2000/svg" mode="inline_svg" match="svg:svg">
+    <svg>
       <xsl:attribute name="preserveAspectRatio">
         <xsl:text>none</xsl:text>
       </xsl:attribute>
@@ -114,7 +114,7 @@
         <xsl:text>100vw</xsl:text>
       </xsl:attribute>
       <xsl:apply-templates mode="inline_svg" select="@* | node()"/>
-    </xsl:copy>
+    </svg>
   </xsl:template>
   <xsl:template mode="inline_svg" match="svg:svg[@viewBox!=concat('0 0 ', @width, ' ', @height)]">
     <xsl:message terminate="yes">
@@ -126,6 +126,40 @@
       <xsl:text>All units must be set to "px" in Inkscape's document properties</xsl:text>
     </xsl:message>
   </xsl:template>
+  <xsl:template xmlns="http://www.w3.org/2000/svg" mode="inline_svg" match="svg:use">
+    <g>
+      <xsl:attribute name="style">
+        <xsl:value-of select="@style"/>
+      </xsl:attribute>
+      <xsl:attribute name="transform">
+        <xsl:value-of select="@transform"/>
+      </xsl:attribute>
+      <xsl:attribute name="id">
+        <xsl:value-of select="@id"/>
+      </xsl:attribute>
+      <xsl:variable name="targetid" select="substring-after(@xlink:href,'#')"/>
+      <xsl:apply-templates mode="unlink_clone" select="//svg:*[@id = $targetid]"/>
+    </g>
+  </xsl:template>
+  <xsl:template xmlns="http://www.w3.org/2000/svg" mode="unlink_clone" match="@*">
+    <xsl:copy/>
+  </xsl:template>
+  <xsl:template xmlns="http://www.w3.org/2000/svg" mode="unlink_clone" match="svg:*">
+    <xsl:choose>
+      <xsl:when test="@id = $hmi_elements/@id">
+        <use>
+          <xsl:attribute name="xlink:href">
+            <xsl:value-of select="concat('#',@id)"/>
+          </xsl:attribute>
+        </use>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:copy>
+          <xsl:apply-templates mode="unlink_clone" select="@* | node()"/>
+        </xsl:copy>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
   <xsl:template match="/">
     <xsl:comment>
       <xsl:text>Made with SVGHMI. https://beremiz.org</xsl:text>
@@ -139,7 +173,7 @@
     <xsl:comment>
       <xsl:apply-templates mode="testtree" select="$indexed_hmitree"/>
     </xsl:comment>
-    <html xmlns="http://www.w3.org/1999/xhtml">
+    <html xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/1999/xhtml">
       <head/>
       <body style="margin:0;overflow:hidden;">
         <xsl:apply-templates mode="inline_svg" select="svg:svg"/>
@@ -333,9 +367,9 @@
       <xsl:value-of select="$desc/arg[1]/@value"/>
       <xsl:text>": {
 </xsl:text>
-      <xsl:text>        id: "</xsl:text>
+      <xsl:text>        widget: hmi_widgets["</xsl:text>
       <xsl:value-of select="@id"/>
-      <xsl:text>",
+      <xsl:text>"],
 </xsl:text>
       <xsl:text>        bbox: [</xsl:text>
       <xsl:value-of select="$p/@x"/>
@@ -824,17 +858,65 @@
 </xsl:text>
     <xsl:text>    let new_desc = page_desc[page_name];
 </xsl:text>
-    <xsl:text>    /* TODO hide / show widgets */
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    if(new_desc == undefined){
+</xsl:text>
+    <xsl:text>        return;
+</xsl:text>
+    <xsl:text>    }
 </xsl:text>
     <xsl:text>
 </xsl:text>
     <xsl:text>    /* remove subsribers of previous page if any */
 </xsl:text>
-    <xsl:text>    if(old_desc) for(let widget of old_desc.widgets){
+    <xsl:text>    if(old_desc){
+</xsl:text>
+    <xsl:text>        for(let widget of old_desc.widgets){
+</xsl:text>
+    <xsl:text>            for(let index of widget.indexes){
+</xsl:text>
+    <xsl:text>                subscribers[index].delete(widget);
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        old_desc.widget.element.style.display = "none";
+</xsl:text>
+    <xsl:text>    } else {
+</xsl:text>
+    <xsl:text>        /* initial page switch : set everybody hidden */
+</xsl:text>
+    <xsl:text>        for(let name in page_desc){
+</xsl:text>
+    <xsl:text>            if(name != new_desc){
+</xsl:text>
+    <xsl:text>                page_desc[name].widget.element.style.display = "none";
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    /* add new subsribers if any */
+</xsl:text>
+    <xsl:text>    for(let widget of new_desc.widgets){
 </xsl:text>
     <xsl:text>        for(let index of widget.indexes){
 </xsl:text>
-    <xsl:text>            subscribers[index].delete(widget);
+    <xsl:text>            subscribers[index].add(widget);
+</xsl:text>
+    <xsl:text>            /* dispatch current cache in newly opened page widgets */
+</xsl:text>
+    <xsl:text>            let cached_val = cache[index];
+</xsl:text>
+    <xsl:text>            if(cached_val != undefined)
+</xsl:text>
+    <xsl:text>                dispatch_value_to_widget(widget, index, cached_val, cached_val);
 </xsl:text>
     <xsl:text>        }
 </xsl:text>
@@ -842,31 +924,11 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
-    <xsl:text>    if(new_desc) {
-</xsl:text>
-    <xsl:text>        /* add new subsribers if any */
-</xsl:text>
-    <xsl:text>        for(let widget of new_desc.widgets){
-</xsl:text>
-    <xsl:text>            for(let index of widget.indexes){
-</xsl:text>
-    <xsl:text>                subscribers[index].add(widget);
-</xsl:text>
-    <xsl:text>                let cached_val = cache[index];
-</xsl:text>
-    <xsl:text>                if(cached_val != undefined)
-</xsl:text>
-    <xsl:text>                    dispatch_value_to_widget(widget, index, cached_val, cached_val);
-</xsl:text>
-    <xsl:text>            }
-</xsl:text>
-    <xsl:text>        }
-</xsl:text>
-    <xsl:text>        svg_root.setAttribute('viewBox',new_desc.bbox.join(" "));
-</xsl:text>
-    <xsl:text>        // TODO dispatch current cache in newly opened page
-</xsl:text>
-    <xsl:text>    }
+    <xsl:text>    new_desc.widget.element.style.display = "inline";
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    svg_root.setAttribute('viewBox',new_desc.bbox.join(" "));
 </xsl:text>
     <xsl:text>    current_page = page_name;
 </xsl:text>
--- a/svghmi/gen_index_xhtml.ysl2	Fri Feb 21 16:18:53 2020 +0100
+++ b/svghmi/gen_index_xhtml.ysl2	Fri Feb 21 16:22:44 2020 +0100
@@ -133,6 +133,43 @@
         error > All units must be set to "px" in Inkscape's document properties
     }
 
+    /* clone unlinkink until widget for better perf with webkit */
+    svgtmpl "svg:use", mode="inline_svg" 
+    {
+        g{
+            attrib "style" > «@style»
+            attrib "transform" > «@transform»
+            /* keep same id and label in case it is a widget */
+            //attrib "inkscape:label","@inkscape:label";
+            attrib "id" > «@id»
+            const "targetid","substring-after(@xlink:href,'#')";
+            apply "//svg:*[@id = $targetid]", mode="unlink_clone";
+        }
+    }
+    svgtmpl "@*", mode="unlink_clone" xsl:copy;
+    svgtmpl "svg:*", mode="unlink_clone" {
+        choose {
+            when "@id = $hmi_elements/@id" {
+                use{
+                    attrib "xlink:href" > «concat('#',@id)»
+                }
+            }
+            otherwise {
+                xsl:copy apply "@* | node()", mode="unlink_clone";
+            }
+        }
+    }
+
+    // template "svg:use/@style", mode="inline_svg"{
+    //     attrib "style" > all:initial;
+    //     //«.»
+    // }
+
+    // template "svg:*[concat('#',@id) = //svg:use/@xlink:href]/@style", mode="inline_svg"{
+    //     attrib "style" > all:unset;
+    //     //«.»
+    // }
+
     /*const "mark" > =HMI=\n*/
 
     /* copy root node and add geometry as comment for a test */