Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / MS / Internal / TextFormatting / TextMetrics.cs / 1305600 / TextMetrics.cs
//------------------------------------------------------------------------ // // Microsoft Windows Client Platform // Copyright (C) Microsoft Corporation, 2001 // // File: TextMetrics.cs // // Contents: Full text implementation of ITextMetrics // // Created: 5-6-2002 Worachai Chaoweeraprasit (wchao) // History: 2-3-2005 (wchao) Refactoring from FullTextLine for optimal paragraph usage. // //----------------------------------------------------------------------- using System; using System.Diagnostics; using System.Windows; using System.Windows.Media; using System.Windows.Media.TextFormatting; using System.Security; using System.Security.Permissions; using MS.Internal.FontCache; using SR = MS.Internal.PresentationCore.SR; using SRID = MS.Internal.PresentationCore.SRID; namespace MS.Internal.TextFormatting { internal partial struct TextMetrics : ITextMetrics { private TextFormatterImp _formatter; // text formatter formatting this metrics private int _lscpLim; // number of LSCP in the line (for boundary condition handling) private int _cchLength; // actual character count private int _cchDepend; // number of chars after linebreak that triggers reformatting this line private int _cchNewline; // number of chars of newline symbol private int _height; // line height private int _textHeight; // measured height of text within the line private int _baselineOffset; // offset from top of line height to baseline private int _textAscent; // offset from top of text height to baseline private int _textStart; // distance from LS origin to text start private int _textWidth; // text start to end private int _textWidthAtTrailing; // text start to end excluding trailing whitespaces private int _paragraphToText; // paragraph start to text start private LSRun _lastRun; // Last Text LSRun ////// Construct text metrics from full text info /// ////// /// When the application formats a line of text. It starts from the leading edge of the paragraph - the reference position /// called "Paragraph Start". It gives the width of the paragraph or "Paragraph Width" to TextFormatter as one of the main /// parameters to TextFormatter.FormatLine method. It may also provide additional info about how it wants the line to look /// like. The following are all of such info and how the formatting process is carried on inside TextFormatter. /// /// /// *** Indent/Paragraph Indent *** /// The application may specify "Indent" - the distance from the beginning of the line to the beginning of the text in that /// line. The value is sent to TextFormatter via [TextParagraphProperties.Indent]. It may also specify "Paragraph Indent" /// - the distance from the beginning of the paragraph to the beginning of the line [TextParagraphProperties.ParagraphIndent]. /// The usage of paragraph indent is to offset the beginning of the line relative to the paragraph starting point, while /// indent is to offset the beginning of text realtive to the line starting point. Paragraph indent is not included as part /// of the line width while indent is. /// /// /// *** Text Alignment *** /// "Text Alignment" [TextParagraphProperties.TextAlignment] may be specified to align the leading, center or trailing edge /// of the line to the leading, center or trailing edge of the paragraph excluding paragraph indent. /// /// /// *** Bullet/Auto-numbering *** /// The application may also specify "bullet" (or "marker") for the line. Marker does not affect the layout measurement of the /// line. Line with marker has the same line width with the line that has not. The presence of marker however affects the /// pixel-wise black width of the line. The application specifies the distance from the beginning of the line to the trailing /// edge of the marker symbol via the property [TextMarkerProperties.Offset]. The application can create the visual effect of /// having marker embedded inside the body of paragraph text (so-called "marker inside") by specifying a positive indent so /// that the text starts after the beginning of the line and a positive smaller amount of marker offset to place the marker /// symbol at between the beginning of the line and the beginning of the text. The "marker outside" visual effect can /// also be achieved in a similar manner by specifying zero or positive indent value with negative marker offset value. /// /// /// *** Formatted Line Properties *** /// Once the line formatting process is completed and a line is returned to the application. The application determines the /// distance from the paragraph starting point to the actual beginning of the line by looking at the "Line Start" property of /// the text line [TextLine.Start]. The "Width" of the line can be determined, naturally, from the property [TextLine.Width]. /// The property value [TextLine.OverhangLeading] represents the distance from the beginning of the line, or the line's alignment /// point, to the first leading pixel of that line so-called the "Black Start". The property [TextLine.OverhangTrailing] /// is the distance from the last trailing pixel of the line to the trailing edge alignment point of the line. The application /// uses these "overhang" or "overshoot" values to ensure proper positioning of text that avoids pixel clipping of the /// glyph image. A less sophisticated application may provide reasonable leading and trailing margin around the text line /// and ignores these properties altogether. /// /// /// *** Hit-Testing *** /// The application may also perform hit-testing by calling methods on TextLine. All the distances involved in hit-testing /// operations are distances from the paragraph start, not from the line start. Marker symbol on its own is not hit-testable. /// /// /// *** Tabs *** /// The application may specify tab stops - an array of positions to where text aligns. Each tab stop may have different /// "Tab Alignment". The left, center and right tab alignment aligns the tab stop position to the leading, center and the /// trailing edge of the text following the tab character. "Tab Leader" may also be specified to fill the distance occupied /// by the presence of tab character with the symbol of choice. Tab stops is specified thru the property [TextParagraph.Tabs]. /// In the absence of tab stops, the application may assume an automatic tab stop - so called "Incremental Tab" specified by /// the property [TextParagraphProperties.DefaultIncrementalTab]. The property could be overridden, by default the value /// is set by TextFormatter to 4 em of the paragraph's default font. /// /// /// *** Line Services Properties *** /// TextFormatter relies on LS to calculate the distance from the beginning of the line to the beginning of text or "Text Start" /// and keep it in the private property [this._textStart]. This value is non-zero when 1) the line starts with indentation or /// 2) the line starts with marker - either bullet or auto-numbering symbol. /// /// In case of the line with marker, LS also produces the distance from the beginning of the line to the beginning of the marker /// symbol, but TextFormatter does not retain that distance because marker is outside the line. The application is assumed /// responsibility to make sure the marker symbol is not going to be clipped out. The application achieves that by manipulating /// the indent value along with the marker offset value. /// /// TextFormatter also retains the total "Text Width" value computed by LS in the private property [this._textWidth]. This /// is the distance from the beginning of the text to the end including all trailing whitespaces at the end of the line. The /// similar value but with trailing whitespaces excluded is kept in the private property [this._textWidthAtTrailing]. /// /// TextFormatter starts formatting a LS line by assuming the beginning of the line being at an imaginary origin. It then /// places the starting point of the content depending on whether the line has either marker symbol or indent. The actual /// mechanism for the placement is in FetchLineProps callback where the value [LsLineProps.durLeft] represents the distance /// relative to the line's origin where actual content begins. The distances can either be positive or negative. Negative /// distance runs in the reverse direction from the direction of text flow. When a negative indent or marker offset is /// specified, durLeft is set to negative distance relative to line start. /// /// TextFormatter however does not rely on LS for the whole line's text alignment. It always formats LS as if the line is /// left-aligned. Once the distances of the line are received, it aligns the whole line according to the text alignment setting /// specified by the application, outside the LS call. The result of this aligning process is a distance from the beginning of /// the paragraph to the beginning of text and is kept in a private property [this._paragraphToText]. /// /// [SecurityCritical] internal unsafe void Compute( FullTextState fullText, int firstCharIndex, int paragraphWidth, FormattedTextSymbols collapsingSymbol, ref LsLineWidths lineWidths, LsLInfo* plsLineInfo ) { _formatter = fullText.Formatter; TextStore store = fullText.TextStore; // obtain position of important distances _textStart = lineWidths.upStartMainText; _textWidthAtTrailing = lineWidths.upStartTrailing; _textWidth = lineWidths.upLimLine; // append line end collapsing symbol if any if (collapsingSymbol != null) { AppendCollapsingSymbolWidth(TextFormatterImp.RealToIdeal(collapsingSymbol.Width)); } // make all widths relative to text start _textWidth -= _textStart; _textWidthAtTrailing -= _textStart; // keep the newline character count if any _cchNewline = store.CchEol; // count text and dependant characters _lscpLim = plsLineInfo->cpLimToContinue; _lastRun = fullText.CountText(_lscpLim, firstCharIndex, out _cchLength); Debug.Assert(_cchLength > 0); if ( plsLineInfo->endr != LsEndRes.endrEndPara && plsLineInfo->endr != LsEndRes.endrSoftCR) { // endrEndPara denotes that the line ends at paragraph end. It is a result of submitting Paragraph Separator to LS. // endrSoftCR denotes end of line but not end of paragraph. This is a result of submitting Line Separator to LS. _cchNewline = 0; if (plsLineInfo->dcpDepend >= 0) { // According to SergeyGe [2/16/2006], dcpDepend reported from LS cannot made precise when considering // the line ending with hyphenation - this is because LS does not have the knowledge about the amount // of text, after the hyphenation point, being examined by its client during the process of finding // the right place to hyphenate. LS client must therefore take into account the number of lookahead // LSCP examined by hyphenator when computing the correct dcpDepend for the line. In our implementation // it would just mean we take the max of the two values. int lscpFirstIndependence = Math.Max( plsLineInfo->cpLimToContinue + plsLineInfo->dcpDepend, fullText.LscpHyphenationLookAhead ); fullText.CountText(lscpFirstIndependence, firstCharIndex, out _cchDepend); _cchDepend -= _cchLength; } } ParaProp pap = store.Pap; if (_height <= 0) { // if height has not been settled, // calculate line height and baseline offset if(pap.LineHeight > 0) { // Host specifies line height, honor it. _height = pap.LineHeight; _baselineOffset = (int)Math.Round( _height * pap.DefaultTypeface.Baseline(pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode) / pap.DefaultTypeface.LineSpacing(pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode) ); } if(plsLineInfo->dvrMultiLineHeight == int.MaxValue) { // Line is empty so text height and text baseline are based on the default typeface; // it doesn't make sense even for an emtpy line to have zero text height _textAscent = (int)Math.Round(pap.DefaultTypeface.Baseline(pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode)); _textHeight = (int)Math.Round(pap.DefaultTypeface.LineSpacing(pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode)); } else { _textAscent = plsLineInfo->dvrAscent; _textHeight = _textAscent + plsLineInfo->dvrDescent; if (fullText.VerticalAdjust) { // Line requires vertical repositioning of text runs store.AdjustRunsVerticalOffset( plsLineInfo->cpLimToContinue - firstCharIndex, _height, _baselineOffset, out _textHeight, out _textAscent ); } } // if the client hasn't specified a line height then the line height and baseline // are the same as the text height and text baseline if (_height <= 0) { _height = _textHeight; _baselineOffset = _textAscent; } } // Text alignment aligns the line to correspondent paragraph alignment start edge switch(pap.Align) { case TextAlignment.Right: // alignment rule: // "The sum of paragraph start to line start and line width is equal to paragraph width" // // PTL + LW = PW // (PTT - LTT) + (LTT + TW) = PW // (thus) PTT = PW - TW _paragraphToText = paragraphWidth - _textWidthAtTrailing; break; case TextAlignment.Center: // alignment rule: // "The sum of paragraph start to line start and half the line width is equal to half the paragraph width" // // PTL + 0.5*LW = 0.5*PW // (PTT - LTT) + 0.5*(LTT + TW) = 0.5*PW // (thus) PTT = 0.5 * (PW + LTT - TW) _paragraphToText = (int)Math.Round((paragraphWidth + _textStart - _textWidthAtTrailing) * 0.5); break; default: // alignment rule: // "Paragraph start to line start is paragraph indent" // // PTL = PI // PTT - LTT = PI // (thus) PTT = PI + LTT _paragraphToText = pap.ParagraphIndent + _textStart; break; } } ////// Client to acquire a state at the point where line is broken by line breaking process; /// can be null when the line ends by the ending of the paragraph. Client may pass this /// value back to TextFormatter as an input argument to TextFormatter.FormatLine when /// formatting the next line within the same paragraph. /// ////// TextLineBreak is a finalizable object which may contain a reference to an unmanaged /// structure called break record. Break record can be acquired thru ploline. This method /// acquire break record only when the passing ploline object is not NULL. /// /// Not all situations requires break record. Single-line formatting without complex text /// object does not need it, but optimal break session does. For performance reason, we /// should not produce break record unnecessarily because it makes TextLineBreak become /// finalizable, which therefore unnecessarily put additional pressure to GC since each /// finalizable object wakes finalizer thread and requires double GC collections. /// ////// Critical - as this calls LoAcquireBreakRecord /// [SecurityCritical] internal TextLineBreak GetTextLineBreak(IntPtr ploline) { IntPtr pbreakrec = IntPtr.Zero; if (ploline != IntPtr.Zero) { LsErr lserr = UnsafeNativeMethods.LoAcquireBreakRecord(ploline, out pbreakrec); if (lserr != LsErr.None) { TextFormatterContext.ThrowExceptionFromLsError(SR.Get(SRID.AcquireBreakRecordFailure, lserr), lserr); } } if ( _lastRun != null && _lastRun.TextModifierScope != null && !(_lastRun.TextRun is TextEndOfParagraph)) { return new TextLineBreak( _lastRun.TextModifierScope, new SecurityCriticalDataForSet(pbreakrec) ); } return (pbreakrec != IntPtr.Zero) ? new TextLineBreak(null, new SecurityCriticalDataForSet (pbreakrec)) : null; } /// /// Append the ideal width of line end collapsing symbol /// private void AppendCollapsingSymbolWidth( int symbolIdealWidth ) { _textWidth += symbolIdealWidth; _textWidthAtTrailing += symbolIdealWidth; } ////// Client to get the number of text source positions of this line /// public int Length { get { return _cchLength; } } ////// Client to get the number of characters following the last character /// of the line that may trigger reformatting of the current line. /// public int DependentLength { get { return _cchDepend; } } ////// Client to get the number of newline characters at line end /// public int NewlineLength { get { return _cchNewline; } } ////// Client to get distance from paragraph start to line start /// public double Start { get { return _formatter.IdealToReal(_paragraphToText - _textStart); } } ////// Client to get the total width of this line /// public double Width { get { return _formatter.IdealToReal(_textWidthAtTrailing + _textStart); } } ////// Client to get the total width of this line including width of whitespace characters at the end of the line. /// public double WidthIncludingTrailingWhitespace { get { return _formatter.IdealToReal(_textWidth + _textStart); } } ////// Client to get the height of the line /// public double Height { get { return _formatter.IdealToReal(_height); } } ////// Client to get the height of the text (or other content) in the line; this property may differ from the Height /// property if the client specified the line height /// public double TextHeight { get { return _formatter.IdealToReal(_textHeight); } } ////// Client to get the distance from top to baseline of this text line /// public double Baseline { get { return _formatter.IdealToReal(_baselineOffset); } } ////// Client to get the distance from the top of the text (or other content) to the baseline of this text line; /// this property may differ from the Baseline property if the client specified the line height /// public double TextBaseline { get { return _formatter.IdealToReal(_textAscent); } } ////// Client to get the distance from the before edge of line height /// to the baseline of marker of the line if any. /// public double MarkerBaseline { get { return Baseline; } } ////// Client to get the overall height of the list items marker of the line if any. /// public double MarkerHeight { get { return Height; } } } } // 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
- ToolStripDropDownButton.cs
- RadioButtonFlatAdapter.cs
- ClosableStream.cs
- InvalidComObjectException.cs
- ItemCollection.cs
- StructuredType.cs
- SecurityRuntime.cs
- PromptBuilder.cs
- XmlHierarchyData.cs
- EditorPart.cs
- EventlogProvider.cs
- _DisconnectOverlappedAsyncResult.cs
- Comparer.cs
- TableLayoutColumnStyleCollection.cs
- MeshGeometry3D.cs
- WindowsGrip.cs
- IndependentlyAnimatedPropertyMetadata.cs
- FixUp.cs
- ColumnResult.cs
- CoTaskMemHandle.cs
- WinInetCache.cs
- Query.cs
- ByteKeyFrameCollection.cs
- PeerCollaborationPermission.cs
- UIPermission.cs
- ExpanderAutomationPeer.cs
- Opcode.cs
- GridView.cs
- ActivityWithResultValueSerializer.cs
- Image.cs
- SchemaLookupTable.cs
- GroupJoinQueryOperator.cs
- SystemWebSectionGroup.cs
- BitmapSource.cs
- DataGridColumnReorderingEventArgs.cs
- TimerElapsedEvenArgs.cs
- SqlDataSourceCache.cs
- ImageKeyConverter.cs
- ListDependantCardsRequest.cs
- MouseActionConverter.cs
- QilInvoke.cs
- HashSet.cs
- ClientData.cs
- SignedInfo.cs
- DbProviderFactories.cs
- Keywords.cs
- Odbc32.cs
- SchemaElement.cs
- TagPrefixInfo.cs
- EncoderExceptionFallback.cs
- PropertyStore.cs
- CodeIdentifier.cs
- OracleRowUpdatingEventArgs.cs
- ObjectIDGenerator.cs
- PageCache.cs
- DesignerVerbCollection.cs
- MULTI_QI.cs
- GlyphTypeface.cs
- CombinedHttpChannel.cs
- SelectionRange.cs
- ExtendedProtectionPolicyElement.cs
- JournalNavigationScope.cs
- NetSectionGroup.cs
- UriTemplatePathPartiallyEquivalentSet.cs
- TraceFilter.cs
- XmlCollation.cs
- SessionIDManager.cs
- RichTextBoxConstants.cs
- Timer.cs
- _SafeNetHandles.cs
- TakeQueryOptionExpression.cs
- ControlTemplate.cs
- SchemaComplexType.cs
- FilterRepeater.cs
- TreeView.cs
- Tablet.cs
- Stopwatch.cs
- OleDbStruct.cs
- FontFamilyIdentifier.cs
- UnaryNode.cs
- TimeoutValidationAttribute.cs
- HttpProcessUtility.cs
- Pair.cs
- _ListenerRequestStream.cs
- CompositeFontInfo.cs
- baseshape.cs
- ComboBoxAutomationPeer.cs
- LinqDataSourceDeleteEventArgs.cs
- SafeNativeMethods.cs
- InkCanvasAutomationPeer.cs
- ToolStripSplitButton.cs
- SchemaTableColumn.cs
- RtfNavigator.cs
- ScalarConstant.cs
- SafeNativeMethods.cs
- CodeTypeOfExpression.cs
- DataGridParentRows.cs
- CopyNamespacesAction.cs
- ListItemParagraph.cs
- UnsafeNativeMethods.cs