internal Rect Draw( DrawingContext drawingContext, double x, double y, bool visiCodePath ) { if (Length <= 0 || this.Ghost) { return Rect.Empty; // nothing to draw } Brush foregroundBrush = TextRun.Properties.ForegroundBrush; if(visiCodePath && foregroundBrush is SolidColorBrush) { Color color = ((SolidColorBrush)foregroundBrush).Color; foregroundBrush = new SolidColorBrush(Color.FromArgb( (byte)(color.A>>2), // * 0.25 color.R, color.G, color.B )); } Rect inkBoundingBox; IList<double> displayGlyphAdvances; if (_textFormatterImp.TextFormattingMode == TextFormattingMode.Ideal) { displayGlyphAdvances = new ThousandthOfEmRealDoubles(EmSize, NominalAdvances.Length); for (int i = 0; i < displayGlyphAdvances.Count; i++) { // convert ideal glyph advance width to real width for displaying. displayGlyphAdvances[i] = _textFormatterImp.IdealToReal(NominalAdvances[i]); } } else { displayGlyphAdvances = new List<double>(NominalAdvances.Length); for (int i = 0; i < NominalAdvances.Length; i++) { // convert ideal glyph advance width to real width for displaying. displayGlyphAdvances.Add(_textFormatterImp.IdealToReal(NominalAdvances[i])); } } CharacterBufferRange charBufferRange = new CharacterBufferRange(CharBufferReference, Length); GlyphTypeface glyphTypeface = Typeface.TryGetGlyphTypeface(); Invariant.Assert(glyphTypeface != null); GlyphRun glyphRun = glyphTypeface.ComputeUnshapedGlyphRun( new Point(x, y), charBufferRange, displayGlyphAdvances, EmSize, TextRun.Properties.FontHintingEmSize, Typeface.NullFont, CultureMapper.GetSpecificCulture(TextRun.Properties.CultureInfo), null, // device font name _textFormatterImp.TextFormattingMode ); if (glyphRun != null) { inkBoundingBox = glyphRun.ComputeInkBoundingBox(); } else { inkBoundingBox = Rect.Empty; } if (!inkBoundingBox.IsEmpty) { // glyph run's ink bounding box is relative to its origin inkBoundingBox.X += glyphRun.BaselineOrigin.X; inkBoundingBox.Y += glyphRun.BaselineOrigin.Y; } if (drawingContext != null) { if (glyphRun != null) { glyphRun.EmitBackground(drawingContext, TextRun.Properties.BackgroundBrush); drawingContext.DrawGlyphRun(foregroundBrush, glyphRun); } // draw underline here if (Underline != null) { // Determine number of characters to underline. We don't underline trailing spaces // if the TrimTrailingUnderline flag is set. int underlineLength = Length; if (TrimTrailingUnderline) { while (underlineLength > 0 && IsSpace(charBufferRange[underlineLength - 1])) { --underlineLength; } } // Determine the width of the underline. double dxUnderline = 0; for (int i = 0; i < underlineLength; ++i) { dxUnderline += _textFormatterImp.IdealToReal(NominalAdvances[i]); } // We know only TextDecoration.Underline will be handled in Simple Path. double offset = -Typeface.UnderlinePosition * EmSize; double penThickness = Typeface.UnderlineThickness * EmSize; Point lineOrigin = new Point(x, y + offset); Rect underlineRect = new Rect( lineOrigin.X, lineOrigin.Y - penThickness * 0.5, dxUnderline, penThickness ); // Apply the pair of guidelines: one for baseline and another // for top edge of undelining line. Both will be snapped to pixel grid. // Guideline pairing algorithm detects the case when these two // guidelines happen to be close to one another and provides // synchronous snapping, so that the gap between baseline and // undelining line does not depend on the position of text line. drawingContext.PushGuidelineY2(y, lineOrigin.Y - penThickness * 0.5 - y); try { drawingContext.DrawRectangle( foregroundBrush, null, // pen underlineRect ); } finally { drawingContext.Pop(); } // underline pen thickness is always positive in fast path inkBoundingBox.Union( underlineRect ); } } return inkBoundingBox; }