Browse Source

Text element: improved the default sizing behavior for the Text element. Now, when the text is empty, it works more consistently by taking up zero width while still reserving vertical space based on the font size.

Marcin Ziąbek 1 year ago
parent
commit
32e2b1e98e

+ 36 - 1
Source/QuestPDF/Elements/Text/TextBlock.cs

@@ -4,7 +4,6 @@ using System.Linq;
 using QuestPDF.Drawing;
 using QuestPDF.Drawing.Exceptions;
 using QuestPDF.Elements.Text.Items;
-using QuestPDF.Helpers;
 using QuestPDF.Infrastructure;
 using QuestPDF.Skia;
 using QuestPDF.Skia.Text;
@@ -37,6 +36,7 @@ namespace QuestPDF.Elements.Text
         private float MaximumWidth { get; set; }
         
         private bool IsRendered { get; set; }
+        private bool? ContainsOnlyWhiteSpace { get; set; }
         private int CurrentLineIndex { get; set; }
         private float CurrentTopOffset { get; set; }
         
@@ -61,6 +61,13 @@ namespace QuestPDF.Elements.Text
             
             if (IsRendered)
                 return SpacePlan.Empty();
+
+            // if the text block does not contain any items, or all items are null, return SpacePlan.Empty
+            // but if the text block contains only whitespace, return SpacePlan.FullRender with zero width and font-based height
+            ContainsOnlyWhiteSpace ??= Items.All(x => x is TextBlockSpan textBlockSpan && string.IsNullOrWhiteSpace(textBlockSpan.Text));
+            
+            if (ContainsOnlyWhiteSpace == true)
+                return SpacePlan.FullRender(0, MeasureHeightOfParagraphContainingOnlyWhiteSpace());
             
             Initialize();
             
@@ -108,6 +115,9 @@ namespace QuestPDF.Elements.Text
             if (IsRendered)
                 return;
             
+            if (ContainsOnlyWhiteSpace == true)
+                return;
+            
             CalculateParagraphMetrics(availableSpace);
 
             if (MaximumWidth == 0)
@@ -501,5 +511,30 @@ namespace QuestPDF.Elements.Text
                 $"You can disable this check by setting the 'Settings.CheckIfAllTextGlyphsAreAvailable' option to 'false'. \n" +
                 $"However, this may result with text glyphs being incorrectly rendered without any warning.");
         }
+
+        private float MeasureHeightOfParagraphContainingOnlyWhiteSpace()
+        {
+            var paragraphStyle = new ParagraphStyleConfiguration
+            {
+                Alignment = ParagraphStyleConfiguration.TextAlign.Start,
+                Direction = ParagraphStyleConfiguration.TextDirection.Ltr
+            };
+            
+            var builder = SkParagraphBuilderPoolManager.Get(paragraphStyle);
+
+            try
+            {
+                foreach (var textBlockSpan in Items.OfType<TextBlockSpan>())
+                    builder.AddText("\u00A0", textBlockSpan.Style.GetSkTextStyle()); // non-breaking space
+
+                var paragraph = builder.CreateParagraph();
+                paragraph.PlanLayout(1000);
+                return paragraph.GetLineMetrics().First().Height;
+            }
+            finally
+            {
+                SkParagraphBuilderPoolManager.Return(builder);
+            }
+        }
     }
 }

+ 4 - 4
Source/QuestPDF/Fluent/TextExtensions.cs

@@ -237,7 +237,7 @@ namespace QuestPDF.Fluent
         /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for="text.returns.spanDescriptor"]/*' />
         public TextSpanDescriptor Span(string? text)
         {
-            if (IsNullOrEmpty(text))
+            if (text == null)
                 return new TextSpanDescriptor(new TextBlockSpan());
 
             var textSpan = new TextBlockSpan() { Text = text };
@@ -352,7 +352,7 @@ namespace QuestPDF.Fluent
             if (IsNullOrEmpty(sectionName))
                 throw new ArgumentException("Section name cannot be null or empty", nameof(sectionName));
 
-            if (IsNullOrEmpty(text))
+            if (text == null)
                 return new TextSpanDescriptor(new TextBlockSpan());
 
             var textBlockItem = new TextBlockSectionLink
@@ -381,7 +381,7 @@ namespace QuestPDF.Fluent
             if (IsNullOrEmpty(url))
                 throw new ArgumentException("Url cannot be null or empty", nameof(url));
 
-            if (IsNullOrEmpty(text))
+            if (text == null)
                 return new TextSpanDescriptor(new TextBlockSpan());
             
             var textBlockItem = new TextBlockHyperlink
@@ -478,7 +478,7 @@ namespace QuestPDF.Fluent
         /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for="text.returns.spanDescriptor"]/*' />
         public static TextBlockDescriptor Text(this IContainer container, string? text)
         {
-            if (IsNullOrEmpty(text))
+            if (text == null)
                 return new TextBlockDescriptor(new TextBlock(), new TextBlockSpan());
             
             var textBlock = new TextBlock();

+ 4 - 0
Source/QuestPDF/Resources/ReleaseNotes.txt

@@ -20,3 +20,7 @@ Bug Fixes:
 - Column Element: Resolved instability issues in nested layouts with spacing and zero-sized elements.
 - JPEG Quality: Disabled JPEG image downsampling/downscaling to maintain the highest quality levels.
 - Image Compression: Disabled additional image compression performed by Skia.
+
+
+Version 2024.6.1
+- Text element: improved the default sizing behavior for the Text element. Now, when the text is empty, it works more consistently by taking up zero width while still reserving vertical space based on the font size.