/// <summary>
        /// Get the table cells spacing for all the cells in the table.<br/>
        /// Used to calculate the spacing the table has in addition to regular padding and borders.
        /// </summary>
        /// <param name="tableBox">the table box to calculate the spacing for</param>
        /// <returns>the calculated spacing</returns>
        public static double GetTableSpacing(CssBox tableBox)
        {
            int count = 0;
            int columns = 0;
            foreach (var box in tableBox.Boxes)
            {
                if (box.Display == CssConstants.TableColumn)
                {
                    columns += GetSpan(box);
                }
                else if (box.Display == CssConstants.TableRowGroup)
                {
                    foreach (CssBox cr in tableBox.Boxes)
                    {
                        count++;
                        if (cr.Display == CssConstants.TableRow)
                            columns = Math.Max(columns, cr.Boxes.Count);
                    }
                }
                else if (box.Display == CssConstants.TableRow)
                {
                    count++;
                    columns = Math.Max(columns, box.Boxes.Count);
                }

                // limit the amount of rows to process for performance
                if (count > 30)
                    break;
            }

            // +1 columns because padding is between the cell and table borders
            return (columns + 1) * GetHorizontalSpacing(tableBox);
        }
Пример #2
0
 /// <summary>
 /// Clip the region the graphics will draw on by the overflow style of the containing block.<br/>
 /// Recursively travel up the tree to find containing block that has overflow style set to hidden. if not
 /// block found there will be no clipping and null will be returned.
 /// </summary>
 /// <param name="g">the graphics to clip</param>
 /// <param name="box">the box that is rendered to get containing blocks</param>
 /// <returns>true - was clipped, false - not clipped</returns>
 public static bool ClipGraphicsByOverflow(RGraphics g, CssBox box)
 {
     var containingBlock = box.ContainingBlock;
     while (true)
     {
         if (containingBlock.Overflow == CssConstants.Hidden)
         {
             var prevClip = g.GetClip();
             var rect = box.ContainingBlock.ClientRectangle;
             rect.X -= 2; // TODO:a find better way to fix it
             rect.Width += 2;
             rect.Offset(box.HtmlContainer.ScrollOffset);
             rect.Intersect(prevClip);
             g.PushClip(rect);
             return true;
         }
         else
         {
             var cBlock = containingBlock.ContainingBlock;
             if (cBlock == containingBlock)
                 return false;
             containingBlock = cBlock;
         }
     }
 }
Пример #3
0
        /// <summary>
        /// Init.
        /// </summary>
        /// <param name="parent">the parent box of this box</param>
        /// <param name="tag">the html tag data of this box</param>
        public CssBoxFrame(CssBox parent, HtmlTag tag)
            : base(parent, tag)
        {
            _imageWord = new CssRectImage(this);
            Words.Add(_imageWord);

            Uri uri;
            if (Uri.TryCreate(GetAttribute("src"), UriKind.Absolute, out uri))
            {
                if (uri.Host.IndexOf("youtube.com", StringComparison.InvariantCultureIgnoreCase) > -1)
                {
                    _isVideo = true;
                    LoadYoutubeDataAsync(uri);
                }
                else if (uri.Host.IndexOf("vimeo.com", StringComparison.InvariantCultureIgnoreCase) > -1)
                {
                    _isVideo = true;
                    LoadVimeoDataAsync(uri);
                }
            }

            if (!_isVideo)
            {
                SetErrorBorder();
            }
        }
Пример #4
0
 /// <summary>
 /// Creates a new LineBox
 /// </summary>
 public CssLineBox(CssBox ownerBox)
 {
     _rects = new Dictionary<CssBox, RRect>();
     _relatedBoxes = new List<CssBox>();
     _words = new List<CssRect>();
     _ownerBox = ownerBox;
     _ownerBox.LineBoxes.Add(this);
 }
Пример #5
0
        public CssSpacingBox(CssBox tableBox, ref CssBox extendedBox, int startRow)
            : base(tableBox, new HtmlTag("none", false, new Dictionary<string, string> { { "colspan", "1" } }))
        {
            _extendedBox = extendedBox;
            Display = CssConstants.None;

            _startRow = startRow;
            _endRow = startRow + Int32.Parse(extendedBox.GetAttribute("rowspan", "1")) - 1;
        }
Пример #6
0
        /// <summary>
        /// Check if the given box contains only inline child boxes.
        /// </summary>
        /// <param name="box">the box to check</param>
        /// <returns>true - only inline child boxes, false - otherwise</returns>
        public static bool ContainsInlinesOnly(CssBox box)
        {
            foreach (CssBox b in box.Boxes)
            {
                if (!b.IsInline)
                {
                    return false;
                }
            }

            return true;
        }
Пример #7
0
 /// <summary>
 /// Check if the given location is inside the given box deep.<br/>
 /// Check inner boxes and all lines that the given box spans to.
 /// </summary>
 /// <param name="box">the box to check</param>
 /// <param name="location">the location to check</param>
 /// <returns>true - location inside the box, false - otherwise</returns>
 public static bool IsInBox(CssBox box, RPoint location)
 {
     foreach (var line in box.Rectangles)
     {
         if (line.Value.Contains(location))
             return true;
     }
     foreach (var childBox in box.Boxes)
     {
         if (IsInBox(childBox, location))
             return true;
     }
     return false;
 }
Пример #8
0
 /// <summary>
 /// Recursively searches for the parent with the specified HTML Tag name
 /// </summary>
 /// <param name="root"></param>
 /// <param name="tagName"></param>
 /// <param name="box"></param>
 public static CssBox FindParent(CssBox root, string tagName, CssBox box)
 {
     if (box == null)
     {
         return root;
     }
     else if (box.HtmlTag != null && box.HtmlTag.Name.Equals(tagName, StringComparison.CurrentCultureIgnoreCase))
     {
         return box.ParentBox ?? root;
     }
     else
     {
         return FindParent(root, tagName, box.ParentBox);
     }
 }
 /// <summary>
 /// Draws all the border of the box with respect to style, width, etc.
 /// </summary>
 /// <param name="g">the device to draw into</param>
 /// <param name="box">the box to draw borders for</param>
 /// <param name="rect">the bounding rectangle to draw in</param>
 /// <param name="isFirst">is it the first rectangle of the element</param>
 /// <param name="isLast">is it the last rectangle of the element</param>
 public static void DrawBoxBorders(RGraphics g, CssBox box, RRect rect, bool isFirst, bool isLast)
 {
     if (rect.Width > 0 && rect.Height > 0)
     {
         if (!(string.IsNullOrEmpty(box.BorderTopStyle) || box.BorderTopStyle == CssConstants.None || box.BorderTopStyle == CssConstants.Hidden) && box.ActualBorderTopWidth > 0)
         {
             DrawBorder(Border.Top, box, g, rect, isFirst, isLast);
         }
         if (isFirst && !(string.IsNullOrEmpty(box.BorderLeftStyle) || box.BorderLeftStyle == CssConstants.None || box.BorderLeftStyle == CssConstants.Hidden) && box.ActualBorderLeftWidth > 0)
         {
             DrawBorder(Border.Left, box, g, rect, true, isLast);
         }
         if (!(string.IsNullOrEmpty(box.BorderBottomStyle) || box.BorderBottomStyle == CssConstants.None || box.BorderBottomStyle == CssConstants.Hidden) && box.ActualBorderBottomWidth > 0)
         {
             DrawBorder(Border.Bottom, box, g, rect, isFirst, isLast);
         }
         if (isLast && !(string.IsNullOrEmpty(box.BorderRightStyle) || box.BorderRightStyle == CssConstants.None || box.BorderRightStyle == CssConstants.Hidden) && box.ActualBorderRightWidth > 0)
         {
             DrawBorder(Border.Right, box, g, rect, isFirst, true);
         }
     }
 }
        /// <summary>
        /// Draw the background image of the given box in the given rectangle.<br/>
        /// Handle background-repeat and background-position values.
        /// </summary>
        /// <param name="g">the device to draw into</param>
        /// <param name="box">the box to draw its background image</param>
        /// <param name="imageLoadHandler">the handler that loads image to draw</param>
        /// <param name="rectangle">the rectangle to draw image in</param>
        public static void DrawBackgroundImage(RGraphics g, CssBox box, ImageLoadHandler imageLoadHandler, RRect rectangle)
        {
            // image size depends if specific rectangle given in image loader
            var imgSize = new RSize(imageLoadHandler.Rectangle == RRect.Empty ? imageLoadHandler.Image.Width : imageLoadHandler.Rectangle.Width,
                imageLoadHandler.Rectangle == RRect.Empty ? imageLoadHandler.Image.Height : imageLoadHandler.Rectangle.Height);

            // get the location by BackgroundPosition value
            var location = GetLocation(box.BackgroundPosition, rectangle, imgSize);

            var srcRect = imageLoadHandler.Rectangle == RRect.Empty
                ? new RRect(0, 0, imgSize.Width, imgSize.Height)
                : new RRect(imageLoadHandler.Rectangle.Left, imageLoadHandler.Rectangle.Top, imgSize.Width, imgSize.Height);

            // initial image destination rectangle
            var destRect = new RRect(location, imgSize);

            // need to clip so repeated image will be cut on rectangle
            var lRectangle = rectangle;
            lRectangle.Intersect(g.GetClip());
            g.PushClip(lRectangle);

            switch (box.BackgroundRepeat)
            {
                case "no-repeat":
                    g.DrawImage(imageLoadHandler.Image, destRect, srcRect);
                    break;
                case "repeat-x":
                    DrawRepeatX(g, imageLoadHandler, rectangle, srcRect, destRect, imgSize);
                    break;
                case "repeat-y":
                    DrawRepeatY(g, imageLoadHandler, rectangle, srcRect, destRect, imgSize);
                    break;
                default:
                    DrawRepeat(g, imageLoadHandler, rectangle, srcRect, destRect, imgSize);
                    break;
            }

            g.PopClip();
        }
Пример #11
0
 /// <summary>
 /// Cascades to the TD's the border spacified in the TABLE tag.
 /// </summary>
 /// <param name="table"></param>
 /// <param name="border"></param>
 private static void ApplyTableBorder(CssBox table, string border)
 {
     SetForAllCells(table, cell =>
     {
         cell.BorderLeftStyle = cell.BorderTopStyle = cell.BorderRightStyle = cell.BorderBottomStyle = CssConstants.Solid;
         cell.BorderLeftWidth = cell.BorderTopWidth = cell.BorderRightWidth = cell.BorderBottomWidth = border;
     });
 }
Пример #12
0
 /// <summary>
 /// Cascades to the TD's the border spacified in the TABLE tag.
 /// </summary>
 /// <param name="table"></param>
 /// <param name="padding"></param>
 private static void ApplyTablePadding(CssBox table, string padding)
 {
     var length = TranslateLength(padding);
     SetForAllCells(table, cell => cell.PaddingLeft = cell.PaddingTop = cell.PaddingRight = cell.PaddingBottom = length);
 }
Пример #13
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="box"></param>
        private void TranslateAttributes(HtmlTag tag, CssBox box)
        {
            if (tag.HasAttributes())
            {
                foreach (string att in tag.Attributes.Keys)
                {
                    string value = tag.Attributes[att];

                    switch (att)
                    {
                        case HtmlConstants.Align:
                            if (value == HtmlConstants.Left || value == HtmlConstants.Center || value == HtmlConstants.Right || value == HtmlConstants.Justify)
                                box.TextAlign = value.ToLower();
                            else
                                box.VerticalAlign = value.ToLower();
                            break;
                        case HtmlConstants.Background:
                            box.BackgroundImage = value.ToLower();
                            break;
                        case HtmlConstants.Bgcolor:
                            box.BackgroundColor = value.ToLower();
                            break;
                        case HtmlConstants.Border:
                            if (!string.IsNullOrEmpty(value) && value != "0")
                                box.BorderLeftStyle = box.BorderTopStyle = box.BorderRightStyle = box.BorderBottomStyle = CssConstants.Solid;
                            box.BorderLeftWidth = box.BorderTopWidth = box.BorderRightWidth = box.BorderBottomWidth = TranslateLength(value);

                            if (tag.Name == HtmlConstants.Table)
                            {
                                if (value != "0")
                                    ApplyTableBorder(box, "1px");
                            }
                            else
                            {
                                box.BorderTopStyle = box.BorderLeftStyle = box.BorderRightStyle = box.BorderBottomStyle = CssConstants.Solid;
                            }
                            break;
                        case HtmlConstants.Bordercolor:
                            box.BorderLeftColor = box.BorderTopColor = box.BorderRightColor = box.BorderBottomColor = value.ToLower();
                            break;
                        case HtmlConstants.Cellspacing:
                            box.BorderSpacing = TranslateLength(value);
                            break;
                        case HtmlConstants.Cellpadding:
                            ApplyTablePadding(box, value);
                            break;
                        case HtmlConstants.Color:
                            box.Color = value.ToLower();
                            break;
                        case HtmlConstants.Dir:
                            box.Direction = value.ToLower();
                            break;
                        case HtmlConstants.Face:
                            box.FontFamily = _cssParser.ParseFontFamily(value);
                            break;
                        case HtmlConstants.Height:
                            box.Height = TranslateLength(value);
                            break;
                        case HtmlConstants.Hspace:
                            box.MarginRight = box.MarginLeft = TranslateLength(value);
                            break;
                        case HtmlConstants.Nowrap:
                            box.WhiteSpace = CssConstants.NoWrap;
                            break;
                        case HtmlConstants.Size:
                            if (tag.Name.Equals(HtmlConstants.Hr, StringComparison.OrdinalIgnoreCase))
                                box.Height = TranslateLength(value);
                            else if (tag.Name.Equals(HtmlConstants.Font, StringComparison.OrdinalIgnoreCase))
                                box.FontSize = value;
                            break;
                        case HtmlConstants.Valign:
                            box.VerticalAlign = value.ToLower();
                            break;
                        case HtmlConstants.Vspace:
                            box.MarginTop = box.MarginBottom = TranslateLength(value);
                            break;
                        case HtmlConstants.Width:
                            box.Width = TranslateLength(value);
                            break;
                    }
                }
            }
        }
Пример #14
0
        /// <summary>
        /// Check if the given box contains inline and block child boxes.
        /// </summary>
        /// <param name="box">the box to check</param>
        /// <returns>true - has variant child boxes, false - otherwise</returns>
        private static bool ContainsVariantBoxes(CssBox box)
        {
            bool hasBlock = false;
            bool hasInline = false;
            for (int i = 0; i < box.Boxes.Count && (!hasBlock || !hasInline); i++)
            {
                var isBlock = !box.Boxes[i].IsInline;
                hasBlock = hasBlock || isBlock;
                hasInline = hasInline || !isBlock;
            }

            return hasBlock && hasInline;
        }
Пример #15
0
        /// <summary>
        /// Makes block boxes be among only block boxes and all inline boxes have block parent box.<br/>
        /// Inline boxes should live in a pool of Inline boxes only so they will define a single block.<br/>
        /// At the end of this process a block box will have only block siblings and inline box will have
        /// only inline siblings.
        /// </summary>
        /// <param name="box">the current box to correct its sub-tree</param>
        private static void CorrectInlineBoxesParent(CssBox box)
        {
            if (ContainsVariantBoxes(box))
            {
                for (int i = 0; i < box.Boxes.Count; i++)
                {
                    if (box.Boxes[i].IsInline)
                    {
                        var newbox = CssBox.CreateBlock(box, null, box.Boxes[i++]);
                        while (i < box.Boxes.Count && box.Boxes[i].IsInline)
                        {
                            box.Boxes[i].ParentBox = newbox;
                        }
                    }
                }
            }

            if (!DomUtils.ContainsInlinesOnly(box))
            {
                foreach (var childBox in box.Boxes)
                {
                    CorrectInlineBoxesParent(childBox);
                }
            }
        }
Пример #16
0
        /// <summary>
        /// Rearrange the DOM of the box to have block box with boxes before the inner block box and after.
        /// </summary>
        /// <param name="box">the box that has the problem</param>
        private static CssBox CorrectBlockInsideInlineImp(CssBox box)
        {
            if (box.Display == CssConstants.Inline)
                box.Display = CssConstants.Block;

            if (box.Boxes.Count > 1 || box.Boxes[0].Boxes.Count > 1)
            {
                var leftBlock = CssBox.CreateBlock(box);

                while (ContainsInlinesOnlyDeep(box.Boxes[0]))
                    box.Boxes[0].ParentBox = leftBlock;
                leftBlock.SetBeforeBox(box.Boxes[0]);

                var splitBox = box.Boxes[1];
                splitBox.ParentBox = null;

                CorrectBlockSplitBadBox(box, splitBox, leftBlock);

                // remove block that did not get any inner elements
                if (leftBlock.Boxes.Count < 1)
                    leftBlock.ParentBox = null;

                int minBoxes = leftBlock.ParentBox != null ? 2 : 1;
                if (box.Boxes.Count > minBoxes)
                {
                    // create temp box to handle the tail elements and then get them back so no deep hierarchy is created
                    var tempRightBox = CssBox.CreateBox(box, null, box.Boxes[minBoxes]);
                    while (box.Boxes.Count > minBoxes + 1)
                        box.Boxes[minBoxes + 1].ParentBox = tempRightBox;

                    return tempRightBox;
                }
            }
            else if (box.Boxes[0].Display == CssConstants.Inline)
            {
                box.Boxes[0].Display = CssConstants.Block;
            }

            return null;
        }
Пример #17
0
        /// <summary>
        /// Correct the DOM tree recursively by replacing  "br" html boxes with anonymous blocks that respect br spec.<br/>
        /// If the "br" tag is after inline box then the anon block will have zero height only acting as newline,
        /// but if it is after block box then it will have min-height of the font size so it will create empty line.
        /// </summary>
        /// <param name="box">the current box to correct its sub-tree</param>
        /// <param name="followingBlock">used to know if the br is following a box so it should create an empty line or not so it only
        /// move to a new line</param>
        private static void CorrectLineBreaksBlocks(CssBox box, ref bool followingBlock)
        {
            followingBlock = followingBlock || box.IsBlock;
            foreach (var childBox in box.Boxes)
            {
                CorrectLineBreaksBlocks(childBox, ref followingBlock);
                followingBlock = childBox.Words.Count == 0 && (followingBlock || childBox.IsBlock);
            }

            int lastBr = -1;
            CssBox brBox;
            do
            {
                brBox = null;
                for (int i = 0; i < box.Boxes.Count && brBox == null; i++)
                {
                    if (i > lastBr && box.Boxes[i].IsBrElement)
                    {
                        brBox = box.Boxes[i];
                        lastBr = i;
                    }
                    else if (box.Boxes[i].Words.Count > 0)
                    {
                        followingBlock = false;
                    }
                    else if (box.Boxes[i].IsBlock)
                    {
                        followingBlock = true;
                    }
                }

                if (brBox != null)
                {
                    brBox.Display = CssConstants.Block;
                    if (followingBlock)
                        brBox.Height = ".95em"; // TODO:a check the height to min-height when it is supported
                }
            } while (brBox != null);
        }
Пример #18
0
        /// <summary>
        /// Go over all the text boxes (boxes that have some text that will be rendered) and
        /// remove all boxes that have only white-spaces but are not 'preformatted' so they do not effect
        /// the rendered html.
        /// </summary>
        /// <param name="box">the current box to correct its sub-tree</param>
        private static void CorrectTextBoxes(CssBox box)
        {
            for (int i = box.Boxes.Count - 1; i >= 0; i--)
            {
                var childBox = box.Boxes[i];
                if (childBox.Text != null)
                {
                    // is the box has text
                    var keepBox = !childBox.Text.IsEmptyOrWhitespace();

                    // is the box is pre-formatted
                    keepBox = keepBox || childBox.WhiteSpace == CssConstants.Pre || childBox.WhiteSpace == CssConstants.PreWrap;

                    // is the box is only one in the parent
                    keepBox = keepBox || box.Boxes.Count == 1;

                    // is it a whitespace between two inline boxes
                    keepBox = keepBox || (i > 0 && i < box.Boxes.Count - 1 && box.Boxes[i - 1].IsInline && box.Boxes[i + 1].IsInline);

                    // is first/last box where is in inline box and it's next/previous box is inline
                    keepBox = keepBox || (i == 0 && box.Boxes.Count > 1 && box.Boxes[1].IsInline && box.IsInline) || (i == box.Boxes.Count - 1 && box.Boxes.Count > 1 && box.Boxes[i - 1].IsInline && box.IsInline);

                    if (keepBox)
                    {
                        // valid text box, parse it to words
                        childBox.ParseToWords();
                    }
                    else
                    {
                        // remove text box that has no
                        childBox.ParentBox.Boxes.RemoveAt(i);
                    }
                }
                else
                {
                    // recursive
                    CorrectTextBoxes(childBox);
                }
            }
        }
Пример #19
0
 /// <summary>
 /// Execute action on all the "td" cells of the table.<br/>
 /// Handle if there is "theader" or "tbody" exists.
 /// </summary>
 /// <param name="table">the table element</param>
 /// <param name="action">the action to execute</param>
 private static void SetForAllCells(CssBox table, ActionInt<CssBox> action)
 {
     foreach (var l1 in table.Boxes)
     {
         foreach (var l2 in l1.Boxes)
         {
             if (l2.HtmlTag != null && l2.HtmlTag.Name == "td")
             {
                 action(l2);
             }
             else
             {
                 foreach (var l3 in l2.Boxes)
                 {
                     action(l3);
                 }
             }
         }
     }
 }
Пример #20
0
        /// <summary>
        /// Assigns the given css classes to the given css box checking if matching.<br/>
        /// Support multiple classes in single attribute separated by whitespace.
        /// </summary>
        /// <param name="box">the css box to assign css to</param>
        /// <param name="cssData">the css data to use to get the matching css blocks</param>
        private static void AssignClassCssBlocks(CssBox box, CssData cssData)
        {
            var classes = box.HtmlTag.TryGetAttribute("class");

            var startIdx = 0;
            while (startIdx < classes.Length)
            {
                while (startIdx < classes.Length && classes[startIdx] == ' ')
                    startIdx++;

                if (startIdx < classes.Length)
                {
                    var endIdx = classes.IndexOf(' ', startIdx);

                    if (endIdx < 0)
                        endIdx = classes.Length;

                    var cls = "." + classes.Substring(startIdx, endIdx - startIdx);
                    AssignCssBlocks(box, cssData, cls);
                    AssignCssBlocks(box, cssData, box.HtmlTag.Name + cls);

                    startIdx = endIdx + 1;
                }
            }
        }
Пример #21
0
 /// <summary>
 /// Go over all image boxes and if its display style is set to block, put it inside another block but set the image to inline.
 /// </summary>
 /// <param name="box">the current box to correct its sub-tree</param>
 private static void CorrectImgBoxes(CssBox box)
 {
     for (int i = box.Boxes.Count - 1; i >= 0; i--)
     {
         var childBox = box.Boxes[i];
         if (childBox is CssBoxImage && childBox.Display == CssConstants.Block)
         {
             var block = CssBox.CreateBlock(childBox.ParentBox, null, childBox);
             childBox.ParentBox = block;
             childBox.Display = CssConstants.Inline;
         }
         else
         {
             // recursive
             CorrectImgBoxes(childBox);
         }
     }
 }
Пример #22
0
 /// <summary>
 /// Assigns the given css style blocks to the given css box checking if matching.
 /// </summary>
 /// <param name="box">the css box to assign css to</param>
 /// <param name="cssData">the css data to use to get the matching css blocks</param>
 /// <param name="className">the class selector to search for css blocks</param>
 private static void AssignCssBlocks(CssBox box, CssData cssData, string className)
 {
     var blocks = cssData.GetCssBlock(className);
     foreach (var block in blocks)
     {
         if (IsBlockAssignableToBox(box, block))
         {
             AssignCssBlock(box, block);
         }
     }
 }
Пример #23
0
        /// <summary>
        /// Correct DOM tree if there is block boxes that are inside inline blocks.<br/>
        /// Need to rearrange the tree so block box will be only the child of other block box.
        /// </summary>
        /// <param name="box">the current box to correct its sub-tree</param>
        private static void CorrectBlockInsideInline(CssBox box)
        {
            try
            {
                if (DomUtils.ContainsInlinesOnly(box) && !ContainsInlinesOnlyDeep(box))
                {
                    var tempRightBox = CorrectBlockInsideInlineImp(box);
                    while (tempRightBox != null)
                    {
                        // loop on the created temp right box for the fixed box until no more need (optimization remove recursion)
                        CssBox newTempRightBox = null;
                        if (DomUtils.ContainsInlinesOnly(tempRightBox) && !ContainsInlinesOnlyDeep(tempRightBox))
                            newTempRightBox = CorrectBlockInsideInlineImp(tempRightBox);

                        tempRightBox.ParentBox.SetAllBoxes(tempRightBox);
                        tempRightBox.ParentBox = null;
                        tempRightBox = newTempRightBox;
                    }
                }

                if (!DomUtils.ContainsInlinesOnly(box))
                {
                    foreach (var childBox in box.Boxes)
                    {
                        CorrectBlockInsideInline(childBox);
                    }
                }
            }
            catch (Exception ex)
            {
                box.HtmlContainer.ReportError(HtmlRenderErrorType.HtmlParsing, "Failed in block inside inline box correction", ex);
            }
        }
Пример #24
0
        /// <summary>
        /// Check if the given css block is assignable to the given css box.<br/>
        /// the block is assignable if it has no hierarchical selectors or if the hierarchy matches.<br/>
        /// Special handling for ":hover" pseudo-class.<br/>
        /// </summary>
        /// <param name="box">the box to check assign to</param>
        /// <param name="block">the block to check assign of</param>
        /// <returns>true - the block is assignable to the box, false - otherwise</returns>
        private static bool IsBlockAssignableToBox(CssBox box, CssBlock block)
        {
            bool assignable = true;
            if (block.Selectors != null)
            {
                assignable = IsBlockAssignableToBoxWithSelector(box, block);
            }
            else if (box.HtmlTag.Name.Equals("a", StringComparison.OrdinalIgnoreCase) && block.Class.Equals("a", StringComparison.OrdinalIgnoreCase) && !box.HtmlTag.HasAttribute("href"))
            {
                assignable = false;
            }

            if (assignable && block.Hover)
            {
                box.HtmlContainer.AddHoverBox(box, block);
                assignable = false;
            }

            return assignable;
        }
Пример #25
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;
            }
        }
Пример #26
0
        /// <summary>
        /// Check if the given css block is assignable to the given css box by validating the selector.<br/>
        /// </summary>
        /// <param name="box">the box to check assign to</param>
        /// <param name="block">the block to check assign of</param>
        /// <returns>true - the block is assignable to the box, false - otherwise</returns>
        private static bool IsBlockAssignableToBoxWithSelector(CssBox box, CssBlock block)
        {
            foreach (var selector in block.Selectors)
            {
                bool matched = false;
                while (!matched)
                {
                    box = box.ParentBox;
                    while (box != null && box.HtmlTag == null)
                        box = box.ParentBox;

                    if (box == null)
                        return false;

                    if (box.HtmlTag.Name.Equals(selector.Class, StringComparison.InvariantCultureIgnoreCase))
                        matched = true;

                    if (!matched && box.HtmlTag.HasAttribute("class"))
                    {
                        var className = box.HtmlTag.TryGetAttribute("class");
                        if (selector.Class.Equals("." + className, StringComparison.InvariantCultureIgnoreCase) || selector.Class.Equals(box.HtmlTag.Name + "." + className, StringComparison.InvariantCultureIgnoreCase))
                            matched = true;
                    }

                    if (!matched && box.HtmlTag.HasAttribute("id"))
                    {
                        var id = box.HtmlTag.TryGetAttribute("id");
                        if (selector.Class.Equals("#" + id, StringComparison.InvariantCultureIgnoreCase))
                            matched = true;
                    }

                    if (!matched && selector.DirectParent)
                        return false;
                }
            }
            return true;
        }
Пример #27
0
        /// <summary>
        /// Check if the given box contains only inline child boxes in all subtree.
        /// </summary>
        /// <param name="box">the box to check</param>
        /// <returns>true - only inline child boxes, false - otherwise</returns>
        private static bool ContainsInlinesOnlyDeep(CssBox box)
        {
            foreach (var childBox in box.Boxes)
            {
                if (!childBox.IsInline || !ContainsInlinesOnlyDeep(childBox))
                {
                    return false;
                }
            }

            return true;
        }
Пример #28
0
 /// <summary>
 /// Assigns the given css style block properties to the given css box.
 /// </summary>
 /// <param name="box">the css box to assign css to</param>
 /// <param name="block">the css block to assign</param>
 private static void AssignCssBlock(CssBox box, CssBlock block)
 {
     foreach (var prop in block.Properties)
     {
         var value = prop.Value;
         if (prop.Value == CssConstants.Inherit && box.ParentBox != null)
         {
             value = CssUtils.GetPropertyValue(box.ParentBox, prop.Key);
         }
         if (IsStyleOnElementAllowed(box, prop.Key, value))
         {
             CssUtils.SetPropertyValue(box, prop.Key, value);
         }
     }
 }
Пример #29
0
        /// <summary>
        /// Read styles defined inside the dom structure in links and style elements.<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">the box to parse style data in</param>
        /// <param name="htmlContainer">the html container to use for reference resolve</param>
        /// <param name="cssData">the style data to fill with found styles</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 void CascadeParseStyles(CssBox box, HtmlContainerInt htmlContainer, ref CssData cssData, ref bool cssDataChanged)
        {
            if (box.HtmlTag != null)
            {
                // 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);
                }

                // Check for the <style> tag
                if (box.HtmlTag.Name.Equals("style", StringComparison.CurrentCultureIgnoreCase) && box.Boxes.Count > 0)
                {
                    CloneCssData(ref cssData, ref cssDataChanged);
                    foreach (var child in box.Boxes)
                        _cssParser.ParseStyleSheet(cssData, child.Text.CutSubstring());
                }
            }

            foreach (var childBox in box.Boxes)
            {
                CascadeParseStyles(childBox, htmlContainer, ref cssData, ref cssDataChanged);
            }
        }
Пример #30
0
 /// <summary>
 /// Check if the given style is allowed to be set on the given css box.<br/>
 /// Used to prevent invalid CssBoxes creation like table with inline display style.
 /// </summary>
 /// <param name="box">the css box to assign css to</param>
 /// <param name="key">the style key to cehck</param>
 /// <param name="value">the style value to check</param>
 /// <returns>true - style allowed, false - not allowed</returns>
 private static bool IsStyleOnElementAllowed(CssBox box, string key, string value)
 {
     if (box.HtmlTag != null && key == HtmlConstants.Display)
     {
         switch (box.HtmlTag.Name)
         {
             case HtmlConstants.Table:
                 return value == CssConstants.Table;
             case HtmlConstants.Tr:
                 return value == CssConstants.TableRow;
             case HtmlConstants.Tbody:
                 return value == CssConstants.TableRowGroup;
             case HtmlConstants.Thead:
                 return value == CssConstants.TableHeaderGroup;
             case HtmlConstants.Tfoot:
                 return value == CssConstants.TableFooterGroup;
             case HtmlConstants.Col:
                 return value == CssConstants.TableColumn;
             case HtmlConstants.Colgroup:
                 return value == CssConstants.TableColumnGroup;
             case HtmlConstants.Td:
             case HtmlConstants.Th:
                 return value == CssConstants.TableCell;
             case HtmlConstants.Caption:
                 return value == CssConstants.TableCaption;
         }
     }
     return true;
 }