示例#1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GorgonFont"/> class.
 /// </summary>
 /// <param name="name">The name of the font.</param>
 /// <param name="factory">The factory that this font is registered with.</param>
 /// <param name="info">The information used to create the font.</param>
 /// <param name="fontHeight">The height of the font, in pixels.</param>
 /// <param name="lineHeight">The height of a line, in pixels.</param>
 /// <param name="ascent">The font ascent, in pixels.</param>
 /// <param name="descent">The font descent, in pixels.</param>
 /// <param name="glyphs">The glyphs for the font.</param>
 /// <param name="textures">The textures for the font.</param>
 /// <param name="kerningPairs">The kerning pairs for the font.</param>
 internal GorgonFont(string name,
                     GorgonFontFactory factory,
                     IGorgonFontInfo info,
                     float fontHeight,
                     float lineHeight,
                     float ascent,
                     float descent,
                     IReadOnlyList <GorgonGlyph> glyphs,
                     IReadOnlyList <GorgonTexture2D> textures,
                     IReadOnlyDictionary <GorgonKerningPair, int> kerningPairs)
     : base(name)
 {
     Factory = factory;
     _info   = new GorgonFontInfo(info)
     {
         Brush = info.Brush.Clone()
     };
     Graphics          = Factory.Graphics;
     FontHeight        = fontHeight;
     LineHeight        = lineHeight;
     Ascent            = ascent;
     Descent           = descent;
     Glyphs            = new GorgonGlyphCollection(glyphs);
     KerningPairs      = kerningPairs?.ToDictionary(k => k.Key, v => v.Value) ?? new Dictionary <GorgonKerningPair, int>();
     _internalTextures = new List <GorgonTexture2D>(textures);
 }
示例#2
0
        /// <summary>
        /// Function to write the font data to the stream.
        /// </summary>
        /// <param name="fontData">The font data to write.</param>
        /// <param name="stream">The stream to write into.</param>
        /// <remarks>
        /// <para>
        /// Implementors must override this method to write out the font data in the expected format.
        /// </para>
        /// </remarks>
        protected override void OnWriteFontData(GorgonFont fontData, Stream stream)
        {
            var             fontFile = new GorgonChunkFileWriter(stream, FileHeader.ChunkID());
            IGorgonFontInfo fontInfo = fontData.Info;

            try
            {
                fontFile.Open();

                GorgonBinaryWriter writer = fontFile.OpenChunk(FontInfoChunk);

                writer.Write(fontInfo.FontFamilyName);
                writer.Write(fontInfo.Size);
                writer.WriteValue(fontInfo.FontHeightMode);
                writer.WriteValue(fontInfo.FontStyle);
                writer.Write(fontInfo.DefaultCharacter);
                writer.Write(string.Join(string.Empty, fontInfo.Characters));
                writer.WriteValue(fontInfo.AntiAliasingMode);
                writer.Write(fontInfo.OutlineColor1.ToARGB());
                writer.Write(fontInfo.OutlineColor2.ToARGB());
                writer.Write(fontInfo.OutlineSize);
                writer.Write(fontInfo.PackingSpacing);
                writer.Write(fontInfo.TextureWidth);
                writer.Write(fontInfo.TextureHeight);
                writer.Write(fontInfo.UsePremultipliedTextures);
                writer.Write(fontInfo.UseKerningPairs);
                fontFile.CloseChunk();

                writer = fontFile.OpenChunk(FontHeightChunk);
                writer.Write(fontData.FontHeight);
                writer.Write(fontData.LineHeight);
                writer.Write(fontData.Ascent);
                writer.Write(fontData.Descent);
                fontFile.CloseChunk();

                if (fontInfo.Brush != null)
                {
                    writer = fontFile.OpenChunk(BrushChunk);
                    writer.Write((int)fontInfo.Brush.BrushType);
                    fontInfo.Brush.WriteBrushData(writer);
                    fontFile.CloseChunk();
                }

                if (fontInfo.UseKerningPairs)
                {
                    WriteKerningValues(fontData, fontFile);
                }
            }
            finally
            {
                fontFile.Close();
            }
        }
示例#3
0
        /// <summary>
        /// Function to determine if the font cache contains a font with the specified name, and the specified font information.
        /// </summary>
        /// <param name="fontInfo">The information about the font to find.</param>
        /// <returns><b>true</b> if found, <b>false</b> if not.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="fontInfo"/> parameter is <b>null</b>.</exception>
        /// <remarks>
        /// <para>
        /// The <see cref="IGorgonNamedObject.Name"/> value on the <paramref name="fontInfo"/> parameter is used in caching, and is user defined. It is not necessary to have it share the same name as the font family name in the
        /// <paramref name="fontInfo"/> parameter, however it is best practice to indicate the font family name in the name for ease of use. By default, this parameter is set to the font family, height and unit of measure.
        /// </para>
        /// <para>
        /// If a font with the same name was previously created by this factory, then this method will return <b>true</b> if the <paramref name="fontInfo"/> is the same as the cached version. If no font with the
        /// same name or the <paramref name="fontInfo"/> is different, then this method will return <b>false</b>.
        /// </para>
        /// </remarks>
        public bool HasFont(IGorgonFontInfo fontInfo)
        {
            if (fontInfo == null)
            {
                throw new ArgumentNullException(nameof(fontInfo));
            }

            lock (_syncLock)
            {
                return((_fontCache.TryGetValue(fontInfo.Name, out GorgonFont result)) &&
                       (!IsFontDifferent(fontInfo, result.Info)));
            }
        }
示例#4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GorgonFont"/> class.
 /// </summary>
 /// <param name="name">The name of the font.</param>
 /// <param name="factory">The factory that created this font.</param>
 /// <param name="info">The information used to generate the font.</param>
 internal GorgonFont(string name, GorgonFontFactory factory, IGorgonFontInfo info)
     : base(name)
 {
     Factory  = factory;
     Graphics = Factory.Graphics;
     _info    = new GorgonFontInfo(info)
     {
         Brush = info.Brush?.Clone()
     };
     _internalTextures = new List <GorgonTexture2D>();
     Glyphs            = new GorgonGlyphCollection();
     KerningPairs      = new Dictionary <GorgonKerningPair, int>();
 }
示例#5
0
        /// <summary>
        /// Function to build the font from the data provided.
        /// </summary>
        /// <param name="info">The font information used to generate the font.</param>
        /// <param name="fontHeight">The height of the font, in pixels.</param>
        /// <param name="lineHeight">The height of a line, in pixels.</param>
        /// <param name="ascent">The ascent for the font, in pixels.</param>
        /// <param name="descent">The descent for the font, in pixels.</param>
        /// <param name="textures">The textures associated with the font.</param>
        /// <param name="glyphs">The glyphs associated with the font.</param>
        /// <param name="kerningValues">The kerning values, if any, associated with the font.</param>
        /// <returns>A new <seealso cref="GorgonFont"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="info"/>, <paramref name="textures"/>, or the <paramref name="glyphs"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="textures"/>, or the <paramref name="glyphs"/> parameter is empty.</exception>
        /// <remarks>
        /// <para>
        /// Codec implementors should call this method once all information has been gathered for the font. This will load the font data into the <seealso cref="GorgonFont"/>, and store that font in the
        /// <seealso cref="Factory"/> cache for reuse.
        /// </para>
        /// <para>
        /// This method must be called because an application will not be able to create a <seealso cref="GorgonFont"/> directly.
        /// </para>
        /// </remarks>
        protected GorgonFont BuildFont(IGorgonFontInfo info,
                                       float fontHeight,
                                       float lineHeight,
                                       float ascent,
                                       float descent,
                                       IReadOnlyList <GorgonTexture2D> textures,
                                       IReadOnlyList <GorgonGlyph> glyphs,
                                       IReadOnlyDictionary <GorgonKerningPair, int> kerningValues)
        {
            if (info == null)
            {
                throw new ArgumentNullException(nameof(info));
            }

            if (textures == null)
            {
                throw new ArgumentNullException(nameof(textures));
            }

            if (textures.Count == 0)
            {
                throw new ArgumentException(Resources.GORGFX_ERR_PARAMETER_MUST_NOT_BE_EMPTY, nameof(textures));
            }

            if (glyphs == null)
            {
                throw new ArgumentNullException(nameof(glyphs));
            }

            if (glyphs.Count == 0)
            {
                throw new ArgumentException(Resources.GORGFX_ERR_PARAMETER_MUST_NOT_BE_EMPTY, nameof(glyphs));
            }

            GorgonFont result = null;

            try
            {
                result = new GorgonFont(info.Name, Factory, info, fontHeight, lineHeight, ascent, descent, glyphs, textures, kerningValues);

                // Register with the factory font cache.
                Factory.RegisterFont(result);

                return(result);
            }
            catch
            {
                result?.Dispose();
                throw;
            }
        }
示例#6
0
        /// <summary>
        /// Function to return or create a new <see cref="GorgonFont"/>.
        /// </summary>
        /// <param name="fontInfo">The information used to create the font.</param>
        /// <returns>A new or existing <see cref="GorgonFont"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="fontInfo"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentException">Thrown when the <see cref="IGorgonFontInfo.TextureWidth"/> or <see cref="IGorgonFontInfo.TextureHeight"/> parameters exceed the <see cref="IGorgonVideoAdapterInfo.MaxTextureWidth"/> or
        /// <see cref="IGorgonVideoAdapterInfo.MaxTextureHeight"/> available for the current <see cref="FeatureSet"/>.
        /// <para>-or-</para>
        /// <para>Thrown if the <see cref="IGorgonFontInfo.Characters"/> list does not contain the <see cref="IGorgonFontInfo.DefaultCharacter"/> character.</para>
        /// <para>-or-</para>
        /// <para>A font with the same name was already created by the factory, but does not have the same parameters.</para>
        /// </exception>
        /// <remarks>
        /// <para>
        /// This method creates an object that contains a group of textures with font glyphs.  These textures can be used by another application to display text (or symbols) on the screen.
        /// Kerning information (the proper spacing for a glyph), advances, etc... are all included for the glyphs with font.
        /// </para>
        /// <para>
        /// The <see cref="IGorgonNamedObject.Name"/> value on the <paramref name="fontInfo"/> parameter is used in caching, and is user defined. It is not necessary to have it share the same name as the
        /// font family name in the <paramref name="fontInfo"/> parameter, however it is best practice to indicate the font family name in the name for ease of use. By default, this parameter is set to the
        /// font family, height and unit of measure.
        /// </para>
        /// <para>
        /// If a font with the same name was previously created by this factory, then that font will be returned if the <paramref name="fontInfo"/> is the same as the cached version. If the font was not
        /// found by its name, then a new font will be created. Otherwise, if a cached font with the same name exists, but its <see cref="IGorgonFontInfo"/> is different from the <paramref name="fontInfo"/>
        /// passed in, then an exception will be thrown.
        /// </para>
        /// </remarks>
        public GorgonFont GetFont(IGorgonFontInfo fontInfo)
        {
            if (fontInfo == null)
            {
                throw new ArgumentNullException(nameof(fontInfo));
            }

            lock (_syncLock)
            {
                // Check the cache for a font with the same name.
                if ((_fontCache.TryGetValue(fontInfo.Name, out GorgonFont result)) &&
                    (!IsFontDifferent(fontInfo, result.Info)))
                {
                    return(result);
                }

                if (result != null)
                {
                    throw new ArgumentException(string.Format(Resources.GORGFX_ERR_FONT_EXISTS, fontInfo.Name), nameof(fontInfo));
                }

                if ((fontInfo.TextureWidth > Graphics.VideoAdapter.MaxTextureWidth) ||
                    (fontInfo.TextureHeight > Graphics.VideoAdapter.MaxTextureHeight))
                {
                    throw new ArgumentException(string.Format(Resources.GORGFX_ERR_FONT_TEXTURE_SIZE_TOO_LARGE,
                                                              fontInfo.TextureWidth,
                                                              fontInfo.TextureHeight),
                                                nameof(fontInfo));
                }

                if (!fontInfo.Characters.Contains(fontInfo.DefaultCharacter))
                {
                    throw new ArgumentException(string.Format(Resources.GORGFX_ERR_FONT_DEFAULT_CHAR_DOES_NOT_EXIST, fontInfo.DefaultCharacter));
                }

                if (Convert.ToInt32(fontInfo.DefaultCharacter) < 32)
                {
                    throw new ArgumentException(string.Format(Resources.GORGFX_ERR_FONT_DEFAULT_CHAR_NOT_VALID, Convert.ToInt32(fontInfo.DefaultCharacter)));
                }

                // Destroy the previous font if one exists with the same name.
                result?.Dispose();

                // If not found, then create a new font and cache it.
                _fontCache[fontInfo.Name] = result = new GorgonFont(fontInfo.Name, this, fontInfo);
                result.GenerateFont(new[] { _externalFonts });

                return(result);
            }
        }
示例#7
0
 /// <summary>
 /// Function to compare two <see cref="IGorgonFontInfo"/> types to determine equality.
 /// </summary>
 /// <param name="left">The left instance to compare.</param>
 /// <param name="right">The right instance to compare.</param>
 /// <returns><b>true</b> if the fonts are different, <b>false</b> if not.</returns>
 private static bool IsFontDifferent(IGorgonFontInfo left, IGorgonFontInfo right) => ((left.UseKerningPairs != right.UseKerningPairs) ||
                                                                                      (left.FontHeightMode != right.FontHeightMode) ||
                                                                                      (left.TextureWidth != right.TextureWidth) ||
                                                                                      (left.TextureHeight != right.TextureHeight) ||
                                                                                      (left.AntiAliasingMode != right.AntiAliasingMode) ||
                                                                                      (((left.Brush == null) && (right.Brush == null)) ||
                                                                                       ((left.Brush != null) && (left.Brush.Equals(right.Brush)))) ||
                                                                                      (left.DefaultCharacter != right.DefaultCharacter) ||
                                                                                      (!string.Equals(left.FontFamilyName, right.FontFamilyName, StringComparison.CurrentCultureIgnoreCase)) ||
                                                                                      (left.FontStyle != right.FontStyle) ||
                                                                                      (left.OutlineColor1 != right.OutlineColor1) ||
                                                                                      (left.OutlineColor2 != right.OutlineColor2) ||
                                                                                      (left.OutlineSize != right.OutlineSize) ||
                                                                                      (left.PackingSpacing != right.PackingSpacing) ||
                                                                                      (!left.Size.EqualsEpsilon(right.Size)) ||
                                                                                      (!left.Characters.SequenceEqual(right.Characters)));
示例#8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GlyphDraw"/> class.
 /// </summary>
 /// <param name="fontInfo">The font information used to create the font.</param>
 /// <param name="fontData">The font data for the glyphs.</param>
 public GlyphDraw(IGorgonFontInfo fontInfo, GdiFontData fontData)
 {
     _fontInfo = fontInfo;
     _fontData = fontData;
 }
示例#9
0
        /// <summary>
        /// Function to build out the font data.
        /// </summary>
        /// <param name="graphics">The graphics context to use.</param>
        /// <param name="fontInfo">The information used to generate the font.</param>
        /// <param name="externalFonts">The external fonts provided by an application.</param>
        /// <returns>A new <see cref="GdiFontData"/> object.</returns>
        public static GdiFontData GetFontData(System.Drawing.Graphics graphics, IGorgonFontInfo fontInfo, IEnumerable <PrivateFontCollection> externalFonts)
        {
            var result = new GdiFontData();

            CharacterRange[] range =
            {
                new CharacterRange(0, 1)
            };

            System.Drawing.FontStyle style = System.Drawing.FontStyle.Regular;

            switch (fontInfo.FontStyle)
            {
            case FontStyle.Bold:
                style = System.Drawing.FontStyle.Bold;
                break;

            case FontStyle.Italics:
                style = System.Drawing.FontStyle.Italic;
                break;

            case FontStyle.BoldItalics:
                style = System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic;
                break;
            }

            FontFamily fontFamily = (externalFonts != null ? (externalFonts.SelectMany(item => item.Families).Concat(FontFamily.Families)) : FontFamily.Families)
                                    .FirstOrDefault(item => string.Equals(fontInfo.FontFamilyName, item.Name, StringComparison.InvariantCultureIgnoreCase));

            // If we cannot locate the font family by name, then fall back.
            if (fontFamily == null)
            {
                fontFamily = FontFamily.GenericSerif;
            }


            // Scale the font appropriately.
            if (fontInfo.FontHeightMode == FontHeightMode.Points)
            {
                // Convert the internal font to pixel size.
                result.Font = new Font(fontFamily,
                                       (fontInfo.Size * graphics.DpiY) / 72.0f,
                                       style,
                                       GraphicsUnit.Pixel);
            }
            else
            {
                result.Font = new Font(fontFamily, fontInfo.Size, style, GraphicsUnit.Pixel);
            }

            result.FontHeight = result.Font.GetHeight(graphics);

            result.StringFormat = new StringFormat(StringFormat.GenericTypographic)
            {
                FormatFlags   = StringFormatFlags.NoFontFallback | StringFormatFlags.MeasureTrailingSpaces,
                Alignment     = StringAlignment.Near,
                LineAlignment = StringAlignment.Near
            };
            result.StringFormat.SetMeasurableCharacterRanges(range);

            // Create a separate drawing format because some glyphs are being clipped when they have overhang
            // on the left boundary.
            result.DrawFormat = new StringFormat(StringFormat.GenericDefault)
            {
                FormatFlags   = StringFormatFlags.NoFontFallback | StringFormatFlags.MeasureTrailingSpaces,
                Alignment     = StringAlignment.Near,
                LineAlignment = StringAlignment.Near
            };
            result.DrawFormat.SetMeasurableCharacterRanges(range);

            return(result);
        }