internal Font(FontStreamReader reader, OffsetTable offsetTable) { this.reader = reader; this.offsetTable = offsetTable; HeadTable = HeadTable.Read(reader, offsetTable.Entries["head"]); if (offsetTable.Entries.ContainsKey("fpgm")) { fpgmTable = FpgmTable.Read(reader, offsetTable.Entries["fpgm"]); } cmapTable = CmapTable.Read(reader, offsetTable.Entries["cmap"]); locaTable = LocaTable.Read(this, reader, offsetTable.Entries["loca"]); glyfTable = GlyfTable.Read(reader, offsetTable.Entries["glyf"]); //TODO run fpgm }
public OpenTypeFont Deserialize(BinaryReader reader) { var font = new OpenTypeFont { SfntVersion = DataTypeConverter.ReadFixed(reader) }; if (!_supportedSfntVersions.Contains(font.SfntVersion)) { throw new NotSupportedException("Bad sfnt version."); } // Table directory var numberOfTables = DataTypeConverter.ReadUShort(reader); reader.BaseStream.Position += 3 * DataTypeLength.UShort; // searchRange, entrySelector, rangeShift var entryList = Enumerable.Range(0, numberOfTables).Select(i => { var entry = new TableDirectoryEntry { Tag = DataTypeConverter.ReadTag(reader) }; reader.BaseStream.Position += DataTypeLength.ULong; // checksum entry.Offset = DataTypeConverter.ReadULong(reader); entry.Length = DataTypeConverter.ReadULong(reader); return(entry); }).ToList(); // Tables font.Tables.AddRange( entryList.OrderBy(entry => entry.Priority).Select <TableDirectoryEntry, IOpenTypeFontTable>(entry => { switch (entry.Tag) { case "cmap": return(CmapTable.Deserialize(reader, entry.Offset)); case "head": return(HeadTable.Deserialize(reader, entry.Offset)); case "maxp": return(MaxpTable.Deserialize(reader, entry.Offset)); case "loca": return(LocaTable.Deserialize(reader, entry.Offset, font.Get <MaxpTable>().NumberOfGlyphs, font.Get <HeadTable>().LocaTableVersion)); case "glyf": return(GlyfTable.Deserialize(reader, entry.Offset, entry.Length, font.Get <LocaTable>())); case "hhea": return(HheaTable.Deserialize(reader, entry.Offset)); case "hmtx": return(HmtxTable.Deserialize(reader, entry.Offset, font.Get <HheaTable>().NumberOfHMetrics, font.Get <MaxpTable>().NumberOfGlyphs)); case "post": return(PostTable.Deserialize(reader, entry.Offset)); default: return(BinaryDataTable.Deserialize(reader, entry.Offset, entry.Length, entry.Tag)); } })); return(font); }
private static IEnumerable <uint> GlyphIdsTransitiveClosure(ISet <uint> glyphIds, GlyfTable glyfTable, int depth = 0) { if (depth > 10) { throw new ArgumentOutOfRangeException("depth", "Too many composite redirects."); } var compositeGlyphs = glyfTable.Glyphs.OfType <CompositeGlyph>().Where(glyph => glyphIds.Contains(glyph.Id)).ToList(); if (!compositeGlyphs.Any()) { return(glyphIds); } glyphIds.UnionWith( GlyphIdsTransitiveClosure( new HashSet <uint>( compositeGlyphs.SelectMany(glyph => glyph.Components) .Select(component => (uint)component.GlyphId)), glyfTable, depth + 1)); return(glyphIds); }