Browse Source

Layout Overflow Debugging: improved stability

Marcin Ziąbek 2 years ago
parent
commit
02a69ad09a

+ 3 - 0
Source/QuestPDF.Examples/ContentOverflowVisualizationExamples.cs

@@ -39,6 +39,9 @@ public class ContentOverflowVisualizationExamples
                             row.RelativeItem().Border(1).Background(Colors.Grey.Lighten3).Padding(5).Text("Will it work?").FontSize(20);
                             row.RelativeItem().Border(1).Background(Colors.Grey.Lighten3).Padding(5).Height(100).ShowEntire().Text(Placeholders.LoremIpsum()).FontSize(20);
                         });
+                        
+                        foreach (var size in Enumerable.Range(20, 20))
+                            column.Item().Width(size * 10).Height(40).Background(Colors.Grey.Lighten3);
                     });
                     
                     page.Footer().AlignCenter().Text(text =>

+ 4 - 6
Source/QuestPDF/Drawing/DocumentGenerator.cs

@@ -195,8 +195,6 @@ namespace QuestPDF.Drawing
             
             while(true)
             {
-                debuggingState?.Reset();
-                
                 var spacePlan = content.Measure(Size.Max);
 
                 if (spacePlan.Type == SpacePlanType.Wrap)
@@ -242,14 +240,14 @@ namespace QuestPDF.Drawing
             }
 
             void ApplyLayoutDebugging()
-            { 
+            {
                 content.RemoveExistingProxies();
-                
-                content.ApplyInfiniteLayoutDebugging();
+
+                content.ApplyLayoutOverflowDetection();
                 content.Measure(Size.Max);
 
                 var overflowState = content.ExtractProxyOfType<OverflowDebuggingProxy>();
-                overflowState.ApplyOverlayDebugging();
+                overflowState.ApplyLayoutOverflowVisualization();
                 
                 content.ApplyContentDirection();
                 content.InjectDependencies(pageContext, canvas);

+ 33 - 15
Source/QuestPDF/Drawing/Proxy/Helpers.cs

@@ -1,14 +1,14 @@
 using System.Linq;
+using System.Text;
 using QuestPDF.Elements;
 using QuestPDF.Helpers;
 using QuestPDF.Infrastructure;
-using QuestPDF.Previewer;
 
 namespace QuestPDF.Drawing.Proxy;
 
 internal static class Helpers
 {
-    public static void ApplyInfiniteLayoutDebugging(this Container container)
+    public static void ApplyLayoutOverflowDetection(this Container container)
     {
         container.VisitChildren(x =>
         {
@@ -16,7 +16,7 @@ internal static class Helpers
         });
     }
     
-    public static void ApplyOverlayDebugging(this TreeNode<OverflowDebuggingProxy> hierarchyRoot)
+    public static void ApplyLayoutOverflowVisualization(this TreeNode<OverflowDebuggingProxy> hierarchyRoot)
     {
         Traverse(hierarchyRoot);
         
@@ -28,35 +28,53 @@ internal static class Helpers
             if (parent.Value.SpacePlanType == SpacePlanType.FullRender)
                 return;
             
-            var hasWraps = parent.Children.Any(x => x.Value.SpacePlanType == SpacePlanType.Wrap);
-            var hasPartialRenders = parent.Children.Any(x => x.Value.SpacePlanType == SpacePlanType.PartialRender);
+            var hasInternalIssue = parent.Children.Any(x => x.Value.SpacePlanType is SpacePlanType.Wrap or SpacePlanType.PartialRender);
 
-            // TODO: using hasPartialRenders in the condition below, helps in certain cases and breaks others, investigate reasons
-            if (hasWraps || hasPartialRenders)
+            if (hasInternalIssue)
             {
                 foreach (var child in parent.Children)
                     Traverse(child);
             }
             else
             {
-                parent.Value.CreateProxy(x => new ContentOverflowDebugArea { Child = x });
+                parent.Value.CreateProxy(x => new LayoutOverflowVisualization { Child = x });
             }
         }
     }
 
-    public static void RemoveProxiesOfType<T>(this Container content) where T : ElementProxy
+    public static void RemoveExistingProxies(this Container content)
     {
         content.VisitChildren(x =>
         {
-            x.CreateProxy(y => y is T proxy ? proxy.Child : y);
+            x.CreateProxy(y => y is ElementProxy proxy ? proxy.Child : y);
         });
     }
-    
-    public static void RemoveExistingProxies(this Container content)
+
+    public static string HierarchyToString(this Element root)
     {
-        content.VisitChildren(x =>
+        var indentationCache = Enumerable.Range(0, 128).Select(x => new string(' ', x)).ToArray();
+        
+        var indentationLevel = 0;
+        var result = new StringBuilder();
+        
+        Traverse(root);
+
+        return result.ToString();
+        
+        void Traverse(Element parent)
         {
-            x.CreateProxy(y => y is ElementProxy proxy ? proxy.Child : y);
-        });
+            var elementName = (parent as DebugPointer)?.Target ?? parent.GetType().Name;
+            
+            result.AppendLine();
+            result.Append(indentationCache[indentationLevel]);
+            result.Append(elementName);
+
+            indentationLevel++;
+            
+            foreach (var child in parent.GetChildren())
+                Traverse(child);
+
+            indentationLevel--;
+        }
     }
 }

+ 4 - 6
Source/QuestPDF/Drawing/Proxy/TreeTraversal.cs

@@ -1,19 +1,17 @@
 using System.Collections.Generic;
 using System.Linq;
-using QuestPDF.Drawing.Proxy;
 using QuestPDF.Infrastructure;
 
-namespace QuestPDF.Previewer;
+namespace QuestPDF.Drawing.Proxy;
 
 internal class TreeNode<T>
 {
     public T Value { get; }
-    public ICollection<TreeNode<T>> Children { get; }
+    public ICollection<TreeNode<T>> Children { get; } = new List<TreeNode<T>>();
     
-    public TreeNode(T Value, ICollection<TreeNode<T>> Children)
+    public TreeNode(T Value)
     {
         this.Value = Value;
-        this.Children = Children;
     }
 }
 
@@ -27,7 +25,7 @@ internal static class TreeTraversal
         {
             if (element is T proxy)
             {
-                var result = new TreeNode<T>(proxy, new List<TreeNode<T>>());
+                var result = new TreeNode<T>(proxy);
                 
                 foreach (var treeNode in proxy.Child!.GetChildren().SelectMany(Traverse))
                     result.Children.Add(treeNode);

+ 6 - 6
Source/QuestPDF/Elements/ContentOverflowDebugArea.cs → Source/QuestPDF/Elements/LayoutOverflowVisualization.cs

@@ -6,7 +6,7 @@ using SkiaSharp;
 
 namespace QuestPDF.Elements;
 
-internal class ContentOverflowDebugArea : ContainerElement, IContentDirectionAware
+internal class LayoutOverflowVisualization : ContainerElement, IContentDirectionAware
 {
     private const float BorderThickness = 1.5f;
     private const float StripeThickness = 1.5f;
@@ -22,10 +22,10 @@ internal class ContentOverflowDebugArea : ContainerElement, IContentDirectionAwa
     {
         var childSize = base.Measure(availableSpace);
         
-        if (childSize.Type == SpacePlanType.Wrap)
-            return SpacePlan.FullRender(availableSpace);
-
-        return childSize;
+        if (childSize.Type == SpacePlanType.FullRender)
+            return childSize;
+        
+        return SpacePlan.FullRender(availableSpace);
     }
         
     internal override void Draw(Size availableSpace)
@@ -33,7 +33,7 @@ internal class ContentOverflowDebugArea : ContainerElement, IContentDirectionAwa
         // measure content area
         var childSize = base.Measure(availableSpace);
         
-        if (childSize.Type != SpacePlanType.Wrap)
+        if (childSize.Type == SpacePlanType.FullRender)
         {
             Child?.Draw(availableSpace);
             return;

+ 0 - 5
Source/QuestPDF/Fluent/ElementExtensions.cs

@@ -374,10 +374,5 @@ namespace QuestPDF.Fluent
         {
             return element.Element(new ScaleToFit());
         }
-        
-        internal static IContainer ContentOverflowDebugArea(this IContainer element)
-        {
-            return element.Element(new ContentOverflowDebugArea());
-        }
     }
 }