File: src\Framework\MS\Internal\Text\TypographyProperties.cs
Project: wpf\PresentationFramework.csproj (PresentationFramework)
//---------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
// 
// File: TypographyProperties.cs
//
// Description: Typography properties. 
//
// History:  
//  06/13/2003 : sergeym - created.
//
//---------------------------------------------------------------------------
 
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
 
namespace MS.Internal.Text
{
    /// <summary>
    /// Typography properties provider.
    /// </summary>
    internal sealed class TypographyProperties : TextRunTypographyProperties
    {
        /// <summary>
        /// Used as indexes to bitscale for boolean properties
        /// </summary>
        private enum PropertyId
        {
            /// <summary> StandardLigatures property </summary>
            StandardLigatures = 0,
            /// <summary> ContextualLigatures property </summary>
            ContextualLigatures = 1,
            /// <summary> DiscretionaryLigatures property </summary>
            DiscretionaryLigatures = 2,
            /// <summary> HistoricalLigatures property </summary>
            HistoricalLigatures = 3,
            /// <summary> CaseSensitiveForms property </summary>
            CaseSensitiveForms = 4,
            /// <summary> ContextualAlternates property </summary>
            ContextualAlternates = 5,
            /// <summary> HistoricalForms property </summary>
            HistoricalForms = 6,
            /// <summary> Kerning property </summary>
            Kerning = 7,
            /// <summary> CapitalSpacing property </summary>
            CapitalSpacing = 8,
            /// <summary> StylisticSet1 property </summary>
            StylisticSet1 = 9,
            /// <summary> StylisticSet2 property </summary>
            StylisticSet2 = 10,
            /// <summary> StylisticSet3 property </summary>
            StylisticSet3 = 11,
            /// <summary> StylisticSet4 property </summary>
            StylisticSet4 = 12,
            /// <summary> StylisticSet5 property </summary>
            StylisticSet5 = 13,
            /// <summary> StylisticSet6 property </summary>
            StylisticSet6 = 14,
            /// <summary> StylisticSet7 property </summary>
            StylisticSet7 = 15,
            /// <summary> StylisticSet8 property </summary>
            StylisticSet8 = 16,
            /// <summary> StylisticSet9 property </summary>
            StylisticSet9 = 17,
            /// <summary> StylisticSet10 property </summary>
            StylisticSet10 = 18,
            /// <summary> StylisticSet11 property </summary>
            StylisticSet11 = 19,
            /// <summary> StylisticSet12 property </summary>
            StylisticSet12 = 20,
            /// <summary> StylisticSet13 property </summary>
            StylisticSet13 = 21,
            /// <summary> StylisticSet14 property </summary>
            StylisticSet14 = 22,
            /// <summary> StylisticSet15 property </summary>
            StylisticSet15 = 23,
            /// <summary> StylisticSet16 property </summary>
            StylisticSet16 = 24,
            /// <summary> StylisticSet17 property </summary>
            StylisticSet17 = 25,
            /// <summary> StylisticSet18 property </summary>
            StylisticSet18 = 26,
            /// <summary> StylisticSet19 property </summary>
            StylisticSet19 = 27,
            /// <summary> StylisticSet20 property </summary>
            StylisticSet20 = 28,
            /// <summary> SlashedZero property </summary>
            SlashedZero = 29,
            /// <summary> MathematicalGreek property </summary>
            MathematicalGreek = 30,
            /// <summary> EastAsianExpertForms property </summary>
            EastAsianExpertForms = 31,
            /// <summary> 
            /// Total number of properties. Should not be >32. 
            /// Otherwise bitmask field _idPropertySetFlags should be changed to ulong 
            /// </summary>
            PropertyCount = 32
        }
 
        /// <summary>
        /// Create new typographyProperties with deefault values
        /// </summary>
        public TypographyProperties()
        {
            // Flags are stored in uint (32 bits).
            // Any way to check it at compile time?
            Debug.Assert((uint)PropertyId.PropertyCount <= 32);
            ResetProperties();
        }
 
        #region Public typography properties   
        /// <summary>
        /// 
        /// </summary>
        public override bool StandardLigatures
        {
            get { return IsBooleanPropertySet(PropertyId.StandardLigatures); }
        }
 
        public void SetStandardLigatures(bool value)
        {
            SetBooleanProperty(PropertyId.StandardLigatures, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool ContextualLigatures
        {
            get { return IsBooleanPropertySet(PropertyId.ContextualLigatures); }
        }
 
        public void SetContextualLigatures(bool value)
        {
            SetBooleanProperty(PropertyId.ContextualLigatures, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool DiscretionaryLigatures
        {
            get { return IsBooleanPropertySet(PropertyId.DiscretionaryLigatures); }
        }
 
        public void SetDiscretionaryLigatures(bool value)
        {
            SetBooleanProperty(PropertyId.DiscretionaryLigatures, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool HistoricalLigatures
        {
            get { return IsBooleanPropertySet(PropertyId.HistoricalLigatures); }
        }
 
        public void SetHistoricalLigatures(bool value)
        {
            SetBooleanProperty(PropertyId.HistoricalLigatures, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool CaseSensitiveForms
        {
            get { return IsBooleanPropertySet(PropertyId.CaseSensitiveForms); }
        }
 
        public void SetCaseSensitiveForms(bool value)
        {
            SetBooleanProperty(PropertyId.CaseSensitiveForms, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool ContextualAlternates
        {
            get { return IsBooleanPropertySet(PropertyId.ContextualAlternates); }
        }
 
        public void SetContextualAlternates(bool value)
        {
            SetBooleanProperty(PropertyId.ContextualAlternates, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool HistoricalForms
        {
            get { return IsBooleanPropertySet(PropertyId.HistoricalForms); }
        }
 
        public void SetHistoricalForms(bool value)
        {
            SetBooleanProperty(PropertyId.HistoricalForms, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool Kerning
        {
            get { return IsBooleanPropertySet(PropertyId.Kerning); }
        }
 
        public void SetKerning(bool value)
        {
            SetBooleanProperty(PropertyId.Kerning, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool CapitalSpacing
        {
            get { return IsBooleanPropertySet(PropertyId.CapitalSpacing); }
        }
 
        public void SetCapitalSpacing(bool value)
        {
            SetBooleanProperty(PropertyId.CapitalSpacing, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet1
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet1); }
        }
 
        public void SetStylisticSet1(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet1, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet2
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet2); }
        }
 
        public void SetStylisticSet2(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet2, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet3
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet3); }
        }
 
        public void SetStylisticSet3(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet3, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet4
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet4); }
        }
 
        public void SetStylisticSet4(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet4, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet5
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet5); }
        }
 
        public void SetStylisticSet5(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet5, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet6
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet6); }
        }
 
        public void SetStylisticSet6(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet6, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet7
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet7); }
        }
 
        public void SetStylisticSet7(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet7, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet8
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet8); }
        }
 
        public void SetStylisticSet8(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet8, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet9
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet9); }
        }
 
        public void SetStylisticSet9(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet9, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet10
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet10); }
        }
 
        public void SetStylisticSet10(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet10, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet11
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet11); }
        }
 
        public void SetStylisticSet11(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet11, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet12
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet12); }
        }
 
        public void SetStylisticSet12(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet12, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet13
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet13); }
        }
 
        public void SetStylisticSet13(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet13, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet14
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet14); }
        }
 
        public void SetStylisticSet14(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet14, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet15
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet15); }
        }
 
        public void SetStylisticSet15(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet15, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet16
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet16); }
        }
 
        public void SetStylisticSet16(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet16, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet17
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet17); }
        }
 
        public void SetStylisticSet17(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet17, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet18
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet18); }
        }
 
        public void SetStylisticSet18(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet18, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet19
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet19); }
        }
 
        public void SetStylisticSet19(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet19, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool StylisticSet20
        {
            get { return IsBooleanPropertySet(PropertyId.StylisticSet20); }
        }
 
        public void SetStylisticSet20(bool value)
        {
            SetBooleanProperty(PropertyId.StylisticSet20, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override FontFraction Fraction
        {
            get { return _fraction; }
        }
 
        public void SetFraction(FontFraction value)
        {
            _fraction = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool SlashedZero
        {
            get { return IsBooleanPropertySet(PropertyId.SlashedZero); }
        }
 
        public void SetSlashedZero(bool value)
        {
            SetBooleanProperty(PropertyId.SlashedZero, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool MathematicalGreek
        {
            get { return IsBooleanPropertySet(PropertyId.MathematicalGreek); }
        }
 
        public void SetMathematicalGreek(bool value)
        {
            SetBooleanProperty(PropertyId.MathematicalGreek, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override bool EastAsianExpertForms
        {
            get { return IsBooleanPropertySet(PropertyId.EastAsianExpertForms); }
        }
 
        public void SetEastAsianExpertForms(bool value)
        {
            SetBooleanProperty(PropertyId.EastAsianExpertForms, value);
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override FontVariants Variants
        {
            get { return _variant; }
        }
 
        public void SetVariants(FontVariants value)
        {
            _variant = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override FontCapitals Capitals
        {
            get { return _capitals; }
        }
 
        public void SetCapitals(FontCapitals value)
        {
            _capitals = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override FontNumeralStyle NumeralStyle
        {
            get { return _numeralStyle; }
        }
 
        public void SetNumeralStyle(FontNumeralStyle value)
        {
            _numeralStyle = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override FontNumeralAlignment NumeralAlignment
        {
            get { return _numeralAlignment; }
        }
 
        public void SetNumeralAlignment(FontNumeralAlignment value)
        {
            _numeralAlignment = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override FontEastAsianWidths EastAsianWidths
        {
            get { return _eastAsianWidths; }
        }
 
        public void SetEastAsianWidths(FontEastAsianWidths value)
        {
            _eastAsianWidths = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override FontEastAsianLanguage EastAsianLanguage
        {
            get { return _eastAsianLanguage; }
        }
 
        public void SetEastAsianLanguage(FontEastAsianLanguage value)
        {
            _eastAsianLanguage = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override int StandardSwashes
        {
            get { return _standardSwashes; }
        }
 
        public void SetStandardSwashes(int value)
        {
            _standardSwashes = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override int ContextualSwashes
        {
            get { return _contextualSwashes; }
        }
 
        public void SetContextualSwashes(int value)
        {
            _contextualSwashes = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override int StylisticAlternates
        {
            get { return _stylisticAlternates; }
        }
 
        public void SetStylisticAlternates(int value)
        {
            _stylisticAlternates = value;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// 
        /// </summary>
        public override int AnnotationAlternates
        {
            get { return _annotationAlternates; }
        }
 
        public void SetAnnotationAlternates(int value)
        {
            _annotationAlternates = value;
            OnPropertiesChanged();
        }
 
        #endregion Public typography properties
        
        /// <summary>
        /// Check whether two Property sets are equal
        /// </summary>
        /// <param name="other">property to compare</param>
        /// <returns></returns>
        public override bool Equals(object other)
        {
            if (other == null)
            {
                return false;
            }
 
            if (this.GetType() != other.GetType())
            {
                return false;
            }
 
            TypographyProperties genericOther = (TypographyProperties)other;
 
            return  //This will cover all boolean properties
                _idPropertySetFlags == genericOther._idPropertySetFlags &&
                //And this will cover the rest
                _variant == genericOther._variant && 
                _capitals == genericOther._capitals && 
                _fraction == genericOther._fraction && 
                _numeralStyle == genericOther._numeralStyle && 
                _numeralAlignment == genericOther._numeralAlignment && 
                _eastAsianWidths == genericOther._eastAsianWidths && 
                _eastAsianLanguage == genericOther._eastAsianLanguage && 
                _standardSwashes == genericOther._standardSwashes && 
                _contextualSwashes == genericOther._contextualSwashes && 
                _stylisticAlternates == genericOther._stylisticAlternates &&
                _annotationAlternates == genericOther._annotationAlternates;
        }
 
        public override int GetHashCode()
        {
            return (int)(_idPropertySetFlags >> 32) ^ 
                   (int)(_idPropertySetFlags & 0xFFFFFFFF) ^ 
                   (int)_variant << 28 ^ 
                   (int)_capitals << 24 ^ 
                   (int)_numeralStyle << 20 ^ 
                   (int)_numeralAlignment << 18 ^ 
                   (int)_eastAsianWidths << 14 ^ 
                   (int)_eastAsianLanguage << 10 ^ 
                   (int)_standardSwashes << 6 ^ 
                   (int)_contextualSwashes << 2 ^ 
                   (int)_stylisticAlternates ^ 
                   (int)_fraction << 16 ^ 
                   (int)_annotationAlternates << 12;
        }
 
        public static bool operator ==(TypographyProperties first, TypographyProperties second)
        {
            //Need to cast to object to do null comparision.
            if (((object)first) == null) return (((object)second) == null);
 
            return first.Equals(second);
        }
 
        public static bool operator !=(TypographyProperties first, TypographyProperties second)
        {
            return !(first == second);
        }
 
        #region Private methods
        /// <summary>
        /// Set all properties to default value
        /// </summary>
        private void ResetProperties()
        {
            //clean flags
            _idPropertySetFlags = 0;
 
            //assign non-trivial(not bolean) values
            _standardSwashes = 0;
            _contextualSwashes = 0;
            _stylisticAlternates = 0;
            _annotationAlternates = 0;
            _variant = FontVariants.Normal;
            _capitals = FontCapitals.Normal;
            _numeralStyle = FontNumeralStyle.Normal;
            _numeralAlignment = FontNumeralAlignment.Normal;
            _eastAsianWidths = FontEastAsianWidths.Normal;
            _eastAsianLanguage = FontEastAsianLanguage.Normal;
            _fraction = FontFraction.Normal;
            OnPropertiesChanged();
        }
 
        /// <summary>
        /// Check whether boolean property is set to non-default value
        /// </summary>
        /// <param name="propertyId">PropertyId</param>
        /// <returns></returns>
        private bool IsBooleanPropertySet(PropertyId propertyId)
        {
            Debug.Assert((uint)propertyId < (uint)PropertyId.PropertyCount, "Invalid typography property id");
 
            uint flagMask = (uint)(((uint)1) << ((int)propertyId));
 
            return (_idPropertySetFlags & flagMask) != 0;
        }
 
        /// <summary>
        ///     Set/clean flag that property value is non-default
        ///     Used only internally to support quick checks while forming FeatureSet
        ///     
        /// </summary>
        /// <param name="propertyId">Property id</param>
        /// <param name="flagValue">Value of the flag</param>
        private void SetBooleanProperty(PropertyId propertyId, bool flagValue)
        {
            Debug.Assert((uint)propertyId < (uint)PropertyId.PropertyCount, "Invalid typography property id");
 
            uint flagMask = (uint)(((uint)1) << ((int)propertyId));
 
            if (flagValue)
                _idPropertySetFlags |= flagMask;
            else
                _idPropertySetFlags &= ~flagMask;
 
            OnPropertiesChanged();
        }
 
        private uint _idPropertySetFlags;
 
        private int _standardSwashes;
 
        private int _contextualSwashes;
 
        private int _stylisticAlternates;
 
        private int _annotationAlternates;
 
        private FontVariants _variant;
 
        private FontCapitals _capitals;
 
        private FontFraction _fraction;
 
        private FontNumeralStyle _numeralStyle;
 
        private FontNumeralAlignment _numeralAlignment;
 
        private FontEastAsianWidths _eastAsianWidths;
 
        private FontEastAsianLanguage _eastAsianLanguage;
        #endregion Private members
    }
}