diff --git a/src/PdfSharp/Drawing/FontHelper.cs b/src/PdfSharp/Drawing/FontHelper.cs index bfd35c92..333670b3 100644 --- a/src/PdfSharp/Drawing/FontHelper.cs +++ b/src/PdfSharp/Drawing/FontHelper.cs @@ -75,18 +75,48 @@ public static XSize MeasureString(string text, XFont font, XStringFormat stringF if (descriptor != null) { // Height is the sum of ascender and descender. - size.Height = (descriptor.Ascender + descriptor.Descender) * font.Size / font.UnitsPerEm; + var singleLineHeight = (descriptor.Ascender + descriptor.Descender) * font.Size / font.UnitsPerEm; + var lineGapHeight = (descriptor.LineSpacing - descriptor.Ascender - descriptor.Descender) * font.Size / font.UnitsPerEm; + Debug.Assert(descriptor.Ascender > 0); bool symbol = descriptor.FontFace.cmap.symbol; int length = text.Length; + int adjustedLength = length; + var height = singleLineHeight; + int maxWidth = 0; int width = 0; for (int idx = 0; idx < length; idx++) { char ch = text[idx]; + + // Handle line feed (\n) + if (ch == 10) + { + adjustedLength--; + if (idx < (length - 1)) + { + maxWidth = Math.Max(maxWidth, width); + width = 0; + height += lineGapHeight + singleLineHeight; + } + + continue; + } + + // HACK: Handle tabulator sign as space (\t) + if (ch == 9) + { + ch = ' '; + } + // HACK: Unclear what to do here. if (ch < 32) + { + adjustedLength--; + continue; + } if (symbol) { @@ -97,15 +127,18 @@ public static XSize MeasureString(string text, XFont font, XStringFormat stringF int glyphIndex = descriptor.CharCodeToGlyphIndex(ch); width += descriptor.GlyphIndexToWidth(glyphIndex); } - // What? size.Width = width * font.Size * (font.Italic ? 1 : 1) / descriptor.UnitsPerEm; - size.Width = width * font.Size / descriptor.UnitsPerEm; + maxWidth = Math.Max(maxWidth, width); + + // What? size.Width = maxWidth * font.Size * (font.Italic ? 1 : 1) / descriptor.UnitsPerEm; + size.Width = maxWidth * font.Size / descriptor.UnitsPerEm; + size.Height = height; // Adjust bold simulation. if ((font.GlyphTypeface.StyleSimulations & XStyleSimulations.BoldSimulation) == XStyleSimulations.BoldSimulation) { // Add 2% of the em-size for each character. // Unsure how to deal with white space. Currently count as regular character. - size.Width += length * font.Size * Const.BoldEmphasis; + size.Width += adjustedLength * font.Size * Const.BoldEmphasis; } } Debug.Assert(descriptor != null, "No OpenTypeDescriptor."); diff --git a/src/PdfSharp/Fonts.OpenType/GlyphTypefaceCache.cs b/src/PdfSharp/Fonts.OpenType/GlyphTypefaceCache.cs index c716d3d4..bdbd5fed 100644 --- a/src/PdfSharp/Fonts.OpenType/GlyphTypefaceCache.cs +++ b/src/PdfSharp/Fonts.OpenType/GlyphTypefaceCache.cs @@ -27,12 +27,12 @@ // DEALINGS IN THE SOFTWARE. #endregion +using PdfSharp.Drawing; +using PdfSharp.Internal; using System; +using System.Collections.Concurrent; using System.Diagnostics; -using System.Collections.Generic; using System.Text; -using PdfSharp.Drawing; -using PdfSharp.Internal; namespace PdfSharp.Fonts.OpenType { @@ -43,7 +43,7 @@ internal class GlyphTypefaceCache { GlyphTypefaceCache() { - _glyphTypefacesByKey = new Dictionary(); + _glyphTypefacesByKey = new ConcurrentDictionary(); } public static bool TryGetGlyphTypeface(string key, out XGlyphTypeface glyphTypeface) @@ -64,7 +64,7 @@ public static void AddGlyphTypeface(XGlyphTypeface glyphTypeface) Lock.EnterFontFactory(); GlyphTypefaceCache cache = Singleton; Debug.Assert(!cache._glyphTypefacesByKey.ContainsKey(glyphTypeface.Key)); - cache._glyphTypefacesByKey.Add(glyphTypeface.Key, glyphTypeface); + cache._glyphTypefacesByKey.TryAdd(glyphTypeface.Key, glyphTypeface); } finally { Lock.ExitFontFactory(); } } @@ -97,7 +97,7 @@ internal static string GetCacheState() StringBuilder state = new StringBuilder(); state.Append("====================\n"); state.Append("Glyph typefaces by name\n"); - Dictionary.KeyCollection familyKeys = Singleton._glyphTypefacesByKey.Keys; + var familyKeys = Singleton._glyphTypefacesByKey.Keys; int count = familyKeys.Count; string[] keys = new string[count]; familyKeys.CopyTo(keys, 0); @@ -111,6 +111,6 @@ internal static string GetCacheState() /// /// Maps typeface key to glyph typeface. /// - readonly Dictionary _glyphTypefacesByKey; + readonly ConcurrentDictionary _glyphTypefacesByKey; } }