예제 #1
0
        public static Element Find_Formatting_Container(Element Target)
        {
            // Root Elements
            if (Target.parentElement is null)
            {
                return(null);
            }

            // Other Elements
            var Tree    = new DOM.TreeWalker(Target, DOM.Enums.ENodeFilterMask.SHOW_ELEMENT);
            var Current = Tree.parentNode();

            while (Current is object)
            {
                if (Current is Element currentAsElement)
                {
                    if (currentAsElement.Box.IsParticipatingInFlow)
                    {
                        return(currentAsElement);
                    }
                }
            }

            return(null);
        }
예제 #2
0
        public static Rect4f Find_Containing_Block(Element Target)
        {/* Docs: https://www.w3.org/TR/CSS22/visudet.html#containing-block-details */
            /* Root elements */
            if (Target.parentElement is null)
            {
                return(Target.ownerDocument.Viewport?.getBoundingClientRect());
            }
            /* Other elements */
            switch (Target.Style.Positioning)
            {
            case EBoxPositioning.Static:
            case EBoxPositioning.Relative:
            {
                /*
                 * For other elements, if the element's position is 'relative' or 'static',
                 * the containing block is formed by the content edge of the nearest ancestor box that is a block container or which establishes a formatting context.
                 */
                var Tree    = new DOM.TreeWalker(Target, DOM.Enums.ENodeFilterMask.SHOW_ELEMENT);
                var Current = Tree.parentNode();
                while (Current is object)
                {
                    if (Current is DOM.Element element)
                    {
                        if (element.Box.DisplayType.Outer == EOuterDisplayType.Block || element.Box.FormattingContext is object)
                        {
                            return(element.Box.Content);
                        }
                    }
                    Current = Tree.parentNode();
                }
                throw new CssException($"Cant find containing-block for element: {Target.ToString()}");
            }

            case EBoxPositioning.Fixed:
            {        /* If the element has 'position: fixed', the containing block is established by the viewport in the case of continuous media or the page area in the case of paged media. */
                Viewport view = Target.ownerDocument.Viewport;
                return(view.getBoundingClientRect());
            }

            case EBoxPositioning.Absolute:
            {
                /*
                 * If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:
                 * In the case that the ancestor is an inline element, the containing block is the bounding box around the padding boxes of the first and the last inline boxes generated for that element.
                 * In CSS 2.2, if the inline element is split across multiple lines, the containing block is undefined.
                 * Otherwise, the containing block is formed by the padding edge of the ancestor.
                 *
                 */
                var Tree    = new DOM.TreeWalker(Target, DOM.Enums.ENodeFilterMask.SHOW_ELEMENT);
                var Current = Tree.parentNode();
                while (Current is object)
                {
                    if (Current is DOM.Element ancestor)
                    {
                        if (ancestor.Style.Positioning == EBoxPositioning.Absolute || ancestor.Style.Positioning == EBoxPositioning.Relative || ancestor.Style.Positioning == EBoxPositioning.Fixed)
                        {
                            if (ancestor.Box.DisplayType.Outer == EOuterDisplayType.Inline)
                            {
                                double  top = 0, right = 0, bottom = 0, left = 0;
                                Element child;

                                // find our first inline-level element and its padding-edges
                                child = ancestor.firstElementChild;
                                while (child is object)
                                {
                                    if (child.Box.DisplayType.Outer == EOuterDisplayType.Inline)
                                    {
                                        top  = child.Box.Padding.Top;
                                        left = child.Box.Padding.Left;
                                        break;
                                    }

                                    child = child.nextElementSibling;
                                }

                                // find our last inline-level element and its padding-edges
                                child = ancestor.lastElementChild;
                                while (child is object)
                                {
                                    if (child.Box.DisplayType.Outer == EOuterDisplayType.Inline)
                                    {
                                        right  = child.Box.Padding.Right;
                                        bottom = child.Box.Padding.Bottom;
                                        break;
                                    }

                                    child = child.previousElementSibling;
                                }

                                //return new DOMRect(top, left, (right - left), (bottom - top));
                                return(new Rect4f(top, right, bottom, left));
                            }
                            else
                            {
                                return(ancestor.Box.Padding);
                            }
                        }
                    }
                    Current = Tree.parentNode();
                }
                /* If there is no such ancestor, the containing block is the initial containing block. */
                Node rootNode = Target.getRootNode();
                return((rootNode as Element).Box.Content);
            }

            default:
            {
                return(Target.parentElement?.Box.Content);
            }
            }
        }
예제 #3
0
        public static bool Is_Containing_Block_Ancestor_Of(Element A, Element B)
        {/* Docs: https://www.w3.org/TR/CSS22/visudet.html#containing-block-details */
            /* Root elements */
            if (A.parentElement is null)
            {
                return(true);
            }

            /* Other elements */
            switch (A.Style.Positioning)
            {
            case EBoxPositioning.Static:
            case EBoxPositioning.Relative:
            {
                /*
                 * For other elements, if the element's position is 'relative' or 'static',
                 * the containing block is formed by the content edge of the nearest ancestor box that is a block container or which establishes a formatting context.
                 */

                var Tree    = new DOM.TreeWalker(A, DOM.Enums.ENodeFilterMask.SHOW_ELEMENT);
                var Current = Tree.parentNode();
                while (Current is object)
                {
                    if (Current is DOM.Element element)
                    {
                        if (element.Box.DisplayType.Outer == EOuterDisplayType.Block || element.Box.FormattingContext is object)
                        {
                            return(DOMCommon.Is_Ancestor(element, B));
                        }
                    }

                    Current = Tree.parentNode();
                }

                throw new CssException($"Cant find containing-block for element: {A.ToString()}");
            }

            case EBoxPositioning.Fixed:
            {        /* If the element has 'position: fixed', the containing block is established by the viewport in the case of continuous media or the page area in the case of paged media. */
                return(true);
            }

            case EBoxPositioning.Absolute:
            {
                /*
                 * If the element has 'position: absolute', the containing block is established by the nearest ancestor with a 'position' of 'absolute', 'relative' or 'fixed', in the following way:
                 * In the case that the ancestor is an inline element, the containing block is the bounding box around the padding boxes of the first and the last inline boxes generated for that element.
                 * In CSS 2.2, if the inline element is split across multiple lines, the containing block is undefined.
                 * Otherwise, the containing block is formed by the padding edge of the ancestor.
                 *
                 */

                var Tree    = new DOM.TreeWalker(A, DOM.Enums.ENodeFilterMask.SHOW_ELEMENT);
                var Current = Tree.parentNode();
                while (Current is object)
                {
                    if (Current is DOM.Element ancestor)
                    {
                        if (ancestor.Style.Positioning == EBoxPositioning.Absolute || ancestor.Style.Positioning == EBoxPositioning.Relative || ancestor.Style.Positioning == EBoxPositioning.Fixed)
                        {
                            return(DOMCommon.Is_Ancestor(ancestor, B));
                        }
                    }

                    Current = Tree.parentNode();
                }

                /* If there is no such ancestor, the containing block is the initial containing block. */
                return(DOMCommon.Is_Ancestor(A.getRootNode(), B));
            }

            default:
            {
                return(DOMCommon.Is_Ancestor(A.parentElement, B));
            }
            }
        }