use tryget rather than lambdas for union type

avoid the allocations caused by lambda expressions for performance reasons.
This commit is contained in:
Eliot Jones
2020-02-28 16:02:20 +00:00
parent 4d911fb9d1
commit 4442a69a97
9 changed files with 141 additions and 55 deletions

View File

@@ -19,6 +19,16 @@ namespace UglyToad.PdfPig.Core
/// </summary> /// </summary>
public abstract TResult Match<TResult>(Func<A, TResult> first, Func<B, TResult> second); public abstract TResult Match<TResult>(Func<A, TResult> first, Func<B, TResult> second);
/// <summary>
/// Get the item if it is of the specific type.
/// </summary>
public abstract bool TryGetFirst(out A a);
/// <summary>
/// Get the item if it is of the specific type.
/// </summary>
public abstract bool TryGetSecond(out B b);
private Union() { } private Union() { }
/// <summary> /// <summary>
@@ -69,6 +79,20 @@ namespace UglyToad.PdfPig.Core
return first(Item); return first(Item);
} }
/// <inheritdoc />
public override bool TryGetFirst(out A a)
{
a = Item;
return true;
}
/// <inheritdoc />
public override bool TryGetSecond(out B b)
{
b = default(B);
return false;
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
@@ -108,6 +132,20 @@ namespace UglyToad.PdfPig.Core
return second(Item); return second(Item);
} }
/// <inheritdoc />
public override bool TryGetFirst(out A a)
{
a = default(A);
return false;
}
/// <inheritdoc />
public override bool TryGetSecond(out B b)
{
b = Item;
return true;
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {

View File

@@ -48,21 +48,26 @@
var defaultWidthX = GetDefaultWidthX(characterName); var defaultWidthX = GetDefaultWidthX(characterName);
var nominalWidthX = GetNominalWidthX(characterName); var nominalWidthX = GetNominalWidthX(characterName);
var result = CharStrings.Match(x => throw new NotImplementedException("Type 1 CharStrings in a CFF font are currently unsupported."), if (CharStrings.TryGetFirst(out var _))
x => {
{ throw new NotImplementedException("Type 1 CharStrings in a CFF font are currently unsupported.");
var glyph = x.Generate(characterName, (double)defaultWidthX, (double)nominalWidthX); }
var rectangle = glyph.Path.GetBoundingRectangle();
if (rectangle.HasValue)
{
return rectangle;
}
var defaultBoundingBox = TopDictionary.FontBoundingBox; if (!CharStrings.TryGetSecond(out var type2CharStrings))
return new PdfRectangle(0, 0, glyph.Width.GetValueOrDefault(), defaultBoundingBox.Height); {
}); return null;
}
var glyph = type2CharStrings.Generate(characterName, (double)defaultWidthX, (double)nominalWidthX);
var rectangle = glyph.Path.GetBoundingRectangle();
if (rectangle.HasValue)
{
return rectangle;
}
var defaultBoundingBox = TopDictionary.FontBoundingBox;
return new PdfRectangle(0, 0, glyph.Width.GetValueOrDefault(), defaultBoundingBox.Height);
return result;
} }
/// <summary> /// <summary>
@@ -88,8 +93,8 @@
public IReadOnlyList<CompactFontFormatPrivateDictionary> PrivateDictionaries { get; } public IReadOnlyList<CompactFontFormatPrivateDictionary> PrivateDictionaries { get; }
public ICompactFontFormatFdSelect FdSelect { get; } public ICompactFontFormatFdSelect FdSelect { get; }
public CompactFontFormatCidFont(CompactFontFormatTopLevelDictionary topDictionary, CompactFontFormatPrivateDictionary privateDictionary, public CompactFontFormatCidFont(CompactFontFormatTopLevelDictionary topDictionary, CompactFontFormatPrivateDictionary privateDictionary,
ICompactFontFormatCharset charset, ICompactFontFormatCharset charset,
Union<Type1CharStrings, Type2CharStrings> charStrings, Union<Type1CharStrings, Type2CharStrings> charStrings,
IReadOnlyList<CompactFontFormatTopLevelDictionary> fontDictionaries, IReadOnlyList<CompactFontFormatTopLevelDictionary> fontDictionaries,
IReadOnlyList<CompactFontFormatPrivateDictionary> privateDictionaries, IReadOnlyList<CompactFontFormatPrivateDictionary> privateDictionaries,

View File

@@ -2,7 +2,6 @@
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Core; using Core;
/// <summary> /// <summary>
@@ -21,6 +20,11 @@
/// </summary> /// </summary>
public IReadOnlyDictionary<string, CompactFontFormatFont> Fonts { get; } public IReadOnlyDictionary<string, CompactFontFormatFont> Fonts { get; }
/// <summary>
/// The first font contained in the collection.
/// </summary>
public CompactFontFormatFont FirstFont { get; }
/// <summary> /// <summary>
/// Create a new <see cref="CompactFontFormatFontCollection"/>. /// Create a new <see cref="CompactFontFormatFontCollection"/>.
/// </summary> /// </summary>
@@ -30,6 +34,11 @@
{ {
Header = header; Header = header;
Fonts = fontSet ?? throw new ArgumentNullException(nameof(fontSet)); Fonts = fontSet ?? throw new ArgumentNullException(nameof(fontSet));
foreach (var pair in fontSet)
{
FirstFont = pair.Value;
break;
}
} }
/// <summary> /// <summary>
@@ -50,7 +59,7 @@
/// </summary> /// </summary>
public PdfRectangle? GetCharacterBoundingBox(string characterName) public PdfRectangle? GetCharacterBoundingBox(string characterName)
{ {
return Fonts.First().Value.GetCharacterBoundingBox(characterName); return FirstFont.GetCharacterBoundingBox(characterName);
} }
/// <summary> /// <summary>
@@ -58,7 +67,7 @@
/// </summary> /// </summary>
public string GetCharacterName(int characterCode) public string GetCharacterName(int characterCode)
{ {
var font = Fonts.First().Value; var font = FirstFont;
if (font.Encoding != null) if (font.Encoding != null)
{ {

View File

@@ -23,8 +23,14 @@
foreach (var command in subroutine.Commands) foreach (var command in subroutine.Commands)
{ {
command.Match(x => context.Stack.Push(x), if (command.TryGetFirst(out var num))
x => x.Run(context)); {
context.Stack.Push(num);
}
else if (command.TryGetSecond(out var lazyCommand))
{
lazyCommand.Run(context);
}
} }
} }
} }

View File

@@ -92,8 +92,14 @@
foreach (var command in sequence.Commands) foreach (var command in sequence.Commands)
{ {
command.Match(x => context.Stack.Push(x), if (command.TryGetFirst(out var num))
x => x.Run(context)); {
context.Stack.Push(num);
}
else if (command.TryGetSecond(out var lazyCommand))
{
lazyCommand.Run(context);
}
} }
return context.Path; return context.Path;

View File

@@ -54,10 +54,14 @@
{ {
foreach (var image in images) foreach (var image in images)
{ {
var result = image.Match<IPdfImage>(x => XObjectFactory.ReadImage(x, pdfScanner, filterProvider, resourceStore), if (image.TryGetFirst(out var xObjectContentRecord))
x => x); {
yield return XObjectFactory.ReadImage(xObjectContentRecord, pdfScanner, filterProvider, resourceStore);
yield return result; }
else if (image.TryGetSecond(out var inlineImage))
{
yield return inlineImage;
}
} }
} }

View File

@@ -71,7 +71,7 @@
throw new NotSupportedException("Multiple fonts in a CFF"); throw new NotSupportedException("Multiple fonts in a CFF");
} }
#endif #endif
return fontCollection.Fonts.First().Value; return fontCollection.FirstFont;
} }
} }
} }

View File

@@ -1,6 +1,5 @@
namespace UglyToad.PdfPig.PdfFonts.Parser.Handlers namespace UglyToad.PdfPig.PdfFonts.Parser.Handlers
{ {
using System.Linq;
using Cmap; using Cmap;
using Core; using Core;
using Filters; using Filters;
@@ -101,21 +100,25 @@
} }
} }
Encoding fromFont = font?.Match(x => x.Encoding != null ? new BuiltInEncoding(x.Encoding) : default(Encoding), x =>
var fromFont = default(Encoding);
if (font != null)
{ {
if (x.Fonts != null && x.Fonts.Count > 0) if (font.TryGetFirst(out var t1Font))
{ {
return x.Fonts.First().Value.Encoding; fromFont = t1Font.Encoding != null ? new BuiltInEncoding(t1Font.Encoding) : default(Encoding);
} }
else if (font.TryGetSecond(out var cffFont))
{
fromFont = cffFont.FirstFont?.Encoding;
}
}
return default(Encoding); var encoding = encodingReader.Read(dictionary, descriptor, fromFont);
});
Encoding encoding = encodingReader.Read(dictionary, descriptor, fromFont); if (encoding == null && font != null && font.TryGetFirst(out var t1FontReplacment))
if (encoding == null)
{ {
font?.Match(x => encoding = new BuiltInEncoding(x.Encoding), _ => { }); encoding = new BuiltInEncoding(t1FontReplacment.Encoding);
} }
return new Type1FontSimple(name, firstCharacter, lastCharacter, widths, descriptor, encoding, toUnicodeCMap, font); return new Type1FontSimple(name, firstCharacter, lastCharacter, widths, descriptor, encoding, toUnicodeCMap, font);

View File

@@ -1,7 +1,6 @@
namespace UglyToad.PdfPig.PdfFonts.Simple namespace UglyToad.PdfPig.PdfFonts.Simple
{ {
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Cmap; using Cmap;
using Composite; using Composite;
using Core; using Core;
@@ -17,6 +16,8 @@
/// </summary> /// </summary>
internal class Type1FontSimple : IFont internal class Type1FontSimple : IFont
{ {
private static readonly TransformationMatrix DefaultTransformationMatrix = TransformationMatrix.FromValues(0.001, 0, 0, 0.001, 0, 0);
private readonly Dictionary<int, CharacterBoundingBox> cachedBoundingBoxes = new Dictionary<int, CharacterBoundingBox>(); private readonly Dictionary<int, CharacterBoundingBox> cachedBoundingBoxes = new Dictionary<int, CharacterBoundingBox>();
private readonly int firstChar; private readonly int firstChar;
@@ -52,8 +53,19 @@
this.fontProgram = fontProgram; this.fontProgram = fontProgram;
this.toUnicodeCMap = new ToUnicodeCMap(toUnicodeCMap); this.toUnicodeCMap = new ToUnicodeCMap(toUnicodeCMap);
var matrix = TransformationMatrix.FromValues(0.001, 0, 0, 0.001, 0, 0); var matrix = DefaultTransformationMatrix;
fontProgram?.Match(x => matrix = x.FontMatrix, x => { matrix = x.GetFirstTransformationMatrix(); });
if (fontProgram != null)
{
if (fontProgram.TryGetFirst(out var t1Font))
{
matrix = t1Font.FontMatrix;
}
else if (fontProgram.TryGetSecond(out var cffFont))
{
matrix = cffFont.GetFirstTransformationMatrix();
}
}
fontMatrix = matrix; fontMatrix = matrix;
@@ -90,10 +102,11 @@
} }
var containsEncoding = false; var containsEncoding = false;
var capturedValue = default(string); if (fontProgram.TryGetFirst(out var t1Font))
fontProgram.Match(x => { containsEncoding = x.Encoding.TryGetValue(characterCode, out capturedValue); }, {
_ => {}); containsEncoding = t1Font.Encoding.TryGetValue(characterCode, out value);
value = capturedValue; }
return containsEncoding; return containsEncoding;
} }
} }
@@ -163,14 +176,15 @@
return new PdfRectangle(0, 0, widths[characterCode - firstChar], 0); return new PdfRectangle(0, 0, widths[characterCode - firstChar], 0);
} }
var rect = fontProgram.Match(x => PdfRectangle? rect = null;
{ if (fontProgram.TryGetFirst(out var t1Font))
var name = encoding.GetName(characterCode); {
return x.GetCharacterBoundingBox(name); var name = encoding.GetName(characterCode);
}, rect = t1Font.GetCharacterBoundingBox(name);
x => }
{ else if (fontProgram.TryGetSecond(out var cffFont))
var first = x.Fonts.First().Value; {
var first = cffFont.FirstFont;
string characterName; string characterName;
if (encoding != null) if (encoding != null)
{ {
@@ -178,11 +192,12 @@
} }
else else
{ {
characterName = x.GetCharacterName(characterCode); characterName = cffFont.GetCharacterName(characterCode);
} }
return first.GetCharacterBoundingBox(characterName); rect = first.GetCharacterBoundingBox(characterName);
}); }
if (!rect.HasValue) if (!rect.HasValue)
{ {