private IEnumerable <Inline> ConvertInlines(HTML.Element e, Context ctx, bool collapseSpace, ParagraphSizeTracker pst) { return(from i in (from n in e.Contents select ConvertInline(n, ctx, collapseSpace, pst)) where i != null select i); }
private Span RenderHyperlink(HTML.Element e) { if (e.Attributes.ContainsKey("href")) { Hyperlink h = new Hyperlink(); Uri TargetURI; if (Uri.TryCreate(e.Attributes["href"], UriKind.RelativeOrAbsolute, out TargetURI)) { if (!TargetURI.IsAbsoluteUri) { TargetURI = BaseUri != null ? new Uri(BaseUri, TargetURI) : null; } } if (TargetURI != null) { h.NavigateUri = TargetURI; h.RequestNavigate += RequestedNavigate; h.ToolTip = TargetURI; } else { // tooltip contains URI even if it's bad h.ToolTip = e.Attributes["href"]; } return(h); } else { return(new Span()); } }
private InlineUIContainer RenderImage(HTML.Element e, ParagraphSizeTracker pst) { Uri ImageURI; if (e.Attributes.ContainsKey("src") && Uri.TryCreate(e.Attributes["src"], UriKind.RelativeOrAbsolute, out ImageURI)) { Image image = new Image() { Stretch = Stretch.Fill }; BitmapImage bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.UriSource = ImageURI; bitmapImage.EndInit(); image.Source = bitmapImage; if (ImageSizeCache.ContainsKey(ImageURI)) { Tuple <int, int> size = ImageSizeCache[ImageURI]; image.Width = size.Item1; image.Height = size.Item2; } // This hack forces image size to match pixel size, // which undermines WPF's preference for honoring the // embedded DPI value which leads to upscaled and // mildly blurry images where that doesn't match // the local display. Very high resolution displays // might need another approach. bitmapImage.DownloadCompleted += (s, ee) => { ImageSizeCache[ImageURI] = new Tuple <int, int>(bitmapImage.PixelWidth, bitmapImage.PixelHeight); image.Width = bitmapImage.PixelWidth; image.Height = bitmapImage.PixelHeight; }; // Communicate image size info back up to the container if (pst != null) { pst.Add(image); } if (e.Attributes.ContainsKey("title")) { image.ToolTip = e.Attributes["title"]; } else if (e.Attributes.ContainsKey("alt")) { image.ToolTip = e.Attributes["alt"]; } // TODO arrange to display alt value if image can't be loaded // (or before it has loaded) return(new InlineUIContainer() { Child = image }); } else { return(null); } }
public void TestHTMLSimpleNoOpen() { HTML.Document d = HTML.Document.Parse("wibble"); HTML.Element p = d.HTML.Follow("body.p"); Assert.AreEqual(1, p.Contents.Count); HTML.Cdata cdata = p.Contents[0] as HTML.Cdata; Assert.AreEqual("wibble", cdata.Content); }
private IEnumerable <Block> ConvertFlowsOrBlocks(HTML.Element root, Context ctx) { List <Block> blocks = new List <Block>(); foreach (HTML.Node n in root.Contents) { blocks.AddRange(ConvertFlowOrBlock(n as HTML.Element, ctx)); } return(blocks); }
public void TestHTMLEmpty() { HTML.Document d = HTML.Document.Parse(""); Assert.AreEqual("html", d.HTML.Name); Assert.AreEqual(2, d.HTML.Contents.Count); HTML.Element body = d.HTML.Contents[1] as HTML.Element; Assert.IsNotNull(body); Assert.AreEqual("body", body.Name); Assert.AreEqual(0, body.Contents.Count); }
public void TestHTMLExtraSlash() { HTML.Document d = HTML.Document.Parse("<img src=\"http://imgs.xkcd.com/comics/voyager_1.png\" title=\"what'ever'\" />"); HTML.Element img = d.HTML.Follow("body.p.img"); Assert.AreEqual(2, img.Attributes.Count); Assert.IsTrue(img.Attributes.ContainsKey("src")); Assert.AreEqual("http://imgs.xkcd.com/comics/voyager_1.png", img.Attributes["src"]); Assert.IsTrue(img.Attributes.ContainsKey("title")); Assert.AreEqual("what'ever'", img.Attributes["title"]); Assert.AreEqual("<html><head></head><body><p><img src=\"http://imgs.xkcd.com/comics/voyager_1.png\" title=\"what'ever'\"></p></body></html>", d.ToString()); }
private Paragraph ConvertParagraph(HTML.Element e, Context ctx, bool collapseSpace) { LastCharacter = ' '; Paragraph p = new Paragraph(); p.Inlines.AddRange(ConvertInlines(e, ctx, collapseSpace, new ParagraphSizeTracker() { ParentScrollViewer = ParentScrollViewer })); return(p.Inlines.Count > 0 ? p : null); }
private List ConvertList(HTML.Element e, Context ctx) { List l = new List(); foreach (HTML.Element ee in e.Contents) { ListItem li = new ListItem(); li.Blocks.AddRange(ConvertFlowOrBlock(ee, ctx)); l.ListItems.Add(li); } return(l); }
public void TestHTMLTwoPara() { HTML.Document d = HTML.Document.Parse("<p>first</p> <p>second</p>"); Assert.AreEqual(2, d.HTML.Follow("body").Contents.Count); HTML.Element p1 = d.HTML.Follow("body.p"); Assert.AreEqual(1, p1.Contents.Count); HTML.Cdata cdata1 = p1.Contents[0] as HTML.Cdata; Assert.AreEqual("first", cdata1.Content); HTML.Element p2 = (HTML.Element)d.HTML.Follow("body").Contents[1]; HTML.Cdata cdata2 = p2.Contents[0] as HTML.Cdata; Assert.AreEqual("second", cdata2.Content); }
public void TestHTMLInline() { HTML.Document d = HTML.Document.Parse("<p>one <i>two</i> three</p>"); HTML.Element p = d.HTML.Follow("body.p"); Assert.AreEqual(3, p.Contents.Count); HTML.Cdata cdata1 = p.Contents[0] as HTML.Cdata; Assert.AreEqual("one ", cdata1.Content); HTML.Element italic = p.Contents[1] as HTML.Element; Assert.AreEqual("i", italic.Name); Assert.AreEqual(1, italic.Contents.Count); HTML.Cdata cdata2 = italic.Contents[0] as HTML.Cdata; Assert.AreEqual("two", cdata2.Content); HTML.Cdata cdata3 = p.Contents[2] as HTML.Cdata; Assert.AreEqual(" three", cdata3.Content); }
public void TestHTMLSimple() { HTML.Document d = HTML.Document.Parse("<p>wibble</p>"); Assert.AreEqual("html", d.HTML.Name); Assert.AreEqual(2, d.HTML.Contents.Count); HTML.Element body = d.HTML.Contents[1] as HTML.Element; Assert.IsNotNull(body); Assert.AreEqual("body", body.Name); Assert.AreEqual(1, body.Contents.Count); HTML.Element p = body.Contents[0] as HTML.Element; Assert.AreEqual("p", p.Name); Assert.AreEqual(1, p.Contents.Count); HTML.Cdata cdata = p.Contents[0] as HTML.Cdata; Assert.AreEqual("wibble", cdata.Content); }
private IEnumerable <Block> ConvertDefinitionList(HTML.Element e, Context ctx) { List <Block> blocks = new List <Block>(); foreach (HTML.Element d in e.Contents) { IEnumerable <Block> dblocks = ConvertFlowOrBlock(d, ctx); if (d.Name == "dd") { foreach (Block b in dblocks) { Indent(b, 12, 0); } } blocks.AddRange(dblocks); } return(blocks); }
static private int GetSpan(HTML.Element e, string attribute) { string attributeValue; if (e.Attributes.TryGetValue(attribute, out attributeValue)) { int value; if (int.TryParse(attributeValue, out value)) { if (value < 1) { value = 1; } return(value); } } return(1); }
public void TestHTMLAttributes() { HTML.Document d = HTML.Document.Parse("<p><a href=\"http://www.example.com/\">target</a></p>"); HTML.Element a = d.HTML.Follow("body.p.a"); Assert.AreEqual(1, a.Attributes.Count); Assert.IsTrue(a.Attributes.ContainsKey("href")); Assert.AreEqual("http://www.example.com/", a.Attributes["href"]); d = HTML.Document.Parse("<p><a href='http://www.example.com/&' >target</a></p>"); a = d.HTML.Follow("body.p.a"); Assert.AreEqual(1, a.Attributes.Count); Assert.IsTrue(a.Attributes.ContainsKey("href")); Assert.AreEqual("http://www.example.com/&", a.Attributes["href"]); d = HTML.Document.Parse("<p><a href=\"http://www.example.com/\" Target=_blank>target</a></p>"); a = d.HTML.Follow("body.p.a"); Assert.AreEqual(2, a.Attributes.Count); Assert.IsTrue(a.Attributes.ContainsKey("href")); Assert.AreEqual("http://www.example.com/", a.Attributes["href"]); Assert.IsTrue(a.Attributes.ContainsKey("target")); Assert.AreEqual("_blank", a.Attributes["target"]); }
public void TestHTMLLists() { HTML.Document d = HTML.Document.Parse("<ul><li>one</li><li>two</li></ul>"); HTML.Element ul = d.HTML.Follow("body.ul"); Assert.AreEqual(2, ul.Contents.Count); HTML.Element li1 = ul.Contents[0] as HTML.Element; Assert.AreEqual("li", li1.Name); Assert.AreEqual(1, li1.Contents.Count); Assert.AreEqual("one", (li1.Contents[0] as HTML.Cdata).Content); HTML.Element li2 = ul.Contents[1] as HTML.Element; Assert.AreEqual("li", li2.Name); Assert.AreEqual(1, li2.Contents.Count); Assert.AreEqual("two", (li2.Contents[0] as HTML.Cdata).Content); d = HTML.Document.Parse("<ul><li><p>one<p>two</ul>"); ul = d.HTML.Follow("body.ul"); Assert.AreEqual(1, ul.Contents.Count); li1 = ul.Contents[0] as HTML.Element; Assert.AreEqual("li", li1.Name); Assert.AreEqual(2, li1.Contents.Count); Assert.AreEqual("one", ((li1.Contents[0] as HTML.Element).Contents[0] as HTML.Cdata).Content); Assert.AreEqual("two", ((li1.Contents[1] as HTML.Element).Contents[0] as HTML.Cdata).Content); }
private Table ConvertTable(HTML.Element e, Context ctx) { Table t = new Table() { CellSpacing = 0, }; TableRowGroup trg = new TableRowGroup(); t.RowGroups.Add(trg); int columns = 0; HTML.Element caption = null; foreach (HTML.Element r in e.Contents) { switch (r.Name) { case "tr": TableRow tr = new TableRow(); trg.Rows.Add(tr); int columnNumber = 0; foreach (HTML.Element c in r.Contents) { TableCell tc = new TableCell() { ColumnSpan = GetSpan(c, "colspan"), RowSpan = GetSpan(c, "rowspan"), BorderBrush = Brushes.Black, BorderThickness = new Thickness(0.5, 0.5, 0.5, 0.5), Padding = new Thickness(1), }; if (c.Name == "th") { tc.Blocks.AddRange(ConvertFlowOrBlock(c, new Context(ctx) { fontWeight = FontWeights.Bold })); } else { tc.Blocks.AddRange(ConvertFlowOrBlock(c, ctx)); } tr.Cells.Add(tc); columnNumber += tc.ColumnSpan; } if (columnNumber > columns) { columns = columnNumber; } break; case "caption": caption = r; break; } } if (caption != null && columns == 0) { columns = 1; } for (int i = 0; i < columns; ++i) { t.Columns.Add(new TableColumn()); } if (caption != null) { TableRow tr = new TableRow(); TableCell tc = new TableCell() { ColumnSpan = columns, TextAlignment = TextAlignment.Center, }; Paragraph p = ConvertParagraph(caption, new Context(ctx) { fontStyle = FontStyles.Italic }, true); tc.Blocks.Add(p); tr.Cells.Add(tc); trg.Rows.Add(tr); } return(t); }
private IEnumerable <Block> ConvertFlowOrBlock(HTML.Element e, Context ctx) { if (e.IsBlockElement() || e.IsListElement() || e.IsTableElement()) { Block block = null; switch (e.Name) { case "ul": block = ConvertList(e, ctx); break; case "ol": List l = ConvertList(e, ctx); l.StartIndex = 1; block = l; break; case "dl": return(ConvertDefinitionList(e, ctx)); case "h1": case "h2": case "h3": case "h4": case "h5": case "h6": block = ConvertParagraph(e, new Context(ctx) { fontFamily = HeadingFont, fontWeight = FontWeights.Bold, fontSize = TextSize * Math.Pow(1.125, '7' - e.Name[1]) }, true); break; case "pre": block = ConvertParagraph(e, new Context(ctx) { fontFamily = MonospaceFont }, false); break; case "table": block = ConvertTable(e, ctx); break; case "hr": block = HorizontalRule(); break; default: block = ConvertParagraph(e, ctx, true); break; } if (block != null) { return(new List <Block>() { block }); } else { return(new List <Block>()); } } else { IEnumerable <Block> content; if (e.Contents.Count > 0 && (e.Contents[0] is HTML.Cdata || (e.Contents[0] as HTML.Element).IsInlineElement())) { content = new List <Block>() { ConvertParagraph(e, ctx, true) }; } else { content = ConvertFlowsOrBlocks(e, ctx); } switch (e.Name) { case "blockquote": foreach (Block b in content) { Indent(b, 12, 12); break; } break; // TODO other kinds of flow container } return(content); } }
private Inline ConvertInlineElement(HTML.Element e, Context ctx, bool collapseSpace, ParagraphSizeTracker pst) { Span s; switch (e.Name) { case "b": case "strong": s = new Span(); ctx = new Context(ctx) { fontWeight = FontWeights.Bold }; break; case "i": case "em": s = new Span(); ctx = new Context(ctx) { fontStyle = FontStyles.Italic }; break; case "u": s = new Underline(); break; case "big": { s = new Span(); double newSize = ctx.fontSize * 1.25; ctx = new Context(ctx) { fontSize = newSize }; break; } case "small": { s = new Span(); double newSize = ctx.fontSize / 1.25; ctx = new Context(ctx) { fontSize = newSize }; break; } case "code": case "tt": s = new Span(); ctx = new Context(ctx) { fontFamily = MonospaceFont }; break; case "sub": s = new Span(); s.Typography.Variants = FontVariants.Subscript; break; case "sup": s = new Span(); s.Typography.Variants = FontVariants.Superscript; break; case "a": s = RenderHyperlink(e); break; case "img": return(RenderImage(e, pst)); case "br": return(new LineBreak()); // TODO map, anything else? default: s = new Span(); break; } s.Inlines.AddRange(ConvertInlines(e, ctx, collapseSpace, pst)); return(s); }