/// <summary> /// Converts an HTML length into a Css length /// </summary> /// <param name="htmlLength"></param> /// <returns></returns> private string TranslateLength(string htmlLength) { var len = new CssLength(htmlLength); if (len.HasError) { return(htmlLength + "px"); } return(htmlLength); }
private float GetAvailableWidth() { CssLength cssLength = new CssLength(this.TableBox.Width); if (cssLength.Number <= 0f) { return(this.TableBox.ParentBox.AvailableWidth); } this._widthSpecified = true; if (!cssLength.IsPercentage) { return(cssLength.Number); } return(CssValue.ParseNumber(cssLength.Length, this.TableBox.ParentBox.AvailableWidth)); }
/// <summary> /// Gets the available width for the whole table. /// It also sets the value of <see cref="WidthSpecified" /> /// </summary> /// <returns></returns> /// <remarks> /// The table's width can be larger than the result of this method, because of the minimum /// size that individual boxes. /// </remarks> private float GetAvailableWidth() { var tblen = new CssLength(TableBox.Width); if (tblen.Number > 0) { WidthSpecified = true; if (tblen.IsPercentage) { return(CssValue.ParseNumber(tblen.Length, TableBox.ParentBox.AvailableWidth)); } return(tblen.Number); } return(TableBox.ParentBox.AvailableWidth); }
/// <summary> /// Ensures that the specified length is converted to pixels if necessary /// </summary> /// <param name="length"></param> private string NoEms(string length) { CssLength len = new CssLength(length); if (len.Unit == CssLength.CssUnit.Ems) { length = len.ConvertEmToPixels(GetEmHeight()).ToString(); } return length; }
/// <summary> /// Analyzes the Table and assigns values to this CssTable object. /// To be called from the constructor /// </summary> private void Analyze(Graphics g) { float availSpace = GetAvailableWidth(); float availCellSpace = float.NaN; //Will be set later #region Assign box kinds foreach (CssBox b in TableBox.Boxes) { b.RemoveAnonymousSpaces(); switch (b.Display) { case CssConstants.TableCaption: _caption = b; break; case CssConstants.TableColumn: for (int i = 0; i < GetSpan(b); i++) { Columns.Add(CreateColumn(b)); } break; case CssConstants.TableColumnGroup: if (b.Boxes.Count == 0) { int gspan = GetSpan(b); for (int i = 0; i < gspan; i++) { Columns.Add(CreateColumn(b)); } } else { foreach (CssBox bb in b.Boxes) { int bbspan = GetSpan(bb); for (int i = 0; i < bbspan; i++) { Columns.Add(CreateColumn(bb)); } } } break; case CssConstants.TableFooterGroup: if (FooterBox != null) { BodyRows.Add(b); } else { _footerBox = b; } break; case CssConstants.TableHeaderGroup: if (HeaderBox != null) { BodyRows.Add(b); } else { _headerBox = b; } break; case CssConstants.TableRow: BodyRows.Add(b); break; case CssConstants.TableRowGroup: foreach (CssBox bb in b.Boxes) { if (b.Display == CssConstants.TableRow) { BodyRows.Add(b); } } break; default: break; } } #endregion #region Gather AllRows if (HeaderBox != null) { _allRows.AddRange(HeaderBox.Boxes); } _allRows.AddRange(BodyRows); if (FooterBox != null) { _allRows.AddRange(FooterBox.Boxes); } #endregion #region Insert EmptyBoxes for vertical cell spanning if (!TableBox.TableFixed) { int currow = 0; int curcol = 0; List <CssBox> rows = BodyRows; foreach (CssBox row in rows) { row.RemoveAnonymousSpaces(); curcol = 0; for (int k = 0; k < row.Boxes.Count; k++) { CssBox cell = row.Boxes[k]; int rowspan = GetRowSpan(cell); int realcol = GetCellRealColumnIndex(row, cell); //Real column of the cell for (int i = currow + 1; i < currow + rowspan; i++) { int colcount = 0; for (int j = 0; j <= rows[i].Boxes.Count; j++) { if (colcount == realcol) { rows[i].Boxes.Insert(colcount, new SpacingBox(TableBox, ref cell, currow)); break; } colcount++; realcol -= GetColSpan(rows[i].Boxes[j]) - 1; } } // End for (int i = currow + 1; i < currow + rowspan; i++) curcol++; } /// End foreach (Box cell in row.Boxes) currow++; } /// End foreach (Box row in rows) TableBox.TableFixed = true; } /// End if (!TableBox.TableFixed) #endregion #region Determine Row and Column Count, and ColumnWidths //Rows _rowCount = BodyRows.Count + (HeaderBox != null ? HeaderBox.Boxes.Count : 0) + (FooterBox != null ? FooterBox.Boxes.Count : 0); //Columns if (Columns.Count > 0) { _columnCount = Columns.Count; } else { foreach (CssBox b in AllRows) //Check trhough rows { _columnCount = Math.Max(_columnCount, b.Boxes.Count); } } //Initialize column widths array _columnWidths = new float[_columnCount]; //Fill them with NaNs for (int i = 0; i < _columnWidths.Length; i++) { _columnWidths[i] = float.NaN; } availCellSpace = GetAvailableCellWidth(); if (Columns.Count > 0) { #region Fill ColumnWidths array by scanning column widths for (int i = 0; i < Columns.Count; i++) { CssLength len = new CssLength(Columns[i].Width); //Get specified width if (len.Number > 0) //If some width specified { if (len.IsPercentage) //Get width as a percentage { ColumnWidths[i] = CssValue.ParseNumber(Columns[i].Width, availCellSpace); } else if (len.Unit == CssLength.CssUnit.Pixels || len.Unit == CssLength.CssUnit.None) { ColumnWidths[i] = len.Number; //Get width as an absolute-pixel value } } } #endregion } else { #region Fill ColumnWidths array by scanning width in table-cell definitions foreach (CssBox row in AllRows) { //Check for column width in table-cell definitions for (int i = 0; i < _columnCount; i++) { if (float.IsNaN(ColumnWidths[i]) && //Check if no width specified for column i < row.Boxes.Count && //And there's a box to check row.Boxes[i].Display == CssConstants.TableCell) //And the box is a table-cell { CssLength len = new CssLength(row.Boxes[i].Width); //Get specified width if (len.Number > 0) //If some width specified { int colspan = GetColSpan(row.Boxes[i]); float flen = 0f; if (len.IsPercentage)//Get width as a percentage { flen = CssValue.ParseNumber(row.Boxes[i].Width, availCellSpace); } else if (len.Unit == CssLength.CssUnit.Pixels || len.Unit == CssLength.CssUnit.None) { flen = len.Number; //Get width as an absolute-pixel value } flen /= Convert.ToSingle(colspan); for (int j = i; j < i + colspan; j++) { ColumnWidths[j] = flen; } } } } } #endregion } #endregion #region Determine missing Column widths if (WidthSpecified) //If a width was specified, { //Assign NaNs equally with space left after gathering not-NaNs int numberOfNans = 0; float occupedSpace = 0f; //Calculate number of NaNs and occuped space for (int i = 0; i < ColumnWidths.Length; i++) { if (float.IsNaN(ColumnWidths[i])) { numberOfNans++; } else { occupedSpace += ColumnWidths[i]; } } //Determine width that will be assigned to un asigned widths float nanWidth = (availCellSpace - occupedSpace) / Convert.ToSingle(numberOfNans); for (int i = 0; i < ColumnWidths.Length; i++) { if (float.IsNaN(ColumnWidths[i])) { ColumnWidths[i] = nanWidth; } } } else { //Assign NaNs using full width float[] _maxFullWidths = new float[ColumnWidths.Length]; //Get the maximum full length of NaN boxes foreach (CssBox row in AllRows) { for (int i = 0; i < row.Boxes.Count; i++) { int col = GetCellRealColumnIndex(row, row.Boxes[i]); if (float.IsNaN(ColumnWidths[col]) && i < row.Boxes.Count && GetColSpan(row.Boxes[i]) == 1) { _maxFullWidths[col] = Math.Max(_maxFullWidths[col], row.Boxes[i].GetFullWidth(g)); } } } for (int i = 0; i < ColumnWidths.Length; i++) { if (float.IsNaN(ColumnWidths[i])) { ColumnWidths[i] = _maxFullWidths[i]; } } } #endregion #region Reduce widths if necessary int curCol = 0; float reduceAmount = 1f; //While table width is larger than it should, and width is reductable while (GetWidthSum() > GetAvailableWidth() && CanReduceWidth()) { while (!CanReduceWidth(curCol)) { curCol++; } ColumnWidths[curCol] -= reduceAmount; curCol++; if (curCol >= ColumnWidths.Length) { curCol = 0; } } #endregion #region Check for minimum sizes (increment widths if necessary) foreach (CssBox row in AllRows) { foreach (CssBox cell in row.Boxes) { int colspan = GetColSpan(cell); int col = GetCellRealColumnIndex(row, cell); int affectcol = col + colspan - 1; if (ColumnWidths[col] < ColumnMinWidths[col]) { float diff = ColumnMinWidths[col] - ColumnWidths[col]; ColumnWidths[affectcol] = ColumnMinWidths[affectcol]; if (col < ColumnWidths.Length - 1) { ColumnWidths[col + 1] -= diff; } } } } #endregion #region Set table padding TableBox.Padding = "0"; //Ensure there's no padding #endregion #region Layout cells //Actually layout cells! float startx = TableBox.ClientLeft + HorizontalSpacing; float starty = TableBox.ClientTop + VerticalSpacing; float curx = startx; float cury = starty; float maxRight = startx; float maxBottom = 0f; int currentrow = 0; foreach (CssBox row in AllRows) { if (row is CssAnonymousSpaceBlockBox || row is CssAnonymousSpaceBox) { continue; } curx = startx; curCol = 0; foreach (CssBox cell in row.Boxes) { if (curCol >= ColumnWidths.Length) { break; } int rowspan = GetRowSpan(cell); float width = GetCellWidth(GetCellRealColumnIndex(row, cell), cell); cell.Location = new PointF(curx, cury); cell.Size = new SizeF(width, 0f); cell.MeasureBounds(g); //That will automatically set the bottom of the cell //Alter max bottom only if row is cell's row + cell's rowspan - 1 SpacingBox sb = cell as SpacingBox; if (sb != null) { if (sb.EndRow == currentrow) { maxBottom = Math.Max(maxBottom, sb.ExtendedBox.ActualBottom); } } else if (rowspan == 1) { maxBottom = Math.Max(maxBottom, cell.ActualBottom); } maxRight = Math.Max(maxRight, cell.ActualRight); curCol++; curx = cell.ActualRight + HorizontalSpacing; } foreach (CssBox cell in row.Boxes) { SpacingBox spacer = cell as SpacingBox; if (spacer == null && GetRowSpan(cell) == 1) { cell.ActualBottom = maxBottom; CssLayoutEngine.ApplyCellVerticalAlignment(g, cell); } else if (spacer != null && spacer.EndRow == currentrow) { spacer.ExtendedBox.ActualBottom = maxBottom; CssLayoutEngine.ApplyCellVerticalAlignment(g, spacer.ExtendedBox); } } cury = maxBottom + VerticalSpacing; currentrow++; } TableBox.ActualRight = maxRight + HorizontalSpacing + TableBox.ActualBorderRightWidth; TableBox.ActualBottom = maxBottom + VerticalSpacing + TableBox.ActualBorderBottomWidth; #endregion }
private void Analyze(Graphics g) { int num; List <CssBox> .Enumerator enumerator; this.GetAvailableWidth(); float availableCellWidth = float.NaN; foreach (CssBox box in this.TableBox.Boxes) { box.RemoveAnonymousSpaces(); string display = box.Display; string str = display; if (display == null) { continue; } if (_method0x6000713_1 == null) { _method0x6000713_1 = new Dictionary <string, int>(7) { { "table-caption", 0 }, { "table-column", 1 }, { "table-column-group", 2 }, { "table-footer-group", 3 }, { "table-header-group", 4 }, { "table-row", 5 }, { "table-row-group", 6 } }; } if (!_method0x6000713_1.TryGetValue(str, out num)) { continue; } switch (num) { case 0: { this._caption = box; continue; } case 1: { for (int i = 0; i < this.GetSpan(box); i++) { this.Columns.Add(this.CreateColumn(box)); } continue; } case 2: { if (box.Boxes.Count != 0) { enumerator = box.Boxes.GetEnumerator(); try { while (enumerator.MoveNext()) { CssBox current = enumerator.Current; int span = this.GetSpan(current); for (int j = 0; j < span; j++) { this.Columns.Add(this.CreateColumn(current)); } } continue; } finally { ((IDisposable)enumerator).Dispose(); } } else { int span1 = this.GetSpan(box); for (int k = 0; k < span1; k++) { this.Columns.Add(this.CreateColumn(box)); } continue; } break; } case 3: { if (this.FooterBox == null) { this._footerBox = box; continue; } else { this.BodyRows.Add(box); continue; } } case 4: { if (this.HeaderBox == null) { this._headerBox = box; continue; } else { this.BodyRows.Add(box); continue; } } case 5: { this.BodyRows.Add(box); continue; } case 6: { enumerator = box.Boxes.GetEnumerator(); try { while (enumerator.MoveNext()) { CssBox cssBox = enumerator.Current; if (box.Display != "table-row") { continue; } this.BodyRows.Add(box); } continue; } finally { ((IDisposable)enumerator).Dispose(); } break; } default: { continue; } } } if (this.HeaderBox != null) { this._allRows.AddRange(this.HeaderBox.Boxes); } this._allRows.AddRange(this.BodyRows); if (this.FooterBox != null) { this._allRows.AddRange(this.FooterBox.Boxes); } if (!this.TableBox.TableFixed) { int num1 = 0; int num2 = 0; List <CssBox> bodyRows = this.BodyRows; foreach (CssBox bodyRow in bodyRows) { bodyRow.RemoveAnonymousSpaces(); num2 = 0; for (int l = 0; l < bodyRow.Boxes.Count; l++) { CssBox item = bodyRow.Boxes[l]; int rowSpan = this.GetRowSpan(item); int cellRealColumnIndex = this.GetCellRealColumnIndex(bodyRow, item); for (int m = num1 + 1; m < num1 + rowSpan; m++) { int num3 = 0; int num4 = 0; while (num4 <= bodyRows[m].Boxes.Count) { if (num3 != cellRealColumnIndex) { num3++; cellRealColumnIndex = cellRealColumnIndex - (this.GetColSpan(bodyRows[m].Boxes[num4]) - 1); num4++; } else { bodyRows[m].Boxes.Insert(num3, new CssTable.SpacingBox(this.TableBox, ref item, num1)); break; } } } num2++; } num1++; } this.TableBox.TableFixed = true; } this._rowCount = this.BodyRows.Count + (this.HeaderBox != null ? this.HeaderBox.Boxes.Count : 0) + (this.FooterBox != null ? this.FooterBox.Boxes.Count : 0); if (this.Columns.Count <= 0) { foreach (CssBox allRow in this.AllRows) { this._columnCount = Math.Max(this._columnCount, allRow.Boxes.Count); } } else { this._columnCount = this.Columns.Count; } this._columnWidths = new float[this._columnCount]; for (int n = 0; n < (int)this._columnWidths.Length; n++) { this._columnWidths[n] = float.NaN; } availableCellWidth = this.GetAvailableCellWidth(); if (this.Columns.Count <= 0) { foreach (CssBox allRow1 in this.AllRows) { for (int o = 0; o < this._columnCount; o++) { if (float.IsNaN(this.ColumnWidths[o]) && o < allRow1.Boxes.Count && allRow1.Boxes[o].Display == "table-cell") { CssLength cssLength = new CssLength(allRow1.Boxes[o].Width); if (cssLength.Number > 0f) { int colSpan = this.GetColSpan(allRow1.Boxes[o]); float number = 0f; if (cssLength.IsPercentage) { number = CssValue.ParseNumber(allRow1.Boxes[o].Width, availableCellWidth); } else if (cssLength.Unit == CssLength.CssUnit.Pixels || cssLength.Unit == CssLength.CssUnit.None) { number = cssLength.Number; } number = number / Convert.ToSingle(colSpan); for (int p = o; p < o + colSpan; p++) { this.ColumnWidths[p] = number; } } } } } } else { for (int q = 0; q < this.Columns.Count; q++) { CssLength cssLength1 = new CssLength(this.Columns[q].Width); if (cssLength1.Number > 0f) { if (cssLength1.IsPercentage) { this.ColumnWidths[q] = CssValue.ParseNumber(this.Columns[q].Width, availableCellWidth); } else if (cssLength1.Unit == CssLength.CssUnit.Pixels || cssLength1.Unit == CssLength.CssUnit.None) { this.ColumnWidths[q] = cssLength1.Number; } } } } if (!this.WidthSpecified) { float[] singleArray = new float[(int)this.ColumnWidths.Length]; foreach (CssBox cssBox1 in this.AllRows) { for (int r = 0; r < cssBox1.Boxes.Count; r++) { int cellRealColumnIndex1 = this.GetCellRealColumnIndex(cssBox1, cssBox1.Boxes[r]); if (float.IsNaN(this.ColumnWidths[cellRealColumnIndex1]) && r < cssBox1.Boxes.Count && this.GetColSpan(cssBox1.Boxes[r]) == 1) { singleArray[cellRealColumnIndex1] = Math.Max(singleArray[cellRealColumnIndex1], cssBox1.Boxes[r].GetFullWidth(g)); } } } for (int s = 0; s < (int)this.ColumnWidths.Length; s++) { if (float.IsNaN(this.ColumnWidths[s])) { this.ColumnWidths[s] = singleArray[s]; } } } else { int num5 = 0; float columnWidths = 0f; for (int t = 0; t < (int)this.ColumnWidths.Length; t++) { if (!float.IsNaN(this.ColumnWidths[t])) { columnWidths = columnWidths + this.ColumnWidths[t]; } else { num5++; } } float single = (availableCellWidth - columnWidths) / Convert.ToSingle(num5); for (int u = 0; u < (int)this.ColumnWidths.Length; u++) { if (float.IsNaN(this.ColumnWidths[u])) { this.ColumnWidths[u] = single; } } } int num6 = 0; float single1 = 1f; while (this.GetWidthSum() > this.GetAvailableWidth() && this.CanReduceWidth()) { while (!this.CanReduceWidth(num6)) { num6++; } this.ColumnWidths[num6] = this.ColumnWidths[num6] - single1; num6++; if (num6 < (int)this.ColumnWidths.Length) { continue; } num6 = 0; } foreach (CssBox allRow2 in this.AllRows) { foreach (CssBox box1 in allRow2.Boxes) { int colSpan1 = this.GetColSpan(box1); int cellRealColumnIndex2 = this.GetCellRealColumnIndex(allRow2, box1); int num7 = cellRealColumnIndex2 + colSpan1 - 1; if (this.ColumnWidths[cellRealColumnIndex2] >= this.ColumnMinWidths[cellRealColumnIndex2]) { continue; } float columnMinWidths = this.ColumnMinWidths[cellRealColumnIndex2] - this.ColumnWidths[cellRealColumnIndex2]; this.ColumnWidths[num7] = this.ColumnMinWidths[num7]; if (cellRealColumnIndex2 >= (int)this.ColumnWidths.Length - 1) { continue; } this.ColumnWidths[cellRealColumnIndex2 + 1] = this.ColumnWidths[cellRealColumnIndex2 + 1] - columnMinWidths; } } this.TableBox.Padding = "0"; float clientLeft = this.TableBox.ClientLeft + this.HorizontalSpacing; float clientTop = this.TableBox.ClientTop + this.VerticalSpacing; float actualRight = clientLeft; float verticalSpacing = clientTop; float single2 = clientLeft; float single3 = 0f; int num8 = 0; foreach (CssBox cssBox2 in this.AllRows) { if (cssBox2 is CssAnonymousSpaceBlockBox || cssBox2 is CssAnonymousSpaceBox) { continue; } actualRight = clientLeft; num6 = 0; foreach (CssBox pointF in cssBox2.Boxes) { if (num6 >= (int)this.ColumnWidths.Length) { break; } int rowSpan1 = this.GetRowSpan(pointF); float cellWidth = this.GetCellWidth(this.GetCellRealColumnIndex(cssBox2, pointF), pointF); pointF.Location = new PointF(actualRight, verticalSpacing); pointF.Size = new SizeF(cellWidth, 0f); pointF.MeasureBounds(g); CssTable.SpacingBox spacingBox = pointF as CssTable.SpacingBox; if (spacingBox != null) { if (spacingBox.EndRow == num8) { single3 = Math.Max(single3, spacingBox.ExtendedBox.ActualBottom); } } else if (rowSpan1 == 1) { single3 = Math.Max(single3, pointF.ActualBottom); } single2 = Math.Max(single2, pointF.ActualRight); num6++; actualRight = pointF.ActualRight + this.HorizontalSpacing; } foreach (CssBox box2 in cssBox2.Boxes) { CssTable.SpacingBox spacingBox1 = box2 as CssTable.SpacingBox; if (spacingBox1 != null || this.GetRowSpan(box2) != 1) { if (spacingBox1 == null || spacingBox1.EndRow != num8) { continue; } spacingBox1.ExtendedBox.ActualBottom = single3; CssLayoutEngine.ApplyCellVerticalAlignment(g, spacingBox1.ExtendedBox); } else { box2.ActualBottom = single3; CssLayoutEngine.ApplyCellVerticalAlignment(g, box2); } } verticalSpacing = single3 + this.VerticalSpacing; num8++; } this.TableBox.ActualRight = single2 + this.HorizontalSpacing + this.TableBox.ActualBorderRightWidth; this.TableBox.ActualBottom = single3 + this.VerticalSpacing + this.TableBox.ActualBorderBottomWidth; }
/// <summary> /// Converts an HTML length into a Css length /// </summary> /// <param name="htmlLength"></param> /// <returns></returns> private string TranslateLength(string htmlLength) { CssLength len = new CssLength(htmlLength); if (len.HasError) { return htmlLength + "px"; } return htmlLength; }
/// <summary> /// Gets the available width for the whole table. /// It also sets the value of <see cref="WidthSpecified"/> /// </summary> /// <returns></returns> /// <remarks> /// The table's width can be larger than the result of this method, because of the minimum /// size that individual boxes. /// </remarks> private float GetAvailableWidth() { CssLength tblen = new CssLength(TableBox.Width); if (tblen.Number > 0) { _widthSpecified = true; if (tblen.IsPercentage) { return CssValue.ParseNumber(tblen.Length, TableBox.ParentBox.AvailableWidth); } else { return tblen.Number; } } else { return TableBox.ParentBox.AvailableWidth; } }
/// <summary> /// Analyzes the Table and assigns values to this CssTable object. /// To be called from the constructor /// </summary> private void Analyze(Graphics g) { float availSpace = GetAvailableWidth(); float availCellSpace = float.NaN; //Will be set later #region Assign box kinds foreach (CssBox b in TableBox.Boxes) { b.RemoveAnonymousSpaces(); switch (b.Display) { case CssConstants.TableCaption: _caption = b; break; case CssConstants.TableColumn: for (int i = 0; i < GetSpan(b); i++) { Columns.Add(CreateColumn(b)); } break; case CssConstants.TableColumnGroup: if (b.Boxes.Count == 0) { int gspan = GetSpan(b); for (int i = 0; i < gspan; i++) { Columns.Add(CreateColumn(b)); } } else { foreach (CssBox bb in b.Boxes) { int bbspan = GetSpan(bb); for (int i = 0; i < bbspan; i++) { Columns.Add(CreateColumn(bb)); } } } break; case CssConstants.TableFooterGroup: if (FooterBox != null) BodyRows.Add(b); else _footerBox = b; break; case CssConstants.TableHeaderGroup: if (HeaderBox != null) BodyRows.Add(b); else _headerBox = b; break; case CssConstants.TableRow: BodyRows.Add(b); break; case CssConstants.TableRowGroup: foreach (CssBox bb in b.Boxes) if (b.Display == CssConstants.TableRow) BodyRows.Add(b); break; default: break; } } #endregion #region Gather AllRows if (HeaderBox != null) _allRows.AddRange(HeaderBox.Boxes); _allRows.AddRange(BodyRows); if (FooterBox != null) _allRows.AddRange(FooterBox.Boxes); #endregion #region Insert EmptyBoxes for vertical cell spanning if (!TableBox.TableFixed) { int currow = 0; int curcol = 0; List<CssBox> rows = BodyRows; foreach (CssBox row in rows) { row.RemoveAnonymousSpaces(); curcol = 0; for(int k = 0; k < row.Boxes.Count ; k++) { CssBox cell = row.Boxes[k]; int rowspan = GetRowSpan(cell); int realcol = GetCellRealColumnIndex(row, cell); //Real column of the cell for (int i = currow + 1; i < currow + rowspan; i++) { int colcount = 0; for (int j = 0; j <= rows[i].Boxes.Count; j++) { if (colcount == realcol) { rows[i].Boxes.Insert(colcount, new SpacingBox(TableBox, ref cell, currow)); break; } colcount++; realcol -= GetColSpan(rows[i].Boxes[j]) - 1; } } // End for (int i = currow + 1; i < currow + rowspan; i++) curcol++; } /// End foreach (Box cell in row.Boxes) currow++; } /// End foreach (Box row in rows) TableBox.TableFixed = true; } /// End if (!TableBox.TableFixed) #endregion #region Determine Row and Column Count, and ColumnWidths //Rows _rowCount = BodyRows.Count + (HeaderBox != null ? HeaderBox.Boxes.Count : 0) + (FooterBox != null ? FooterBox.Boxes.Count : 0); //Columns if (Columns.Count > 0) _columnCount = Columns.Count; else foreach (CssBox b in AllRows) //Check trhough rows _columnCount = Math.Max(_columnCount, b.Boxes.Count); //Initialize column widths array _columnWidths = new float[_columnCount]; //Fill them with NaNs for (int i = 0; i < _columnWidths.Length; i++) _columnWidths[i] = float.NaN; availCellSpace = GetAvailableCellWidth(); if (Columns.Count > 0) { #region Fill ColumnWidths array by scanning column widths for (int i = 0; i < Columns.Count; i++) { CssLength len = new CssLength(Columns[i].Width); //Get specified width if (len.Number > 0) //If some width specified { if (len.IsPercentage)//Get width as a percentage { ColumnWidths[i] = CssValue.ParseNumber(Columns[i].Width, availCellSpace); } else if (len.Unit == CssLength.CssUnit.Pixels || len.Unit == CssLength.CssUnit.None) { ColumnWidths[i] = len.Number; //Get width as an absolute-pixel value } } } #endregion } else { #region Fill ColumnWidths array by scanning width in table-cell definitions foreach (CssBox row in AllRows) { //Check for column width in table-cell definitions for (int i = 0; i < _columnCount; i++) { if (float.IsNaN(ColumnWidths[i]) && //Check if no width specified for column i < row.Boxes.Count && //And there's a box to check row.Boxes[i].Display == CssConstants.TableCell)//And the box is a table-cell { CssLength len = new CssLength(row.Boxes[i].Width); //Get specified width if (len.Number > 0) //If some width specified { int colspan = GetColSpan(row.Boxes[i]); float flen = 0f; if (len.IsPercentage)//Get width as a percentage { flen = CssValue.ParseNumber(row.Boxes[i].Width, availCellSpace); } else if (len.Unit == CssLength.CssUnit.Pixels || len.Unit == CssLength.CssUnit.None) { flen = len.Number; //Get width as an absolute-pixel value } flen /= Convert.ToSingle(colspan); for (int j = i; j < i + colspan; j++) { ColumnWidths[j] = flen; } } } } } #endregion } #endregion #region Determine missing Column widths if (WidthSpecified) //If a width was specified, { //Assign NaNs equally with space left after gathering not-NaNs int numberOfNans = 0; float occupedSpace = 0f; //Calculate number of NaNs and occuped space for (int i = 0; i < ColumnWidths.Length; i++) if (float.IsNaN(ColumnWidths[i])) numberOfNans++; else occupedSpace += ColumnWidths[i]; //Determine width that will be assigned to un asigned widths float nanWidth = (availCellSpace - occupedSpace) / Convert.ToSingle(numberOfNans); for (int i = 0; i < ColumnWidths.Length; i++) if (float.IsNaN(ColumnWidths[i])) ColumnWidths[i] = nanWidth; } else { //Assign NaNs using full width float[] _maxFullWidths = new float[ColumnWidths.Length]; //Get the maximum full length of NaN boxes foreach (CssBox row in AllRows) { for (int i = 0; i < row.Boxes.Count; i++) { int col = GetCellRealColumnIndex(row, row.Boxes[i]); if (float.IsNaN(ColumnWidths[col]) && i < row.Boxes.Count && GetColSpan(row.Boxes[i]) == 1) { _maxFullWidths[col] = Math.Max(_maxFullWidths[col], row.Boxes[i].GetFullWidth(g)); } } } for (int i = 0; i < ColumnWidths.Length; i++) if (float.IsNaN(ColumnWidths[i])) ColumnWidths[i] = _maxFullWidths[i]; } #endregion #region Reduce widths if necessary int curCol = 0; float reduceAmount = 1f; //While table width is larger than it should, and width is reductable while (GetWidthSum() > GetAvailableWidth() && CanReduceWidth()) { while (!CanReduceWidth(curCol)) curCol++; ColumnWidths[curCol] -= reduceAmount; curCol++; if (curCol >= ColumnWidths.Length) curCol = 0; } #endregion #region Check for minimum sizes (increment widths if necessary) foreach (CssBox row in AllRows) { foreach (CssBox cell in row.Boxes) { int colspan = GetColSpan(cell); int col = GetCellRealColumnIndex(row, cell); int affectcol = col + colspan - 1; if (ColumnWidths[col] < ColumnMinWidths[col]) { float diff = ColumnMinWidths[col] - ColumnWidths[col]; ColumnWidths[affectcol] = ColumnMinWidths[affectcol]; if (col < ColumnWidths.Length - 1) { ColumnWidths[col + 1] -= diff; } } } } #endregion #region Set table padding TableBox.Padding = "0"; //Ensure there's no padding #endregion #region Layout cells //Actually layout cells! float startx = TableBox.ClientLeft + HorizontalSpacing; float starty = TableBox.ClientTop + VerticalSpacing; float curx = startx; float cury = starty; float maxRight = startx; float maxBottom = 0f; int currentrow = 0; foreach (CssBox row in AllRows) { if (row is CssAnonymousSpaceBlockBox || row is CssAnonymousSpaceBox) continue; curx = startx; curCol = 0; foreach (CssBox cell in row.Boxes) { if (curCol >= ColumnWidths.Length) break; int rowspan = GetRowSpan(cell); float width = GetCellWidth(GetCellRealColumnIndex(row, cell), cell); cell.Location = new PointF(curx, cury); cell.Size = new SizeF(width, 0f); cell.MeasureBounds(g); //That will automatically set the bottom of the cell //Alter max bottom only if row is cell's row + cell's rowspan - 1 SpacingBox sb = cell as SpacingBox; if (sb != null) { if (sb.EndRow == currentrow) { maxBottom = Math.Max(maxBottom, sb.ExtendedBox.ActualBottom); } } else if(rowspan == 1) { maxBottom = Math.Max(maxBottom, cell.ActualBottom); } maxRight = Math.Max(maxRight, cell.ActualRight); curCol++; curx = cell.ActualRight + HorizontalSpacing; } foreach (CssBox cell in row.Boxes) { SpacingBox spacer = cell as SpacingBox; if (spacer == null && GetRowSpan(cell) == 1) { cell.ActualBottom = maxBottom; CssLayoutEngine.ApplyCellVerticalAlignment(g, cell); } else if(spacer != null && spacer.EndRow == currentrow) { spacer.ExtendedBox.ActualBottom = maxBottom; CssLayoutEngine.ApplyCellVerticalAlignment(g, spacer.ExtendedBox); } } cury = maxBottom + VerticalSpacing; currentrow++; } TableBox.ActualRight = maxRight + HorizontalSpacing + TableBox.ActualBorderRightWidth; TableBox.ActualBottom = maxBottom + VerticalSpacing + TableBox.ActualBorderBottomWidth; #endregion }