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
- DataGridViewAutoSizeColumnsModeEventArgs.cs
- TypeDelegator.cs
- ProviderCollection.cs
- XmlSchemaIdentityConstraint.cs
- DbFunctionCommandTree.cs
- UInt64Converter.cs
- PublisherIdentityPermission.cs
- WebPartVerb.cs
- AdornerDecorator.cs
- WeakEventTable.cs
- TextBoxDesigner.cs
- RootBrowserWindow.cs
- Activity.cs
- XmlSignatureManifest.cs
- BlockCollection.cs
- TabControl.cs
- ItemDragEvent.cs
- ValidationService.cs
- CngKey.cs
- RuntimeEnvironment.cs
- DependencyObjectValidator.cs
- FontInfo.cs
- Events.cs
- XDRSchema.cs
- DataSetMappper.cs
- RemoteHelper.cs
- TextFormatterContext.cs
- Pkcs9Attribute.cs
- BitStack.cs
- WebPermission.cs
- RequestedSignatureDialog.cs
- FixedSOMFixedBlock.cs
- AsymmetricSignatureDeformatter.cs
- KeyInstance.cs
- TdsEnums.cs
- ContentHostHelper.cs
- DetailsViewRow.cs
- BooleanStorage.cs
- SecurityPermission.cs
- BinaryParser.cs
- DataObjectEventArgs.cs
- SoapSchemaExporter.cs
- CodeTypeConstructor.cs
- BaseAsyncResult.cs
- PanelDesigner.cs
- OdbcConnectionStringbuilder.cs
- mediaeventshelper.cs
- InvalidCastException.cs
- ErrorHandler.cs
- ClickablePoint.cs
- CardSpacePolicyElement.cs
- TabOrder.cs
- VariableModifiersHelper.cs
- NotifyInputEventArgs.cs
- ServiceNameElementCollection.cs
- WebServiceClientProxyGenerator.cs
- SchemaImporterExtensionsSection.cs
- Shape.cs
- DispatcherProcessingDisabled.cs
- TagMapInfo.cs
- TransportContext.cs
- DataControlReference.cs
- ItemCheckEvent.cs
- SqlMetaData.cs
- DBSqlParserTable.cs
- UserMapPath.cs
- ToolStripRenderer.cs
- XmlToDatasetMap.cs
- HebrewCalendar.cs
- ReadOnlyHierarchicalDataSourceView.cs
- XamlTreeBuilderBamlRecordWriter.cs
- SelectionManager.cs
- ContainsRowNumberChecker.cs
- ColorBlend.cs
- StringStorage.cs
- XslAst.cs
- SiteMapHierarchicalDataSourceView.cs
- SecurityKeyIdentifierClause.cs
- RoutedEvent.cs
- ToolboxComponentsCreatingEventArgs.cs
- NumberFormatter.cs
- DbModificationCommandTree.cs
- HttpCapabilitiesEvaluator.cs
- TextElementCollectionHelper.cs
- PropertyRecord.cs
- OrderPreservingPipeliningSpoolingTask.cs
- UnauthorizedWebPart.cs
- Attachment.cs
- UserInitiatedRoutedEventPermissionAttribute.cs
- SecurityManager.cs
- DoubleAnimation.cs
- Signature.cs
- DesignTimeResourceProviderFactoryAttribute.cs
- BitmapEffectGeneralTransform.cs
- DomainConstraint.cs
- Html32TextWriter.cs
- EventRoute.cs
- MessageQueuePermissionEntryCollection.cs
- ZoomPercentageConverter.cs
- Table.cs