/// <summary>Parses the given html markup and returns the corresponding inline content element.</summary> /// <param name="html">The html markup text.</param> /// <param name="source">The source html block element for inheriting styling properties.</param> /// <returns>The inline content element that renders the given html markup.</returns> public static Inline ParseHTML(string html, HtmlBlock source) { html = "<Span>{0}</Span>".Substitute(html); html = html.ReplaceAll(_reCharEntity, match => "\xBF"+match.Groups[1].Value+"?"); var doc = XDocument.Parse(html, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); return _parseHTMLNode(doc.Root, source); }
// Recursively parses the given Html node into a corresponding Inline element private static Inline _parseHTMLNode(XNode node, HtmlBlock source) { if (node.NodeType == XmlNodeType.Text) { var text = ((XText)node).Value; text = text.ReplaceAll(_reWhitespace, " "); text = text.ReplaceAll(_reEncodedEntity, match => { var code = match.Groups[1].Value; if (code.At(0) == "#") { return Char.ConvertFromUtf32(Int32.Parse(code.After(0))); } else if (_htmlEntities.ContainsKey(code)) { return Char.ConvertFromUtf32(_htmlEntities[code]); } else { throw new Exception(TEXT.HtmlBlock_UnrecognizedChar.Substitute(code)); } }); return new Run(text); } if (node.NodeType != XmlNodeType.Element) { return null; } var tag = (XElement)node; var name = tag.Name.LocalName.ToLower(); Span outer = null; Brush emphBrush = null; double fontSize = 11; double paraBreak = 0; if (source != null) { emphBrush = source.EmphasizedForeground; fontSize = Double.IsNaN(source.FontSize) ? 11 : source.FontSize; } // hyperlink if (name == "a") { var link = new Hyperlink(); var href = tag.Get<Uri>("href"); if (href != null) link.NavigateUri = href; var trg = tag.Get("target"); if (trg.NotEmpty()) link.TargetName = trg; outer = link; } // bold else if (name == "b") { outer = new Bold(); } // big else if (name == "big") { outer = new Span(); outer.FontSize = fontSize * _fontFactors[4]; } // line break else if (name == "br") { return new LineBreak(); } // code else if (name == "c" || name == "code") { outer = new Span(); outer.FontFamily = new FontFamily("Courier New"); } // code else if (name == "em") { outer = new Span(); if (emphBrush != null) outer.Foreground = emphBrush; } // font style else if (name == "font") { outer = new Span(); var face = tag.Get("face"); if (face.NotEmpty()) outer.FontFamily = new FontFamily(face); var brush = tag.Get<Brush>("color", null); if (brush != null) outer.Foreground = brush; var size = tag.Get<int>("size", -1); if (size > 0) outer.FontSize = size; } // header 1-6 else if (name.Matches(_reHeaderTag)) { outer = new Bold(); if (emphBrush != null) outer.Foreground = emphBrush; outer.FontSize = fontSize * _fontFactors[7-Int32.Parse(name.At(1))]; paraBreak = 1; } // italic else if (name == "i") { outer = new Italic(); } // image else if (name == "img") { outer = new Span(); var uic = new InlineUIContainer(); var img = new Image(); var src = tag.GetImage("src"); if (src != null) img.Source = src; var w = tag.Get<int>("width", -1); if (w >= 0) img.Width = w; var h = tag.Get<int>("height", -1); if (h >= 0) img.Height = h; uic.Child = img; outer.Inlines.Add(uic); } // paragraph else if (name == "p") { outer = new Span(); paraBreak = 4; } // small else if (name == "small") { outer = new Span(); outer.FontSize = fontSize * _fontFactors[2]; } // span else if (name == "span") { outer = new Span(); } // underline else if (name == "u") { outer = new Underline(); } // invalid tag else { throw new Exception(TEXT.HtmlBlock_UnrecognizedTag.Substitute(tag.Name.LocalName)); } var tip = tag.GetImage("title"); if (tip != null) { outer.ToolTip = tip; } foreach (var child in tag.Nodes()) { var inner = _parseHTMLNode(child, source); if (inner != null) outer.Inlines.Add(inner); } if (paraBreak == 0) return outer; var para = new Span(); para.Inlines.Add(outer); para.Inlines.Add(new LineBreak()); var blankline = new Span(); blankline.FontSize = paraBreak; para.Inlines.Add(blankline); para.Inlines.Add(new LineBreak()); return para; }
private static Slot _createBodySlot(BplProperty parentProperty, BplClass bplClass, Stack<BplClass> parentClasses) { if (parentClasses.Any(pclass => bplClass.IsA(pclass))) { var error = new Record("", parentProperty.Name + " : " + bplClass.Name + " [recursive]"); return new Slot(error, _slotErrorBG); } parentClasses.Push(bplClass); var childSlots = new StackPanel { Margin = new Thickness(0, _slotSize, _slotSize, 0) }; childSlots.Children.Add(new Slot(0, new Record("4", "Opcode (<c>0x{0:X8}</c>)".Substitute(bplClass.Protocol.Opcode)))); var depth = 0; int? fixedSize = 4; foreach (var prop in bplClass.Properties) { Slot slot = null; if (prop.IsCalculated) continue; if (prop.IsPrimitive) { var ptype = prop.PrimitiveType; var pname = "{0} : <i>{1}</i>".Substitute(prop.Name, (ptype.IsDelegate ? "Function" : ptype.Name)); var psize = BplLanguage.BinaryConverters[ptype].SizeOf(); if (psize.Size.HasValue && fixedSize.HasValue) { fixedSize = fixedSize.Value + psize.Size.Value; } else { fixedSize = null; } slot = new Slot(0, new Record(psize.Formula, pname)); } else { fixedSize = null; var refClass = prop.ReferencedClass; if (prop.IsAssociation) { var multiplier = ""; var suffix = "*"; if (prop.IsCollection) { multiplier = @"n {0} ".Substitute(DOT); suffix = "[]"; } var record = new Record("4 + {0}|id|".Substitute(multiplier), "{0} : <i>{1}{2}</i>".Substitute(prop.Name, refClass.Name, suffix)); slot = new Slot(0, record); } else { slot = _createBodySlot(prop, refClass, parentClasses); } } depth = Math.Max(depth, slot.Depth); childSlots.Children.Add(slot); } var parentGrid = new Grid(); parentGrid.Children.Add(childSlots); if (parentProperty == null) { var title = new HtmlBlock("<b>{0}</b>".Substitute(bplClass.Name)) { Margin = new Thickness(_slotMargin), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top }; parentGrid.Children.Add(title); _ncollections = 0; } else { var name = "{0} : <i>{1}</i>".Substitute(parentProperty.Name, bplClass.Name + (parentProperty.IsCollection ? "[]" : "*")); var cardinality = "1"; if (parentProperty.IsCollection) { cardinality = @"N<font size=""8"">{0}</font>".Substitute(++_ncollections); } var parentSize = String.Empty; if (fixedSize.HasValue) { parentSize = fixedSize.Value.ToString(); } else { parentSize = "|{0}|".Substitute(_getNameStem(bplClass.Name)); } if (cardinality == "1") { parentSize = "4 + {0}?".Substitute(parentSize); } else { parentSize = "4 + {0} {1} {2}".Substitute(cardinality, DOT, parentSize); } parentGrid.Children.Add(new Record(parentSize, name)); parentGrid.Children.Add(new HtmlBlock(cardinality) { Width = _slotSize, TextAlignment = TextAlignment.Center, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Center }); } parentClasses.Pop(); return new Slot(depth + 1, parentGrid); }