Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / MS / Internal / TextFormatting / NumberSubstitution.cs / 1 / NumberSubstitution.cs
using System; using System.Globalization; using System.Runtime.InteropServices; using System.Windows.Media; using System.Windows.Media.TextFormatting; using MS.Internal.FontCache; using MS.Internal.FontFace; using MS.Internal.Shaping; using MS.Win32; namespace MS.Internal.TextFormatting { ////// DigitState contains the high-level logic used to convert the number culture implied by /// text run properties to the low-level digit culture used for shaping. /// internal class DigitState { ////// DigitCulture gets a CultureInfo with the actual symbols and digits used for digit /// substitution. If no substitution is required, this property is null. /// internal CultureInfo DigitCulture { get { return _digitCulture; } } ////// RequiresNumberSubstitution is true if digit substitution is required (DigitCulture != null) /// and false if digit substitution is not required (DigitCulture == null). /// internal bool RequiresNumberSubstitution { get { return _digitCulture != null; } } ////// Contextual is true if contextual digit substitution is required. If so, DigitCulture specifies /// the digits to use in Arabic contexts. In non-Arabic contexts, null should be used as the /// digit culture. /// internal bool Contextual { get { return _contextual; } } ////// SetTextRunProperties initializes the DigitCulture and Contextual properties to reflect the /// specified text run properties. /// internal void SetTextRunProperties(TextRunProperties properties) { // Determine the number culture and substitution method. NumberSubstitutionMethod method; CultureInfo numberCulture = GetNumberCulture(properties, out method); // The digit culture is a function of the number culture and the substitution method. Only // determine the digit culture if either of these two parameters change. if (!object.ReferenceEquals(numberCulture, _lastNumberCulture) || method != _lastMethod) { _lastNumberCulture = numberCulture; _lastMethod = method; _digitCulture = GetDigitCulture(numberCulture, method, out _contextual); } } private CultureInfo GetNumberCulture(TextRunProperties properties, out NumberSubstitutionMethod method) { NumberSubstitution sub = properties.NumberSubstitution; if (sub == null) { method = NumberSubstitutionMethod.AsCulture; return CultureMapper.GetSpecificCulture(properties.CultureInfo); } method = sub.Substitution; switch (sub.CultureSource) { case NumberCultureSource.Text: return CultureMapper.GetSpecificCulture(properties.CultureInfo); case NumberCultureSource.User: return CultureInfo.CurrentCulture; case NumberCultureSource.Override: return sub.CultureOverride; } return null; } private CultureInfo GetDigitCulture(CultureInfo numberCulture, NumberSubstitutionMethod method, out bool contextual) { contextual = false; if (numberCulture == null) { return null; } if (method == NumberSubstitutionMethod.AsCulture) { switch (numberCulture.NumberFormat.DigitSubstitution) { case DigitShapes.Context: method = NumberSubstitutionMethod.Context; break; case DigitShapes.NativeNational: method = NumberSubstitutionMethod.NativeNational; break; default: return null; } } CultureInfo digitCulture; switch (method) { case NumberSubstitutionMethod.Context: if (IsArabic(numberCulture) || IsFarsi(numberCulture)) { contextual = true; digitCulture = GetTraditionalCulture(numberCulture); } else { digitCulture = null; } break; case NumberSubstitutionMethod.NativeNational: if (!HasLatinDigits(numberCulture)) { digitCulture = numberCulture; } else { digitCulture = null; } break; case NumberSubstitutionMethod.Traditional: digitCulture = GetTraditionalCulture(numberCulture); break; default: method = NumberSubstitutionMethod.European; digitCulture = null; break; } return digitCulture; } private static bool HasLatinDigits(CultureInfo culture) { string[] digits = culture.NumberFormat.NativeDigits; for (int i = 0; i < 10; ++i) { string d = digits[i]; if (d.Length != 1 || d[0] != (char)('0' + i)) return false; } return true; } private static bool IsArabic(CultureInfo culture) { return (culture.LCID & 0xFF) == 0x01; } private static bool IsFarsi(CultureInfo culture) { return (culture.LCID & 0xFF) == 0x29; } #region Traditional Cultures ////// Returns the digit culture to use for traditional number substitution given the /// specified number culture. /// private CultureInfo GetTraditionalCulture(CultureInfo numberCulture) { int lcid = numberCulture.LCID; // Do we already have a traditional culture for this LCID? if (_lastTraditionalCulture != null && _lastTraditionalCulture.LCID == lcid) { return _lastTraditionalCulture; } // Branch using the primary language ID (the low-order word of the LCID). If a language // maps to more than one script, we then branch on the entire LCID. The mapping of cultures // (LCIDs) to scripts is based on the following spreadsheet: // [....]/teams/giftweb/lme/typography/Font%20Technology%20Infrastructure/OpenType%20and%20OTLS/lcid%20to%20OT%20ScriptLang.xls. // // If the LCID maps to a script for which we have traditional digits, we return the // the corresponding property. For example, the Marathi and Sanscrit languages map to // the Devangari script so we return the TraditionalDevangari property. The script names // are the English names in ISO-15924 (http://www.unicode.org/iso15924/iso15924-codes.html). // The "Arabic" script is a special case as it has two sets of digits, and therefore two // properties: TraditionalArabic and TraditionalEasternArabic. // // See also the Uniscribe number substitution spec: // [....]/teams/giftweb/lme/typography/Font%20Technology%20Infrastructure/Uniscribe%20and%20Shaping%20Engines/Digit%20Substitution.doc. // CultureInfo digitCulture = null; switch (lcid & 0xFF) { case 0x01: // Arabic digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0660, // Unicode value of Arabic digit zero true); // Arabic percent, decimal, and group symbols break; case 0x1e: // Thai digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0e50, // Unicode value of Thai digit zero false); // European percent, decimal, and group symbols break; case 0x20: // Urdu case 0x29: // Persian digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x06F0, // Unicode value of Eastern Arabic digit zero true); // Arabic percent, decimal, and group symbols break; case 0x39: // Hindi digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0966, // Unicode value of Devanagari digit zero false); // European percent, decimal, and group symbols break; case 0x45: // Bengali digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x09e6, // Unicode value of Bengali digit zero false); // European percent, decimal, and group symbols break; case 0x46: // Punjabi // This language maps to more than one script; branch on the lcid. if (lcid == 0x0446) // Punjabi (India) digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0a66, // Unicode value of Gurmukhi digit zero false); // European percent, decimal, and group symbols else if (lcid == 0x0846) // Punjabi (Pakistan) digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x06F0, // Unicode value of Eastern Arabic digit zero true); // Arabic percent, decimal, and group symbols break; case 0x47: // Gujarati digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0ae6, // Unicode value of Gujarati digit zero false); // European percent, decimal, and group symbols break; case 0x48: // Oriya digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0b66, // Unicode value of Oriya digit zero false); // European percent, decimal, and group symbols break; case 0x49: // Tamil digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0be6, // Unicode value of Tamil digit zero false); // European percent, decimal, and group symbols break; case 0x4a: // Teluga digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0c66, // Unicode value of Teluga digit zero false); // European percent, decimal, and group symbols break; case 0x4b: // Kannada digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0ce6, // Unicode value of Kannada digit zero false); // European percent, decimal, and group symbols break; case 0x4c: // Malayalam digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0d66, // Unicode value of Malayalam digit zero false); // European percent, decimal, and group symbols break; case 0x4d: // Assamese digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x09e6, // Unicode value of Bengali digit zero false); // European percent, decimal, and group symbols break; case 0x4e: // Marathi case 0x4f: // Sanskrit digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0966, // Unicode value of Devanagari digit zero false); // European percent, decimal, and group symbols break; case 0x50: // Mongolian // This language maps to more than one script; branch on the lcid. if (lcid == 0x0850) // Mongolian (PRC) digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x1810, // Unicode value of Mongolian digit zero false); // European percent, decimal, and group symbols break; case 0x51: // Tibetan digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0f20, // Unicode value of Tibetan digit zero false); // European percent, decimal, and group symbols break; case 0x53: // Khmer digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x17e0, // Unicode value of Khmer digit zero false); // European percent, decimal, and group symbols break; case 0x54: // Lao digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0ed0, // Unicode value of Lao digit zero false); // European percent, decimal, and group symbols break; case 0x55: // Burmese digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x1040, // Unicode value of Myanmar (Burmese) digit zero false); // European percent, decimal, and group symbols break; case 0x57: // Konkani digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0966, // Unicode value of Devanagari digit zero false); // European percent, decimal, and group symbols break; case 0x58: // Manipuri - India digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x09e6, // Unicode value of Bengali digit zero false); // European percent, decimal, and group symbols break; case 0x59: // Sindhi // This language maps to more than one script; branch on the lcid. if (lcid == 0x0459) // Sindhi (India) digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0966, // Unicode value of Devanagari digit zero false); // European percent, decimal, and group symbols else if (lcid == 0x0859) // Sindhi (Pakistan) digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x06F0, // Unicode value of Eastern Arabic digit zero true); // Arabic percent, decimal, and group symbols break; case 0x5f: // Tamazight // This language maps to more than one script; branch on the lcid. if (lcid == 0x045f) // Tamazight (Berber/Arabic) digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0660, // Unicode value of Arabic digit zero true); // Arabic percent, decimal, and group symbols break; case 0x60: // Kashmiri // This language maps to more than one script; branch on the lcid. if (lcid == 0x0460) // Kashmiri (Arabic); ks-PK digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x06F0, // Unicode value of Eastern Arabic digit zero true); // Arabic percent, decimal, and group symbols else if (lcid == 0x0860) // Kashmiri; ks-IN digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0966, // Unicode value of Devanagari digit zero false); // European percent, decimal, and group symbols break; case 0x61: // Nepali digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x0966, // Unicode value of Devanagari digit zero false); // European percent, decimal, and group symbols break; case 0x63: // Pashto digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x06F0, // Unicode value of Eastern Arabic digit zero true); // Arabic percent, decimal, and group symbols break; case 0x8c: // Dari digitCulture = CreateTraditionalCulture( numberCulture, // culture to clone 0x06F0, // Unicode value of Eastern Arabic digit zero true); // Arabic percent, decimal, and group symbols break; } if (digitCulture == null) { // No hard-coded mapping for this LCID. Use the given culture if it has non-Latin digits, // otherwise return null. Don't cache the number culture because we didn't create it and // its digits may depend on other things than the LCID (e.g., it may be a custom culture). if (!HasLatinDigits(numberCulture)) { digitCulture = numberCulture; } } else { // We have a mapping for this LCID. Cache the digit culture in case we're called with // the same LCID again. _lastTraditionalCulture = digitCulture; } return digitCulture; } // Create a modifiable culture with the same properties as the specified number culture, // but with digits '0' through '9' starting at the specified unicode value. private CultureInfo CreateTraditionalCulture(CultureInfo numberCulture, int firstDigit, bool arabic) { // Create the digit culture by cloning the given number culture. According to MSDN, // "CultureInfo.Clone is a shallow copy with exceptions. The objects returned by // the NumberFormat and the DateTimeFormat properties are also cloned, so that the // CultureInfo clone can modify the properties of NumberFormat and DateTimeFormat // without affecting the original CultureInfo." CultureInfo digitCulture = (CultureInfo)numberCulture.Clone(); // Create the array of digits. string[] digits = new string[10]; if (firstDigit < 0x10000) { for (int i = 0; i < 10; ++i) { digits[i] = new string((char)(firstDigit + i), 1); } } else { for (int i = 0; i < 10; ++i) { int n = firstDigit + i - 0x10000; digits[i] = new string( new char[] { (char)((n >> 10) | 0xD800), // high surrogate (char)((n & 0x03FF) | 0xDC00) // low surrogate } ); } } // Set the digits. digitCulture.NumberFormat.NativeDigits = digits; if (arabic) { digitCulture.NumberFormat.PercentSymbol = "\u066a"; digitCulture.NumberFormat.NumberDecimalSeparator = "\u066b"; digitCulture.NumberFormat.NumberGroupSeparator = "\u066c"; } else { digitCulture.NumberFormat.PercentSymbol = "%"; digitCulture.NumberFormat.NumberDecimalSeparator = "."; digitCulture.NumberFormat.NumberGroupSeparator = ","; } return digitCulture; } private CultureInfo _lastTraditionalCulture; #endregion private NumberSubstitutionMethod _lastMethod; private CultureInfo _lastNumberCulture; private CultureInfo _digitCulture; private bool _contextual; } ////// DigitMap maps unicode code points (from the backing store) to unicode code /// points (to be rendered) based on a specified digit culture. /// internal struct DigitMap { private NumberFormatInfo _format; private string[] _digits; internal DigitMap(CultureInfo digitCulture) { if (digitCulture != null) { _format = digitCulture.NumberFormat; _digits = _format.NativeDigits; } else { _format = null; _digits = null; } } internal int this[int ch] { get { if (_format != null && IsDigitOrSymbol(ch)) { uint n = (uint)ch - '0'; if (n < 10) { ch = StringToScalar(_digits[n], ch); } else if (ch == '%') { ch = StringToScalar(_format.PercentSymbol, ch); } else if (ch == ',') { ch = StringToScalar(_format.NumberGroupSeparator, ch); } else { ch = StringToScalar(_format.NumberDecimalSeparator, ch); } } return ch; } } ////// In some cases, our first choice for a substituted code point is not present /// in many older fonts. To avoid displaying missing glyphs in such cases, this /// function returns the alternate character to fall back to if the specified /// substituted character does not exist in the font. The return value is zero /// if there is no fallback character. /// internal static int GetFallbackCharacter(int ch) { switch (ch) { case 0x066B: return (int)','; // Arabic decimal point -> Western comma case 0x066C: return 0x060C; // Arabic thousands separator -> Arabic comma case 0x0BE6: return (int)'0'; // Tamil zero -> Western zero } return 0; // no fallback character } private static int StringToScalar(string s, int defaultValue) { if (s.Length == 1) { return (int)s[0]; } else if (s.Length == 2 && DefaultShape.DefaultSurrogateShaper.IsHighSurrogate((int)s[0]) && DefaultShape.DefaultSurrogateShaper.IsLowSurrogate((int)s[1])) { return DefaultShape.DefaultSurrogateShaper.MakeUnicodeScalar((int)s[0], (int)s[1]); } else { return defaultValue; } } private static bool IsDigitOrSymbol(int ch) { // The code points we're interested in are in the range 0x25 - 0x39. const int first = 0x25; // percent const int last = 0x39; // '9' // Make sure we're in range. This is necessary because (mask >> N) // where N is some large number does not yield zero, but rather is // equivalent to (mask >> (N % 32)). if ((uint)(ch - first) <= (uint)(last - first)) { // Let mask be an array of bits indexed by code point, with // first as the base for indexing. const uint mask = (1U << ('%' - first)) | // U+0025 (1U << (',' - first)) | // U+002C (1U << ('.' - first)) | // U+002E (1U << ('0' - first)) | // U+0030 (1U << ('1' - first)) | // U+0031 (1U << ('2' - first)) | // U+0032 (1U << ('3' - first)) | // U+0033 (1U << ('4' - first)) | // U+0034 (1U << ('5' - first)) | // U+0035 (1U << ('6' - first)) | // U+0036 (1U << ('7' - first)) | // U+0037 (1U << ('8' - first)) | // U+0038 (1U << ('9' - first)); // U+0039 // Return the bit that correponds to the given code point. return ((mask >> (ch - first)) & 1) != 0; } else { // The code point is out of our given range. return false; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- PointKeyFrameCollection.cs
- WMIGenerator.cs
- PointAnimation.cs
- CardSpaceException.cs
- SafeReadContext.cs
- ProgressBar.cs
- webproxy.cs
- InitiatorSessionSymmetricMessageSecurityProtocol.cs
- KeyInterop.cs
- DbDeleteCommandTree.cs
- NativeObjectSecurity.cs
- ValidatorCompatibilityHelper.cs
- GridViewRowPresenter.cs
- XmlSchemaSequence.cs
- SmiEventSink.cs
- SoapSchemaImporter.cs
- FormViewModeEventArgs.cs
- ListViewUpdatedEventArgs.cs
- ComponentEditorForm.cs
- EditorPartDesigner.cs
- NavigationPropertySingletonExpression.cs
- CheckBoxFlatAdapter.cs
- EnlistmentState.cs
- ContractMapping.cs
- FileLevelControlBuilderAttribute.cs
- DbDataReader.cs
- WebSysDescriptionAttribute.cs
- ColumnCollection.cs
- CircleHotSpot.cs
- CollectionBuilder.cs
- ActivityTrace.cs
- SourceFileBuildProvider.cs
- Line.cs
- HotSpot.cs
- FontClient.cs
- ListViewInsertionMark.cs
- LinkLabelLinkClickedEvent.cs
- ISAPIRuntime.cs
- SHA384Managed.cs
- IResourceProvider.cs
- TypeToken.cs
- SortDescriptionCollection.cs
- SqlFlattener.cs
- WSTransactionSection.cs
- AcceptorSessionSymmetricTransportSecurityProtocol.cs
- AutomationEventArgs.cs
- HttpFileCollection.cs
- PTConverter.cs
- XPathMessageFilter.cs
- ServiceNameElementCollection.cs
- TextDecorationCollection.cs
- Misc.cs
- SchemaTypeEmitter.cs
- ZoneLinkButton.cs
- TableAdapterManagerHelper.cs
- PlatformNotSupportedException.cs
- HostingPreferredMapPath.cs
- PreviewPrintController.cs
- BadImageFormatException.cs
- DPCustomTypeDescriptor.cs
- SinglePageViewer.cs
- ConditionChanges.cs
- RemotingConfigParser.cs
- BackStopAuthenticationModule.cs
- ImportOptions.cs
- PropertyIDSet.cs
- SpecularMaterial.cs
- NamespaceQuery.cs
- HighlightComponent.cs
- CancellationHandler.cs
- XmlSchemaFacet.cs
- AQNBuilder.cs
- BinaryNode.cs
- XmlSerializerVersionAttribute.cs
- DrawingServices.cs
- DropDownList.cs
- EventLogInformation.cs
- SqlStatistics.cs
- HttpCacheVary.cs
- RegistrationServices.cs
- LocalFileSettingsProvider.cs
- DbParameterHelper.cs
- ConvertEvent.cs
- UrlUtility.cs
- Touch.cs
- ServiceOperationListItemList.cs
- EntityChangedParams.cs
- ReferencedType.cs
- CounterSampleCalculator.cs
- SmtpNtlmAuthenticationModule.cs
- TaskFileService.cs
- UnknownBitmapEncoder.cs
- GCHandleCookieTable.cs
- TypeValidationEventArgs.cs
- ExportOptions.cs
- TdsParameterSetter.cs
- DataError.cs
- DoubleLink.cs
- FormsIdentity.cs
- GPRECTF.cs