Browse Source

Implemented experiment

MarcinZiabek 3 years ago
parent
commit
704256510e

+ 1 - 1
QuestPDF.Examples/TableBenchmark.cs

@@ -17,7 +17,7 @@ namespace QuestPDF.Examples
                 .PageSize(PageSizes.A4)
                 .ShowResults()
                 .MaxPages(10_000)
-                .EnableCaching(true)
+                //.EnableCaching(true)
                 .EnableDebugging(false)
                 .Render(container =>
                 {

+ 2 - 2
QuestPDF.ReportSample/DataSource.cs

@@ -15,8 +15,8 @@ namespace QuestPDF.ReportSample
                 HeaderFields = HeaderFields(),
                 
                 LogoData = Helpers.GetImage("Logo.png"),
-                Sections = Enumerable.Range(0, 40).Select(x => GenerateSection()).ToList(),
-                Photos = Enumerable.Range(0, 25).Select(x => GetReportPhotos()).ToList()
+                Sections = Enumerable.Range(0, 2000).Select(x => GenerateSection()).ToList(),
+                Photos = Enumerable.Range(0, 200).Select(x => GetReportPhotos()).ToList()
             };
 
             List<ReportHeaderField> HeaderFields()

+ 4 - 1
QuestPDF.ReportSample/Tests.cs

@@ -24,7 +24,10 @@ namespace QuestPDF.ReportSample
         [Test] 
         public void GenerateAndShowPdf()
         {
-            //ImagePlaceholder.Solid = true;
+            Settings.DocumentLayoutExceptionThreshold = 10_000;
+            Settings.EnableCaching = true;
+            Settings.EnableDebugging = false;
+            ImagePlaceholder.Solid = true;
         
             var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"test_result.pdf");
             Report.GeneratePdf(path);

+ 1 - 0
QuestPDF.UnitTests/TestEngine/MockCanvas.cs

@@ -20,6 +20,7 @@ namespace QuestPDF.UnitTests.TestEngine
         public void DrawRectangle(Position vector, Size size, string color) => DrawRectFunc(vector, size, color);
         public void DrawText(SKTextBlob skTextBlob, Position position, TextStyle style) => throw new NotImplementedException();
         public void DrawImage(SKImage image, Position position, Size size) => DrawImageFunc(image, position, size);
+        public void DrawPicture(SKPicture picture) => throw new NotImplementedException();
 
         public void DrawHyperlink(string url, Size size) => throw new NotImplementedException();
         public void DrawSectionLink(string sectionName, Size size) => throw new NotImplementedException();

+ 2 - 1
QuestPDF.UnitTests/TestEngine/OperationRecordingCanvas.cs

@@ -18,7 +18,8 @@ namespace QuestPDF.UnitTests.TestEngine
         public void DrawRectangle(Position vector, Size size, string color) => Operations.Add(new CanvasDrawRectangleOperation(vector, size, color));
         public void DrawText(SKTextBlob skTextBlob, Position position, TextStyle style) => throw new NotImplementedException();
         public void DrawImage(SKImage image, Position position, Size size) => Operations.Add(new CanvasDrawImageOperation(position, size));
-        
+        public void DrawPicture(SKPicture picture) => throw new NotImplementedException();
+
         public void DrawHyperlink(string url, Size size) => throw new NotImplementedException();
         public void DrawSectionLink(string sectionName, Size size) => throw new NotImplementedException();
         public void DrawSection(string sectionName) => throw new NotImplementedException();

+ 14 - 2
QuestPDF/Drawing/DocumentGenerator.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using QuestPDF.Drawing.Exceptions;
@@ -67,13 +68,24 @@ namespace QuestPDF.Drawing
             ApplyDefaultTextStyle(content, TextStyle.LibraryDefault);
             
             var debuggingState = Settings.EnableDebugging ? ApplyDebugging(content) : null;
+            debuggingState = null;
             
-            if (Settings.EnableCaching)
-                ApplyCaching(content);
+            //if (Settings.EnableCaching)
+                //ApplyCaching(content);
 
             var pageContext = new PageContext();
+
+            var stopwatch = new Stopwatch();
+            
+            stopwatch.Restart(); 
             RenderPass(pageContext, new FreeCanvas(), content, debuggingState);
+            stopwatch.Stop();
+            Console.WriteLine($"Cold free: {stopwatch.Elapsed}");
+
+            stopwatch.Restart();
             RenderPass(pageContext, canvas, content, debuggingState);
+            stopwatch.Stop();
+            Console.WriteLine($"Canvas: {stopwatch.Elapsed}");
         }
         
         internal static void RenderPass<TCanvas>(PageContext pageContext, TCanvas canvas, Container content, DebuggingState? debuggingState)

+ 5 - 0
QuestPDF/Drawing/FreeCanvas.cs

@@ -51,6 +51,11 @@ namespace QuestPDF.Drawing
             
         }
 
+        public void DrawPicture(SKPicture picture)
+        {
+            
+        }
+
         public void DrawHyperlink(string url, Size size)
         {
            

+ 5 - 0
QuestPDF/Drawing/SkiaCanvasBase.cs

@@ -38,6 +38,11 @@ namespace QuestPDF.Drawing
             Canvas.DrawImage(image, new SKRect(vector.X, vector.Y, size.Width, size.Height));
         }
 
+        public void DrawPicture(SKPicture picture)
+        {
+            Canvas.DrawPicture(picture);
+        }
+
         public void DrawHyperlink(string url, Size size)
         {
             Canvas.DrawUrlAnnotation(new SKRect(0, 0, size.Width, size.Height), url);

+ 39 - 0
QuestPDF/Drawing/SkiaCaptureCanvas.cs

@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using QuestPDF.Helpers;
+using QuestPDF.Infrastructure;
+using SkiaSharp;
+
+namespace QuestPDF.Drawing
+{
+    internal class SkiaCaptureCanvas : SkiaCanvasBase
+    {
+        private SKPictureRecorder? PictureRecorder { get; set; }
+        private Size? CurrentPageSize { get; set; }
+        public SKPicture? CurrentPicture { get; set; }
+        
+        public override void BeginDocument()
+        {
+            
+        }
+
+        public override void BeginPage(Size size)
+        {
+            CurrentPageSize = size;
+            PictureRecorder = new SKPictureRecorder();
+
+            Canvas = PictureRecorder.BeginRecording(new SKRect(0, 0, size.Width, size.Height));
+        }
+
+        public override void EndPage()
+        {
+            CurrentPicture = PictureRecorder?.EndRecording();
+            
+            PictureRecorder?.Dispose();
+            PictureRecorder = null;
+        }
+
+        public override void EndDocument() { }
+    }
+}

+ 59 - 0
QuestPDF/Elements/DrawingCache.cs

@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+using QuestPDF.Drawing;
+using QuestPDF.Helpers;
+using QuestPDF.Infrastructure;
+using SkiaSharp;
+
+namespace QuestPDF.Elements
+{
+    internal class DrawingCache : ContainerElement
+    {
+        private SkiaCaptureCanvas CaptureCanvas { get; } = new();
+        private Dictionary<int, SpacePlan> MeasureCache { get; } = new();
+        private Dictionary<int, SKPicture> DrawCache { get; } = new();
+        
+        ~DrawingCache()
+        {
+            foreach (var picture in DrawCache.Values)
+                picture.Dispose();
+
+            DrawCache.Clear();
+        }
+        
+        internal override void Initialize(IPageContext pageContext, ICanvas canvas)
+        {
+            Child.VisitChildren(x => x.Canvas = CaptureCanvas);
+            base.Initialize(pageContext, canvas);
+        }
+        
+        internal override SpacePlan Measure(Size availableSpace)
+        {
+            var cacheKey = PageContext.CurrentPage;
+
+            if (MeasureCache.TryGetValue(cacheKey, out var result))
+                return result;
+
+            var childSize = Child?.Measure(availableSpace) ?? SpacePlan.FullRender(Size.Zero);
+            MeasureCache.Add(cacheKey, childSize);
+            return childSize;
+        }
+        
+        internal override void Draw(Size availableSpace)
+        {
+            var cacheKey = PageContext.CurrentPage;
+
+            if (DrawCache.TryGetValue(cacheKey, out var result))
+            {
+                Canvas.DrawPicture(result);
+                return;
+            }
+            
+            CaptureCanvas.BeginPage(availableSpace);
+            Child?.Draw(availableSpace);
+            CaptureCanvas.EndPage();
+
+            var picture = CaptureCanvas.CurrentPicture;
+            DrawCache.Add(cacheKey, picture);
+        }
+    }
+}

+ 1 - 0
QuestPDF/Elements/Page.cs

@@ -30,6 +30,7 @@ namespace QuestPDF.Elements
         public void Compose(IContainer container)
         {
             container
+                //.Element(new DrawingCache())
                 .Background(BackgroundColor)
                 .Layers(layers =>
                 {

+ 0 - 11
QuestPDF/Fluent/TextSpanDescriptorExtensions.cs

@@ -15,17 +15,6 @@ namespace QuestPDF.Fluent
             return descriptor;
         }
         
-        public static T Fallback<T>(this T descriptor, TextStyle? value = null) where T : TextSpanDescriptor
-        {
-            descriptor.TextStyle.Fallback = value;
-            return descriptor;
-        }
-        
-        public static T Fallback<T>(this T descriptor, Func<TextStyle, TextStyle> handler) where T : TextSpanDescriptor
-        {
-            return descriptor.Fallback(handler(TextStyle.Default));
-        }
-        
         public static T FontColor<T>(this T descriptor, string value) where T : TextSpanDescriptor
         {
             descriptor.MutateTextStyle(x => x.FontColor(value));

+ 1 - 0
QuestPDF/Infrastructure/ICanvas.cs

@@ -10,6 +10,7 @@ namespace QuestPDF.Infrastructure
         void DrawRectangle(Position vector, Size size, string color);
         void DrawText(SKTextBlob skTextBlob, Position position, TextStyle style);
         void DrawImage(SKImage image, Position position, Size size);
+        void DrawPicture(SKPicture picture);
 
         void DrawHyperlink(string url, Size size);
         void DrawSectionLink(string sectionName, Size size);