private double _baseGuidelineY; // the Y guideline of the text line. /// <summary> /// Construct drawing state for full text /// </summary> internal DrawingState( DrawingContext drawingContext, Point lineOrigin, MatrixTransform antiInversion, TextMetrics.FullTextLine currentLine ) { _drawingContext = drawingContext; _antiInversion = antiInversion; _currentLine = currentLine; if (antiInversion == null) { _lineOrigin = lineOrigin; } else { _vectorToLineOrigin = lineOrigin; } if (_drawingContext != null) { // LineServices draws GlyphRun and TextDecorations in multiple // callbacks and GlyphRuns may have different baselines. Pushing guideline // for each DrawGlyphRun are too costly. We optimize for the common case where // GlyphRuns and TextDecorations in the TextLine share the same baseline. _baseGuidelineY = lineOrigin.Y + currentLine.Baseline; _drawingContext.PushGuidelineY1(_baseGuidelineY); } }
/// <summary> /// Client to collapse the line to fit for display /// </summary> /// <param name="collapsingPropertiesList">a list of collapsing properties</param> public override TextLine Collapse( params TextCollapsingProperties[] collapsingPropertiesList ) { if ((_statusFlags & StatusFlags.IsDisposed) != 0) { throw new ObjectDisposedException(SR.Get(SRID.TextLineHasBeenDisposed)); } if ( !HasOverflowed && (_statusFlags & StatusFlags.KeepState) == 0) { // Attempt to collapse a non-overflowed line results in the original line returned return this; } if (collapsingPropertiesList == null || collapsingPropertiesList.Length == 0) throw new ArgumentNullException("collapsingPropertiesList"); TextCollapsingProperties collapsingProp = collapsingPropertiesList[0]; double constraintWidth = collapsingProp.Width; if (TextFormatterImp.CompareReal(constraintWidth, Width, _textFormattingMode) > 0) { // constraining width is greater than original line width, no collapsing neeeded. return this; } FormattedTextSymbols symbol = null; if (collapsingProp.Symbol != null) { // create formatted collapsing symbol symbol = new FormattedTextSymbols( _metrics._formatter.GlyphingCache, collapsingProp.Symbol, RightToLeft, TextFormatterImp.ToIdeal, _textFormattingMode, false ); constraintWidth -= symbol.Width; } Debug.Assert(_fullText != null); FullTextLine line = new TextMetrics.FullTextLine(_textFormattingMode, IsJustified); // collapsing preserves original line metrics Debug.Assert(_metrics._height > 0); line._metrics._formatter = _metrics._formatter; line._metrics._height = _metrics._height; line._metrics._baselineOffset = _metrics._baselineOffset; if (constraintWidth > 0) { // format main text line with constraint width int finiteFormatWidth = _fullText.TextStore.Settings.GetFiniteFormatWidth( TextFormatterImp.RealToIdeal(constraintWidth) ); bool forceWrap = _fullText.ForceWrap; _fullText.ForceWrap = true; if ((_statusFlags & StatusFlags.KeepState) != 0) { // inherit this flag so the collapsed line retains full text state too. line._statusFlags |= StatusFlags.KeepState; } line.FormatLine( _fullText, _cpFirst, 0, // no line length limit finiteFormatWidth, finiteFormatWidth, _paragraphWidth, // collapsed line is still bound to the original paragraph width (collapsingProp.Style == TextCollapsingStyle.TrailingCharacter ? LineFlags.BreakAlways : LineFlags.None), symbol ); _fullText.ForceWrap = forceWrap; line._metrics._cchDepend = 0; // no dependency } else if (symbol != null) { line.AppendCollapsingSymbol(symbol); } if (line._metrics._cchLength < Length) { line._collapsedRange = new TextCollapsedRange( _cpFirst + line._metrics._cchLength, Length - line._metrics._cchLength, Width - line.Width ); // collapsed line has the original length line._metrics._cchLength = Length; } // mark the indication flags signify collapsing line._statusFlags |= StatusFlags.HasCollapsed; line._statusFlags &= ~StatusFlags.HasOverflowed; return line; }
/// <summary> /// Client to collapse the line to fit for display /// </summary> /// <param name="collapsingPropertiesList">a list of collapsing properties</param> public override TextLine Collapse( params TextCollapsingProperties[] collapsingPropertiesList ) { if (!HasOverflowed) return this; Invariant.Assert(_settings != null); // instantiate a collapsible full text line, collapse it and return the collapsed line TextMetrics.FullTextLine textLine = new TextMetrics.FullTextLine( _settings, _cpFirst, 0, // lineLength TextFormatterImp.RealToIdeal(_paragraphWidth), LineFlags.None ); // When in TextFormattingMode.Display the math processing performed by SimpleTextLine // involves some rounding operations because of which the decision to collapse the text may // not be unanimous amongst SimpleTextLine and FullTextLine. There are several watson // crash reports that are testament to this theory. See Win8 PS bug# 643676. Hence we // now allow the case where FullTextLine concludes that it doesnt need to collapse the // text even though SimpleTextLine thought it should. if (textLine.HasOverflowed) { TextLine collapsedTextLine = textLine.Collapse(collapsingPropertiesList); if (collapsedTextLine != textLine) { // if collapsed line is genuinely new, // Dispose its maker as we no longer need it around, dispose it explicitly // to reduce unnecessary finalization of this intermediate line. textLine.Dispose(); } return collapsedTextLine; } return textLine; }
/// <summary> /// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content /// </summary> /// <param name="textSource">an object representing text layout clients text source for TextFormatter.</param> /// <param name="firstCharIndex">character index to specify where in the source text the line starts</param> /// <param name="paragraphProperties">properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.</param> /// <param name="textRunCache">an object representing content cache of the client.</param> /// <returns>min max paragraph width</returns> 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; }
/// <summary> /// Format and produce a text line either with or without previously known /// line break point. /// </summary> 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; }
/// <summary> /// Client to collapse the line to fit for display /// </summary> /// <param name="collapsingPropertiesList">a list of collapsing properties</param> public override TextLine Collapse( params TextCollapsingProperties[] collapsingPropertiesList ) { if (!HasOverflowed) return this; Invariant.Assert(_settings != null); // instantiate a collapsible full text line, collapse it and return the collapsed line TextMetrics.FullTextLine textLine = new TextMetrics.FullTextLine( _settings, _cpFirst, 0, // lineLength TextFormatterImp.RealToIdeal(_paragraphWidth), LineFlags.None ); Invariant.Assert(textLine.HasOverflowed); TextLine collapsedTextLine = textLine.Collapse(collapsingPropertiesList); if (collapsedTextLine != textLine) { // if collapsed line is genuinely new, // Dispose its maker as we no longer need it around, dispose it explicitly // to reduce unnecessary finalization of this intermediate line. textLine.Dispose(); } return collapsedTextLine; }