private static T Open <T>(XmlReader reader) where T : SvgDocument, new() { if (!SkipGdiPlusCapabilityCheck) { EnsureSystemIsGdiPlusCapable(); //Validate whether the GDI+ can be loaded, this will yield an exception if not } var elementStack = new Stack <SvgElement>(); bool elementEmpty; SvgElement element = null; SvgElement parent; T svgDocument = null; var elementFactory = new SvgElementFactory(); var styles = new List <ISvgNode>(); while (reader.Read()) { try { switch (reader.NodeType) { case XmlNodeType.Element: // Does this element have a value or children // (Must do this check here before we progress to another node) elementEmpty = reader.IsEmptyElement; // Create element if (elementStack.Count > 0) { element = elementFactory.CreateElement(reader, svgDocument); } else { svgDocument = elementFactory.CreateDocument <T>(reader); element = svgDocument; } // Add to the parents children if (elementStack.Count > 0) { parent = elementStack.Peek(); if (parent != null && element != null) { parent.Children.Add(element); parent.Nodes.Add(element); } } // Push element into stack elementStack.Push(element); // Need to process if the element is empty if (elementEmpty) { goto case XmlNodeType.EndElement; } break; case XmlNodeType.EndElement: // Pop the element out of the stack element = elementStack.Pop(); if (element.Nodes.OfType <SvgContentNode>().Any()) { element.Content = (from e in element.Nodes select e.Content).Aggregate((p, c) => p + c); } else { element.Nodes.Clear(); // No sense wasting the space where it isn't needed } if (element is SvgUnknownElement unknown && unknown.ElementName == "style") { styles.Add(unknown); } break; case XmlNodeType.CDATA: case XmlNodeType.Text: case XmlNodeType.SignificantWhitespace: element = elementStack.Peek(); element.Nodes.Add(new SvgContentNode() { Content = reader.Value }); break; case XmlNodeType.EntityReference: reader.ResolveEntity(); element = elementStack.Peek(); element.Nodes.Add(new SvgContentNode() { Content = reader.Value }); break; } } catch (Exception exc) { Trace.TraceError(exc.Message); } } if (styles.Any()) { var cssTotal = styles.Select((s) => s.Content).Aggregate((p, c) => p + Environment.NewLine + c); var cssParser = new Parser(); var sheet = cssParser.Parse(cssTotal); foreach (var rule in sheet.StyleRules) { try { var rootNode = new NonSvgElement(); rootNode.Children.Add(svgDocument); var elemsToStyle = rootNode.QuerySelectorAll(rule.Selector.ToString(), elementFactory); foreach (var elem in elemsToStyle) { foreach (var decl in rule.Declarations) { elem.AddStyle(decl.Name, decl.Term.ToString(), rule.Selector.GetSpecificity()); } } } catch (Exception ex) { Trace.TraceWarning(ex.Message); } } } svgDocument?.FlushStyles(true); return(svgDocument); }
private static T Open <T>(XmlReader reader) where T : SvgDocument, new() { try { var elementStack = new Stack <SvgElement>(); bool elementEmpty; SvgElement element = null; SvgElement parent; T svgDocument = null; var elementFactory = new SvgElementFactory(); var styles = new List <ISvgNode>(); while (reader.Read()) { try { switch (reader.NodeType) { case XmlNodeType.Element: // Does this element have a value or children // (Must do this check here before we progress to another node) elementEmpty = reader.IsEmptyElement; // Create element if (elementStack.Count > 0) { element = elementFactory.CreateElement(reader, svgDocument); } else { svgDocument = elementFactory.CreateDocument <T>(reader); element = svgDocument; } // Add to the parents children if (elementStack.Count > 0) { parent = elementStack.Peek(); if (parent != null && element != null) { parent.Children.Add(element); parent.Nodes.Add(element); } } // Push element into stack elementStack.Push(element); // Need to process if the element is empty if (elementEmpty) { goto case XmlNodeType.EndElement; } break; case XmlNodeType.EndElement: // Pop the element out of the stack element = elementStack.Pop(); if (element.Nodes.OfType <SvgContentNode>().Any()) { element.Content = (from e in element.Nodes select e.Content).Aggregate((p, c) => p + c); } else { element.Nodes.Clear(); // No sense wasting the space where it isn't needed } var unknown = element as SvgUnknownElement; if (unknown != null && unknown.ElementName == "style") { styles.Add(unknown); } break; case XmlNodeType.CDATA: case XmlNodeType.Text: element = elementStack.Peek(); element.Nodes.Add(new SvgContentNode() { Content = reader.Value }); break; case XmlNodeType.EntityReference: reader.ResolveEntity(); element = elementStack.Peek(); element.Nodes.Add(new SvgContentNode() { Content = reader.Value }); break; } } catch (Exception exc) { Trace.TraceError(exc.Message); if (ExceptionCaughtIsGdiPlusRelated(exc)) { throw; } // GDI+ errors should be rethrown } } if (styles.Any()) { var cssTotal = styles.Select((s) => s.Content).Aggregate((p, c) => p + Environment.NewLine + c); var cssParser = new Parser(); var sheet = cssParser.Parse(cssTotal); AggregateSelectorList aggList; IEnumerable <BaseSelector> selectors; IEnumerable <SvgElement> elemsToStyle; foreach (var rule in sheet.StyleRules) { aggList = rule.Selector as AggregateSelectorList; if (aggList != null && aggList.Delimiter == ",") { selectors = aggList; } else { selectors = Enumerable.Repeat(rule.Selector, 1); } foreach (var selector in selectors) { try { var rootNode = new NonSvgElement(); rootNode.Children.Add(svgDocument); elemsToStyle = rootNode.QuerySelectorAll(rule.Selector.ToString(), elementFactory); foreach (var elem in elemsToStyle) { foreach (var decl in rule.Declarations) { elem.AddStyle(decl.Name, decl.Term.ToString(), rule.Selector.GetSpecificity()); } } } catch (Exception ex) { Trace.TraceWarning(ex.Message); if (ExceptionCaughtIsGdiPlusRelated(ex)) { throw; } // GDI+ errors should be rethrown } } } } if (svgDocument != null) { FlushStyles(svgDocument); } return(svgDocument); } // GDI+ loading errors will result in TypeInitializationExceptions, // for readability we will catch and wrap the error catch (Exception e) { if (ExceptionCaughtIsGdiPlusRelated(e)) { // Throw only the customized exception if we are sure GDI+ is causing the problem throw new SvgGdiPlusCannotBeLoadedException(e); } // No wrapping, just rethrow the exception throw; } }