19 using Markdig.Extensions;
20 using Markdig.Extensions.Tables;
21 using Markdig.Helpers;
22 using Markdig.Renderers.Html;
24 using Markdig.Syntax.Inlines;
26 using System.Collections.Generic;
47 28 / 12.0, 22 / 12.0, 16 / 12.0, 14 / 12.0, 13 / 12.0, 12 / 12.0
265 public List<Action<Graphics, Colour>>
Bullets {
get; } =
new List<Action<Graphics, Colour>>()
267 (graphics, colour) =>
269 graphics.FillPath(
new GraphicsPath().
Arc(-0.5, 0, 0.25, 0, 2 * Math.PI), colour);
272 (graphics, colour) =>
274 graphics.StrokePath(
new GraphicsPath().
Arc(-0.5, 0, 0.25, 0, 2 * Math.PI), colour, 0.1);
277 (graphics, colour) =>
279 graphics.StrokeRectangle(-0.75, -0.25, 0.5, 0.5, colour, 0.1);
365 GraphicsPath checkboxPath =
new GraphicsPath().
MoveTo(-0.7, -0.4).
LineTo(-0.3, -0.4).
Arc(-0.3, -0.2, 0.2, 3 * Math.PI / 2, 2 * Math.PI).
LineTo(-0.1, 0.2).
Arc(-0.3, 0.2, 0.2, 0, Math.PI / 2).
LineTo(-0.7, 0.4).
Arc(-0.7, 0.2, 0.2, Math.PI / 2, Math.PI).
LineTo(-0.9, -0.2).
Arc(-0.7, -0.2, 0.2, Math.PI, 3 * Math.PI / 2).
Close();
380 GraphicsPath checkboxPath =
new GraphicsPath().
MoveTo(-0.7, -0.4).
LineTo(-0.3, -0.4).
Arc(-0.3, -0.2, 0.2, 3 * Math.PI / 2, 2 * Math.PI).
LineTo(-0.1, 0.2).
Arc(-0.3, 0.2, 0.2, 0, Math.PI / 2).
LineTo(-0.7, 0.4).
Arc(-0.7, 0.2, 0.2, Math.PI / 2, Math.PI).
LineTo(-0.9, -0.2).
Arc(-0.7, -0.2, 0.2, Math.PI, 3 * Math.PI / 2).
Close();
409 public Page RenderSinglePage(
string markdownSource,
double width, out Dictionary<string, string> linkDestinations)
411 MarkdownDocument document = Markdig.Markdown.Parse(markdownSource,
new MarkdownPipelineBuilder().UseGridTables().UsePipeTables().UseEmphasisExtras().UseGenericAttributes().UseAutoIdentifiers().UseAutoLinks().UseTaskLists().UseListExtras().UseCitations().UseMathematics().UseSmartyPants().Build());
423 public Page RenderSinglePage(MarkdownDocument markdownDocument,
double width, out Dictionary<string, string> linkDestinations)
428 this.
PageSize =
new Size(width,
double.PositiveInfinity);
439 void newPageAction(ref MarkdownContext mdContext, ref
Graphics pageGraphics)
444 MarkdownContext context =
new MarkdownContext()
447 Cursor =
new Point(0, 0),
457 foreach (Block block
in markdownDocument)
459 RenderBlock(block, ref context, ref graphics, newPageAction, index > 0, index < markdownDocument.Count - 1);
463 if (context.CurrentLine !=
null)
465 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
470 pag.Crop(
new Point(0, 0),
new Size(width, context.BottomRight.Y +
this.Margins.Bottom));
472 linkDestinations = context.LinkDestinations;
482 public Document Render(
string markdownSource, out Dictionary<string, string> linkDestinations)
484 MarkdownDocument document = Markdig.Markdown.Parse(markdownSource,
new MarkdownPipelineBuilder().UseGridTables().UsePipeTables().UseEmphasisExtras().UseGenericAttributes().UseAutoIdentifiers().UseAutoLinks().UseTaskLists().UseListExtras().UseCitations().UseMathematics().UseSmartyPants().Build());
486 return this.
Render(document, out linkDestinations);
495 public Document Render(MarkdownDocument mardownDocument, out Dictionary<string, string> linkDestinations)
505 void newPageAction(ref MarkdownContext mdContext, ref
Graphics pageGraphics)
508 doc.
Pages.Add(newPag);
511 mdContext.Cursor =
new Point(0, 0);
512 mdContext.ForbiddenAreasLeft.Clear();
513 mdContext.ForbiddenAreasRight.Clear();
516 mdContext.CurrentPage = newPag;
519 MarkdownContext context =
new MarkdownContext()
522 Cursor =
new Point(0, 0),
533 foreach (Block block
in mardownDocument)
535 RenderBlock(block, ref context, ref graphics, newPageAction, index > 0, index < mardownDocument.Count - 1);
539 if (context.CurrentLine !=
null)
541 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
544 linkDestinations = context.LinkDestinations;
549 private Document RenderSubDocument(ContainerBlock document, ref MarkdownContext context)
561 void newPageAction(ref MarkdownContext mdContext, ref
Graphics pageGraphics)
563 pageGraphics.Restore();
565 doc.
Pages.Add(newPag);
569 mdContext.Cursor =
new Point(0, 0);
570 mdContext.ForbiddenAreasLeft.Clear();
571 mdContext.ForbiddenAreasRight.Clear();
574 mdContext.CurrentPage = newPag;
577 context.Translation =
new Point(context.Translation.X +
Margins.
Left, context.Translation.Y +
Margins.
Top);
578 context.CurrentPage = pag;
579 context.ListDepth = 0;
582 foreach (Block block
in document)
584 RenderBlock(block, ref context, ref graphics, newPageAction, index > 0, index < document.Count - 1);
588 if (context.CurrentLine !=
null)
590 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
598 internal delegate
void NewPageAction(ref MarkdownContext context, ref Graphics graphics);
600 private void RenderBlock(Block block, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction,
bool spaceBefore,
bool spaceAfter)
602 HtmlAttributes attributes = block.TryGetAttributes();
604 if (attributes !=
null && !
string.IsNullOrEmpty(attributes.Id))
606 Point cursor = context.Cursor;
607 NewPageAction reversibleNewPageAction = (ref MarkdownContext currContext, ref Graphics currGraphics) =>
609 newPageAction(ref currContext, ref currGraphics);
610 cursor = currContext.Cursor;
613 RenderHTMLBlock(
"<a name=\"" + attributes.Id +
"\"></a>",
false, ref context, ref graphics, reversibleNewPageAction, spaceBefore, spaceAfter);
614 context.Cursor = cursor;
617 if (block is LeafBlock leaf)
619 if (leaf is HeadingBlock heading)
621 RenderHeadingBlock(heading, ref context, ref graphics, newPageAction, spaceBefore, spaceAfter);
623 else if (leaf is ParagraphBlock paragraph)
625 RenderParagraphBlock(paragraph, ref context, ref graphics, newPageAction, spaceBefore, spaceAfter);
627 else if (leaf is CodeBlock code)
629 if (block is Markdig.Extensions.Mathematics.MathBlock math)
631 StringBuilder mathBuilder =
new StringBuilder();
632 foreach (StringLine line
in math.Lines)
634 mathBuilder.Append(line.ToString());
635 mathBuilder.Append(
"\n");
638 string imageUri =
"https://render.githubusercontent.com/render/math?math=" + System.Web.HttpUtility.UrlEncode(mathBuilder.ToString());
640 RenderHTMLBlock(
"<img src=\"" + imageUri +
"\">",
false, ref context, ref graphics, newPageAction,
true,
true);
642 else if (leaf is FencedCodeBlock fenced)
644 if (!
string.IsNullOrEmpty(fenced.Info))
646 RenderFencedCodeBlock(fenced, ref context, ref graphics, newPageAction, spaceBefore, spaceAfter);
650 RenderCodeBlock(code, ref context, ref graphics, newPageAction, spaceBefore, spaceAfter);
656 RenderCodeBlock(code, ref context, ref graphics, newPageAction, spaceBefore, spaceAfter);
659 else if (leaf is HtmlBlock html)
661 RenderHTMLBlock(html.Lines.ToString(),
false, ref context, ref graphics, newPageAction, spaceBefore, spaceAfter);
663 else if (leaf is ThematicBreakBlock thematicBreak)
665 RenderThematicBreakBlock(thematicBreak, ref context, ref graphics, newPageAction, spaceBefore, spaceAfter);
667 else if (leaf is LinkReferenceDefinition link)
673 else if (block is ContainerBlock)
675 if (block is ListBlock list)
677 RenderListBlock(list, ref context, ref graphics, newPageAction);
679 else if (block is ListItemBlock listItem)
681 RenderListItemBlock(listItem, ref context, ref graphics, newPageAction);
683 else if (block is QuoteBlock quote)
685 RenderQuoteBlock(quote, ref context, ref graphics, newPageAction);
687 else if (block is LinkReferenceDefinitionGroup linkGroup)
691 else if (block is Table table)
693 RenderTable(table, ref context, ref graphics, newPageAction);
696 else if (block is BlankLineBlock)
702 private void RenderHeadingBlock(HeadingBlock heading, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction,
bool spaceBefore,
bool spaceAfter)
704 MarkdownContext prevContext = context.Clone();
708 double minX = context.GetMinX(context.Cursor.Y +
SpaceBeforeHeading * context.Font.FontSize, context.Cursor.Y + context.Font.Ascent +
SpaceBeforeHeading * context.Font.FontSize - context.Font.Descent);
712 context.Cursor =
new Point(minX, context.Cursor.Y + context.Font.Ascent +
SpaceBeforeHeading * context.Font.FontSize);
716 context.Cursor =
new Point(minX, context.Cursor.Y + context.Font.Ascent);
719 if (context.CurrentLine ==
null)
721 context.CurrentLine =
new Line(context.Font.Ascent);
725 double delta = context.Cursor.Y - (prevContext.Cursor.Y + prevContext.Font.Ascent +
SpaceBeforeParagaph * prevContext.Font.FontSize);
727 for (
int i = 0; i < context.CurrentLine.Fragments.Count; i++)
729 context.CurrentLine.Fragments[i].Translate(0, delta);
733 foreach (Inline
inline in heading.Inline)
735 RenderInline(
inline, ref context, ref graphics, newPageAction);
740 double lineY = context.Cursor.Y + context.Font.FontSize * 0.3;
741 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(minX, context.Cursor.Y + context.Font.FontSize * 0.3),
new Point(context.GetMaxX(lineY,
PageSize.
Width -
Margins.
Right - context.Translation.X), lineY),
this.HeaderLineColour,
this.HeaderLineThicknesses[heading.Level - 1], context.Tag));
744 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
745 context.CurrentLine =
null;
749 double lineY = context.Cursor.Y + context.Font.FontSize * 0.3;
750 context.Cursor =
new Point(context.Cursor.X, lineY +
this.HeaderLineThicknesses[heading.Level - 1]);
753 context.Cursor =
new Point(0, context.Cursor.Y - context.Font.Descent +
SpaceAfterLine * context.Font.FontSize);
757 context.Cursor =
new Point(0, context.Cursor.Y +
SpaceAfterHeading * context.Font.FontSize);
760 prevContext.Cursor = context.Cursor;
761 prevContext.BottomRight = context.BottomRight;
762 prevContext.CurrentPage = context.CurrentPage;
763 prevContext.CurrentLine = context.CurrentLine;
765 context = prevContext;
768 private void RenderParagraphBlock(ParagraphBlock paragraph, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction,
bool spaceBefore,
bool spaceAfter)
770 double minX = context.GetMinX(context.Cursor.Y +
SpaceBeforeParagaph * context.Font.FontSize, context.Cursor.Y + context.Font.Ascent +
SpaceBeforeParagaph * context.Font.FontSize - context.Font.Descent);
774 context.Cursor =
new Point(minX, context.Cursor.Y + context.Font.Ascent +
SpaceBeforeParagaph * context.Font.FontSize);
778 context.Cursor =
new Point(minX, context.Cursor.Y + context.Font.Ascent);
781 if (context.CurrentLine ==
null)
783 context.CurrentLine =
new Line(context.Font.Ascent);
786 foreach (Inline
inline in paragraph.Inline)
788 RenderInline(
inline, ref context, ref graphics, newPageAction);
791 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
792 context.CurrentLine =
null;
794 context.Cursor =
new Point(0, context.Cursor.Y - context.Font.Descent +
SpaceAfterLine * context.Font.FontSize);
798 context.Cursor =
new Point(0, context.Cursor.Y +
SpaceAfterParagraph * context.Font.FontSize);
802 private void RenderFencedCodeBlock(FencedCodeBlock codeBlock, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction,
bool spaceBefore,
bool spaceAfter)
804 string info = codeBlock.Info;
806 if (
string.IsNullOrEmpty(info) || codeBlock.Lines.Count == 0)
808 RenderCodeBlock(codeBlock, ref context, ref graphics, newPageAction, spaceBefore, spaceAfter);
812 StringBuilder code =
new StringBuilder();
814 foreach (StringLine line
in codeBlock.Lines)
816 code.Append(line.ToString());
820 List<List<FormattedString>> lines = this.
SyntaxHighlighter(code.ToString(0, code.Length - 1), info);
824 RenderCodeBlock(codeBlock, ref context, ref graphics, newPageAction, spaceBefore, spaceAfter);
828 MarkdownContext prevContext = context.Clone();
830 context.Font =
new Font(this.
CodeFont, context.Font.FontSize);
834 context.Cursor =
new Point(0, context.Cursor.Y +
SpaceBeforeParagaph * context.Font.FontSize);
839 if (codeBlock.Lines.Count > 0)
841 foreach (List<FormattedString> line
in lines)
843 if (index < codeBlock.Lines.Count)
845 if (context.CurrentLine ==
null)
847 context.CurrentLine =
new Line(context.Font.Ascent);
850 double maxX = context.GetMaxX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
852 double minX = context.GetMinX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent);
854 context.Cursor =
new Point(minX + context.Font.FontSize, context.Cursor.Y + context.Font.YMax);
858 context.CurrentLine.Fragments.Insert(0,
new RectangleFragment(
new Point(minX, context.Cursor.Y - context.Font.YMax -
this.SpaceAfterLine * context.Font.FontSize),
new Size(maxX - minX, this.
SpaceAfterLine * context.Font.FontSize * 2),
CodeBlockBackgroundColour, context.Tag));
861 foreach (FormattedString item
in line)
863 context.Colour = item.Colour;
865 if (!item.IsBold && !item.IsItalic)
867 context.Font =
new Font(this.
CodeFont, context.Font.FontSize);
869 else if (item.IsBold && !item.IsItalic)
871 context.Font =
new Font(this.
CodeFontBold, context.Font.FontSize);
873 else if (item.IsBold && item.IsItalic)
877 else if (!item.IsBold && item.IsItalic)
879 context.Font =
new Font(this.
CodeFontItalic, context.Font.FontSize);
882 RenderCodeBlockLine(item.Text, ref context, ref graphics, newPageAction);
886 context.Colour = Colours.Black;
888 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
889 context.CurrentLine =
null;
891 context.Cursor =
new Point(0, context.Cursor.Y - context.Font.YMin);
901 context.Cursor =
new Point(0, context.Cursor.Y +
SpaceAfterLine * context.Font.FontSize);
905 context.Cursor =
new Point(0, context.Cursor.Y +
SpaceAfterParagraph * context.Font.FontSize);
908 prevContext.Cursor = context.Cursor;
909 prevContext.BottomRight = context.BottomRight;
910 prevContext.CurrentPage = context.CurrentPage;
911 prevContext.CurrentLine = context.CurrentLine;
913 context = prevContext;
917 private void RenderCodeBlock(CodeBlock codeBlock, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction,
bool spaceBefore,
bool spaceAfter)
919 MarkdownContext prevContext = context.Clone();
921 context.Font =
new Font(this.
CodeFont, context.Font.FontSize);
925 context.Cursor =
new Point(0, context.Cursor.Y +
SpaceBeforeParagaph * context.Font.FontSize);
930 if (codeBlock.Lines.Count > 0)
932 foreach (StringLine line
in codeBlock.Lines)
934 if (index < codeBlock.Lines.Count)
936 if (context.CurrentLine ==
null)
938 context.CurrentLine =
new Line(context.Font.Ascent);
941 double maxX = context.GetMaxX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
943 double minX = context.GetMinX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent);
945 context.Cursor =
new Point(minX + context.Font.FontSize, context.Cursor.Y + context.Font.YMax);
949 context.CurrentLine.Fragments.Insert(0,
new RectangleFragment(
new Point(minX, context.Cursor.Y - context.Font.YMax -
this.SpaceAfterLine * context.Font.FontSize),
new Size(maxX - minX, this.
SpaceAfterLine * context.Font.FontSize * 2),
CodeBlockBackgroundColour, context.Tag));
953 RenderCodeBlockLine(line.ToString(), ref context, ref graphics, newPageAction);
956 context.Colour = Colours.Black;
958 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
959 context.CurrentLine =
null;
961 context.Cursor =
new Point(0, context.Cursor.Y - context.Font.YMin);
971 context.Cursor =
new Point(0, context.Cursor.Y +
SpaceAfterLine * context.Font.FontSize);
975 context.Cursor =
new Point(0, context.Cursor.Y +
SpaceAfterParagraph * context.Font.FontSize);
978 prevContext.Cursor = context.Cursor;
979 prevContext.BottomRight = context.BottomRight;
980 prevContext.CurrentPage = context.CurrentPage;
981 prevContext.CurrentLine = context.CurrentLine;
983 context = prevContext;
986 private void RenderThematicBreakBlock(ThematicBreakBlock thematicBreak, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction,
bool spaceBefore,
bool spaceAfter)
988 if (context.CurrentLine ==
null)
990 context.CurrentLine =
new Line(0);
995 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y +
SpaceBeforeParagaph * context.Font.FontSize +
this.ThematicBreakThickness * 0.5);
999 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y +
this.ThematicBreakThickness * 0.5);
1003 double maxX = context.GetMaxX(context.Cursor.Y,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
1004 double minX = context.GetMinX(context.Cursor.Y);
1006 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(minX, context.Cursor.Y),
new Point(maxX, context.Cursor.Y),
this.ThematicBreakLineColour,
this.ThematicBreakThickness, context.Tag));
1008 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
1009 context.CurrentLine =
null;
1013 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y +
SpaceAfterParagraph * context.Font.FontSize +
this.ThematicBreakThickness * 0.5);
1017 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y +
this.ThematicBreakThickness * 0.5);
1021 private void RenderInline(Inline
inline, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1023 HtmlAttributes attributes =
inline.TryGetAttributes();
1025 if (attributes !=
null && !
string.IsNullOrEmpty(attributes.Id))
1027 Point cursor = context.Cursor;
1028 RenderHTMLBlock(
"<a name=\"" + attributes.Id +
"\"></a>",
true, ref context, ref graphics, newPageAction,
false,
false);
1029 context.Cursor = cursor;
1032 if (
inline is LeafInline)
1034 if (
inline is AutolinkInline autoLink)
1036 LinkInline link =
new LinkInline((autoLink.IsEmail ?
"mailto:" :
"") + autoLink.Url,
"");
1037 link.AppendChild(
new LiteralInline(autoLink.Url));
1039 RenderLinkInline(link, ref context, ref graphics, newPageAction);
1041 else if (
inline is CodeInline code)
1043 RenderCodeInline(code, ref context, ref graphics, newPageAction);
1045 else if (
inline is HtmlEntityInline htmlEntity)
1047 RenderLiteralInline(
new LiteralInline(htmlEntity.Transcoded), ref context, ref graphics, newPageAction);
1049 else if (
inline is HtmlInline html)
1051 RenderHTMLBlock(html.Tag,
true, ref context, ref graphics, newPageAction,
true,
true);
1053 else if (
inline is LineBreakInline lineBreak)
1055 RenderLineBreakInline(lineBreak.IsHard,
false, ref context, ref graphics, newPageAction);
1057 else if (
inline is LiteralInline literal)
1059 RenderLiteralInline(literal, ref context, ref graphics, newPageAction);
1061 else if (
inline is Markdig.Extensions.Mathematics.MathInline math)
1063 string imageUri =
"https://render.githubusercontent.com/render/math?math=" + System.Web.HttpUtility.UrlEncode(math.Content.ToString());
1065 RenderHTMLBlock(
"<img src=\"" + imageUri +
"\">",
true, ref context, ref graphics, newPageAction,
true,
true);
1067 else if (
inline is Markdig.Extensions.SmartyPants.SmartyPant smartyPant)
1069 switch (smartyPant.Type)
1071 case Markdig.Extensions.SmartyPants.SmartyPantType.LeftDoubleQuote:
1072 RenderLiteralInline(
new LiteralInline(
"“"), ref context, ref graphics, newPageAction);
1074 case Markdig.Extensions.SmartyPants.SmartyPantType.RightDoubleQuote:
1075 RenderLiteralInline(
new LiteralInline(
"”"), ref context, ref graphics, newPageAction);
1077 case Markdig.Extensions.SmartyPants.SmartyPantType.LeftQuote:
1078 RenderLiteralInline(
new LiteralInline(
"‘"), ref context, ref graphics, newPageAction);
1080 case Markdig.Extensions.SmartyPants.SmartyPantType.RightQuote:
1081 RenderLiteralInline(
new LiteralInline(
"’"), ref context, ref graphics, newPageAction);
1083 case Markdig.Extensions.SmartyPants.SmartyPantType.Dash2:
1084 RenderLiteralInline(
new LiteralInline(
"–"), ref context, ref graphics, newPageAction);
1086 case Markdig.Extensions.SmartyPants.SmartyPantType.Dash3:
1087 RenderLiteralInline(
new LiteralInline(
"—"), ref context, ref graphics, newPageAction);
1089 case Markdig.Extensions.SmartyPants.SmartyPantType.DoubleQuote:
1090 RenderLiteralInline(
new LiteralInline(
"\""), ref context, ref graphics, newPageAction);
1092 case Markdig.Extensions.SmartyPants.SmartyPantType.Ellipsis:
1093 RenderLiteralInline(
new LiteralInline(
"…"), ref context, ref graphics, newPageAction);
1095 case Markdig.Extensions.SmartyPants.SmartyPantType.LeftAngleQuote:
1096 RenderLiteralInline(
new LiteralInline(
"«"), ref context, ref graphics, newPageAction);
1098 case Markdig.Extensions.SmartyPants.SmartyPantType.Quote:
1099 RenderLiteralInline(
new LiteralInline(
"'"), ref context, ref graphics, newPageAction);
1101 case Markdig.Extensions.SmartyPants.SmartyPantType.RightAngleQuote:
1102 RenderLiteralInline(
new LiteralInline(
"»"), ref context, ref graphics, newPageAction);
1106 else if (
inline is Markdig.Extensions.TaskLists.TaskList)
1111 else if (
inline is ContainerInline)
1113 if (
inline is DelimiterInline)
1117 else if (
inline is EmphasisInline emphasis)
1119 RenderEmphasisInline(emphasis, ref context, ref graphics, newPageAction);
1121 else if (
inline is LinkInline link)
1123 RenderLinkInline(link, ref context, ref graphics, newPageAction);
1128 private void RenderLineBreakInline(
bool isHard,
bool isPageBreak, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1132 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
1133 context.CurrentLine =
new Line(context.Font.Ascent);
1134 context.Cursor =
new Point(0, context.Cursor.Y - context.Font.Descent +
SpaceAfterLine * context.Font.FontSize + context.Font.Ascent);
1136 double minX = context.GetMinX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent);
1138 context.Cursor =
new Point(minX, context.Cursor.Y);
1142 newPageAction(ref context, ref graphics);
1147 double spaceWidth = context.Font.FontFamily.TrueTypeFile.Get1000EmGlyphWidth(
' ') / 1000.0 * context.Font.FontSize;
1148 context.Cursor =
new Point(context.Cursor.X + spaceWidth, context.Cursor.Y);
1152 private void RenderLiteralInline(LiteralInline literal, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1154 string text = literal.Content.ToString();
1156 double spaceWidth = context.Font.FontFamily.TrueTypeFile.Get1000EmGlyphWidth(
' ') / 1000.0 * context.Font.FontSize;
1158 List<Word> words = Word.GetWords(text, context.Font,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X).ToList();
1160 double underlineStart = context.Cursor.X;
1161 double underlineEnd = context.Cursor.X;
1163 double currLineMaxX = context.GetMaxX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
1165 bool ignoreNextWhitespace =
false;
1167 bool broken =
false;
1169 for (
int i = 0; i < words.Count; i++)
1173 if (!
string.IsNullOrEmpty(w.Text))
1175 if (!ignoreNextWhitespace)
1177 context.Cursor =
new Point(context.Cursor.X + spaceWidth * w.WhitespaceCount * (w.PrecedingWhitespace ==
'\t' ? 4 : 1), context.Cursor.Y);
1181 ignoreNextWhitespace =
false;
1184 Font.DetailedFontMetrics wordMetrics = w.Metrics;
1186 double finalX = context.Cursor.X + wordMetrics.Width + wordMetrics.RightSideBearing + wordMetrics.LeftSideBearing;
1188 if (finalX <= currLineMaxX || broken)
1190 context.CurrentLine.Fragments.Add(
new TextFragment(
new Point(context.Cursor.X + wordMetrics.LeftSideBearing, context.Cursor.Y), w.Text, context.Font, context.Colour, context.Tag));
1191 context.Cursor =
new Point(context.Cursor.X + wordMetrics.Width + wordMetrics.RightSideBearing + wordMetrics.LeftSideBearing, context.Cursor.Y);
1195 if (context.Underline || context.StrikeThrough)
1197 underlineEnd = context.Cursor.X;
1202 if (context.Underline && underlineStart != underlineEnd)
1204 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y + context.Font.FontSize * 0.2),
new Point(underlineEnd, context.Cursor.Y + context.Font.FontSize * 0.2), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1206 else if (context.StrikeThrough && underlineStart != underlineEnd)
1208 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5),
new Point(underlineEnd, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1211 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
1215 context.CurrentLine =
new Line(context.Font.Ascent);
1216 context.Cursor =
new Point(0, context.Cursor.Y - context.Font.Descent +
SpaceAfterLine * context.Font.FontSize + context.Font.Ascent);
1217 currLineMaxX = context.GetMaxX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
1219 double minX = context.GetMinX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent);
1221 context.Cursor =
new Point(minX, context.Cursor.Y);
1223 underlineStart = minX;
1224 underlineEnd = minX;
1227 ignoreNextWhitespace =
true;
1233 context.Cursor =
new Point(context.Cursor.X + spaceWidth * w.WhitespaceCount * (w.PrecedingWhitespace ==
'\t' ? 4 : 1), context.Cursor.Y);
1237 if (context.Underline && underlineStart != underlineEnd)
1239 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y + context.Font.FontSize * 0.2),
new Point(underlineEnd, context.Cursor.Y + context.Font.FontSize * 0.2), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1241 else if (context.StrikeThrough && underlineStart != underlineEnd)
1243 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5),
new Point(underlineEnd, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1247 private void RenderCodeInline(CodeInline code, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1249 MarkdownContext prevContext = context.Clone();
1251 context.Font =
new Font(this.
CodeFont, context.Font.FontSize);
1253 double spaceWidth = context.Font.FontFamily.TrueTypeFile.Get1000EmGlyphWidth(
' ') / 1000.0 * context.Font.FontSize;
1255 string text = code.Content.ToString();
1256 List<Word> words = Word.GetWords(text, context.Font,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X).ToList();
1258 double currLineMaxX = context.GetMaxX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
1260 context.Cursor =
new Point(context.Cursor.X +
this.CodeInlineMargin * context.Font.FontSize, context.Cursor.Y);
1263 double underlineStart = context.Cursor.X;
1264 double underlineEnd = context.Cursor.X;
1266 bool broken =
false;
1268 for (
int i = 0; i < words.Count; i++)
1272 if (!
string.IsNullOrEmpty(w.Text))
1274 context.Cursor =
new Point(context.Cursor.X + spaceWidth * w.WhitespaceCount * (w.PrecedingWhitespace ==
'\t' ? 4 : 1), context.Cursor.Y);
1276 Font.DetailedFontMetrics wordMetrics = w.Metrics;
1278 double finalX = context.Cursor.X + wordMetrics.Width + wordMetrics.RightSideBearing + wordMetrics.LeftSideBearing;
1280 if (finalX <= currLineMaxX || broken)
1284 context.CurrentLine.Fragments.Add(
new RectangleFragment(
new Point(context.Cursor.X -
this.CodeInlineMargin * context.Font.FontSize, context.Cursor.Y - context.Font.YMax),
new Size(this.
CodeInlineMargin * context.Font.FontSize, context.Font.YMax - context.Font.YMin),
CodeInlineBackgroundColour, context.Tag));
1287 context.CurrentLine.Fragments.Add(
new RectangleFragment(
new Point(context.Cursor.X - spaceWidth * w.WhitespaceCount * (w.PrecedingWhitespace ==
'\t' ? 4 : 1), context.Cursor.Y - context.Font.YMax),
new Size(wordMetrics.Width + wordMetrics.LeftSideBearing * 2 + wordMetrics.RightSideBearing + spaceWidth * w.WhitespaceCount * (w.PrecedingWhitespace ==
'\t' ? 4 : 1), context.Font.YMax - context.Font.YMin),
CodeInlineBackgroundColour, context.Tag));
1289 context.CurrentLine.Fragments.Add(
new TextFragment(
new Point(context.Cursor.X + wordMetrics.LeftSideBearing, context.Cursor.Y), w.Text, context.Font, context.Colour, context.Tag));
1290 context.Cursor =
new Point(context.Cursor.X + wordMetrics.Width + wordMetrics.RightSideBearing + wordMetrics.LeftSideBearing, context.Cursor.Y);
1294 if (context.Underline || context.StrikeThrough)
1296 underlineEnd = context.Cursor.X;
1301 if (context.Underline && underlineStart != underlineEnd)
1303 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y + context.Font.FontSize * 0.2),
new Point(underlineEnd, context.Cursor.Y + context.Font.FontSize * 0.2), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1305 else if (context.StrikeThrough && underlineStart != underlineEnd)
1307 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5),
new Point(underlineEnd, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1310 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
1312 context.CurrentLine =
new Line(prevContext.Font.Ascent);
1314 context.Cursor =
new Point(0, context.Cursor.Y - prevContext.Font.Descent +
SpaceAfterLine * prevContext.Font.FontSize + prevContext.Font.Ascent);
1317 double minX = context.GetMinX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent);
1319 context.Cursor =
new Point(minX, context.Cursor.Y);
1323 context.Cursor =
new Point(context.Cursor.X +
this.CodeInlineMargin * context.Font.FontSize, context.Cursor.Y);
1326 underlineStart = minX;
1327 underlineEnd = minX;
1336 if (context.Underline && underlineStart != underlineEnd)
1338 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y + context.Font.FontSize * 0.2),
new Point(underlineEnd, context.Cursor.Y + context.Font.FontSize * 0.2), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1340 else if (context.StrikeThrough && underlineStart != underlineEnd)
1342 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5),
new Point(underlineEnd, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1345 context.CurrentLine.Fragments.Add(
new RectangleFragment(
new Point(context.Cursor.X, context.Cursor.Y - context.Font.YMax),
new Size(this.
CodeInlineMargin * context.Font.FontSize, context.Font.YMax - context.Font.YMin),
CodeInlineBackgroundColour, context.Tag));
1347 context.Cursor =
new Point(context.Cursor.X +
this.CodeInlineMargin * context.Font.FontSize, context.Cursor.Y);
1349 prevContext.Cursor = context.Cursor;
1350 prevContext.BottomRight = context.BottomRight;
1351 prevContext.CurrentPage = context.CurrentPage;
1352 prevContext.CurrentLine = context.CurrentLine;
1354 context = prevContext;
1357 private void RenderCodeBlockLine(
string text, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1359 double spaceWidth = context.Font.FontFamily.TrueTypeFile.Get1000EmGlyphWidth(
' ') / 1000.0 * context.Font.FontSize;
1361 List<Word> words = Word.GetWords(text, context.Font,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.Font.FontSize * 2 - context.MarginBottomRight.X).ToList();
1363 double underlineStart = context.Cursor.X;
1364 double underlineEnd = context.Cursor.X;
1366 double minX = context.GetMinX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent);
1368 double currLineMaxX = context.GetMaxX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X) - context.Font.FontSize;
1370 bool broken =
false;
1372 for (
int i = 0; i < words.Count; i++)
1375 if (!
string.IsNullOrEmpty(w.Text))
1377 context.Cursor =
new Point(context.Cursor.X + spaceWidth * w.WhitespaceCount * (w.PrecedingWhitespace ==
'\t' ? 4 : 1), context.Cursor.Y);
1378 Font.DetailedFontMetrics wordMetrics = w.Metrics;
1380 double finalX = context.Cursor.X + wordMetrics.Width + wordMetrics.RightSideBearing + wordMetrics.LeftSideBearing;
1382 double effW = wordMetrics.Width + wordMetrics.RightSideBearing + wordMetrics.LeftSideBearing;
1384 double maxW = this.
PageSize.
Width - this.
Margins.
Right - context.Translation.X - context.Font.FontSize * 2 - spaceWidth * w.WhitespaceCount * (w.PrecedingWhitespace ==
'\t' ? 4 : 1) - context.MarginBottomRight.X;
1386 if (finalX <= currLineMaxX || broken)
1389 context.CurrentLine.Fragments.Add(
new TextFragment(
new Point(context.Cursor.X + wordMetrics.LeftSideBearing, context.Cursor.Y), w.Text, context.Font, context.Colour, context.Tag));
1390 context.Cursor =
new Point(context.Cursor.X + wordMetrics.Width + wordMetrics.RightSideBearing + wordMetrics.LeftSideBearing, context.Cursor.Y);
1392 if (context.Underline || context.StrikeThrough)
1394 underlineEnd = context.Cursor.X;
1399 context.CurrentLine.Fragments.Insert(0,
new RectangleFragment(
new Point(minX, context.Cursor.Y - context.Font.YMax),
new Size(currLineMaxX + context.Font.FontSize - minX, context.Font.YMax - context.Font.YMin +
this.SpaceAfterLine * context.Font.FontSize),
CodeBlockBackgroundColour, context.Tag));
1401 if (context.Underline && underlineStart != underlineEnd)
1403 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y + context.Font.FontSize * 0.2),
new Point(underlineEnd, context.Cursor.Y + context.Font.FontSize * 0.2), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1405 else if (context.StrikeThrough && underlineStart != underlineEnd)
1407 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5),
new Point(underlineEnd, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1410 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
1415 context.CurrentLine =
new Line(context.Font.Ascent);
1417 context.Cursor =
new Point(0, context.Cursor.Y - context.Font.Descent +
SpaceAfterLine * context.Font.FontSize + context.Font.Ascent);
1419 currLineMaxX = context.GetMaxX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X) - context.Font.FontSize;
1421 minX = context.GetMinX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent);
1423 context.Cursor =
new Point(minX + context.Font.FontSize, context.Cursor.Y);
1431 context.Cursor =
new Point(context.Cursor.X + spaceWidth * w.WhitespaceCount * (w.PrecedingWhitespace ==
'\t' ? 4 : 1), context.Cursor.Y);
1435 if (context.Underline && underlineStart != underlineEnd)
1437 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y + context.Font.FontSize * 0.2),
new Point(underlineEnd, context.Cursor.Y + context.Font.FontSize * 0.2), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1439 else if (context.StrikeThrough && underlineStart != underlineEnd)
1441 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(underlineStart, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5),
new Point(underlineEnd, context.Cursor.Y - context.Font.Ascent * 0.5 - context.Font.Descent * 0.5), context.Colour, context.Font.FontSize * (context.Font.FontFamily.IsBold ?
this.BoldUnderlineThickness :
this.UnderlineThickness), context.Tag));
1444 context.CurrentLine.Fragments.Insert(0,
new RectangleFragment(
new Point(minX, context.Cursor.Y - context.Font.YMax),
new Size(currLineMaxX + context.Font.FontSize - minX, context.Font.YMax - context.Font.YMin +
this.SpaceAfterLine * context.Font.FontSize),
CodeBlockBackgroundColour, context.Tag));
1447 private void RenderEmphasisInline(EmphasisInline emphasis, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1449 MarkdownContext prevContext = context.Clone();
1451 Point translationToUndo =
new Point(0, 0);
1453 switch (emphasis.DelimiterChar)
1457 if (emphasis.DelimiterCount == 2)
1459 if (context.Font.FontFamily ==
this.ItalicFontFamily)
1463 else if (context.Font.FontFamily ==
this.BoldFontFamily)
1467 else if (context.Font.FontFamily ==
this.BoldItalicFontFamily)
1473 context.Font =
new Font(this.
BoldFontFamily, context.Font.FontSize);
1476 else if (emphasis.DelimiterCount == 3)
1478 if (context.Font.FontFamily ==
this.ItalicFontFamily)
1480 context.Font =
new Font(this.
BoldFontFamily, context.Font.FontSize);
1482 else if (context.Font.FontFamily ==
this.BoldFontFamily)
1486 else if (context.Font.FontFamily ==
this.BoldItalicFontFamily)
1497 if (context.Font.FontFamily ==
this.ItalicFontFamily)
1501 else if (context.Font.FontFamily ==
this.BoldFontFamily)
1505 else if (context.Font.FontFamily ==
this.BoldItalicFontFamily)
1507 context.Font =
new Font(this.
BoldFontFamily, context.Font.FontSize);
1516 if (emphasis.DelimiterCount == 2)
1518 if (context.Font.FontFamily ==
this.ItalicFontFamily)
1522 else if (context.Font.FontFamily ==
this.BoldFontFamily)
1526 else if (context.Font.FontFamily ==
this.BoldItalicFontFamily)
1528 context.Font =
new Font(this.
BoldFontFamily, context.Font.FontSize);
1537 if (emphasis.DelimiterCount == 1)
1540 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y + context.Font.FontSize *
this.SubscriptShift);
1541 translationToUndo =
new Point(translationToUndo.X, translationToUndo.Y + context.Font.FontSize *
this.SubscriptShift);
1542 context.Font =
new Font(context.Font.FontFamily, context.Font.FontSize *
this.SubSuperscriptFontSize);
1547 context.StrikeThrough =
true;
1551 if (emphasis.DelimiterCount == 1)
1554 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y - context.Font.FontSize *
this.SuperscriptShift);
1555 translationToUndo =
new Point(translationToUndo.X, translationToUndo.Y - context.Font.FontSize *
this.SuperscriptShift);
1556 context.Font =
new Font(context.Font.FontFamily, context.Font.FontSize *
this.SubSuperscriptFontSize);
1567 foreach (Inline innerInline
in emphasis)
1569 RenderInline(innerInline, ref context, ref graphics, newPageAction);
1572 if (translationToUndo.X != 0 || translationToUndo.Y != 0)
1574 context.Cursor =
new Point(context.Cursor.X - translationToUndo.X, context.Cursor.Y - translationToUndo.Y);
1578 prevContext.Cursor = context.Cursor;
1579 prevContext.BottomRight = context.BottomRight;
1580 prevContext.CurrentPage = context.CurrentPage;
1581 prevContext.CurrentLine = context.CurrentLine;
1583 context = prevContext;
1586 private void RenderLinkInline(LinkInline link, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1590 MarkdownContext prevContext = context.Clone();
1593 context.Underline =
true;
1594 string tag = Guid.NewGuid().ToString(
"N");
1596 if (!link.Url.StartsWith(
"#"))
1598 if (Uri.TryCreate(
this.BaseLinkUri, link.Url, out Uri uri))
1609 if (!context.InternalAnchors.TryGetValue(link.Url, out
string anchor))
1611 anchor = Guid.NewGuid().ToString(
"N");
1612 context.InternalAnchors[link.Url] = anchor;
1615 context.LinkDestinations[tag] =
"#" + anchor;
1620 foreach (Inline innerInline
in link)
1622 RenderInline(innerInline, ref context, ref graphics, newPageAction);
1625 prevContext.Cursor = context.Cursor;
1626 prevContext.BottomRight = context.BottomRight;
1627 prevContext.CurrentPage = context.CurrentPage;
1628 prevContext.CurrentLine = context.CurrentLine;
1630 context = prevContext;
1634 HtmlTag tag = HtmlTag.Parse(
"<img src=\"" + link.Url.Replace(
"\"",
"\\\"") +
"\">").FirstOrDefault();
1636 RenderHTMLImage(tag,
true, ref context, ref graphics, newPageAction);
1640 private void RenderListBlock(ListBlock list, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1642 MarkdownContext prevContext = context.Clone();
1644 context.ListDepth++;
1646 double minX = context.GetMinX(context.Cursor.Y +
SpaceBeforeParagaph * context.Font.FontSize, context.Cursor.Y - context.Font.Descent + context.Font.Ascent +
SpaceBeforeParagaph * context.Font.FontSize);
1648 if (context.CurrentLine !=
null)
1650 foreach (LineFragment fragment
in context.CurrentLine.Fragments)
1657 context.Translation =
new Point(context.Translation.X + minX +
this.IndentWidth, context.Translation.Y);
1659 foreach (Block block
in list)
1661 RenderBlock(block, ref context, ref graphics, newPageAction,
true,
true);
1665 context.Translation =
new Point(context.Translation.X - minX -
this.IndentWidth, context.Translation.Y);
1667 prevContext.Cursor = context.Cursor;
1668 prevContext.BottomRight = context.BottomRight;
1669 prevContext.CurrentPage = context.CurrentPage;
1670 prevContext.CurrentLine = context.CurrentLine;
1672 context = prevContext;
1675 private void RenderQuoteBlock(QuoteBlock quote, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1677 MarkdownContext prevContext = context.Clone();
1679 double minX = context.GetMinX(context.Cursor.Y +
SpaceBeforeParagaph * context.Font.FontSize, context.Cursor.Y - context.Font.Descent + context.Font.Ascent +
SpaceBeforeParagaph * context.Font.FontSize);
1681 Graphics quoteGraphics =
new Graphics();
1685 context.MarginBottomRight =
new Point(context.MarginBottomRight.X + prevContext.Translation.X, context.MarginBottomRight.Y + prevContext.Translation.Y);
1689 double startY = context.Cursor.Y + context.Font.Ascent - context.Font.YMax;
1691 Point currTranslation = context.Translation;
1693 Graphics parentGraphics = graphics;
1695 NewPageAction newPageActionWithBlockquotes = (ref MarkdownContext currContext, ref Graphics currGraphics) =>
1697 double currEndY = currContext.Cursor.Y;
1699 double currMaxX = maxX;
1701 Graphics currBackgroundGraphics =
new Graphics();
1703 currBackgroundGraphics.Save();
1705 currBackgroundGraphics.Translate(currContext.Translation);
1709 currBackgroundGraphics.Restore();
1711 currBackgroundGraphics.DrawGraphics(0, 0, currGraphics);
1713 parentGraphics.DrawGraphics(0, 0, currBackgroundGraphics);
1715 Point currContextTranslation = currContext.Translation;
1717 currContext.Translation = prevContext.Translation;
1719 newPageAction(ref currContext, ref parentGraphics);
1721 currContext.Translation = currContextTranslation;
1723 currGraphics =
new Graphics();
1726 startY = currContext.Cursor.Y + currContext.Font.Ascent - currContext.Font.YMax;
1731 foreach (Block block
in quote)
1733 RenderBlock(block, ref context, ref quoteGraphics, newPageActionWithBlockquotes,
true, index < quote.Count - 1);
1737 double endY = context.Cursor.Y;
1739 Graphics backgroundGraphics =
new Graphics();
1741 backgroundGraphics.Save();
1743 backgroundGraphics.Translate(context.Translation);
1747 backgroundGraphics.Restore();
1749 backgroundGraphics.DrawGraphics(0, 0, quoteGraphics);
1751 parentGraphics.DrawGraphics(0, 0, backgroundGraphics);
1753 graphics = parentGraphics;
1755 context.Translation = prevContext.Translation;
1757 if (!(quote.Parent is QuoteBlock) || quote.Parent.LastChild != quote)
1759 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y +
SpaceAfterParagraph * context.Font.FontSize);
1762 prevContext.Cursor = context.Cursor;
1763 prevContext.BottomRight = context.BottomRight;
1764 prevContext.CurrentPage = context.CurrentPage;
1765 prevContext.CurrentLine = context.CurrentLine;
1767 context = prevContext;
1770 private void RenderListItemBlock(ListItemBlock listItem, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1772 MarkdownContext prevContext = context.Clone();
1774 bool isLoose =
false;
1776 double startX = context.Cursor.X;
1777 double startY = context.Cursor.Y;
1779 if (listItem.Parent is ListBlock list)
1783 if (context.CurrentLine ==
null)
1785 context.CurrentLine =
new Line(context.Font.Ascent);
1790 switch (list.BulletType)
1794 bullet = ((char)((
int)list.DefaultOrderedStart[0] + listItem.Order - 1)).ToString() + list.OrderedDelimiter;
1797 bullet = GetRomanNumeral(listItem.Order).ToLower() + list.OrderedDelimiter;
1800 bullet = GetRomanNumeral(listItem.Order) + list.OrderedDelimiter;
1803 bullet = listItem.Order.ToString() + list.OrderedDelimiter;
1810 context.CurrentLine.Fragments.Add(
new TextFragment(
new Point(context.Cursor.X - context.Font.MeasureText(bullet).Width -
this.IndentWidth * 0.15, context.Cursor.Y + context.Font.Ascent +
SpaceBeforeParagaph * context.Font.FontSize), bullet, context.Font, context.Colour, context.Tag));
1815 context.CurrentLine.Fragments.Add(
new TextFragment(
new Point(context.Cursor.X - context.Font.MeasureText(bullet).Width -
this.IndentWidth * 0.15, context.Cursor.Y + context.Font.Ascent), bullet, context.Font, context.Colour, context.Tag));
1820 if (listItem.Count > 0 && listItem[0] is ParagraphBlock paragraph && paragraph.Inline?.FirstChild is Markdig.Extensions.TaskLists.TaskList task)
1822 if (context.CurrentLine ==
null)
1824 context.CurrentLine =
new Line(context.Font.Ascent);
1827 Graphics bullet =
new Graphics();
1828 bullet.Scale(context.Font.FontSize, context.Font.FontSize);
1842 context.CurrentLine.Fragments.Add(
new GraphicsFragment(
new Point(context.Cursor.X -
this.IndentWidth * 0.15, context.Cursor.Y + context.Font.Ascent +
SpaceBeforeParagaph * context.Font.FontSize - context.Font.Descent * 0.5 - (context.Font.Ascent - context.Font.Descent) * 0.5), bullet, 0));
1847 context.CurrentLine.Fragments.Add(
new GraphicsFragment(
new Point(context.Cursor.X -
this.IndentWidth * 0.15, context.Cursor.Y + context.Font.Ascent - context.Font.Descent * 0.5 - (context.Font.Ascent - context.Font.Descent) * 0.5), bullet, 0));
1852 if (context.CurrentLine ==
null)
1854 context.CurrentLine =
new Line(context.Font.Ascent);
1857 Graphics bullet =
new Graphics();
1858 bullet.Scale(context.Font.FontSize, context.Font.FontSize);
1859 this.
Bullets[(context.ListDepth - 1) % this.
Bullets.Count](bullet, context.Colour);
1864 context.CurrentLine.Fragments.Add(
new GraphicsFragment(
new Point(context.Cursor.X -
this.IndentWidth * 0.15, context.Cursor.Y + context.Font.Ascent +
SpaceBeforeParagaph * context.Font.FontSize - context.Font.Descent * 0.5 - (context.Font.Ascent - context.Font.Descent) * 0.5), bullet, 0));
1869 context.CurrentLine.Fragments.Add(
new GraphicsFragment(
new Point(context.Cursor.X -
this.IndentWidth * 0.15, context.Cursor.Y + context.Font.Ascent - context.Font.Descent * 0.5 - (context.Font.Ascent - context.Font.Descent) * 0.5), bullet, 0));
1875 foreach (Block block
in listItem)
1877 RenderBlock(block, ref context, ref graphics, newPageAction, isLoose || listItem == listItem.Parent[0], isLoose || listItem == listItem.Parent.LastChild);
1880 prevContext.Cursor = context.Cursor;
1881 prevContext.BottomRight = context.BottomRight;
1882 prevContext.CurrentPage = context.CurrentPage;
1883 prevContext.CurrentLine = context.CurrentLine;
1885 context = prevContext;
1888 private void RenderHTMLBlock(
string html,
bool isInline, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction,
bool spaceBefore,
bool spaceAfter)
1892 double minX = context.GetMinX(context.Cursor.Y +
SpaceBeforeParagaph * context.Font.FontSize, context.Cursor.Y + context.Font.Ascent +
SpaceBeforeParagaph * context.Font.FontSize - context.Font.Descent);
1894 context.Cursor =
new Point(minX, context.Cursor.Y + context.Font.Ascent +
SpaceBeforeParagaph * context.Font.FontSize);
1896 if (context.CurrentLine ==
null)
1898 context.CurrentLine =
new Line(context.Font.Ascent);
1902 foreach (HtmlTag tag
in HtmlTag.Parse(html))
1904 if (tag.Tag.Equals(
"img", StringComparison.OrdinalIgnoreCase) || tag.Tag.Equals(
"image", StringComparison.OrdinalIgnoreCase))
1906 RenderHTMLImage(tag, isInline, ref context, ref graphics, newPageAction);
1908 else if (tag.Tag.Equals(
"br", StringComparison.OrdinalIgnoreCase))
1910 RenderLineBreakInline(
true, tag.Attributes.TryGetValue(
"type", out
string typeValue) && typeValue.Equals(
"page", StringComparison.OrdinalIgnoreCase) &&
this.AllowPageBreak, ref context, ref graphics, newPageAction);
1912 else if (tag.Tag.Equals(
"a"))
1914 if (tag.Attributes.TryGetValue(
"name", out
string anchorName))
1916 if (!context.InternalAnchors.TryGetValue(
"#" + anchorName, out
string anchor))
1918 anchor = Guid.NewGuid().ToString(
"N");
1919 context.InternalAnchors[
"#" + anchorName] = anchor;
1922 if (context.CurrentLine ==
null)
1924 context.CurrentLine =
new Line(0);
1929 context.CurrentLine.Fragments.Add(
new RectangleFragment(
new Point(context.Cursor.X, context.Cursor.Y - anchorHeight),
new Size(10, anchorHeight), Colour.FromRgba(0, 0, 0, 0), anchor));
1940 if (context.CurrentLine !=
null)
1942 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
1943 context.CurrentLine =
null;
1945 context.Cursor =
new Point(0, context.Cursor.Y - context.Font.Descent +
SpaceAfterLine * context.Font.FontSize);
1947 context.Cursor =
new Point(0, context.Cursor.Y +
SpaceAfterParagraph * context.Font.FontSize);
1952 private void RenderHTMLImage(HtmlTag imgTag,
bool isInline, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
1956 if (imgTag.Attributes.TryGetValue(
"src", out
string imageSrc))
1960 Page imagePage =
null;
1962 if (imageFile !=
null)
1964 if (System.IO.Path.GetExtension(imageFile) ==
".svg")
1980 imagePage =
new Page(raster.Width, raster.Height);
1981 imagePage.Graphics.DrawRasterImage(0, 0, raster, tag: context.Tag);
1992 System.IO.File.Delete(imageFile);
1993 System.IO.Directory.Delete(System.IO.Path.GetDirectoryName(imageFile));
1996 else if (imageSrc.StartsWith(
"data:"))
2009 if (imagePage !=
null)
2014 bool hasWidth =
false;
2015 bool hasHeight =
false;
2017 if (imgTag.Attributes.TryGetValue(
"width", out
string widthString) &&
double.TryParse(widthString, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out
double width))
2023 if (imgTag.Attributes.TryGetValue(
"height", out
string heightString) &&
double.TryParse(heightString, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out
double height))
2029 if (hasWidth && !hasHeight)
2033 else if (hasHeight && !hasWidth)
2045 if (!imgTag.Attributes.TryGetValue(
"align", out alignValue))
2050 if (alignValue ==
"center")
2052 if (context.CurrentLine !=
null)
2054 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
2055 context.CurrentLine =
null;
2058 double minX = context.GetMinX(context.Cursor.Y + context.Translation.Y, context.Cursor.Y + context.Translation.Y + scaleY * imagePage.Height);
2059 double maxX = context.GetMaxX(context.Cursor.Y + context.Translation.Y, context.Cursor.Y + context.Translation.Y + scaleY * imagePage.Height,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
2061 if (scaleX * imagePage.Width > maxX - minX)
2063 scaleX = (maxX - minX) / imagePage.Width;
2067 double finalY = context.Cursor.Y + scaleY * imagePage.Height;
2069 if (finalY + context.Translation.Y >
this.PageSize.Height -
this.Margins.Bottom +
this.ImageMarginTolerance - context.MarginBottomRight.Y)
2071 newPageAction(ref context, ref graphics);
2072 finalY = context.Cursor.Y + scaleY * imagePage.Height;
2076 graphics.Translate((minX + maxX - scaleX * imagePage.Width) * 0.5, context.Cursor.Y);
2077 graphics.Scale(scaleX, scaleY);
2078 graphics.SetClippingPath(0, 0, imagePage.Width, imagePage.Height);
2079 graphics.DrawGraphics(0, 0, imagePage.Graphics);
2085 else if (alignValue ==
"right")
2087 if (context.CurrentLine !=
null)
2089 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
2090 context.CurrentLine =
null;
2093 double finalY = context.Cursor.Y + scaleY * imagePage.Height;
2095 if (finalY + context.Translation.Y >
this.PageSize.Height -
this.Margins.Bottom +
this.ImageMarginTolerance - context.MarginBottomRight.Y)
2097 newPageAction(ref context, ref graphics);
2098 finalY = context.Cursor.Y + scaleY * imagePage.Height;
2102 graphics.Translate(this.
PageSize.
Width -
this.Margins.Right - context.Translation.X - scaleX * imagePage.Width - context.MarginBottomRight.X, context.Cursor.Y);
2103 graphics.Scale(scaleX, scaleY);
2104 graphics.SetClippingPath(0, 0, imagePage.Width, imagePage.Height);
2106 graphics.DrawGraphics(0, 0, imagePage.Graphics);
2110 context.ForbiddenAreasRight.Add((this.
PageSize.
Width -
this.Margins.Right - scaleX * imagePage.Width -
this.ImageSideMargin - context.MarginBottomRight.X, context.Cursor.Y + context.Translation.Y, context.Cursor.Y + context.Translation.Y + scaleY * imagePage.Height));
2112 else if (alignValue ==
"left")
2114 if (context.CurrentLine !=
null)
2116 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
2117 context.CurrentLine =
null;
2120 double finalY = context.Cursor.Y + scaleY * imagePage.Height;
2122 if (finalY + context.Translation.Y >
this.PageSize.Height -
this.Margins.Bottom +
this.ImageMarginTolerance - context.MarginBottomRight.Y)
2124 newPageAction(ref context, ref graphics);
2125 finalY = context.Cursor.Y + scaleY * imagePage.Height;
2129 graphics.Translate(0, context.Cursor.Y);
2130 graphics.Scale(scaleX, scaleY);
2131 graphics.SetClippingPath(0, 0, imagePage.Width, imagePage.Height);
2133 graphics.DrawGraphics(0, 0, imagePage.Graphics);
2137 context.ForbiddenAreasLeft.Add((scaleX * imagePage.Width + context.Translation.X +
this.ImageSideMargin, context.Cursor.Y + context.Translation.Y, context.Cursor.Y + context.Translation.Y + scaleY * imagePage.Height));
2147 Graphics scaledImage =
new Graphics();
2148 scaledImage.Scale(scaleX, scaleY);
2149 scaledImage.DrawGraphics(0, 0, imagePage.Graphics);
2151 if (context.CurrentLine ==
null)
2153 context.CurrentLine =
new Line(context.Font.Ascent);
2155 context.Cursor =
new Point(0, context.Cursor.Y);
2156 double minX = context.GetMinX(context.Cursor.Y - scaleY * imagePage.Height, context.Cursor.Y);
2157 context.Cursor =
new Point(minX, context.Cursor.Y);
2160 double currLineMaxX = context.GetMaxX(context.Cursor.Y - scaleY * imagePage.Height, context.Cursor.Y,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
2162 double finalX = context.Cursor.X + imagePage.Width;
2164 if (finalX > currLineMaxX)
2166 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
2168 context.CurrentLine =
new Line(context.Font.Ascent);
2169 context.Cursor =
new Point(0, context.Cursor.Y - context.Font.Descent +
SpaceAfterLine * context.Font.FontSize + context.Font.Ascent);
2170 currLineMaxX = context.GetMaxX(context.Cursor.Y - context.Font.Ascent, context.Cursor.Y - context.Font.Descent,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
2172 double minX = context.GetMinX(context.Cursor.Y - scaleY * imagePage.Height * scaleY, context.Cursor.Y);
2174 context.Cursor =
new Point(minX, context.Cursor.Y);
2177 context.CurrentLine.Fragments.Add(
new GraphicsFragment(
new Point(context.Cursor.X, context.Cursor.Y - scaleY * imagePage.Height), scaledImage, scaleY * imagePage.Height));
2178 context.Cursor =
new Point(context.Cursor.X + scaleX * imagePage.Width, context.Cursor.Y);
2185 private void RenderTable(Table table, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
2187 if (table.Count > 0)
2189 if (!table.IsValid())
2191 table.NormalizeUsingMaxWidth();
2192 table.NormalizeUsingHeaderRow();
2195 if (table.IsValid() && table.ColumnDefinitions?.Count > 0)
2197 bool isGridTable =
false;
2199 foreach (TableColumnDefinition def
in table.ColumnDefinitions)
2212 foreach (TableRow row
in table)
2214 maxColumns = Math.Max(maxColumns, ((TableCell)row.Last()).ColumnIndex + 1);
2217 if (table.ColumnDefinitions.Count > maxColumns)
2219 table.ColumnDefinitions.RemoveRange(maxColumns, table.ColumnDefinitions.Count - maxColumns);
2226 foreach (TableRow row
in table)
2228 maxColumns = Math.Max(maxColumns, row.Count);
2231 if (table.ColumnDefinitions.Count > maxColumns)
2233 table.ColumnDefinitions.RemoveRange(maxColumns, table.ColumnDefinitions.Count - maxColumns);
2237 double[] columnWidths =
new double[table.ColumnDefinitions.Count];
2239 if (table.ColumnDefinitions.Count == 0)
2241 int columnCount = 0;
2242 foreach (TableRow row
in table)
2244 columnCount = Math.Max(row.Count, columnCount);
2247 columnWidths =
new double[columnCount];
2250 int missingColumns = columnWidths.Length;
2252 for (
int i = 0; i < columnWidths.Length; i++)
2254 columnWidths[i] =
double.NaN;
2257 double remainingPerc = 1;
2259 for (
int i = 0; i < table.ColumnDefinitions.Count; i++)
2261 if (table.ColumnDefinitions[i].Width > 0)
2264 remainingPerc -= table.ColumnDefinitions[i].Width / 100.0;
2265 columnWidths[i] = table.ColumnDefinitions[i].Width / 100.0;
2269 if (missingColumns > 0)
2271 remainingPerc /= missingColumns;
2272 for (
int i = 0; i < columnWidths.Length; i++)
2274 if (
double.IsNaN(columnWidths[i]))
2276 columnWidths[i] = remainingPerc;
2281 double maxX = context.GetMaxX(context.Cursor.Y, context.Cursor.Y,
this.PageSize.Width -
this.Margins.Right - context.Translation.X - context.MarginBottomRight.X);
2283 for (
int i = 0; i < columnWidths.Length; i++)
2285 columnWidths[i] *= maxX;
2290 foreach (TableRow row
in table)
2292 RenderTableRow(row, columnWidths, index == table.Count - 1, ref context, ref graphics, newPageAction);
2296 context.Cursor =
new Point(context.Cursor.X, context.Cursor.Y +
SpaceAfterParagraph * context.Font.FontSize);
2301 private void RenderTableRow(TableRow row,
double[] columnWidths,
bool isLastRow, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
2303 if (context.CurrentLine ==
null)
2305 context.CurrentLine =
new Line(0);
2310 foreach (TableCell cell
in row)
2312 if (cell.ColumnIndex < 0)
2314 cell.ColumnIndex = index;
2315 index += cell.ColumnSpan;
2319 index = cell.ColumnIndex + cell.ColumnSpan;
2323 double maxHeight = 0;
2324 double startX = context.Cursor.X;
2326 MarkdownContext prevContext = context.Clone();
2330 context.Font =
new Font(this.
BoldFontFamily, context.Font.FontSize);
2334 foreach (TableCell cell
in row)
2336 double cellWidth = 0;
2338 for (
int i = 0; i < cell.ColumnSpan && cell.ColumnIndex + i < columnWidths.Length; i++)
2340 cellWidth += columnWidths[cell.ColumnIndex + i];
2343 Page cellPage = RenderTableCell(cell, cellWidth, ref context, ref graphics, newPageAction);
2345 double prevMaxHeight = maxHeight;
2346 maxHeight = Math.Max(maxHeight, cellPage.Height);
2348 context.CurrentLine.Fragments.Add(
new GraphicsFragment(
new Point(context.Cursor.X, context.Cursor.Y - cellPage.Height), cellPage.Graphics, cellPage.Height));
2350 context.Cursor =
new Point(context.Cursor.X + cellWidth, context.Cursor.Y);
2355 for (
int i = 0; i < context.CurrentLine.Fragments.Count; i++)
2357 context.CurrentLine.Fragments[i].Translate(0, -maxHeight + ((GraphicsFragment)context.CurrentLine.Fragments[i]).Ascent);
2362 for (
int i = 0; i < context.CurrentLine.Fragments.Count; i++)
2364 context.CurrentLine.Fragments[i].Translate(0, (-maxHeight + ((GraphicsFragment)context.CurrentLine.Fragments[i]).Ascent) * 0.5);
2368 context.CurrentLine.Fragments.Add(
new UnderlineFragment(
new Point(startX, context.Cursor.Y),
new Point(columnWidths.Sum() + startX, context.Cursor.Y), row.IsHeader ?
this.TableHeaderRowSeparatorColour :
this.TableRowSeparatorColour, row.IsHeader ?
this.TableHeaderRowSeparatorThickness :
this.TableHeaderSeparatorThickness, context.Tag));
2370 context.CurrentLine.Render(ref graphics, ref context, newPageAction, this.
PageSize.
Height -
this.Margins.Bottom - context.Translation.Y - context.MarginBottomRight.Y);
2371 context.CurrentLine =
null;
2373 context.Cursor =
new Point(startX, context.Cursor.Y);
2375 context.Cursor =
new Point(startX, context.Cursor.Y +
SpaceAfterLine * context.Font.FontSize + (row.IsHeader ?
this.TableHeaderRowSeparatorThickness :
this.TableHeaderSeparatorThickness));
2377 prevContext.Cursor = context.Cursor;
2378 prevContext.BottomRight = context.BottomRight;
2379 prevContext.CurrentPage = context.CurrentPage;
2380 prevContext.CurrentLine = context.CurrentLine;
2382 context = prevContext;
2385 private Page RenderTableCell(TableCell cell,
double cellWidth, ref MarkdownContext context, ref Graphics graphics, NewPageAction newPageAction)
2387 MarkdownRenderer clonedRenderer = this.Clone();
2388 clonedRenderer.PageSize =
new Size(cellWidth,
double.PositiveInfinity);
2391 MarkdownContext clonedContext = context.Clone();
2392 clonedContext.Translation =
new Point(0, 0);
2393 clonedContext.Cursor =
new Point(0, 0);
2394 clonedContext.BottomRight =
new Point(0, 0);
2395 clonedContext.CurrentLine =
null;
2396 clonedContext.CurrentPage =
null;
2397 clonedContext.ForbiddenAreasLeft =
new List<(double MinX, double MinY, double MaxY)>();
2398 clonedContext.ForbiddenAreasRight =
new List<(double MinX, double MinY, double MaxY)>();
2400 Page cellPage = clonedRenderer.RenderSubDocument(cell, ref clonedContext).Pages[0];
2402 cellPage.Crop(
new Point(0, 0),
new Size(cellWidth, clonedContext.BottomRight.Y +
this.TableCellMargins.Bottom));
2407 static (int, string)[] RomanNumbers =
new (
int,
string)[] { (1000,
"M"), (900,
"CM"), (500,
"D"), (400,
"CD"), (100,
"C"), (90,
"XC"), (50,
"L"), (40,
"XL"), (10,
"X"), (9,
"IX"), (5,
"V"), (4,
"IV"), (1,
"I") };
2409 private static string GetRomanNumeral(
int number)
2411 StringBuilder tbr =
new StringBuilder();
2413 for (
int i = 0; i < RomanNumbers.Length; i++)
2415 while (number >= RomanNumbers[i].Item1)
2417 tbr.Append(RomanNumbers[i].Item2);
2418 number -= RomanNumbers[i].Item1;
2422 return tbr.ToString();