Browse Source

Fixed build, adapted fallback process for cached TextStyle

MarcinZiabek 3 years ago
parent
commit
fbebbd85eb

+ 1 - 1
QuestPDF/Drawing/DocumentGenerator.cs

@@ -172,7 +172,7 @@ namespace QuestPDF.Drawing
                 {
                     if (textBlockItem is TextBlockSpan textSpan)
                     {
-                        textSpan.Style = textSpan.Style.ApplyGlobalStyle(TextStyle.LibraryDefault);
+                        textSpan.Style = textSpan.Style.ApplyGlobalStyle(documentDefaultTextStyle);
                     }
                     else if (textBlockItem is TextBlockElement textElement)
                     {

+ 8 - 4
QuestPDF/Elements/Text/FontFallback.cs

@@ -85,22 +85,26 @@ namespace QuestPDF.Elements.Text
                     if (fallbackOption.Font.ContainsGlyph(codepoint))
                         return fallbackOption;
                 }
-                
+
+                throw CreateNotMatchingFontException(codepoint);
+            }
+
+            static Exception CreateNotMatchingFontException(int codepoint)
+            {
                 var character = char.ConvertFromUtf32(codepoint);
                 var unicode = $"U-{codepoint:X4}";
 
-
                 var proposedFonts = FindFontsContainingGlyph(codepoint);
                 var proposedFontsFormatted = proposedFonts.Any() ? string.Join(", ", proposedFonts) : "no fonts available";
                 
-                throw new DocumentDrawingException(
+                return new DocumentDrawingException(
                     $"Could not find an appropriate font fallback for glyph: {unicode} '{character}'. " +
                     $"Font families available on current environment that contain this glyph: {proposedFontsFormatted}. " +
                     $"Possible solutions: " +
                     $"1) Use one of the listed fonts as the primary font in your document. " +
                     $"2) Configure the fallback TextStyle using the 'TextStyle.Fallback' method with one of the listed fonts. ");
             }
-
+            
             static IEnumerable<string> FindFontsContainingGlyph(int codepoint)
             {
                 var fontManager = SKFontManager.Default;

+ 1 - 1
QuestPDF/Fluent/TextStyleExtensions.cs

@@ -156,7 +156,7 @@ namespace QuestPDF.Fluent
         
         public static TextStyle Fallback(this TextStyle style, TextStyle? value = null)
         {
-            return style.Mutate(x => x.Fallback = value);
+            return style.Mutate(TextStyleProperty.Fallback, value);
         }
         
         public static TextStyle Fallback(this TextStyle style, Func<TextStyle, TextStyle> handler)

+ 53 - 20
QuestPDF/Infrastructure/TextStyleManager.cs

@@ -16,13 +16,15 @@ namespace QuestPDF.Infrastructure
         IsItalic,
         HasStrikethrough,
         HasUnderline,
-        WrapAnywhere
+        WrapAnywhere,
+        Fallback
     }
     
     internal static class TextStyleManager
     {
-        public static ConcurrentDictionary<(TextStyle origin, TextStyleProperty property, object value), TextStyle> TextStyleMutateCache = new();
-        public static ConcurrentDictionary<(TextStyle origin, TextStyle parent, bool overrideValue), TextStyle> TextStyleApplyCache = new();
+        private static readonly ConcurrentDictionary<(TextStyle origin, TextStyleProperty property, object value), TextStyle> TextStyleMutateCache = new();
+        private static readonly ConcurrentDictionary<(TextStyle origin, TextStyle parent), TextStyle> TextStyleApplyGlobalCache = new();
+        private static readonly ConcurrentDictionary<(TextStyle origin, TextStyle parent), TextStyle> TextStyleOverrideCache = new();
 
         public static TextStyle Mutate(this TextStyle origin, TextStyleProperty property, object value)
         {
@@ -30,7 +32,7 @@ namespace QuestPDF.Infrastructure
             return TextStyleMutateCache.GetOrAdd(cacheKey, x => MutateStyle(x.origin, x.property, x.value));
         }
 
-        private static TextStyle MutateStyle(TextStyle origin, TextStyleProperty property, object value, bool overrideValue = true)
+        private static TextStyle MutateStyle(TextStyle origin, TextStyleProperty property, object? value, bool overrideValue = true)
         {
             if (overrideValue && value == null)
                 return origin;
@@ -177,38 +179,69 @@ namespace QuestPDF.Infrastructure
                 
                 return origin with { WrapAnywhere = castedValue };
             }
+            
+            if (property == TextStyleProperty.Fallback)
+            {
+                if (!overrideValue && origin.Fallback != null)
+                    return origin;
+
+                var castedValue = (TextStyle?)value;
+                
+                if (origin.Fallback == castedValue)
+                    return origin;
+                
+                return origin with { Fallback = castedValue };
+            }
 
             throw new ArgumentOutOfRangeException(nameof(property), property, "Expected to mutate the TextStyle object. Provided property type is not supported.");
         }
         
         internal static TextStyle ApplyGlobalStyle(this TextStyle style, TextStyle parent)
         {
-            var cacheKey = (style, parent, false);
-            return TextStyleApplyCache.GetOrAdd(cacheKey, key => ApplyStyle(key.origin, key.parent, key.overrideValue));
+            var cacheKey = (style, parent);
+            return TextStyleApplyGlobalCache.GetOrAdd(cacheKey, key => ApplyStyle(key.origin, key.parent, overrideStyle: false).ApplyFontFallback());
+        }
+        
+        private static TextStyle ApplyFontFallback(this TextStyle style)
+        {
+            var targetFallbackStyle = style
+                ?.Fallback
+                ?.ApplyStyle(style, overrideStyle: false, applyFallback: false)
+                ?.ApplyFontFallback();
+            
+            return MutateStyle(style, TextStyleProperty.Fallback, targetFallbackStyle);
         }
         
         internal static TextStyle OverrideStyle(this TextStyle style, TextStyle parent)
         {
-            var cacheKey = (style, parent, true);
-            return TextStyleApplyCache.GetOrAdd(cacheKey, key => ApplyStyle(key.origin, key.parent, key.overrideValue));
+            var cacheKey = (style, parent);
+            
+            return TextStyleOverrideCache.GetOrAdd(cacheKey, key =>
+            {
+                var result = ApplyStyle(key.origin, key.parent);
+                return MutateStyle(result, TextStyleProperty.Fallback, key.parent.Fallback);
+            });
         }
         
-        private static TextStyle ApplyStyle(TextStyle style, TextStyle parent, bool overrideValue)
+        private static TextStyle ApplyStyle(this TextStyle style, TextStyle parent, bool overrideStyle = true, bool applyFallback = true)
         {
             var result = style;
 
-            result = MutateStyle(result, TextStyleProperty.Color, parent.Color, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.BackgroundColor, parent.BackgroundColor, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.FontFamily, parent.FontFamily, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.Size, parent.Size, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.LineHeight, parent.LineHeight, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.FontWeight, parent.FontWeight, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.FontPosition, parent.FontPosition, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.IsItalic, parent.IsItalic, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.HasStrikethrough, parent.HasStrikethrough, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.HasUnderline, parent.HasUnderline, overrideValue);
-            result = MutateStyle(result, TextStyleProperty.WrapAnywhere, parent.WrapAnywhere, overrideValue);
+            result = MutateStyle(result, TextStyleProperty.Color, parent.Color, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.BackgroundColor, parent.BackgroundColor, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.FontFamily, parent.FontFamily, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.Size, parent.Size, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.LineHeight, parent.LineHeight, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.FontWeight, parent.FontWeight, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.FontPosition, parent.FontPosition, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.IsItalic, parent.IsItalic, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.HasStrikethrough, parent.HasStrikethrough, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.HasUnderline, parent.HasUnderline, overrideStyle);
+            result = MutateStyle(result, TextStyleProperty.WrapAnywhere, parent.WrapAnywhere, overrideStyle);
             
+            if (applyFallback)
+                result = MutateStyle(result, TextStyleProperty.Fallback, parent.Fallback, overrideStyle);
+
             return result;
         }
     }