private void FillOpenType(TinyFont font)
        {
            HashSet <ushort> userGlyphs = new HashSet <ushort>();

            foreach (CharacterImportInfo info in EnumerateAllImports())
            {
                if (info.Mapping.Glyph.HasValue)
                {
                    userGlyphs.Add(info.Mapping.Glyph.Value);
                }
            }

            Dictionary <ushort, BuilderState> allGeneratedGlyphs = new Dictionary <ushort, BuilderState>();

            foreach (FeatureImportInfo feature in _features.Where(f => f.Type == FeatureImportType.Substitution))
            {
                foreach (ushort generatedGlyph in _compiler.GetGeneratedGlyphIds(feature.BuilderState.GlyphTypeface, feature.Script, feature.Language, feature.Feature))
                {
                    allGeneratedGlyphs[generatedGlyph] = feature.BuilderState;
                }
            }

            GlyphClassesAppendix classes      = font.GetOrAddNewAppendix <GlyphClassesAppendix>();
            SubstitutionAppendix substitution = font.GetOrAddNewAppendix <SubstitutionAppendix>();
            PositioningAppendix  positioning  = font.GetOrAddNewAppendix <PositioningAppendix>();

            Dictionary <ushort, BuilderState> glyphsToAdd = new Dictionary <ushort, BuilderState>();

            foreach (FeatureImportInfo feature in _features.Where(f => f.Type == FeatureImportType.Substitution))
            {
                foreach (ushort generatedGlyph in _compiler.CompileFeature(feature.BuilderState.GlyphTypeface, feature.Script, feature.Language, feature.Feature, substitution, classes, allGeneratedGlyphs.Keys.Concat(userGlyphs)))
                {
                    glyphsToAdd[generatedGlyph] = feature.BuilderState;
                }
            }

            foreach (KeyValuePair <ushort, BuilderState> toAddPair in glyphsToAdd)
            {
                if (!userGlyphs.Contains(toAddPair.Key))
                {
                    int character;

                    if (toAddPair.Value.GlyphToCharacterMap.TryGetValue(toAddPair.Key, out character))
                    {
                        _characterImportList[character] = new CharacterImportInfo(toAddPair.Value, new CharacterGlyphPair(character, toAddPair.Key));
                    }
                    else if (toAddPair.Key < toAddPair.Value.GlyphTypeface.GlyphCount)
                    {
                        _glyphImportList.Add(new CharacterImportInfo(toAddPair.Value, new CharacterGlyphPair(null, toAddPair.Key)));
                    }

                    userGlyphs.Add(toAddPair.Key);
                }
            }

            foreach (FeatureImportInfo feature in _features.Where(f => f.Type == FeatureImportType.Positioning))
            {
                _compiler.CompileFeature(feature.BuilderState.GlyphTypeface, feature.Script, feature.Language, feature.Feature, positioning, classes, allGeneratedGlyphs.Keys.Concat(userGlyphs), feature.BuilderState.EmSize);
            }
        }
        private void FillVerticalMetrics(TinyFont font)
        {
            GlyphMetadataAppendix metadata = font.GetOrAddNewAppendix <GlyphMetadataAppendix>();

            List <sbyte> marginTop    = new List <sbyte>();
            List <sbyte> marginBottom = new List <sbyte>();

            foreach (CharacterImportInfo info in from import in _characterImportList.Values
                     orderby import.Mapping.Character
                     select import)
            {
                marginTop.Add(Helper.FitIntoInt8(info.EmSideBearing.Top, Trace));
                marginBottom.Add(Helper.FitIntoInt8(info.EmSideBearing.Bottom, Trace));
            }

            foreach (CharacterImportInfo info in _glyphImportList)
            {
                marginTop.Add(Helper.FitIntoInt8(info.EmSideBearing.Top, Trace));
                marginBottom.Add(Helper.FitIntoInt8(info.EmSideBearing.Bottom, Trace));
            }

            GlyphMetadataAppendix.MetadataSetOffset offsetTop = new GlyphMetadataAppendix.MetadataSetOffset();
            offsetTop.Id   = GlyphMetadataAppendix.MarginTopSet;
            offsetTop.Bits = GlyphMetadataAppendix.MetadataSetBitLength.Eight;

            metadata.Sets.Add(marginTop.Select(m => (byte)m).ToArray());
            metadata.SetsOffsets.Add(offsetTop);

            GlyphMetadataAppendix.MetadataSetOffset offsetBottom = new GlyphMetadataAppendix.MetadataSetOffset();
            offsetBottom.Id   = GlyphMetadataAppendix.MarginBottomSet;
            offsetBottom.Bits = GlyphMetadataAppendix.MetadataSetBitLength.Eight;

            metadata.Sets.Add(marginBottom.Select(m => (byte)m).ToArray());
            metadata.SetsOffsets.Add(offsetBottom);
        }
        private void FillGraphemeClusterBoundaries(TinyFont font)
        {
            GlyphMetadataAppendix metadata = font.GetOrAddNewAppendix <GlyphMetadataAppendix>();

            byte[] clusterBoundaries = Resources.GraphemeBreakProperty;

            BitArray data = new BitArray(0);

            foreach (CharacterInfo info in font.EnumerateAllCharacterInfos())
            {
                byte property = FindClusterProperty(clusterBoundaries, info.Codepoint);
                data.AppendLsb(property, 4);
            }

            byte[] setData = new byte[(data.Length + 7) / 8];
            data.CopyTo(setData, 0);

            metadata.Sets.Add(setData);
            GlyphMetadataAppendix.MetadataSetOffset offset = new GlyphMetadataAppendix.MetadataSetOffset();
            offset.Id   = GlyphMetadataAppendix.GraphemeSet;
            offset.Bits = GlyphMetadataAppendix.MetadataSetBitLength.Four;

            metadata.SetsOffsets.Add(offset);
        }