Ejemplo n.º 1
0
        /// <summary>
        /// do layout line formatting context
        /// </summary>
        /// <param name="hostBlock"></param>
        /// <param name="lay"></param>
        public static void DoLayoutLinesContext(CssBox hostBlock, LayoutVisitor lay)
        {
            //this in line formatting context
            //*** hostBlock must confirm that it has all inline children     
            hostBlock.SetHeightToZero();
            hostBlock.ResetLineBoxes();
            //----------------------------------------------------------------------------------------
            float limitLocalRight = hostBlock.VisualWidth - (hostBlock.ActualPaddingRight + hostBlock.ActualBorderRightWidth);
            float localX = hostBlock.ActualTextIndent + hostBlock.ActualPaddingLeft + hostBlock.ActualBorderLeftWidth;
            float localY = hostBlock.ActualPaddingTop + hostBlock.ActualBorderTopWidth;
            //----------------------------------------------------------------------------------------

            if (lay.HasFloatBoxInContext)
            {
                var recentLeftFloatBox = lay.LatestLeftFloatBox;
                var recentRightFloatBox = lay.LatestRightFloatBox;
                var latestSibling = lay.LatestSiblingBox;
                if (latestSibling != null)
                {
                    //check latest sibling first 
                    if (hostBlock.Float == CssFloat.None)
                    {
                        if (recentLeftFloatBox != null)
                        {
                            if (hostBlock.LocalY < recentLeftFloatBox.LocalVisualBottom)
                            {
                                localX = recentLeftFloatBox.LocalVisualRight;
                            }
                        }
                        else
                        {
                        }
                    }
                }
                else
                {
                    if (hostBlock.Float == CssFloat.None)
                    {
                        if (recentLeftFloatBox != null)
                        {
                            localX = recentLeftFloatBox.LocalVisualRight;
                        }
                        if (recentRightFloatBox != null)
                        {
                            limitLocalRight = recentRightFloatBox.LocalX;
                        }
                    }
                    //check if need newline or not 
                }
            }

            int interlineSpace = 0;
            //First line box 

            var line = new CssLineBox(hostBlock);
            hostBlock.AddLineBox(line);
            //****
            var floatCtx = new FloatFormattingContext();
            FlowBoxContentIntoHostLineFmtContext(lay, hostBlock, hostBlock,
                  limitLocalRight, localX,
                  ref line, ref localX, ref floatCtx);
            //**** 
            // if width is not restricted we need to lower it to the actual width
            if (hostBlock.VisualWidth + lay.ContainerBlockGlobalX >= CssBoxConstConfig.BOX_MAX_RIGHT)
            {
                float newWidth = localX + hostBlock.ActualPaddingRight + hostBlock.ActualBorderRightWidth;// CssBox.MAX_RIGHT - (args.ContainerBlockGlobalX + blockBox.LocalX);
                if (newWidth <= CSS_OFFSET_THRESHOLD)
                {
                    newWidth = CSS_OFFSET_THRESHOLD;
                }
                hostBlock.SetVisualWidth(newWidth);
            }
            //--------------------- 
            float maxLineWidth = 0;
            if (hostBlock.CssDirection == CssDirection.Rtl)
            {
                CssTextAlign textAlign = hostBlock.CssTextAlign;
                foreach (CssLineBox linebox in hostBlock.GetLineBoxIter())
                {
                    ApplyAlignment(linebox, textAlign, lay);
                    ApplyRightToLeft(linebox); //*** 
                    linebox.CloseLine(lay); //*** 
                    linebox.CachedLineTop = localY;
                    localY += linebox.CacheLineHeight + interlineSpace; // + interline space?
                    if (maxLineWidth < linebox.CachedExactContentWidth)
                    {
                        maxLineWidth = linebox.CachedExactContentWidth;
                    }
                }
            }
            else
            {
                CssTextAlign textAlign = hostBlock.CssTextAlign;
                foreach (CssLineBox linebox in hostBlock.GetLineBoxIter())
                {
                    ApplyAlignment(linebox, textAlign, lay);
                    linebox.CloseLine(lay); //***
                    linebox.CachedLineTop = localY;
                    localY += linebox.CacheLineHeight + interlineSpace;
                    if (maxLineWidth < linebox.CachedExactContentWidth)
                    {
                        maxLineWidth = linebox.CachedExactContentWidth;
                    }
                }
            }

            hostBlock.SetVisualHeight(localY + hostBlock.ActualPaddingBottom + hostBlock.ActualBorderBottomWidth);
            //final 
            SetFinalInnerContentSize(hostBlock, maxLineWidth, hostBlock.VisualHeight, lay);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Recursively flows the content of the box using the inline model
        /// </summary>
        /// <param name="lay"></param>
        /// <param name="hostBox"></param>
        /// <param name="srcBox"></param>
        /// <param name="limitLocalRight"></param>
        /// <param name="firstRunStartX"></param>
        /// <param name="hostLine"></param>
        /// <param name="cx"></param>
        static void FlowBoxContentIntoHostLineFmtContext(
          LayoutVisitor lay,
          CssBox hostBox, //target host box that contains line formatting context
          CssBox srcBox, //src that has  runs /splitable content) to flow into hostBox line model
          float limitLocalRight,
          float firstRunStartX,
          ref CssLineBox hostLine,
          ref float cx,
          ref FloatFormattingContext floatCtx)
        {
            //recursive *** 
            //-------------------------------------------------------------------- 
            var oX = cx;
            if (srcBox.HasOnlyRuns)
            {
                //condition 3 

                FlowRunsIntoHost(lay, hostBox, srcBox, srcBox, 0,
                     limitLocalRight, firstRunStartX,
                     0, 0,
                     CssBox.UnsafeGetRunList(srcBox),
                     ref hostLine, ref cx
                     );
            }
            else
            {
                int childNumber = 0;
                var ifonts = lay.SampleIFonts;
                CssBoxCollection children = CssBox.UnsafeGetChildren(srcBox);
                var cNode = children.GetFirstLinkedNode();
                while (cNode != null)
                {
                    float leftMostSpace = 0, rightMostSpace = 0;
                    CssBox b = cNode.Value;
                    //if b has absolute pos then it is removed from the flow 
                    if (b.NeedComputedValueEvaluation)
                    {
                        b.ReEvaluateComputedValues(ifonts, hostBox);
                    }
                    b.MeasureRunsSize(lay);
#if DEBUG
                    if (b.Position == CssPosition.Absolute)
                    {
                        //should not found here!
                        throw new NotSupportedException();
                    }
#endif


                    cx += leftMostSpace;
                    if (b.CssDisplayInside == CssDisplayInside.FlowRoot)//eg. inline block
                    {
                        //--------
                        // if inside display is FlowRoot *** 
                        //--------- 

                        //outside -> inline
                        //inside -> flow-root

                        //can't split 
                        //create 'block-run'  
                        CssLayoutEngine.PerformContentLayout(b, lay);
                        CssBlockRun blockRun = b.JustBlockRun;
                        if (blockRun == null)
                        {
                            blockRun = new CssBlockRun(b);
                            blockRun.SetOwner(srcBox);
                            b.JustBlockRun = blockRun;
                        }


                        if (b.Width.IsEmptyOrAuto)
                        {
                            blockRun.SetSize(CssBox.GetLatestCachedMinWidth(b), b.VisualHeight);
                        }
                        else
                        {
                            blockRun.SetSize(b.VisualWidth, b.VisualHeight);
                        }

                        b.SetLocation(b.LocalX, 0); //because of inline***
                        FlowRunsIntoHost(lay, hostBox, srcBox, b, childNumber,
                            limitLocalRight, firstRunStartX,
                            leftMostSpace, rightMostSpace,
                            new List<CssRun>() { b.JustBlockRun },
                            ref hostLine, ref cx);
                    }
                    else if (b.CssDisplayOutside == CssDisplayOutside.Block)
                    {
                        //warning : this code block not follow w3c spec ***


                        CssLayoutEngine.PerformContentLayout(b, lay);
                        CssBlockRun blockRun = b.JustBlockRun;
                        if (blockRun == null)
                        {
                            blockRun = new CssBlockRun(b);
                            blockRun.SetOwner(srcBox);
                            b.JustBlockRun = blockRun;
                        }

                        //set width to full ***
                        blockRun.SetSize(hostBox.GetClientWidth(), b.VisualHeight);
                        b.SetLocation(b.LocalX, 0); //because of inline***
                        FlowRunsIntoHost(lay, hostBox, srcBox, b, childNumber,
                            limitLocalRight, firstRunStartX,
                            leftMostSpace, rightMostSpace,
                            new List<CssRun>() { b.JustBlockRun },
                            ref hostLine, ref cx);
                    }
                    else if (b.HasOnlyRuns)
                    {
                        switch (b.Float)
                        {
                            default:
                            case CssFloat.None:
                                {
                                    FlowRunsIntoHost(lay, hostBox, srcBox, b, childNumber,
                                        limitLocalRight, firstRunStartX,
                                        leftMostSpace, rightMostSpace,
                                        CssBox.UnsafeGetRunList(b),
                                        ref hostLine, ref cx);
                                }
                                break;
                            case CssFloat.Left:
                                {
                                    //float is out of flow item 
                                    //1. current line is shortening
                                    //2. add 'b' to special container ***  

                                    var newAnonBlock = new CssFloatContainerBox(
                                        CssBox.UnsafeGetBoxSpec(b),
                                        b.RootGfx, CssDisplay.Block);
                                    newAnonBlock.ReEvaluateComputedValues(ifonts, hostBox);
                                    //add to abs layer
                                    hostBox.AppendToAbsoluteLayer(newAnonBlock);
                                    newAnonBlock.ResetLineBoxes();
                                    float localX1 = 0;
                                    var line = new CssLineBox(newAnonBlock);
                                    newAnonBlock.AddLineBox(line);
                                    var newFloatCtx = new FloatFormattingContext();
                                    FlowBoxContentIntoHostLineFmtContext(lay, newAnonBlock, b,
                                        limitLocalRight, 0,
                                        ref line, ref localX1, ref newFloatCtx);
                                    float localY = 0;
                                    int interlineSpace = 0;
                                    float maxLineWidth = 0;
                                    CssTextAlign textAlign = newAnonBlock.CssTextAlign;
                                    foreach (CssLineBox linebox in newAnonBlock.GetLineBoxIter())
                                    {
                                        ApplyAlignment(linebox, textAlign, lay);
                                        linebox.CloseLine(lay); //*** 
                                        linebox.CachedLineTop = localY;
                                        localY += linebox.CacheLineHeight + interlineSpace;
                                        if (maxLineWidth < linebox.CachedExactContentWidth)
                                        {
                                            maxLineWidth = linebox.CachedExactContentWidth;
                                        }
                                    }

                                    float hostSizeW = hostBox.VisualWidth;
                                    SetFinalInnerContentSize(newAnonBlock, maxLineWidth, localY, lay);
                                    //need to adjust line box   

                                    //TODO: review here!, 
                                    if (hostLine.CanDoMoreLeftOffset(newAnonBlock.InnerContentWidth, limitLocalRight))
                                    {
                                        hostLine.DoLeftOffset(newAnonBlock.InnerContentWidth);
                                        cx = hostLine.GetRightOfLastRun();
                                        newAnonBlock.SetLocation(floatCtx.lineLeftOffset, floatCtx.offsetFloatTop); //TODO: review top location again
                                        floatCtx.lineLeftOffset = newAnonBlock.LocalX + newAnonBlock.InnerContentWidth;
                                    }
                                    else
                                    {
                                        //newline
                                        newAnonBlock.SetLocation(hostBox.GetClientLeft(), hostLine.CalculateLineHeight());
                                        floatCtx.offsetFloatTop = newAnonBlock.LocalY;
                                    }
                                }
                                break;
                            case CssFloat.Right:
                                {
                                    //float is out of flow item      
                                    //1. create new block box and then
                                    //flow content in to this new box
                                    var newAnonBlock = new CssFloatContainerBox(
                                        CssBox.UnsafeGetBoxSpec(b),
                                        b.RootGfx, CssDisplay.Block);
                                    newAnonBlock.ReEvaluateComputedValues(ifonts, hostBox);
                                    //add to abs layer
                                    hostBox.AppendToAbsoluteLayer(newAnonBlock);
                                    newAnonBlock.ResetLineBoxes();
                                    float localX1 = 0;
                                    var line = new CssLineBox(newAnonBlock);
                                    newAnonBlock.AddLineBox(line);
                                    var newFloatCtx = new FloatFormattingContext();
                                    FlowBoxContentIntoHostLineFmtContext(lay, newAnonBlock, b,
                                        limitLocalRight, 0,
                                        ref line, ref localX1, ref newFloatCtx);
                                    float localY = 0;
                                    int interlineSpace = 0;
                                    float maxLineWidth = 0;
                                    CssTextAlign textAlign = newAnonBlock.CssTextAlign;
                                    foreach (CssLineBox linebox in newAnonBlock.GetLineBoxIter())
                                    {
                                        ApplyAlignment(linebox, textAlign, lay);
                                        linebox.CloseLine(lay); //*** 
                                        linebox.CachedLineTop = localY;
                                        localY += linebox.CacheLineHeight + interlineSpace;
                                        if (maxLineWidth < linebox.CachedExactContentWidth)
                                        {
                                            maxLineWidth = linebox.CachedExactContentWidth;
                                        }
                                    }
                                    SetFinalInnerContentSize(newAnonBlock, maxLineWidth, localY, lay);
                                    //todo: review here
                                    float hostSizeW = hostBox.VisualWidth;
                                    var rightOfLastRun = hostLine.GetRightOfLastRun();
                                    if (!floatCtx.floatingOutOfLine)
                                    {
                                        if (rightOfLastRun + maxLineWidth < hostSizeW - floatCtx.lineRightOffset)
                                        {
                                            float newX = hostSizeW - (maxLineWidth + floatCtx.lineRightOffset);
                                            newAnonBlock.SetLocation(newX, floatCtx.offsetFloatTop);
                                            floatCtx.lineRightOffset = newX;
                                            floatCtx.rightFloatBox = newAnonBlock;
                                            floatCtx.floatingOutOfLine = true;
                                        }
                                        else
                                        {
                                            //start newline 
                                            float newX = hostSizeW - maxLineWidth;
                                            newAnonBlock.SetLocation(newX, floatCtx.offsetFloatTop + hostLine.CalculateLineHeight());
                                            floatCtx.lineRightOffset = newX;
                                            floatCtx.rightFloatBox = newAnonBlock;
                                            floatCtx.floatingOutOfLine = true;
                                            floatCtx.offsetFloatTop = newAnonBlock.LocalY;
                                        }
                                    }
                                    else
                                    {
                                        //out-of-line mode
                                        if (floatCtx.rightFloatBox != null)
                                        {
                                            float newX = floatCtx.rightFloatBox.LocalX - maxLineWidth;
                                            if (newX > 0)
                                            {
                                                newAnonBlock.SetLocation(newX, floatCtx.offsetFloatTop);
                                                floatCtx.lineRightOffset = newX;
                                                floatCtx.rightFloatBox = newAnonBlock;
                                                floatCtx.offsetFloatTop = newAnonBlock.LocalY;
                                            }
                                            else
                                            {  //start new line
                                                newX = hostSizeW - maxLineWidth;
                                                newAnonBlock.SetLocation(newX, floatCtx.rightFloatBox.LocalY + floatCtx.rightFloatBox.InnerContentHeight);
                                                floatCtx.lineRightOffset = newX;
                                                floatCtx.rightFloatBox = newAnonBlock;
                                                floatCtx.offsetFloatTop = newAnonBlock.LocalY + newAnonBlock.InnerContentHeight;
                                            }
                                        }
                                        else
                                        {
                                            throw new NotSupportedException();
                                        }
                                    }
                                }
                                break;
                        }
                    }
                    else
                    {
                        //go deeper  
                        //recursive *** 
                        //not new lineFormatting context
                        FlowBoxContentIntoHostLineFmtContext(lay, hostBox, b,
                                   limitLocalRight, firstRunStartX,
                                   ref hostLine, ref cx, ref floatCtx);
                    }

                    cx += rightMostSpace;
                    childNumber++;
                    //---------------------
                    cNode = cNode.Next;
                }
            }
            if (srcBox.Position == CssPosition.Relative)
            {
                //offset content relative to it 'flow' position'
                var left = CssValueParser.ConvertToPx(srcBox.Left, hostBox.VisualWidth, srcBox);
                var top = CssValueParser.ConvertToPx(srcBox.Top, hostBox.VisualWidth, srcBox);
                srcBox.SetLocation(srcBox.LocalX + left, srcBox.LocalY + top);
            }
        }