Exemplo n.º 1
0
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            // Get rid of this font from its factory cache when its disposed. Otherwise it'll live on in a half initialized state.
            Factory?.UnregisterFont(this);

            foreach (GorgonTexture2D texture in _internalTextures)
            {
                texture?.Dispose();
            }

            var brush = _info.Brush as IDisposable;

            brush?.Dispose();
            _internalTextures.Clear();
            KerningPairs.Clear();
            Glyphs.Clear();
        }
Exemplo n.º 2
0
        /// <summary>
        /// Function to retrieve the built in kerning pairs and advancement information for the font.
        /// </summary>
        /// <param name="graphics">The GDI graphics interface.</param>
        /// <param name="font">The GDI font.</param>
        /// <param name="allowedCharacters">The list of characters available to the font.</param>
        private Dictionary <char, ABC> GetKerningInformation(System.Drawing.Graphics graphics, Font font, IList <char> allowedCharacters)
        {
            Dictionary <char, ABC> advancementInfo;

            KerningPairs.Clear();

            IntPtr prevGdiHandle = Win32API.SetActiveFont(graphics, font);

            try
            {
                advancementInfo = Win32API.GetCharABCWidths(allowedCharacters[0], allowedCharacters[allowedCharacters.Count - 1]);

                if (!Info.UseKerningPairs)
                {
                    return(advancementInfo);
                }

                IList <KERNINGPAIR> kerningPairs = Win32API.GetKerningPairs();

                foreach (KERNINGPAIR pair in kerningPairs.Where(item => item.KernAmount != 0))
                {
                    var newPair = new GorgonKerningPair(Convert.ToChar(pair.First), Convert.ToChar(pair.Second));

                    if ((!allowedCharacters.Contains(newPair.LeftCharacter)) ||
                        (!allowedCharacters.Contains(newPair.RightCharacter)))
                    {
                        continue;
                    }

                    KerningPairs[newPair] = pair.KernAmount;
                }
            }
            finally
            {
                Win32API.RestoreActiveObject(prevGdiHandle);
            }

            return(advancementInfo);
        }
Exemplo n.º 3
0
 /// <summary>
 ///     Class constructor.
 /// </summary>
 /// <param name="pairs">Kerning pairs read from the TrueType font file.</param>
 /// <param name="converter">Class to convert from TTF to PDF units.</param>
 internal GdiKerningPairs(KerningPairs pairs, PdfUnitConverter converter)
 {
     this.pairs     = pairs;
     this.converter = converter;
 }
Exemplo n.º 4
0
        /// <summary>
        /// Function to perform word wrapping on a string based on this font.
        /// </summary>
        /// <param name="text">The text to word wrap.</param>
        /// <param name="wordWrapWidth">The maximum width, in pixels, that must be met for word wrapping to occur.</param>
        /// <returns>The string with word wrapping.</returns>
        /// <remarks>
        /// <para>
        /// The <paramref name="wordWrapWidth"/> is the maximum number of pixels required for word wrapping, if an individual font glyph cell width (the <see cref="GorgonGlyph.Offset"/> +
        /// <see cref="GorgonGlyph.Advance"/>) exceeds that of the <paramref name="wordWrapWidth"/>, then the parameter value is updated to glyph cell width.
        /// </para>
        /// </remarks>
        public string WordWrap(string text, float wordWrapWidth)
        {
            if (string.IsNullOrEmpty(text))
            {
                return(text);
            }

            var wordText = new StringBuilder(text);

            if (!Glyphs.TryGetValue(Info.DefaultCharacter, out GorgonGlyph defaultGlyph))
            {
                throw new GorgonException(GorgonResult.CannotEnumerate, string.Format(Resources.GORGFX_ERR_FONT_DEFAULT_CHAR_NOT_VALID, Info.DefaultCharacter));
            }

            int   maxLength = wordText.Length;
            int   index     = 0;
            float position  = 0.0f;
            bool  firstChar = true;

            while (index < maxLength)
            {
                char character = wordText[index];

                // Don't count newline or carriage return.
                if ((character == '\n') ||
                    (character == '\r'))
                {
                    firstChar = true;
                    position  = 0;
                    ++index;
                    continue;
                }


                if (!Glyphs.TryGetValue(character, out GorgonGlyph glyph))
                {
                    glyph = defaultGlyph;
                }

                float glyphCellWidth = glyph.Advance;

                if (firstChar)
                {
                    glyphCellWidth += glyph.Offset.X;
                    firstChar       = false;
                }

                // If we're using kerning, then adjust for the kerning value.
                if ((Info.UseKerningPairs) &&
                    (index < maxLength - 1))
                {
                    if (KerningPairs.TryGetValue(new GorgonKerningPair(character, wordText[index + 1]), out int kernValue))
                    {
                        glyphCellWidth += kernValue;
                    }
                }

                position += glyphCellWidth;

                // Update the word wrap boundary if the cell size exceeds it.
                if (glyphCellWidth > wordWrapWidth)
                {
                    wordWrapWidth = glyphCellWidth;
                }

                // We're not at the break yet.
                if (position < wordWrapWidth)
                {
                    ++index;
                    continue;
                }

                int whiteSpaceIndex = index;

                // If we hit the max width, then we need to find the previous whitespace and inject a newline.
                while ((whiteSpaceIndex <= index) && (whiteSpaceIndex >= 0))
                {
                    char breakChar = wordText[whiteSpaceIndex];

                    if ((char.IsWhiteSpace(breakChar)) &&
                        (breakChar != '\n') &&
                        (breakChar != '\r'))
                    {
                        index = whiteSpaceIndex;
                        break;
                    }

                    --whiteSpaceIndex;
                }

                // If we're at the beginning, then we cannot wrap this text, so we'll break it at the border specified.
                if (index != whiteSpaceIndex)
                {
                    if (index != 0)
                    {
                        wordText.Insert(index, '\n');
                        maxLength = wordText.Length;
                        ++index;
                    }
                    position  = 0;
                    firstChar = true;
                    // Move to next character.
                    ++index;
                    continue;
                }

                // Extract the space.
                wordText[whiteSpaceIndex] = '\n';
                position  = 0;
                firstChar = true;
                index     = whiteSpaceIndex + 1;
            }

            return(wordText.ToString());
        }
Exemplo n.º 5
0
        /// <summary>
        /// Function to measure the width of an individual line of text.
        /// </summary>
        /// <param name="line">The line to measure.</param>
        /// <param name="useOutline"><b>true</b> to use the font outline, <b>false</b> to disregard it.</param>
        /// <returns>The width of the line.</returns>
        private float GetLineWidth(string line, bool useOutline)
        {
            float size      = 0;
            bool  firstChar = true;

            if (!Glyphs.TryGetValue(Info.DefaultCharacter, out GorgonGlyph defaultGlyph))
            {
                throw new GorgonException(GorgonResult.CannotEnumerate, string.Format(Resources.GORGFX_ERR_FONT_DEFAULT_CHAR_NOT_VALID, Info.DefaultCharacter));
            }

            for (int i = 0; i < line.Length; i++)
            {
                char character = line[i];

                if (!Glyphs.TryGetValue(character, out GorgonGlyph glyph))
                {
                    glyph = defaultGlyph;
                }

                // Skip out on carriage returns and newlines.
                if ((character == '\r') ||
                    (character == '\n'))
                {
                    continue;
                }

                // Whitespace will use the glyph width.
                if (char.IsWhiteSpace(character))
                {
                    size += glyph.Advance;
                    continue;
                }

                // Include the initial offset.
                if (firstChar)
                {
                    size     += (useOutline && glyph.OutlineCoordinates.Width > 0) ? glyph.OutlineOffset.X : glyph.Offset.X;
                    firstChar = false;
                }

                size += glyph.Advance;

                if (!Info.UseKerningPairs)
                {
                    continue;
                }

                if ((i == line.Length - 1) ||
                    (KerningPairs.Count == 0))
                {
                    continue;
                }

                var kerning = new GorgonKerningPair(character, line[i + 1]);

                if (KerningPairs.TryGetValue(kerning, out int kernAmount))
                {
                    size += kernAmount;
                }
            }

            return(size);
        }