/// <summary>
        /// Creates a <see cref="SpriteFontFaceDescription"/> from the specified input file.
        /// </summary>
        private static SpriteFontFaceDescription CreateSpriteFontFaceDescription(ContentManager manager, IContentProcessorMetadata metadata, XElement input)
        {
            if (input == null)
            {
                return(null);
            }

            var spriteFontFaceDesc = new SpriteFontFaceDescription();

            var textureElement = input.Element("Texture");

            spriteFontFaceDesc.Texture = (String)textureElement;

            var textureRegionElement = input.Element("TextureRegion");

            spriteFontFaceDesc.TextureRegion = (textureRegionElement == null) ? (Rectangle?)null :
                                               Rectangle.Parse((String)textureRegionElement);

            var glyphsElement = input.Element("Glyphs");

            if (glyphsElement != null)
            {
                var glyphsDesc = new SpriteFontFaceGlyphDescription();
                spriteFontFaceDesc.Glyphs = glyphsDesc;

                var substitutionElement = glyphsElement.Element("Substitution");
                glyphsDesc.Substitution = (substitutionElement == null) ? (Char?)null :
                                          Char.Parse((String)substitutionElement);
            }

            var kerningsElement = input.Element("Kernings");

            if (kerningsElement != null)
            {
                var kernings = new Dictionary <String, Int32>();
                spriteFontFaceDesc.Kernings = kernings;

                kernings["default"] = (Int32?)kerningsElement.Attribute("DefaultAdjustment") ?? 0;

                var kerningElements = kerningsElement.Elements("Kerning");
                foreach (var kerningElement in kerningElements)
                {
                    var kerningPair  = (String)kerningElement.Attribute("Pair");
                    var kerningValue = (Int32)kerningElement;

                    kernings[kerningPair] = kerningValue;
                }
            }

            return(spriteFontFaceDesc);
        }
        /// <summary>
        /// Exports a font face to the specified preprocessed asset stream.
        /// </summary>
        private static void ExportPreprocessedFace(ContentManager manager,
                                                   IContentProcessorMetadata metadata, BinaryWriter writer, SpriteFontFaceDescription description, String style, Boolean delete)
        {
            if (description == null)
            {
                writer.Write(false);
                return;
            }
            writer.Write(true);

            var textureName = ResolveDependencyAssetPath(metadata, description.Texture);

            writer.Write(textureName ?? String.Empty);

            var textureRegion = description.TextureRegion;

            writer.Write(textureRegion.HasValue);
            if (textureRegion.HasValue)
            {
                writer.Write(textureRegion.Value.X);
                writer.Write(textureRegion.Value.Y);
                writer.Write(textureRegion.Value.Width);
                writer.Write(textureRegion.Value.Height);
            }

            if (String.IsNullOrEmpty(textureName))
            {
                throw new ContentLoadException(OpenGLStrings.InvalidSpriteFontTexture);
            }

            var glyphs = default(IEnumerable <Rectangle>);

            using (var surface = manager.Import <SDL_Surface>(textureName))
                glyphs = OpenGLSpriteFontHelper.IdentifyGlyphs(surface, textureRegion);

            var substitution = description.Glyphs?.Substitution ?? '?';

            writer.Write(substitution);

            writer.Write(glyphs.Count());
            foreach (var glyph in glyphs)
            {
                writer.Write(glyph.X);
                writer.Write(glyph.Y);
                writer.Write(glyph.Width);
                writer.Write(glyph.Height);
            }

            var kerningDefaultAdjustment = description.Kernings?["default"] ?? 0;
            var kerning = description.Kernings?.Where(x => !String.Equals(x.Key, "default", StringComparison.InvariantCulture))
                          .ToDictionary(x => CreateKerningPair(x.Key), x => x.Value);

            writer.Write(kerningDefaultAdjustment);
            writer.Write(kerning.Count);
            foreach (var kvp in kerning)
            {
                writer.Write(kvp.Key.FirstCharacter);
                writer.Write(kvp.Key.SecondCharacter);
                writer.Write(kvp.Value);
            }
        }
        /// <summary>
        /// Processes the definition for a single font face.
        /// </summary>
        private static SpriteFontFace ProcessFace(Dictionary <String, SDL_Surface> textures, ContentManager manager,
                                                  IContentProcessorMetadata metadata, SpriteFontFaceDescription description, String style, IEnumerable <CharacterRegion> characterRegions)
        {
            if (description == null)
            {
                return(null);
            }

            var textureName   = ResolveDependencyAssetPath(metadata, description.Texture);
            var textureRegion = description.TextureRegion;

            if (String.IsNullOrEmpty(textureName))
            {
                throw new ContentLoadException(OpenGLStrings.InvalidSpriteFontTexture);
            }

            var faceSurface = textures[textureName];
            var faceGlyphs  = OpenGLSpriteFontHelper.IdentifyGlyphs(faceSurface, textureRegion);

            var faceTexture = manager.Load <Texture2D>(textureName);
            var face        = new SpriteFontFace(manager.Ultraviolet,
                                                 faceTexture, characterRegions, faceGlyphs, description.Glyphs?.Substitution ?? '?');

            var kerningDefaultAdjustment = description.Kernings?["default"] ?? 0;
            var kerning = description.Kernings?.Where(x => !String.Equals(x.Key, "default", StringComparison.InvariantCulture))
                          .ToDictionary(x => CreateKerningPair(x.Key), x => x.Value);

            face.Kerning.DefaultAdjustment = kerningDefaultAdjustment;

            foreach (var kvp in kerning)
            {
                face.Kerning.Set(kvp.Key, kvp.Value);
            }

            return(face);
        }