/// <summary> /// Populates text measures. If you use a shared textShaper, call this before GetSpans, or GetLines. /// </summary> public void LoadMeasures(TextShaper textShaper = null) { if (textShaper == null) { textShaper = new TextShaper(false); } if (GlyphSpan == null) { GlyphSpan = textShaper.GetGlyphSpan(Font, Text); var fontMetrics = GlyphSpan.Paints[0].FontMetrics; FontHeight = fontMetrics.CapHeight; if (Font.LineHeight.HasValue) { LineHeight = Font.LineHeight.Value; } else { LineHeight = (fontMetrics.Descent - fontMetrics.Ascent + fontMetrics.Leading) * LineSpacing; } MarginY = (LineHeight - FontHeight) / 2; } if (LineBreakMode == LineBreakMode.MiddleTruncation) { if (EllipsisGlyphSpan == null) { EllipsisGlyphSpan = textShaper.GetGlyphSpan(Font, " … "); } } }
/// <summary> /// Measure this text block, given supplied maximum width /// </summary> /// <param name="textShaper">Text Shaper (measurement cache) to use, or null if measurements shouldn't be cached in memory</param> public SKSize Measure(float maxwidth, TextShaper textShaper = null) { float width = 0; LoadMeasures(textShaper); if (LineBreakMode == LineBreakMode.MiddleTruncation) { var spans = GetSpans(maxwidth); foreach (var span in spans) { width += span.width; } return(new SKSize(width, LineHeight)); } else { var lines = GetLines(maxwidth); foreach (var line in lines) { if (width < line.width) { width = line.width; } } return(new SKSize(width, lines.Count * LineHeight)); } }
private SKRect Layout(SKCanvas canvas, SKRect rect, FlowDirection flowDirection, TextShaper textShaper) { var width = rect.Width; var line = new List <(RichTextSpan span, MeasuredSpan wordspan)>(); var linewidth = 0.0f; var linefontheight = 0f; var linemarginy = 0f; var maxlinewidth = 0.0f; var y = rect.Top; if (Spans != null) { // calculate maximum font dimensions foreach (var span in Spans) { if (span != null) { var(fontheight, marginy) = span.GetMeasures(textShaper); if (linefontheight < fontheight) { linefontheight = fontheight; } if (linemarginy < marginy) { linemarginy = marginy; } } } y += linefontheight + linemarginy; // draw all text blocks in succession foreach (var span in Spans) { if (span != null) { var childlines = span.GetLines(width, linewidth, false); if (childlines != null) { var childlinecount = childlines.Count; for (var i = 0; i < childlinecount; i++) { var wordspan = childlines[i]; line.Add((span, wordspan)); linewidth += wordspan.width; if (maxlinewidth < linewidth) { maxlinewidth = linewidth; } if (i != childlinecount - 1) { LayoutLine(); } } } } } if (line.Count > 0) { LayoutLine(); } y -= linefontheight + linemarginy; } if (flowDirection == FlowDirection.Unknown || flowDirection == FlowDirection.LeftToRight) { return(new SKRect(rect.Left, rect.Top, rect.Left + maxlinewidth + floatroundingmargin, y)); } else { return(new SKRect(rect.Right - maxlinewidth - floatroundingmargin, rect.Top, rect.Right, y)); } void LayoutLine() { if (canvas != null) { if (flowDirection == FlowDirection.LeftToRight) { var x = rect.Left; foreach (var chunk in line) { if (PixelRounding) { x = (float)Math.Round(x); } var span = chunk.span; var spanwidth = chunk.wordspan.width; // draw the span span.DrawMeasuredSpan(canvas, x, y, linefontheight, linemarginy, chunk.wordspan, false); #if DEBUGCONTAINER var paintrect = new SKRect(x + t.X, y - text.FontHeight - text.MarginY + t.Y, x + spanwidth + t.X, y + text.MarginY + t.Y); using (var borderpaint = new SKPaint() { Color = SKColors.Orange.WithAlpha(64), IsStroke = true }) canvas.DrawRect(paintrect, borderpaint); #endif x += spanwidth; } } else { var x = rect.Right; foreach (var chunk in line) { var span = chunk.span; var spanwidth = chunk.wordspan.width; if (PixelRounding) { x = (float)Math.Round(x); } x -= spanwidth; // draw the span span.DrawMeasuredSpan(canvas, x, y, linefontheight, linemarginy, chunk.wordspan, true); #if DEBUGCONTAINER var paintrect = new SKRect(x - t.X, y - text.FontHeight - text.MarginY + t.Y, x + spanwidth - t.X, y + text.MarginY + t.Y); using (var borderpaint = new SKPaint() { Color = SKColors.Orange.WithAlpha(64), IsStroke = true }) canvas.DrawRect(paintrect, borderpaint); #endif } } } linewidth = 0; y += linefontheight + linemarginy * 2; line.Clear(); } }
/// <summary> /// Paint's the rich text in the provided rectangle /// </summary> /// <returns>a rect containing the actual bottom of painted text</returns> public SKRect Paint(SKCanvas canvas, SKRect rect, FlowDirection flowDirection = FlowDirection.LeftToRight, TextShaper textShaper = null) { return(Layout(canvas, rect, flowDirection, textShaper)); }
/// <summary> /// Measures the Rich Text, given the maximum width /// </summary> /// <param name="maxWidth"></param> /// <param name="textShaper"></param> /// <returns></returns> public SKSize Measure(float maxWidth, TextShaper textShaper = null) { var calculated = Layout(null, new SKRect(0, 0, maxWidth, float.MaxValue), FlowDirection.LeftToRight, textShaper ?? new TextShaper(false)); return(new SKSize(calculated.Width, calculated.Height)); }
public SKRect Draw(SKCanvas canvas, SKRect rect, TextShaper textShaper = null, FlowDirection flowDirection = FlowDirection.LeftToRight) { LoadMeasures(textShaper); var y = rect.Top + FontHeight + MarginY; if (LineBreakMode == LineBreakMode.MiddleTruncation) { var spans = GetSpans(rect.Width); if (flowDirection == FlowDirection.LeftToRight) { var x = rect.Left; if (spans.Count > 0) { canvas.DrawGlyphSpan(GlyphSpan, x, y, Color, spans[0]); x += spans[0].width; } if (spans.Count > 1) { canvas.DrawGlyphSpan(EllipsisGlyphSpan, x, y, Color, spans[1]); x += spans[1].width; } if (spans.Count > 2) { canvas.DrawGlyphSpan(GlyphSpan, x, y, Color, spans[2]); } } else { var x = rect.Right; if (spans.Count > 0) { x -= spans[0].width; canvas.DrawGlyphSpan(GlyphSpan, x, y, Color, spans[0]); } if (spans.Count > 1) { x -= spans[1].width; canvas.DrawGlyphSpan(EllipsisGlyphSpan, x, y, Color, spans[1]); } if (spans.Count > 2) { x -= spans[2].width; canvas.DrawGlyphSpan(GlyphSpan, x, y, Color, spans[2]); } } y += LineHeight; } else { var lines = GetLines(rect.Width); var i = 0; foreach (var line in lines) { if (GetLineColor != null) { Color = GetLineColor(i++, lines.Count); } if (LineBreakMode == LineBreakMode.WordWrap) { float x; if (flowDirection == FlowDirection.LeftToRight) { x = rect.Left; } else { x = rect.Right - line.width; } canvas.DrawGlyphSpan(GlyphSpan, x, y, Color, line, GlyphAnimation); } else if (LineBreakMode == LineBreakMode.Center) { var x = rect.Left + (rect.Width - line.width) / 2; canvas.DrawGlyphSpan(GlyphSpan, x, y, Color, line, GlyphAnimation); } y += LineHeight; } } var paintrect = new SKRect(rect.Left, rect.Top, rect.Right, y - LineHeight + MarginY); #if DEBUGCONTAINER if (canvas != null) { using (var borderpaint = new SKPaint() { Color = SKColors.Red.WithAlpha(64), IsStroke = true }) canvas.DrawRect(paintrect, borderpaint); } #endif return(paintrect); }
/// <summary> /// Draw a block of text on the canvas. /// </summary> /// <returns>The bounds of the painted text. Note that the returned rectangle's Width is equal to the input (IE only bottom is calculated). Use TextBlock.Measure to get text bounds</returns> public static SKRect DrawRichTextBlock(this SKCanvas canvas, RichTextBlock text, SKRect rect, TextShaper textShaper = null, FlowDirection flowDirection = FlowDirection.LeftToRight) { return(text.Paint(canvas, rect, flowDirection, textShaper)); }
/// <summary> /// Draw a block of text on the canvas. /// </summary> /// <returns>The bounds of the painted text. Note that the returned rectangle's Width is equal to the input (IE only bottom is calculated). Use TextBlock.Measure to get text bounds</returns> public static SKRect DrawTextBlock(this SKCanvas canvas, TextBlock text, SKRect rect, TextShaper textShaper = null, FlowDirection flowDirection = FlowDirection.LeftToRight) { return(text.Draw(canvas, rect, textShaper, flowDirection)); }
/// <summary> /// Draw a text block /// </summary> public static SKRect DrawTextBlock(this SKCanvas canvas, string text, SKRect rect, Font font, SKColor color, TextShaper textShaper = null) { var textblock = new TextBlock(font, color, text); return(DrawTextBlock(canvas, textblock, rect, textShaper)); }