Пример #1
0
        /// <summary>This is the second pass of layout requests.
        /// It positions the element in global screen space and also fires the render events
        /// which in turn generate or reallocates mesh blocks. This call applies to all it's
        /// children elements too.</summary>
        /// <param name="relativeTo">The current style we are positioning relative to.</param>
        public void PositionGlobally(ComputedStyle relativeTo)
        {
            ComputedStyle computed = Style.Computed;

            if (computed.Display == DisplayType.None)
            {
                // Don't draw this element or it's kids.
                return;
            }

            // Position globally:
            if (computed.Position == PositionType.Fixed)
            {
                // Fixed elements are nice and simple to deal with - Their essentially absolutely positioned but relative to the html tag.

                ComputedStyle html = Document.html.style.Computed;

                if (computed.RightPositioned)
                {
                    // The right hand edge of parent minus how far from the edge minus the width.
                    computed.OffsetLeft = computed.MarginLeft + html.OffsetLeft + html.PixelWidth - computed.PositionRight - computed.PixelWidth;
                }
                else
                {
                    computed.OffsetLeft = computed.MarginLeft + html.OffsetLeft + computed.PositionLeft;
                }

                if (computed.BottomPositioned)
                {
                    computed.OffsetTop = computed.MarginTop + html.OffsetTop + html.PixelHeight - computed.PositionBottom - computed.PixelHeight;
                }
                else
                {
                    computed.OffsetTop = computed.MarginTop + html.OffsetTop + computed.PositionTop;
                }

                // Change relativeTo here - we are now hopping to this fixed objects kids.
                relativeTo = computed;
            }
            else if (computed.Position == PositionType.Relative)
            {
                // Relative to where they should have been. PositionLeft/PositionRight etc. may be zero, but not always.

                // The width of border/padding/margin + the position of the parent + the offet from the parent.
                if (relativeTo == null)
                {
                    computed.OffsetLeft = computed.MarginLeft + computed.ParentOffsetLeft;
                }
                else
                {
                    computed.OffsetLeft = computed.MarginLeft + relativeTo.StyleOffsetLeft + relativeTo.OffsetLeft + computed.ParentOffsetLeft;
                }

                if (computed.RightPositioned)
                {
                    computed.OffsetLeft -= computed.PositionRight;
                }
                else
                {
                    computed.OffsetLeft += computed.PositionLeft;
                }

                if (relativeTo == null)
                {
                    computed.OffsetTop = computed.MarginTop + computed.ParentOffsetTop;
                }
                else
                {
                    computed.OffsetTop = computed.MarginTop + relativeTo.StyleOffsetTop + relativeTo.OffsetTop + computed.ParentOffsetTop;
                }

                if (computed.BottomPositioned)
                {
                    computed.OffsetTop -= computed.PositionBottom;
                }
                else
                {
                    computed.OffsetTop += computed.PositionTop;
                }

                // Vertical alignment:
                bool tableCell = (computed.Display == DisplayType.TableCell);
                if (relativeTo != null || computed.AutoMarginY || tableCell)
                {
                    if (computed.AutoMarginY || relativeTo.VerticalAlign == VerticalAlignType.Middle || (tableCell && computed.VerticalAlign == VerticalAlignType.Middle))
                    {
                        // Similar to below - we find the gap, then add *half* of that onto OffsetTop.
                        if (tableCell)
                        {
                            // Move upwards - we're sitting on the line and want to be above it.
                            computed.OffsetTop -= (relativeTo.InnerHeight - computed.PixelHeight) / 2;
                        }
                        else
                        {
                            computed.OffsetTop += (relativeTo.InnerHeight - relativeTo.ContentHeight) / 2;
                        }
                    }
                    else if (relativeTo.VerticalAlign == VerticalAlignType.Bottom)
                    {
                        // Find the gap - parent height-contentHeight.
                        // Then simply add that onto offsetTop.
                        computed.OffsetTop += relativeTo.InnerHeight - relativeTo.ContentHeight;
                    }
                    else if (tableCell && computed.VerticalAlign == VerticalAlignType.Top)
                    {
                        // This time we find the gap and remove it - we're at the bottom by default as a td sits on the line.
                        computed.OffsetTop -= relativeTo.InnerHeight - computed.PixelHeight;
                    }
                }

                // Note: relativeTo does not change here if we're in an inline element:
                if (computed.Display != DisplayType.Inline)
                {
                    relativeTo = computed;
                }
            }
            else
            {
                // Absolute - relative to parent. It's ParentOffsetLeft/Top are both zero.

                if (computed.RightPositioned)
                {
                    // The right hand edge of parent minus how far from the edge minus the width.
                    computed.OffsetLeft = computed.MarginLeft + relativeTo.OffsetLeft - relativeTo.StyleOffsetLeft - relativeTo.ScrollLeft + relativeTo.PixelWidth - computed.PositionRight - computed.PixelWidth;
                }
                else
                {
                    computed.OffsetLeft = computed.MarginLeft + relativeTo.OffsetLeft + relativeTo.StyleOffsetLeft + relativeTo.ScrollLeft + computed.PositionLeft;
                }

                if (computed.BottomPositioned)
                {
                    computed.OffsetTop = computed.MarginTop + relativeTo.OffsetTop - relativeTo.StyleOffsetTop - relativeTo.ScrollTop + relativeTo.PixelHeight - computed.PositionBottom - computed.PixelHeight;
                }
                else
                {
                    computed.OffsetTop = computed.MarginTop + relativeTo.OffsetTop + relativeTo.StyleOffsetTop + relativeTo.ScrollTop + computed.PositionTop;
                }

                // Set relativeTo to this - this is because the kids of absolute objects are relative to the absolute object itself.
                relativeTo = computed;
            }

            // Push the transform to our stack, if we have one.
            if (computed.Transform != null)
            {
                // Add it to the stack:
                Document.Renderer.Transformations.Push(computed.Transform);
                // Update it:
                computed.Transform.RecalculateMatrix(computed);
            }

            // Great, it's good to go!
            computed.Render();

            if (KidsToRender != null || HScrollbar || VScrollbar)
            {
                BoxRegion parentBoundary = null;

                if (relativeTo == computed)
                {
                    // We changed who we're relative to.
                    // Change the clipping boundary:
                    Renderman renderer = Document.Renderer;
                    parentBoundary = renderer.ClippingBoundary;

                    renderer.SetBoundary(computed);
                }

                if (KidsToRender != null)
                {
                    for (int i = 0; i < KidsToRender.Count; i++)
                    {
                        Element child = KidsToRender[i];
                        if (child != null)
                        {
                            child.PositionGlobally(relativeTo);
                        }
                    }
                }

                if (HScrollbar)
                {
                    HorizontalScrollbar.Element.PositionGlobally(relativeTo);
                }

                if (VScrollbar)
                {
                    VerticalScrollbar.Element.PositionGlobally(relativeTo);
                }


                if (relativeTo == computed)
                {
                    // Restore the previous boundary before this one: [Note - can't use SetBoundary here as it would destroy the box.]
                    Document.Renderer.ClippingBoundary = parentBoundary;
                }
            }

            if (computed.Transform != null)
            {
                // Pop it off again:
                Document.Renderer.Transformations.Pop();
            }
        }