diff --git a/Source/Demo/Common/HtmlRenderer.Demo.Common.csproj b/Source/Demo/Common/HtmlRenderer.Demo.Common.csproj
index b2b829640..d6a6a96d0 100644
--- a/Source/Demo/Common/HtmlRenderer.Demo.Common.csproj
+++ b/Source/Demo/Common/HtmlRenderer.Demo.Common.csproj
@@ -87,6 +87,7 @@
++ + diff --git a/Source/HtmlRenderer/Core/Dom/CssBox.cs b/Source/HtmlRenderer/Core/Dom/CssBox.cs index b2cd3d984..05ae7f539 100644 --- a/Source/HtmlRenderer/Core/Dom/CssBox.cs +++ b/Source/HtmlRenderer/Core/Dom/CssBox.cs @@ -60,7 +60,7 @@ internal class CssBox : CssBoxProperties, IDisposable ///+ The html is parsed using a real HTML5 tokenizer (from the + HtmlKit library) instead of a hand-rolled + scanner, so the pages below - all of which are intentionally malformed - render + correctly instead of breaking the layout. Every example shows the raw (broken) html + source followed by the actual live rendering of that exact same markup. +
+
+Optional / omitted end tags +
++ Real world html is full of tags whose closing tag was never written. The parser now + follows the + HTML5 end-tag omission rules and automatically closes them at the right + place, instead of nesting everything into one deep, broken tree. +
+Source:+<p>First paragraph, never closed +<p>Second paragraph, never closed +<p>Third paragraph, never closed+Live result:+++First paragraph, never closed +
Second paragraph, never closed +
Third paragraph, never closed +
+Tables with missing <tr>/<td> end tags +
++ The same omission rules apply to table rows and cells, so a table written without a + single closing
+</tr>or</td>still comes out as + a proper grid. +Source:+<table border="1" cellpadding="4"> +<tr><td>A<td>B +<tr><td>C<td>D +</table>+Live result:++++
+A B + C D +
+Anonymous table boxes +
++ Per the CSS 2.1 anonymous + table object rules, a stray
+<td>with no<tr>+ (or even no<table>) around it is automatically wrapped in the missing + row/table boxes, rather than producing a broken or invisible layout. +Source:+<table border="1"><td>Anonymous row generated around me</td></table>+Live result:++++
Anonymous row generated around me
+Comments containing ">" +
++ A real tokenizer knows where a comment actually ends, so a stray
+>character + inside a comment no longer truncates it early or corrupts the rest of the page. +Source:+<!-- a comment that contains a > character right here --> +<p>This paragraph renders normally right after it.</p>+Live result:++ ++This paragraph renders normally right after it.
+
+<script> content is not mistaken for markup +
++
+<script>content is tokenized as raw text (this renderer does not execute + script, so the code itself is not shown), which means<and>+ characters used for comparisons inside the script can no longer be misread as the start + of a nested tag and swallow the rest of the document. +Source:+<script> + if (1 < 2 && 3 > 2) { + runDemo('<b>looks like a tag</b>, but is just a string'); + } +</script> +<p>This paragraph still renders correctly right after the script block.</p>+Live result:++ ++This paragraph still renders correctly right after the script block.
+
+<noscript> content is parsed as real markup +
++ Per the HTML5 tokenizer spec,
+<noscript>content is normally tokenized + as raw text too. Since this renderer never runs script, its<noscript>+ content is specifically re-parsed as nested html, so tags placed inside it render as real + elements instead of showing up as literal text. +Source:+<noscript><p>This is <b>real, nested markup</b> inside noscript.</p></noscript>+Live result:++ ++
tags per https://html.spec.whatwg.org/dev/grouping-content.html#the-p-element + public static bool ShouldTagCloseParagraph(string tagName) + { + switch (tagName) + { + case "address": + case "article": + case "aside": + case "blockquote": + case "details": + case "dialog": + case "div": + case "dl": + case "fieldset": + case "figcaption": + case "figure": + case "footer": + case "form": + case "h1": + case "h2": + case "h3": + case "h4": + case "h5": + case "h6": + case "header": + case "hgroup": + case "hr": + case "main": + case "menu": + case "nav": + case "ol": + case "p": + case "pre": + case "search": + case "section": + case "table": + case "ul": + return true; + default: + return false; + } + } + + // Close