Merge pull request #411 from Bykiev/FixDisposable

Fix IDisposable usage
This commit is contained in:
James Jackson-South 2024-08-02 19:11:26 +10:00 коммит произвёл GitHub
Родитель 165a348e4e ed4b24edc4
Коммит fec131d9b6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
17 изменённых файлов: 93 добавлений и 54 удалений

Просмотреть файл

@ -26,7 +26,7 @@ internal ref struct Buffer<T>
this.buffer = ArrayPool<byte>.Shared.Rent(bufferSizeInBytes); this.buffer = ArrayPool<byte>.Shared.Rent(bufferSizeInBytes);
this.length = length; this.length = length;
ByteMemoryManager<T> manager = new(this.buffer); using ByteMemoryManager<T> manager = new(this.buffer);
this.Memory = manager.Memory.Slice(0, this.length); this.Memory = manager.Memory.Slice(0, this.length);
this.span = this.Memory.Span; this.span = this.Memory.Span;

Просмотреть файл

@ -164,7 +164,7 @@ internal sealed class FileFontMetrics : FontMetrics
{ {
using FileStream fs = File.OpenRead(path); using FileStream fs = File.OpenRead(path);
long startPos = fs.Position; long startPos = fs.Position;
BigEndianBinaryReader reader = new(fs, true); using BigEndianBinaryReader reader = new(fs, true);
TtcHeader ttcHeader = TtcHeader.Read(reader); TtcHeader ttcHeader = TtcHeader.Read(reader);
FileFontMetrics[] fonts = new FileFontMetrics[(int)ttcHeader.NumFonts]; FileFontMetrics[] fonts = new FileFontMetrics[(int)ttcHeader.NumFonts];

Просмотреть файл

@ -234,7 +234,7 @@ public sealed class FontCollection : IFontCollection, IFontMetricsCollection
out IEnumerable<FontDescription> descriptions) out IEnumerable<FontDescription> descriptions)
{ {
long startPos = stream.Position; long startPos = stream.Position;
BigEndianBinaryReader reader = new(stream, true); using BigEndianBinaryReader reader = new(stream, true);
TtcHeader ttcHeader = TtcHeader.Read(reader); TtcHeader ttcHeader = TtcHeader.Read(reader);
List<FontDescription> result = new((int)ttcHeader.NumFonts); List<FontDescription> result = new((int)ttcHeader.NumFonts);
HashSet<FontFamily> installedFamilies = new(); HashSet<FontFamily> installedFamilies = new();

Просмотреть файл

@ -92,7 +92,7 @@ public class FontDescription
Guard.NotNullOrWhiteSpace(path, nameof(path)); Guard.NotNullOrWhiteSpace(path, nameof(path));
using FileStream fs = File.OpenRead(path); using FileStream fs = File.OpenRead(path);
var reader = new FontReader(fs); using var reader = new FontReader(fs);
return LoadDescription(reader); return LoadDescription(reader);
} }
@ -106,7 +106,7 @@ public class FontDescription
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
// Only read the name tables. // Only read the name tables.
var reader = new FontReader(stream); using var reader = new FontReader(stream);
return LoadDescription(reader); return LoadDescription(reader);
} }
@ -152,14 +152,14 @@ public class FontDescription
public static FontDescription[] LoadFontCollectionDescriptions(Stream stream) public static FontDescription[] LoadFontCollectionDescriptions(Stream stream)
{ {
long startPos = stream.Position; long startPos = stream.Position;
var reader = new BigEndianBinaryReader(stream, true); using var reader = new BigEndianBinaryReader(stream, true);
var ttcHeader = TtcHeader.Read(reader); var ttcHeader = TtcHeader.Read(reader);
var result = new FontDescription[(int)ttcHeader.NumFonts]; var result = new FontDescription[(int)ttcHeader.NumFonts];
for (int i = 0; i < ttcHeader.NumFonts; ++i) for (int i = 0; i < ttcHeader.NumFonts; ++i)
{ {
stream.Position = startPos + ttcHeader.OffsetTable[i]; stream.Position = startPos + ttcHeader.OffsetTable[i];
var fontReader = new FontReader(stream); using var fontReader = new FontReader(stream);
result[i] = LoadDescription(fontReader); result[i] = LoadDescription(fontReader);
} }

Просмотреть файл

@ -9,21 +9,23 @@ using SixLabors.Fonts.Tables.Woff;
namespace SixLabors.Fonts; namespace SixLabors.Fonts;
internal sealed class FontReader internal sealed class FontReader : IDisposable
{ {
private readonly Stream stream; private readonly Stream stream;
private readonly Dictionary<Type, Table> loadedTables = new(); private readonly Dictionary<Type, Table> loadedTables = new();
private readonly TableLoader loader; private readonly TableLoader loader;
private readonly bool isOwnedStream;
private bool isDisposed;
internal FontReader(Stream stream, TableLoader loader) internal FontReader(Stream stream, TableLoader loader)
{ {
this.loader = loader; this.loader = loader;
Func<BigEndianBinaryReader, TableHeader> loadHeader = TableHeader.Read; Func<BigEndianBinaryReader, TableHeader> loadHeader = TableHeader.Read;
long startOfFilePosition = stream.Position;
this.stream = stream; this.stream = stream;
var reader = new BigEndianBinaryReader(stream, true); using var reader = new BigEndianBinaryReader(stream, true);
// we should immediately read the table header to learn which tables we have and what order they are in // we should immediately read the table header to learn which tables we have and what order they are in
uint version = reader.ReadUInt32(); uint version = reader.ReadUInt32();
@ -85,13 +87,14 @@ internal sealed class FontReader
this.CompressedTableData = true; this.CompressedTableData = true;
this.Headers = Woff2Utils.ReadWoff2Headers(reader, tableCount); this.Headers = Woff2Utils.ReadWoff2Headers(reader, tableCount);
this.isOwnedStream = true;
byte[] compressedBuffer = reader.ReadBytes((int)totalCompressedSize); byte[] compressedBuffer = reader.ReadBytes((int)totalCompressedSize);
var decompressedStream = new MemoryStream(); var decompressedStream = new MemoryStream();
using var input = new MemoryStream(compressedBuffer); using var input = new MemoryStream(compressedBuffer);
using var decompressor = new BrotliStream(input, CompressionMode.Decompress); using var decompressor = new BrotliStream(input, CompressionMode.Decompress);
decompressor.CopyTo(decompressedStream); decompressor.CopyTo(decompressedStream);
decompressedStream.Position = 0; decompressedStream.Position = 0;
this.stream.Dispose();
this.stream = decompressedStream; this.stream = decompressedStream;
return; return;
} }
@ -197,4 +200,18 @@ internal sealed class FontReader
reader = header?.CreateReader(this.stream); reader = header?.CreateReader(this.stream);
return reader != null; return reader != null;
} }
public void Dispose()
{
if (this.isDisposed)
{
return;
}
if (this.isOwnedStream)
{
this.stream.Dispose();
this.isDisposed = true;
}
}
} }

Просмотреть файл

@ -18,7 +18,7 @@ namespace SixLabors.Fonts.Native;
/// Internally, it calls the native CoreText's <see cref="CTFontManagerCopyAvailableFontURLs"/> method to retrieve /// Internally, it calls the native CoreText's <see cref="CTFontManagerCopyAvailableFontURLs"/> method to retrieve
/// the list of fonts so using this class must be guarded by <c>RuntimeInformation.IsOSPlatform(OSPlatform.OSX)</c>. /// the list of fonts so using this class must be guarded by <c>RuntimeInformation.IsOSPlatform(OSPlatform.OSX)</c>.
/// </remarks> /// </remarks>
internal class MacSystemFontsEnumerator : IEnumerable<string>, IEnumerator<string> internal sealed class MacSystemFontsEnumerator : IEnumerable<string>, IEnumerator<string>
{ {
private static readonly ArrayPool<byte> BytePool = ArrayPool<byte>.Shared; private static readonly ArrayPool<byte> BytePool = ArrayPool<byte>.Shared;

Просмотреть файл

@ -333,7 +333,7 @@ internal partial class StreamFontMetrics : FontMetrics
public static StreamFontMetrics LoadFont(string path) public static StreamFontMetrics LoadFont(string path)
{ {
using FileStream fs = File.OpenRead(path); using FileStream fs = File.OpenRead(path);
var reader = new FontReader(fs); using var reader = new FontReader(fs);
return LoadFont(reader); return LoadFont(reader);
} }
@ -357,7 +357,7 @@ internal partial class StreamFontMetrics : FontMetrics
/// <returns>a <see cref="StreamFontMetrics"/>.</returns> /// <returns>a <see cref="StreamFontMetrics"/>.</returns>
public static StreamFontMetrics LoadFont(Stream stream) public static StreamFontMetrics LoadFont(Stream stream)
{ {
var reader = new FontReader(stream); using var reader = new FontReader(stream);
return LoadFont(reader); return LoadFont(reader);
} }

Просмотреть файл

@ -15,7 +15,7 @@ public class FontReaderTests
var writer = new BigEndianBinaryWriter(); var writer = new BigEndianBinaryWriter();
writer.WriteTrueTypeFileHeader(0, 0, 0, 0); writer.WriteTrueTypeFileHeader(0, 0, 0, 0);
var reader = new FontReader(writer.GetStream()); using var reader = new FontReader(writer.GetStream());
Assert.Equal(OutlineType.TrueType, reader.OutlineType); Assert.Equal(OutlineType.TrueType, reader.OutlineType);
} }
@ -25,7 +25,7 @@ public class FontReaderTests
var writer = new BigEndianBinaryWriter(); var writer = new BigEndianBinaryWriter();
writer.WriteCffFileHeader(0, 0, 0, 0); writer.WriteCffFileHeader(0, 0, 0, 0);
var reader = new FontReader(writer.GetStream()); using var reader = new FontReader(writer.GetStream());
Assert.Equal(OutlineType.CFF, reader.OutlineType); Assert.Equal(OutlineType.CFF, reader.OutlineType);
} }
@ -37,7 +37,7 @@ public class FontReaderTests
writer.WriteTableHeader("name", 0, 10, 0); writer.WriteTableHeader("name", 0, 10, 0);
writer.WriteTableHeader("cmap", 0, 1, 0); writer.WriteTableHeader("cmap", 0, 1, 0);
var reader = new FontReader(writer.GetStream()); using var reader = new FontReader(writer.GetStream());
Assert.Equal(2, reader.Headers.Count); Assert.Equal(2, reader.Headers.Count);
} }
@ -59,7 +59,7 @@ public class FontReaderTests
new byte[] { 2, 9 }) new byte[] { 2, 9 })
}); });
var reader = new FontReader(writer.GetStream()); using var reader = new FontReader(writer.GetStream());
CMapTable cmap = reader.GetTable<CMapTable>(); CMapTable cmap = reader.GetTable<CMapTable>();
Assert.NotNull(cmap); Assert.NotNull(cmap);
} }
@ -67,8 +67,8 @@ public class FontReaderTests
[Fact] [Fact]
public void ReadFont_WithWoffFormat_EqualsTtf() public void ReadFont_WithWoffFormat_EqualsTtf()
{ {
var fontReaderTtf = new FontReader(TestFonts.OpenSansTtfData()); using var fontReaderTtf = new FontReader(TestFonts.OpenSansTtfData());
var fontReaderWoff = new FontReader(TestFonts.OpensSansWoff1Data()); using var fontReaderWoff = new FontReader(TestFonts.OpensSansWoff1Data());
Assert.Equal(fontReaderTtf.Headers.Count, fontReaderWoff.Headers.Count); Assert.Equal(fontReaderTtf.Headers.Count, fontReaderWoff.Headers.Count);
foreach (string key in fontReaderTtf.Headers.Keys) foreach (string key in fontReaderTtf.Headers.Keys)
@ -80,9 +80,9 @@ public class FontReaderTests
[Fact] [Fact]
public void GlyphsCount_WithWoffFormat_EqualsTtf() public void GlyphsCount_WithWoffFormat_EqualsTtf()
{ {
var fontReaderWoff = new FontReader(TestFonts.OpensSansWoff1Data()); using var fontReaderWoff = new FontReader(TestFonts.OpensSansWoff1Data());
GlyphTable glyphsWoff = fontReaderWoff.GetTable<GlyphTable>(); GlyphTable glyphsWoff = fontReaderWoff.GetTable<GlyphTable>();
var fontReaderTtf = new FontReader(TestFonts.OpenSansTtfData()); using var fontReaderTtf = new FontReader(TestFonts.OpenSansTtfData());
GlyphTable glyphsTtf = fontReaderTtf.GetTable<GlyphTable>(); GlyphTable glyphsTtf = fontReaderTtf.GetTable<GlyphTable>();
Assert.Equal(glyphsTtf.GlyphCount, glyphsWoff.GlyphCount); Assert.Equal(glyphsTtf.GlyphCount, glyphsWoff.GlyphCount);
@ -91,8 +91,8 @@ public class FontReaderTests
[Fact] [Fact]
public void ReadFont_WithWoff2Format_EqualsTtf() public void ReadFont_WithWoff2Format_EqualsTtf()
{ {
var fontReaderTtf = new FontReader(TestFonts.OpenSansTtfData()); using var fontReaderTtf = new FontReader(TestFonts.OpenSansTtfData());
var fontReaderWoff = new FontReader(TestFonts.OpensSansWoff2Data()); using var fontReaderWoff = new FontReader(TestFonts.OpensSansWoff2Data());
Assert.Equal(fontReaderTtf.Headers.Count, fontReaderWoff.Headers.Count); Assert.Equal(fontReaderTtf.Headers.Count, fontReaderWoff.Headers.Count);
foreach (string key in fontReaderTtf.Headers.Keys) foreach (string key in fontReaderTtf.Headers.Keys)
@ -104,9 +104,9 @@ public class FontReaderTests
[Fact] [Fact]
public void GlyphsCount_WithWoff2Format_EqualsTtf() public void GlyphsCount_WithWoff2Format_EqualsTtf()
{ {
var fontReaderWoff = new FontReader(TestFonts.OpensSansWoff2Data()); using var fontReaderWoff = new FontReader(TestFonts.OpensSansWoff2Data());
GlyphTable glyphsWoff = fontReaderWoff.GetTable<GlyphTable>(); GlyphTable glyphsWoff = fontReaderWoff.GetTable<GlyphTable>();
var fontReaderTtf = new FontReader(TestFonts.OpenSansTtfData()); using var fontReaderTtf = new FontReader(TestFonts.OpenSansTtfData());
GlyphTable glyphsTtf = fontReaderTtf.GetTable<GlyphTable>(); GlyphTable glyphsTtf = fontReaderTtf.GetTable<GlyphTable>();
Assert.Equal(glyphsTtf.GlyphCount, glyphsWoff.GlyphCount); Assert.Equal(glyphsTtf.GlyphCount, glyphsWoff.GlyphCount);

Просмотреть файл

@ -35,7 +35,11 @@ public class CMapTableTests
using (System.IO.MemoryStream stream = writer.GetStream()) using (System.IO.MemoryStream stream = writer.GetStream())
{ {
InvalidFontTableException exception = Assert.Throws<InvalidFontTableException>(() => CMapTable.Load(new FontReader(stream))); InvalidFontTableException exception = Assert.Throws<InvalidFontTableException>(() =>
{
using var reader = new FontReader(stream);
CMapTable.Load(reader);
});
Assert.Equal("cmap", exception.Table); Assert.Equal("cmap", exception.Table);
} }

Просмотреть файл

@ -14,9 +14,10 @@ public class ColrTableTests
var writer = new BigEndianBinaryWriter(); var writer = new BigEndianBinaryWriter();
writer.WriteTrueTypeFileHeader(); writer.WriteTrueTypeFileHeader();
using (System.IO.MemoryStream stream = writer.GetStream()) using (MemoryStream stream = writer.GetStream())
{ {
Assert.Null(ColrTable.Load(new FontReader(stream))); using var reader = new FontReader(stream);
Assert.Null(ColrTable.Load(reader));
} }
} }
@ -47,12 +48,12 @@ public class ColrTableTests
} }
}); });
using (System.IO.Stream stream = TestFonts.TwemojiMozillaData()) using (Stream stream = TestFonts.TwemojiMozillaData())
{ {
var reader = new FontReader(stream); using var reader = new FontReader(stream);
ColrTable tbl = reader.GetTable<ColrTable>(); ColrTable tbl = reader.GetTable<ColrTable>();
System.Span<LayerRecord> layers = tbl.GetLayers(15); Span<LayerRecord> layers = tbl.GetLayers(15);
Assert.Equal(2, layers.Length); Assert.Equal(2, layers.Length);
} }
} }

Просмотреть файл

@ -35,9 +35,10 @@ public class HorizontalHeadTableTests
var writer = new BigEndianBinaryWriter(); var writer = new BigEndianBinaryWriter();
writer.WriteTrueTypeFileHeader(); writer.WriteTrueTypeFileHeader();
using (System.IO.MemoryStream stream = writer.GetStream()) using (MemoryStream stream = writer.GetStream())
{ {
Assert.Null(HorizontalHeadTable.Load(new FontReader(stream))); using var reader = new FontReader(stream);
Assert.Null(HorizontalHeadTable.Load(reader));
} }
} }
} }

Просмотреть файл

@ -15,10 +15,13 @@ public class IndexLocationTableTests
var writer = new BigEndianBinaryWriter(); var writer = new BigEndianBinaryWriter();
writer.WriteTrueTypeFileHeader(); writer.WriteTrueTypeFileHeader();
using (System.IO.MemoryStream stream = writer.GetStream()) using (MemoryStream stream = writer.GetStream())
{ {
MissingFontTableException exception = Assert.Throws<MissingFontTableException>( MissingFontTableException exception = Assert.Throws<MissingFontTableException>(() =>
() => IndexLocationTable.Load(new FontReader(stream))); {
using var reader = new FontReader(stream);
IndexLocationTable.Load(reader);
});
Assert.Equal("head", exception.Table); Assert.Equal("head", exception.Table);
} }
@ -40,10 +43,13 @@ public class IndexLocationTableTests
0, 0,
HeadTable.IndexLocationFormats.Offset16)); HeadTable.IndexLocationFormats.Offset16));
using (System.IO.MemoryStream stream = writer.GetStream()) using (MemoryStream stream = writer.GetStream())
{ {
InvalidFontTableException exception = Assert.Throws<InvalidFontTableException>( InvalidFontTableException exception = Assert.Throws<InvalidFontTableException>(() =>
() => IndexLocationTable.Load(new FontReader(stream))); {
using var reader = new FontReader(stream);
IndexLocationTable.Load(reader);
});
Assert.Equal("maxp", exception.Table); Assert.Equal("maxp", exception.Table);
} }
@ -65,9 +71,10 @@ public class IndexLocationTableTests
0, 0,
HeadTable.IndexLocationFormats.Offset16)); HeadTable.IndexLocationFormats.Offset16));
using (System.IO.MemoryStream stream = writer.GetStream()) using (MemoryStream stream = writer.GetStream())
{ {
Assert.Null(IndexLocationTable.Load(new FontReader(stream))); using var reader = new FontReader(stream);
Assert.Null(IndexLocationTable.Load(reader));
} }
} }
} }

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using SixLabors.Fonts.Tables.General.Kern; using SixLabors.Fonts.Tables.General.Kern;
@ -13,9 +13,10 @@ public class KerningTableTests
var writer = new BigEndianBinaryWriter(); var writer = new BigEndianBinaryWriter();
writer.WriteTrueTypeFileHeader(); writer.WriteTrueTypeFileHeader();
using (System.IO.MemoryStream stream = writer.GetStream()) using (MemoryStream stream = writer.GetStream())
{ {
var table = KerningTable.Load(new FontReader(stream)); using var reader = new FontReader(stream);
var table = KerningTable.Load(reader);
Assert.NotNull(table); Assert.NotNull(table);
} }
} }

Просмотреть файл

@ -15,8 +15,11 @@ public class MaximumProfileTableTests
using (MemoryStream stream = writer.GetStream()) using (MemoryStream stream = writer.GetStream())
{ {
InvalidFontTableException exception = Assert.Throws<InvalidFontTableException>( InvalidFontTableException exception = Assert.Throws<InvalidFontTableException>(() =>
() => MaximumProfileTable.Load(new FontReader(stream))); {
using var reader = new FontReader(stream);
MaximumProfileTable.Load(reader);
});
Assert.Equal("maxp", exception.Table); Assert.Equal("maxp", exception.Table);
} }

Просмотреть файл

@ -76,10 +76,13 @@ public class NameTableTests
var writer = new BigEndianBinaryWriter(); var writer = new BigEndianBinaryWriter();
writer.WriteTrueTypeFileHeader(); writer.WriteTrueTypeFileHeader();
using (System.IO.MemoryStream stream = writer.GetStream()) using (MemoryStream stream = writer.GetStream())
{ {
InvalidFontTableException exception = Assert.Throws<InvalidFontTableException>( InvalidFontTableException exception = Assert.Throws<InvalidFontTableException>(() =>
() => NameTable.Load(new FontReader(stream))); {
using var reader = new FontReader(stream);
NameTable.Load(reader);
});
Assert.Equal("name", exception.Table); Assert.Equal("name", exception.Table);
} }

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using SixLabors.Fonts.Tables.General; using SixLabors.Fonts.Tables.General;
@ -13,9 +13,10 @@ public class OS2TableTests
var writer = new BigEndianBinaryWriter(); var writer = new BigEndianBinaryWriter();
writer.WriteTrueTypeFileHeader(); writer.WriteTrueTypeFileHeader();
using (System.IO.MemoryStream stream = writer.GetStream()) using (MemoryStream stream = writer.GetStream())
{ {
Assert.Null(OS2Table.Load(new FontReader(stream))); using var reader = new FontReader(stream);
Assert.Null(OS2Table.Load(reader));
} }
} }
} }

Просмотреть файл

@ -36,6 +36,7 @@ public class VerticalHeadTableTests
writer.WriteTrueTypeFileHeader(); writer.WriteTrueTypeFileHeader();
using MemoryStream stream = writer.GetStream(); using MemoryStream stream = writer.GetStream();
Assert.Null(VerticalHeadTable.Load(new FontReader(stream))); using var reader = new FontReader(stream);
Assert.Null(VerticalHeadTable.Load(reader));
} }
} }