Compare commits

..

6 Commits

Author SHA1 Message Date
MarcinZiabek e01835cc55 Minor code refactoring 2023-04-22 09:52:33 +02:00
MarcinZiabek fdc395f956 Bug fixes + test 2023-04-21 09:22:14 +02:00
MarcinZiabek bd4aac0594 FontStyle: making method arguments explicit 2023-04-19 22:57:16 +02:00
MarcinZiabek f79bd1db62 Code refactoring 2023-04-19 22:51:59 +02:00
MarcinZiabek 8cec0059d8 Fixed applying text style for fallback styles 2023-04-19 20:25:58 +02:00
MarcinZiabek ef89be9710 Improvement: updated the CreateNotMatchingFontException text to mention that glyph checking operation can be disabled with the Settings.CheckIfAllTextGlyphsAreAvailable setting 2023-04-17 02:15:19 +02:00
17 changed files with 181 additions and 388 deletions
+31 -15
View File
@@ -1,12 +1,10 @@
using System;
using System.IO;
using System.Linq;
using NUnit.Framework;
using QuestPDF.Drawing.Exceptions;
using QuestPDF.Examples.Engine;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.Examples
{
@@ -66,24 +64,42 @@ namespace QuestPDF.Examples
});
}
[Test]
public void ImageResolutionScaling()
public void ReusingTheSameImageFileShouldBePossible()
{
var image = Image.FromFile("large-image.jpg");
var fileName = Path.GetTempFileName() + ".jpg";
Document
.Create(document =>
{
document.Page(page =>
try
{
var image = Placeholders.Image(300, 100);
using var file = File.Create(fileName);
file.Write(image);
file.Dispose();
RenderingTest
.Create()
.ProducePdf()
.PageSize(PageSizes.A4)
.ShowResults()
.Render(container =>
{
page.Size(210, 210);
page.Margin(50);
page.Content().Image(image);
container
.Padding(20)
.Column(column =>
{
column.Spacing(20);
column.Item().Image(fileName);
column.Item().Image(fileName);
column.Item().Image(fileName);
});
});
})
.GeneratePdf($"test.pdf");
}
finally
{
File.Delete(fileName);
}
}
}
}
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
@@ -32,12 +32,6 @@
<None Update="pdf-icon.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="large-image.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="large-image.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
+35
View File
@@ -1004,5 +1004,40 @@ namespace QuestPDF.Examples
});
});
}
[Test]
public void FontFallback_Nested()
{
RenderingTest
.Create()
.ProduceImages()
.ShowResults()
.RenderDocument(container =>
{
container.Page(page =>
{
page.Margin(50);
page.PageColor(Colors.White);
page.Size(PageSizes.A5.Landscape());
page.DefaultTextStyle(x => x
.FontSize(24)
.Bold()
.FontFamily("Times New Roman")
.Fallback(y => y
.FontFamily("Microsoft YaHei")
.Underline()
.BackgroundColor(Colors.Red.Lighten2)));
page.Content().Text(text =>
{
text.Line("Default times new roman 中文文本 text.");
text.Line("Normal weight and green 中文文本 text.").NormalWeight().BackgroundColor(Colors.Green.Lighten2);
text.Line("Strikethrough without underline 中文文本 text.").Strikethrough().Underline(false);
text.Line("Lato italic 中文文本 text.").FontFamily("Lato").Italic();
});
});
});
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

+5 -73
View File
@@ -1,16 +1,10 @@
using System;
using System.Linq;
using System.Net.Mime;
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
using SkiaSharp;
using Image = QuestPDF.Infrastructure.Image;
namespace QuestPDF.UnitTests
{
@@ -21,9 +15,9 @@ namespace QuestPDF.UnitTests
public void Measure_TakesAvailableSpaceRegardlessOfSize()
{
TestPlan
.For(x => new QuestPDF.Elements.Image
.For(x => new Image
{
DocumentImage = Image.FromSkImage(GenerateImage(400, 300))
InternalImage = GenerateImage(400, 300)
})
.MeasureElement(new Size(300, 200))
.CheckMeasureResult(SpacePlan.FullRender(300, 200));
@@ -33,9 +27,9 @@ namespace QuestPDF.UnitTests
public void Draw_TakesAvailableSpaceRegardlessOfSize()
{
TestPlan
.For(x => new QuestPDF.Elements.Image
.For(x => new Image
{
DocumentImage = Image.FromSkImage(GenerateImage(400, 300))
InternalImage = GenerateImage(400, 300)
})
.DrawElement(new Size(300, 200))
.ExpectCanvasDrawImage(new Position(0, 0), new Size(300, 200))
@@ -57,52 +51,6 @@ namespace QuestPDF.UnitTests
.MeasureElement(new Size(300, 200))
.CheckMeasureResult(SpacePlan.FullRender(300, 100));;
}
[Test]
public void UsingSharedImageShouldNotDrasticallyIncreaseDocumentSize()
{
var placeholderImage = Placeholders.Image(1000, 200);
var documentWithSingleImageSize = GetDocumentSize(container =>
{
container.Image(placeholderImage);
});
var documentWithMultipleImagesSize = GetDocumentSize(container =>
{
container.Column(column =>
{
foreach (var i in Enumerable.Range(0, 100))
column.Item().Image(placeholderImage);
});
});
var documentWithSingleImageUsedMultipleTimesSize = GetDocumentSize(container =>
{
container.Column(column =>
{
var sharedImage = Image.FromBinaryData(placeholderImage).DisposeAfterDocumentGeneration();
foreach (var i in Enumerable.Range(0, 100))
column.Item().Image(sharedImage);
});
});
(documentWithMultipleImagesSize / (float)documentWithSingleImageSize).Should().BeInRange(90, 100);
(documentWithSingleImageUsedMultipleTimesSize / (float)documentWithSingleImageSize).Should().BeInRange(1f, 1.5f);
}
[Test]
public void ImageShouldNotBeScaledAboveItsNativeResolution()
{
var image = Placeholders.Image(200, 200);
var documentSizeWithScaledDownImage = GetDocumentSize(container => container.Width(100).Height(100).Image(Image.FromBinaryData(image)));
//var documentSizeWithNormalImage = GetDocumentSize(container => container.Width(200).Height(200).Image(image));
//var documentSizeWithScaledUpImage = GetDocumentSize(container => container.Width(400).Height(400).Image(image));
}
#region helpers
SKImage GenerateImage(int width, int height)
{
@@ -110,21 +58,5 @@ namespace QuestPDF.UnitTests
using var surface = SKSurface.Create(imageInfo);
return surface.Snapshot();
}
private static int GetDocumentSize(Action<IContainer> container)
{
return Document
.Create(document =>
{
document.Page(page =>
{
page.Content().Element(container);
});
})
.GeneratePdf()
.Length;
}
#endregion
}
}
@@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<LangVersion>9</LangVersion>
</PropertyGroup>
<ItemGroup>
@@ -0,0 +1,59 @@
using FluentAssertions;
using NUnit.Framework;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class TextStyleTests
{
[Test]
public void ApplyInheritedAndGlobalStyle()
{
// arrange
var defaultTextStyle = TextStyle
.Default
.FontSize(20)
.FontFamily("Arial")
.BackgroundColor(Colors.Green.Lighten2)
.Fallback(y => y
.FontFamily("Microsoft YaHei")
.Underline()
.NormalWeight()
.BackgroundColor(Colors.Blue.Lighten2));
var spanTextStyle = TextStyle
.Default
.FontFamily("Times New Roman")
.Bold()
.Strikethrough()
.BackgroundColor(Colors.Red.Lighten2);
// act
var targetStyle = spanTextStyle.ApplyInheritedStyle(defaultTextStyle).ApplyGlobalStyle();
// assert
var expectedStyle = TextStyle.LibraryDefault with
{
Size = 20,
FontFamily = "Times New Roman",
FontWeight = FontWeight.Bold,
BackgroundColor = Colors.Red.Lighten2,
HasStrikethrough = true,
Fallback = TextStyle.LibraryDefault with
{
Size = 20,
FontFamily = "Microsoft YaHei",
FontWeight = FontWeight.Bold,
BackgroundColor = Colors.Red.Lighten2,
HasUnderline = true,
HasStrikethrough = true
}
};
targetStyle.Should().BeEquivalentTo(expectedStyle);
}
}
}
+14 -32
View File
@@ -10,7 +10,6 @@ using QuestPDF.Elements.Text.Items;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using Image = QuestPDF.Elements.Image;
namespace QuestPDF.Drawing
{
@@ -22,7 +21,7 @@ namespace QuestPDF.Drawing
var metadata = document.GetMetadata();
var canvas = new PdfCanvas(stream, metadata);
RenderDocument(canvas, document, metadata);
RenderDocument(canvas, document);
}
internal static void GenerateXps(Stream stream, IDocument document)
@@ -31,7 +30,7 @@ namespace QuestPDF.Drawing
var metadata = document.GetMetadata();
var canvas = new XpsCanvas(stream, metadata);
RenderDocument(canvas, document, metadata);
RenderDocument(canvas, document);
}
private static void CheckIfStreamIsCompatible(Stream stream)
@@ -47,27 +46,25 @@ namespace QuestPDF.Drawing
{
var metadata = document.GetMetadata();
var canvas = new ImageCanvas(metadata);
RenderDocument(canvas, document, metadata);
RenderDocument(canvas, document);
return canvas.Images;
}
internal static ICollection<PreviewerPicture> GeneratePreviewerPictures(IDocument document)
{
var metadata = document.GetMetadata();
var canvas = new SkiaPictureCanvas();
RenderDocument(canvas, document, metadata);
RenderDocument(canvas, document);
return canvas.Pictures;
}
internal static void RenderDocument<TCanvas>(TCanvas canvas, IDocument document, DocumentMetadata metadata)
internal static void RenderDocument<TCanvas>(TCanvas canvas, IDocument document)
where TCanvas : ICanvas, IRenderingCanvas
{
var container = new DocumentContainer();
document.Compose(container);
var content = container.Compose();
ApplyDefaultImageDpi(content, metadata.RasterDpi, metadata.ImageQuality);
ApplyDefaultTextStyle(content, TextStyle.LibraryDefault);
ApplyInheritedAndGlobalTexStyle(content, TextStyle.Default);
ApplyContentDirection(content, ContentDirection.LeftToRight);
var debuggingState = Settings.EnableDebugging ? ApplyDebugging(content) : null;
@@ -176,18 +173,6 @@ namespace QuestPDF.Drawing
return debuggingState;
}
internal static void ApplyDefaultImageDpi(this Element? content, int targetDpi, int targetImageQuality)
{
content.VisitChildren(x =>
{
if (x is not Image { DocumentImage: { } image })
return;
image.TargetDpi ??= targetDpi;
image.ImageQuality ??= targetImageQuality;
});
}
internal static void ApplyContentDirection(this Element? content, ContentDirection direction)
{
@@ -207,7 +192,7 @@ namespace QuestPDF.Drawing
ApplyContentDirection(child, direction);
}
internal static void ApplyDefaultTextStyle(this Element? content, TextStyle documentDefaultTextStyle)
internal static void ApplyInheritedAndGlobalTexStyle(this Element? content, TextStyle documentDefaultTextStyle)
{
if (content == null)
return;
@@ -217,26 +202,23 @@ namespace QuestPDF.Drawing
foreach (var textBlockItem in textBlock.Items)
{
if (textBlockItem is TextBlockSpan textSpan)
{
textSpan.Style = textSpan.Style.ApplyGlobalStyle(documentDefaultTextStyle);
}
else if (textBlockItem is TextBlockElement textElement)
{
ApplyDefaultTextStyle(textElement.Element, documentDefaultTextStyle);
}
textSpan.Style = textSpan.Style.ApplyInheritedStyle(documentDefaultTextStyle).ApplyGlobalStyle();
if (textBlockItem is TextBlockElement textElement)
ApplyInheritedAndGlobalTexStyle(textElement.Element, documentDefaultTextStyle);
}
return;
}
if (content is DynamicHost dynamicHost)
dynamicHost.TextStyle = dynamicHost.TextStyle.ApplyGlobalStyle(documentDefaultTextStyle);
dynamicHost.TextStyle = dynamicHost.TextStyle.ApplyInheritedStyle(documentDefaultTextStyle);
if (content is DefaultTextStyle defaultTextStyleElement)
documentDefaultTextStyle = defaultTextStyleElement.TextStyle.ApplyGlobalStyle(documentDefaultTextStyle);
documentDefaultTextStyle = defaultTextStyleElement.TextStyle.ApplyInheritedStyle(documentDefaultTextStyle);
foreach (var child in content.GetChildren())
ApplyDefaultTextStyle(child, documentDefaultTextStyle);
ApplyInheritedAndGlobalTexStyle(child, documentDefaultTextStyle);
}
}
}
+1 -3
View File
@@ -5,10 +5,8 @@ namespace QuestPDF.Drawing
{
public class DocumentMetadata
{
public const int DefaultPdfDpi = 72;
public int ImageQuality { get; set; } = 101;
public int RasterDpi { get; set; } = DefaultPdfDpi;
public int RasterDpi { get; set; } = 72;
public bool PdfA { get; set; }
public string? Title { get; set; }
+1 -1
View File
@@ -89,7 +89,7 @@ namespace QuestPDF.Elements
var container = new DynamicElement();
content(container);
container.ApplyDefaultTextStyle(TextStyle);
container.ApplyInheritedAndGlobalTexStyle(TextStyle);
container.ApplyContentDirection(ContentDirection);
container.InjectDependencies(PageContext, Canvas);
+4 -5
View File
@@ -7,12 +7,11 @@ namespace QuestPDF.Elements
{
internal class Image : Element, ICacheable
{
public Infrastructure.Image? DocumentImage { get; set; }
public SKImage? InternalImage { get; set; }
~Image()
{
if (DocumentImage is { IsDocumentScoped: true })
DocumentImage?.Dispose();
InternalImage?.Dispose();
}
internal override SpacePlan Measure(Size availableSpace)
@@ -24,10 +23,10 @@ namespace QuestPDF.Elements
internal override void Draw(Size availableSpace)
{
if (DocumentImage == null)
if (InternalImage == null)
return;
Canvas.DrawImage(DocumentImage.GetVersionOfSize(availableSpace), Position.Zero, availableSpace);
Canvas.DrawImage(InternalImage, Position.Zero, availableSpace);
}
}
}
@@ -105,7 +105,9 @@ namespace QuestPDF.Elements.Text
$"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. ");
$"2) Configure the fallback TextStyle using the 'TextStyle.Fallback' method with one of the listed fonts. " +
$"You can disable this check by setting the 'Settings.CheckIfAllTextGlyphsAreAvailable' option to 'false'. " +
$"However, this may result with text glyphs being incorrectly rendered without any warning.");
}
static IEnumerable<string> FindFontsContainingGlyph(int codepoint)
+7 -6
View File
@@ -3,6 +3,7 @@ using System.IO;
using QuestPDF.Drawing.Exceptions;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.Fluent
{
@@ -10,30 +11,30 @@ namespace QuestPDF.Fluent
{
public static void Image(this IContainer parent, byte[] imageData, ImageScaling scaling = ImageScaling.FitWidth)
{
var image = Infrastructure.Image.FromBinaryData(imageData).DisposeAfterDocumentGeneration();
var image = SKImage.FromEncodedData(imageData);
parent.Image(image, scaling);
}
public static void Image(this IContainer parent, string filePath, ImageScaling scaling = ImageScaling.FitWidth)
{
var image = Infrastructure.Image.FromFile(filePath).DisposeAfterDocumentGeneration();
var image = SKImage.FromEncodedData(filePath);
parent.Image(image, scaling);
}
public static void Image(this IContainer parent, Stream fileStream, ImageScaling scaling = ImageScaling.FitWidth)
{
var image = Infrastructure.Image.FromStream(fileStream).DisposeAfterDocumentGeneration();
var image = SKImage.FromEncodedData(fileStream);
parent.Image(image, scaling);
}
public static void Image(this IContainer parent, Infrastructure.Image image, ImageScaling scaling = ImageScaling.FitWidth)
private static void Image(this IContainer parent, SKImage image, ImageScaling scaling = ImageScaling.FitWidth)
{
if (image == null)
throw new DocumentComposeException("Cannot load or decode provided image.");
var imageElement = new QuestPDF.Elements.Image
var imageElement = new Image
{
DocumentImage = image
InternalImage = image
};
if (scaling != ImageScaling.Resize)
-181
View File
@@ -1,181 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using QuestPDF.Drawing;
using QuestPDF.Drawing.Exceptions;
using SkiaSharp;
namespace QuestPDF.Infrastructure
{
public class Image : IDisposable
{
private SKImage SkImage { get; }
internal List<(Size size, SKImage image)>? ScaledImageCache { get; set; }
internal int? TargetDpi { get; set; }
internal int? ImageQuality { get; set; }
internal bool PerformScalingToTargetDpi { get; set; }
internal bool IsDocumentScoped { get; set; }
public int Width => SkImage.Width;
public int Height => SkImage.Height;
private const float ImageSizeSimilarityToleranceMax = 1.1f;
private const float ImageSizeSimilarityToleranceMin = 1 / ImageSizeSimilarityToleranceMax;
private Image(SKImage image)
{
SkImage = image;
PerformScalingToTargetDpi = image.EncodedData.Size >= Settings.AdjustImageSizeThreshold;
}
public void Dispose()
{
SkImage.Dispose();
ScaledImageCache?.ForEach(x => x.image.Dispose());
}
internal SKImage GetVersionOfSize(Size size)
{
if (!PerformScalingToTargetDpi)
return SkImage;
var scalingFactor = TargetDpi.Value / (float)DocumentMetadata.DefaultPdfDpi;
var targetResolution = new Size(size.Width * scalingFactor, size.Height * scalingFactor);
if (targetResolution.Width > Width || targetResolution.Height > Height)
return SkImage;
ScaledImageCache ??= new List<(Size size, SKImage image)>();
foreach (var imageCache in ScaledImageCache)
{
if (HasSimilarSize(imageCache.size, targetResolution))
return imageCache.image;
}
var scaledImage = ScaleImage(SkImage, targetResolution, ImageQuality);
ScaledImageCache.Add((targetResolution, scaledImage));
if (SkImage.EncodedData.Size < scaledImage.EncodedData.Size)
return SkImage;
return scaledImage;
static SKImage ScaleImage(SKImage originalImage, Size targetSize, int? imageQuality)
{
var imageInfo = new SKImageInfo((int)targetSize.Width, (int)targetSize.Height);
using var target = SKImage.Create(imageInfo);
originalImage.ScalePixels(target.PeekPixels(), SKFilterQuality.High);
var codes = SKCodec.Create(target.EncodedData);
var targetFormat = imageQuality > 100 ? SKEncodedImageFormat.Png : SKEncodedImageFormat.Jpeg;
var targetQuality = Math.Max(imageQuality, 100);
var data = target.Encode(targetFormat, targetQuality);
return SKImage.FromEncodedData(data);
}
static (SKEncodedImageFormat format, int quality) GetTargetImageFormat(SKImage originalImage, int? imageQuality)
{
if (imageQuality.HasValue)
{
var format = imageQuality > 100
? SKEncodedImageFormat.Png
: SKEncodedImageFormat.Jpeg;
var quality = Math.Max(imageQuality.Value, 100);
return (format, quality);
}
var codec = SKCodec.Create(originalImage.EncodedData);
}
static bool HasSimilarSize(Size a, Size b)
{
var widthRatio = a.Width / b.Width;
var heightRatio = a.Height / b.Height;
return widthRatio is > ImageSizeSimilarityToleranceMin and < ImageSizeSimilarityToleranceMax &&
heightRatio is > ImageSizeSimilarityToleranceMin and < ImageSizeSimilarityToleranceMax;
}
}
#region public constructors
internal static Image FromSkImage(SKImage image)
{
return CreateImage(image);
}
public static Image FromBinaryData(byte[] imageData)
{
return CreateImage(SKImage.FromEncodedData(imageData));
}
public static Image FromFile(string filePath)
{
return CreateImage(SKImage.FromEncodedData(filePath));
}
public static Image FromStream(Stream fileStream)
{
return CreateImage(SKImage.FromEncodedData(fileStream));
}
private static Image CreateImage(SKImage? image)
{
if (image == null)
throw new DocumentComposeException("Cannot load or decode provided image.");
return new Image(image);
}
#endregion
#region configuration API
public Image DisposeAfterDocumentGeneration()
{
IsDocumentScoped = true;
return this;
}
/// <summary>
/// Values from 1 to 100 correspond to the JPEG format, where 1 is lowest and 100 is highest quality.
/// Value 101 correspond to the PNG format with a lossless compression and alpha channel support.
/// </summary>
/// <param name="quality"></param>
/// <returns></returns>
public Image WithQuality(int quality)
{
ImageQuality = quality;
return this;
}
public Image WithQuality(ImageQuality quality)
{
ImageQuality = (int)quality;
return this;
}
public Image WithTargetDpi(int dpi = DocumentMetadata.DefaultPdfDpi)
{
TargetDpi = dpi;
return this;
}
public Image ScaleToTargetDpi(bool value = true)
{
PerformScalingToTargetDpi = value;
return this;
}
#endregion
}
}
@@ -1,40 +0,0 @@
namespace QuestPDF.Infrastructure
{
public enum ImageQuality
{
/// <summary>
/// PNG format with alpha support
/// </summary>
Lossless = 101,
/// <summary>
/// JPEG format with compression set to 100 out of 100
/// </summary>
Max = 100,
/// <summary>
/// JPEG format with compression set to 90 out of 100
/// </summary>
VeryHigh = 90,
/// <summary>
/// JPEG format with compression set to 80 out of 100
/// </summary>
High = 80,
/// <summary>
/// JPEG format with compression set to 60 out of 100
/// </summary>
Medium = 60,
/// <summary>
/// JPEG format with compression set to 40 out of 100
/// </summary>
Low = 40,
/// <summary>
/// JPEG format with compression set to 20 out of 100
/// </summary>
VeryLow = 20
}
}
@@ -25,16 +25,17 @@ namespace QuestPDF.Infrastructure
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> TextStyleApplyInheritedCache = new();
private static readonly ConcurrentDictionary<TextStyle, 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));
return TextStyleMutateCache.GetOrAdd(cacheKey, x => MutateStyle(x.origin, x.property, x.value, overrideValue: true));
}
private static TextStyle MutateStyle(TextStyle origin, TextStyleProperty property, object? value, bool overrideValue = true)
private static TextStyle MutateStyle(this TextStyle origin, TextStyleProperty property, object? value, bool overrideValue)
{
if (overrideValue && value == null)
return origin;
@@ -224,37 +225,37 @@ namespace QuestPDF.Infrastructure
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)
internal static TextStyle ApplyInheritedStyle(this TextStyle style, TextStyle parent)
{
var cacheKey = (style, parent);
return TextStyleApplyGlobalCache.GetOrAdd(cacheKey, key => ApplyStyle(key.origin, key.parent, overrideStyle: false).ApplyFontFallback());
return TextStyleApplyInheritedCache.GetOrAdd(cacheKey, key => key.origin.ApplyStyleProperties(key.parent, overrideStyle: false, overrideFontFamily: false, applyFallback: true).UpdateFontFallback(overrideStyle: true));
}
private static TextStyle ApplyFontFallback(this TextStyle style)
internal static TextStyle ApplyGlobalStyle(this TextStyle style)
{
return TextStyleApplyGlobalCache.GetOrAdd(style, key => key.ApplyStyleProperties(TextStyle.LibraryDefault, overrideStyle: false, overrideFontFamily: false, applyFallback: true).UpdateFontFallback(overrideStyle: false));
}
private static TextStyle UpdateFontFallback(this TextStyle style, bool overrideStyle)
{
var targetFallbackStyle = style
?.Fallback
?.ApplyStyle(style, overrideStyle: false, applyFallback: false)
?.ApplyFontFallback();
?.ApplyStyleProperties(style, overrideStyle: overrideStyle, overrideFontFamily: false, applyFallback: false)
?.UpdateFontFallback(overrideStyle);
return MutateStyle(style, TextStyleProperty.Fallback, targetFallbackStyle);
return style.MutateStyle(TextStyleProperty.Fallback, targetFallbackStyle, overrideValue: true);
}
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);
});
return TextStyleOverrideCache.GetOrAdd(cacheKey, key => ApplyStyleProperties(key.origin, key.parent, overrideStyle: true, overrideFontFamily: true, applyFallback: true));
}
private static TextStyle ApplyStyle(this TextStyle style, TextStyle parent, bool overrideStyle = true, bool applyFallback = true)
private static TextStyle ApplyStyleProperties(this TextStyle style, TextStyle parent, bool overrideStyle, bool overrideFontFamily, bool applyFallback)
{
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);
-6
View File
@@ -36,11 +36,5 @@
/// </summary>
/// <remarks>By default, this flag is enabled only when the debugger IS attached.</remarks>
public static bool CheckIfAllTextGlyphsAreAvailable { get; set; } = System.Diagnostics.Debugger.IsAttached;
/// <summary>
/// The file size threshold in bytes that is used to determine if the image should be automatically scaled to physical dimensions.
/// </summary>
public static int AdjustImageSizeThreshold { get; set; } = 32 * 1024;
}
}