From 69a422a540550d9ba19e1baccc7632f632fd1880 Mon Sep 17 00:00:00 2001 From: Tom Laird-McConnell Date: Sat, 2 Nov 2024 19:00:22 -0700 Subject: [PATCH 1/4] Fix strikethrough implementation Details: I didn't have a way of determing when strikethrough vs underline was happening. I finally figured a somewhat hacky but legit as far as I can tell way to signal underline and strikethrough, which is to use a large value of thickness in the font metric. Since we only support a thickness of 1 in a console app, this feels like a safe way to do it and shouldn't get in the way of anything. --- .../Drawing/DrawingContextImpl.cs | 155 +++++++++++------- .../PixelBufferImplementation/Pixel.cs | 12 +- src/Consolonia.Core/Text/GlyphTypeface.cs | 8 +- .../GalleryViews/GalleryTextBlock.axaml | 29 ++-- 4 files changed, 116 insertions(+), 88 deletions(-) diff --git a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs index b6b1d89..aa9ae9b 100644 --- a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs +++ b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs @@ -21,12 +21,14 @@ internal class DrawingContextImpl : IDrawingContextImpl private const byte HorizontalStartPattern = 0b0100; private const byte HorizontalLinePattern = 0b0101; private const byte HorizontalEndPattern = 0b0001; - private readonly Stack _clipStack = new(100); private readonly ConsoleWindow _consoleWindow; private readonly PixelBuffer _pixelBuffer; private readonly Matrix _postTransform = Matrix.Identity; private Matrix _transform = Matrix.Identity; + + public const int UnderlineThickness = 10; + public const int StrikthroughThickness = 11; public DrawingContextImpl(ConsoleWindow consoleWindow, PixelBuffer pixelBuffer) { @@ -68,20 +70,20 @@ public void DrawBitmap(IBitmapImpl source, double opacity, Rect sourceRect, Rect int width = bitmap.Info.Width; int height = bitmap.Info.Height; for (int x = 0; x < width; x++) - for (int y = 0; y < height; y++) - { - int px = (int)targetRect.TopLeft.X + x; - int py = (int)targetRect.TopLeft.Y + y; - SKColor skColor = bitmap.GetPixel(x, y); - Color color = Color.FromRgb(skColor.Red, skColor.Green, skColor.Blue); - var imagePixel = new Pixel('█', color); - CurrentClip.ExecuteWithClipping(new Point(px, py), - () => - { - _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py), - (existingPixel, _) => existingPixel.Blend(imagePixel), imagePixel.Background.Color); - }); - } + for (int y = 0; y < height; y++) + { + int px = (int)targetRect.TopLeft.X + x; + int py = (int)targetRect.TopLeft.Y + y; + SKColor skColor = bitmap.GetPixel(x, y); + Color color = Color.FromRgb(skColor.Red, skColor.Green, skColor.Blue); + var imagePixel = new Pixel('█', color); + CurrentClip.ExecuteWithClipping(new Point(px, py), + () => + { + _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py), + (existingPixel, _) => existingPixel.Blend(imagePixel), imagePixel.Background.Color); + }); + } } public void DrawBitmap(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) @@ -132,11 +134,11 @@ public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry) case VisualBrush: throw new NotImplementedException(); case ISceneBrush sceneBrush: - { - ISceneBrushContent sceneBrushContent = sceneBrush.CreateContent(); - if (sceneBrushContent != null) sceneBrushContent.Render(this, Matrix.Identity); - return; - } + { + ISceneBrushContent sceneBrushContent = sceneBrush.CreateContent(); + if (sceneBrushContent != null) sceneBrushContent.Render(this, Matrix.Identity); + return; + } } Rect r2 = r.TransformToAABB(Transform); @@ -144,19 +146,19 @@ public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry) double width = r2.Width + (pen?.Thickness ?? 0); double height = r2.Height + (pen?.Thickness ?? 0); for (int x = 0; x < width; x++) - for (int y = 0; y < height; y++) - { - int px = (int)(r2.TopLeft.X + x); - int py = (int)(r2.TopLeft.Y + y); - - ConsoleBrush backgroundBrush = ConsoleBrush.FromPosition(brush, x, y, (int)width, (int)height); - CurrentClip.ExecuteWithClipping(new Point(px, py), () => + for (int y = 0; y < height; y++) { - _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py), - (pixel, bb) => pixel.Blend(new Pixel(new PixelBackground(bb.Mode, bb.Color))), - backgroundBrush); - }); - } + int px = (int)(r2.TopLeft.X + x); + int py = (int)(r2.TopLeft.Y + y); + + ConsoleBrush backgroundBrush = ConsoleBrush.FromPosition(brush, x, y, (int)width, (int)height); + CurrentClip.ExecuteWithClipping(new Point(px, py), () => + { + _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py), + (pixel, bb) => pixel.Blend(new Pixel(new PixelBackground(bb.Mode, bb.Color))), + backgroundBrush); + }); + } } if (pen is null or { Thickness: 0 } @@ -288,6 +290,13 @@ private void DrawLineInternal(IPen pen, Line line) if (IfMoveConsoleCaretMove(pen, head)) return; + if (line.Vertical == false && pen.Thickness > 1) + { + // horizontal lines with thickness larger than one are text decorations + ApplyTextDecorationLineInternal(ref head, pen, line); + return; + } + var extractColorCheckPlatformSupported = ExtractColorOrNullWithPlatformCheck(pen, out var lineStyle); if (extractColorCheckPlatformSupported == null) return; @@ -298,6 +307,36 @@ private void DrawLineInternal(IPen pen, Line line) DrawPixelAndMoveHead(ref head, line, lineStyle, pattern, color, line.Length); //line } + private void ApplyTextDecorationLineInternal(ref Point head, IPen pen, Line line) + { + TextDecorationCollection textDecoration = pen.Thickness switch + { + UnderlineThickness => TextDecorations.Underline, + StrikthroughThickness => TextDecorations.Strikethrough, + }; + + for (int x = 0; x < line.Length; x++) + { + Point h = head; + CurrentClip.ExecuteWithClipping(h, () => + { + // ReSharper disable once AccessToModifiedClosure todo: pass as a parameter + _pixelBuffer.Set((PixelBufferCoordinate)h, + (pixel) => + { + var newPixelForeground = new PixelForeground(pixel.Foreground.Symbol, + pixel.Foreground.Weight, + pixel.Foreground.Style, + textDecoration, + pixel.Foreground.Color); + return pixel.Blend(new Pixel(newPixelForeground, pixel.Background)); + }); + }); + head = head.WithX(head.X + 1); + } + return; + } + /// /// Draw a rectangle line with corners /// @@ -372,7 +411,7 @@ private bool IfMoveConsoleCaretMove(IPen pen, Point head) if (pen is not { Brush: ConsoleBrush or LineBrush or ImmutableSolidColorBrush, - Thickness: 1, + // Thickness: 1, DashStyle: null or { Dashes: { Count: 0 } }, LineCap: PenLineCap.Flat, LineJoin: PenLineJoin.Miter @@ -454,43 +493,43 @@ private void DrawPixelAndMoveHead(ref Point head, Line line, LineStyle? lineStyl switch (c) { case '\t': - { - const int tabSize = 8; - var consolePixel = new Pixel(' ', foregroundColor); - for (int j = 0; j < tabSize; j++) { - Point newCharacterPoint = characterPoint.WithX(characterPoint.X + j); - CurrentClip.ExecuteWithClipping(newCharacterPoint, () => + const int tabSize = 8; + var consolePixel = new Pixel(' ', foregroundColor); + for (int j = 0; j < tabSize; j++) { - _pixelBuffer.Set((PixelBufferCoordinate)newCharacterPoint, - (oldPixel, cp) => oldPixel.Blend(cp), consolePixel); - }); + Point newCharacterPoint = characterPoint.WithX(characterPoint.X + j); + CurrentClip.ExecuteWithClipping(newCharacterPoint, () => + { + _pixelBuffer.Set((PixelBufferCoordinate)newCharacterPoint, + (oldPixel, cp) => oldPixel.Blend(cp), consolePixel); + }); + } + + currentXPosition += tabSize - 1; } - - currentXPosition += tabSize - 1; - } break; case '\n': - { - /* it's not clear if we need to draw anything. Cursor can be placed at the end of the line - var consolePixel = new Pixel(' ', foregroundColor); + { + /* it's not clear if we need to draw anything. Cursor can be placed at the end of the line + var consolePixel = new Pixel(' ', foregroundColor); - _pixelBuffer.Set((PixelBufferCoordinate)characterPoint, - (oldPixel, cp) => oldPixel.Blend(cp), consolePixel);*/ - } + _pixelBuffer.Set((PixelBufferCoordinate)characterPoint, + (oldPixel, cp) => oldPixel.Blend(cp), consolePixel);*/ + } break; case '\u200B': currentXPosition--; break; default: - { - var consolePixel = new Pixel(c, foregroundColor, typeface.Style, typeface.Weight); - CurrentClip.ExecuteWithClipping(characterPoint, () => { - _pixelBuffer.Set((PixelBufferCoordinate)characterPoint, - (oldPixel, cp) => oldPixel.Blend(cp), consolePixel); - }); - } + var consolePixel = new Pixel(c, foregroundColor, typeface.Style, typeface.Weight); + CurrentClip.ExecuteWithClipping(characterPoint, () => + { + _pixelBuffer.Set((PixelBufferCoordinate)characterPoint, + (oldPixel, cp) => oldPixel.Blend(cp), consolePixel); + }); + } break; } } diff --git a/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs b/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs index 25d289e..5262039 100644 --- a/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs +++ b/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs @@ -68,17 +68,7 @@ public Pixel Blend(Pixel pixelAbove) case PixelBackgroundMode.Colored: return pixelAbove; case PixelBackgroundMode.Transparent: - // when a textdecoration of underline happens a DrawLine() is called over the top of the a pixel with non-zero symbol. - // this detects this situation and eats the draw line, turning it into a textdecoration - if (pixelAbove.Foreground.Symbol is DrawingBoxSymbol && - Foreground.Symbol is SimpleSymbol simpleSymbol && - ((ISymbol)simpleSymbol).GetCharacter() != (char)0) - // this is a line being draw through text. add TextDecoration for underline. - newForeground = new PixelForeground(Foreground.Symbol, Foreground.Weight, Foreground.Style, - TextDecorations.Underline, Foreground.Color); - else - // do normal blend. - newForeground = Foreground.Blend(pixelAbove.Foreground); + newForeground = Foreground.Blend(pixelAbove.Foreground); newBackground = Background; break; case PixelBackgroundMode.Shaded: diff --git a/src/Consolonia.Core/Text/GlyphTypeface.cs b/src/Consolonia.Core/Text/GlyphTypeface.cs index 14b1680..0969aa4 100644 --- a/src/Consolonia.Core/Text/GlyphTypeface.cs +++ b/src/Consolonia.Core/Text/GlyphTypeface.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Avalonia.Media; +using Consolonia.Core.Drawing; namespace Consolonia.Core.Text { @@ -73,11 +74,10 @@ public bool TryGetTable(uint tag, out byte[] table) Ascent = -1, //var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale; //todo: need to consult Avalonia guys Descent = 0, LineGap = 0, - UnderlinePosition = - -1, // this turns on TextDecorations="Underline", -1 is so it draws over the top of the text. - UnderlineThickness = 1, // this is the thickness of the underline, aka 1 char thick. + UnderlinePosition = -1, + UnderlineThickness = DrawingContextImpl.UnderlineThickness, StrikethroughPosition = -1, - StrikethroughThickness = 1, + StrikethroughThickness = DrawingContextImpl.StrikthroughThickness, IsFixedPitch = true }; diff --git a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml index eed9e19..a0f44c5 100644 --- a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml +++ b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml @@ -30,21 +30,20 @@ Text="Multiline TextBlock with TextWrapping. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." /> - - - - - - - - - - - - - - - + + + + + + + + + + + + + + From 416520e01ffd00ab1caee41c1d6e92d6a3ce3eb8 Mon Sep 17 00:00:00 2001 From: Tom Laird-McConnell Date: Sat, 2 Nov 2024 19:04:16 -0700 Subject: [PATCH 2/4] add default to switch with exception --- src/Consolonia.Core/Drawing/DrawingContextImpl.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs index aa9ae9b..0ad35ab 100644 --- a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs +++ b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs @@ -313,6 +313,7 @@ private void ApplyTextDecorationLineInternal(ref Point head, IPen pen, Line line { UnderlineThickness => TextDecorations.Underline, StrikthroughThickness => TextDecorations.Strikethrough, + _ => throw new ArgumentOutOfRangeException($"Unsupported thickness {pen.Thickness}") }; for (int x = 0; x < line.Length; x++) From 264c9864fa21b9e3acc1d9e61550c3b951aac056 Mon Sep 17 00:00:00 2001 From: Tom Laird-McConnell Date: Sat, 2 Nov 2024 19:09:34 -0700 Subject: [PATCH 3/4] fix lint issue --- src/Consolonia.Core/Drawing/DrawingContextImpl.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs index 0ad35ab..5cdf0e9 100644 --- a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs +++ b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs @@ -335,7 +335,6 @@ private void ApplyTextDecorationLineInternal(ref Point head, IPen pen, Line line }); head = head.WithX(head.X + 1); } - return; } /// From 3ceb3627c161f531e63e0ae4437103eb1af30f85 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 02:12:20 +0000 Subject: [PATCH 4/4] Automated JetBrains cleanup Co-authored-by: <+@users.noreply.github.com> --- .../Drawing/DrawingContextImpl.cs | 128 +++++++++--------- src/Consolonia.Core/Text/GlyphTypeface.cs | 4 +- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs index 5cdf0e9..28f2f37 100644 --- a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs +++ b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs @@ -21,14 +21,14 @@ internal class DrawingContextImpl : IDrawingContextImpl private const byte HorizontalStartPattern = 0b0100; private const byte HorizontalLinePattern = 0b0101; private const byte HorizontalEndPattern = 0b0001; + + public const int UnderlineThickness = 10; + public const int StrikthroughThickness = 11; private readonly Stack _clipStack = new(100); private readonly ConsoleWindow _consoleWindow; private readonly PixelBuffer _pixelBuffer; private readonly Matrix _postTransform = Matrix.Identity; private Matrix _transform = Matrix.Identity; - - public const int UnderlineThickness = 10; - public const int StrikthroughThickness = 11; public DrawingContextImpl(ConsoleWindow consoleWindow, PixelBuffer pixelBuffer) { @@ -70,20 +70,20 @@ public void DrawBitmap(IBitmapImpl source, double opacity, Rect sourceRect, Rect int width = bitmap.Info.Width; int height = bitmap.Info.Height; for (int x = 0; x < width; x++) - for (int y = 0; y < height; y++) - { - int px = (int)targetRect.TopLeft.X + x; - int py = (int)targetRect.TopLeft.Y + y; - SKColor skColor = bitmap.GetPixel(x, y); - Color color = Color.FromRgb(skColor.Red, skColor.Green, skColor.Blue); - var imagePixel = new Pixel('█', color); - CurrentClip.ExecuteWithClipping(new Point(px, py), - () => - { - _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py), - (existingPixel, _) => existingPixel.Blend(imagePixel), imagePixel.Background.Color); - }); - } + for (int y = 0; y < height; y++) + { + int px = (int)targetRect.TopLeft.X + x; + int py = (int)targetRect.TopLeft.Y + y; + SKColor skColor = bitmap.GetPixel(x, y); + Color color = Color.FromRgb(skColor.Red, skColor.Green, skColor.Blue); + var imagePixel = new Pixel('█', color); + CurrentClip.ExecuteWithClipping(new Point(px, py), + () => + { + _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py), + (existingPixel, _) => existingPixel.Blend(imagePixel), imagePixel.Background.Color); + }); + } } public void DrawBitmap(IBitmapImpl source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) @@ -134,11 +134,11 @@ public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry) case VisualBrush: throw new NotImplementedException(); case ISceneBrush sceneBrush: - { - ISceneBrushContent sceneBrushContent = sceneBrush.CreateContent(); - if (sceneBrushContent != null) sceneBrushContent.Render(this, Matrix.Identity); - return; - } + { + ISceneBrushContent sceneBrushContent = sceneBrush.CreateContent(); + if (sceneBrushContent != null) sceneBrushContent.Render(this, Matrix.Identity); + return; + } } Rect r2 = r.TransformToAABB(Transform); @@ -146,19 +146,19 @@ public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry) double width = r2.Width + (pen?.Thickness ?? 0); double height = r2.Height + (pen?.Thickness ?? 0); for (int x = 0; x < width; x++) - for (int y = 0; y < height; y++) - { - int px = (int)(r2.TopLeft.X + x); - int py = (int)(r2.TopLeft.Y + y); + for (int y = 0; y < height; y++) + { + int px = (int)(r2.TopLeft.X + x); + int py = (int)(r2.TopLeft.Y + y); - ConsoleBrush backgroundBrush = ConsoleBrush.FromPosition(brush, x, y, (int)width, (int)height); - CurrentClip.ExecuteWithClipping(new Point(px, py), () => - { - _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py), - (pixel, bb) => pixel.Blend(new Pixel(new PixelBackground(bb.Mode, bb.Color))), - backgroundBrush); - }); - } + ConsoleBrush backgroundBrush = ConsoleBrush.FromPosition(brush, x, y, (int)width, (int)height); + CurrentClip.ExecuteWithClipping(new Point(px, py), () => + { + _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py), + (pixel, bb) => pixel.Blend(new Pixel(new PixelBackground(bb.Mode, bb.Color))), + backgroundBrush); + }); + } } if (pen is null or { Thickness: 0 } @@ -323,13 +323,13 @@ private void ApplyTextDecorationLineInternal(ref Point head, IPen pen, Line line { // ReSharper disable once AccessToModifiedClosure todo: pass as a parameter _pixelBuffer.Set((PixelBufferCoordinate)h, - (pixel) => + pixel => { var newPixelForeground = new PixelForeground(pixel.Foreground.Symbol, - pixel.Foreground.Weight, - pixel.Foreground.Style, - textDecoration, - pixel.Foreground.Color); + pixel.Foreground.Weight, + pixel.Foreground.Style, + textDecoration, + pixel.Foreground.Color); return pixel.Blend(new Pixel(newPixelForeground, pixel.Background)); }); }); @@ -493,43 +493,43 @@ private void DrawPixelAndMoveHead(ref Point head, Line line, LineStyle? lineStyl switch (c) { case '\t': + { + const int tabSize = 8; + var consolePixel = new Pixel(' ', foregroundColor); + for (int j = 0; j < tabSize; j++) { - const int tabSize = 8; - var consolePixel = new Pixel(' ', foregroundColor); - for (int j = 0; j < tabSize; j++) + Point newCharacterPoint = characterPoint.WithX(characterPoint.X + j); + CurrentClip.ExecuteWithClipping(newCharacterPoint, () => { - Point newCharacterPoint = characterPoint.WithX(characterPoint.X + j); - CurrentClip.ExecuteWithClipping(newCharacterPoint, () => - { - _pixelBuffer.Set((PixelBufferCoordinate)newCharacterPoint, - (oldPixel, cp) => oldPixel.Blend(cp), consolePixel); - }); - } - - currentXPosition += tabSize - 1; + _pixelBuffer.Set((PixelBufferCoordinate)newCharacterPoint, + (oldPixel, cp) => oldPixel.Blend(cp), consolePixel); + }); } + + currentXPosition += tabSize - 1; + } break; case '\n': - { - /* it's not clear if we need to draw anything. Cursor can be placed at the end of the line - var consolePixel = new Pixel(' ', foregroundColor); + { + /* it's not clear if we need to draw anything. Cursor can be placed at the end of the line + var consolePixel = new Pixel(' ', foregroundColor); - _pixelBuffer.Set((PixelBufferCoordinate)characterPoint, - (oldPixel, cp) => oldPixel.Blend(cp), consolePixel);*/ - } + _pixelBuffer.Set((PixelBufferCoordinate)characterPoint, + (oldPixel, cp) => oldPixel.Blend(cp), consolePixel);*/ + } break; case '\u200B': currentXPosition--; break; default: + { + var consolePixel = new Pixel(c, foregroundColor, typeface.Style, typeface.Weight); + CurrentClip.ExecuteWithClipping(characterPoint, () => { - var consolePixel = new Pixel(c, foregroundColor, typeface.Style, typeface.Weight); - CurrentClip.ExecuteWithClipping(characterPoint, () => - { - _pixelBuffer.Set((PixelBufferCoordinate)characterPoint, - (oldPixel, cp) => oldPixel.Blend(cp), consolePixel); - }); - } + _pixelBuffer.Set((PixelBufferCoordinate)characterPoint, + (oldPixel, cp) => oldPixel.Blend(cp), consolePixel); + }); + } break; } } diff --git a/src/Consolonia.Core/Text/GlyphTypeface.cs b/src/Consolonia.Core/Text/GlyphTypeface.cs index 0969aa4..6ce98a9 100644 --- a/src/Consolonia.Core/Text/GlyphTypeface.cs +++ b/src/Consolonia.Core/Text/GlyphTypeface.cs @@ -75,9 +75,9 @@ public bool TryGetTable(uint tag, out byte[] table) Descent = 0, LineGap = 0, UnderlinePosition = -1, - UnderlineThickness = DrawingContextImpl.UnderlineThickness, + UnderlineThickness = DrawingContextImpl.UnderlineThickness, StrikethroughPosition = -1, - StrikethroughThickness = DrawingContextImpl.StrikthroughThickness, + StrikethroughThickness = DrawingContextImpl.StrikthroughThickness, IsFixedPitch = true };