Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / MS / Internal / TextFormatting / TextFormatterImp.cs / 1 / TextFormatterImp.cs
//+------------------------------------------------------------------------ // // Microsoft Windows Client Platform // Copyright (C) Microsoft Corporation // // File: TextFormatterImp.cs // // Contents: Text formatter implementation // // Created: 2-25-2003 Worachai Chaoweeraprasit (wchao) // //----------------------------------------------------------------------- using System; using System.Security; using System.Windows; using System.Windows.Media; using System.Windows.Threading; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Windows.Media.TextFormatting; using MS.Utility; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using MS.Internal.Shaping; #if !OPTIMALBREAK_API using MS.Internal.PresentationCore; #endif namespace MS.Internal.TextFormatting { ////// Implementation of TextFormatter /// internal sealed class TextFormatterImp : TextFormatter { private FrugalStructList_contextList; // LS context free list private double _toIdeal; // scaling factor from client's real space to LS ideal resolution private double _toReal; // scaling factor from LS ideal resolution to client's real space private bool _multipleContextProhibited; // prohibit multiple contexts within the same formatter private GlyphingCache _glyphingCache; // Glyphing cache for font linking process private const int MaxGlyphingCacheCapacity = 16; /// /// Construct an instance of TextFormatter implementation /// internal TextFormatterImp() : this(null) {} ////// Construct an instance of TextFormatter implementation with the specified context /// /// ////// 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. /// internal TextFormatterImp(TextFormatterContext soleContext) { _toIdeal = Constants.DefaultRealToIdeal; _toReal = Constants.DefaultIdealToReal; if (soleContext != null) _contextList.Add(soleContext); _multipleContextProhibited = (_contextList.Count != 0); } ////// Finalizing text formatter /// ~TextFormatterImp() { CleanupInternal(); } ////// Release all unmanaged LS contexts /// public override void Dispose() { CleanupInternal(); base.Dispose(); GC.SuppressFinalize(this); } ////// Release all unmanaged LS contexts /// private void CleanupInternal() { for (int i = 0; i < _contextList.Count; i++) { _contextList[i].Destroy(); } _contextList.Clear(); } ////// Client to format a text line that fills a paragraph in the document. /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// width of paragraph in which the line fills /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// LineBreak property of the previous text line, or null if this is the first line in the paragraph ///object representing a line of text that client interacts with. public override TextLine FormatLine( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak ) { return FormatLineInternal( textSource, firstCharIndex, 0, // lineLength paragraphWidth, paragraphProperties, previousLineBreak, new TextRunCache() // local cache, only live within this call ); } ////// Client to format a text line that fills a paragraph in the document. /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// width of paragraph in which the line fills /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// LineBreak property of the previous text line, or null if this is the first line in the paragraph /// an object representing content cache of the client. ///object representing a line of text that client interacts with. public override TextLine FormatLine( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) { return FormatLineInternal( textSource, firstCharIndex, 0, // lineLength paragraphWidth, paragraphProperties, previousLineBreak, textRunCache ); } ////// Client to reconstruct a previously formatted text line /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// character length of the line /// width of paragraph in which the line fills /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// LineBreak property of the previous text line, or null if this is the first line in the paragraph /// an object representing content cache of the client. ///object representing a line of text that client interacts with. #if OPTIMALBREAK_API public override TextLine RecreateLine( #else internal override TextLine RecreateLine( #endif TextSource textSource, int firstCharIndex, int lineLength, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) { return FormatLineInternal( textSource, firstCharIndex, lineLength, paragraphWidth, paragraphProperties, previousLineBreak, textRunCache ); } ////// Format and produce a text line either with or without previously known /// line break point. /// private TextLine FormatLineInternal( TextSource textSource, int firstCharIndex, int lineLength, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) { if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) { EventTrace.EventProvider.TraceEvent( EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), EventType.StartEvent, "TextFormatterImp.FormatLineInternal Start" ); } // prepare formatting settings FormatSettings settings = PrepareFormatSettings( textSource, firstCharIndex, paragraphWidth, paragraphProperties, previousLineBreak, textRunCache, (lineLength != 0), // Do optimal break if break is given true // isSingleLineFormatting ); TextLine textLine = null; if ( !settings.Pap.AlwaysCollapsible && previousLineBreak == null && lineLength <= 0 ) { // simple text line. textLine = SimpleTextLine.Create( settings, firstCharIndex, RealToIdealFloor(paragraphWidth) ) as TextLine; } if (textLine == null) { // content is complex, creating complex line textLine = new TextMetrics.FullTextLine( settings, firstCharIndex, lineLength, RealToIdealFloor(paragraphWidth), LineFlags.None ) as TextLine; } if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) { EventTrace.EventProvider.TraceEvent( EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), EventType.EndEvent, "TextFormatterImp.FormatLineInternal End" ); } return textLine; } ////// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. ///min max paragraph width public override MinMaxParagraphWidth FormatMinMaxParagraphWidth( TextSource textSource, int firstCharIndex, TextParagraphProperties paragraphProperties ) { return FormatMinMaxParagraphWidth( textSource, firstCharIndex, paragraphProperties, new TextRunCache() // local cache, only live within this call ); } ////// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// an object representing content cache of the client. ///min max paragraph width public override MinMaxParagraphWidth FormatMinMaxParagraphWidth( TextSource textSource, int firstCharIndex, TextParagraphProperties paragraphProperties, TextRunCache textRunCache ) { // prepare formatting settings FormatSettings settings = PrepareFormatSettings( textSource, firstCharIndex, 0, // infinite paragraphWidth paragraphProperties, null, // always format the whole paragraph - no previousLineBreak textRunCache, false, // optimalBreak true // isSingleLineFormatting ); // create specialized line specifically for min/max calculation TextMetrics.FullTextLine line = new TextMetrics.FullTextLine( settings, firstCharIndex, 0, // lineLength 0, // paragraph width has no significant meaning in min/max calculation (LineFlags.KeepState | LineFlags.MinMax) ); // line width in this case is the width of a line when the entire paragraph is laid out // as a single long line. MinMaxParagraphWidth minMax = new MinMaxParagraphWidth(line.MinWidth, line.Width); line.Dispose(); return minMax; } ////// Client to cache information about a paragraph to be used during optimal paragraph line formatting /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// width of paragraph in which the line fills /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// text formatting state at the point where the previous line in the paragraph /// was broken by the text formatting process, as specified by the TextLine.LineBreak property for the previous /// line; this parameter can be null, and will always be null for the first line in a paragraph. /// an object representing content cache of the client. ///object representing a line of text that client interacts with. #if OPTIMALBREAK_API public override TextParagraphCache CreateParagraphCache( #else internal override TextParagraphCache CreateParagraphCache( #endif TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) { // prepare formatting settings FormatSettings settings = PrepareFormatSettings( textSource, firstCharIndex, paragraphWidth, paragraphProperties, previousLineBreak, textRunCache, true, // optimalBreak false // !isSingleLineFormatting ); // // Optimal paragraph formatting session specific check // if (!settings.Pap.Wrap && settings.Pap.OptimalBreak) { // Optimal paragraph must wrap. throw new ArgumentException(SR.Get(SRID.OptimalParagraphMustWrap)); } // create paragraph content cache object return new TextParagraphCache( settings, firstCharIndex, RealToIdeal(paragraphWidth) ); } ////// Validate all the relevant text formatting initial settings and package them /// private FormatSettings PrepareFormatSettings( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache, bool useOptimalBreak, bool isSingleLineFormatting ) { 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 ); } ////// Verify all text formatting arguments /// private void VerifyTextFormattingArguments( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextRunCache textRunCache ) { if (textSource == null) throw new ArgumentNullException("textSource"); if (textRunCache == null) throw new ArgumentNullException("textRunCache"); if (paragraphProperties == null) throw new ArgumentNullException("paragraphProperties"); if (paragraphProperties.DefaultTextRunProperties == null) throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties"); if (paragraphProperties.DefaultTextRunProperties.Typeface == null) throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties.Typeface"); if (DoubleUtil.IsNaN(paragraphWidth)) throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeNaN)); if (double.IsInfinity(paragraphWidth)) throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeInfinity)); double realInfiniteWidth = IdealToReal(Constants.InfiniteWidth); if ( paragraphWidth < 0 || paragraphWidth > realInfiniteWidth) { throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterMustBeBetween, 0, realInfiniteWidth)); } double realMaxFontRenderingEmSize = realInfiniteWidth / Constants.GreatestMutiplierOfEm; if ( paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize < 0 || paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize > realMaxFontRenderingEmSize) { throw new ArgumentOutOfRangeException("paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize", SR.Get(SRID.ParameterMustBeBetween, 0, realMaxFontRenderingEmSize)); } if (paragraphProperties.Indent > realInfiniteWidth) throw new ArgumentOutOfRangeException("paragraphProperties.Indent", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth)); if (paragraphProperties.LineHeight > realInfiniteWidth) throw new ArgumentOutOfRangeException("paragraphProperties.LineHeight", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth)); if ( paragraphProperties.DefaultIncrementalTab < 0 || paragraphProperties.DefaultIncrementalTab > realInfiniteWidth) { throw new ArgumentOutOfRangeException("paragraphProperties.DefaultIncrementalTab", SR.Get(SRID.ParameterMustBeBetween, 0, realInfiniteWidth)); } } ////// Validate the input character hit /// internal static void VerifyCaretCharacterHit( CharacterHit characterHit, int cpFirst, int cchLength ) { if ( characterHit.FirstCharacterIndex < cpFirst || characterHit.FirstCharacterIndex > cpFirst + cchLength) { throw new ArgumentOutOfRangeException("First", SR.Get(SRID.ParameterMustBeBetween, cpFirst, cpFirst + cchLength)); } if (characterHit.TrailingLength < 0) { throw new ArgumentOutOfRangeException("Length", SR.Get(SRID.ParameterCannotBeNegative)); } } ////// Acquire a free TextFormatter context for complex line operation /// /// object that becomes the owner of LS context once acquired /// matching PLOC ///Active LS context ////// Critical - this sets the owner of the context /// Safe - this doesn't expose critical info /// [SecurityCritical, SecurityTreatAsSafe] internal TextFormatterContext AcquireContext( object owner, IntPtr ploc ) { Invariant.Assert(owner != null); TextFormatterContext context = null; int c; int contextCount = _contextList.Count; for (c = 0; c < contextCount; c++) { context = (TextFormatterContext)_contextList[c]; if (ploc == IntPtr.Zero) { if(context.Owner == null) break; } else if (ploc == context.Ploc.Value) { // LS requires that we use the exact same context for line // destruction or hittesting (part of the reason is that LS // actually caches some run info in the context). So here // we use the actual PLSC as the context signature so we // locate the one we want. Debug.Assert(context.Owner == null); break; } } if (c == contextCount) { if (contextCount == 0 || !_multipleContextProhibited) { // no free one exists, create a new one context = new TextFormatterContext(); _contextList.Add(context); } else { // This instance of TextFormatter only allows a single context, reentering the // same TextFormatter in this case is not allowed. // // This requirement is currently enforced only during optimal break computation. // Client implementing nesting of optimal break content inside another must create // a separate TextFormatter instance for each content in different nesting level. throw new InvalidOperationException(SR.Get(SRID.TextFormatterReentranceProhibited)); } } Debug.Assert(context != null); context.Owner = owner; return context; } ////// Create an anti-inversion transform from the inversion flags. /// The result is used to correct glyph bitmap on an output to /// a drawing surface with the specified inversions applied on. /// internal static MatrixTransform CreateAntiInversionTransform( InvertAxes inversion, double paragraphWidth, double lineHeight ) { if (inversion == InvertAxes.None) { // avoid creating unncessary pressure on GC when anti-transform is not needed. return null; } double m11 = 1; double m22 = 1; double offsetX = 0; double offsetY = 0; if ((inversion & InvertAxes.Horizontal) != 0) { m11 = -m11; offsetX = paragraphWidth; } if ((inversion & InvertAxes.Vertical) != 0) { m22 = -m22; offsetY = lineHeight; } return new MatrixTransform(m11, 0, 0, m22, offsetX, offsetY); } ////// Scale LS ideal resolution value to real value /// internal double IdealToReal(int i) { return i * _toReal; } ////// Scale real value to LS ideal resolution /// internal int RealToIdeal(double i) { return (int) Math.Round(i * _toIdeal); } ////// Scale the real value to LS ideal resolution /// Use the floor value of the scale value /// ////// Using Math.Round may result in a line larger than /// the actual given paragraph width. For example, /// round tripping 100.112 with factor 300 becomes 100.1133... /// Using floor to ensure we never go beyond paragraph width /// internal int RealToIdealFloor(double i) { return (int) Math.Floor(i * _toIdeal); } ////// Ideal to real value scaling factor /// internal double ToReal { get { return _toReal; } } ////// Real to ideal value scaling factor /// internal double ToIdeal { get { return _toIdeal; } } ////// Return the GlyphingCache associated with this TextFormatterImp object. /// GlyphingCache stores the mapping from Unicode scalar value to the physical font that is /// used to display it. /// internal GlyphingCache GlyphingCache { get { if (_glyphingCache == null) { _glyphingCache = new GlyphingCache(MaxGlyphingCacheCapacity); } return _glyphingCache; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //+------------------------------------------------------------------------ // // Microsoft Windows Client Platform // Copyright (C) Microsoft Corporation // // File: TextFormatterImp.cs // // Contents: Text formatter implementation // // Created: 2-25-2003 Worachai Chaoweeraprasit (wchao) // //----------------------------------------------------------------------- using System; using System.Security; using System.Windows; using System.Windows.Media; using System.Windows.Threading; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Windows.Media.TextFormatting; using MS.Utility; using SR=MS.Internal.PresentationCore.SR; using SRID=MS.Internal.PresentationCore.SRID; using MS.Internal.Shaping; #if !OPTIMALBREAK_API using MS.Internal.PresentationCore; #endif namespace MS.Internal.TextFormatting { ////// Implementation of TextFormatter /// internal sealed class TextFormatterImp : TextFormatter { private FrugalStructList_contextList; // LS context free list private double _toIdeal; // scaling factor from client's real space to LS ideal resolution private double _toReal; // scaling factor from LS ideal resolution to client's real space private bool _multipleContextProhibited; // prohibit multiple contexts within the same formatter private GlyphingCache _glyphingCache; // Glyphing cache for font linking process private const int MaxGlyphingCacheCapacity = 16; /// /// Construct an instance of TextFormatter implementation /// internal TextFormatterImp() : this(null) {} ////// Construct an instance of TextFormatter implementation with the specified context /// /// ////// 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. /// internal TextFormatterImp(TextFormatterContext soleContext) { _toIdeal = Constants.DefaultRealToIdeal; _toReal = Constants.DefaultIdealToReal; if (soleContext != null) _contextList.Add(soleContext); _multipleContextProhibited = (_contextList.Count != 0); } ////// Finalizing text formatter /// ~TextFormatterImp() { CleanupInternal(); } ////// Release all unmanaged LS contexts /// public override void Dispose() { CleanupInternal(); base.Dispose(); GC.SuppressFinalize(this); } ////// Release all unmanaged LS contexts /// private void CleanupInternal() { for (int i = 0; i < _contextList.Count; i++) { _contextList[i].Destroy(); } _contextList.Clear(); } ////// Client to format a text line that fills a paragraph in the document. /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// width of paragraph in which the line fills /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// LineBreak property of the previous text line, or null if this is the first line in the paragraph ///object representing a line of text that client interacts with. public override TextLine FormatLine( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak ) { return FormatLineInternal( textSource, firstCharIndex, 0, // lineLength paragraphWidth, paragraphProperties, previousLineBreak, new TextRunCache() // local cache, only live within this call ); } ////// Client to format a text line that fills a paragraph in the document. /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// width of paragraph in which the line fills /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// LineBreak property of the previous text line, or null if this is the first line in the paragraph /// an object representing content cache of the client. ///object representing a line of text that client interacts with. public override TextLine FormatLine( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) { return FormatLineInternal( textSource, firstCharIndex, 0, // lineLength paragraphWidth, paragraphProperties, previousLineBreak, textRunCache ); } ////// Client to reconstruct a previously formatted text line /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// character length of the line /// width of paragraph in which the line fills /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// LineBreak property of the previous text line, or null if this is the first line in the paragraph /// an object representing content cache of the client. ///object representing a line of text that client interacts with. #if OPTIMALBREAK_API public override TextLine RecreateLine( #else internal override TextLine RecreateLine( #endif TextSource textSource, int firstCharIndex, int lineLength, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) { return FormatLineInternal( textSource, firstCharIndex, lineLength, paragraphWidth, paragraphProperties, previousLineBreak, textRunCache ); } ////// Format and produce a text line either with or without previously known /// line break point. /// private TextLine FormatLineInternal( TextSource textSource, int firstCharIndex, int lineLength, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) { if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) { EventTrace.EventProvider.TraceEvent( EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), EventType.StartEvent, "TextFormatterImp.FormatLineInternal Start" ); } // prepare formatting settings FormatSettings settings = PrepareFormatSettings( textSource, firstCharIndex, paragraphWidth, paragraphProperties, previousLineBreak, textRunCache, (lineLength != 0), // Do optimal break if break is given true // isSingleLineFormatting ); TextLine textLine = null; if ( !settings.Pap.AlwaysCollapsible && previousLineBreak == null && lineLength <= 0 ) { // simple text line. textLine = SimpleTextLine.Create( settings, firstCharIndex, RealToIdealFloor(paragraphWidth) ) as TextLine; } if (textLine == null) { // content is complex, creating complex line textLine = new TextMetrics.FullTextLine( settings, firstCharIndex, lineLength, RealToIdealFloor(paragraphWidth), LineFlags.None ) as TextLine; } if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) { EventTrace.EventProvider.TraceEvent( EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID), EventType.EndEvent, "TextFormatterImp.FormatLineInternal End" ); } return textLine; } ////// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. ///min max paragraph width public override MinMaxParagraphWidth FormatMinMaxParagraphWidth( TextSource textSource, int firstCharIndex, TextParagraphProperties paragraphProperties ) { return FormatMinMaxParagraphWidth( textSource, firstCharIndex, paragraphProperties, new TextRunCache() // local cache, only live within this call ); } ////// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// an object representing content cache of the client. ///min max paragraph width public override MinMaxParagraphWidth FormatMinMaxParagraphWidth( TextSource textSource, int firstCharIndex, TextParagraphProperties paragraphProperties, TextRunCache textRunCache ) { // prepare formatting settings FormatSettings settings = PrepareFormatSettings( textSource, firstCharIndex, 0, // infinite paragraphWidth paragraphProperties, null, // always format the whole paragraph - no previousLineBreak textRunCache, false, // optimalBreak true // isSingleLineFormatting ); // create specialized line specifically for min/max calculation TextMetrics.FullTextLine line = new TextMetrics.FullTextLine( settings, firstCharIndex, 0, // lineLength 0, // paragraph width has no significant meaning in min/max calculation (LineFlags.KeepState | LineFlags.MinMax) ); // line width in this case is the width of a line when the entire paragraph is laid out // as a single long line. MinMaxParagraphWidth minMax = new MinMaxParagraphWidth(line.MinWidth, line.Width); line.Dispose(); return minMax; } ////// Client to cache information about a paragraph to be used during optimal paragraph line formatting /// /// an object representing text layout clients text source for TextFormatter. /// character index to specify where in the source text the line starts /// width of paragraph in which the line fills /// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation. /// text formatting state at the point where the previous line in the paragraph /// was broken by the text formatting process, as specified by the TextLine.LineBreak property for the previous /// line; this parameter can be null, and will always be null for the first line in a paragraph. /// an object representing content cache of the client. ///object representing a line of text that client interacts with. #if OPTIMALBREAK_API public override TextParagraphCache CreateParagraphCache( #else internal override TextParagraphCache CreateParagraphCache( #endif TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) { // prepare formatting settings FormatSettings settings = PrepareFormatSettings( textSource, firstCharIndex, paragraphWidth, paragraphProperties, previousLineBreak, textRunCache, true, // optimalBreak false // !isSingleLineFormatting ); // // Optimal paragraph formatting session specific check // if (!settings.Pap.Wrap && settings.Pap.OptimalBreak) { // Optimal paragraph must wrap. throw new ArgumentException(SR.Get(SRID.OptimalParagraphMustWrap)); } // create paragraph content cache object return new TextParagraphCache( settings, firstCharIndex, RealToIdeal(paragraphWidth) ); } ////// Validate all the relevant text formatting initial settings and package them /// private FormatSettings PrepareFormatSettings( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache, bool useOptimalBreak, bool isSingleLineFormatting ) { 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 ); } ////// Verify all text formatting arguments /// private void VerifyTextFormattingArguments( TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextRunCache textRunCache ) { if (textSource == null) throw new ArgumentNullException("textSource"); if (textRunCache == null) throw new ArgumentNullException("textRunCache"); if (paragraphProperties == null) throw new ArgumentNullException("paragraphProperties"); if (paragraphProperties.DefaultTextRunProperties == null) throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties"); if (paragraphProperties.DefaultTextRunProperties.Typeface == null) throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties.Typeface"); if (DoubleUtil.IsNaN(paragraphWidth)) throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeNaN)); if (double.IsInfinity(paragraphWidth)) throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeInfinity)); double realInfiniteWidth = IdealToReal(Constants.InfiniteWidth); if ( paragraphWidth < 0 || paragraphWidth > realInfiniteWidth) { throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterMustBeBetween, 0, realInfiniteWidth)); } double realMaxFontRenderingEmSize = realInfiniteWidth / Constants.GreatestMutiplierOfEm; if ( paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize < 0 || paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize > realMaxFontRenderingEmSize) { throw new ArgumentOutOfRangeException("paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize", SR.Get(SRID.ParameterMustBeBetween, 0, realMaxFontRenderingEmSize)); } if (paragraphProperties.Indent > realInfiniteWidth) throw new ArgumentOutOfRangeException("paragraphProperties.Indent", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth)); if (paragraphProperties.LineHeight > realInfiniteWidth) throw new ArgumentOutOfRangeException("paragraphProperties.LineHeight", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth)); if ( paragraphProperties.DefaultIncrementalTab < 0 || paragraphProperties.DefaultIncrementalTab > realInfiniteWidth) { throw new ArgumentOutOfRangeException("paragraphProperties.DefaultIncrementalTab", SR.Get(SRID.ParameterMustBeBetween, 0, realInfiniteWidth)); } } ////// Validate the input character hit /// internal static void VerifyCaretCharacterHit( CharacterHit characterHit, int cpFirst, int cchLength ) { if ( characterHit.FirstCharacterIndex < cpFirst || characterHit.FirstCharacterIndex > cpFirst + cchLength) { throw new ArgumentOutOfRangeException("First", SR.Get(SRID.ParameterMustBeBetween, cpFirst, cpFirst + cchLength)); } if (characterHit.TrailingLength < 0) { throw new ArgumentOutOfRangeException("Length", SR.Get(SRID.ParameterCannotBeNegative)); } } ////// Acquire a free TextFormatter context for complex line operation /// /// object that becomes the owner of LS context once acquired /// matching PLOC ///Active LS context ////// Critical - this sets the owner of the context /// Safe - this doesn't expose critical info /// [SecurityCritical, SecurityTreatAsSafe] internal TextFormatterContext AcquireContext( object owner, IntPtr ploc ) { Invariant.Assert(owner != null); TextFormatterContext context = null; int c; int contextCount = _contextList.Count; for (c = 0; c < contextCount; c++) { context = (TextFormatterContext)_contextList[c]; if (ploc == IntPtr.Zero) { if(context.Owner == null) break; } else if (ploc == context.Ploc.Value) { // LS requires that we use the exact same context for line // destruction or hittesting (part of the reason is that LS // actually caches some run info in the context). So here // we use the actual PLSC as the context signature so we // locate the one we want. Debug.Assert(context.Owner == null); break; } } if (c == contextCount) { if (contextCount == 0 || !_multipleContextProhibited) { // no free one exists, create a new one context = new TextFormatterContext(); _contextList.Add(context); } else { // This instance of TextFormatter only allows a single context, reentering the // same TextFormatter in this case is not allowed. // // This requirement is currently enforced only during optimal break computation. // Client implementing nesting of optimal break content inside another must create // a separate TextFormatter instance for each content in different nesting level. throw new InvalidOperationException(SR.Get(SRID.TextFormatterReentranceProhibited)); } } Debug.Assert(context != null); context.Owner = owner; return context; } ////// Create an anti-inversion transform from the inversion flags. /// The result is used to correct glyph bitmap on an output to /// a drawing surface with the specified inversions applied on. /// internal static MatrixTransform CreateAntiInversionTransform( InvertAxes inversion, double paragraphWidth, double lineHeight ) { if (inversion == InvertAxes.None) { // avoid creating unncessary pressure on GC when anti-transform is not needed. return null; } double m11 = 1; double m22 = 1; double offsetX = 0; double offsetY = 0; if ((inversion & InvertAxes.Horizontal) != 0) { m11 = -m11; offsetX = paragraphWidth; } if ((inversion & InvertAxes.Vertical) != 0) { m22 = -m22; offsetY = lineHeight; } return new MatrixTransform(m11, 0, 0, m22, offsetX, offsetY); } ////// Scale LS ideal resolution value to real value /// internal double IdealToReal(int i) { return i * _toReal; } ////// Scale real value to LS ideal resolution /// internal int RealToIdeal(double i) { return (int) Math.Round(i * _toIdeal); } ////// Scale the real value to LS ideal resolution /// Use the floor value of the scale value /// ////// Using Math.Round may result in a line larger than /// the actual given paragraph width. For example, /// round tripping 100.112 with factor 300 becomes 100.1133... /// Using floor to ensure we never go beyond paragraph width /// internal int RealToIdealFloor(double i) { return (int) Math.Floor(i * _toIdeal); } ////// Ideal to real value scaling factor /// internal double ToReal { get { return _toReal; } } ////// Real to ideal value scaling factor /// internal double ToIdeal { get { return _toIdeal; } } ////// Return the GlyphingCache associated with this TextFormatterImp object. /// GlyphingCache stores the mapping from Unicode scalar value to the physical font that is /// used to display it. /// internal GlyphingCache GlyphingCache { get { if (_glyphingCache == null) { _glyphingCache = new GlyphingCache(MaxGlyphingCacheCapacity); } return _glyphingCache; } } } } // 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
- _ConnectionGroup.cs
- UnsafeNativeMethods.cs
- IDispatchConstantAttribute.cs
- PerformanceCounter.cs
- HTMLTextWriter.cs
- DataRow.cs
- OrderedEnumerableRowCollection.cs
- ApplicationDirectory.cs
- Relationship.cs
- GridSplitterAutomationPeer.cs
- ForwardPositionQuery.cs
- HighlightComponent.cs
- MimeFormReflector.cs
- CopyAction.cs
- cache.cs
- Registry.cs
- ScriptReference.cs
- HandledEventArgs.cs
- ClientBuildManagerCallback.cs
- OperatingSystem.cs
- GB18030Encoding.cs
- Context.cs
- CodeIdentifier.cs
- ScriptingRoleServiceSection.cs
- FlowLayoutSettings.cs
- ChooseAction.cs
- TreeSet.cs
- DbXmlEnabledProviderManifest.cs
- DtdParser.cs
- TableRow.cs
- PartBasedPackageProperties.cs
- GridViewRowCollection.cs
- UnSafeCharBuffer.cs
- MultiPartWriter.cs
- DbParameterHelper.cs
- SafeRegistryKey.cs
- StoreConnection.cs
- SimpleApplicationHost.cs
- MessageBox.cs
- InfoCardCryptoHelper.cs
- DataGridViewCheckBoxCell.cs
- WebPartMinimizeVerb.cs
- XmlText.cs
- Guid.cs
- ValueTypePropertyReference.cs
- ScrollableControlDesigner.cs
- NamedPermissionSet.cs
- ModelVisual3D.cs
- TypeConverterHelper.cs
- CopyOfAction.cs
- XPathNavigatorReader.cs
- XamlUtilities.cs
- PathFigureCollectionConverter.cs
- CommandBinding.cs
- ToggleButtonAutomationPeer.cs
- dataobject.cs
- JsonWriter.cs
- DataRowExtensions.cs
- CalendarKeyboardHelper.cs
- ResourceReferenceExpressionConverter.cs
- SizeLimitedCache.cs
- MetadataItemCollectionFactory.cs
- CacheAxisQuery.cs
- Base64Stream.cs
- HexParser.cs
- Calendar.cs
- DataFieldCollectionEditor.cs
- MsmqHostedTransportConfiguration.cs
- XmlQualifiedNameTest.cs
- SEHException.cs
- SerializerDescriptor.cs
- DataColumn.cs
- ConnectionProviderAttribute.cs
- Interlocked.cs
- RewritingValidator.cs
- SiteMapNodeItem.cs
- PropertyPath.cs
- ShapingWorkspace.cs
- ConsoleKeyInfo.cs
- XmlAnyElementAttributes.cs
- TableRowCollection.cs
- VisualBrush.cs
- XmlArrayItemAttribute.cs
- DataGridPageChangedEventArgs.cs
- Vector3DCollection.cs
- HtmlWindow.cs
- DataObject.cs
- Image.cs
- DocumentViewer.cs
- CompilerTypeWithParams.cs
- DBSchemaRow.cs
- BitmapPalette.cs
- ToolTipService.cs
- ProcessHostFactoryHelper.cs
- BitmapEncoder.cs
- TdsParser.cs
- TokenBasedSetEnumerator.cs
- X509ScopedServiceCertificateElementCollection.cs
- Encoding.cs
- Console.cs