internal FormatSettings( TextFormatterImp formatter, TextSource textSource, TextRunCacheImp runCache, ParaProp pap, TextLineBreak previousLineBreak, bool isSingleLineFormatting, TextFormattingMode textFormattingMode, bool isSideways ) { _isSideways = isSideways; _textFormattingMode = textFormattingMode; _formatter = formatter; _textSource = textSource; _runCache = runCache; _pap = pap; _digitState = new DigitState(); _previousLineBreak = previousLineBreak; _maxLineWidth = Constants.IdealInfiniteWidth; if (isSingleLineFormatting) { // Apply text indent on each line in single line mode _textIndent = _pap.Indent; } }
/// <summary> /// Construct an instance of TextFormatter implementation with the specified context /// </summary> /// <param name="soleContext"></param> /// <remarks> /// TextFormatter created via this special ctor takes a specified context and uses it as the only known /// context within its entire lifetime. It prohibits reentering of TextFormatter during formatting as only /// one context is allowed. This restriction is critical to the optimal break algorithm supported by the current /// version of PTLS. /// </remarks> internal TextFormatterImp(TextFormatterContext soleContext, TextFormattingMode textFormattingMode) { _textFormattingMode = textFormattingMode; if (soleContext != null) _contextList.Add(soleContext); _multipleContextProhibited = (_contextList.Count != 0); }
public static void SetTextFormattingMode(DependencyObject element, TextFormattingMode value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(TextFormattingModeProperty, value); }
public static void SetTextFormattingMode(FrameworkElement element, TextFormattingMode value) { if (element == null) { throw new ArgumentNullException("element"); } element.SetValue(TextFormattingModeProperty, value); }
//------------------------------------------------------------------- // // Internal Methods // //------------------------------------------------------------------- #region Internal Methods /// <summary> /// Acquires new PTS Context and associates it with new owner. /// </summary> /// <param name="ptsContext">Context used to communicate with PTS component.</param> internal static PtsHost AcquireContext(PtsContext ptsContext, TextFormattingMode textFormattingMode) { PtsCache ptsCache = ptsContext.Dispatcher.PtsCache as PtsCache; if (ptsCache == null) { ptsCache = new PtsCache(ptsContext.Dispatcher); ptsContext.Dispatcher.PtsCache = ptsCache; } return ptsCache.AcquireContextCore(ptsContext, textFormattingMode); }
/// <summary> /// Client to create a new instance of TextFormatter /// </summary> /// <returns>New instance of TextFormatter</returns> static public TextFormatter Create(TextFormattingMode textFormattingMode) { if ((int)textFormattingMode < 0 || (int)textFormattingMode > 1) { throw new System.ComponentModel.InvalidEnumArgumentException("textFormattingMode", (int)textFormattingMode, typeof(TextFormattingMode)); } // create a new instance of TextFormatter which allows the use of multiple contexts. return(new TextFormatterImp(textFormattingMode)); }
/// <summary> /// Client to create a new instance of TextFormatter /// </summary> /// <returns>New instance of TextFormatter</returns> static public TextFormatter Create(TextFormattingMode textFormattingMode) { if ((int)textFormattingMode < 0 || (int)textFormattingMode > 1) { throw new System.ComponentModel.InvalidEnumArgumentException("textFormattingMode", (int)textFormattingMode, typeof(TextFormattingMode)); } // create a new instance of TextFormatter which allows the use of multiple contexts. return new TextFormatterImp(textFormattingMode); }
/// <summary> /// Ensures the PtsContext exists. /// </summary> private void EnsurePtsContext() { if (_ptsContext == null) { TextFormattingMode textFormattingMode = TextOptions.GetTextFormattingMode(this.PropertyOwner); _ptsContext = new PtsContext(true, textFormattingMode); _textFormatterHost = new TextFormatterHost(_ptsContext.TextFormatter, textFormattingMode); _section = new MS.Internal.PtsHost.Section(this); } }
/// <summary> /// Empty private constructor /// </summary> private FullTextLine(TextFormattingMode textFormattingMode, bool justify, double pixelsPerDip) : base(pixelsPerDip) { _textFormattingMode = textFormattingMode; if (justify) { _statusFlags |= StatusFlags.IsJustified; } _metrics = new TextMetrics(); _metrics._pixelsPerDip = pixelsPerDip; }
// Token: 0x06006A7B RID: 27259 RVA: 0x001E4664 File Offset: 0x001E2864 private void EnsurePtsContext() { if (this._ptsContext == null) { TextFormattingMode textFormattingMode = TextOptions.GetTextFormattingMode(this.PropertyOwner); this._ptsContext = new PtsContext(true, textFormattingMode); this._textFormatterHost = new TextFormatterHost(this._ptsContext.TextFormatter, textFormattingMode, this._owner.PixelsPerDip); this._section = new Section(this); } }
/// <summary> /// Construct an instance of TextFormatter implementation with the specified context /// </summary> /// <param name="soleContext"></param> /// <remarks> /// TextFormatter created via this special ctor takes a specified context and uses it as the only known /// context within its entire lifetime. It prohibits reentering of TextFormatter during formatting as only /// one context is allowed. This restriction is critical to the optimal break algorithm supported by the current /// version of PTLS. /// </remarks> internal TextFormatterImp(TextFormatterContext soleContext, TextFormattingMode textFormattingMode) { _textFormattingMode = textFormattingMode; if (soleContext != null) { _contextList.Add(soleContext); } _multipleContextProhibited = (_contextList.Count != 0); }
internal static PtsHost AcquireContext(PtsContext ptsContext, TextFormattingMode textFormattingMode) { PtsCache ptsCache = ptsContext.Dispatcher.PtsCache as PtsCache; if (ptsCache == null) { ptsCache = new PtsCache(ptsContext.Dispatcher); ptsContext.Dispatcher.PtsCache = ptsCache; } return(ptsCache.AcquireContextCore(ptsContext, textFormattingMode)); }
internal static double RoundDip(double value, TextFormattingMode textFormattingMode) { if (TextFormattingMode.Display == textFormattingMode) { return(RoundDipForDisplayMode(value)); } else { return(value); } }
internal TextFormatterHost(TextFormatter textFormatter, TextFormattingMode textFormattingMode) { if (textFormatter == null) { TextFormatter = TextFormatter.FromCurrentDispatcher(textFormattingMode); } else { TextFormatter = textFormatter; } }
internal TextFormatterHost(TextFormatter textFormatter, TextFormattingMode textFormattingMode) { if(textFormatter == null) { TextFormatter = TextFormatter.FromCurrentDispatcher(textFormattingMode); } else { TextFormatter = textFormatter; } }
internal PtsContext(bool isOptimalParagraphEnabled, TextFormattingMode textFormattingMode) { _pages = new ArrayList(1); _pageBreakRecords = new ArrayList(1); _unmanagedHandles = new HandleIndex[_defaultHandlesCapacity]; // Limit initial size _isOptimalParagraphEnabled = isOptimalParagraphEnabled; BuildFreeList(1); // 1 is the first free index in UnmanagedHandles array // Acquire PTS Context _ptsHost = PtsCache.AcquireContext(this, textFormattingMode); }
//------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors /// <summary> /// Constructor. /// </summary> /// <remarks> /// The array of entries initially can store up to 16 entries. Upon /// adding elements the capacity increased in multiples of two as /// required. The first element always contains index to the next /// free entry. All free entries are forming a linked list. /// </remarks> internal PtsContext(bool isOptimalParagraphEnabled, TextFormattingMode textFormattingMode) { _pages = new ArrayList(1); _pageBreakRecords = new ArrayList(1); _unmanagedHandles = new HandleIndex[_defaultHandlesCapacity]; // Limit initial size _isOptimalParagraphEnabled = isOptimalParagraphEnabled; BuildFreeList(1); // 1 is the first free index in UnmanagedHandles array // Acquire PTS Context _ptsHost = PtsCache.AcquireContext(this, textFormattingMode); }
// Token: 0x06006ADD RID: 27357 RVA: 0x001E958E File Offset: 0x001E778E internal TextFormatterHost(TextFormatter textFormatter, TextFormattingMode textFormattingMode, double pixelsPerDip) { if (textFormatter == null) { this.TextFormatter = TextFormatter.FromCurrentDispatcher(textFormattingMode); } else { this.TextFormatter = textFormatter; } base.PixelsPerDip = pixelsPerDip; }
public FormattedTextBuilder([NotNull] IFontInfo fontInfo, string text) { mFontInfo = fontInfo ?? throw new ArgumentNullException(nameof(fontInfo)); mText = text ?? string.Empty; mCulture = CultureInfo.CurrentCulture; mFlowDirection = System.Windows.FlowDirection.LeftToRight; mForeground = Brushes.Black; mNumberSubstitution = null; mTextFormattingMode = System.Windows.Media.TextFormattingMode.Display; mDpi = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null, null) as double? ?? 96.0; }
/// <summary> /// Lookup characters nominal glyphs and width /// </summary> /// <param name="charBufferRange">character buffer range</param> /// <param name="emSize">height of Em</param> /// <param name="toIdeal"> scaling factor from real to ideal unit </param> /// <param name="nominalWidths">glyph nominal advances in ideal units</param> /// <param name="idealWidth">total width in ideal units</param> /// <returns>true for success</returns> /// <remarks>This function is only used in fast path, and can only be called /// if CheckFastPathNominalGlyphs has previously returned true.</remarks> internal void GetCharacterNominalWidthsAndIdealWidth( CharacterBufferRange charBufferRange, double emSize, float pixelsPerDip, double toIdeal, TextFormattingMode textFormattingMode, bool isSideways, out int[] nominalWidths, out int idealWidth ) { // This function should only be called if CheckFastPathNominalGlyphs has // returned true so we can assume the ITypefaceMetrics is a GlyphTypeface. GlyphTypeface glyphTypeface = TryGetGlyphTypeface(); Invariant.Assert(glyphTypeface != null); MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = BufferCache.GetGlyphMetrics(charBufferRange.Length); glyphTypeface.GetGlyphMetricsOptimized(charBufferRange, emSize, pixelsPerDip, textFormattingMode, isSideways, glyphMetrics); nominalWidths = new int[charBufferRange.Length]; idealWidth = 0; if (TextFormattingMode.Display == textFormattingMode) { double designToEm = emSize / glyphTypeface.DesignEmHeight; for (int i = 0; i < charBufferRange.Length; i++) { nominalWidths[i] = (int)Math.Round(TextFormatterImp.RoundDipForDisplayMode(glyphMetrics[i].AdvanceWidth * designToEm, pixelsPerDip) * toIdeal); idealWidth += nominalWidths[i]; } } else { double designToEm = emSize * toIdeal / glyphTypeface.DesignEmHeight; for (int i = 0; i < charBufferRange.Length; i++) { nominalWidths[i] = (int)Math.Round(glyphMetrics[i].AdvanceWidth * designToEm); idealWidth += nominalWidths[i]; } } BufferCache.ReleaseGlyphMetrics(glyphMetrics); }
protected FormattedText buildFormattedText(String Text, FontInfo Font, CharDisplayInfo cdi, DrawingContext dc) { TextFormattingMode tfm = TextFormattingMode.Display; FormattedText ft = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Font.Typeface, Font.PointSize, ZColorCheck.ZColorToBrush(cdi.ForegroundColor, ColorType.Foreground), _substituion, tfm); setStyle(cdi, Text.Length, ft); return(ft); }
internal void GetShapeableText( Typeface typeface, CharacterBufferReference characterBufferReference, int stringLength, TextRunProperties textRunProperties, CultureInfo digitCulture, bool isRightToLeftParagraph, IList <TextShapeableSymbols> shapeableList, IShapeableTextCollector collector, TextFormattingMode textFormattingMode ) { if (!typeface.Symbol) { Lookup(typeface).GetShapeableText( characterBufferReference, stringLength, textRunProperties, digitCulture, isRightToLeftParagraph, shapeableList, collector, textFormattingMode ); } else { // It's a non-Unicode ("symbol") font, where code points have non-standard meanings. We // therefore want to bypass the usual itemization and font linking. Instead, just map // everything to the default script and first GlyphTypeface. ShapeTypeface shapeTypeface = new ShapeTypeface( typeface.TryGetGlyphTypeface(), null // device font ); collector.Add( shapeableList, new CharacterBufferRange(characterBufferReference, stringLength), textRunProperties, new MS.Internal.Text.TextInterface.ItemProps(), shapeTypeface, 1.0, // scale in Em false, // null shape textFormattingMode ); } }
internal void GetShapeableText( Typeface typeface, CharacterBufferReference characterBufferReference, int stringLength, TextRunProperties textRunProperties, CultureInfo digitCulture, bool isRightToLeftParagraph, IList<TextShapeableSymbols> shapeableList, IShapeableTextCollector collector, TextFormattingMode textFormattingMode ) { if (!typeface.Symbol) { Lookup(typeface).GetShapeableText( characterBufferReference, stringLength, textRunProperties, digitCulture, isRightToLeftParagraph, shapeableList, collector, textFormattingMode ); } else { // It's a non-Unicode ("symbol") font, where code points have non-standard meanings. We // therefore want to bypass the usual itemization and font linking. Instead, just map // everything to the default script and first GlyphTypeface. ShapeTypeface shapeTypeface = new ShapeTypeface( typeface.TryGetGlyphTypeface(), null // device font ); collector.Add( shapeableList, new CharacterBufferRange(characterBufferReference, stringLength), textRunProperties, new MS.Internal.Text.TextInterface.ItemProps(), shapeTypeface, 1.0, // scale in Em false, // null shape textFormattingMode ); } }
/// <summary> /// Determine the width of the margin, using the number of visible digits (e.g. 5) to construct /// a model string (e.g. "88888"). /// </summary> private void DetermineMarginWidth() { string template = _showMilliseconds ? "XX:XX.XXX" : "XX:XX"; if (_showHours) { template = "XX:" + template; } TextFormattingMode textFormattingMode = _textView.FormattedLineSource.UseDisplayMode ? TextFormattingMode.Display : TextFormattingMode.Ideal; FormattedText formattedText = new FormattedText(template, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, _formatting.Typeface, _formatting.FontRenderingEmSize, Brushes.Black, TimeStampVisual.InvariantNumberSubstitution, textFormattingMode); base.MinWidth = formattedText.Width; }
[FriendAccessAllowed] // used by Framework static internal TextFormatter FromCurrentDispatcher(TextFormattingMode textFormattingMode) { Dispatcher dispatcher = Dispatcher.CurrentDispatcher; if (dispatcher == null) { throw new ArgumentException(SR.Get(SRID.CurrentDispatcherNotFound)); } TextFormatter defaultTextFormatter; if (textFormattingMode == TextFormattingMode.Display) { defaultTextFormatter = (TextFormatterImp)dispatcher.Reserved4; } else { defaultTextFormatter = (TextFormatterImp)dispatcher.Reserved1; } if (defaultTextFormatter == null) { lock (_staticLock) { if (defaultTextFormatter == null) { // Default formatter has not been created for this dispatcher, // create a new one and stick it to the dispatcher. defaultTextFormatter = Create(textFormattingMode); if (textFormattingMode == TextFormattingMode.Display) { dispatcher.Reserved4 = defaultTextFormatter; } else { dispatcher.Reserved1 = defaultTextFormatter; } } } } Invariant.Assert(defaultTextFormatter != null); return(defaultTextFormatter); }
private IntPtr CreatePTSContext(int index, TextFormattingMode textFormattingMode) { PtsHost ptsHost; IntPtr installedObjects; int installedObjectsCount; TextFormatterContext textFormatterContext; IntPtr context; ptsHost = _contextPool[index].PtsHost; Invariant.Assert(ptsHost != null); InitInstalledObjectsInfo(ptsHost, ref _contextPool[index].SubtrackParaInfo, ref _contextPool[index].SubpageParaInfo, out installedObjects, out installedObjectsCount); _contextPool[index].InstalledObjects = installedObjects; InitGenericInfo(ptsHost, (IntPtr)(index + 1), installedObjects, installedObjectsCount, ref _contextPool[index].ContextInfo); InitFloaterObjInfo(ptsHost, ref _contextPool[index].FloaterInit); InitTableObjInfo(ptsHost, ref _contextPool[index].TableobjInit); if (_contextPool[index].IsOptimalParagraphEnabled) { textFormatterContext = new TextFormatterContext(); TextPenaltyModule penaltyModule = textFormatterContext.GetTextPenaltyModule(); IntPtr ptsPenaltyModule = penaltyModule.DangerousGetHandle(); _contextPool[index].TextPenaltyModule = penaltyModule; _contextPool[index].ContextInfo.ptsPenaltyModule = ptsPenaltyModule; _contextPool[index].TextFormatter = TextFormatter.CreateFromContext(textFormatterContext, textFormattingMode); GC.SuppressFinalize(_contextPool[index].TextPenaltyModule); } PTS.Validate(PTS.CreateDocContext(ref _contextPool[index].ContextInfo, out context)); return(context); }
/// <summary> /// Construct a shapeable characters object /// </summary> /// <remarks> /// The shapeTypeface parameter can be null if and only if CheckFastPathNominalGlyphs /// has previously returned true. /// </remarks> internal TextShapeableCharacters( CharacterBufferRange characterRange, TextRunProperties properties, double emSize, ItemProps textItem, ShapeTypeface shapeTypeface, bool nullShape, TextFormattingMode textFormattingMode, bool isSideways ) { _isSideways = isSideways; _textFormattingMode = textFormattingMode; _characterBufferRange = characterRange; _properties = properties; _emSize = emSize; _textItem = textItem; _shapeTypeface = shapeTypeface; _nullShape = nullShape; }
/// <summary> /// Lookup characters nominal glyphs and width /// </summary> /// <param name="charBufferRange">character buffer range</param> /// <param name="emSize">height of Em</param> /// <param name="toIdeal"> scaling factor from real to ideal unit </param> /// <param name="nominalWidths">glyph nominal advances in ideal units</param> /// <returns>true for success</returns> /// <remarks>This function is only used in fast path, and can only be called /// if CheckFastPathNominalGlyphs has previously returned true.</remarks> internal void GetCharacterNominalWidthsAndIdealWidth( CharacterBufferRange charBufferRange, double emSize, double toIdeal, TextFormattingMode textFormattingMode, bool isSideways, out int[] nominalWidths ) { int idealWidth; GetCharacterNominalWidthsAndIdealWidth( charBufferRange, emSize, toIdeal, textFormattingMode, isSideways, out nominalWidths, out idealWidth ); }
public DiagramStyleCache(IDiagramStyleProvider diagramStyleProvider) { Background = diagramStyleProvider.Background; Foreground = diagramStyleProvider.Foreground; DiagramFill = diagramStyleProvider.DiagramFill; DiagramStroke = diagramStyleProvider.DiagramStroke; FontStyle = diagramStyleProvider.FontStyle; FontSize = diagramStyleProvider.FontSize; FontFamily = diagramStyleProvider.FontFamily; FontStretch = diagramStyleProvider.FontStretch; FontWeight = diagramStyleProvider.FontWeight; AdditionalResourceDictionary = diagramStyleProvider.AdditionalResourceDictionary; ClipToBounds = diagramStyleProvider.ClipToBounds; SnapsToDevicePixels = diagramStyleProvider.SnapsToDevicePixels; UseLayoutRounding = diagramStyleProvider.UseLayoutRounding; EdgeMode = diagramStyleProvider.EdgeMode; ClearTypeHint = diagramStyleProvider.ClearTypeHint; TextRenderingMode = diagramStyleProvider.TextRenderingMode; TextHintingMode = diagramStyleProvider.TextHintingMode; TextFormattingMode = TextFormattingMode; }
private FormattedText buildFormattedText(String Text, FontInfo Font, bool UseDisplayMode, List <FontChanges> changes, DrawingContext dc) { TextFormattingMode tfm = TextFormattingMode.Display; FormattedText ft = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Font.Typeface, Font.PointSize, ZColorCheck.ZColorToBrush(fColor, ColorType.Foreground), _substituion, tfm); if (changes != null) { foreach (FontChanges fc in changes) { setStyle(fc.FandS, fc, ft, dc); } } return(ft); }
/// <summary> /// Recommended baseline-to-baseline distance for text in this font. /// </summary> public double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode) { if (textFormattingMode == TextFormattingMode.Ideal) { return(((IFontFamily)this).LineSpacingDesign * emSize); } else { // If the composite font has a pre specified LineSpacing then we respect it in calculating the // linespacing but we round it since Compatible metrics are pixel aligned. if (_fontInfo.LineSpacing != 0) { return(Math.Round(_fontInfo.LineSpacing * emSize)); } // If the composite font has no specifed LineSpacing then we get the compatible font metrics of the // first fontfamily in the composite font. else { return(GetFirstFontFamily().LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode)); } } }
/// <summary> /// Validate all the relevant text formatting initial settings and package them /// </summary> private FormatSettings PrepareFormatSettings( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache, bool useOptimalBreak, bool isSingleLineFormatting, TextFormattingMode textFormattingMode ) { VerifyTextFormattingArguments( textSource, firstCharIndex, paragraphWidth, paragraphProperties, textRunCache ); if (textRunCache.Imp == null) { // No run cache object available, create one textRunCache.Imp = new TextRunCacheImp(); } // initialize formatting settings return(new FormatSettings( this, textSource, textRunCache.Imp, new ParaProp(this, paragraphProperties, useOptimalBreak), previousLineBreak, isSingleLineFormatting, textFormattingMode, false )); }
private PtsHost AcquireContextCore(PtsContext ptsContext, TextFormattingMode textFormattingMode) { int num = 0; while (num < this._contextPool.Count && (this._contextPool[num].InUse || this._contextPool[num].IsOptimalParagraphEnabled != ptsContext.IsOptimalParagraphEnabled)) { num++; } if (num == this._contextPool.Count) { this._contextPool.Add(new PtsCache.ContextDesc()); this._contextPool[num].IsOptimalParagraphEnabled = ptsContext.IsOptimalParagraphEnabled; this._contextPool[num].PtsHost = new PtsHost(); this._contextPool[num].PtsHost.Context = this.CreatePTSContext(num, textFormattingMode); } if (this._contextPool[num].IsOptimalParagraphEnabled) { ptsContext.TextFormatter = this._contextPool[num].TextFormatter; } this._contextPool[num].InUse = true; this._contextPool[num].Owner = new WeakReference(ptsContext); return(this._contextPool[num].PtsHost); }
/// <summary> /// Compare text formatter real values - since values are rounded in Display mode, comparison /// must also round and only return true if one rounded value is greater than the other. /// </summary> /// <param name="x">First value to compare.</param> /// <param name="y">Second value to compare.</param> /// <param name="mode">Text formatting mode.</param> /// <returns>1 if x greater than y, -1 if x less than y, 0 if x == y</returns> internal static int CompareReal(double x, double y, TextFormattingMode mode) { double xDisplay = x; double yDisplay = y; if (mode == TextFormattingMode.Display) { xDisplay = RoundDipForDisplayMode(x); yDisplay = RoundDipForDisplayMode(y); } if (xDisplay > yDisplay) { return(1); } if (xDisplay < yDisplay) { return(-1); } return(0); }
private PtsHost AcquireContextCore(PtsContext ptsContext, TextFormattingMode textFormattingMode) { int index; for (index = 0; index < _contextPool.Count; index++) { if (!_contextPool[index].InUse && _contextPool[index].IsOptimalParagraphEnabled == ptsContext.IsOptimalParagraphEnabled) { break; } } if (index == _contextPool.Count) { _contextPool.Add(new ContextDesc()); _contextPool[index].IsOptimalParagraphEnabled = ptsContext.IsOptimalParagraphEnabled; _contextPool[index].PtsHost = new PtsHost(); _contextPool[index].PtsHost.Context = CreatePTSContext(index, textFormattingMode); } if (_contextPool[index].IsOptimalParagraphEnabled) { ptsContext.TextFormatter = _contextPool[index].TextFormatter; } _contextPool[index].InUse = true; _contextPool[index].Owner = new WeakReference(ptsContext); return(_contextPool[index].PtsHost); }
/// <summary> /// Scan through specified character string checking for valid character /// nominal glyph. /// </summary> /// <param name="charBufferRange">character buffer range</param> /// <param name="emSize">height of Em</param> /// <param name="scalingFactor">This is the factor by which we will scale up /// the metrics. Typically this value to used to convert metrics from the real /// space to the ideal space</param> /// <param name="widthMax">maximum width allowed</param> /// <param name="keepAWord">do not stop arbitrarily in the middle of a word</param> /// <param name="numberSubstitution">digits require complex shaping</param> /// <param name="cultureInfo">CultureInfo of the text</param> /// <param name="stringLengthFit">number of character fit in given width</param> /// <returns>whether the specified string can be optimized by nominal glyph lookup</returns> internal bool CheckFastPathNominalGlyphs( CharacterBufferRange charBufferRange, double emSize, double scalingFactor, double widthMax, bool keepAWord, bool numberSubstitution, CultureInfo cultureInfo, TextFormattingMode textFormattingMode, bool isSideways, out int stringLengthFit ) { stringLengthFit = 0; if (CachedTypeface.NullFont) return false; GlyphTypeface glyphTypeface = TryGetGlyphTypeface(); if (glyphTypeface == null) return false; double totalWidth = 0; int i = 0; ushort blankGlyph = glyphTypeface.BlankGlyphIndex; ushort glyph = blankGlyph; ushort charFlagsMask = numberSubstitution ? (ushort)(CharacterAttributeFlags.CharacterComplex | CharacterAttributeFlags.CharacterDigit) : (ushort)CharacterAttributeFlags.CharacterComplex; ushort charFlags = 0; ushort charFastTextCheck = (ushort)(CharacterAttributeFlags.CharacterFastText | CharacterAttributeFlags.CharacterIdeo); bool symbolTypeface = glyphTypeface.Symbol; if (symbolTypeface) { // we don't care what code points are present if it's a non-Unicode font such as Symbol or Wingdings; // the code points don't have any standardized meanings, and we always want to bypass shaping charFlagsMask = 0; } bool ignoreWidths = widthMax == double.MaxValue; ushort[] glyphIndices = BufferCache.GetUShorts(charBufferRange.Length); MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = ignoreWidths ? null : BufferCache.GetGlyphMetrics(charBufferRange.Length); glyphTypeface.GetGlyphMetricsOptimized(charBufferRange, emSize, glyphIndices, glyphMetrics, textFormattingMode, isSideways ); double designToEm = emSize / glyphTypeface.DesignEmHeight; // // This block will advance until one of: // 1. The end of the charBufferRange is reached // 2. The charFlags have some of the charFlagsMask values // 3. The glyph is BlankGlyph (space) // 4. Glyph index is 0 (unless symbol font) // // At this point totalWidth includes all of the widths including the stop character (which fits above) // i indexes the next character (not included in the width) // if(keepAWord) { do { char ch = charBufferRange[i++]; if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn) { --i; break; } else { int charClass = (int)Classification.GetUnicodeClassUTF16(ch); charFlags = Classification.CharAttributeOf(charClass).Flags; charFastTextCheck &= charFlags; glyph = glyphIndices[i-1]; if (!ignoreWidths) { totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; } } } while( i < charBufferRange.Length && ((charFlags & charFlagsMask) == 0) && (glyph != 0 || symbolTypeface) && glyph != blankGlyph ); // i is now at a character immediately following a leading blank } // // This block will advance until one of: // 1. The end of the charBufferRange is reached // 2. The charFlags have some of the charFlagsMask values // 3. Glyph index is 0 (unless symbol font) // 4. totalWidth > widthMax // while( i < charBufferRange.Length && (ignoreWidths || totalWidth <= widthMax) && ((charFlags & charFlagsMask) == 0) && (glyph != 0 || symbolTypeface) ) { char ch = charBufferRange[i++]; if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn) { --i; break; } else { int charClass = (int)Classification.GetUnicodeClassUTF16(ch); charFlags = Classification.CharAttributeOf(charClass).Flags; charFastTextCheck &= charFlags; glyph = glyphIndices[i-1]; if (!ignoreWidths) { totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; } } } BufferCache.ReleaseUShorts(glyphIndices); glyphIndices = null; BufferCache.ReleaseGlyphMetrics(glyphMetrics); glyphMetrics = null; if (symbolTypeface) { // always optimize for non-Unicode font as we don't support shaping or typographic features; // we also don't fall back from non-Unicode fonts so we don't care if there are missing glyphs stringLengthFit = i; return true; } if (glyph == 0) { // character is not supported by the font return false; } if ((charFlags & charFlagsMask) != 0) { // complex character encountered, exclude it Debug.Assert(i > 0); if(--i <= 0) { // first char is complex, fail the call return false; } } stringLengthFit = i; TypographyAvailabilities typography = glyphTypeface.FontFaceLayoutInfo.TypographyAvailabilities; if ((charFastTextCheck & (byte) CharacterAttributeFlags.CharacterFastText) != 0) { // all input code points are Fast Text if ((typography & ( TypographyAvailabilities.FastTextTypographyAvailable | TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable ) ) != 0 ) { // Considered too risky to optimize. It is either because the font // has required features or the font has 'locl' lookup for major languages. return false; } else if ((typography & TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable) != 0) { // The font has 'locl' lookup for FastText code points for non major languages. // Check whether the input is major langauge. If it is, we are still good to optimize. return MajorLanguages.Contains(cultureInfo); } else { // No FastText flags are present, safe to optimize return true; } } else if ((charFastTextCheck & (byte) CharacterAttributeFlags.CharacterIdeo) != 0) { // The input are all ideographs, check the IdeoTypographyAvailable bit. It is safe if // the bit is not set. return ((typography & TypographyAvailabilities.IdeoTypographyAvailable) == 0); } else { // for all the rest of the cases, just check whether there is any required typography // present at all. If none exists, it is optimizable. We might under-optimize here but // it will be non-major languages. return ((typography & TypographyAvailabilities.Available) == 0); } }
internal double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode) { return CachedTypeface.FirstFontFamily.LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode); }
/// <summary> /// Client to create a new instance of TextFormatter from the specified TextFormatter context /// </summary> /// <param name="soleContext">TextFormatter context</param> /// <returns>New instance of TextFormatter</returns> #if OPTIMALBREAK_API static public TextFormatter CreateFromContext(TextFormatterContext soleContext, TextFormattingMode textFormattingMode)
/// <summary> /// Construct an instance of TextFormatter implementation /// </summary> internal TextFormatterImp(TextFormattingMode textFormattingMode) : this(null, textFormattingMode) { }
/// <summary> /// Break a run of text into individually shape items. /// Shape items are delimited by /// Change of writing system /// Change of glyph typeface /// </summary> IList<TextShapeableSymbols> ITextSymbols.GetTextShapeableSymbols( GlyphingCache glyphingCache, CharacterBufferReference characterBufferReference, int length, bool rightToLeft, bool isRightToLeftParagraph, CultureInfo digitCulture, TextModifierScope textModifierScope, TextFormattingMode textFormattingMode, bool isSideways ) { if (characterBufferReference.CharacterBuffer == null) { throw new ArgumentNullException("characterBufferReference.CharacterBuffer"); } int offsetToFirstChar = characterBufferReference.OffsetToFirstChar - _characterBufferReference.OffsetToFirstChar; Debug.Assert(characterBufferReference.CharacterBuffer == _characterBufferReference.CharacterBuffer); Debug.Assert(offsetToFirstChar >= 0 && offsetToFirstChar < _length); if ( length < 0 || offsetToFirstChar + length > _length) { length = _length - offsetToFirstChar; } // Get the actual text run properties in effect, after invoking any // text modifiers that may be in scope. TextRunProperties textRunProperties = _textRunProperties; if (textModifierScope != null) { textRunProperties = textModifierScope.ModifyProperties(textRunProperties); } if (!rightToLeft) { // Fast loop early out for run with all non-complex characters // which can be optimized by not going thru shaping engine. int nominalLength; if (textRunProperties.Typeface.CheckFastPathNominalGlyphs( new CharacterBufferRange(characterBufferReference, length), textRunProperties.FontRenderingEmSize, 1.0, double.MaxValue, // widthMax true, // keepAWord digitCulture != null, CultureMapper.GetSpecificCulture(textRunProperties.CultureInfo), textFormattingMode, isSideways, false, //breakOnTabs out nominalLength ) && length == nominalLength) { return new TextShapeableCharacters[] { new TextShapeableCharacters( new CharacterBufferRange(characterBufferReference, nominalLength), textRunProperties, textRunProperties.FontRenderingEmSize, new MS.Internal.Text.TextInterface.ItemProps(), null, // shapeTypeface (no shaping required) false, // nullShape, textFormattingMode, isSideways ) }; } } IList<TextShapeableSymbols> shapeables = new List<TextShapeableSymbols>(2); glyphingCache.GetShapeableText( textRunProperties.Typeface, characterBufferReference, length, textRunProperties, digitCulture, isRightToLeftParagraph, shapeables, this as IShapeableTextCollector, textFormattingMode ); return shapeables; }
private FullTextLine(TextFormattingMode textFormattingMode, bool justify) { _textFormattingMode = textFormattingMode; if (justify) { _statusFlags |= StatusFlags.IsJustified; } _metrics = new TextMetrics(); _ploline = new SecurityCriticalDataForSet<IntPtr>(IntPtr.Zero); }
public FormattedTextCache(bool useDisplayMode) { textFormattingMode = useDisplayMode ? TextFormattingMode.Display : TextFormattingMode.Ideal; dict = new Dictionary<TextFormattingRunProperties, Info>(); }
public FormattedTextSymbols( GlyphingCache glyphingCache, TextRun textSymbols, bool rightToLeft, double scalingFactor, TextFormattingMode textFormattingMode, bool isSideways ) { _textFormattingMode = textFormattingMode; _isSideways = isSideways; ITextSymbols symbols = textSymbols as ITextSymbols; Debug.Assert(symbols != null); // break down a single text run into pieces IList<TextShapeableSymbols> shapeables = symbols.GetTextShapeableSymbols( glyphingCache, textSymbols.CharacterBufferReference, textSymbols.Length, rightToLeft, // This is a bool indicating the RTL // based on the bidi level of text (if applicable). // For FormattedTextSymbols it is equal to paragraph flow direction. rightToLeft, // This is the flow direction of the paragraph as // specified by the user. DWrite needs the paragraph // flow direction of the paragraph // while WPF algorithms need the RTL of the text based on // Bidi if possible. null, // cultureInfo null, // textModifierScope _textFormattingMode, _isSideways ); Debug.Assert(shapeables != null && shapeables.Count > 0); _rightToLeft = rightToLeft; _glyphs = new Glyphs[shapeables.Count]; CharacterBuffer charBuffer = textSymbols.CharacterBufferReference.CharacterBuffer; int offsetToFirstChar = textSymbols.CharacterBufferReference.OffsetToFirstChar; int i = 0; int ich = 0; while (i < shapeables.Count) { TextShapeableSymbols current = shapeables[i] as TextShapeableSymbols; Debug.Assert(current != null); int cch = current.Length; int j; // make a separate character buffer for glyphrun persistence char[] charArray = new char[cch]; for (j = 0; j < cch; j++) charArray[j] = charBuffer[offsetToFirstChar + ich + j]; if (current.IsShapingRequired) { ushort[] clusterMap; ushort[] glyphIndices; int[] glyphAdvances; GlyphOffset[] glyphOffsets; // unsafe { fixed (char* fixedCharArray = &charArray[0]) { MS.Internal.Text.TextInterface.TextAnalyzer textAnalyzer = MS.Internal.FontCache.DWriteFactory.Instance.CreateTextAnalyzer(); GlyphTypeface glyphTypeface = current.GlyphTypeFace; DWriteFontFeature[][] fontFeatures; uint[] fontFeatureRanges; uint unsignedCch = checked((uint)cch); LSRun.CompileFeatureSet(current.Properties.TypographyProperties, unsignedCch, out fontFeatures, out fontFeatureRanges); textAnalyzer.GetGlyphsAndTheirPlacements( (ushort*)fixedCharArray, unsignedCch, glyphTypeface.FontDWrite, glyphTypeface.BlankGlyphIndex, false, // no sideway support yet /************************************************************************************************/ // rightToLeft, current.Properties.CultureInfo, /************************************************************************************************/ fontFeatures, fontFeatureRanges, current.Properties.FontRenderingEmSize, scalingFactor, Util.PixelsPerDip, _textFormattingMode, current.ItemProps, out clusterMap, out glyphIndices, out glyphAdvances, out glyphOffsets ); } _glyphs[i] = new Glyphs( current, charArray, glyphAdvances, clusterMap, glyphIndices, glyphOffsets, scalingFactor ); } } else { // shaping not required, // bypass glyphing process altogether int[] nominalAdvances = new int[charArray.Length]; unsafe { fixed (char* fixedCharArray = &charArray[0]) fixed (int* fixedNominalAdvances = &nominalAdvances[0]) { current.GetAdvanceWidthsUnshaped( fixedCharArray, cch, scalingFactor, // format resolution specified per em, fixedNominalAdvances ); } } _glyphs[i] = new Glyphs( current, charArray, nominalAdvances, scalingFactor ); } i++; ich += cch; } }
/// <summary> /// Construct a FormattedText object. /// </summary> /// <param name="textToFormat">String of text to be displayed.</param> /// <param name="culture">Culture of text.</param> /// <param name="flowDirection">Flow direction of text.</param> /// <param name="typeface">Type face used to display text.</param> /// <param name="emSize">Font em size in visual units (1/96 of an inch).</param> /// <param name="foreground">Foreground brush used to render text.</param> /// <param name="numberSubstitution">Number substitution behavior to apply to the text; can be null, /// in which case the default number number method for the text culture is used.</param> public FormattedText( string textToFormat, CultureInfo culture, FlowDirection flowDirection, Typeface typeface, double emSize, Brush foreground, NumberSubstitution numberSubstitution, TextFormattingMode textFormattingMode) { if (textToFormat == null) throw new ArgumentNullException("textToFormat"); if (typeface == null) throw new ArgumentNullException("typeface"); ValidateCulture(culture); ValidateFlowDirection(flowDirection, "flowDirection"); ValidateFontSize(emSize); _textFormattingMode = textFormattingMode; _text = textToFormat; GenericTextRunProperties runProps = new GenericTextRunProperties( typeface, emSize, 12.0f, // default hinting size null, // decorations foreground, null, // highlight background BaselineAlignment.Baseline, culture, numberSubstitution ); _latestPosition = _formatRuns.SetValue(0, _text.Length, runProps, _latestPosition); _defaultParaProps = new GenericTextParagraphProperties( flowDirection, TextAlignment.Left, false, false, runProps, TextWrapping.WrapWithOverflow, 0, // line height not specified 0 // indentation not specified ); InvalidateMetrics(); }
/// <summary> /// Lookup characters nominal glyphs and width /// </summary> /// <param name="charBufferRange">character buffer range</param> /// <param name="emSize">height of Em</param> /// <param name="toIdeal"> scaling factor from real to ideal unit </param> /// <param name="nominalWidths">glyph nominal advances in ideal units</param> /// <param name="idealWidth">total width in ideal units</param> /// <returns>true for success</returns> /// <remarks>This function is only used in fast path, and can only be called /// if CheckFastPathNominalGlyphs has previously returned true.</remarks> internal void GetCharacterNominalWidthsAndIdealWidth( CharacterBufferRange charBufferRange, double emSize, double toIdeal, TextFormattingMode textFormattingMode, bool isSideways, out int[] nominalWidths, out int idealWidth ) { // This function should only be called if CheckFastPathNominalGlyphs has // returned true so we can assume the ITypefaceMetrics is a GlyphTypeface. GlyphTypeface glyphTypeface = TryGetGlyphTypeface(); Invariant.Assert(glyphTypeface != null); MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = BufferCache.GetGlyphMetrics(charBufferRange.Length); glyphTypeface.GetGlyphMetricsOptimized(charBufferRange, emSize, textFormattingMode, isSideways, glyphMetrics); nominalWidths = new int[charBufferRange.Length]; idealWidth = 0; if (TextFormattingMode.Display == textFormattingMode) { double designToEm = emSize / glyphTypeface.DesignEmHeight; for (int i = 0; i < charBufferRange.Length; i++) { nominalWidths[i] = (int)Math.Round(TextFormatterImp.RoundDipForDisplayMode(glyphMetrics[i].AdvanceWidth * designToEm) * toIdeal); idealWidth += nominalWidths[i]; } } else { double designToEm = emSize * toIdeal / glyphTypeface.DesignEmHeight; for (int i = 0; i < charBufferRange.Length; i++) { nominalWidths[i] = (int)Math.Round(glyphMetrics[i].AdvanceWidth * designToEm); idealWidth += nominalWidths[i]; } } BufferCache.ReleaseGlyphMetrics(glyphMetrics); }
/// <summary> /// Compare text formatter real values - since values are rounded in Display mode, comparison /// must also round and only return true if one rounded value is greater than the other. /// </summary> /// <param name="x">First value to compare.</param> /// <param name="y">Second value to compare.</param> /// <param name="mode">Text formatting mode.</param> /// <returns>1 if x greater than y, -1 if x less than y, 0 if x == y</returns> internal static int CompareReal(double x, double y, TextFormattingMode mode) { double xDisplay = x; double yDisplay = y; if (mode == TextFormattingMode.Display) { xDisplay = RoundDipForDisplayMode(x); yDisplay = RoundDipForDisplayMode(y); } if (xDisplay > yDisplay) { return 1; } if (xDisplay < yDisplay) { return -1; } return 0; }
/// <summary> /// Returns whether the conditions are met to make it possible to process tabs /// in the simple shaping path. /// </summary> static private bool CanProcessTabsInSimpleShapingPath( ParaProp textParagraphProperties, TextFormattingMode textFormattingMode ) { return (textParagraphProperties.Tabs == null && textParagraphProperties.DefaultIncrementalTab > 0); }
/// <summary> /// Add shapeable text object to the list /// </summary> void IShapeableTextCollector.Add( IList<TextShapeableSymbols> shapeables, CharacterBufferRange characterBufferRange, TextRunProperties textRunProperties, MS.Internal.Text.TextInterface.ItemProps textItem, ShapeTypeface shapeTypeface, double emScale, bool nullShape, TextFormattingMode textFormattingMode ) { Debug.Assert(shapeables != null); shapeables.Add( new TextShapeableCharacters( characterBufferRange, textRunProperties, textRunProperties.FontRenderingEmSize * emScale, textItem, shapeTypeface, nullShape, textFormattingMode, false ) ); }
internal static double RoundDip(double value, TextFormattingMode textFormattingMode) { if (TextFormattingMode.Display == textFormattingMode) { return RoundDipForDisplayMode(value); } else { return value; } }
internal double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode) { return(CachedTypeface.FirstFontFamily.LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode)); }
internal void GetShapeableText( CharacterBufferReference characterBufferReference, int stringLength, TextRunProperties textRunProperties, CultureInfo digitCulture, bool isRightToLeftParagraph, IList<TextShapeableSymbols> shapeableList, IShapeableTextCollector collector, TextFormattingMode textFormattingMode ) { SpanVector<int> cachedScaledTypefaceIndexSpans; int ichItem = 0; CharacterBufferRange unicodeString = new CharacterBufferRange( characterBufferReference, stringLength ); CultureInfo culture = textRunProperties.CultureInfo; IList<Span> spans; GCHandle gcHandle; IntPtr ptext = characterBufferReference.CharacterBuffer.PinAndGetCharacterPointer(characterBufferReference.OffsetToFirstChar, out gcHandle); // Contextual number substitution cannot be performed on the run level, since it depends // on context - nearest preceding strong character. For this reason, contextual number // substitutions has been already done (TextStore.CreateLSRunsUniformBidiLevel) and // digitCulture has been updated to reflect culture which is dependent on the context. // NumberSubstitutionMethod.AsCulture method can be resolved to Context, hence it also needs to be resolved to appropriate // not ambiguous method. // Both of those values (Context and AsCulture) are resolved to one of following: European, Traditional or NativeNational, // which can be safely handled by DWrite without getting context information. bool ignoreUserOverride; NumberSubstitutionMethod numberSubstitutionMethod = DigitState.GetResolvedSubstitutionMethod(textRunProperties, digitCulture, out ignoreUserOverride); // Itemize the text based on DWrite's text analysis for scripts and number substitution. unsafe { checked { spans = MS.Internal.Text.TextInterface.TextAnalyzer.Itemize( (ushort*)ptext.ToPointer(), (uint)stringLength, culture, MS.Internal.FontCache.DWriteFactory.Instance, isRightToLeftParagraph, digitCulture, ignoreUserOverride, (uint)numberSubstitutionMethod, ClassificationUtility.Instance, UnsafeNativeMethods.CreateTextAnalysisSink, UnsafeNativeMethods.GetScriptAnalysisList, UnsafeNativeMethods.GetNumberSubstitutionList, UnsafeNativeMethods.CreateTextAnalysisSource ); } } characterBufferReference.CharacterBuffer.UnpinCharacterPointer(gcHandle); SpanVector itemSpans = new SpanVector(null, new FrugalStructList<Span>((ICollection<Span>)spans)); cachedScaledTypefaceIndexSpans = new SpanVector<int>(-1); foreach(Span itemSpan in itemSpans) { MapItem( new CharacterBufferRange( unicodeString, ichItem, itemSpan.length ), culture, itemSpan, ref cachedScaledTypefaceIndexSpans, ichItem ); #if DEBUG ValidateMapResult( ichItem, itemSpan.length, ref cachedScaledTypefaceIndexSpans ); #endif ichItem += itemSpan.length; } Debug.Assert(ichItem == unicodeString.Length); // intersect item spans with shapeable spans to create span of shapeable runs int ich = 0; SpanRider itemSpanRider = new SpanRider(itemSpans); SpanRider<int> typefaceIndexSpanRider = new SpanRider<int>(cachedScaledTypefaceIndexSpans); while(ich < unicodeString.Length) { itemSpanRider.At(ich); typefaceIndexSpanRider.At(ich); int index = typefaceIndexSpanRider.CurrentValue; Debug.Assert(index >= 0); int cch = unicodeString.Length - ich; cch = Math.Min(cch, itemSpanRider.Length); cch = Math.Min(cch, typefaceIndexSpanRider.Length); ScaledShapeTypeface scaledShapeTypeface = _cachedScaledTypefaces[index]; collector.Add( shapeableList, new CharacterBufferRange( unicodeString, ich, cch ), textRunProperties, (MS.Internal.Text.TextInterface.ItemProps)itemSpanRider.CurrentElement, scaledShapeTypeface.ShapeTypeface, scaledShapeTypeface.ScaleInEm, scaledShapeTypeface.NullShape, textFormattingMode ); ich += cch; } }
/// <summary> /// Validate all the relevant text formatting initial settings and package them /// </summary> private FormatSettings PrepareFormatSettings( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache, bool useOptimalBreak, bool isSingleLineFormatting, TextFormattingMode textFormattingMode ) { VerifyTextFormattingArguments( textSource, firstCharIndex, paragraphWidth, paragraphProperties, textRunCache ); if (textRunCache.Imp == null) { // No run cache object available, create one textRunCache.Imp = new TextRunCacheImp(); } // initialize formatting settings return new FormatSettings( this, textSource, textRunCache.Imp, new ParaProp(this, paragraphProperties, useOptimalBreak), previousLineBreak, isSingleLineFormatting, textFormattingMode, false ); }
/// <summary> /// Recommended baseline-to-baseline distance for text in this font. /// </summary> public double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode) { if (textFormattingMode == TextFormattingMode.Ideal) { return ((IFontFamily)this).LineSpacingDesign * emSize; } else { // If the composite font has a pre specified LineSpacing then we respect it in calculating the // linespacing but we round it since Compatible metrics are pixel aligned. if (_fontInfo.LineSpacing != 0) { return Math.Round(_fontInfo.LineSpacing * emSize); } // If the composite font has no specifed LineSpacing then we get the compatible font metrics of the // first fontfamily in the composite font. else { return GetFirstFontFamily().LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode); } } }
[FriendAccessAllowed] // used by Framework static internal TextFormatter CreateFromContext(TextFormatterContext soleContext, TextFormattingMode textFormattingMode) #endif { // create a new instance of TextFormatter for the specified context. // This creation prohibits the use of multiple contexts within the same TextFormatter via reentrance. return new TextFormatterImp(soleContext, textFormattingMode); }
[FriendAccessAllowed] // used by Framework static internal TextFormatter FromCurrentDispatcher(TextFormattingMode textFormattingMode) { Dispatcher dispatcher = Dispatcher.CurrentDispatcher; if (dispatcher == null) throw new ArgumentException(SR.Get(SRID.CurrentDispatcherNotFound)); TextFormatter defaultTextFormatter; if (textFormattingMode == TextFormattingMode.Display) { defaultTextFormatter = (TextFormatterImp)dispatcher.Reserved4; } else { defaultTextFormatter = (TextFormatterImp)dispatcher.Reserved1; } if (defaultTextFormatter == null) { lock (_staticLock) { if (defaultTextFormatter == null) { // Default formatter has not been created for this dispatcher, // create a new one and stick it to the dispatcher. defaultTextFormatter = Create(textFormattingMode); if (textFormattingMode == TextFormattingMode.Display) { dispatcher.Reserved4 = defaultTextFormatter; } else { dispatcher.Reserved1 = defaultTextFormatter; } } } } Invariant.Assert(defaultTextFormatter != null); return defaultTextFormatter; }
/// <summary> /// Scan through specified character string checking for valid character /// nominal glyph. /// </summary> /// <param name="charBufferRange">character buffer range</param> /// <param name="emSize">height of Em</param> /// <param name="scalingFactor">This is the factor by which we will scale up /// the metrics. Typically this value to used to convert metrics from the real /// space to the ideal space</param> /// <param name="widthMax">maximum width allowed</param> /// <param name="keepAWord">do not stop arbitrarily in the middle of a word</param> /// <param name="numberSubstitution">digits require complex shaping</param> /// <param name="cultureInfo">CultureInfo of the text</param> /// <param name="textFormattingMode">The TextFormattingMode used (Ideal vs. Display)</param> /// <param name="isSideways">Indicates whether to rotate glyphs.</param> /// <param name="breakOnTabs">Determines whether to stop checking at a tab and /// break the run there</param> /// <param name="stringLengthFit">number of character fit in given width</param> /// <returns>whether the specified string can be optimized by nominal glyph lookup</returns> internal bool CheckFastPathNominalGlyphs( CharacterBufferRange charBufferRange, double emSize, double scalingFactor, double widthMax, bool keepAWord, bool numberSubstitution, CultureInfo cultureInfo, TextFormattingMode textFormattingMode, bool isSideways, bool breakOnTabs, out int stringLengthFit ) { stringLengthFit = 0; if (CachedTypeface.NullFont) { return(false); } GlyphTypeface glyphTypeface = TryGetGlyphTypeface(); if (glyphTypeface == null) { return(false); } double totalWidth = 0; int i = 0; ushort blankGlyph = glyphTypeface.BlankGlyphIndex; ushort glyph = blankGlyph; ushort charFlagsMask = numberSubstitution ? (ushort)(CharacterAttributeFlags.CharacterComplex | CharacterAttributeFlags.CharacterDigit) : (ushort)CharacterAttributeFlags.CharacterComplex; ushort charFlags = 0; ushort charFastTextCheck = (ushort)(CharacterAttributeFlags.CharacterFastText | CharacterAttributeFlags.CharacterIdeo); bool symbolTypeface = glyphTypeface.Symbol; if (symbolTypeface) { // we don't care what code points are present if it's a non-Unicode font such as Symbol or Wingdings; // the code points don't have any standardized meanings, and we always want to bypass shaping charFlagsMask = 0; } bool ignoreWidths = widthMax == double.MaxValue; ushort[] glyphIndices = BufferCache.GetUShorts(charBufferRange.Length); MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = ignoreWidths ? null : BufferCache.GetGlyphMetrics(charBufferRange.Length); glyphTypeface.GetGlyphMetricsOptimized(charBufferRange, emSize, glyphIndices, glyphMetrics, textFormattingMode, isSideways ); double designToEm = emSize / glyphTypeface.DesignEmHeight; // // This block will advance until one of: // 1. The end of the charBufferRange is reached // 2. The charFlags have some of the charFlagsMask values // 3. The glyph is BlankGlyph (space) // 4. Glyph index is 0 (unless symbol font) // // At this point totalWidth includes all of the widths including the stop character (which fits above) // i indexes the next character (not included in the width) // if (keepAWord) { do { char ch = charBufferRange[i++]; if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn || (breakOnTabs && ch == TextStore.CharTab)) { --i; break; } else { int charClass = (int)Classification.GetUnicodeClassUTF16(ch); charFlags = Classification.CharAttributeOf(charClass).Flags; charFastTextCheck &= charFlags; glyph = glyphIndices[i - 1]; if (!ignoreWidths) { totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; } } } while( i < charBufferRange.Length && ((charFlags & charFlagsMask) == 0) && (glyph != 0 || symbolTypeface) && glyph != blankGlyph ); // i is now at a character immediately following a leading blank } // // This block will advance until one of: // 1. The end of the charBufferRange is reached // 2. The charFlags have some of the charFlagsMask values // 3. Glyph index is 0 (unless symbol font) // 4. totalWidth > widthMax // while ( i < charBufferRange.Length && (ignoreWidths || totalWidth <= widthMax) && ((charFlags & charFlagsMask) == 0) && (glyph != 0 || symbolTypeface) ) { char ch = charBufferRange[i++]; if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn || (breakOnTabs && ch == TextStore.CharTab)) { --i; break; } else { int charClass = (int)Classification.GetUnicodeClassUTF16(ch); charFlags = Classification.CharAttributeOf(charClass).Flags; charFastTextCheck &= charFlags; glyph = glyphIndices[i - 1]; if (!ignoreWidths) { totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; } } } BufferCache.ReleaseUShorts(glyphIndices); glyphIndices = null; BufferCache.ReleaseGlyphMetrics(glyphMetrics); glyphMetrics = null; if (symbolTypeface) { // always optimize for non-Unicode font as we don't support shaping or typographic features; // we also don't fall back from non-Unicode fonts so we don't care if there are missing glyphs stringLengthFit = i; return(true); } if (glyph == 0) { // character is not supported by the font return(false); } if ((charFlags & charFlagsMask) != 0) { // complex character encountered, exclude it Debug.Assert(i > 0); if (--i <= 0) { // first char is complex, fail the call return(false); } } stringLengthFit = i; TypographyAvailabilities typography = glyphTypeface.FontFaceLayoutInfo.TypographyAvailabilities; if ((charFastTextCheck & (byte)CharacterAttributeFlags.CharacterFastText) != 0) { // all input code points are Fast Text if ((typography & (TypographyAvailabilities.FastTextTypographyAvailable | TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable ) ) != 0 ) { // Considered too risky to optimize. It is either because the font // has required features or the font has 'locl' lookup for major languages. return(false); } else if ((typography & TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable) != 0) { // The font has 'locl' lookup for FastText code points for non major languages. // Check whether the input is major langauge. If it is, we are still good to optimize. return(MajorLanguages.Contains(cultureInfo)); } else { // No FastText flags are present, safe to optimize return(true); } } else if ((charFastTextCheck & (byte)CharacterAttributeFlags.CharacterIdeo) != 0) { // The input are all ideographs, check the IdeoTypographyAvailable bit. It is safe if // the bit is not set. return((typography & TypographyAvailabilities.IdeoTypographyAvailable) == 0); } else { // for all the rest of the cases, just check whether there is any required typography // present at all. If none exists, it is optimizable. We might under-optimize here but // it will be non-major languages. return((typography & TypographyAvailabilities.Available) == 0); } }
private PtsHost AcquireContextCore(PtsContext ptsContext, TextFormattingMode textFormattingMode) { int index; // Look for the first free PTS Context. for (index = 0; index < _contextPool.Count; index++) { if (!_contextPool[index].InUse && _contextPool[index].IsOptimalParagraphEnabled == ptsContext.IsOptimalParagraphEnabled) { break; } } // Create new PTS Context, if cannot find free one. if (index == _contextPool.Count) { _contextPool.Add(new ContextDesc()); _contextPool[index].IsOptimalParagraphEnabled = ptsContext.IsOptimalParagraphEnabled; _contextPool[index].PtsHost = new PtsHost(); _contextPool[index].PtsHost.Context = CreatePTSContext(index, textFormattingMode); } // Initialize TextFormatter, if optimal paragraph is enabled. // Optimal paragraph requires new TextFormatter for every PTS Context. if (_contextPool[index].IsOptimalParagraphEnabled) { ptsContext.TextFormatter = _contextPool[index].TextFormatter; } // Assign PTS Context to new owner. _contextPool[index].InUse = true; _contextPool[index].Owner = new WeakReference(ptsContext); return _contextPool[index].PtsHost; }
public FormattedTextCache(bool useDisplayMode) { textFormattingMode = useDisplayMode ? TextFormattingMode.Display : TextFormattingMode.Ideal; dict = new Dictionary <TextFormattingRunProperties, Info>(); }
private IntPtr CreatePTSContext(int index, TextFormattingMode textFormattingMode) { PtsHost ptsHost; IntPtr installedObjects; int installedObjectsCount; TextFormatterContext textFormatterContext; IntPtr context; ptsHost = _contextPool[index].PtsHost; Invariant.Assert(ptsHost != null); // Create installed object info. InitInstalledObjectsInfo(ptsHost, ref _contextPool[index].SubtrackParaInfo, ref _contextPool[index].SubpageParaInfo, out installedObjects, out installedObjectsCount); _contextPool[index].InstalledObjects = installedObjects; // Create generic callbacks info. InitGenericInfo(ptsHost, (IntPtr)(index + 1), installedObjects, installedObjectsCount, ref _contextPool[index].ContextInfo); // Preallocated floater and table info. InitFloaterObjInfo(ptsHost, ref _contextPool[index].FloaterInit); InitTableObjInfo(ptsHost, ref _contextPool[index].TableobjInit); // Setup for optimal paragraph if (_contextPool[index].IsOptimalParagraphEnabled) { textFormatterContext = new TextFormatterContext(); TextPenaltyModule penaltyModule = textFormatterContext.GetTextPenaltyModule(); IntPtr ptsPenaltyModule = penaltyModule.DangerousGetHandle(); _contextPool[index].TextPenaltyModule = penaltyModule; _contextPool[index].ContextInfo.ptsPenaltyModule = ptsPenaltyModule; _contextPool[index].TextFormatter = TextFormatter.CreateFromContext(textFormatterContext, textFormattingMode); // Explicitly take the penalty module object out of finalization queue; // PTSCache must manage lifetime of the penalty module explicitly by calling // TextPenaltyModule.Dispose to ensure proper destruction order of PTSContext // and the penalty module (PTS context must be destroyed first). GC.SuppressFinalize(_contextPool[index].TextPenaltyModule); } // Create PTS Context PTS.Validate(PTS.CreateDocContext(ref _contextPool[index].ContextInfo, out context)); return context; }