Skip to content

Commit

Permalink
Added streaming support to Face
Browse files Browse the repository at this point in the history
  • Loading branch information
MnemonicWME authored and HinTak committed May 9, 2017
1 parent af71f6e commit ff46f01
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 4 deletions.
6 changes: 3 additions & 3 deletions Source/SharpFontShared/FTStream.cs
Expand Up @@ -43,14 +43,14 @@ namespace SharpFont
/// <returns>The number of bytes effectively read by the stream.</returns>
[CLSCompliant(false)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint StreamIOFunc(NativeReference<FTStream> stream, uint offset, IntPtr buffer, uint count);
public delegate uint StreamIOFunc(IntPtr stream, uint offset, IntPtr buffer, uint count);

/// <summary>
/// A function used to close a given input stream.
/// </summary>
/// <param name="stream">A handle to the target stream.</param>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void StreamCloseFunc(NativeReference<FTStream> stream);
public delegate void StreamCloseFunc(IntPtr stream);

/// <summary>
/// A handle to an input stream.
Expand Down Expand Up @@ -84,7 +84,7 @@ public IntPtr Base
return rec.@base;
}
}

/// <summary>
/// Gets the stream size in bytes.
/// </summary>
Expand Down
93 changes: 92 additions & 1 deletion Source/SharpFontShared/Face.cs
Expand Up @@ -24,6 +24,7 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;

using SharpFont.Bdf;
Expand Down Expand Up @@ -53,6 +54,13 @@ public sealed class Face : NativeObject, IDisposable
private Library parentLibrary;
private List<FTSize> childSizes;

private StreamIOFunc streamIOFunc;
private StreamCloseFunc streamCloseFunc;
private bool streamOwned;
private GCHandle streamHandle;
private IntPtr streamPtr;
private IntPtr openArgsPtr;

#endregion

#region Constructors
Expand All @@ -67,6 +75,8 @@ public Face(Library library, string path)
{
}



/// <summary>
/// Initializes a new instance of the <see cref="Face"/> class.
/// </summary>
Expand All @@ -85,7 +95,84 @@ public Face(Library library, string path, int faceIndex)
Reference = reference;
}

//TODO make an overload with a FileStream instead of a byte[]

/// <summary>
/// Initializes a new instance of the <see cref="Face"/> class.
/// </summary>
/// <param name="library">The parent library.</param>
/// <param name="stream">The stream of the font file.</param>
/// <param name="faceIndex">The index of the face to take from the file.</param>
/// <param name="takeStreamOwnership">The stream is automatically disposed with the face.</param>
public Face(Library library, Stream stream, int faceIndex, bool takeStreamOwnership)
: this(library)
{
if (stream == null)
throw new ArgumentException("Stream cannot be null", "stream");

if (!stream.CanRead || !stream.CanSeek)
throw new ArgumentException("Stream must support reading and seeking", "stream");

IntPtr reference;

streamIOFunc = new StreamIOFunc(StreamIOFunc);
streamCloseFunc = new StreamCloseFunc(StreamCloseFunc);

streamOwned = takeStreamOwnership;
streamHandle = GCHandle.Alloc(stream);

StreamRec streamRec = new StreamRec();
streamRec.size = (UIntPtr)stream.Length;
streamRec.descriptor.pointer = GCHandle.ToIntPtr(streamHandle);
streamRec.read = streamIOFunc;
streamRec.close = streamCloseFunc;

streamPtr = Marshal.AllocHGlobal(Marshal.SizeOf(streamRec));
Marshal.StructureToPtr(streamRec, streamPtr, false);


OpenArgsRec openArgs = new OpenArgsRec();
openArgs.flags = OpenFlags.Stream;
openArgs.stream = streamPtr;

openArgsPtr = Marshal.AllocHGlobal(Marshal.SizeOf(openArgs));
Marshal.StructureToPtr(openArgs, openArgsPtr, false);


Error err = FT.FT_Open_Face(library.Reference, openArgsPtr, faceIndex, out reference);
if (err != Error.Ok)
throw new FreeTypeException(err);

Reference = reference;
}

private uint StreamIOFunc(IntPtr streamPtr, uint offset, IntPtr buffer, uint count)
{
FTStream ftStream = new FTStream(streamPtr);
Stream stream = ((GCHandle)ftStream.Descriptor.Pointer).Target as Stream;
if (stream != null)
{
stream.Seek(offset, SeekOrigin.Begin);
if (count > 0)
{
byte[] readbuffer = new byte[count];
uint bytesread = (uint)stream.Read(readbuffer, 0, (int)count);
Marshal.Copy(readbuffer, 0, buffer, (int)count);
return bytesread;
}
}
return 0;
}

private void StreamCloseFunc(IntPtr streamPtr)
{
if (streamOwned)
{
FTStream ftStream = new FTStream(streamPtr);
Stream stream = ((GCHandle)ftStream.Descriptor.Pointer).Target as Stream;
if (stream != null) stream.Dispose();
}
}


/// <summary>
/// Initializes a new instance of the <see cref="Face"/> class from a file that's already loaded into memory.
Expand Down Expand Up @@ -2401,6 +2488,10 @@ private void Dispose(bool disposing)
if (memoryFaceHandle.IsAllocated)
memoryFaceHandle.Free();

if (openArgsPtr != IntPtr.Zero) Marshal.FreeHGlobal(openArgsPtr);
if (streamPtr != IntPtr.Zero) Marshal.FreeHGlobal(streamPtr);
if (streamHandle.IsAllocated) streamHandle.Free();

EventHandler handler = Disposed;
if (handler != null)
handler(this, EventArgs.Empty);
Expand Down

0 comments on commit ff46f01

Please sign in to comment.