19 using System.Collections.Generic;
24 internal abstract class LineFragment
26 public abstract void Translate(
double deltaX,
double deltaY);
27 public string Tag {
get;
protected set; }
30 internal class TextFragment : LineFragment
32 public string Text {
get; }
33 public Point Position {
get;
private set; }
34 public Font Font {
get; }
35 public Colour Colour {
get; }
37 public TextFragment(Point position,
string text, Font font, Colour colour,
string tag)
39 this.Position = position;
46 public override void Translate(
double deltaX,
double deltaY)
48 this.Position =
new Point(this.Position.X + deltaX,
this.Position.Y + deltaY);
52 internal class UnderlineFragment : LineFragment
54 public Point Start {
get;
private set; }
55 public Point End {
get;
private set; }
56 public Colour Colour {
get; }
57 public double Thickness {
get; }
59 public UnderlineFragment(Point start, Point end, Colour colour,
double thickness,
string tag)
64 this.Thickness = thickness;
68 public override void Translate(
double deltaX,
double deltaY)
70 this.Start =
new Point(this.Start.X + deltaX,
this.Start.Y + deltaY);
71 this.End =
new Point(this.End.X + deltaX,
this.End.Y + deltaY);
75 internal class RectangleFragment : LineFragment
77 public Point TopLeft {
get;
private set; }
78 public Size Size {
get; }
79 public Colour Colour {
get; }
81 public RectangleFragment(Point topLeft, Size size, Colour colour,
string tag)
83 this.TopLeft = topLeft;
89 public override void Translate(
double deltaX,
double deltaY)
91 this.TopLeft =
new Point(this.TopLeft.X + deltaX,
this.TopLeft.Y + deltaY);
95 internal class GraphicsFragment : LineFragment
97 public Point Origin {
get;
private set; }
98 public Graphics Graphics {
get; }
99 public double Ascent {
get; }
101 public GraphicsFragment(Point origin, Graphics graphics,
double ascent)
103 this.Origin = origin;
104 this.Graphics = graphics;
105 this.Ascent = ascent;
108 public override void Translate(
double deltaX,
double deltaY)
110 this.Origin =
new Point(this.Origin.X + deltaX,
this.Origin.Y + deltaY);
116 public List<LineFragment> Fragments {
get; }
117 public double InitialAscent {
get; }
119 public Line(
double initialAscent)
121 this.InitialAscent = initialAscent;
122 this.Fragments =
new List<LineFragment>();
125 public void Render(ref Graphics graphics, ref MarkdownContext context, MarkdownRenderer.NewPageAction newPageAction,
double pageMaxY)
130 foreach (LineFragment fragment
in this.Fragments)
132 if (fragment is TextFragment text)
134 deltaY = Math.Max(deltaY, text.Font.Ascent -
this.InitialAscent);
135 maxY = Math.Max(maxY, text.Position.Y - text.Font.Descent);
137 else if (fragment is UnderlineFragment underline)
139 maxY = Math.Max(maxY, Math.Max(underline.Start.Y, underline.End.Y));
141 else if (fragment is RectangleFragment rectangle)
143 maxY = Math.Max(maxY, rectangle.TopLeft.Y + rectangle.Size.Height);
145 else if (fragment is GraphicsFragment graphicsFragment)
147 deltaY = Math.Max(deltaY, graphicsFragment.Ascent -
this.InitialAscent);
148 maxY = Math.Max(maxY, graphicsFragment.Origin.Y);
156 double currCursY = context.Cursor.Y;
158 newPageAction(ref context, ref graphics);
160 double currDelta = deltaY;
162 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y +
this.InitialAscent + currDelta);
164 deltaY -= currCursY - context.Cursor.Y + currDelta;
166 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y);
170 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y + deltaY);
174 for (
int i = 0; i < this.Fragments.Count; i++)
176 LineFragment fragment = this.Fragments[i];
177 if (fragment is TextFragment text)
179 Size size = text.Font.MeasureText(text.Text);
180 context.BottomRight =
new Point(Math.Max(context.BottomRight.X, size.Width + text.Position.X + context.Translation.X), Math.Max(context.BottomRight.Y, text.Position.Y + size.Height + deltaY + context.Translation.Y));
181 graphics.FillText(text.Position.X, text.Position.Y + deltaY, text.Text, text.Font, text.Colour,
TextBaselines.Baseline, tag: fragment.Tag);
183 else if (fragment is UnderlineFragment underline)
185 graphics.StrokePath(
new GraphicsPath().MoveTo(underline.Start.X, underline.Start.Y + deltaY).LineTo(underline.End.X, underline.End.Y + deltaY), underline.Colour, underline.Thickness, tag: fragment.Tag);
187 else if (fragment is RectangleFragment rectangle)
189 graphics.FillRectangle(rectangle.TopLeft.X, rectangle.TopLeft.Y + deltaY, rectangle.Size.Width, rectangle.Size.Height, rectangle.Colour, tag: fragment.Tag);
191 else if (fragment is GraphicsFragment graphicsFragment)
193 graphics.DrawGraphics(graphicsFragment.Origin.X, graphicsFragment.Origin.Y + deltaY, graphicsFragment.Graphics);