/// <summary> /// Paint this font run /// </summary> /// <param name="ctx"></param> internal void Paint(PaintTextContext ctx) { // Paint selection? if (ctx.PaintSelectionBackground != null) { float selStartXCoord; if (ctx.SelectionStart < Start) { selStartXCoord = Direction == TextDirection.LTR ? 0 : Width; } else if (ctx.SelectionStart >= End) { selStartXCoord = Direction == TextDirection.LTR ? Width : 0; } else { selStartXCoord = RelativeCodePointXCoords[ctx.SelectionStart - this.Start]; } float selEndXCoord; if (ctx.SelectionEnd < Start) { selEndXCoord = Direction == TextDirection.LTR ? 0 : Width; } else if (ctx.SelectionEnd >= End) { selEndXCoord = Direction == TextDirection.LTR ? Width : 0; } else { selEndXCoord = RelativeCodePointXCoords[ctx.SelectionEnd - this.Start]; } if (selStartXCoord != selEndXCoord) { var rect = new SKRect(this.XCoord + selStartXCoord, Line.YCoord, this.XCoord + selEndXCoord, Line.YCoord + Line.Height); ctx.Canvas.DrawRect(rect, ctx.PaintSelectionBackground); } } // Don't paint trailing whitespace runs if (RunKind == FontRunKind.TrailingWhitespace) { return; } // Text using (var paint = new SKPaint()) { // Work out font variant adjustments float glyphScale = 1; float glyphVOffset = 0; if (Style.FontVariant == FontVariant.SuperScript) { glyphScale = 0.65f; glyphVOffset = -Style.FontSize * 0.35f; } if (Style.FontVariant == FontVariant.SubScript) { glyphScale = 0.65f; glyphVOffset = Style.FontSize * 0.1f; } // Setup SKPaint paint.Color = Style.TextColor; paint.TextEncoding = SKTextEncoding.GlyphId; paint.Typeface = Typeface; paint.TextSize = Style.FontSize * glyphScale; paint.SubpixelText = true; paint.IsAntialias = ctx.Options.IsAntialias; paint.LcdRenderText = ctx.Options.LcdRenderText; unsafe { fixed(ushort *pGlyphs = Glyphs.Underlying) { // Get glyph positions var glyphPositions = GlyphPositions.ToArray(); // Paint underline if (Style.Underline != UnderlineStyle.None && RunKind == FontRunKind.Normal) { // Work out underline metrics paint.TextSize = Style.FontSize; float underlineYPos = Line.YCoord + Line.BaseLine + (paint.FontMetrics.UnderlinePosition ?? 0); paint.StrokeWidth = paint.FontMetrics.UnderlineThickness ?? 0; paint.TextSize = Style.FontSize * glyphScale; if (Style.Underline == UnderlineStyle.Gapped) { // Get intercept positions var interceptPositions = paint.GetPositionedTextIntercepts( (IntPtr)(pGlyphs + Glyphs.Start), Glyphs.Length * sizeof(ushort), glyphPositions, underlineYPos - paint.StrokeWidth / 2, underlineYPos + paint.StrokeWidth); // Paint gapped underlinline float x = XCoord; for (int i = 0; i < interceptPositions.Length; i += 2) { float b = interceptPositions[i] - paint.StrokeWidth; if (x < b) { ctx.Canvas.DrawLine(new SKPoint(x, underlineYPos), new SKPoint(b, underlineYPos), paint); } x = interceptPositions[i + 1] + paint.StrokeWidth; } if (x < XCoord + Width) { ctx.Canvas.DrawLine(new SKPoint(x, underlineYPos), new SKPoint(XCoord + Width, underlineYPos), paint); } } else { // Paint solid underline ctx.Canvas.DrawLine(new SKPoint(XCoord, underlineYPos), new SKPoint(XCoord + Width, underlineYPos), paint); } } // Draw the text ctx.Canvas.DrawPositionedText((IntPtr)(pGlyphs + Glyphs.Start), Glyphs.Length * sizeof(ushort), glyphPositions, paint); } } // Paint strikethrough if (Style.StrikeThrough != StrikeThroughStyle.None && RunKind == FontRunKind.Normal) { paint.StrokeWidth = paint.FontMetrics.StrikeoutThickness ?? 0; float strikeYPos = Line.YCoord + Line.BaseLine + (paint.FontMetrics.StrikeoutPosition ?? 0) + glyphVOffset; ctx.Canvas.DrawLine(new SKPoint(XCoord, strikeYPos), new SKPoint(XCoord + Width, strikeYPos), paint); } } }