Skip to content

Commit

Permalink
Basic composite support
Browse files Browse the repository at this point in the history
  • Loading branch information
vidstige committed Oct 30, 2016
1 parent 5db9f0e commit 6cf3fb2
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 13 deletions.
86 changes: 86 additions & 0 deletions NOpenType/CompositeGlyph.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;

namespace NRasterizer
{
public class CompositeGlyph: IGlyph
{
public class Composite
{
private readonly ushort _glyphIndex;
private readonly Transform _transform;
public Composite(ushort glyphIndex, Transform transform)
{
_glyphIndex = glyphIndex;
_transform = transform;
}

public ushort GlyphIndex { get { return _glyphIndex; } }
public Transform Transform { get { return _transform; } }
}

private readonly List<Composite> _composites;

public CompositeGlyph(List<Composite> composites)
{
_composites = composites;
}

private IGlyph Transform(Transform transform, IGlyph glyph)
{
return glyph;
}

private T[] Concat<T>(T[] first, T[] second)
{
var result = new T[first.Length + second.Length];
first.CopyTo(result, 0);
second.CopyTo(result, first.Length);
return result;
}

private IGlyph Combine(IGlyph first, IGlyph second)
{
var xs = Concat(first.X, second.X);
var ys = Concat(first.Y, second.Y);
var ons = Concat(first.On, second.On);

var endPoints = (ushort[])second.EndPoints.Clone();
var offset = first.X.Length;
for (int i = 0; i < endPoints.Length; i++)
{
endPoints[i] = (ushort)(endPoints[i] + offset);
}

return new Glyph(xs, ys, ons, Concat(first.EndPoints, endPoints), null);
}

public IGlyph Flatten(List<IGlyph> glyphs)
{
IGlyph flat = Glyph.Empty;
List<IGlyph> parts = new List<IGlyph>();
foreach (var composite in _composites)
{
flat = Combine(flat, Transform(composite.Transform, glyphs[composite.GlyphIndex]));
parts.Add(glyphs[composite.GlyphIndex]);
}

return flat;
}

#region IGlyph implementation

public Bounds Bounds { get { throw new NotSupportedException(); } }

public short[] X { get { throw new NotSupportedException(); } }

public short[] Y { get { throw new NotSupportedException(); } }

public bool[] On { get { throw new NotSupportedException(); } }

public ushort[] EndPoints { get { throw new NotSupportedException(); } }

#endregion

}
}
2 changes: 1 addition & 1 deletion NOpenType/Glyph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using NRasterizer.Rasterizer;
namespace NRasterizer
{
public class Glyph
public class Glyph: IGlyph
{
private readonly short[] _x;
private readonly short[] _y;
Expand Down
14 changes: 14 additions & 0 deletions NOpenType/IGlyph.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace NRasterizer
{
public interface IGlyph
{
Bounds Bounds { get; }

short[] X { get; }
short[] Y { get; }
bool[] On { get; }
ushort[] EndPoints { get; }
}
}
5 changes: 4 additions & 1 deletion NOpenType/NOpenType.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
<ItemGroup>
<Compile Include="Bounds.cs" />
<Compile Include="CharacterMap.cs" />
<Compile Include="Glyph.cs" />
<Compile Include="Interpreter.cs" />
<Compile Include="IO\ByteOrderSwappingBinaryReader.cs" />
<Compile Include="Net20\ExtensionAttribute.cs" />
Expand All @@ -61,6 +60,10 @@
<Compile Include="Renderer.cs" />
<Compile Include="EmSquare.cs" />
<Compile Include="ToPixelRasterizer.cs" />
<Compile Include="CompositeGlyph.cs" />
<Compile Include="Transform.cs" />
<Compile Include="IGlyph.cs" />
<Compile Include="Glyph.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Expand Down
2 changes: 1 addition & 1 deletion NOpenType/Renderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public Renderer(Typeface typeface, IGlyphRasterizer rasterizer)
_rasterizer = rasterizer;
}

public void RenderGlyph(int x, int y, int m, int d, Glyph glyph)
public void RenderGlyph(int x, int y, int m, int d, IGlyph glyph)
{
var rasterizer = new ToPixelRasterizer(x, y, m, d, _rasterizer);

Expand Down
94 changes: 88 additions & 6 deletions NOpenType/Tables/Glyf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,89 @@ private static Glyph ReadSimpleGlyph(BinaryReader input, int count, Bounds bound
return new Glyph(xs, ys, onCurves, endPoints, bounds);
}

private static Glyph ReadCompositeGlyph(BinaryReader input, int count, Bounds bounds)
private enum CompositeFlags: ushort
{
// TODO: Parse composite glyphs
return Glyph.Empty;
ArgsAreWords = 1, // If this is set, the arguments are words; otherwise, they are bytes.
ArgsAreXYValues = 2, // If this is set, the arguments are xy values; otherwise, they are points.
RoundXYToGrid = 4, // For the xy values if the preceding is true.
WeHaveAScale = 8, // This indicates that there is a simple scale for the component. Otherwise, scale = 1.0.
Reserved = 16, // This bit is reserved. Set it to 0.
MoreComponents = 32, // Indicates at least one more glyph after this one.
WeHaveXAndYScale = 64, // The x direction will use a different scale from the y direction.
WeHaveATwoByTwo = 128, // There is a 2 by 2 transformation that will be used to scale the component.
WeHaveInstructions = 256, // Following the last component are instructions for the composite character.
UseMyMetrics = 512, // If set, this forces the aw and lsb (and rsb) for the composite to be equal to those from this original glyph. This works for hinted and unhinted characters.
OverlapCompound = 1024, // If set, the components of the compound glyph overlap. Use of this flag is not required in OpenType — that is, it is valid to have components overlap without having this flag set. It may affect behaviors in some platforms, however. (See Apple’s specification for details regarding behavior in Apple platforms.)
ScaledComponentOffset = 2048, // The composite is designed to have the component offset scaled.
UnscaledComponentOffset = 4096 // The composite is designed not to have the component offset scaled.
}

internal static List<Glyph> From(TableEntry table, GlyphLocations locations)
private static bool HasFlag(CompositeFlags haystack, CompositeFlags needle)
{
return (haystack & needle) != 0;
}

private static CompositeGlyph ReadCompositeGlyph(BinaryReader input, int count, Bounds bounds, List<IGlyph> glyphs)
{
List<CompositeGlyph.Composite> result = new List<CompositeGlyph.Composite>();
CompositeFlags flags;
ushort glyphIndex;
do {
flags = (CompositeFlags)input.ReadUInt16();
glyphIndex = input.ReadUInt16();

short arg1;
short arg2;
short M00 = 1, M01 = 0, M10 = 0, M11 = 1;
if (HasFlag(flags, CompositeFlags.ArgsAreWords)) {
arg1 = input.ReadInt16();
arg2 = input.ReadInt16();
} else {
arg1 = input.ReadByte();
arg2 = input.ReadByte();
//USHORT arg1and2; /* (arg1 << 8) | arg2 */
}

if (HasFlag(flags, CompositeFlags.ArgsAreXYValues))
{
// args are dx,dy value
} else {
// args are points to be matched
}

if (HasFlag(flags, CompositeFlags.WeHaveAScale)) {
short scale = input.ReadInt16(); // Format 2.14
M00 = scale;
M11 = scale;
} else if (HasFlag(flags, CompositeFlags.WeHaveXAndYScale)) {
short xscale = input.ReadInt16(); // Format 2.14
short yscale = input.ReadInt16(); // Format 2.14
M00 = xscale;
M11 = yscale;
} else if (HasFlag(flags, CompositeFlags.WeHaveATwoByTwo)) {
M00 = input.ReadInt16(); // Format 2.14
M01 = input.ReadInt16(); // Format 2.14
M10 = input.ReadInt16(); // Format 2.14
M11 = input.ReadInt16(); // Format 2.14
}
result.Add(new CompositeGlyph.Composite(glyphIndex, null));
} while (HasFlag(flags, CompositeFlags.MoreComponents));

if (HasFlag(flags, CompositeFlags.WeHaveInstructions))
{
//USHORT numInstr
//BYTE instr[numInstr];
}

return new CompositeGlyph(result);
//return Glyph.Empty;
}

internal static List<IGlyph> From(TableEntry table, GlyphLocations locations)
{
var glyphCount = locations.GlyphCount;

var glyphs = new List<Glyph>(glyphCount);
var glyphs = new List<IGlyph>(glyphCount);
for (int i = 0; i < glyphCount; i++)
{
var input = table.GetDataReader();
Expand All @@ -133,14 +205,24 @@ internal static List<Glyph> From(TableEntry table, GlyphLocations locations)
}
else
{
glyphs.Add(ReadCompositeGlyph(input, -contoursCount, bounds));
glyphs.Add(ReadCompositeGlyph(input, -contoursCount, bounds, glyphs));
}
}
else
{
glyphs.Add(Glyph.Empty);
}
}

// Flatten all composites
for (int i = 0; i < glyphs.Count; i++)
{
var composite = glyphs[i] as CompositeGlyph;
if (composite != null)
{
glyphs[i] = composite.Flatten(glyphs);
}
}
return glyphs;
}
}
Expand Down
18 changes: 18 additions & 0 deletions NOpenType/Transform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace NRasterizer
{
public class Transform
{
private readonly short _m00;
private readonly short _m01;
private readonly short _m10;
private readonly short _m11;
private readonly short _dx;
private readonly short _dy;

public Transform(short m00, short m01, short m10, short m11, short dx, short dy)
{
}
}
}
8 changes: 4 additions & 4 deletions NOpenType/Typeface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ public class Typeface
{
private readonly Bounds _bounds;
private readonly ushort _unitsPerEm;
private readonly List<Glyph> _glyphs;
private readonly List<IGlyph> _glyphs;
private readonly List<CharacterMap> _cmaps;
private readonly HorizontalMetrics _horizontalMetrics;

internal Typeface(Bounds bounds, ushort unitsPerEm, List<Glyph> glyphs, List<CharacterMap> cmaps, HorizontalMetrics horizontalMetrics)
internal Typeface(Bounds bounds, ushort unitsPerEm, List<IGlyph> glyphs, List<CharacterMap> cmaps, HorizontalMetrics horizontalMetrics)
{
_bounds = bounds;
_unitsPerEm = unitsPerEm;
Expand All @@ -26,7 +26,7 @@ public int LookupIndex(char character)
return _cmaps[0].CharacterToGlyphIndex(character);
}

public Glyph Lookup(char character)
public IGlyph Lookup(char character)
{
return _glyphs[LookupIndex(character)];
}
Expand All @@ -38,6 +38,6 @@ public ushort GetAdvanceWidth(char character)

public Bounds Bounds { get { return _bounds; } }
public ushort UnitsPerEm { get { return _unitsPerEm; } }
public List<Glyph> Glyphs { get { return _glyphs; } }
public List<IGlyph> Glyphs { get { return _glyphs; } }
}
}

0 comments on commit 6cf3fb2

Please sign in to comment.