Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / TextFormatting / TextFormatterImp.cs / 1600529 / 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; using MS.Internal.Text.TextInterface; using MS.Internal.FontCache; #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 bool _multipleContextProhibited; // prohibit multiple contexts within the same formatter private GlyphingCache _glyphingCache; // Glyphing cache for font linking process private TextFormattingMode _textFormattingMode; private TextAnalyzer _textAnalyzer; // TextAnalyzer used for shaping process private const int MaxGlyphingCacheCapacity = 16; /// /// Construct an instance of TextFormatter implementation /// internal TextFormatterImp(TextFormattingMode textFormattingMode) : this(null, textFormattingMode) { } ////// Construct an instance of TextFormatter implementation /// internal TextFormatterImp() : this(null, TextFormattingMode.Ideal) {} ////// 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, TextFormattingMode textFormattingMode) { _textFormattingMode = textFormattingMode; 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 ) { EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordText, EventTrace.Level.Verbose, EventTrace.Event.WClientStringBegin, "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 _textFormattingMode ); 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; } EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordText, EventTrace.Level.Verbose, EventTrace.Event.WClientStringEnd, "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 _textFormattingMode ); // 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; } internal TextFormattingMode TextFormattingMode { get { return _textFormattingMode; } } ////// 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 _textFormattingMode ); // // 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, 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 ); } ////// 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)); if ( paragraphWidth < 0 || paragraphWidth > Constants.RealInfiniteWidth) { throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterMustBeBetween, 0, Constants.RealInfiniteWidth)); } double realMaxFontRenderingEmSize = Constants.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 > Constants.RealInfiniteWidth) throw new ArgumentOutOfRangeException("paragraphProperties.Indent", SR.Get(SRID.ParameterCannotBeGreaterThan, Constants.RealInfiniteWidth)); if (paragraphProperties.LineHeight > Constants.RealInfiniteWidth) throw new ArgumentOutOfRangeException("paragraphProperties.LineHeight", SR.Get(SRID.ParameterCannotBeGreaterThan, Constants.RealInfiniteWidth)); if ( paragraphProperties.DefaultIncrementalTab < 0 || paragraphProperties.DefaultIncrementalTab > Constants.RealInfiniteWidth) { throw new ArgumentOutOfRangeException("paragraphProperties.DefaultIncrementalTab", SR.Get(SRID.ParameterMustBeBetween, 0, Constants.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("cpFirst", SR.Get(SRID.ParameterMustBeBetween, cpFirst, cpFirst + cchLength)); } if (characterHit.TrailingLength < 0) { throw new ArgumentOutOfRangeException("cchLength", 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); } ////// 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. /// /// First value to compare. /// Second value to compare. /// Text formatting mode. ///1 if x greater than y, -1 if x less than y, 0 if x == y 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; } internal static double RoundDip(double value, TextFormattingMode textFormattingMode) { if (TextFormattingMode.Display == textFormattingMode) { return RoundDipForDisplayMode(value); } else { return value; } } internal static double RoundDipForDisplayMode(double value) { return RoundDipForDisplayMode(value, MidpointRounding.ToEven); } private static double RoundDipForDisplayMode(double value, MidpointRounding midpointRounding) { return Math.Round(value * Util.PixelsPerDip, midpointRounding) / Util.PixelsPerDip; } ////// The default behavior of Math.Round() leads to undesirable behavior /// When used for display mode justified text, where we can find /// characters belonging to the same word jumping sideways. /// A word can break among several GlyphRuns. So we need consistent /// rounding of the width of the GlyphRuns. If the width of one GlyphRun /// rounds up and the next GlyphRun rounds down then we see characters /// overlapping and so on. /// It is too late to change the behavior of our rounding universally /// so we are making the change targeted to Display mode + Justified text /// /// ///internal static double RoundDipForDisplayModeJustifiedText(double value) { return RoundDipForDisplayMode(value, MidpointRounding.AwayFromZero); } /// /// Scale LS ideal resolution value to real value /// internal static double IdealToRealWithNoRounding(double i) { return i * Constants.DefaultIdealToReal; } ////// Scale LS ideal resolution value to real value /// internal double IdealToReal(double i) { double value = IdealToRealWithNoRounding(i); if (_textFormattingMode == TextFormattingMode.Display) { value = RoundDipForDisplayMode(value); } if (i > 0) { // Non-zero values should not be converted to 0 accidentally through rounding, ensure that at least the min value is returned. value = Math.Max(value, Constants.DefaultIdealToReal); } return value; } ////// Scale real value to LS ideal resolution /// internal static int RealToIdeal(double i) { int value = (int)Math.Round(i * ToIdeal); if (i > 0) { // Non-zero values should not be converted to 0 accidentally through rounding, ensure that at least the min value is returned. value = Math.Max(value, 1); } return value; } ////// 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 static int RealToIdealFloor(double i) { int value = (int)Math.Floor(i * ToIdeal); if (i > 0) { // Non-zero values should not be converted to 0 accidentally through rounding, ensure that at least the min value is returned. value = Math.Max(value, 1); } return value; } ////// Real to ideal value scaling factor /// internal static double ToIdeal { get { return Constants.DefaultRealToIdeal; } } ////// 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; } } internal TextAnalyzer TextAnalyzer { ////// Return the TextAnalyzer associated with this TextFormatterImp object. /// TextAnalyzer is used in shaping process. /// ////// Critical - Uses security critical DWriteFactory.Instance. /// Safe - Does not expose the Factory instance. /// [SecuritySafeCritical] get { if (_textAnalyzer == null) { _textAnalyzer = DWriteFactory.Instance.CreateTextAnalyzer(); } return _textAnalyzer; } } } } // 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
- Positioning.cs
- ConditionalBranch.cs
- DbMetaDataFactory.cs
- ToolZone.cs
- ContactManager.cs
- MarshalByRefObject.cs
- MetricEntry.cs
- InvalidFilterCriteriaException.cs
- IOThreadTimer.cs
- SinglePageViewer.cs
- EventPrivateKey.cs
- ListViewCancelEventArgs.cs
- ListControlConvertEventArgs.cs
- ProfilePropertyMetadata.cs
- ResolveDuplex11AsyncResult.cs
- Attributes.cs
- DocumentReferenceCollection.cs
- VariantWrapper.cs
- XmlSequenceWriter.cs
- AmbiguousMatchException.cs
- SchemaImporter.cs
- ObjectPersistData.cs
- ObjectDataProvider.cs
- CircleHotSpot.cs
- CustomErrorsSectionWrapper.cs
- RegistryKey.cs
- HttpResponseHeader.cs
- DrawingCollection.cs
- EntityCollection.cs
- WindowsTokenRoleProvider.cs
- ReadOnlyDataSource.cs
- SqlInternalConnectionTds.cs
- Component.cs
- SynchronizingStream.cs
- ToolStripButton.cs
- FileVersionInfo.cs
- ToolboxDataAttribute.cs
- ContextMenuService.cs
- Inline.cs
- ModelItemExtensions.cs
- DataRecordInternal.cs
- ColorConvertedBitmap.cs
- XsdBuildProvider.cs
- HttpModulesSection.cs
- TagElement.cs
- ToolStripStatusLabel.cs
- OdbcConnectionHandle.cs
- Perspective.cs
- QueryAsyncResult.cs
- SessionPageStatePersister.cs
- XmlSchemaDocumentation.cs
- SessionStateModule.cs
- CodeCommentStatement.cs
- PolicyImporterElementCollection.cs
- TrustDriver.cs
- FontFamily.cs
- ValidationService.cs
- BufferedReadStream.cs
- ActivityTypeCodeDomSerializer.cs
- QueryInterceptorAttribute.cs
- CodeArrayIndexerExpression.cs
- HttpVersion.cs
- Delegate.cs
- SqlUnionizer.cs
- dataSvcMapFileLoader.cs
- RtType.cs
- XPathParser.cs
- DataContractSerializer.cs
- WindowsBrush.cs
- ToolboxSnapDragDropEventArgs.cs
- TraceUtils.cs
- SamlSecurityTokenAuthenticator.cs
- StoreUtilities.cs
- StructuredTypeEmitter.cs
- IndicShape.cs
- UInt64.cs
- SiteOfOriginPart.cs
- AnnotationObservableCollection.cs
- Reference.cs
- EndOfStreamException.cs
- InvokePattern.cs
- TdsParserSessionPool.cs
- BitmapFrameDecode.cs
- ImageBrush.cs
- Decorator.cs
- ListViewDeletedEventArgs.cs
- WorkflowOperationInvoker.cs
- Accessible.cs
- NumberSubstitution.cs
- HwndHost.cs
- UnmanagedMarshal.cs
- ProfilePropertySettings.cs
- Int64Converter.cs
- MatrixTransform3D.cs
- ScriptingJsonSerializationSection.cs
- WebHeaderCollection.cs
- querybuilder.cs
- TrackingServices.cs
- ManagementOptions.cs
- safex509handles.cs