278 lines
10 KiB
C#
278 lines
10 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using QuestPDF.Fluent;
|
|
|
|
namespace QuestPDF.Infrastructure
|
|
{
|
|
internal enum TextStyleProperty
|
|
{
|
|
Color,
|
|
BackgroundColor,
|
|
FontFamily,
|
|
Size,
|
|
LineHeight,
|
|
LetterSpacing,
|
|
FontWeight,
|
|
FontPosition,
|
|
IsItalic,
|
|
HasStrikethrough,
|
|
HasUnderline,
|
|
WrapAnywhere,
|
|
Fallback,
|
|
Direction
|
|
}
|
|
|
|
internal static class TextStyleManager
|
|
{
|
|
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)
|
|
{
|
|
var cacheKey = (origin, property, value);
|
|
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)
|
|
{
|
|
if (overrideValue && value == null)
|
|
return origin;
|
|
|
|
if (property == TextStyleProperty.Color)
|
|
{
|
|
if (!overrideValue && origin.Color != null)
|
|
return origin;
|
|
|
|
var castedValue = (string?)value;
|
|
|
|
if (origin.Color == castedValue)
|
|
return origin;
|
|
|
|
return origin with { Color = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.BackgroundColor)
|
|
{
|
|
if (!overrideValue && origin.BackgroundColor != null)
|
|
return origin;
|
|
|
|
var castedValue = (string?)value;
|
|
|
|
if (origin.BackgroundColor == castedValue)
|
|
return origin;
|
|
|
|
return origin with { BackgroundColor = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.FontFamily)
|
|
{
|
|
if (!overrideValue && origin.FontFamily != null)
|
|
return origin;
|
|
|
|
var castedValue = (string?)value;
|
|
|
|
if (origin.FontFamily == castedValue)
|
|
return origin;
|
|
|
|
return origin with { FontFamily = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.Size)
|
|
{
|
|
if (!overrideValue && origin.Size != null)
|
|
return origin;
|
|
|
|
var castedValue = (float?)value;
|
|
|
|
if (origin.Size == castedValue)
|
|
return origin;
|
|
|
|
return origin with { Size = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.LineHeight)
|
|
{
|
|
if (!overrideValue && origin.LineHeight != null)
|
|
return origin;
|
|
|
|
var castedValue = (float?)value;
|
|
|
|
if (origin.LineHeight == castedValue)
|
|
return origin;
|
|
|
|
return origin with { LineHeight = castedValue };
|
|
}
|
|
|
|
if(property == TextStyleProperty.LetterSpacing)
|
|
{
|
|
if (!overrideValue && origin.LetterSpacing != null)
|
|
return origin;
|
|
|
|
var castedValue = (float?)value;
|
|
|
|
if (origin.LetterSpacing == castedValue)
|
|
return origin;
|
|
|
|
return origin with { LetterSpacing = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.FontWeight)
|
|
{
|
|
if (!overrideValue && origin.FontWeight != null)
|
|
return origin;
|
|
|
|
var castedValue = (FontWeight?)value;
|
|
|
|
if (origin.FontWeight == castedValue)
|
|
return origin;
|
|
|
|
return origin with { FontWeight = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.FontPosition)
|
|
{
|
|
if (!overrideValue && origin.FontPosition != null)
|
|
return origin;
|
|
|
|
var castedValue = (FontPosition?)value;
|
|
|
|
if (origin.FontPosition == castedValue)
|
|
return origin;
|
|
|
|
return origin with { FontPosition = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.IsItalic)
|
|
{
|
|
if (!overrideValue && origin.IsItalic != null)
|
|
return origin;
|
|
|
|
var castedValue = (bool?)value;
|
|
|
|
if (origin.IsItalic == castedValue)
|
|
return origin;
|
|
|
|
return origin with { IsItalic = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.HasStrikethrough)
|
|
{
|
|
if (!overrideValue && origin.HasStrikethrough != null)
|
|
return origin;
|
|
|
|
var castedValue = (bool?)value;
|
|
|
|
if (origin.HasStrikethrough == castedValue)
|
|
return origin;
|
|
|
|
return origin with { HasStrikethrough = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.HasUnderline)
|
|
{
|
|
if (!overrideValue && origin.HasUnderline != null)
|
|
return origin;
|
|
|
|
var castedValue = (bool?)value;
|
|
|
|
if (origin.HasUnderline == castedValue)
|
|
return origin;
|
|
|
|
return origin with { HasUnderline = castedValue };
|
|
}
|
|
|
|
if (property == TextStyleProperty.WrapAnywhere)
|
|
{
|
|
if (!overrideValue && origin.WrapAnywhere != null)
|
|
return origin;
|
|
|
|
var castedValue = (bool?)value;
|
|
|
|
if (origin.WrapAnywhere == castedValue)
|
|
return origin;
|
|
|
|
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 };
|
|
}
|
|
|
|
if (property == TextStyleProperty.Direction)
|
|
{
|
|
if (!overrideValue && origin.Direction != null)
|
|
return origin;
|
|
|
|
var castedValue = (TextDirection?)value;
|
|
|
|
if (origin.Direction == castedValue)
|
|
return origin;
|
|
|
|
return origin with { Direction = 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);
|
|
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);
|
|
|
|
return TextStyleOverrideCache.GetOrAdd(cacheKey, key =>
|
|
{
|
|
var result = ApplyStyle(key.origin, key.parent);
|
|
return MutateStyle(result, TextStyleProperty.Fallback, key.parent.Fallback);
|
|
});
|
|
}
|
|
|
|
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, 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.LetterSpacing, parent.LetterSpacing, 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);
|
|
result = MutateStyle(result, TextStyleProperty.Direction, parent.Direction, overrideStyle);
|
|
|
|
if (applyFallback)
|
|
result = MutateStyle(result, TextStyleProperty.Fallback, parent.Fallback, overrideStyle);
|
|
|
|
return result;
|
|
}
|
|
}
|
|
} |