public static MyHtmlVisualRoot CreateHtmlVisualRootFromFullHtml( HtmlHost htmlHost, string fullHtmlString, HtmlRenderBox htmlFrgmentRenderBox) { HtmlDocument htmldoc = WebDocumentParser.ParseDocument( htmlHost, new LayoutFarm.WebDom.Parser.TextSource(fullHtmlString.ToCharArray())); //1. builder RenderTreeBuilder renderTreeBuilder = htmlHost.GetRenderTreeBuilder(); //------------------------------------------------------------------- //2. generate render tree ////build rootbox from htmldoc CssBox rootElement = renderTreeBuilder.BuildCssRenderTree(htmldoc, htmlHost.BaseStylesheet, htmlFrgmentRenderBox); //3. create small htmlContainer MyHtmlVisualRoot htmlContainer = new MyHtmlVisualRoot(htmlHost); htmlContainer.WebDocument = htmldoc; htmlContainer.SetRootCssBox(rootElement); htmlContainer.SetMaxSize(htmlFrgmentRenderBox.Width, 0); // LayoutVisitor lay = htmlHost.GetSharedHtmlLayoutVisitor(htmlContainer); htmlContainer.PerformLayout(lay); htmlHost.ReleaseHtmlLayoutVisitor(lay); htmlFrgmentRenderBox.SetHtmlContainer(htmlContainer, rootElement); return(htmlContainer); }
public static MyHtmlVisualRoot CreateHtmlVisualRoot( HtmlHost htmlHost, WebDom.WebDocument htmldoc, HtmlRenderBox htmlFrgmentRenderBox) { //1. builder RenderTreeBuilder renderTreeBuilder = htmlHost.GetRenderTreeBuilder(); //------------------------------------------------------------------- //2. generate render tree ////build rootbox from htmldoc CssBox rootElement = renderTreeBuilder.BuildCssRenderTree(htmldoc, htmlHost.BaseStylesheet, htmlFrgmentRenderBox); //3. create small htmlContainer MyHtmlVisualRoot htmlContainer = new MyHtmlVisualRoot(htmlHost); htmlContainer.WebDocument = htmldoc; htmlContainer.SetRootCssBox(rootElement); htmlContainer.SetMaxSize(htmlFrgmentRenderBox.Width, 0); //htmlContainer.SetRootRenderElement(htmlFrgmentRenderBox); LayoutVisitor lay = htmlHost.GetSharedHtmlLayoutVisitor(htmlContainer); htmlContainer.PerformLayout(lay); htmlHost.ReleaseHtmlLayoutVisitor(lay); htmlFrgmentRenderBox.SetHtmlContainer(htmlContainer, rootElement); return(htmlContainer); }
/// <summary> /// /// </summary> /// <param name="g"></param> /// <param name="tableBox"> </param> public static void PerformLayout(CssBox tableBox, float hostAvailableWidth, LayoutVisitor lay) { var table = new CssTableLayoutEngine(tableBox, hostAvailableWidth); table._tmpIFonts = lay.SampleIFonts; table.Layout(lay); table._tmpIFonts = null; }
/// <summary> /// Assigns words its width and height /// </summary> /// <param name="g">the device to use</param> public override void MeasureRunsSize(LayoutVisitor lay) { if (this.RunSizeMeasurePass) { return; } this.RunSizeMeasurePass = true; MeasureImageSize(_imgRun, lay); }
/// <summary> /// Measures the bounds of box and children, recursively.<br/> /// Performs layout of the DOM structure creating lines by set bounds restrictions. /// </summary> /// <param name="g">Device context to use</param> public void PerformLayout(LayoutVisitor lay) { //if (this.dbugMark1 > 0) //{ //} //derived class can perform its own layout algo //by override performContentLayout PerformContentLayout(lay); }
/// <summary> /// Measures the bounds of box and children, recursively.<br/> /// Performs layout of the DOM structure creating lines by set bounds restrictions.<br/> /// </summary> /// <param name="g">Device context to use</param> protected virtual void PerformContentLayout(LayoutVisitor lay) { switch (this.CssDisplay) { case Css.CssDisplay.None: { return; } default: { //others ... if (this.NeedComputedValueEvaluation) { this.ReEvaluateComputedValues(lay.SampleIFonts, lay.LatestContainingBlock); } this.MeasureRunsSize(lay); } break; case Css.CssDisplay.Block: case Css.CssDisplay.ListItem: case Css.CssDisplay.Table: case Css.CssDisplay.InlineTable: case Css.CssDisplay.TableCell: case Css.CssDisplay.Flex: case Css.CssDisplay.InlineFlex: { //this box has its own container property //this box may be used for ... // 1) line formatting context , or // 2) block formatting context if (this.NeedComputedValueEvaluation) { this.ReEvaluateComputedValues(lay.SampleIFonts, lay.LatestContainingBlock); } this.MeasureRunsSize(lay); //for general block layout CssLayoutEngine.PerformContentLayout(this, lay); } break; } //set height UpdateIfHigher(this, ExpectedHeight); //update back lay.UpdateRootSize(this); }
public LayoutFarm.HtmlBoxes.LayoutVisitor GetSharedHtmlLayoutVisitor(HtmlContainer htmlCont) { LayoutFarm.HtmlBoxes.LayoutVisitor lay = null; if (htmlLayoutVisitorStock.Count == 0) { lay = new LayoutVisitor(this.gfxplatform); } else { lay = this.htmlLayoutVisitorStock.Dequeue(); } lay.Bind(htmlCont); return(lay); }
protected override void PerformContentLayout(LayoutVisitor lay) { base.PerformContentLayout(lay); if (_listItemBulletBox != null) { //layout list item var prevSibling = lay.LatestSiblingBox; lay.LatestSiblingBox = null;//reset _listItemBulletBox.PerformLayout(lay); lay.LatestSiblingBox = prevSibling; var fRun = _listItemBulletBox.FirstRun; _listItemBulletBox.FirstRun.SetSize(fRun.Width, fRun.Height); _listItemBulletBox.FirstRun.SetLocation(_listItemBulletBox.VisualWidth - 5, this.ActualPaddingTop); } }
public void SetHtmlHost(HtmlHost htmlhost) { this.htmlhost = htmlhost; htmlhost.SetHtmlContainerUpdateHandler(htmlCont => { var updatedHtmlCont = htmlCont as MyHtmlContainer; if (updatedHtmlCont != null && !updatedHtmlCont.IsInUpdateQueue) { updatedHtmlCont.IsInUpdateQueue = true; waitingUpdateList.Add(updatedHtmlCont); } }); htmlContainer = new MyHtmlContainer(htmlhost); htmlContainer.AttachEssentialHandlers( OnRefresh, myHtmlContainer_NeedUpdateDom, OnRefresh, null); htmlLayoutVisitor = new LayoutVisitor(this.gfxPlatform); htmlLayoutVisitor.Bind(htmlContainer); //------------------------------------------------------- timer01.Interval = 20;//20ms? timer01.Tick += (s, e) => { //clear waiting int j = waitingUpdateList.Count; for (int i = 0; i < j; ++i) { var htmlCont = waitingUpdateList[i]; htmlCont.IsInUpdateQueue = false; htmlCont.RefreshDomIfNeed(); } for (int i = j - 1; i >= 0; --i) { waitingUpdateList.RemoveAt(i); } }; timer01.Enabled = true; //------------------------------------------- _htmlInputEventAdapter = new HtmlInputEventAdapter(gfxPlatform.SampleIFonts); _htmlInputEventAdapter.Bind(htmlContainer); //------------------------------------------- }
public LayoutVisitor GetSharedHtmlLayoutVisitor(HtmlContainer htmlCont) { LayoutVisitor lay = null; if (htmlLayoutVisitorStock.Count == 0) { RootGraphic rootgfx = (RootGraphic)htmlCont.RootCssBox.RootGfx; lay = new LayoutVisitor(rootgfx.IFonts); } else { lay = this.htmlLayoutVisitorStock.Dequeue(); } lay.Bind(htmlCont); return(lay); }
public LayoutVisitor GetSharedHtmlLayoutVisitor(HtmlContainer htmlCont) { LayoutVisitor lay = null; if (htmlLayoutVisitorStock.Count == 0) { RootGraphic rootgfx = (RootGraphic)htmlCont.RootCssBox.GetInternalRootGfx(); lay = new LayoutVisitor(this.GetTextService()); } else { lay = this.htmlLayoutVisitorStock.Dequeue(); } lay.Bind(htmlCont); return(lay); }
public static MyHtmlVisualRoot CreateHtmlVisualRootFromFragmentHtml( HtmlHost htmlHost, string htmlFragment, HtmlRenderBox htmlFrgmentRenderBox) { HtmlDocument htmldoc = htmlHost.CreateNewSharedHtmlDoc(); WebDom.DomElement myHtmlBodyElement = htmldoc.CreateElement("body"); htmldoc.RootNode.AddChild(myHtmlBodyElement); //data is wraped up within div? //TODO: review this, use shadow dom instead WebDom.DomElement newDivHost = htmldoc.CreateElement("div"); myHtmlBodyElement.AddChild(newDivHost); WebDocumentParser.ParseHtmlDom( new LayoutFarm.WebDom.Parser.TextSource(htmlFragment.ToCharArray()), htmldoc, newDivHost); //1. builder RenderTreeBuilder renderTreeBuilder = htmlHost.GetRenderTreeBuilder(); //------------------------------------------------------------------- //2. generate render tree CssBox rootElement = renderTreeBuilder.BuildCssRenderTree( htmldoc, htmldoc.CssActiveSheet, htmlFrgmentRenderBox); //3. create small htmlContainer MyHtmlVisualRoot htmlContainer = new MyHtmlVisualRoot(htmlHost); htmlContainer.WebDocument = newDivHost.OwnerDocument; htmlContainer.SetRootCssBox(rootElement); htmlContainer.SetMaxSize(htmlFrgmentRenderBox.Width, 0); //htmlContainer.SetRootRenderElement(htmlFrgmentRenderBox); // LayoutVisitor lay = htmlHost.GetSharedHtmlLayoutVisitor(htmlContainer); htmlContainer.PerformLayout(lay); htmlHost.ReleaseHtmlLayoutVisitor(lay); htmlFrgmentRenderBox.SetHtmlContainer(htmlContainer, rootElement); return(htmlContainer); }
public float CalculateTotalBoxBaseLine(LayoutVisitor lay) { //not correct !! float maxRunHeight = 0; CssRun maxRun = null; for (int i = _runs.Count - 1; i >= 0; --i) { CssRun run = _runs[i]; if (run.Height > maxRunHeight) { maxRun = run; maxRunHeight = run.Height; } } if (maxRun != null) { //lay.GraphicsPlatform.SampleIFonts //var f = maxRun.OwnerBox.ResolvedFont; //PixelFarm.Drawing.Fonts.ActualFont ff = f.ActualFont; //return (float)(f.Height * ff.AscentInPixels / f.Height); //return fontHeight* fontAscent / lineSpacing ) } return(0); //int j = _runs.Count; //for (int i = _runs.Count - 1; i >= 0; --i) //{ // Font ownerFont = _runs[i].OwnerBox.ActualFont; // HtmlRenderer.Drawing.FontsUtils.GetDescent( //} //return 0; //float baseline = Single.MinValue; //for (int i = _bottomUpBoxStrips.Count - 1; i >= 0; --i) //{ // baseline = Math.Max(baseline, _bottomUpBoxStrips[i].Top);//?top //} //return baseline; }
/// <summary> /// Analyzes the Table and assigns values to this CssTable object. /// To be called from the constructor /// </summary> void Layout(LayoutVisitor lay) { S1_RecursiveMeasureRunContentSize(_tableBox, lay); //------------------------------------------------ // get the table boxes into the proper fields // Insert EmptyBoxes for vertical cell spanning. List<CssBox> userColumnList = S2_PrepareTableCellBoxes(); // Determine Row and Column Count, and ColumnWidths float availableWidthForAllCells = S3_CalculateCountAndWidth(userColumnList); S4_DetermineMissingColumnWidths(availableWidthForAllCells); // S5_CalculateColumnMinWidths(lay.EpisodeId); // Check for minimum sizes (increment widths if necessary) S6_EnforceMinimumSize(); // While table width is larger than it should, and width is reducible S7_EnforceMaximumSize(); // Ensure there's no padding //_tableBox.PaddingLeft = _tableBox.PaddingTop = _tableBox.PaddingRight = _tableBox.PaddingBottom = CssLength.ZeroPx; //Actually layout cells! S8_LayoutCells(lay); }
public float CalculateTotalBoxBaseLine(LayoutVisitor lay) { //not correct !! float maxRunHeight = 0; CssRun maxRun = null; for (int i = this._runs.Count - 1; i >= 0; --i) { var run = this._runs[i]; if (run.Height > maxRunHeight) { maxRun = run; maxRunHeight = run.Height; } } if (maxRun != null) { var fontInfo = maxRun.OwnerBox.ActualFont.FontInfo; return(fontInfo.BaseLine); } return(0); //int j = this._runs.Count; //for (int i = this._runs.Count - 1; i >= 0; --i) //{ // Font ownerFont = _runs[i].OwnerBox.ActualFont; // HtmlRenderer.Drawing.FontsUtils.GetDescent( //} //return 0; //float baseline = Single.MinValue; //for (int i = _bottomUpBoxStrips.Count - 1; i >= 0; --i) //{ // baseline = Math.Max(baseline, _bottomUpBoxStrips[i].Top);//?top //} //return baseline; }
public void PerformLayout(LayoutVisitor lay) { if (this._rootBox == null) { return; } //----------------------- //reset _actualWidth = _actualHeight = 0; // if width is not restricted we set it to large value to get the actual later _rootBox.SetLocation(0, 0); _rootBox.SetVisualSize(this._maxWidth > 0 ? this._maxWidth : MAX_WIDTH, 0); CssBox.ValidateComputeValues(_rootBox); //----------------------- //LayoutVisitor layoutArgs = new LayoutVisitor(this.GraphicsPlatform, this); lay.PushContaingBlock(_rootBox); //----------------------- _rootBox.PerformLayout(lay); if (this._maxWidth <= 0.1) { // in case the width is not restricted we need to double layout, first will find the width so second can layout by it (center alignment) _rootBox.SetVisualWidth((int)Math.Ceiling(this._actualWidth)); _actualWidth = _actualHeight = 0; _rootBox.PerformLayout(lay); } lay.PopContainingBlock(); //----------------------- //TODO: review here again FloatingContextStack floatStack = lay.GetFloatingContextStack(); List <FloatingContext> totalContexts = floatStack.GetTotalContexts(); int j = totalContexts.Count; for (int i = 0; i < j; ++i) { FloatingContext floatingContext = totalContexts[i]; int floatBoxCount = floatingContext.FloatBoxCount; if (floatBoxCount == 0) { continue; } CssBox floatingOwner = floatingContext.Owner; float rfx, rfy; floatingOwner.GetGlobalLocation(out rfx, out rfy); CssBox prevParent = null; //TODO: review here again float extraAdjustX = 0; //temp fixed for (int n = 0; n < floatBoxCount; ++n) { float bfx, bfy; CssBox box = floatingContext.GetBox(n); box.GetGlobalLocation(out bfx, out bfy); //diff float nx = bfx - rfx; float ny = bfy - rfy; if (prevParent != null && prevParent != box.ParentBox) { if (n > 0) { CssBox prevFloatChild = floatingContext.GetBox(n - 1); //TODO: review here again //temp fix extraAdjustX = prevFloatChild.ActualMarginRight + box.ActualMarginLeft; ny += box.ActualMarginTop; } } box.SetLocation(nx + extraAdjustX, ny); prevParent = box.ParentBox; floatingOwner.AppendToAbsoluteLayer(box); } } OnLayoutFinished(); //----------------------- unchecked { layoutVersion++; } //----------------------- }
/// <summary> /// Measure image box size by the width\height set on the box and the actual rendered image size.<br/> /// If no image exists for the box error icon will be set. /// </summary> /// <param name="imgRun">the image word to measure</param> static void MeasureImageSize(CssImageRun imgRun, LayoutVisitor lay) { var width = imgRun.OwnerBox.Width; var height = imgRun.OwnerBox.Height; bool hasImageTagWidth = width.Number > 0 && width.UnitOrNames == Css.CssUnitOrNames.Pixels; bool hasImageTagHeight = height.Number > 0 && height.UnitOrNames == Css.CssUnitOrNames.Pixels; bool scaleImageHeight = false; if (hasImageTagWidth) { imgRun.Width = width.Number; } else if (width.Number > 0 && width.IsPercentage) { imgRun.Width = width.Number * lay.LatestContainingBlock.VisualWidth; scaleImageHeight = true; } else if (imgRun.HasUserImageContent) { imgRun.Width = imgRun.ImageRectangle == Rectangle.Empty ? imgRun.OriginalImageWidth : imgRun.ImageRectangle.Width; } else { imgRun.Width = hasImageTagHeight ? height.Number / 1.14f : 20; } var maxWidth = imgRun.OwnerBox.MaxWidth;// new CssLength(imageWord.OwnerBox.MaxWidth); if (maxWidth.Number > 0) { float maxWidthVal = -1; switch (maxWidth.UnitOrNames) { case Css.CssUnitOrNames.Percent: { maxWidthVal = maxWidth.Number * lay.LatestContainingBlock.VisualWidth; } break; case Css.CssUnitOrNames.Pixels: { maxWidthVal = maxWidth.Number; } break; } if (maxWidthVal > -1 && imgRun.Width > maxWidthVal) { imgRun.Width = maxWidthVal; scaleImageHeight = !hasImageTagHeight; } } if (hasImageTagHeight) { imgRun.Height = height.Number; } else if (imgRun.HasUserImageContent) { imgRun.Height = imgRun.ImageRectangle == Rectangle.Empty ? imgRun.OriginalImageHeight : imgRun.ImageRectangle.Height; } else { imgRun.Height = imgRun.Width > 0 ? imgRun.Width * 1.14f : 22.8f; } if (imgRun.HasUserImageContent) { // If only the width was set in the html tag, ratio the height. if ((hasImageTagWidth && !hasImageTagHeight) || scaleImageHeight) { // Divide the given tag width with the actual image width, to get the ratio. float ratio = imgRun.Width / imgRun.OriginalImageWidth; imgRun.Height = imgRun.OriginalImageHeight * ratio; } // If only the height was set in the html tag, ratio the width. else if (hasImageTagHeight && !hasImageTagWidth) { // Divide the given tag height with the actual image height, to get the ratio. float ratio = imgRun.Height / imgRun.OriginalImageHeight; imgRun.Width = imgRun.OriginalImageWidth * ratio; } } //imageWord.Height += imageWord.OwnerBox.ActualBorderBottomWidth + imageWord.OwnerBox.ActualBorderTopWidth + imageWord.OwnerBox.ActualPaddingTop + imageWord.OwnerBox.ActualPaddingBottom; }
static void DoLayoutBlocksContext(CssBox box, LayoutVisitor lay) { //block formatting context.... lay.PushContaingBlock(box); var currentLevelLatestSibling = lay.LatestSiblingBox; lay.LatestSiblingBox = null;//reset //------------------------------------------ var children = CssBox.UnsafeGetChildren(box); var cnode = children.GetFirstLinkedNode(); while (cnode != null) { var childBox = cnode.Value; //---------------------------- if (childBox.IsBrElement) { //br always block CssBox.ChangeDisplayType(childBox, Css.CssDisplay.Block); childBox.SetVisualHeight(FontDefaultConfig.DEFAULT_FONT_SIZE * 0.95f); } //----------------------------- if (childBox.OutsideDisplayIsInline) { //inline correction on-the-fly ! //1. collect consecutive inlinebox // and move to new anon block box CssBox anoForInline = CreateAnonBlock(box, childBox); anoForInline.ReEvaluateComputedValues(lay.SampleIFonts, box); var tmp = cnode.Next; do { children.Remove(childBox); anoForInline.AppendChild(childBox); if (tmp != null) { childBox = tmp.Value; if (childBox.OutsideDisplayIsInline) { tmp = tmp.Next; if (tmp == null) { children.Remove(childBox); anoForInline.AppendChild(childBox); break;//break from do while } } else { break;//break from do while } } else { break;//break from do while } } while (true); childBox = anoForInline; //------------------------ //2. move this inline box //to new anonbox cnode = tmp; //------------------------ childBox.PerformLayout(lay); if (childBox.CanBeReferenceSibling) { lay.LatestSiblingBox = childBox; } } else { //if(childBox.__aa_dbugId == 5) //{ //} childBox.PerformLayout(lay); switch (childBox.Float) { case CssFloat.Left: { childBox.IsOutOfFlowBox = true; // lay.LatestLeftFloatBox = childBox; } break; case CssFloat.Right: { childBox.IsOutOfFlowBox = true; //float box is out-of-flow box //so move it to abs layer //lay.LatestRightFloatBox = childBox; } break; } if (childBox.Float == CssFloat.None && childBox.CanBeReferenceSibling) { lay.LatestSiblingBox = childBox; } cnode = cnode.Next; } } //------------------------------------------ lay.LatestSiblingBox = currentLevelLatestSibling; lay.PopContainingBlock(); //------------------------------------------------ float boxWidth = CalculateActualWidth(box); if (lay.ContainerBlockGlobalX + boxWidth > CssBoxConstConfig.BOX_MAX_RIGHT) { } else { if (box.CssDisplay != Css.CssDisplay.TableCell) { if (box.Width.IsEmptyOrAuto) { box.SetVisualWidth(boxWidth); } } } float boxHeight = box.GetHeightAfterMarginBottomCollapse(lay.LatestContainingBlock); //TODO: review here again, box.SetVisualHeight(boxHeight); //-------------------------------------------------------------------------------- //final SetFinalInnerContentSize(box, boxWidth, boxHeight, lay); }
/// <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); }
//--------------------------- static void FlowRunsIntoHost(LayoutVisitor lay, CssBox hostBox, CssBox splitableBox, CssBox b, int childNumber, //child number of b float limitRight, float firstRunStartX, float leftMostSpace, float rightMostSpace, List<CssRun> runs, ref CssLineBox hostLine, ref float cx) { //flow runs into hostLine, create new line if need bool wrapNoWrapBox = false; CssWhiteSpace bWhiteSpace = b.WhiteSpace; bool hostBoxIsB = hostBox == b; if (bWhiteSpace == CssWhiteSpace.NoWrap && cx > firstRunStartX) { var tmpRight = cx; for (int i = runs.Count - 1; i >= 0; --i) { tmpRight += runs[i].Width; } //----------------------------------------- if (tmpRight > limitRight) { wrapNoWrapBox = true; } } //----------------------------------------------------- int lim = runs.Count - 1; for (int i = 0; i <= lim; ++i) { var run = runs[i]; //--------------------------------------------------- //check if need to start new line ? if ((cx + run.Width + rightMostSpace > limitRight && bWhiteSpace != CssWhiteSpace.NoWrap && bWhiteSpace != CssWhiteSpace.Pre && (bWhiteSpace != CssWhiteSpace.PreWrap || !run.IsSpaces)) || run.IsLineBreak || wrapNoWrapBox) { wrapNoWrapBox = false; //once! //------------------------------- //create new line *** hostLine = new CssLineBox(hostBox); hostBox.AddLineBox(hostLine); //reset x pos for new line cx = firstRunStartX; // handle if line is wrapped for the first text element where parent has left margin/padding if (childNumber == 0 && //b is first child of splitable box ('b' == splitableBox.GetFirstChild()) !run.IsLineBreak && (i == 0 || splitableBox.ParentBox.IsBlock))//this run is first run of 'b' (run == b.FirstRun) { //TODO: review here again!!!! //cx += splitableBox.ActualMarginLeft + // splitableBox.ActualBorderLeftWidth + // splitableBox.ActualPaddingLeft; } if (run.IsSolidContent || i == 0) { cx += leftMostSpace; } } //--------------------------------------------------- if (run.IsSpaces && hostLine.RunCount == 0) { //not add continue; } //--------------------------------------------------- hostLine.AddRun(run); //*** if (lim == 0) { //single one if (!hostBoxIsB) { cx += b.ActualPaddingLeft; } run.SetLocation(cx, 0); cx += run.Width + b.ActualPaddingRight; } else { if (i == 0) { //first if (!hostBoxIsB) { cx += b.ActualPaddingLeft; } run.SetLocation(cx, 0); cx = run.Right; } else if (i == lim) { run.SetLocation(cx, 0); cx += run.Width + b.ActualPaddingRight; } else { run.SetLocation(cx, 0); cx = run.Right; } } //--------------------------------------------------- //move current_line_x to right of run //cx = run.Right; } }
public static void PerformContentLayout(CssBox box, LayoutVisitor lay) { //recursive //this box has its own container property //this box may use... // 1) line formatting context , or // 2) block formatting context CssBox myContainingBlock = lay.LatestContainingBlock; CssBox prevSibling = lay.LatestSiblingBox; if (box.CssDisplay != Css.CssDisplay.TableCell) { //------------------------------------------- if (box.CssDisplay != Css.CssDisplay.Table) { float availableWidth = myContainingBlock.GetClientWidth(); // Console.WriteLine(availableWidth.ToString()); if (!box.Width.IsEmptyOrAuto) { float w = CssValueParser.ConvertToPx(box.Width, availableWidth, box); //specific width box.SetCssBoxWidth(w); } else { box.SetCssBoxFromContainerAvailableWidth(availableWidth); } } //------------------------------------------- float localLeft = myContainingBlock.GetClientLeft() + box.ActualMarginLeft; float localTop = 0; if (prevSibling == null) { //this is first child of parent if (box.ParentBox != null) { localTop = myContainingBlock.GetClientTop(); } } else { localTop = prevSibling.LocalVisualBottom; } //if (box.Float != CssFloat.None) //{ // //float box // //find context floating c // if (lay.HasFloatBoxInContext) // { // } //} localTop += box.UpdateMarginTopCollapse(prevSibling); box.SetLocation(localLeft, localTop); box.SetHeightToZero(); } //-------------------------------------------------------------------------- switch (box.CssDisplay) { case Css.CssDisplay.Table: case Css.CssDisplay.InlineTable: { //If we're talking about a table here.. lay.PushContaingBlock(box); var currentLevelLatestSibling = lay.LatestSiblingBox; lay.LatestSiblingBox = null;//reset CssTableLayoutEngine.PerformLayout(box, myContainingBlock.GetClientWidth(), lay); lay.LatestSiblingBox = currentLevelLatestSibling; lay.PopContainingBlock(); //TODO: check if this can have absolute layer? } break; default: { //formatting context for... //1. line formatting context //2. block formatting context if (box.IsCustomCssBox) { //has custom layout method box.ReEvaluateComputedValues(lay.SampleIFonts, lay.LatestContainingBlock); box.CustomRecomputedValue(lay.LatestContainingBlock); } else { if (ContainsInlinesOnly(box)) { //This will automatically set the bottom of this block LinesFormattingEngine.DoLayoutLinesContext(box, lay); } else if (box.ChildCount > 0) { DoLayoutBlocksContext(box, lay); } if (box.HasAbsoluteLayer) { LayoutContentInAbsoluteLayer(lay, box); } } //--------------------- //again! switch (box.CssDisplay) { case CssDisplay.Flex: case CssDisplay.InlineFlex: { //------------------------------------------------ RearrangeWithFlexContext(box, lay); //------------------------------------------------ } break; default: { //TODO: review here again //if (box.Float != CssFloat.None) //{ // var iw = box.InnerContentWidth; // var ew = box.VisualWidth; // box.SetVisualSize(box.InnerContentWidth, box.InnerContentHeight); // //float to specific position // //box.SetVisualSize(iw, box.VisualHeight); //} } break; } //--------------------- } break; } switch (box.Float) { case CssFloat.Left: { #if DEBUG CssBox a = box; #endif //place it to floating context CssBox currentFloatOwner = lay.GetFloatingContextStack().CurrentTopOwner; CssBox recentLeftFloatBox = lay.LatestLeftFloatBox; CssBox recentRightFloatBox = lay.LatestRightFloatBox; float availableWidth2 = myContainingBlock.GetClientWidth(); if (recentRightFloatBox != null) { availableWidth2 -= recentRightFloatBox.LocalX; } float sx = myContainingBlock.GetClientLeft(); //-------------------------------------------------------------------- float sy = 0; if (myContainingBlock.LineBoxCount > 0) { //line context sy = myContainingBlock.GetClientTop(); } else { var prevNode = box.GetPrevNode(); if (prevNode != null) { if (prevNode.Float != CssFloat.None) { //float left/right //TODO: review inherit here if (box.VisualWidth < availableWidth2) { sy = prevNode.LocalY; } else { sy = prevNode.LocalVisualBottom; } } else { sy = prevNode.LocalVisualBottom; } } else { sy = myContainingBlock.GetClientTop(); } } if (recentLeftFloatBox != null) { availableWidth2 -= recentLeftFloatBox.LocalVisualRight; //TODO: review here again sx = recentLeftFloatBox.LocalVisualRight + recentLeftFloatBox.ActualMarginRight; sy = recentLeftFloatBox.LocalY; } if (box.VisualWidth > availableWidth2) { //start newline sx = myContainingBlock.GetClientLeft(); float sy1 = 0; float sy2 = 0; sy1 = sy2 = myContainingBlock.GetClientTop(); if (recentLeftFloatBox != null) { sy1 = recentLeftFloatBox.LocalVisualBottom + recentLeftFloatBox.ActualMarginBottom; } if (recentRightFloatBox != null) { sy2 = recentRightFloatBox.LocalVisualBottom + recentRightFloatBox.ActualMarginBottom; } sy = (sy1 > sy2) ? sy1 : sy2; } sx += box.ActualMarginLeft; sy += box.ActualMarginTop; box.SetLocation(sx, sy); lay.AddFloatBox(box); } break; case CssFloat.Right: { CssBox recentLeftFloatBox = lay.LatestLeftFloatBox; CssBox recentRightFloatBox = lay.LatestRightFloatBox; float availableWidth2 = myContainingBlock.GetClientWidth(); if (recentLeftFloatBox != null) { availableWidth2 -= recentLeftFloatBox.LocalVisualRight; } float sx = myContainingBlock.GetClientRight() - (box.VisualWidth + box.ActualMarginLeft + box.ActualMarginRight); //-------------------------------------------------------------------- float sy = 0; if (myContainingBlock.LineBoxCount > 0) { //line context sy = myContainingBlock.GetClientTop(); } else { var prevNode = box.GetPrevNode(); if (prevNode != null) { if (prevNode.Float != CssFloat.None) { //float left/right //TODO: review inherit here if (box.VisualWidth < availableWidth2) { sy = prevNode.LocalY; } else { sy = prevNode.LocalVisualBottom; } } else { sy = prevNode.LocalVisualBottom; } } else { sy = myContainingBlock.GetClientTop(); } } //-------------------------------------------------------------------- if (recentRightFloatBox != null) { availableWidth2 -= recentRightFloatBox.LocalX; sx = recentRightFloatBox.LocalX - box.VisualWidth; sy = recentRightFloatBox.LocalY; } if (box.VisualWidth > availableWidth2) { //start newline sx = myContainingBlock.GetClientRight() - (box.VisualWidth + box.ActualMarginLeft + box.ActualMarginRight); float sy1 = 0; float sy2 = 0; sy1 = sy2 = myContainingBlock.GetClientTop(); //if (recentLeftFloatBox != null) //{ // sy1 = recentLeftFloatBox.LocalY + recentLeftFloatBox.InnerContentHeight + // recentLeftFloatBox.ActualPaddingBottom + // recentLeftFloatBox.ActualMarginBottom; //} //if (recentRightFloatBox != null) //{ // sy2 = recentRightFloatBox.LocalY + recentRightFloatBox.InnerContentHeight + // recentRightFloatBox.ActualPaddingBottom + // recentRightFloatBox.ActualMarginBottom; //} if (recentLeftFloatBox != null) { sy1 = recentLeftFloatBox.LocalVisualBottom + recentLeftFloatBox.ActualMarginBottom; } if (recentRightFloatBox != null) { sy2 = recentRightFloatBox.LocalVisualBottom + recentRightFloatBox.ActualMarginBottom; } sy = (sy1 > sy2) ? sy1 : sy2; } sx += box.ActualMarginLeft; sy += box.ActualMarginTop; box.SetLocation(sx, sy); lay.AddFloatBox(box); } break; case CssFloat.None: default: { //review here for inherit property } break; } }
/// <summary> /// Applies vertical and horizontal alignment to words in lineboxes /// </summary> /// <param name="g"></param> /// <param name="lineBox"></param> static void ApplyAlignment(CssLineBox lineBox, CssTextAlign textAlign, LayoutVisitor lay) { switch (textAlign) { case CssTextAlign.Right: ApplyRightAlignment(lineBox); break; case CssTextAlign.Center: ApplyCenterAlignment(lineBox); break; case CssTextAlign.Justify: ApplyJustifyAlignment(lineBox); break; default: break; } //--------------------------------------------- // Applies vertical alignment to the linebox return; //TODO: review here lineBox.ApplyBaseline(lineBox.CalculateTotalBoxBaseLine(lay)); //--------------------------------------------- }
static void SetFinalInnerContentSize(CssBox box, float innerContentW, float innerContentH, LayoutVisitor lay) { box.InnerContentWidth = innerContentW; box.InnerContentHeight = innerContentH; if (!box.Height.IsEmptyOrAuto) { var h = CssValueParser.ConvertToPx(box.Height, lay.LatestContainingBlock.VisualWidth, lay.LatestContainingBlock); box.SetExpectedSize(box.ExpectedWidth, h); box.SetVisualHeight(h); box.SetCssBoxHeight(h); } else { switch (box.Position) { case CssPosition.Fixed: case CssPosition.Absolute: box.SetVisualHeight(box.InnerContentHeight); break; } } if (!box.Width.IsEmptyOrAuto) { //find max line width var w = CssValueParser.ConvertToPx(box.Width, lay.LatestContainingBlock.VisualWidth, lay.LatestContainingBlock); box.SetExpectedSize(w, box.ExpectedHeight); box.SetVisualWidth(w); box.SetCssBoxWidth(w); } else { switch (box.Position) { case CssPosition.Fixed: case CssPosition.Absolute: box.SetVisualWidth(box.InnerContentWidth); break; } } switch (box.Overflow) { case CssOverflow.Scroll: case CssOverflow.Auto: { if ((box.InnerContentHeight > box.VisualHeight) || (box.InnerContentWidth > box.VisualWidth)) { lay.RequestScrollView(box); } } break; } }
public LayoutFarm.HtmlBoxes.LayoutVisitor GetSharedHtmlLayoutVisitor(HtmlContainer htmlCont) { LayoutFarm.HtmlBoxes.LayoutVisitor lay = null; if (htmlLayoutVisitorStock.Count == 0) { lay = new LayoutVisitor(); } else { lay = this.htmlLayoutVisitorStock.Dequeue(); } lay.Bind(htmlCont); return lay; }
/// <summary> /// Assigns words its width and height /// </summary> /// <param name="g"></param> public virtual void MeasureRunsSize(LayoutVisitor lay) { //measure once ! if ((_boxCompactFlags & BoxFlags.LAY_RUNSIZE_MEASURE) != 0) { return; } //-------------------------------- if (this.BackgroundImageBinder != null) { //this has background if (this.BackgroundImageBinder.State == BinderState.Unload) { lay.RequestImage(this.BackgroundImageBinder, this); } } //-------------------------------- if (this.RunCount > 0) { //find word spacing float actualWordspacing = _actualWordSpacing; RequestFont actualFont = this.ResolvedFont; float fontHeight = (actualFont.AscentInPixels - actualFont.DescentInPixels + actualFont.LineGapInPixels); fontHeight += 4; //TODO: why +4 ????*** List <CssRun> tmpRuns = this.Runs; for (int i = tmpRuns.Count - 1; i >= 0; --i) { CssRun run = tmpRuns[i]; run.Height = fontHeight; //if this is newline then width =0 *** switch (run.Kind) { case CssRunKind.Text: { CssTextRun textRun = (CssTextRun)run; Size ss = lay.MeasureStringSize(CssBox.UnsafeGetTextBuffer(this), textRun.TextStartIndex, textRun.TextLength, actualFont); run.SetSize(ss.Width, ss.Height); } break; case CssRunKind.SingleSpace: { run.Width = actualWordspacing; } break; case CssRunKind.Space: { //other space size run.Width = actualWordspacing * ((CssTextRun)run).TextLength; } break; case CssRunKind.LineBreak: { run.Width = 0; } break; } } } _boxCompactFlags |= BoxFlags.LAY_RUNSIZE_MEASURE; }
/// <summary> /// Layout the cells by the calculated table layout /// </summary> /// <param name="g"></param> void S8_LayoutCells(LayoutVisitor lay) { //each cell relative to its owner float table_globalX = lay.ContainerBlockGlobalX; float table_globalY = lay.ContainerBlockGlobalY; float vertical_spacing = GetVerticalSpacing(_tableBox); float horizontal_spacing = GetHorizontalSpacing(_tableBox); float startx_global = Math.Max(table_globalX + _tableBox.GetClientLeft() + horizontal_spacing, 0); float starty_global = Math.Max(table_globalY + _tableBox.GetClientTop() + vertical_spacing, 0); float startx_local = startx_global - table_globalX; float starty_local = starty_global - table_globalY; float curY_local = starty_local; float maxRight_local = startx_local; float maxBottom_local = 0f; int currentRow = 0; int col_count = this.columnCollection.Count; for (int i = 0; i < _allRowBoxes.Count; i++) { var row = _allRowBoxes[i]; float curX_local = startx_local;//reset int col_index = 0; int grid_index = 0; foreach (CssBox cell in row.GetChildBoxIter()) { if (col_index >= col_count) { break; } else { int colspan = cell.ColSpan; float width = this.columnCollection.GetCellWidth(grid_index, colspan, horizontal_spacing); //HtmlRenderer.Boxes.BoxUtils.ForEachTextRunDeep(cell, trun => //{ // if (trun.Text.Contains("Cell1")) // { // cell.dbugMark = 20; // return true; // } // //else if (trun.Text.Contains("You1")) // //{ // // cell.dbugMark = 19; // // return true; // //} // return false; //}); //----------------------------------------- cell.SetLocation(curX_local, curY_local); cell.FreezeWidth = false; cell.SetVisualSize(width, 0); cell.FreezeWidth = true; //----------------------------------------- cell.PerformLayout(lay); //That will automatically set the bottom of the cell //Alter max bottom only if row is cell's row + cell's rowspan - 1 CssVerticalCellSpacingBox sb = cell as CssVerticalCellSpacingBox; if (sb != null) { if (sb.EndRow == currentRow) { maxBottom_local = Math.Max(maxBottom_local, sb.ExtendedBox.LocalVisualBottom); } } else if (cell.RowSpan == 1) { maxBottom_local = Math.Max(maxBottom_local, cell.LocalVisualBottom); } maxRight_local = Math.Max(maxRight_local, cell.LocalVisualRight); curX_local = cell.LocalVisualRight + horizontal_spacing; //------------------------- col_index++; grid_index += colspan; } } foreach (CssBox cell in row.GetChildBoxIter()) { CssVerticalCellSpacingBox spacer = cell as CssVerticalCellSpacingBox; if (spacer == null) { if (cell.RowSpan == 1) { cell.SetVisualHeight(maxBottom_local - curY_local); ApplyCellVerticalAlignment(cell, starty_local); } } else { if (spacer.EndRow == currentRow) { spacer.ExtendedBox.SetVisualHeight(maxBottom_local - curY_local); ApplyCellVerticalAlignment(spacer.ExtendedBox, starty_local); } } } curY_local = maxBottom_local + vertical_spacing; currentRow++; } maxRight_local = Math.Max(maxRight_local, _tableBox.ExpectedWidth); _tableBox.SetVisualWidth(maxRight_local + horizontal_spacing + _tableBox.ActualBorderRightWidth); float globalBottom = Math.Max((maxBottom_local + table_globalY), starty_global) + vertical_spacing + _tableBox.ActualBorderBottomWidth; _tableBox.SetVisualHeight(globalBottom - table_globalY); }
public void PerformLayout(LayoutVisitor lay) { if (this._rootBox == null) { return; } //----------------------- //reset _actualWidth = _actualHeight = 0; // if width is not restricted we set it to large value to get the actual later _rootBox.SetLocation(0, 0); _rootBox.SetVisualSize(this._maxWidth > 0 ? this._maxWidth : MAX_WIDTH, 0); CssBox.ValidateComputeValues(_rootBox); //----------------------- //LayoutVisitor layoutArgs = new LayoutVisitor(this.GraphicsPlatform, this); lay.PushContaingBlock(_rootBox); //----------------------- _rootBox.PerformLayout(lay); if (this._maxWidth <= 0.1) { // in case the width is not restricted we need to double layout, first will find the width so second can layout by it (center alignment) _rootBox.SetVisualWidth((int)Math.Ceiling(this._actualWidth)); _actualWidth = _actualHeight = 0; _rootBox.PerformLayout(lay); } lay.PopContainingBlock(); //----------------------- //TODO: review here again FloatingContextStack floatStack = lay.GetFloatingContextStack(); List<FloatingContext> totalContexts = floatStack.GetTotalContexts(); int j = totalContexts.Count; for (int i = 0; i < j; ++i) { FloatingContext floatingContext = totalContexts[i]; int floatBoxCount = floatingContext.FloatBoxCount; if (floatBoxCount == 0) { continue; } CssBox floatingOwner = floatingContext.Owner; float rfx, rfy; floatingOwner.GetGlobalLocation(out rfx, out rfy); CssBox prevParent = null; //TODO: review here again float extraAdjustX = 0; //temp fixed for (int n = 0; n < floatBoxCount; ++n) { float bfx, bfy; CssBox box = floatingContext.GetBox(n); box.GetGlobalLocation(out bfx, out bfy); //diff float nx = bfx - rfx; float ny = bfy - rfy; if (prevParent != null && prevParent != box.ParentBox) { if (n > 0) { CssBox prevFloatChild = floatingContext.GetBox(n - 1); //TODO: review here again //temp fix extraAdjustX = prevFloatChild.ActualMarginRight + box.ActualMarginLeft; ny += box.ActualMarginTop; } } box.SetLocation(nx + extraAdjustX, ny); prevParent = box.ParentBox; floatingOwner.AppendToAbsoluteLayer(box); } } OnLayoutFinished(); //----------------------- unchecked { layoutVersion++; } //----------------------- }
/// <summary> /// Recursively measures run inside the box /// </summary> /// <param name="box">the box to measure</param> /// <param name="g">Device to use</param> static void S1_RecursiveMeasureRunContentSize(CssBox box, LayoutVisitor lay) { //recursive if (box != null) { float box_fontsize = box.ResolvedFont.SizeInPixels; var ifonts = lay.SampleIFonts; foreach (var childBox in box.GetChildBoxIter()) { childBox.ReEvaluateFont(ifonts, box_fontsize); childBox.MeasureRunsSize(lay); S1_RecursiveMeasureRunContentSize(childBox, lay); //recursive } } }
/// <summary> /// Measures the bounds of box and children, recursively.<br/> /// Performs layout of the DOM structure creating lines by set bounds restrictions. /// </summary> /// <param name="g">Device context to use</param> protected override void PerformContentLayout(LayoutVisitor lay) { if (this.CssDisplay == Css.CssDisplay.None) { return; } var prevSibling = lay.LatestSiblingBox; var myContainingBlock = lay.LatestContainingBlock; if (this.NeedComputedValueEvaluation) { this.ReEvaluateComputedValues(lay.SampleIFonts, myContainingBlock); } float localLeft = myContainingBlock.GetClientLeft() + this.ActualMarginLeft; float localTop = 0; if (prevSibling == null) { if (this.ParentBox != null) { localTop = myContainingBlock.GetClientTop(); } } else { localTop = prevSibling.LocalVisualBottom;// +prevSibling.ActualBorderBottomWidth; } float maringTopCollapse = UpdateMarginTopCollapse(prevSibling); if (maringTopCollapse < 0.1) { maringTopCollapse = this.GetEmHeight() * 1.1f; } localTop += maringTopCollapse; this.SetLocation(localLeft, localTop); this.SetHeightToZero(); //width at 100% (or auto) float minwidth = CalculateMinimumWidth(lay.EpisodeId); float width = myContainingBlock.VisualWidth - myContainingBlock.ActualPaddingLeft - myContainingBlock.ActualPaddingRight - myContainingBlock.ActualBorderLeftWidth - myContainingBlock.ActualBorderRightWidth - ActualMarginLeft - ActualMarginRight - ActualBorderLeftWidth - ActualBorderRightWidth; //Check width if not auto if (!this.Width.IsEmptyOrAuto) { width = CssValueParser.ConvertToPx(Width, width, this); } if (width < minwidth || width >= CssBoxConstConfig.TABLE_MAX_WIDTH) { width = minwidth; } float height = ExpectedHeight; if (height < 1) { height = this.VisualHeight + ActualBorderTopWidth + ActualBorderBottomWidth; } if (height < 1) { height = 2; } if (height <= 2 && ActualBorderTopWidth < 1 && ActualBorderBottomWidth < 1) { DirectSetBorderWidth(CssSide.Top, 1); DirectSetBorderWidth(CssSide.Bottom, 1); } this.SetVisualSize(width, height); this.SetVisualHeight(ActualPaddingTop + ActualPaddingBottom + height); }
internal void CloseLine(LayoutVisitor lay) { #if DEBUG this.dbugIsClosed = true; #endif //============================================================= //part 1: MakeStrips() //============================================================= //*** List<CssRun> myruns = this._runs; CssBox lineOwner = this._ownerBox; List<PartialBoxStrip> tmpStrips = lay.GetReadyStripList(); //--------------------------------------------------------------------------- //first level Dictionary<CssBox, PartialBoxStrip> unqiueStrips = lay.GetReadyStripDic(); //location of run and strip related to its containng block float maxRight = 0; float maxBottom = 0; int j = myruns.Count; float firstRunStartAt = 0; for (int i = 0; i < j; ++i) { CssRun run = myruns[i]; if (i == 0) { firstRunStartAt = run.Left; } maxRight = run.Right > maxRight ? run.Right : maxRight; maxBottom = run.Bottom > maxBottom ? run.Bottom : maxBottom; if (run.IsSpaces) { //strip size include whitespace ? continue; } //------------- //first level data RegisterStripPart(run.OwnerBox, run.Left, run.Top, run.Right, run.Bottom, tmpStrips, unqiueStrips); } //--------------------------------------------------------------------------- //other step to upper layer, until no new strip int newStripIndex = 0; for (int numNewStripCreate = tmpStrips.Count; numNewStripCreate > 0; newStripIndex += numNewStripCreate) { numNewStripCreate = StepUpRegisterStrips(unqiueStrips, lineOwner, tmpStrips, newStripIndex); } this._bottomUpBoxStrips = tmpStrips.ToArray(); lay.ReleaseStripList(tmpStrips); lay.ReleaseStripDic(unqiueStrips); //============================================================= //part 2: Calculate //============================================================= this.CacheLineHeight = maxBottom; this.CachedLineContentWidth = maxRight; this.CachedExactContentWidth = (maxRight - firstRunStartAt); if (lineOwner.VisualWidth < CachedLineContentWidth) { this.CachedLineContentWidth = this.OwnerBox.VisualWidth; } }
/// <summary> /// Measures the bounds of box and children, recursively.<br/> /// Performs layout of the DOM structure creating lines by set bounds restrictions. /// </summary> /// <param name="g">Device context to use</param> public void PerformLayout(LayoutVisitor lay) { //derived class can perform its own layout algo //by override performContentLayout PerformContentLayout(lay); }
public float CalculateTotalBoxBaseLine(LayoutVisitor lay) { //not correct !! float maxRunHeight = 0; CssRun maxRun = null; for (int i = this._runs.Count - 1; i >= 0; --i) { var run = this._runs[i]; if (run.Height > maxRunHeight) { maxRun = run; maxRunHeight = run.Height; } } if (maxRun != null) { //lay.GraphicsPlatform.SampleIFonts //var f = maxRun.OwnerBox.ResolvedFont; //PixelFarm.Drawing.Fonts.ActualFont ff = f.ActualFont; //return (float)(f.Height * ff.AscentInPixels / f.Height); //return fontHeight* fontAscent / lineSpacing ) } return 0; //int j = this._runs.Count; //for (int i = this._runs.Count - 1; i >= 0; --i) //{ // Font ownerFont = _runs[i].OwnerBox.ActualFont; // HtmlRenderer.Drawing.FontsUtils.GetDescent( //} //return 0; //float baseline = Single.MinValue; //for (int i = _bottomUpBoxStrips.Count - 1; i >= 0; --i) //{ // baseline = Math.Max(baseline, _bottomUpBoxStrips[i].Top);//?top //} //return baseline; }
public void ReleaseHtmlLayoutVisitor(LayoutVisitor lay) { lay.UnBind(); this.htmlLayoutVisitorStock.Enqueue(lay); }
static void RearrangeWithFlexContext(CssBox box, LayoutVisitor lay) { //this is an experiment!, var children = CssBox.UnsafeGetChildren(box); var cnode = children.GetFirstLinkedNode(); List<FlexItem> simpleFlexLine = new List<FlexItem>(); FlexLine flexLine = new FlexLine(box); while (cnode != null) { flexLine.AddChild(new FlexItem(cnode.Value)); cnode = cnode.Next; } flexLine.Arrange(); if (box.Height.IsEmptyOrAuto) { //set new height box.SetVisualHeight(flexLine.LineHeightAfterArrange); //check if it need scrollbar or not } if (box.Width.IsEmptyOrAuto) { box.SetVisualWidth(flexLine.LineWidthAfterArrange); } SetFinalInnerContentSize(box, flexLine.LineWidthAfterArrange, flexLine.LineHeightAfterArrange, lay); }
internal void CloseLine(LayoutVisitor lay) { #if DEBUG this.dbugIsClosed = true; #endif //============================================================= //part 1: MakeStrips() //============================================================= //*** List <CssRun> myruns = _runs; CssBox lineOwner = _ownerBox; List <PartialBoxStrip> tmpStrips = lay.GetReadyStripList(); //--------------------------------------------------------------------------- //first level Dictionary <CssBox, PartialBoxStrip> unqiueStrips = lay.GetReadyStripDic(); //location of run and strip related to its containng block float maxRight = 0; float maxBottom = 0; int j = myruns.Count; float firstRunStartAt = 0; for (int i = 0; i < j; ++i) { CssRun run = myruns[i]; if (i == 0) { firstRunStartAt = run.Left; } maxRight = run.Right > maxRight ? run.Right : maxRight; maxBottom = run.Bottom > maxBottom ? run.Bottom : maxBottom; if (run.IsSpaces) { //strip size include whitespace ? continue; } //------------- //first level data RegisterStripPart(run.OwnerBox, run.Left, run.Top, run.Right, run.Bottom, tmpStrips, unqiueStrips); } //--------------------------------------------------------------------------- //other step to upper layer, until no new strip int newStripIndex = 0; for (int numNewStripCreate = tmpStrips.Count; numNewStripCreate > 0; newStripIndex += numNewStripCreate) { numNewStripCreate = StepUpRegisterStrips(unqiueStrips, lineOwner, tmpStrips, newStripIndex); } _bottomUpBoxStrips = tmpStrips.ToArray(); lay.ReleaseStripList(tmpStrips); lay.ReleaseStripDic(unqiueStrips); //============================================================= //part 2: Calculate //============================================================= this.CacheLineHeight = maxBottom; this.CachedLineContentWidth = maxRight; this.CachedExactContentWidth = (maxRight - firstRunStartAt); if (lineOwner.VisualWidth < CachedLineContentWidth) { this.CachedLineContentWidth = this.OwnerBox.VisualWidth; } }
/// <summary> /// Assigns words its width and height /// </summary> /// <param name="g"></param> public virtual void MeasureRunsSize(LayoutVisitor lay) { //measure once ! if ((this._boxCompactFlags & BoxFlags.LAY_RUNSIZE_MEASURE) != 0) { return; } //-------------------------------- if (this.BackgroundImageBinder != null) { //this has background if (this.BackgroundImageBinder.State == ImageBinderState.Unload) { lay.RequestImage(this.BackgroundImageBinder, this); } } //-------------------------------- if (this.RunCount > 0) { //find word spacing float actualWordspacing = this._actualWordSpacing; RequestFont actualFont = this.ResolvedFont; float fontHeight = (actualFont.AscentInPixels - actualFont.DescentInPixels + actualFont.LineGapInPixels); fontHeight += 4; var tmpRuns = this.Runs; for (int i = tmpRuns.Count - 1; i >= 0; --i) { CssRun run = tmpRuns[i]; run.Height = fontHeight; //if this is newline then width =0 *** switch (run.Kind) { case CssRunKind.Text: { CssTextRun textRun = (CssTextRun)run; //run.Width = lay.MeasureStringWidth( // CssBox.UnsafeGetTextBuffer(this), // textRun.TextStartIndex, // textRun.TextLength, // actualFont); Size ss = lay.MeasureStringSize(CssBox.UnsafeGetTextBuffer(this), textRun.TextStartIndex, textRun.TextLength, actualFont); run.SetSize(ss.Width, ss.Height); } break; case CssRunKind.SingleSpace: { run.Width = actualWordspacing; } break; case CssRunKind.Space: { //other space size run.Width = actualWordspacing * ((CssTextRun)run).TextLength; } break; case CssRunKind.LineBreak: { run.Width = 0; } break; } } } this._boxCompactFlags |= BoxFlags.LAY_RUNSIZE_MEASURE; }
public void SetHtmlHost(HtmlHost htmlhost) { this.htmlhost = htmlhost; htmlhost.SetHtmlContainerUpdateHandler(htmlCont => { var updatedHtmlCont = htmlCont as MyHtmlContainer; if (updatedHtmlCont != null && !updatedHtmlCont.IsInUpdateQueue) { updatedHtmlCont.IsInUpdateQueue = true; waitingUpdateList.Add(updatedHtmlCont); } }); htmlContainer = new MyHtmlContainer(htmlhost); htmlContainer.AttachEssentialHandlers( OnRefresh, myHtmlContainer_NeedUpdateDom, OnRefresh, null); htmlLayoutVisitor = new LayoutVisitor(); htmlLayoutVisitor.Bind(htmlContainer); //------------------------------------------------------- timer01.Interval = 20;//20ms? timer01.Tick += (s, e) => { //clear waiting int j = waitingUpdateList.Count; for (int i = 0; i < j; ++i) { var htmlCont = waitingUpdateList[i]; htmlCont.IsInUpdateQueue = false; htmlCont.RefreshDomIfNeed(); } for (int i = j - 1; i >= 0; --i) { waitingUpdateList.RemoveAt(i); } }; timer01.Enabled = true; //------------------------------------------- _htmlInputEventAdapter = new HtmlInputEventAdapter(); _htmlInputEventAdapter.Bind(htmlContainer); //------------------------------------------- }
static void LayoutContentInAbsoluteLayer(LayoutVisitor lay, CssBox srcBox) { if (srcBox.JustTempContainer) return; var ifonts = lay.SampleIFonts; //css3 jan2015: absolute position //use offset relative to its normal the box's containing box*** float containerW = lay.LatestContainingBlock.VisualWidth; float maxRight = 0; float maxBottom = 0; foreach (var b in srcBox.GetAbsoluteChildBoxIter()) { if (b.JustTempContainer) { continue; } if (b.NeedComputedValueEvaluation) { b.ReEvaluateComputedValues(ifonts, lay.LatestContainingBlock); } b.MeasureRunsSize(lay); PerformContentLayout(b, lay); b.SetLocation( CssValueParser.ConvertToPx(b.Left, containerW, b), CssValueParser.ConvertToPx(b.Top, containerW, b)); var localRight = b.LocalVisualRight; var localBottom = b.LocalVisualBottom; if (maxRight < localRight) { maxRight = localRight; } if (maxBottom < localBottom) { maxBottom = localBottom; } } int i_maxRight = (int)maxRight; int i_maxBottom = (int)maxBottom; srcBox.InnerContentWidth = i_maxRight; srcBox.InnerContentHeight = i_maxBottom; }
/// <summary> /// Assigns words its width and height /// </summary> /// <param name="g"></param> public virtual void MeasureRunsSize(LayoutVisitor lay) { //measure once ! if ((this._boxCompactFlags & BoxFlags.LAY_RUNSIZE_MEASURE) != 0) { return; } //-------------------------------- if (this.BackgroundImageBinder != null) { //this has background if (this.BackgroundImageBinder.State == ImageBinderState.Unload) { lay.RequestImage(this.BackgroundImageBinder, this); } } //-------------------------------- if (this.RunCount > 0) { //find word spacing float actualWordspacing = this._actualWordSpacing; Font actualFont = this.ActualFont; var fontInfo = actualFont.FontInfo; float fontHeight = fontInfo.LineHeight; var tmpRuns = this.Runs; for (int i = tmpRuns.Count - 1; i >= 0; --i) { CssRun run = tmpRuns[i]; run.Height = fontHeight; //if this is newline then width =0 *** switch (run.Kind) { case CssRunKind.Text: { CssTextRun textRun = (CssTextRun)run; run.Width = lay.MeasureStringWidth( CssBox.UnsafeGetTextBuffer(this), textRun.TextStartIndex, textRun.TextLength, actualFont); } break; case CssRunKind.SingleSpace: { run.Width = actualWordspacing; } break; case CssRunKind.Space: { //other space size run.Width = actualWordspacing * ((CssTextRun)run).TextLength; } break; case CssRunKind.LineBreak: { run.Width = 0; } break; } } } this._boxCompactFlags |= BoxFlags.LAY_RUNSIZE_MEASURE; }
/// <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); } }