static int GetRelatedness(XmlLanguage keyLang, XmlLanguage userLang) { try { // Get equivalent cultures. CultureInfo keyCulture = CultureInfo.GetCultureInfoByIetfLanguageTag(keyLang.IetfLanguageTag); CultureInfo userCulture = CultureInfo.GetCultureInfoByIetfLanguageTag(userLang.IetfLanguageTag); if (!userCulture.IsNeutralCulture) { userCulture = userCulture.Parent; } // If the key is a prefix or parent of the user language it's a good match. if (IsPrefixOf(keyLang.IetfLanguageTag, userLang.IetfLanguageTag) || userCulture.Equals(keyCulture)) { return 2; } // If the key and user language share a common prefix or parent neutral culture, it's a reasonable match. if (IsPrefixOf(TrimSuffix(userLang.IetfLanguageTag), keyLang.IetfLanguageTag) || userCulture.Equals(keyCulture.Parent)) { return 1; } } catch (ArgumentException) { // Language tag with no corresponding CultureInfo. } // They're unrelated languages. return 0; }
private static bool Compatible(XmlLanguage lang, CultureInfo culture) { if (lang == null || lang == XmlLanguage.Empty) return true; var ll = lang.IetfLanguageTag.ToLowerInvariant(); while (!culture.Equals(CultureInfo.InvariantCulture)) { if (ll == culture.IetfLanguageTag.ToLowerInvariant()) return true; culture = culture.Parent; } return false; }
/// <summary> /// Construct a Family map object /// </summary> /// <param name="firstChar">first character</param> /// <param name="lastChar">last character</param> /// <param name="language">language</param> /// <param name="targetFamilyName">target family name</param> /// <param name="scaleInEm">font scale in EM</param> internal FontFamilyMap( int firstChar, int lastChar, XmlLanguage language, string targetFamilyName, double scaleInEm ) { if (firstChar == 0 && lastChar == LastUnicodeScalar) _ranges = _defaultRanges; else _ranges = new Range[]{ new Range(firstChar, lastChar) }; _language = language; _scaleInEm = scaleInEm; _targetFamilyName = targetFamilyName; }
private static void SetCulture( XmlLanguage lang, CultureInfo cult) { var propertynames = new[] { "_equivalentCulture", "_specificCulture", "_compatibleCulture" }; const BindingFlags flags = BindingFlags.ExactBinding | BindingFlags.SetField | BindingFlags.Instance | BindingFlags.NonPublic; foreach (var name in propertynames) { var field = typeof(XmlLanguage).GetField(name, flags); field.SetValue(lang, cult); } }
private void PrepareAttributes(InputScope inputScope, double fontSize, FontFamily fontFamily, XmlLanguage language, Visual visual, int count, Guid[] filterAttributes) { if (_preparedattributes == null) { _preparedattributes = new ArrayList(count); } else { _preparedattributes.Clear(); } int i; for (i = 0; i < _supportingattributes.Length; i++) { if (count != 0) { int j; bool found = false; for (j = 0; j < count; j++) { if (_supportingattributes[i].Guid.Equals(filterAttributes[j])) found = true; } if (!found) continue; } UnsafeNativeMethods.TS_ATTRVAL attrval = new UnsafeNativeMethods.TS_ATTRVAL(); attrval.attributeId = _supportingattributes[i].Guid; attrval.overlappedId = (int)_supportingattributes[i].Style; attrval.val = new NativeMethods.VARIANT(); // This VARIANT is returned to the caller, which supposed to call VariantClear(). // GC does not have to clear it. attrval.val.SuppressFinalize(); switch (_supportingattributes[i].Style) { case AttributeStyle.InputScope: object obj = new InputScopeAttribute(inputScope); attrval.val.vt = (short)NativeMethods.tagVT.VT_UNKNOWN; attrval.val.data1.Value = Marshal.GetIUnknownForObject(obj); break; case AttributeStyle.Font_Style_Height: // We always evaluate the font size and returns a value. attrval.val.vt = (short)NativeMethods.tagVT.VT_I4; attrval.val.data1.Value = (IntPtr)(int)fontSize; break; case AttributeStyle.Font_FaceName: { string familyName = GetFontFamilyName(fontFamily, language); if (familyName != null) { attrval.val.vt = (short)NativeMethods.tagVT.VT_BSTR; attrval.val.data1.Value = Marshal.StringToBSTR(familyName); } } break; case AttributeStyle.Font_SizePts: attrval.val.vt = (short)NativeMethods.tagVT.VT_I4; attrval.val.data1.Value = (IntPtr)(int)(fontSize / 96.0 * 72.0); break; case AttributeStyle.Text_ReadOnly: attrval.val.vt = (short)NativeMethods.tagVT.VT_BOOL; attrval.val.data1.Value = IsReadOnly ? (IntPtr)1 : (IntPtr)0; break; case AttributeStyle.Text_Orientation: attrval.val.vt = (short)NativeMethods.tagVT.VT_I4; attrval.val.data1.Value = (IntPtr)0; // Get the transformation that is relative from source. PresentationSource source = null; source = PresentationSource.CriticalFromVisual((Visual)RenderScope); if (source != null) { Visual root = source.RootVisual; if ((root != null) && (visual != null)) { // // Calc radian from Matirix. This is approximate calculation from the first row. // If tf.M12 is 0, angle will be 0. So we don't have to calc it. // GeneralTransform transform = visual.TransformToAncestor(root); Transform t = transform.AffineTransform; // if (t != null) { Matrix tf = t.Value; if ((tf.M11 != 0) || (tf.M12 != 0)) { double radSin = Math.Asin(tf.M12 / Math.Sqrt((tf.M11 * tf.M11) + (tf.M12 * tf.M12))); double radCos = Math.Acos(tf.M11 / Math.Sqrt((tf.M11 * tf.M11) + (tf.M12 * tf.M12))); // double angleSin = Math.Round((radSin * 180) / Math.PI, 0); double angleCos = Math.Round((radCos * 180) / Math.PI, 0); double angle; // determine angle from the sign of radSin; if (radSin <= 0) angle = angleCos; else angle = 360 - angleCos; attrval.val.data1.Value = (IntPtr)((int)angle * 10); } } } } break; case AttributeStyle.Text_VerticalWriting: // // attrval.val.vt = (short)NativeMethods.tagVT.VT_BOOL; attrval.val.data1.Value = (IntPtr)0; break; } _preparedattributes.Add(attrval); } }
// determine a family name from a FontFamily and XmlLanguage private static string GetFontFamilyName(FontFamily fontFamily, XmlLanguage language) { if (fontFamily == null) return null; // If the font family was constructed from a font name or URI, return that value. if (fontFamily.Source != null) return fontFamily.Source; // Use the dictionary of names provided by the font. LanguageSpecificStringDictionary names = fontFamily.FamilyNames; if (names == null) return null; // try every matching language to most-specific to least specific, including "" foreach (XmlLanguage matchingLanguage in language.MatchingLanguages) { string name = names[matchingLanguage]; if (name != null) return name; } // give up! return null; }
// Cache the Language property when it's used by DoDefaultExpansion, so // that we can detect changes. (This could also be done by a virtual // OnLanguageChanged method, if FrameworkElement ever defines one.) private void CacheLanguage(XmlLanguage language) { _language = language; }
// Returns the CultureInfo of the content at a position. // Returns null if there is no CultureInfo matching the current XmlLanguage. private CultureInfo GetCurrentCultureAndLanguage(ITextPointer position, out XmlLanguage language) { CultureInfo cultureInfo; bool hasModifiers; // TextBox takes the input language iff no local LanguageProperty is set. if (!_textEditor.AcceptsRichContent && _textEditor.UiScope.GetValueSource(FrameworkElement.LanguageProperty, null, out hasModifiers) == BaseValueSourceInternal.Default) { cultureInfo = _defaultCulture; language = XmlLanguage.GetLanguage(cultureInfo.IetfLanguageTag); } else { language = (XmlLanguage)position.GetValue(FrameworkElement.LanguageProperty); if (language == null) { cultureInfo = null; } else { try { cultureInfo = language.GetSpecificCulture(); } catch (InvalidOperationException) { // Someone set a bogus language on the run. cultureInfo = null; } } } return cultureInfo; }
// Returns the closest of either a halting position or the position preceding text // tagged with a differing XmlLanguage from a start position. private ITextPointer GetNextLanguageTransition(ITextPointer position, LogicalDirection direction, XmlLanguage language, ITextPointer haltPosition) { ITextPointer navigator = position.CreatePointer(); while ((direction == LogicalDirection.Forward && navigator.CompareTo(haltPosition) < 0) || (direction == LogicalDirection.Backward && navigator.CompareTo(haltPosition) > 0)) { if (GetCurrentLanguage(navigator) != language) break; navigator.MoveToNextContextPosition(direction); } // If we moved past haltPosition on the final MoveToNextContextPosition, move back. if ((direction == LogicalDirection.Forward && navigator.CompareTo(haltPosition) > 0) || (direction == LogicalDirection.Backward && navigator.CompareTo(haltPosition) < 0)) { navigator.MoveToPosition(haltPosition); } return navigator; }
public XmlLanguage(CultureInfo culture) { _language = System.Windows.Markup.XmlLanguage.GetLanguage(culture.IetfLanguageTag); }
//----------------------------------------------------------------------------------------------- private void Window_Loaded(object sender, RoutedEventArgs e) { FXmlLanguage = XmlLanguage.GetLanguage(FLanguage); this.SetFontSizeList(); this.SetLanguageList(); if (this.DlgFontWeight == FontWeights.Bold) chkBold.IsChecked = true; this.DlgSampleText = FSampleText; txtSample.Text = FSampleText; }
//--------------------------------------------------------------------------------------------- private void cmbLanguage_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (cmbLanguage.Items.Count < 1) return; ComboBoxItem item = cmbLanguage.SelectedItem as ComboBoxItem; FXmlLanguage = item.Tag as XmlLanguage; if (FXmlLanguage == null) FLanguage = null; else FLanguage = FXmlLanguage.IetfLanguageTag; this.UpdateFamilyName(); }
internal CultureInfo GetCultureInfo() { if (_ci == null || _lang != Language) { _lang = Language; _ci = Util.Util.GetEquivalentCulture(_lang); } return _ci; }
internal static bool MatchCulture(XmlLanguage familyMapLanguage, CultureInfo culture) { // If there is no family map langue, the family map applies to any language. if (familyMapLanguage == null) { return true; } if (culture != null) { return familyMapLanguage.RangeIncludes(culture); } return false; }
/// <summary> /// Returns information about which family maps apply to the specified culture. /// The return value is used by GetFamilyMapOfChar. /// </summary> internal ushort[] GetFamilyMapsOfLanguage(XmlLanguage language) { ushort[] ranges = null; // Look for a family map range for the specified language or one of its matching languages if (_familyMapRangesByLanguage != null && language != null) { foreach (XmlLanguage matchingLanguage in language.MatchingLanguages) { // break out of loop to handle default list of ranges if (matchingLanguage.IetfLanguageTag.Length == 0) break; if (_familyMapRangesByLanguage.TryGetValue(matchingLanguage, out ranges)) { // Recreate the list of ranges if we've added more family maps. if (!IsFamilyMapRangesValid(ranges)) { ranges = CreateFamilyMapRanges(matchingLanguage); _familyMapRangesByLanguage[matchingLanguage] = ranges; } return ranges; } } } // Use the default list of ranges (containing only family maps that match // any culture); recreate it if we've added more family maps. if (!IsFamilyMapRangesValid(_defaultFamilyMapRanges)) { _defaultFamilyMapRanges = CreateFamilyMapRanges(null); } return _defaultFamilyMapRanges; }
private ushort[] CreateFamilyMapRanges(XmlLanguage language) { // We could use an ArrayList, but a ushort[] is not much more code // and requires many fewer boxed objects. ushort[] ranges = new ushort[InitialFamilyMapRangesCapacity]; ranges[0] = (ushort)_familyMaps.Count; int count = 1; Debug.Assert(count == FirstFamilyMapRange); for (int i = 0; i < _familyMaps.Count; ++i) { if (FontFamilyMap.MatchLanguage(_familyMaps[i].Language, language)) { // grow ranges if necessary. if (count + 2 > ranges.Length) { ushort[] temp = new ushort[ranges.Length * 2 - FirstFamilyMapRange]; ranges.CopyTo(temp, 0); ranges = temp; } // beginning of range ranges[count++] = (ushort)i; ++i; while (i < _familyMaps.Count && FontFamilyMap.MatchLanguage(_familyMaps[i].Language, language)) { ++i; } // end of range, i.e., last index + 1 ranges[count++] = (ushort)i; } } // reallocate ranges to the exact size required if (count < ranges.Length) { ushort[] temp = new ushort[count]; Array.Copy(ranges, temp, count); ranges = temp; } return ranges; }
private void ExpandToWordBreakAndContext(ITextPointer position, LogicalDirection direction, XmlLanguage language, out ITextPointer contentPosition, out ITextPointer contextPosition) { ITextPointer start; ITextPointer end; ITextPointer outwardPosition; ITextPointer inwardPosition; TextMap textMap; ArrayList segments; SpellerInterop.STextRange sTextRange; LogicalDirection inwardDirection; int i; contentPosition = position; contextPosition = position; if (position.GetPointerContext(direction) == TextPointerContext.None) { // There is no following context, we're at document start/end. return; } // Disable spell checking functionality since we're only // interested in word breaks here. This greatly cuts down // the engine's workload. _spellerInterop.SetContextOption("IsSpellChecking", false); // // Build an array of wordbreak offsets surrounding the position. // // 1. Search outward, into surrounding text. We need MinWordBreaksForContext // word breaks to handle multi-word errors. outwardPosition = SearchForWordBreaks(position, direction, language, MinWordBreaksForContext, true /* stopOnError */); // 2. Search inward, towards content. We just need one word break inward. inwardDirection = direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward; inwardPosition = SearchForWordBreaks(position, inwardDirection, language, 1, false /* stopOnError */); // Get combined word breaks. This may not be the same as we calculated // in two parts above, since we don't know yet whether or not position is // on a word break. if (direction == LogicalDirection.Backward) { start = outwardPosition; end = inwardPosition; } else { start = inwardPosition; end = outwardPosition; } textMap = new TextMap(start, end, position, position); segments = new ArrayList(MinWordBreaksForContext + 1); _spellerInterop.EnumTextSegments(textMap.Text, textMap.TextLength, null, new SpellerInterop.EnumTextSegmentsCallback(ExpandToWordBreakCallback), segments); // // Use our table of word breaks to calculate context and content positions. // if (segments.Count == 0) { // No segments. This can happen if position is surrounded by // nothing but white space. We've already initialized contentPosition // and contextPosition so there's nothing to do. } else { int leftWordBreak; int rightWordBreak; int contentOffset; int contextOffset; // Figure out where position lives in the segment list. i = FindPositionInSegmentList(textMap, direction, segments, out leftWordBreak, out rightWordBreak); // contentPosition should be an edge on the segment we found. if (direction == LogicalDirection.Backward) { contentOffset = textMap.ContentStartOffset == rightWordBreak ? rightWordBreak : leftWordBreak; } else { contentOffset = textMap.ContentStartOffset == leftWordBreak ? leftWordBreak : rightWordBreak; } contentPosition = textMap.MapOffsetToPosition(contentOffset); // contextPosition should be MinWordBreaksForContext - 1 words away. if (direction == LogicalDirection.Backward) { i -= (MinWordBreaksForContext - 1); sTextRange = (SpellerInterop.STextRange)segments[Math.Max(i, 0)]; // We might actually follow contentOffset if we're at the document edge. // Don't let that happen. contextOffset = Math.Min(sTextRange.Start, contentOffset); } else { i += MinWordBreaksForContext; sTextRange = (SpellerInterop.STextRange)segments[Math.Min(i, segments.Count-1)]; // We might actually preceed contentOffset if we're at the document edge. // Don't let that happen. contextOffset = Math.Max(sTextRange.Start + sTextRange.Length, contentOffset); } contextPosition = textMap.MapOffsetToPosition(contextOffset); } // Final fixup: if the dirty range covers only formatting (which is not passed // to the speller engine) then we might actually "expand" in the wrong // direction, since the TextMap will jump over formatting. // Backup if necessary. if (direction == LogicalDirection.Backward) { if (position.CompareTo(contentPosition) < 0) { contentPosition = position; } if (position.CompareTo(contextPosition) < 0) { contextPosition = position; } } else { if (position.CompareTo(contentPosition) > 0) { contentPosition = position; } if (position.CompareTo(contextPosition) > 0) { contextPosition = position; } } }
public GlyphRun CreateGlyphRun(Point origin, XmlLanguage language) { return new GlyphRun( glyphTypeface, // GlyphTypeface bidiLevel, // Bidi level sideways, // sideways flag fontRenderingSize, // rendering em size in MIL units glyphIndices, // glyph indices origin, // origin of glyph-drawing space advanceWidths, // glyph advances glyphOffsets, // glyph offsets unicodeString.ToCharArray(), // unicode characters deviceFontName, // device font clusterMap, // cluster map caretStops, // caret stops language // language ); }
private ITextPointer SearchForWordBreaks(ITextPointer position, LogicalDirection direction, XmlLanguage language, int minWordCount, bool stopOnError) { ITextPointer closestErrorPosition; ITextPointer searchPosition; ITextPointer start; ITextPointer end; StaticTextPointer nextErrorTransition; int segmentCount; TextMap textMap; searchPosition = position.CreatePointer(); closestErrorPosition = null; if (stopOnError) { nextErrorTransition = _statusTable.GetNextErrorTransition(position.CreateStaticPointer(), direction); if (!nextErrorTransition.IsNull) { closestErrorPosition = nextErrorTransition.CreateDynamicTextPointer(LogicalDirection.Forward); } } bool hitBreakPoint = false; do { searchPosition.MoveByOffset(direction == LogicalDirection.Backward ? -ContextBlockSize : +ContextBlockSize); // Don't go past closestErrorPosition. if (closestErrorPosition != null) { if (direction == LogicalDirection.Backward && closestErrorPosition.CompareTo(searchPosition) > 0 || direction == LogicalDirection.Forward && closestErrorPosition.CompareTo(searchPosition) < 0) { searchPosition.MoveToPosition(closestErrorPosition); hitBreakPoint = true; } } // Don't venture into text in another language. ITextPointer closestLanguageTransition = GetNextLanguageTransition(position, direction, language, searchPosition); if (direction == LogicalDirection.Backward && closestLanguageTransition.CompareTo(searchPosition) > 0 || direction == LogicalDirection.Forward && closestLanguageTransition.CompareTo(searchPosition) < 0) { searchPosition.MoveToPosition(closestLanguageTransition); hitBreakPoint = true; } if (direction == LogicalDirection.Backward) { start = searchPosition; end = position; } else { start = position; end = searchPosition; } textMap = new TextMap(start, end, start, end); segmentCount = _spellerInterop.EnumTextSegments(textMap.Text, textMap.TextLength, null, null, null); } while (!hitBreakPoint && segmentCount < minWordCount + 1 && searchPosition.GetPointerContext(direction) != TextPointerContext.None); return searchPosition; }