// "Therefore those skilled at the unorthodox // are infinite as heaven and earth, // inexhaustible as the great rivers. // When they come to an end, // they begin again, // like the days and months; // they die and are reborn, // like the four seasons." // // - Sun Tsu, // "The Art of War" using System; using System.Globalization; using TheArtOfDev.HtmlRenderer.Adapters.Entities; using TheArtOfDev.HtmlRenderer.Core.Dom; using TheArtOfDev.HtmlRenderer.Core.Entities; using TheArtOfDev.HtmlRenderer.Core.Handlers; using TheArtOfDev.HtmlRenderer.Core.Utils; namespace TheArtOfDev.HtmlRenderer.Core.Parse { /// /// Handle css DOM tree generation from raw html and stylesheet. /// internal sealed class DomParser { #region Fields and Consts /// /// Parser for CSS /// private readonly CssParser _cssParser; #endregion /// /// Init. /// public DomParser(CssParser cssParser) { ArgChecker.AssertArgNotNull(cssParser, "cssParser"); _cssParser = cssParser; } /// /// Generate css tree by parsing the given html and applying the given css style data on it. /// /// the html to parse /// the html container to use for reference resolve /// the css data to use /// the root of the generated tree public CssBox GenerateCssTree(string html, HtmlContainerInt htmlContainer, ref CssData cssData) { var root = HtmlParser.ParseDocument(html); if (root != null) { root.HtmlContainer = htmlContainer; bool cssDataChanged = false; CascadeParseStyles(root, htmlContainer, ref cssData, ref cssDataChanged); CascadeApplyStyles(root, cssData); SetTextSelectionStyle(htmlContainer, cssData); CorrectTextBoxes(root); CorrectImgBoxes(root); bool followingBlock = true; CorrectLineBreaksBlocks(root, ref followingBlock); CorrectInlineBoxesParent(root); CorrectBlockInsideInline(root); CorrectInlineBoxesParent(root); } return root; } #region Private methods /// /// Read styles defined inside the dom structure in links and style elements.
/// If the html tag is "style" tag parse it content and add to the css data for all future tags parsing.
/// If the html tag is "link" that point to style data parse it content and add to the css data for all future tags parsing.
///
/// the box to parse style data in /// the html container to use for reference resolve /// the style data to fill with found styles /// check if the css data has been modified by the handled html not to change the base css data private void CascadeParseStyles(CssBox box, HtmlContainerInt htmlContainer, ref CssData cssData, ref bool cssDataChanged) { if (box.HtmlTag != null) { // Check for the tag if (box.HtmlTag.Name.Equals("link", StringComparison.CurrentCultureIgnoreCase) && box.GetAttribute("rel", string.Empty).Equals("stylesheet", StringComparison.CurrentCultureIgnoreCase)) { CloneCssData(ref cssData, ref cssDataChanged); string stylesheet; CssData stylesheetData; StylesheetLoadHandler.LoadStylesheet(htmlContainer, box.GetAttribute("href", string.Empty), box.HtmlTag.Attributes, out stylesheet, out stylesheetData); if (stylesheet != null) _cssParser.ParseStyleSheet(cssData, stylesheet); else if (stylesheetData != null) cssData.Combine(stylesheetData); } // Check for the