Compare commits

..

19 Commits

Author SHA1 Message Date
MarcinZiabek b658344a46 Experimental version of controlling content repeatability 2022-09-21 19:15:11 +02:00
MarcinZiabek 553c8ab719 2022.9.1 2022-09-19 12:05:44 +02:00
Marcin Ziąbek e768e9b06d Update readme.md 2022-09-19 00:58:55 +02:00
Marcin Ziąbek fd913a777c Update readme.md 2022-09-19 00:57:32 +02:00
MarcinZiabek ed9e6daec5 2022.9.0 2022-09-19 00:45:14 +02:00
Marcin Ziąbek ee6249a658 Merge pull request #341 from QuestPDF/2022.9
2022.9 Release
2022-09-19 00:43:29 +02:00
MarcinZiabek b307304f46 Fixed typo 2022-09-18 20:15:41 +02:00
MarcinZiabek f028f82e11 Removed unsued file 2022-09-17 20:42:14 +02:00
MarcinZiabek 719a3385f6 Updated Previewer to 2022.9 2022-09-16 19:52:10 +02:00
MarcinZiabek 2adff11400 2022.9.0-alpha1 2022-09-16 19:46:32 +02:00
MarcinZiabek 34fed6d547 Settings.CheckIfAllTextGlyphsAreAvailable improvements 2022-09-16 16:08:02 +02:00
MarcinZiabek db2df75624 Text example: fixed visuals 2022-09-15 22:19:28 +02:00
MarcinZiabek 6b535752df Fixed formatting page numbers 2022-09-15 22:12:06 +02:00
MarcinZiabek 556f87ff25 Settings renaming 2022-09-15 21:20:25 +02:00
MarcinZiabek fbebbd85eb Fixed build, adapted fallback process for cached TextStyle 2022-09-15 15:09:30 +02:00
MarcinZiabek 4650c2a4ea Merge branch 'font-fallback' into 2022.9
# Conflicts:
#	QuestPDF/Elements/Text/Items/TextBlockSpan.cs
#	QuestPDF/Fluent/TextStyleExtensions.cs
#	QuestPDF/Infrastructure/TextStyle.cs
2022-09-14 23:28:50 +02:00
MarcinZiabek 1ba01a1cf5 Fixed override value 2022-09-09 11:32:05 +02:00
MarcinZiabek d4448437ac Reduced creation of DefaultTextStyle objects 2022-09-08 17:29:52 +02:00
MarcinZiabek bc853f48fc Implemented TextStyleManager to reduce memory usage 2022-09-08 16:49:28 +02:00
28 changed files with 446 additions and 271 deletions
+1 -1
View File
@@ -111,7 +111,7 @@ namespace QuestPDF.Examples
{ {
page.Margin(50); page.Margin(50);
page.Content().Column(column => page.Content().PaddingVertical(10).Column(column =>
{ {
column.Item().Element(Title); column.Item().Element(Title);
column.Item().PageBreak(); column.Item().PageBreak();
+1 -1
View File
@@ -4,7 +4,7 @@
<Authors>MarcinZiabek</Authors> <Authors>MarcinZiabek</Authors>
<Company>CodeFlint</Company> <Company>CodeFlint</Company>
<PackageId>QuestPDF.Previewer</PackageId> <PackageId>QuestPDF.Previewer</PackageId>
<Version>2022.8.0</Version> <Version>2022.9.1</Version>
<PackAsTool>true</PackAsTool> <PackAsTool>true</PackAsTool>
<ToolCommandName>questpdf-previewer</ToolCommandName> <ToolCommandName>questpdf-previewer</ToolCommandName>
<PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription> <PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
+22 -7
View File
@@ -64,6 +64,8 @@ namespace QuestPDF.Drawing
var container = new DocumentContainer(); var container = new DocumentContainer();
document.Compose(container); document.Compose(container);
var content = container.Compose(); var content = container.Compose();
ApplyRepeatContent(content);
ApplyDefaultTextStyle(content, TextStyle.LibraryDefault); ApplyDefaultTextStyle(content, TextStyle.LibraryDefault);
var debuggingState = Settings.EnableDebugging ? ApplyDebugging(content) : null; var debuggingState = Settings.EnableDebugging ? ApplyDebugging(content) : null;
@@ -172,7 +174,7 @@ namespace QuestPDF.Drawing
{ {
if (textBlockItem is TextBlockSpan textSpan) if (textBlockItem is TextBlockSpan textSpan)
{ {
textSpan.Style.ApplyGlobalStyle(documentDefaultTextStyle); textSpan.Style = textSpan.Style.ApplyGlobalStyle(documentDefaultTextStyle);
} }
else if (textBlockItem is TextBlockElement textElement) else if (textBlockItem is TextBlockElement textElement)
{ {
@@ -184,18 +186,31 @@ namespace QuestPDF.Drawing
} }
if (content is DynamicHost dynamicHost) if (content is DynamicHost dynamicHost)
dynamicHost.TextStyle.ApplyGlobalStyle(documentDefaultTextStyle); dynamicHost.TextStyle = dynamicHost.TextStyle.ApplyGlobalStyle(documentDefaultTextStyle);
var targetTextStyle = documentDefaultTextStyle;
if (content is DefaultTextStyle defaultTextStyleElement) if (content is DefaultTextStyle defaultTextStyleElement)
documentDefaultTextStyle = defaultTextStyleElement.TextStyle.ApplyGlobalStyle(documentDefaultTextStyle);
foreach (var child in content.GetChildren())
ApplyDefaultTextStyle(child, documentDefaultTextStyle);
}
internal static void ApplyRepeatContent(this Element? content, bool enabled = false)
{
if (content == null)
return;
if (content is RepeatContent repeatContent)
{ {
defaultTextStyleElement.TextStyle.ApplyParentStyle(documentDefaultTextStyle); ApplyRepeatContent(repeatContent.Child, repeatContent.Repeat);
targetTextStyle = defaultTextStyleElement.TextStyle; return;
} }
foreach (var child in content.GetChildren()) foreach (var child in content.GetChildren())
ApplyDefaultTextStyle(child, targetTextStyle); ApplyRepeatContent(child, enabled);
if (!enabled)
content.CreateProxy(y => y is IContent ? new ShowOnce { Child = y } : y);
} }
} }
} }
+13 -13
View File
@@ -14,13 +14,13 @@ namespace QuestPDF.Drawing
{ {
public static class FontManager public static class FontManager
{ {
private static ConcurrentDictionary<string, FontStyleSet> StyleSets = new(); private static readonly ConcurrentDictionary<string, FontStyleSet> StyleSets = new();
private static ConcurrentDictionary<object, SKFontMetrics> FontMetrics = new(); private static readonly ConcurrentDictionary<TextStyle, SKFontMetrics> FontMetrics = new();
private static ConcurrentDictionary<object, SKPaint> FontPaints = new(); private static readonly ConcurrentDictionary<TextStyle, SKPaint> FontPaints = new();
private static ConcurrentDictionary<string, SKPaint> ColorPaints = new(); private static readonly ConcurrentDictionary<string, SKPaint> ColorPaints = new();
private static ConcurrentDictionary<object, Font> ShaperFonts = new(); private static readonly ConcurrentDictionary<TextStyle, Font> ShaperFonts = new();
private static ConcurrentDictionary<object, SKFont> Fonts = new(); private static readonly ConcurrentDictionary<TextStyle, SKFont> Fonts = new();
private static ConcurrentDictionary<object, TextShaper> TextShapers = new(); private static readonly ConcurrentDictionary<TextStyle, TextShaper> TextShapers = new();
static FontManager() static FontManager()
{ {
@@ -110,7 +110,7 @@ namespace QuestPDF.Drawing
internal static SKPaint ToPaint(this TextStyle style) internal static SKPaint ToPaint(this TextStyle style)
{ {
return FontPaints.GetOrAdd(style.PaintKey, key => Convert(style)); return FontPaints.GetOrAdd(style, Convert);
static SKPaint Convert(TextStyle style) static SKPaint Convert(TextStyle style)
{ {
@@ -172,14 +172,14 @@ namespace QuestPDF.Drawing
internal static SKFontMetrics ToFontMetrics(this TextStyle style) internal static SKFontMetrics ToFontMetrics(this TextStyle style)
{ {
return FontMetrics.GetOrAdd(style.FontMetricsKey, key => style.NormalPosition().ToPaint().FontMetrics); return FontMetrics.GetOrAdd(style, key => key.NormalPosition().ToPaint().FontMetrics);
} }
internal static Font ToShaperFont(this TextStyle style) internal static Font ToShaperFont(this TextStyle style)
{ {
return ShaperFonts.GetOrAdd(style.PaintKey, _ => return ShaperFonts.GetOrAdd(style, key =>
{ {
var typeface = style.ToPaint().Typeface; var typeface = key.ToPaint().Typeface;
using var harfBuzzBlob = typeface.OpenStream(out var ttcIndex).ToHarfBuzzBlob(); using var harfBuzzBlob = typeface.OpenStream(out var ttcIndex).ToHarfBuzzBlob();
@@ -200,12 +200,12 @@ namespace QuestPDF.Drawing
internal static TextShaper ToTextShaper(this TextStyle style) internal static TextShaper ToTextShaper(this TextStyle style)
{ {
return TextShapers.GetOrAdd(style.PaintKey, _ => new TextShaper(style)); return TextShapers.GetOrAdd(style, key => new TextShaper(key));
} }
internal static SKFont ToFont(this TextStyle style) internal static SKFont ToFont(this TextStyle style)
{ {
return Fonts.GetOrAdd(style.PaintKey, _ => style.ToPaint().ToFont()); return Fonts.GetOrAdd(style, key => key.ToPaint().ToFont());
} }
} }
} }
-8
View File
@@ -1,8 +0,0 @@
namespace QuestPDF.Drawing
{
internal struct TextMeasurement
{
public int LineIndex { get; set; }
public float FragmentWidth { get; set; }
}
}
-17
View File
@@ -56,9 +56,6 @@ namespace QuestPDF.Drawing
yOffset += glyphPositions[i].YAdvance * scaleY; yOffset += glyphPositions[i].YAdvance * scaleY;
} }
if (Settings.CheckIfAllTextGlyphsAreAvailableInSpecifiedFont)
CheckIfAllGlyphsAreAvailable(glyphs, text);
return new TextShapingResult(glyphs); return new TextShapingResult(glyphs);
} }
@@ -78,20 +75,6 @@ namespace QuestPDF.Drawing
else else
throw new NotSupportedException("TextEncoding of type GlyphId is not supported."); throw new NotSupportedException("TextEncoding of type GlyphId is not supported.");
} }
void CheckIfAllGlyphsAreAvailable(ShapedGlyph[] glyphs, string originalText)
{
var containsMissingGlyphs = glyphs.Any(x => x.Codepoint == default);
if (!containsMissingGlyphs)
return;
throw new ArgumentException(
$"Detected missing font glyphs while rendering text. " +
$"This means that the document contains text with characters not present in the assigned font. " +
$"Such characters are replaced by placeholders, usually visible as empty rectangles. " +
$"Font family used: {TextStyle.FontFamily}. Issue detected in text: '{originalText}'");
}
} }
internal struct ShapedGlyph internal struct ShapedGlyph
+1 -1
View File
@@ -7,7 +7,7 @@ namespace QuestPDF.Elements
{ {
public delegate void DrawOnCanvas(SKCanvas canvas, Size availableSpace); public delegate void DrawOnCanvas(SKCanvas canvas, Size availableSpace);
internal class Canvas : Element, ICacheable internal class Canvas : Element, ICacheable, IContent
{ {
public DrawOnCanvas Handler { get; set; } public DrawOnCanvas Handler { get; set; }
+2 -2
View File
@@ -6,12 +6,12 @@ using QuestPDF.Infrastructure;
namespace QuestPDF.Elements namespace QuestPDF.Elements
{ {
internal class DynamicHost : Element, IStateResettable internal class DynamicHost : Element, IStateResettable, IContent
{ {
private DynamicComponentProxy Child { get; } private DynamicComponentProxy Child { get; }
private object InitialComponentState { get; set; } private object InitialComponentState { get; set; }
internal TextStyle TextStyle { get; } = new(); internal TextStyle TextStyle { get; set; } = TextStyle.Default;
public DynamicHost(DynamicComponentProxy child) public DynamicHost(DynamicComponentProxy child)
{ {
+1 -1
View File
@@ -6,7 +6,7 @@ using SkiaSharp;
namespace QuestPDF.Elements namespace QuestPDF.Elements
{ {
internal class DynamicImage : Element internal class DynamicImage : Element, IContent
{ {
public Func<Size, byte[]>? Source { get; set; } public Func<Size, byte[]>? Source { get; set; }
+1 -1
View File
@@ -5,7 +5,7 @@ using SkiaSharp;
namespace QuestPDF.Elements namespace QuestPDF.Elements
{ {
internal class Image : Element, ICacheable internal class Image : Element, ICacheable, IContent
{ {
public SKImage? InternalImage { get; set; } public SKImage? InternalImage { get; set; }
+1 -1
View File
@@ -15,7 +15,7 @@ namespace QuestPDF.Elements
Horizontal Horizontal
} }
internal class Line : Element, ILine, ICacheable internal class Line : Element, ILine, ICacheable, IContent
{ {
public LineType Type { get; set; } = LineType.Vertical; public LineType Type { get; set; } = LineType.Vertical;
public string Color { get; set; } = Colors.Black; public string Color { get; set; } = Colors.Black;
+9
View File
@@ -0,0 +1,9 @@
using QuestPDF.Infrastructure;
namespace QuestPDF.Elements
{
internal class RepeatContent : ContainerElement
{
public bool Repeat { get; set; }
}
}
+8 -5
View File
@@ -86,14 +86,18 @@ namespace QuestPDF.Elements.Text
return fallbackOption; return fallbackOption;
} }
throw CreateNotMatchingFontException(codepoint);
}
static Exception CreateNotMatchingFontException(int codepoint)
{
var character = char.ConvertFromUtf32(codepoint); var character = char.ConvertFromUtf32(codepoint);
var unicode = $"U-{codepoint:X4}"; var unicode = $"U-{codepoint:X4}";
var proposedFonts = FindFontsContainingGlyph(codepoint); var proposedFonts = FindFontsContainingGlyph(codepoint);
var proposedFontsFormatted = proposedFonts.Any() ? string.Join(", ", proposedFonts) : "no fonts available"; 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}'. " + $"Could not find an appropriate font fallback for glyph: {unicode} '{character}'. " +
$"Font families available on current environment that contain this glyph: {proposedFontsFormatted}. " + $"Font families available on current environment that contain this glyph: {proposedFontsFormatted}. " +
$"Possible solutions: " + $"Possible solutions: " +
@@ -117,10 +121,9 @@ namespace QuestPDF.Elements.Text
{ {
foreach (var textBlockItem in textBlockItems) foreach (var textBlockItem in textBlockItems)
{ {
if (textBlockItem is TextBlockSpan textBlockSpan) if (textBlockItem is TextBlockSpan textBlockSpan and not TextBlockPageNumber)
{ {
// perform font-fallback operation only when any fallback is available if (!Settings.CheckIfAllTextGlyphsAreAvailable && textBlockSpan.Style.Fallback == null)
if (textBlockSpan.Style.Fallback == null)
{ {
yield return textBlockSpan; yield return textBlockSpan;
continue; continue;
@@ -14,8 +14,8 @@ namespace QuestPDF.Elements.Text.Items
internal class TextBlockSpan : ITextBlockItem internal class TextBlockSpan : ITextBlockItem
{ {
public string Text { get; set; } public string Text { get; set; }
public TextStyle Style { get; set; } = new(); public TextStyle Style { get; set; } = TextStyle.Default;
private TextShapingResult? TextShapingResult { get; set; } public TextShapingResult? TextShapingResult { get; set; }
private Dictionary<(int startIndex, float availableWidth), TextMeasurementResult?> MeasureCache = new (); private Dictionary<(int startIndex, float availableWidth), TextMeasurementResult?> MeasureCache = new ();
protected virtual bool EnableTextCache => true; protected virtual bool EnableTextCache => true;
+1 -1
View File
@@ -8,7 +8,7 @@ using QuestPDF.Infrastructure;
namespace QuestPDF.Elements.Text namespace QuestPDF.Elements.Text
{ {
internal class TextBlock : Element, IStateResettable internal class TextBlock : Element, IStateResettable, IContent
{ {
public HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left; public HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
public List<ITextBlockItem> Items { get; set; } = new List<ITextBlockItem>(); public List<ITextBlockItem> Items { get; set; } = new List<ITextBlockItem>();
+2 -2
View File
@@ -12,7 +12,7 @@ namespace QuestPDF.Fluent
{ {
var container = new Container(); var container = new Container();
Decoration.Before = container; Decoration.Before = container;
return container; return container.RepeatContent();
} }
public void Before(Action<IContainer> handler) public void Before(Action<IContainer> handler)
@@ -36,7 +36,7 @@ namespace QuestPDF.Fluent
{ {
var container = new Container(); var container = new Container();
Decoration.After = container; Decoration.After = container;
return container; return container.RepeatContent();
} }
public void After(Action<IContainer> handler) public void After(Action<IContainer> handler)
+8
View File
@@ -195,5 +195,13 @@ namespace QuestPDF.Fluent
{ {
return element.Element(new ScaleToFit()); return element.Element(new ScaleToFit());
} }
public static IContainer RepeatContent(this IContainer element, bool enabled = true)
{
return element.Element(new RepeatContent
{
Repeat = enabled
});
}
} }
} }
+35 -41
View File
@@ -12,11 +12,18 @@ namespace QuestPDF.Fluent
{ {
public class TextSpanDescriptor public class TextSpanDescriptor
{ {
internal TextStyle TextStyle { get; } internal TextStyle TextStyle = TextStyle.Default;
internal Action<TextStyle> AssignTextStyle { get; }
internal TextSpanDescriptor(TextStyle textStyle) internal TextSpanDescriptor(Action<TextStyle> assignTextStyle)
{ {
TextStyle = textStyle; AssignTextStyle = assignTextStyle;
}
internal void MutateTextStyle(Func<TextStyle, TextStyle> handler)
{
TextStyle = handler(TextStyle);
AssignTextStyle(TextStyle);
} }
} }
@@ -24,16 +31,17 @@ namespace QuestPDF.Fluent
public class TextPageNumberDescriptor : TextSpanDescriptor public class TextPageNumberDescriptor : TextSpanDescriptor
{ {
internal PageNumberFormatter FormatFunction { get; private set; } = x => x?.ToString() ?? string.Empty; internal Action<PageNumberFormatter> AssignFormatFunction { get; }
internal TextPageNumberDescriptor(TextStyle textStyle) : base(textStyle) internal TextPageNumberDescriptor(Action<TextStyle> assignTextStyle, Action<PageNumberFormatter> assignFormatFunction) : base(assignTextStyle)
{ {
AssignFormatFunction = assignFormatFunction;
AssignFormatFunction(x => x?.ToString());
} }
public TextPageNumberDescriptor Format(PageNumberFormatter formatter) public TextPageNumberDescriptor Format(PageNumberFormatter formatter)
{ {
FormatFunction = formatter ?? FormatFunction; AssignFormatFunction(formatter);
return this; return this;
} }
} }
@@ -41,7 +49,7 @@ namespace QuestPDF.Fluent
public class TextDescriptor public class TextDescriptor
{ {
private ICollection<TextBlock> TextBlocks { get; } = new List<TextBlock>(); private ICollection<TextBlock> TextBlocks { get; } = new List<TextBlock>();
private TextStyle DefaultStyle { get; set; } = TextStyle.Default; private TextStyle? DefaultStyle { get; set; }
internal HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left; internal HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
private float Spacing { get; set; } = 0f; private float Spacing { get; set; } = 0f;
@@ -91,19 +99,15 @@ namespace QuestPDF.Fluent
public TextSpanDescriptor Span(string? text) public TextSpanDescriptor Span(string? text)
{ {
var style = DefaultStyle.Clone();
var descriptor = new TextSpanDescriptor(style);
if (text == null) if (text == null)
return descriptor; return new TextSpanDescriptor(_ => { });
var items = text var items = text
.Replace("\r", string.Empty) .Replace("\r", string.Empty)
.Split(new[] { '\n' }, StringSplitOptions.None) .Split(new[] { '\n' }, StringSplitOptions.None)
.Select(x => new TextBlockSpan .Select(x => new TextBlockSpan
{ {
Text = x, Text = x
Style = style
}) })
.ToList(); .ToList();
@@ -118,7 +122,7 @@ namespace QuestPDF.Fluent
.ToList() .ToList()
.ForEach(TextBlocks.Add); .ForEach(TextBlocks.Add);
return descriptor; return new TextSpanDescriptor(x => items.ForEach(y => y.Style = x));
} }
public TextSpanDescriptor Line(string? text) public TextSpanDescriptor Line(string? text)
@@ -134,16 +138,10 @@ namespace QuestPDF.Fluent
private TextPageNumberDescriptor PageNumber(Func<IPageContext, int?> pageNumber) private TextPageNumberDescriptor PageNumber(Func<IPageContext, int?> pageNumber)
{ {
var style = DefaultStyle.Clone(); var textBlockItem = new TextBlockPageNumber();
var descriptor = new TextPageNumberDescriptor(style); AddItemToLastTextBlock(textBlockItem);
AddItemToLastTextBlock(new TextBlockPageNumber return new TextPageNumberDescriptor(x => textBlockItem.Style = x, x => textBlockItem.Source = context => x(pageNumber(context)));
{
Source = context => descriptor.FormatFunction(pageNumber(context)),
Style = style
});
return descriptor;
} }
public TextPageNumberDescriptor CurrentPageNumber() public TextPageNumberDescriptor CurrentPageNumber()
@@ -187,20 +185,17 @@ namespace QuestPDF.Fluent
if (IsNullOrEmpty(sectionName)) if (IsNullOrEmpty(sectionName))
throw new ArgumentException("Section name cannot be null or empty", nameof(sectionName)); throw new ArgumentException("Section name cannot be null or empty", nameof(sectionName));
var style = DefaultStyle.Clone();
var descriptor = new TextSpanDescriptor(style);
if (IsNullOrEmpty(text)) if (IsNullOrEmpty(text))
return descriptor; return new TextSpanDescriptor(_ => { });
AddItemToLastTextBlock(new TextBlockSectionLink var textBlockItem = new TextBlockSectionLink
{ {
Style = style,
Text = text, Text = text,
SectionName = sectionName SectionName = sectionName
}); };
return descriptor; AddItemToLastTextBlock(textBlockItem);
return new TextSpanDescriptor(x => textBlockItem.Style = x);
} }
[Obsolete("This element has been renamed since version 2022.3. Please use the SectionLink method.")] [Obsolete("This element has been renamed since version 2022.3. Please use the SectionLink method.")]
@@ -214,20 +209,17 @@ namespace QuestPDF.Fluent
if (IsNullOrEmpty(url)) if (IsNullOrEmpty(url))
throw new ArgumentException("Url cannot be null or empty", nameof(url)); throw new ArgumentException("Url cannot be null or empty", nameof(url));
var style = DefaultStyle.Clone();
var descriptor = new TextSpanDescriptor(style);
if (IsNullOrEmpty(text)) if (IsNullOrEmpty(text))
return descriptor; return new TextSpanDescriptor(_ => { });
AddItemToLastTextBlock(new TextBlockHyperlink var textBlockItem = new TextBlockHyperlink
{ {
Style = style,
Text = text, Text = text,
Url = url Url = url
}); };
return descriptor; AddItemToLastTextBlock(textBlockItem);
return new TextSpanDescriptor(x => textBlockItem.Style = x);
} }
[Obsolete("This element has been renamed since version 2022.3. Please use the Hyperlink method.")] [Obsolete("This element has been renamed since version 2022.3. Please use the Hyperlink method.")]
@@ -251,7 +243,9 @@ namespace QuestPDF.Fluent
internal void Compose(IContainer container) internal void Compose(IContainer container)
{ {
TextBlocks.ToList().ForEach(x => x.Alignment = Alignment); TextBlocks.ToList().ForEach(x => x.Alignment = Alignment);
container = container.DefaultTextStyle(DefaultStyle);
if (DefaultStyle != null)
container = container.DefaultTextStyle(DefaultStyle);
if (TextBlocks.Count == 1) if (TextBlocks.Count == 1)
{ {
+36 -34
View File
@@ -11,7 +11,7 @@ namespace QuestPDF.Fluent
if (style == null) if (style == null)
return descriptor; return descriptor;
descriptor.TextStyle.OverrideStyle(style); descriptor.MutateTextStyle(x => x.OverrideStyle(style));
return descriptor; return descriptor;
} }
@@ -28,114 +28,118 @@ namespace QuestPDF.Fluent
public static T FontColor<T>(this T descriptor, string value) where T : TextSpanDescriptor public static T FontColor<T>(this T descriptor, string value) where T : TextSpanDescriptor
{ {
descriptor.TextStyle.Color = value; descriptor.MutateTextStyle(x => x.FontColor(value));
return descriptor; return descriptor;
} }
public static T BackgroundColor<T>(this T descriptor, string value) where T : TextSpanDescriptor public static T BackgroundColor<T>(this T descriptor, string value) where T : TextSpanDescriptor
{ {
descriptor.TextStyle.BackgroundColor = value; descriptor.MutateTextStyle(x => x.BackgroundColor(value));
return descriptor; return descriptor;
} }
public static T FontFamily<T>(this T descriptor, string value) where T : TextSpanDescriptor public static T FontFamily<T>(this T descriptor, string value) where T : TextSpanDescriptor
{ {
descriptor.TextStyle.FontFamily = value; descriptor.MutateTextStyle(x => x.FontFamily(value));
return descriptor; return descriptor;
} }
public static T FontSize<T>(this T descriptor, float value) where T : TextSpanDescriptor public static T FontSize<T>(this T descriptor, float value) where T : TextSpanDescriptor
{ {
descriptor.TextStyle.Size = value; descriptor.MutateTextStyle(x => x.FontSize(value));
return descriptor; return descriptor;
} }
public static T LineHeight<T>(this T descriptor, float value) where T : TextSpanDescriptor public static T LineHeight<T>(this T descriptor, float value) where T : TextSpanDescriptor
{ {
descriptor.TextStyle.LineHeight = value; descriptor.MutateTextStyle(x => x.LineHeight(value));
return descriptor; return descriptor;
} }
public static T Italic<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor public static T Italic<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor
{ {
descriptor.TextStyle.IsItalic = value; descriptor.MutateTextStyle(x => x.Italic(value));
return descriptor; return descriptor;
} }
public static T Strikethrough<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor public static T Strikethrough<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor
{ {
descriptor.TextStyle.HasStrikethrough = value; descriptor.MutateTextStyle(x => x.Strikethrough(value));
return descriptor; return descriptor;
} }
public static T Underline<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor public static T Underline<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor
{ {
descriptor.TextStyle.HasUnderline = value; descriptor.MutateTextStyle(x => x.Underline(value));
return descriptor; return descriptor;
} }
public static T WrapAnywhere<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor public static T WrapAnywhere<T>(this T descriptor, bool value = true) where T : TextSpanDescriptor
{ {
descriptor.TextStyle.WrapAnywhere = value; descriptor.MutateTextStyle(x => x.WrapAnywhere(value));
return descriptor; return descriptor;
} }
#region Weight #region Weight
public static T Weight<T>(this T descriptor, FontWeight weight) where T : TextSpanDescriptor
{
descriptor.TextStyle.FontWeight = weight;
return descriptor;
}
public static T Thin<T>(this T descriptor) where T : TextSpanDescriptor public static T Thin<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.Thin); descriptor.MutateTextStyle(x => x.Thin());
return descriptor;
} }
public static T ExtraLight<T>(this T descriptor) where T : TextSpanDescriptor public static T ExtraLight<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.ExtraLight); descriptor.MutateTextStyle(x => x.ExtraLight());
return descriptor;
} }
public static T Light<T>(this T descriptor) where T : TextSpanDescriptor public static T Light<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.Light); descriptor.MutateTextStyle(x => x.Light());
return descriptor;
} }
public static T NormalWeight<T>(this T descriptor) where T : TextSpanDescriptor public static T NormalWeight<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.Normal); descriptor.MutateTextStyle(x => x.NormalWeight());
return descriptor;
} }
public static T Medium<T>(this T descriptor) where T : TextSpanDescriptor public static T Medium<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.Medium); descriptor.MutateTextStyle(x => x.Medium());
return descriptor;
} }
public static T SemiBold<T>(this T descriptor) where T : TextSpanDescriptor public static T SemiBold<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.SemiBold); descriptor.MutateTextStyle(x => x.SemiBold());
return descriptor;
} }
public static T Bold<T>(this T descriptor) where T : TextSpanDescriptor public static T Bold<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.Bold); descriptor.MutateTextStyle(x => x.Bold());
return descriptor;
} }
public static T ExtraBold<T>(this T descriptor) where T : TextSpanDescriptor public static T ExtraBold<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.ExtraBold); descriptor.MutateTextStyle(x => x.ExtraBold());
return descriptor;
} }
public static T Black<T>(this T descriptor) where T : TextSpanDescriptor public static T Black<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.Black); descriptor.MutateTextStyle(x => x.Black());
return descriptor;
} }
public static T ExtraBlack<T>(this T descriptor) where T : TextSpanDescriptor public static T ExtraBlack<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Weight(FontWeight.ExtraBlack); descriptor.MutateTextStyle(x => x.ExtraBlack());
return descriptor;
} }
#endregion #endregion
@@ -143,24 +147,22 @@ namespace QuestPDF.Fluent
#region Position #region Position
public static T NormalPosition<T>(this T descriptor) where T : TextSpanDescriptor public static T NormalPosition<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Position(FontPosition.Normal); descriptor.MutateTextStyle(x => x.NormalPosition());
return descriptor;
} }
public static T Subscript<T>(this T descriptor) where T : TextSpanDescriptor public static T Subscript<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Position(FontPosition.Subscript); descriptor.MutateTextStyle(x => x.Subscript());
return descriptor;
} }
public static T Superscript<T>(this T descriptor) where T : TextSpanDescriptor public static T Superscript<T>(this T descriptor) where T : TextSpanDescriptor
{ {
return descriptor.Position(FontPosition.Superscript); descriptor.MutateTextStyle(x => x.Superscript());
}
private static T Position<T>(this T descriptor, FontPosition fontPosition) where T : TextSpanDescriptor
{
descriptor.TextStyle.FontPosition = fontPosition;
return descriptor; return descriptor;
} }
#endregion #endregion
} }
} }
+27 -32
View File
@@ -6,24 +6,6 @@ namespace QuestPDF.Fluent
{ {
public static class TextStyleExtensions public static class TextStyleExtensions
{ {
private static TextStyle Mutate(this TextStyle style, Action<TextStyle> handler)
{
style = style.Clone();
handler(style);
return style;
}
public static TextStyle Fallback(this TextStyle style, TextStyle? value = null)
{
return style.Mutate(x => x.Fallback = value);
}
public static TextStyle Fallback(this TextStyle style, Func<TextStyle, TextStyle> handler)
{
return style.Fallback(handler(TextStyle.Default));
}
[Obsolete("This element has been renamed since version 2022.3. Please use the FontColor method.")] [Obsolete("This element has been renamed since version 2022.3. Please use the FontColor method.")]
public static TextStyle Color(this TextStyle style, string value) public static TextStyle Color(this TextStyle style, string value)
{ {
@@ -32,12 +14,12 @@ namespace QuestPDF.Fluent
public static TextStyle FontColor(this TextStyle style, string value) public static TextStyle FontColor(this TextStyle style, string value)
{ {
return style.Mutate(x => x.Color = value); return style.Mutate(TextStyleProperty.Color, value);
} }
public static TextStyle BackgroundColor(this TextStyle style, string value) public static TextStyle BackgroundColor(this TextStyle style, string value)
{ {
return style.Mutate(x => x.BackgroundColor = value); return style.Mutate(TextStyleProperty.BackgroundColor, value);
} }
[Obsolete("This element has been renamed since version 2022.3. Please use the FontFamily method.")] [Obsolete("This element has been renamed since version 2022.3. Please use the FontFamily method.")]
@@ -48,7 +30,7 @@ namespace QuestPDF.Fluent
public static TextStyle FontFamily(this TextStyle style, string value) public static TextStyle FontFamily(this TextStyle style, string value)
{ {
return style.Mutate(x => x.FontFamily = value); return style.Mutate(TextStyleProperty.FontFamily, value);
} }
[Obsolete("This element has been renamed since version 2022.3. Please use the FontSize method.")] [Obsolete("This element has been renamed since version 2022.3. Please use the FontSize method.")]
@@ -59,39 +41,39 @@ namespace QuestPDF.Fluent
public static TextStyle FontSize(this TextStyle style, float value) public static TextStyle FontSize(this TextStyle style, float value)
{ {
return style.Mutate(x => x.Size = value); return style.Mutate(TextStyleProperty.Size, value);
} }
public static TextStyle LineHeight(this TextStyle style, float value) public static TextStyle LineHeight(this TextStyle style, float value)
{ {
return style.Mutate(x => x.LineHeight = value); return style.Mutate(TextStyleProperty.LineHeight, value);
} }
public static TextStyle Italic(this TextStyle style, bool value = true) public static TextStyle Italic(this TextStyle style, bool value = true)
{ {
return style.Mutate(x => x.IsItalic = value); return style.Mutate(TextStyleProperty.IsItalic, value);
} }
public static TextStyle Strikethrough(this TextStyle style, bool value = true) public static TextStyle Strikethrough(this TextStyle style, bool value = true)
{ {
return style.Mutate(x => x.HasStrikethrough = value); return style.Mutate(TextStyleProperty.HasStrikethrough, value);
} }
public static TextStyle Underline(this TextStyle style, bool value = true) public static TextStyle Underline(this TextStyle style, bool value = true)
{ {
return style.Mutate(x => x.HasUnderline = value); return style.Mutate(TextStyleProperty.HasUnderline, value);
} }
public static TextStyle WrapAnywhere(this TextStyle style, bool value = true) public static TextStyle WrapAnywhere(this TextStyle style, bool value = true)
{ {
return style.Mutate(x => x.WrapAnywhere = value); return style.Mutate(TextStyleProperty.WrapAnywhere, value);
} }
#region Weight #region Weight
public static TextStyle Weight(this TextStyle style, FontWeight weight) public static TextStyle Weight(this TextStyle style, FontWeight weight)
{ {
return style.Mutate(x => x.FontWeight = weight); return style.Mutate(TextStyleProperty.FontWeight, weight);
} }
public static TextStyle Thin(this TextStyle style) public static TextStyle Thin(this TextStyle style)
@@ -147,6 +129,7 @@ namespace QuestPDF.Fluent
#endregion #endregion
#region Position #region Position
public static TextStyle NormalPosition(this TextStyle style) public static TextStyle NormalPosition(this TextStyle style)
{ {
return style.Position(FontPosition.Normal); return style.Position(FontPosition.Normal);
@@ -164,11 +147,23 @@ namespace QuestPDF.Fluent
private static TextStyle Position(this TextStyle style, FontPosition fontPosition) private static TextStyle Position(this TextStyle style, FontPosition fontPosition)
{ {
if (style.FontPosition == fontPosition) return style.Mutate(TextStyleProperty.FontPosition, fontPosition);
return style;
return style.Mutate(t => t.FontPosition = fontPosition);
} }
#endregion
#region Fallback
public static TextStyle Fallback(this TextStyle style, TextStyle? value = null)
{
return style.Mutate(TextStyleProperty.Fallback, value);
}
public static TextStyle Fallback(this TextStyle style, Func<TextStyle, TextStyle> handler)
{
return style.Fallback(handler(TextStyle.Default));
}
#endregion #endregion
} }
} }
+7
View File
@@ -0,0 +1,7 @@
namespace QuestPDF.Infrastructure
{
internal interface IContent
{
}
}
+3 -71
View File
@@ -1,13 +1,10 @@
using System; using System;
using HarfBuzzSharp;
using QuestPDF.Helpers; using QuestPDF.Helpers;
namespace QuestPDF.Infrastructure namespace QuestPDF.Infrastructure
{ {
public class TextStyle public record TextStyle
{ {
internal bool HasGlobalStyleApplied { get; private set; }
internal string? Color { get; set; } internal string? Color { get; set; }
internal string? BackgroundColor { get; set; } internal string? BackgroundColor { get; set; }
internal string? FontFamily { get; set; } internal string? FontFamily { get; set; }
@@ -22,11 +19,7 @@ namespace QuestPDF.Infrastructure
internal TextStyle? Fallback { get; set; } internal TextStyle? Fallback { get; set; }
// TODO: without cache, this may be an expensive operation internal static TextStyle LibraryDefault { get; } = new()
internal object PaintKey => (FontFamily, Size, FontWeight, FontPosition, IsItalic, Color);
internal object FontMetricsKey => (FontFamily, Size, FontWeight, IsItalic);
internal static readonly TextStyle LibraryDefault = new TextStyle
{ {
Color = Colors.Black, Color = Colors.Black,
BackgroundColor = Colors.Transparent, BackgroundColor = Colors.Transparent,
@@ -42,67 +35,6 @@ namespace QuestPDF.Infrastructure
Fallback = null Fallback = null
}; };
// it is important to create new instances for the DefaultTextStyle element to work correctly public static TextStyle Default { get; } = new();
public static TextStyle Default => new TextStyle();
internal void ApplyGlobalStyle(TextStyle globalStyle)
{
if (HasGlobalStyleApplied)
return;
HasGlobalStyleApplied = true;
ApplyParentStyle(globalStyle);
if (Fallback != null)
ApplyFallbackStyle(this);
}
internal void ApplyFallbackStyle(TextStyle parentStyle)
{
ApplyParentStyle(parentStyle, false);
Fallback?.ApplyFallbackStyle(this);
}
internal void ApplyParentStyle(TextStyle parentStyle, bool mapFallback = true)
{
Color ??= parentStyle.Color;
BackgroundColor ??= parentStyle.BackgroundColor;
FontFamily ??= parentStyle.FontFamily;
Size ??= parentStyle.Size;
LineHeight ??= parentStyle.LineHeight;
FontWeight ??= parentStyle.FontWeight;
FontPosition ??= parentStyle.FontPosition;
IsItalic ??= parentStyle.IsItalic;
HasStrikethrough ??= parentStyle.HasStrikethrough;
HasUnderline ??= parentStyle.HasUnderline;
WrapAnywhere ??= parentStyle.WrapAnywhere;
if (mapFallback)
Fallback ??= parentStyle.Fallback?.Clone();
}
internal void OverrideStyle(TextStyle parentStyle)
{
Color = parentStyle.Color ?? Color;
BackgroundColor = parentStyle.BackgroundColor ?? BackgroundColor;
FontFamily = parentStyle.FontFamily ?? FontFamily;
Size = parentStyle.Size ?? Size;
LineHeight = parentStyle.LineHeight ?? LineHeight;
FontWeight = parentStyle.FontWeight ?? FontWeight;
FontPosition = parentStyle.FontPosition ?? FontPosition;
IsItalic = parentStyle.IsItalic ?? IsItalic;
HasStrikethrough = parentStyle.HasStrikethrough ?? HasStrikethrough;
HasUnderline = parentStyle.HasUnderline ?? HasUnderline;
WrapAnywhere = parentStyle.WrapAnywhere ?? WrapAnywhere;
Fallback = parentStyle.Fallback?.Clone() ?? Fallback;
}
internal TextStyle Clone()
{
var clone = (TextStyle)MemberwiseClone();
clone.HasGlobalStyleApplied = false;
clone.Fallback = Fallback?.Clone();
return clone;
}
} }
} }
+248
View File
@@ -0,0 +1,248 @@
using System;
using System.Collections.Concurrent;
using QuestPDF.Fluent;
namespace QuestPDF.Infrastructure
{
internal enum TextStyleProperty
{
Color,
BackgroundColor,
FontFamily,
Size,
LineHeight,
FontWeight,
FontPosition,
IsItalic,
HasStrikethrough,
HasUnderline,
WrapAnywhere,
Fallback
}
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.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 };
}
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.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;
}
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ namespace QuestPDF.Previewer
public event Action? OnPreviewerStopped; public event Action? OnPreviewerStopped;
private const int RequiredPreviewerVersionMajor = 2022; private const int RequiredPreviewerVersionMajor = 2022;
private const int RequiredPreviewerVersionMinor = 8; private const int RequiredPreviewerVersionMinor = 9;
public PreviewerService(int port) public PreviewerService(int port)
{ {
+1 -1
View File
@@ -3,7 +3,7 @@
<Authors>MarcinZiabek</Authors> <Authors>MarcinZiabek</Authors>
<Company>CodeFlint</Company> <Company>CodeFlint</Company>
<PackageId>QuestPDF</PackageId> <PackageId>QuestPDF</PackageId>
<Version>2022.8.2</Version> <Version>2022.9.0</Version>
<PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription> <PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
<PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt"))</PackageReleaseNotes> <PackageReleaseNotes>$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)/Resources/ReleaseNotes.txt"))</PackageReleaseNotes>
<LangVersion>9</LangVersion> <LangVersion>9</LangVersion>
+6 -20
View File
@@ -1,20 +1,6 @@
2022.8.0: 2022.9.0
- Implemented font-fallback algorithm,
- Improved library performance, - Introduced new Settings API,
- Breaking change: changed default font from Calibri to an open-source Lato, - Significantly reduced memory allocation cost for TextStyle objects,
- Default font files are included with the nuget package, making it safe to deploy on any environment, - Implemented optional checking if all font glyphs are available,
- Default font files are significantly smaller, so output document files should be smaller too (up to 20x reduction in size), - Minor text-rendering optimizations.
- When requested font is not available on the runtime environment, library provides list of available fonts,
- Fixed a rare layout overflow exception with the Inlined element,
- Fixed a memory leak connected to the HarfBuzz library.
2022.8.1:
- Fixed: default text style does not always work
- Fixed: page breaking rendering does not work in very specific corner cases
- Stability improvements for text wrapping
- Updated stability of rendering elements in negative space
- Optimization for the Column element: do not measure child when available height is negative
2022.8.2
- Fixed: the Column element incorrectly renders zero-height elements.
+2 -2
View File
@@ -3,7 +3,7 @@
public static class Settings public static class Settings
{ {
/// <summary> /// <summary>
/// This value represents the maximum lenght of the document that the library produces. /// This value represents the maximum length of the document that the library produces.
/// This is useful when layout constraints are too strong, e.g. one element does not fit in another. /// This is useful when layout constraints are too strong, e.g. one element does not fit in another.
/// In such cases, the library would produce document of infinite length, consuming all available resources. /// In such cases, the library would produce document of infinite length, consuming all available resources.
/// To break the algorithm and save the environment, the library breaks the rendering process after reaching specified length of document. /// To break the algorithm and save the environment, the library breaks the rendering process after reaching specified length of document.
@@ -35,6 +35,6 @@
/// However, it provides hints that used fonts are not sufficient to produce correct results. /// However, it provides hints that used fonts are not sufficient to produce correct results.
/// </summary> /// </summary>
/// <remarks>By default, this flag is enabled only when the debugger IS attached.</remarks> /// <remarks>By default, this flag is enabled only when the debugger IS attached.</remarks>
public static bool CheckIfAllTextGlyphsAreAvailableInSpecifiedFont { get; set; } = System.Diagnostics.Debugger.IsAttached; public static bool CheckIfAllTextGlyphsAreAvailable { get; set; } = System.Diagnostics.Debugger.IsAttached;
} }
} }
+2 -1
View File
@@ -23,7 +23,8 @@ Choosing a project dependency could be difficult. We need to ensure stability an
⭐ Please give this repository a star. It takes seconds and help thousands of developers! ⭐ ⭐ Please give this repository a star. It takes seconds and help thousands of developers! ⭐
<img src="https://user-images.githubusercontent.com/9263853/184642026-27dd7567-a46a-45d4-9594-e6a70a7193e9.png" width="700" /> <img src="https://user-images.githubusercontent.com/9263853/190931857-8ca52ec8-cc7d-4d12-9467-4442b3342fa1.png" width="700" />
## Please share with the community ## Please share with the community