示例#1
0
        /// <summary>
        /// Applies style to all boxes in the tree.<br/>
        /// If the html tag has style defined for each apply that style to the css box of the tag.<br/>
        /// If the html tag has "class" attribute and the class name has style defined apply that style on the tag css box.<br/>
        /// If the html tag has "style" attribute parse it and apply the parsed style on the tag css box.<br/>
        /// If the html tag is "style" tag parse it content and add to the css data for all future tags parsing.<br/>
        /// 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.<br/>
        /// </summary>
        /// <param name="box"></param>
        /// <param name="bridge"> </param>
        /// <param name="cssData"> </param>
        /// <param name="cssDataChanged">check if the css data has been modified by the handled html not to change the base css data</param>
        private static void CascadeStyles(CssBox box, object bridge, ref CssData cssData, ref bool cssDataChanged)
        {
            box.InheritStyle();

            if (box.HtmlTag != null)
            {
                // try assign style using the html element tag
                AssignCssBlocks(box, cssData, box.HtmlTag.Name);

                // try assign style using the "class" attribute of the html element
                if (box.HtmlTag.HasAttribute("class"))
                {
                    AssignCssBlocks(box, cssData, "." + box.HtmlTag.Attributes["class"]);
                    AssignCssBlocks(box, cssData, box.HtmlTag.Name + "." + box.HtmlTag.Attributes["class"]);
                }

                // try assign style using the "id" attribute of the html element
                if (box.HtmlTag.HasAttribute("id"))
                {
                    AssignCssBlocks(box, cssData, "#" + box.HtmlTag.Attributes["id"]);
                }

                HtmlParser.TranslateAttributes(box.HtmlTag, box);

                // Check for the style="" attribute
                if (box.HtmlTag.HasAttribute("style"))
                {
                    var block = CssParser.ParseCssBlockImp(box.HtmlTag.Name, box.HtmlTag.Attributes["style"]);
                    AssignCssBlock(box, block);
                }

                // Check for the <style> tag
                if (box.HtmlTag.Name.Equals("style", StringComparison.CurrentCultureIgnoreCase) && box.Boxes.Count == 1)
                {
                    CloneCssData(ref cssData, ref cssDataChanged);
                    CssParser.ParseStyleSheet(cssData, box.Boxes[0].Text);
                }

                // Check for the <link rel=stylesheet> tag
                if (box.HtmlTag.Name.Equals("link", StringComparison.CurrentCultureIgnoreCase) &&
                    box.GetAttribute("rel", string.Empty).Equals("stylesheet", StringComparison.CurrentCultureIgnoreCase))
                {
                    CloneCssData(ref cssData, ref cssDataChanged);
                    var styleSheet = CssValueParser.GetStyleSheet(box.GetAttribute("href", string.Empty), bridge);
                    CssParser.ParseStyleSheet(cssData, styleSheet);
                }
            }

            foreach (var childBox in box.Boxes)
            {
                CascadeStyles(childBox, bridge, ref cssData, ref cssDataChanged);
            }
        }
示例#2
0
        /// <summary>
        /// Applies style to all boxes in the tree.<br/>
        /// If the html tag has style defined for each apply that style to the css box of the tag.<br/>
        /// If the html tag has "class" attribute and the class name has style defined apply that style on the tag css box.<br/>
        /// If the html tag has "style" attribute parse it and apply the parsed style on the tag css box.<br/>
        /// </summary>
        /// <param name="box">the box to apply the style to</param>
        /// <param name="cssData">the style data for the html</param>
        private void CascadeApplyStyles(CssBox box, CssData cssData)
        {
            box.InheritStyle();

            if (box.HtmlTag != null)
            {
                // try assign style using all wildcard
                AssignCssBlocks(box, cssData, "*");

                // try assign style using the html element tag
                AssignCssBlocks(box, cssData, box.HtmlTag.Name);

                // try assign style using the "class" attribute of the html element
                if (box.HtmlTag.HasAttribute("class"))
                {
                    AssignClassCssBlocks(box, cssData);
                }

                // try assign style using the "id" attribute of the html element
                if (box.HtmlTag.HasAttribute("id"))
                {
                    var id = box.HtmlTag.TryGetAttribute("id");
                    AssignCssBlocks(box, cssData, "#" + id);
                }

                TranslateAttributes(box.HtmlTag, box);

                // Check for the style="" attribute
                if (box.HtmlTag.HasAttribute("style"))
                {
                    var block = _cssParser.ParseCssBlock(box.HtmlTag.Name, box.HtmlTag.TryGetAttribute("style"));
                    if (block != null)
                    {
                        AssignCssBlock(box, block);
                    }
                }
            }

            // cascade text decoration only to boxes that actually have text so it will be handled correctly.
            if (box.TextDecoration != String.Empty && box.Text == null)
            {
                foreach (var childBox in box.Boxes)
                {
                    childBox.TextDecoration = box.TextDecoration;
                }
                box.TextDecoration = string.Empty;
            }

            foreach (var childBox in box.Boxes)
            {
                CascadeApplyStyles(childBox, cssData);
            }
        }
示例#3
0
        /// <summary>
        /// Split bad box that has inline and block boxes into two parts, the left - before the block box
        /// and right - after the block box.
        /// </summary>
        /// <param name="parentBox">the parent box that has the problem</param>
        /// <param name="badBox">the box to split into different boxes</param>
        /// <param name="leftBlock">the left block box that is created for the split</param>
        private static void CorrectBlockSplitBadBox(CssBox parentBox, CssBox badBox, CssBox leftBlock)
        {
            var leftbox = CssBox.CreateBox(leftBlock, badBox.HtmlTag);

            leftbox.InheritStyle(badBox, true);

            while (badBox.Boxes[0].IsInline && ContainsInlinesOnlyDeep(badBox.Boxes[0]))
            {
                badBox.Boxes[0].ParentBox = leftbox;
            }

            var splitBox = badBox.Boxes[0];

            if (!ContainsInlinesOnlyDeep(splitBox))
            {
                CorrectBlockSplitBadBox(parentBox, splitBox, leftBlock);
                splitBox.ParentBox = null;
            }
            else
            {
                splitBox.ParentBox = parentBox;
            }

            if (badBox.Boxes.Count > 0)
            {
                CssBox rightBox = null;
                if (splitBox.ParentBox != null || parentBox.Boxes.Count < 2)
                {
                    rightBox = CssBox.CreateBox(parentBox, badBox.HtmlTag);
                    rightBox.InheritStyle(badBox, true);

                    if (parentBox.Boxes.Count > 2)
                    {
                        rightBox.SetBeforeBox(parentBox.Boxes[1]);
                    }

                    splitBox.SetBeforeBox(rightBox);
                }
                else if (parentBox.Boxes.Count > 2)
                {
                    rightBox = parentBox.Boxes[2];
                }

                while (badBox.Boxes.Count > 0)
                {
                    badBox.Boxes[0].ParentBox = rightBox;
                }
            }
            else if (splitBox.ParentBox != null && parentBox.Boxes.Count > 1)
            {
                splitBox.SetBeforeBox(parentBox.Boxes[1]);
            }
        }
示例#4
0
        /// <summary>
        /// Applies style to all boxes in the tree.<br/>
        /// If the html tag has style defined for each apply that style to the css box of the tag.<br/>
        /// If the html tag has "class" attribute and the class name has style defined apply that style on the tag css box.<br/>
        /// If the html tag has "style" attribute parse it and apply the parsed style on the tag css box.<br/>
        /// If the html tag is "style" tag parse it content and add to the css data for all future tags parsing.<br/>
        /// 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.<br/>
        /// </summary>
        /// <param name="box"></param>
        /// <param name="htmlContainer">the html container to use for reference resolve</param>
        /// <param name="cssData"> </param>
        /// <param name="cssDataChanged">check if the css data has been modified by the handled html not to change the base css data</param>
        private static void CascadeStyles(CssBox box, HtmlContainer htmlContainer, ref CssData cssData, ref bool cssDataChanged)
        {
            box.InheritStyle();

            if (box.HtmlTag != null)
            {
                // try assign style using the html element tag
                AssignCssBlocks(box, cssData, box.HtmlTag.Name);

                // try assign style using the "class" attribute of the html element
                if (box.HtmlTag.HasAttribute("class"))
                {
                    AssignClassCssBlocks(box, cssData);
                }

                // try assign style using the "id" attribute of the html element
                if (box.HtmlTag.HasAttribute("id"))
                {
                    var id = box.HtmlTag.TryGetAttribute("id");
                    AssignCssBlocks(box, cssData, "#" + id);
                }

                TranslateAttributes(box.HtmlTag, box);

                // Check for the style="" attribute
                if (box.HtmlTag.HasAttribute("style"))
                {
                    var block = CssParser.ParseCssBlock(box.HtmlTag.Name, box.HtmlTag.TryGetAttribute("style"));
                    AssignCssBlock(box, block);
                }

                // Check for the <style> tag
                if (box.HtmlTag.Name.Equals("style", StringComparison.CurrentCultureIgnoreCase) && box.Boxes.Count == 1)
                {
                    CloneCssData(ref cssData, ref cssDataChanged);
                    CssParser.ParseStyleSheet(cssData, box.Boxes[0].Text.CutSubstring());
                }

                // Check for the <link rel=stylesheet> tag
                if (box.HtmlTag.Name.Equals("link", StringComparison.CurrentCultureIgnoreCase) &&
                    box.GetAttribute("rel", string.Empty).Equals("stylesheet", StringComparison.CurrentCultureIgnoreCase))
                {
                    CloneCssData(ref cssData, ref cssDataChanged);
                    var styleSheet = StylesheetLoadHelper.LoadStylesheet(htmlContainer, box.GetAttribute("href", string.Empty), box.HtmlTag.Attributes);
                    CssParser.ParseStyleSheet(cssData, styleSheet);
                }
            }

            foreach (var childBox in box.Boxes)
            {
                CascadeStyles(childBox, htmlContainer, ref cssData, ref cssDataChanged);
            }
        }
示例#5
0
        /// <summary>
        /// Split bad box that has inline and block boxes into two parts, the left - before the block box
        /// and right - after the block box.
        /// </summary>
        /// <param name="parentBox">the parent box that has the problem</param>
        /// <param name="badBox">the box to split into different boxes</param>
        /// <param name="leftBlock">the left block box that is created for the split</param>
        private static void CorrectBlockSplitBadBox(CssBox parentBox, CssBox badBox, CssBox leftBlock)
        {
            CssBox leftbox = null;

            while (badBox.Boxes[0].IsInline && ContainsInlinesOnlyDeep(badBox.Boxes[0]))
            {
                if (leftbox == null)
                {
                    // if there is no elements in the left box there is no reason to keep it
                    leftbox = CssBox.CreateBox(leftBlock, badBox.HtmlTag);
                    leftbox.InheritStyle(badBox, true);
                }
                badBox.Boxes[0].ParentBox = leftbox;
            }

            var splitBox = badBox.Boxes[0];

            if (!ContainsInlinesOnlyDeep(splitBox))
            {
                CorrectBlockSplitBadBox(parentBox, splitBox, leftBlock);
                splitBox.ParentBox = null;
            }
            else
            {
                splitBox.ParentBox = parentBox;
            }

            if (badBox.Boxes.Count > 0)
            {
                CssBox rightBox;
                if (splitBox.ParentBox != null || parentBox.Boxes.Count < 3)
                {
                    rightBox = CssBox.CreateBox(parentBox, badBox.HtmlTag);
                    rightBox.InheritStyle(badBox, true);

                    if (parentBox.Boxes.Count > 2)
                    {
                        rightBox.SetBeforeBox(parentBox.Boxes[1]);
                    }

                    if (splitBox.ParentBox != null)
                    {
                        splitBox.SetBeforeBox(rightBox);
                    }
                }
                else
                {
                    rightBox = parentBox.Boxes[2];
                }

                rightBox.SetAllBoxes(badBox);
            }
            else if (splitBox.ParentBox != null && parentBox.Boxes.Count > 1)
            {
                splitBox.SetBeforeBox(parentBox.Boxes[1]);
                if (splitBox.HtmlTag != null && splitBox.HtmlTag.Name == "br" && (leftbox != null || leftBlock.Boxes.Count > 1))
                {
                    splitBox.Display = CssConstants.Inline;
                }
            }
        }
示例#6
0
        /// <summary>
        /// Split bad box that has inline and block boxes into two parts, the left - before the block box
        /// and right - after the block box.
        /// </summary>
        /// <param name="parentBox">the parent box that has the problem</param>
        /// <param name="badBox">the box to split into different boxes</param>
        /// <param name="leftBlock">the left block box that is created for the split</param>
        private static void CorrectBlockSplitBadBox(CssBox parentBox, CssBox badBox, CssBox leftBlock)
        {
            CssBox leftbox = null;

            //This checks if the first child of badbox isInline and if it has only inline elements
            while (badBox.Boxes[0].IsInline && ContainsInlinesOnlyDeep(badBox.Boxes[0]))
            {
                if (leftbox == null)
                {
                    // if there is no elements in the left box there is no reason to keep it
                    leftbox = CssBox.CreateBox(leftBlock, badBox.HtmlTag);
                    leftbox.InheritStyle(badBox, true);
                }
                //puts the HTML of leftbox (which is a new box?) into the parent ofbadbox (it's previous parent)
                badBox.Boxes[0].ParentBox = leftbox;
            }

            var splitBox = badBox.Boxes[0];

            if (!ContainsInlinesOnlyDeep(splitBox))
            {
                CorrectBlockSplitBadBox(parentBox, splitBox, leftBlock);
                splitBox.ParentBox = null;
            }
            else
            {
                splitBox.ParentBox = parentBox;
            }

            if (badBox.Boxes.Count > 0)
            {
                CssBox rightBox;
                if (splitBox.ParentBox != null || parentBox.Boxes.Count < 3)
                {
                    rightBox = CssBox.CreateBox(parentBox, badBox.HtmlTag);
                    rightBox.InheritStyle(badBox, true);

                    if (parentBox.Boxes.Count > 2)
                    {
                        rightBox.SetBeforeBox(parentBox.Boxes[1]);
                    }

                    if (splitBox.ParentBox != null)
                    {
                        splitBox.SetBeforeBox(rightBox);
                    }
                }
                else
                {
                    rightBox = parentBox.Boxes[2];
                }

                rightBox.SetAllBoxes(badBox);
            }
            else if (splitBox.ParentBox != null && parentBox.Boxes.Count > 1)
            {
                splitBox.SetBeforeBox(parentBox.Boxes[1]);
                if (splitBox.HtmlTag != null && splitBox.HtmlTag.Name == "br" && (leftbox != null || leftBlock.Boxes.Count > 1))
                {
                    splitBox.Display = CssConstants.Inline;
                }
            }
        }
示例#7
0
        /// <summary>
        /// Split bad box that has inline and block boxes into two parts, the left - before the block box
        /// and right - after the block box.
        /// </summary>
        /// <param name="parentBox">the parent box that has the problem</param>
        /// <param name="badBox">the box to split into different boxes</param>
        /// <param name="leftBlock">the left block box that is created for the split</param>
        private static void CorrectBlockSplitBadBox(CssBox parentBox, CssBox badBox, CssBox leftBlock)
        {
            CssBox leftbox = CssBox.CreateBox(leftBlock, badBox.HtmlTag);

            leftbox.InheritStyle(badBox, true);

            bool hadLeft = false;

            while (badBox.Boxes[0].IsInline && ContainsInlinesOnlyDeep(badBox.Boxes[0]))
            {
                hadLeft = true;
                badBox.Boxes[0].ParentBox = leftbox;
            }

            CssBox splitBox = badBox.Boxes[0];

            if (!ContainsInlinesOnlyDeep(splitBox))
            {
                CorrectBlockSplitBadBox(parentBox, splitBox, leftBlock);
                splitBox.ParentBox = null;
            }
            else
            {
                splitBox.ParentBox = parentBox;
            }

            if (badBox.Boxes.Count > 0)
            {
                CssBox rightBox;
                if (splitBox.ParentBox != null || parentBox.Boxes.Count < 3)
                {
                    rightBox = CssBox.CreateBox(parentBox, badBox.HtmlTag);
                    rightBox.InheritStyle(badBox, true);

                    if (parentBox.Boxes.Count > 2)
                    {
                        rightBox.SetBeforeBox(parentBox.Boxes[1]);
                    }

                    if (splitBox.ParentBox != null)
                    {
                        splitBox.SetBeforeBox(rightBox);
                    }
                }
                else
                {
                    rightBox = parentBox.Boxes[2];
                }

                while (badBox.Boxes.Count > 0)
                {
                    badBox.Boxes[0].ParentBox = rightBox;
                }
            }
            else if (splitBox.ParentBox != null && parentBox.Boxes.Count > 1)
            {
                splitBox.SetBeforeBox(parentBox.Boxes[1]);
                if (splitBox.HtmlTag != null && splitBox.HtmlTag.Name == "br" && (hadLeft || leftBlock.Boxes.Count > 1))
                {
                    splitBox.Display = CssConstants.Inline;
                }
            }
        }
示例#8
0
        /// <summary>
        /// Applies style to all boxes in the tree.<br/>
        /// If the html tag has style defined for each apply that style to the css box of the tag.<br/>
        /// If the html tag has "class" attribute and the class name has style defined apply that style on the tag css box.<br/>
        /// If the html tag has "style" attribute parse it and apply the parsed style on the tag css box.<br/>
        /// If the html tag is "style" tag parse it content and add to the css data for all future tags parsing.<br/>
        /// 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.<br/>
        /// </summary>
        /// <param name="box"></param>
        /// <param name="htmlContainer">the html container to use for reference resolve</param>
        /// <param name="cssData"> </param>
        /// <param name="cssDataChanged">check if the css data has been modified by the handled html not to change the base css data</param>
        private static void CascadeStyles(CssBox box, HtmlContainer htmlContainer, ref CssData cssData,
                                          ref bool cssDataChanged)
        {
            box.InheritStyle();

            if (box.HtmlTag != null)
            {
                // try assign style using the html element tag
                AssignCssBlocks(box, cssData, box.HtmlTag.Name);

                // try assign style using the "class" attribute of the html element
                if (box.HtmlTag.HasAttribute("class"))
                {
                    AssignClassCssBlocks(box, cssData);
                }

                // try assign style using the "id" attribute of the html element
                if (box.HtmlTag.HasAttribute("id"))
                {
                    string id = box.HtmlTag.TryGetAttribute("id");
                    AssignCssBlocks(box, cssData, "#" + id);
                }

                TranslateAttributes(box.HtmlTag, box);

                // Check for the style="" attribute
                if (box.HtmlTag.HasAttribute("style"))
                {
                    CssBlock block = CssParser.ParseCssBlock(box.HtmlTag.Name, box.HtmlTag.TryGetAttribute("style"));
                    AssignCssBlock(box, block);
                }

                // Check for the <style> tag
                if (box.HtmlTag.Name.Equals("style", StringComparison.CurrentCultureIgnoreCase) && box.Boxes.Count == 1)
                {
                    CloneCssData(ref cssData, ref cssDataChanged);
                    CssParser.ParseStyleSheet(cssData, box.Boxes[0].Text.CutSubstring());
                }

                // Check for the <link rel=stylesheet> 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);
                    }
                }
            }

            // cascade text decoration only to boxes that actually have text so it will be handled correctly.
            if (box.TextDecoration != String.Empty && box.Text == null)
            {
                foreach (CssBox childBox in box.Boxes)
                {
                    childBox.TextDecoration = box.TextDecoration;
                }
                box.TextDecoration = string.Empty;
            }

            foreach (CssBox childBox in box.Boxes)
            {
                CascadeStyles(childBox, htmlContainer, ref cssData, ref cssDataChanged);
            }
        }