From e279819fcc03cc826b9985b814827316e5f8f530 Mon Sep 17 00:00:00 2001 From: Stepami Date: Sun, 21 Dec 2025 17:40:11 +0300 Subject: [PATCH 1/6] comment gitversion.msbuild --- src/Directory.Build.props | 4 +- src/Directory.Packages.props | 76 +++++++++---------- .../MigraDoc.GrammarByExample-GDI.csproj | 4 +- .../Internal/PdfSharpGitVersionInformation.cs | 20 ++--- 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ec393bfd..9f786e55 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -41,9 +41,9 @@ - + diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index b3272e12..e33e982b 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -1,39 +1,39 @@ - - - - 8.0.1 - 8.0.1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + 8.0.1 + 8.0.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-GDI/MigraDoc.GrammarByExample-GDI.csproj b/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-GDI/MigraDoc.GrammarByExample-GDI.csproj index 60749bf9..d163f31a 100644 --- a/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-GDI/MigraDoc.GrammarByExample-GDI.csproj +++ b/src/foundation/src/MigraDoc/tests/MigraDoc.GrammarByExample-GDI/MigraDoc.GrammarByExample-GDI.csproj @@ -93,9 +93,9 @@ - + diff --git a/src/foundation/src/shared/src/PdfSharp.Shared/Internal/PdfSharpGitVersionInformation.cs b/src/foundation/src/shared/src/PdfSharp.Shared/Internal/PdfSharpGitVersionInformation.cs index 4a52820a..de0498fa 100644 --- a/src/foundation/src/shared/src/PdfSharp.Shared/Internal/PdfSharpGitVersionInformation.cs +++ b/src/foundation/src/shared/src/PdfSharp.Shared/Internal/PdfSharpGitVersionInformation.cs @@ -1,6 +1,8 @@ // PDFsharp - A .NET library for processing PDF // See the LICENSE file in the solution root for more information. +using System.Globalization; + namespace PdfSharp.Internal { /// @@ -11,46 +13,46 @@ public static class PdfSharpGitVersionInformation /// /// The major version number of the product. /// - public static string Major = global::GitVersionInformation.Major; + public static string Major = "1";//global::GitVersionInformation.Major; /// /// The minor version number of the product. /// - public static string Minor = global::GitVersionInformation.Minor; + public static string Minor = "1";//global::GitVersionInformation.Minor; /// /// The patch number of the product. /// - public static string Patch = global::GitVersionInformation.Patch; + public static string Patch = "1";//global::GitVersionInformation.Patch; /// /// The Version pre-release string for NuGet. /// - public static string PreReleaseLabel = global::GitVersionInformation.PreReleaseLabel; + public static string PreReleaseLabel = string.Empty;//global::GitVersionInformation.PreReleaseLabel; /// /// The full version number. /// - public static string MajorMinorPatch = global::GitVersionInformation.MajorMinorPatch; + public static string MajorMinorPatch = "1.1.1";//global::GitVersionInformation.MajorMinorPatch; /// /// The full semantic version number created by GitVersion. /// - public static string SemVer = global::GitVersionInformation.SemVer; + public static string SemVer = "1.1.1";//global::GitVersionInformation.SemVer; /// /// The full informational version number created by GitVersion. /// - public static string InformationalVersion = global::GitVersionInformation.InformationalVersion; + public static string InformationalVersion = "1.1.1";//global::GitVersionInformation.InformationalVersion; /// /// The branch name of the product. /// - public static string BranchName = global::GitVersionInformation.BranchName; + public static string BranchName = "refactoring/locks";//global::GitVersionInformation.BranchName; /// /// The commit date of the product. /// - public static string CommitDate = global::GitVersionInformation.CommitDate; + public static string CommitDate = DateTime.Today.ToString(CultureInfo.InvariantCulture);//global::GitVersionInformation.CommitDate; } } From 8ff516552a1533f1a6995d5a1b041cb859ebf038 Mon Sep 17 00:00:00 2001 From: Stepami Date: Sun, 21 Dec 2025 17:40:31 +0300 Subject: [PATCH 2/6] new benchmark project --- PdfSharp.sln | 7 +++++++ src/Directory.Packages.props | 8 +------- .../PdfSharp.Benchmarks.csproj | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp.Benchmarks/PdfSharp.Benchmarks.csproj diff --git a/PdfSharp.sln b/PdfSharp.sln index 3c82ce5b..b3c3ef98 100644 --- a/PdfSharp.sln +++ b/PdfSharp.sln @@ -274,6 +274,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "docs-dummy", "docs\docs-dum EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PdfSharp.Cryptography", "src\foundation\src\PDFsharp\src\PdfSharp.Cryptography\PdfSharp.Cryptography.csproj", "{769ED050-15AF-4EB5-A89F-D7123EE5AA95}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PdfSharp.Benchmarks", "src\foundation\src\PDFsharp\src\PdfSharp.Benchmarks\PdfSharp.Benchmarks.csproj", "{24B3A17B-FDEE-496B-A2F4-A5F35127CCCF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -568,6 +570,10 @@ Global {769ED050-15AF-4EB5-A89F-D7123EE5AA95}.Debug|Any CPU.Build.0 = Debug|Any CPU {769ED050-15AF-4EB5-A89F-D7123EE5AA95}.Release|Any CPU.ActiveCfg = Release|Any CPU {769ED050-15AF-4EB5-A89F-D7123EE5AA95}.Release|Any CPU.Build.0 = Release|Any CPU + {24B3A17B-FDEE-496B-A2F4-A5F35127CCCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {24B3A17B-FDEE-496B-A2F4-A5F35127CCCF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {24B3A17B-FDEE-496B-A2F4-A5F35127CCCF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {24B3A17B-FDEE-496B-A2F4-A5F35127CCCF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -675,6 +681,7 @@ Global {F4AB506C-AD13-4383-9AF9-48D74085ECC1} = {7C753636-7947-46E0-95E0-135EAA7BFEB3} {76B94284-402D-4951-8DA4-7FFAF15E6C95} = {76BA9372-65AE-479C-AEF7-D50E6B486CEF} {769ED050-15AF-4EB5-A89F-D7123EE5AA95} = {7C753636-7947-46E0-95E0-135EAA7BFEB3} + {24B3A17B-FDEE-496B-A2F4-A5F35127CCCF} = {7C753636-7947-46E0-95E0-135EAA7BFEB3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D5FF5562-3C79-434B-B951-B84542D01625} diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index e33e982b..263878e5 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -4,19 +4,16 @@ 8.0.1 8.0.1 - - + - - @@ -26,14 +23,11 @@ - - - \ No newline at end of file diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.Benchmarks/PdfSharp.Benchmarks.csproj b/src/foundation/src/PDFsharp/src/PdfSharp.Benchmarks/PdfSharp.Benchmarks.csproj new file mode 100644 index 00000000..78d935f7 --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp.Benchmarks/PdfSharp.Benchmarks.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + NETSDK1138 + + + + + + + + + + + From b496d2e2af42e95ccb72ff52ce29ddc7fd80f3e4 Mon Sep 17 00:00:00 2001 From: Stepami Date: Sun, 21 Dec 2025 17:40:52 +0300 Subject: [PATCH 3/6] visibility --- .../PDFsharp/src/PdfSharp/Fonts.OpenType/FontDescriptor.cs | 2 +- .../src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCache.cs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/FontDescriptor.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/FontDescriptor.cs index c481dc50..21aabcaa 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/FontDescriptor.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts.OpenType/FontDescriptor.cs @@ -22,7 +22,7 @@ namespace PdfSharp.Fonts.OpenType /// Base class for all font descriptors. /// Currently only OpenTypeDescriptor is derived from this base class. /// - class FontDescriptor + public class FontDescriptor { protected FontDescriptor(string key) { diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCache.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCache.cs index 19007492..0711a40f 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCache.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCache.cs @@ -3,14 +3,13 @@ using PdfSharp.Drawing; using PdfSharp.Fonts.OpenType; -using PdfSharp.Internal; namespace PdfSharp.Fonts { /// /// Global table of OpenType font descriptor objects. /// - static class FontDescriptorCache + public static class FontDescriptorCache { /// /// Gets the FontDescriptor identified by the specified XFont. If no such object @@ -88,7 +87,7 @@ public static FontDescriptor GetOrCreateDescriptor(string fontFamilyName, XFontS finally { Locks.ExitFontFactory(); } } - internal static void Reset() + public static void Reset() { Globals.Global.Fonts.FontDescriptorCache.Clear(); } From b1bb7ed3de84152b20ec3a19be25e1c9c2b33523 Mon Sep 17 00:00:00 2001 From: Stepami Date: Sun, 21 Dec 2025 17:41:00 +0300 Subject: [PATCH 4/6] v2 cache --- .../PdfSharp/Fonts/FontDescriptorCacheV2.cs | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCacheV2.cs diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCacheV2.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCacheV2.cs new file mode 100644 index 00000000..1e62b8e9 --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCacheV2.cs @@ -0,0 +1,96 @@ +// PDFsharp - A .NET library for processing PDF +// See the LICENSE file in the solution root for more information. + +using System.Collections.Concurrent; +using PdfSharp.Drawing; +using PdfSharp.Fonts.OpenType; + +namespace PdfSharp.Fonts +{ + /// + /// Global table of OpenType font descriptor objects. + /// + public static class FontDescriptorCacheV2 + { + /// + /// Gets the FontDescriptor identified by the specified XFont. If no such object + /// exists, a new FontDescriptor is created and added to the cache. + /// + public static FontDescriptor GetOrCreateDescriptorFor(XFont font) + { + if (font == null) + throw new ArgumentNullException(nameof(font)); + + font.GlyphTypeface.CheckVersion(); + + //FontSelector1 selector = new FontSelector1(font); + string fontDescriptorKey = font.GlyphTypeface.Key; + var cache = Globals.Global.Fonts.FontDescriptorCacheV2; + if (cache.TryGetValue(fontDescriptorKey, out var descriptor)) + return descriptor; + + descriptor = new OpenTypeDescriptor(fontDescriptorKey, font); + cache.TryAdd(fontDescriptorKey, descriptor); + return descriptor; + } + + public static FontDescriptor GetOrCreateDescriptorFor(XGlyphTypeface glyphTypeface) + { + glyphTypeface.CheckVersion(); + + string fontDescriptorKey = glyphTypeface.Key; + var cache = Globals.Global.Fonts.FontDescriptorCacheV2; + if (cache.TryGetValue(fontDescriptorKey, out var descriptor)) + return descriptor; + + descriptor = new OpenTypeDescriptor(fontDescriptorKey, glyphTypeface); + cache.TryAdd(fontDescriptorKey, descriptor); + return descriptor; + } + + /// + /// Gets the FontDescriptor identified by the specified FontSelector. If no such object + /// exists, a new FontDescriptor is created and added to the stock. + /// + public static FontDescriptor GetOrCreateDescriptor(string fontFamilyName, XFontStyleEx style) + { + if (String.IsNullOrEmpty(fontFamilyName)) + throw new ArgumentNullException(nameof(fontFamilyName)); + + //FontSelector1 selector = new FontSelector1(fontFamilyName, style); + string fontDescriptorKey = FontDescriptor.ComputeFdKey(fontFamilyName, style); + var cache = Globals.Global.Fonts.FontDescriptorCache; + Locks.EnterFontFactory(); + if (!cache.TryGetValue(fontDescriptorKey, out var descriptor)) + { + var font = new XFont(fontFamilyName, 10, style); + descriptor = GetOrCreateDescriptorFor(font); + // ReSharper disable once CanSimplifyDictionaryLookupWithTryAdd because there is not TryAdd in .NET Framework + if (cache.ContainsKey(fontDescriptorKey)) + _ = typeof(int); // Just a NOP for a break point. + else + cache.Add(fontDescriptorKey, descriptor); + } + return descriptor; + } + + public static void Reset() + { + Globals.Global.Fonts.FontDescriptorCacheV2.Clear(); + } + } +} + +namespace PdfSharp.Internal +{ + partial class Globals + { + partial class FontStorage + { + /// + /// Maps font descriptor key to font descriptor which is currently only an OpenTypeFontDescriptor. + /// + public readonly ConcurrentDictionary FontDescriptorCacheV2 = []; + } + } +} From 0e0b5996f5df49f875c0c6c095dc5de4d80c1d59 Mon Sep 17 00:00:00 2001 From: Stepami Date: Sun, 21 Dec 2025 17:41:05 +0300 Subject: [PATCH 5/6] benchmark --- .../src/PdfSharp.Benchmarks/Program.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/foundation/src/PDFsharp/src/PdfSharp.Benchmarks/Program.cs diff --git a/src/foundation/src/PDFsharp/src/PdfSharp.Benchmarks/Program.cs b/src/foundation/src/PDFsharp/src/PdfSharp.Benchmarks/Program.cs new file mode 100644 index 00000000..087d2d16 --- /dev/null +++ b/src/foundation/src/PDFsharp/src/PdfSharp.Benchmarks/Program.cs @@ -0,0 +1,53 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Engines; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Running; +using PdfSharp.Drawing; +using PdfSharp.Fonts; + +BenchmarkRunner.Run(); + +[SimpleJob(RuntimeMoniker.Net80)] +public class FontCacheBenchmarks +{ + private static readonly XGlyphTypeface GlyphTypeface = new( + XFontSource.CreateFromFile(@"C:\Windows\Fonts\arial.ttf")); + private static readonly Consumer Consumer = new(); + + [Params(1, 10, 100)] + public int Iterations { get; set; } + + [GlobalSetup] + public void GlobalSetup() + { + FontDescriptorCache.Reset(); + FontDescriptorCacheV2.Reset(); + } + + [GlobalCleanup] + public void GlobalCleanup() + { + FontDescriptorCache.Reset(); + FontDescriptorCacheV2.Reset(); + } + + [Benchmark(Baseline = true)] + public void LockFactory() + { + for (var i = 0; i < Iterations; i++) + { + Consumer.Consume( + FontDescriptorCache.GetOrCreateDescriptorFor(GlyphTypeface)); + } + } + + [Benchmark] + public void ConcurrentDictionary() + { + for (var i = 0; i < Iterations; i++) + { + Consumer.Consume( + FontDescriptorCacheV2.GetOrCreateDescriptorFor(GlyphTypeface)); + } + } +} \ No newline at end of file From 5099abc7338e9eed379ee528d1f285d78e0ed42c Mon Sep 17 00:00:00 2001 From: Stepami Date: Sun, 21 Dec 2025 17:43:13 +0300 Subject: [PATCH 6/6] fix v2 cache --- .../src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCacheV2.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCacheV2.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCacheV2.cs index 1e62b8e9..e1ba03e4 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCacheV2.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Fonts/FontDescriptorCacheV2.cs @@ -59,8 +59,7 @@ public static FontDescriptor GetOrCreateDescriptor(string fontFamilyName, XFontS //FontSelector1 selector = new FontSelector1(fontFamilyName, style); string fontDescriptorKey = FontDescriptor.ComputeFdKey(fontFamilyName, style); - var cache = Globals.Global.Fonts.FontDescriptorCache; - Locks.EnterFontFactory(); + var cache = Globals.Global.Fonts.FontDescriptorCacheV2; if (!cache.TryGetValue(fontDescriptorKey, out var descriptor)) { var font = new XFont(fontFamilyName, 10, style); @@ -69,7 +68,7 @@ public static FontDescriptor GetOrCreateDescriptor(string fontFamilyName, XFontS if (cache.ContainsKey(fontDescriptorKey)) _ = typeof(int); // Just a NOP for a break point. else - cache.Add(fontDescriptorKey, descriptor); + cache.TryAdd(fontDescriptorKey, descriptor); } return descriptor; }