CharacterMetrics.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Media / CharacterMetrics.cs / 1305600 / CharacterMetrics.cs

                            //------------------------------------------------------------------------ 
//
//  Microsoft Windows Client Platform
//  Copyright (C) Microsoft Corporation, 2002
// 
//  File:      CharacterMetrics.cs
// 
//  Contents:  CharacterMetrics 
//
//  Created:   6-6-05 Niklas Borson (niklasb) 
//
//-----------------------------------------------------------------------

using System; 
using System.Globalization;
using StringBuilder = System.Text.StringBuilder; 
using CompositeFontParser = MS.Internal.FontFace.CompositeFontParser; 
using Constants = MS.Internal.TextFormatting.Constants;
using SR = MS.Internal.PresentationCore.SR; 
using SRID = MS.Internal.PresentationCore.SRID;

#pragma warning disable 1634, 1691  // suppressing PreSharp warnings
 
namespace System.Windows.Media
{ 
    ///  
    /// Metrics used to lay out a character in a device font.
    ///  
    public class CharacterMetrics
    {
        private double _blackBoxWidth;
        private double _blackBoxHeight; 
        private double _baseline;
        private double _leftSideBearing; 
        private double _rightSideBearing; 
        private double _topSideBearing;
        private double _bottomSideBearing; 

        private enum FieldIndex
        {
            BlackBoxWidth, 
            BlackBoxHeight,
            Baseline, 
            LeftSideBearing, 
            RightSideBearing,
            TopSideBearing, 
            BottomSideBearing
        }

        private const int NumFields = (int)FieldIndex.BottomSideBearing + 1; 
        private const int NumRequiredFields = (int)FieldIndex.BlackBoxHeight + 1;
 
        ///  
        /// Constructs a CharacterMetrics object with default values.
        ///  
        public CharacterMetrics()
        {
        }
 
        /// 
        /// Constructs a CharacterMetrics with the specified values. 
        ///  
        /// Value of the Metrics property.
        public CharacterMetrics(string metrics) 
        {
            if (metrics == null)
                throw new ArgumentNullException("metrics");
            Metrics = metrics; 
        }
 
        ///  
        /// String specifying the following properties in the following order: BlackBoxWidth, BlackBoxHeight,
        /// Baseline, LeftSideBearing, RightSideBearing, TopSideBearing, BottomSideBearing. Property values 
        /// are delimited by commas, and the first two properties are required. The remaining properties may
        /// be omitted and default to zero. For example, "0.75,0.75,,0.1" sets the first, second, and fourth
        /// properties to the specified values and the rest to zero.
        ///  
        public string Metrics
        { 
            get 
            {
                StringBuilder s = new StringBuilder(); 

                // The following fields are required.
                s.Append(_blackBoxWidth.ToString(System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS));
                s.Append(','); 
                s.Append(_blackBoxHeight.ToString(System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS));
 
                // Index of the last field we added to the string; this tells us how many commas to 
                // insert before the next optional field we add.
                int lastIndex = (int)FieldIndex.BlackBoxHeight; 

                // The following fields are optional, but must be in ascending order of field index.
                AppendField(_baseline, FieldIndex.Baseline, ref lastIndex, s);
                AppendField(_leftSideBearing, FieldIndex.LeftSideBearing, ref lastIndex, s); 
                AppendField(_rightSideBearing, FieldIndex.RightSideBearing, ref lastIndex, s);
                AppendField(_topSideBearing, FieldIndex.TopSideBearing, ref lastIndex, s); 
                AppendField(_bottomSideBearing, FieldIndex.BottomSideBearing, ref lastIndex, s); 

                return s.ToString(); 
            }

            set
            { 
                double[] metrics = ParseMetrics(value);
 
                // Validate all the values before we assign to any field. 
                CompositeFontParser.VerifyNonNegativeMultiplierOfEm("BlackBoxWidth", ref metrics[(int)FieldIndex.BlackBoxWidth]);
                CompositeFontParser.VerifyNonNegativeMultiplierOfEm("BlackBoxHeight", ref metrics[(int)FieldIndex.BlackBoxHeight]); 
                CompositeFontParser.VerifyMultiplierOfEm("Baseline", ref metrics[(int)FieldIndex.Baseline]);
                CompositeFontParser.VerifyMultiplierOfEm("LeftSideBearing", ref metrics[(int)FieldIndex.LeftSideBearing]);
                CompositeFontParser.VerifyMultiplierOfEm("RightSideBearing", ref metrics[(int)FieldIndex.RightSideBearing]);
                CompositeFontParser.VerifyMultiplierOfEm("TopSideBearing", ref metrics[(int)FieldIndex.TopSideBearing]); 
                CompositeFontParser.VerifyMultiplierOfEm("BottomSideBearing", ref metrics[(int)FieldIndex.BottomSideBearing]);
 
                double horizontalAdvance = metrics[(int)FieldIndex.BlackBoxWidth] 
                    + metrics[(int)FieldIndex.LeftSideBearing]
                    + metrics[(int)FieldIndex.RightSideBearing]; 
                if (horizontalAdvance < 0)
                    throw new ArgumentException(SR.Get(SRID.CharacterMetrics_NegativeHorizontalAdvance));

                double verticalAdvance = metrics[(int)FieldIndex.BlackBoxHeight] 
                    + metrics[(int)FieldIndex.TopSideBearing]
                    + metrics[(int)FieldIndex.BottomSideBearing]; 
                if (verticalAdvance < 0) 
                    throw new ArgumentException(SR.Get(SRID.CharacterMetrics_NegativeVerticalAdvance));
 
                // Set all the properties.
                _blackBoxWidth = metrics[(int)FieldIndex.BlackBoxWidth];
                _blackBoxHeight = metrics[(int)FieldIndex.BlackBoxHeight];
                _baseline = metrics[(int)FieldIndex.Baseline]; 
                _leftSideBearing = metrics[(int)FieldIndex.LeftSideBearing];
                _rightSideBearing = metrics[(int)FieldIndex.RightSideBearing]; 
                _topSideBearing = metrics[(int)FieldIndex.TopSideBearing]; 
                _bottomSideBearing = metrics[(int)FieldIndex.BottomSideBearing];
            } 
        }

        private static void AppendField(double value, FieldIndex fieldIndex, ref int lastIndex, StringBuilder s)
        { 
            if (value != 0)
            { 
                s.Append(',', (int)fieldIndex - lastIndex); 
                lastIndex = (int)fieldIndex;
                s.Append(value.ToString(System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS)); 
            }
        }

        private static double[] ParseMetrics(string s) 
        {
            double[] metrics = new double[NumFields]; 
 
            int i = 0, fieldIndex = 0;
            for (; ; ) 
            {
                // Let i be first non-whitespace character or end-of-string.
                while (i < s.Length && s[i] == ' ')
                    ++i; 

                // Let j be delimiter or end-of-string. 
                int j = i; 
                while (j < s.Length && s[j] != ',')
                    ++j; 

                // Let k be end-of-field without trailing whitespace.
                int k = j;
                while (k > i && s[k - 1] == ' ') 
                    --k;
 
                if (k > i) 
                {
                    // Non-empty field; convert it to double. 
                    string field = s.Substring(i, k - i);
                    if (!double.TryParse(
                        field,
                        NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, 
                        System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS,
                        out metrics[fieldIndex] 
                        )) 
                    {
                        throw new ArgumentException(SR.Get(SRID.CannotConvertStringToType, field, "double")); 
                    }
                }
                else if (fieldIndex < NumRequiredFields)
                { 
                    // Empty field; make sure it's an optional one.
                    throw new ArgumentException(SR.Get(SRID.CharacterMetrics_MissingRequiredField)); 
                } 

                ++fieldIndex; 

                if (j < s.Length)
                {
                    // There's a comma so check if we've exceeded the number of fields. 
                    if (fieldIndex == NumFields)
                        throw new ArgumentException(SR.Get(SRID.CharacterMetrics_TooManyFields)); 
 
                    // Initialize character index for next iteration.
                    i = j + 1; 
                }
                else
                {
                    // No more fields; check if we have all required fields. 
                    if (fieldIndex < NumRequiredFields)
                    { 
                        throw new ArgumentException(SR.Get(SRID.CharacterMetrics_MissingRequiredField)); 
                    }
 
                    break;
                }
            }
 
            return metrics;
        } 
 

        ///  
        /// Width of the black box for the character.
        /// 
        public double BlackBoxWidth
        { 
            get { return _blackBoxWidth; }
        } 
 
        /// 
        /// Height of the black box for the character. 
        /// 
        public double BlackBoxHeight
        {
            get { return _blackBoxHeight; } 
        }
 
        ///  
        /// Vertical offset from the bottom of the black box to the baseline. A positive
        /// value indicates the baseline is above the bottom of the black box, and a negative 
        /// value indicates the baseline is below the bottom of the black box.
        /// 
        public double Baseline
        { 
            get { return _baseline; }
        } 
 
        /// 
        /// Recommended white space to the left of the black box. A negative value results in 
        /// an overhang. The horizontal advance for the character is LeftSideBearing +
        /// BlackBoxWidth + RightSideBearing, and cannot be less than zero.
        /// 
        public double LeftSideBearing 
        {
            get { return _leftSideBearing; } 
        } 

        ///  
        /// Recommended white space to the right of the black box. A negative value results in
        /// an overhang. The horizontal advance for the character is LeftSideBearing +
        /// BlackBoxWidth + RightSideBearing, and cannot be less than zero.
        ///  
        public double RightSideBearing
        { 
            get { return _rightSideBearing; } 
        }
 
        /// 
        /// Recommended white space above the black box. A negative value results in
        /// an overhang. The vertical advance for the character is TopSideBearing +
        /// BlackBoxHeight + BottomSideBearing, and cannot be less than zero. 
        /// 
        public double TopSideBearing 
        { 
            get { return _topSideBearing; }
        } 

        /// 
        /// Recommended white space below the black box. A negative value results in
        /// an overhang. The vertical advance for the character is TopSideBearing + 
        /// BlackBoxHeight + BottomSideBearing, and cannot be less than zero.
        ///  
        public double BottomSideBearing 
        {
            get { return _bottomSideBearing; } 
        }


        ///  
        /// Compares two CharacterMetrics for equality.
        ///  
        public override bool Equals(object obj) 
        {
            CharacterMetrics other = obj as CharacterMetrics; 

            // Suppress PRESharp warning that other can be null; apparently PRESharp
            // doesn't understand short circuit evaluation of operator &&.
            #pragma warning disable 6506 
            return other != null &&
                other._blackBoxWidth == _blackBoxWidth && 
                other._blackBoxHeight == _blackBoxHeight && 
                other._leftSideBearing == _leftSideBearing &&
                other._rightSideBearing == _rightSideBearing && 
                other._topSideBearing == _topSideBearing &&
                other._bottomSideBearing == _bottomSideBearing;
            #pragma warning restore 6506
        } 

        ///  
        /// Computes a hash value for a CharacterMetrics. 
        /// 
        public override int GetHashCode() 
        {
            int hash = (int)(_blackBoxWidth * Constants.DefaultRealToIdeal);
            hash = (hash * HashMultiplier) + (int)(_blackBoxHeight * Constants.DefaultRealToIdeal);
            hash = (hash * HashMultiplier) + (int)(_baseline * Constants.DefaultRealToIdeal); 
            hash = (hash * HashMultiplier) + (int)(_leftSideBearing * Constants.DefaultRealToIdeal);
            hash = (hash * HashMultiplier) + (int)(_rightSideBearing * Constants.DefaultRealToIdeal); 
            hash = (hash * HashMultiplier) + (int)(_topSideBearing * Constants.DefaultRealToIdeal); 
            hash = (hash * HashMultiplier) + (int)(_bottomSideBearing * Constants.DefaultRealToIdeal);
            return hash; 
        }

        private const int HashMultiplier = 101;
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK