/** * private ctor used for fit operation */ private TableArea(MathMLTableElement e, Area[] cells, BoundingBox box, PointF[] solidLines, PointF[] dashedLines, Area source) : base(cells, source) { this.element = e; this.dashedLines = dashedLines; this.solidLines = solidLines; this.box = box; }
private static Length[] GetColumnSpacing(MathMLTableElement table, int spaceCount) { Length[] columnSpacing = table.ColumnSpacing; Length[] columnSpaces = new Length[spaceCount]; for (int i = 0; i < columnSpaces.Length; i++) { columnSpaces[i] = columnSpacing[i < columnSpacing.Length ? i : columnSpacing.Length - 1]; } return(columnSpaces); }
/** * grab the column styles from the table. */ private static LineStyle[] GetColumnLines(MathMLTableElement table, int columnCount) { LineStyle[] columnLines = table.ColumnLines; LineStyle[] result = new LineStyle[columnCount - 1]; for (int i = 0; i < result.Length; i++) { result[i] = columnLines[i < columnLines.Length ? i : columnLines.Length - 1]; } return(result); }
private static LineStyle[] GetRowLines(MathMLTableElement table, int rowCount) { LineStyle[] rowLines = table.RowLines; LineStyle[] result = new LineStyle[rowCount - 1]; for (int i = 0; i < result.Length; i++) { result[i] = rowLines[i < rowLines.Length ? i : rowLines.Length - 1]; } return(result); }
private static Length[] GetRowSpacing(MathMLTableElement table, int spaceCount) { Length[] rowSpacing = table.RowSpacing; Length[] rowSpaces = new Length[spaceCount]; for (int i = 0; i < rowSpaces.Length; i++) { rowSpaces[i] = rowSpacing[i < rowSpacing.Length ? i : rowSpacing.Length - 1]; } return(rowSpaces); }
/** * a table element generaly has fewer length types than columns. This * method, using the spec of setting the last length from the table's * 'columnwidths' creates a array of lengths, one for each column, and * sets each item to the last real value if the lenthts from the table * is less than the number of columns */ private static Length[] GetColumnWidths(MathMLTableElement table, int columnCount) { // cache table column widths Length[] tcw = table.ColumnWidth; Length[] columnWidths = new Length[columnCount]; for (int i = 0; i < columnWidths.Length; i++) { columnWidths[i] = tcw[i < tcw.Length ? i : tcw.Length - 1]; } return(columnWidths); }
object MathML.MathMLVisitor.Visit(MathMLTableElement e, object args) { if (selection == SelectionType.Prev || selection == SelectionType.Next) { return(((MathMLElement)e.ParentNode).Accept(this, e)); } else { MathMLElement elm = e.FirstChild as MathMLElement; return(elm != null?elm.Accept(this, args) : e); } }
/** * initialize the shift and vertical extent vars * The final shift is calcuated by the formatter because it requires information * about the formatted size of the cell area. */ private static void CalculateShiftAndSize(IFormattingContext ctx, MathMLTableElement table, Row[] rows, Column[] columns, ref BoundingBox box, ref float shift) { shift = 0; TableAlign align = table.Align; float verticalExtent = 0; float width = 0; for (int i = 0; i < rows.Length; i++) { verticalExtent += rows[i].VerticalExtent; } for (int i = 0; i < columns.Length; i++) { width += columns[i].Width; } shift = -verticalExtent; box = BoundingBox.New(width, verticalExtent, 0); }
/** * calculate a table shift * the initially consists of entierly height, this is a value given to the * TableArea object to determine the vertical location of a table. * * This value is also used to modify the bounding box that is returned from this * class that is used for the TableArea */ private static float GetTableShift(IFormattingContext ctx, MathMLTableElement table, BoundingBox tableExtent) { float shift = 0; // orient the row in the vertical direction, can be one of the following // (top | bottom | center | baseline | axis) [ rownumber ] // TODO rownumver is currently ignored switch (table.Align.Align) { case Align.Top: { shift = tableExtent.VerticalExtent; } break; case Align.Bottom: { shift = 0; } break; case Align.Center: { shift = tableExtent.VerticalExtent / 2.0f; } break; case Align.Axis: { // shift to the axis (shift up in the negative direction) shift = (tableExtent.VerticalExtent / 2.0f) - ctx.Axis; } break; default: { shift = tableExtent.VerticalExtent / 2.0f; } break; } return(shift); }
/** * calculates the minimum table width to satisfy all columns. * This uses each column's Width property to determine the minimum * required width to fit each column. * * pre-reqs: columns, column.Width and equalColumns have been set * readonly function */ private static float CalculateTableWidth(IFormattingContext ctx, MathMLTableElement table, Column[] columns, bool equalColumns, int effectiveColumns) { Length widthLength = table.Width; if(widthLength.Fixed) { return ctx.Evaluate(widthLength); } else { // length is auto, so need to calculate width from columns // sanity check Debug.Assert(widthLength.Type == LengthType.Auto, "table width is not fixed type but also is not auto"); // summed widths float sumFixWidth = 0; float sumScaleWidth = 0; if(equalColumns) { // equal spacing, space the largest column width equally // first find largest column width float maxWidth = 0; for(int i = 0; i < columns.Length; i++) { switch(columns[i].Type) { case ColumnType.Scale: sumScaleWidth += columns[i].ScaleWidth; break; case ColumnType.Fixed: sumFixWidth += columns[i].Width; break; default: // type is Auto or Fit if(columns[i].Width > maxWidth) maxWidth = columns[i].Width; break; } } return (((float)effectiveColumns * maxWidth) + sumFixWidth) / (1.0f - sumScaleWidth); } else { // look for a column that may have a wide min width but a very small percentage // value. In this case, we could have a column that is specified to take up 1% // of the table width, in that case, the rest of the table must be stretched // to take up the 99% float maxEvaluatedWidth = 0; // summed widths float sumAutoFitWidth = 0; for(int i = 0; i < columns.Length; i++) { switch(columns[i].Type) { case ColumnType.Scale: sumScaleWidth += columns[i].ScaleWidth; // evaluate the width of the scaled column using the current width // of the column float evalWidth = columns[i].Width / columns[i].ScaleWidth; if(evalWidth > maxEvaluatedWidth) maxEvaluatedWidth = evalWidth; break; case ColumnType.Fixed: sumFixWidth += columns[i].FixedWidth; break; default: // column type is Auto or Fit sumAutoFitWidth += columns[i].Width; break; } } float width = (sumAutoFitWidth + sumFixWidth) / (1.0f - sumScaleWidth); return Math.Max(width, maxEvaluatedWidth); } } }
/** * construct a new sizer. All calculations are done here. */ public MathMLTableSizer(IFormattingContext ctx, MathMLMeasurer measurer, MathMLTableElement table) { try { // copy the context because we change the stretch size so not to // stretch tables ctx = ctx.Clone(); ctx.Stretch = BoundingBox.New(); ctx.cacheArea = false; //MathMLMeasurer measurer = new MathMLMeasurer(); equalColumns = table.EqualColumns; // get the cells from the table and store them in a multi dim array cells = GetCells(table); // min area sizes for the cells BoundingBox[][] minCellSizes = measurer.MeasureElements(ctx, cells); DebugWriteCellSizes(minCellSizes); // count of columns that are actual table cells int cellColumnCount = GetCellColumnCount(cells); // column widths attr from dom Length[] columnWidths = GetColumnWidths(table, cellColumnCount); // column space attr from dom Length[] columnSpacing = GetColumnSpacing(table, cellColumnCount - 1); // frame spaceing attr from dom Length[] frameSpacing = table.FrameSpacing; // row spacing attr from dom Length[] rowSpacing = GetRowSpacing(table, cells.Length - 1); // create a set of columns from the cells columns = CreateColumns(ctx, measurer, cells, minCellSizes, cellColumnCount, columnWidths, columnSpacing, frameSpacing[0]); // create a set of row measurments, this is both the cell rows and spacing rows Row[] rows = CreateRows(ctx, cells, minCellSizes, rowSpacing, frameSpacing[1]); // adjust rows and columns so there is enough space to fit spanning cells AdjustSpanningCells(cells, minCellSizes, rows, columns); Debug.WriteLine("retrieved " + columns.Length + "total columns, "); DebugWriteColumnWidths("Initial Column Widths: "); // get the minimum area for the columns float tableWidth = CalculateTableWidth(ctx, table, columns, equalColumns, cellColumnCount); Debug.WriteLine("Minimum Table Width: " + tableWidth); // find the space needed to fit the availible for the auto and fit columns float availSpace = CalculateColumnAvailSpace(columns, tableWidth); Debug.WriteLine("Availible Space For Columns: " + availSpace); // set the table widths DistributeSpace(columns, tableWidth, availSpace, cellColumnCount, equalColumns); DebugWriteColumnWidths("Column Widths After Formatting: "); // calcuate the shift float shift = 0; CalculateShiftAndSize(ctx, table, rows, columns, ref box, ref shift); // create the cell sizes and offsets CreateCellSizesAndShifts(cells, rows, columns, ref cellSizes, ref cellShifts); // create the lines for the frame and cell separators LineStyle frame = table.Frame; LineStyle[] columnLines = GetColumnLines(table, cellColumnCount); LineStyle[] rowLines = GetRowLines(table, cells.Length); CreateLines(cellSizes, cells, rows, columns, columnLines, rowLines, frame); // set the shift tableShift = GetTableShift(ctx, table, box); } catch(Exception ex) { throw new Exception("Error constructing table sizer: " + ex.Message); } }
private static Length[] GetColumnSpacing(MathMLTableElement table, int spaceCount) { Length[] columnSpacing = table.ColumnSpacing; Length[] columnSpaces = new Length[spaceCount]; for(int i = 0; i < columnSpaces.Length; i++) { columnSpaces[i] = columnSpacing[i < columnSpacing.Length ? i : columnSpacing.Length - 1]; } return columnSpaces; }
/** * a table element generaly has fewer length types than columns. This * method, using the spec of setting the last length from the table's * 'columnwidths' creates a array of lengths, one for each column, and * sets each item to the last real value if the lenthts from the table * is less than the number of columns */ private static Length[] GetColumnWidths(MathMLTableElement table, int columnCount) { // cache table column widths Length[] tcw = table.ColumnWidth; Length[] columnWidths = new Length[columnCount]; for(int i = 0; i < columnWidths.Length; i++) { columnWidths[i] = tcw[i < tcw.Length ? i : tcw.Length - 1]; } return columnWidths; }
/** * grab the column styles from the table. */ private static LineStyle[] GetColumnLines(MathMLTableElement table, int columnCount) { LineStyle[] columnLines = table.ColumnLines; LineStyle[] result = new LineStyle[columnCount - 1]; for(int i = 0; i < result.Length; i++) { result[i] = columnLines[i < columnLines.Length ? i : columnLines.Length - 1]; } return result; }
private static LineStyle[] GetRowLines(MathMLTableElement table, int rowCount) { LineStyle[] rowLines = table.RowLines; LineStyle[] result = new LineStyle[rowCount - 1]; for(int i = 0; i < result.Length; i++) { result[i] = rowLines[i < rowLines.Length ? i : rowLines.Length - 1]; } return result; }
private static Length[] GetRowSpacing(MathMLTableElement table, int spaceCount) { Length[] rowSpacing = table.RowSpacing; Length[] rowSpaces = new Length[spaceCount]; for(int i = 0; i < rowSpaces.Length; i++) { rowSpaces[i] = rowSpacing[i < rowSpacing.Length ? i : rowSpacing.Length - 1]; } return rowSpaces; }
/** * grab all the cells from a table and return them in a 2 dimensional array * TODO optimize (cache) cell.attribute* calls */ public static MathMLTableCellElement[][] GetCells(MathMLTableElement table) { int i = 0; MathMLNodeList tableRows = table.Rows; MathMLTableCellElement[][] cells = new MathMLTableCellElement[tableRows.Count][]; int[] remainderCols = new int[0]; ArrayList rowCellsList = new ArrayList(); foreach(MathMLTableRowElement row in tableRows) { MathMLNodeList rowCells = row.Cells; rowCellsList.Clear(); foreach(MathMLTableCellElement cell in rowCells) { if(rowCellsList.Count < remainderCols.Length && remainderCols[rowCellsList.Count] > 0) { remainderCols[rowCellsList.Count] = remainderCols[rowCellsList.Count] - 1; rowCellsList.Add(null); } rowCellsList.Add(cell); for(int j = 1; j < cell.ColumnSpan; j++) { // deal with overlapping cells if(rowCellsList.Count < remainderCols.Length && remainderCols[rowCellsList.Count] > 0) { remainderCols[rowCellsList.Count] = remainderCols[rowCellsList.Count] - 1; } rowCellsList.Add(null); } } cells[i] = new MathMLTableCellElement[rowCellsList.Count]; for(int j = 0; j < rowCellsList.Count; j++) { cells[i][j] = (MathMLTableCellElement)rowCellsList[j]; } if(remainderCols.Length < cells[i].Length) { int[] tmp = new int[cells[i].Length]; for(int j = 0; j < remainderCols.Length; j++) { tmp[j] = remainderCols[j]; } for(int j = remainderCols.Length; j < tmp.Length; j++) { tmp[j] = 0; } remainderCols = tmp; } for(int j = 0; j < cells[i].Length; j++) { if(cells[i][j] != null) { Debug.Assert(remainderCols[j] == 0, "remainder columns value should be zero if we have a current cell"); remainderCols[j] = cells[i][j].RowSpan - 1; } } i++; // next row } return cells; }
/** * grab all the cells from a table and return them in a 2 dimensional array * TODO optimize (cache) cell.attribute* calls */ public static MathMLTableCellElement[][] GetCells(MathMLTableElement table) { int i = 0; MathMLNodeList tableRows = table.Rows; MathMLTableCellElement[][] cells = new MathMLTableCellElement[tableRows.Count][]; int[] remainderCols = new int[0]; ArrayList rowCellsList = new ArrayList(); foreach (MathMLTableRowElement row in tableRows) { MathMLNodeList rowCells = row.Cells; rowCellsList.Clear(); foreach (MathMLTableCellElement cell in rowCells) { if (rowCellsList.Count < remainderCols.Length && remainderCols[rowCellsList.Count] > 0) { remainderCols[rowCellsList.Count] = remainderCols[rowCellsList.Count] - 1; rowCellsList.Add(null); } rowCellsList.Add(cell); for (int j = 1; j < cell.ColumnSpan; j++) { // deal with overlapping cells if (rowCellsList.Count < remainderCols.Length && remainderCols[rowCellsList.Count] > 0) { remainderCols[rowCellsList.Count] = remainderCols[rowCellsList.Count] - 1; } rowCellsList.Add(null); } } cells[i] = new MathMLTableCellElement[rowCellsList.Count]; for (int j = 0; j < rowCellsList.Count; j++) { cells[i][j] = (MathMLTableCellElement)rowCellsList[j]; } if (remainderCols.Length < cells[i].Length) { int[] tmp = new int[cells[i].Length]; for (int j = 0; j < remainderCols.Length; j++) { tmp[j] = remainderCols[j]; } for (int j = remainderCols.Length; j < tmp.Length; j++) { tmp[j] = 0; } remainderCols = tmp; } for (int j = 0; j < cells[i].Length; j++) { if (cells[i][j] != null) { Debug.Assert(remainderCols[j] == 0, "remainder columns value should be zero if we have a current cell"); remainderCols[j] = cells[i][j].RowSpan - 1; } } i++; // next row } return(cells); }
/** * construct a new sizer. All calculations are done here. */ public MathMLTableSizer(IFormattingContext ctx, MathMLMeasurer measurer, MathMLTableElement table) { try { // copy the context because we change the stretch size so not to // stretch tables ctx = ctx.Clone(); ctx.Stretch = BoundingBox.New(); ctx.cacheArea = false; //MathMLMeasurer measurer = new MathMLMeasurer(); equalColumns = table.EqualColumns; // get the cells from the table and store them in a multi dim array cells = GetCells(table); // min area sizes for the cells BoundingBox[][] minCellSizes = measurer.MeasureElements(ctx, cells); DebugWriteCellSizes(minCellSizes); // count of columns that are actual table cells int cellColumnCount = GetCellColumnCount(cells); // column widths attr from dom Length[] columnWidths = GetColumnWidths(table, cellColumnCount); // column space attr from dom Length[] columnSpacing = GetColumnSpacing(table, cellColumnCount - 1); // frame spaceing attr from dom Length[] frameSpacing = table.FrameSpacing; // row spacing attr from dom Length[] rowSpacing = GetRowSpacing(table, cells.Length - 1); // create a set of columns from the cells columns = CreateColumns(ctx, measurer, cells, minCellSizes, cellColumnCount, columnWidths, columnSpacing, frameSpacing[0]); // create a set of row measurments, this is both the cell rows and spacing rows Row[] rows = CreateRows(ctx, cells, minCellSizes, rowSpacing, frameSpacing[1]); // adjust rows and columns so there is enough space to fit spanning cells AdjustSpanningCells(cells, minCellSizes, rows, columns); Debug.WriteLine("retrieved " + columns.Length + "total columns, "); DebugWriteColumnWidths("Initial Column Widths: "); // get the minimum area for the columns float tableWidth = CalculateTableWidth(ctx, table, columns, equalColumns, cellColumnCount); Debug.WriteLine("Minimum Table Width: " + tableWidth); // find the space needed to fit the availible for the auto and fit columns float availSpace = CalculateColumnAvailSpace(columns, tableWidth); Debug.WriteLine("Availible Space For Columns: " + availSpace); // set the table widths DistributeSpace(columns, tableWidth, availSpace, cellColumnCount, equalColumns); DebugWriteColumnWidths("Column Widths After Formatting: "); // calcuate the shift float shift = 0; CalculateShiftAndSize(ctx, table, rows, columns, ref box, ref shift); // create the cell sizes and offsets CreateCellSizesAndShifts(cells, rows, columns, ref cellSizes, ref cellShifts); // create the lines for the frame and cell separators LineStyle frame = table.Frame; LineStyle[] columnLines = GetColumnLines(table, cellColumnCount); LineStyle[] rowLines = GetRowLines(table, cells.Length); CreateLines(cellSizes, cells, rows, columns, columnLines, rowLines, frame); // set the shift tableShift = GetTableShift(ctx, table, box); } catch (Exception ex) { throw new Exception("Error constructing table sizer: " + ex.Message); } }
/** * initialize the shift and vertical extent vars * The final shift is calcuated by the formatter because it requires information * about the formatted size of the cell area. */ private static void CalculateShiftAndSize(IFormattingContext ctx, MathMLTableElement table, Row[] rows, Column[] columns, ref BoundingBox box, ref float shift) { shift = 0; TableAlign align = table.Align; float verticalExtent = 0; float width = 0; for(int i = 0; i < rows.Length; i++) { verticalExtent += rows[i].VerticalExtent; } for(int i = 0; i < columns.Length; i++) { width += columns[i].Width; } shift = -verticalExtent; box = BoundingBox.New(width, verticalExtent, 0); }
public TableArea(MathMLTableElement e, Area[] cells, BoundingBox box, PointF[] solidLines, PointF[] dashedLines) : this(e, cells, box, solidLines, dashedLines, null) { }
/** * calculate a table shift * the initially consists of entierly height, this is a value given to the * TableArea object to determine the vertical location of a table. * * This value is also used to modify the bounding box that is returned from this * class that is used for the TableArea */ private static float GetTableShift(IFormattingContext ctx, MathMLTableElement table, BoundingBox tableExtent) { float shift = 0; // orient the row in the vertical direction, can be one of the following // (top | bottom | center | baseline | axis) [ rownumber ] // TODO rownumver is currently ignored switch(table.Align.Align) { case Align.Top: { shift = tableExtent.VerticalExtent; } break; case Align.Bottom: { shift = 0; } break; case Align.Center: { shift = tableExtent.VerticalExtent / 2.0f; } break; case Align.Axis: { // shift to the axis (shift up in the negative direction) shift = (tableExtent.VerticalExtent / 2.0f) -ctx.Axis; } break; default: { shift = tableExtent.VerticalExtent / 2.0f; } break; } return shift; }
object MathML.MathMLVisitor.Visit(MathMLTableElement e, object args) { MathMLTableSizer sizer = new MathMLTableSizer((IFormattingContext)args, this, e); return(sizer.BoundingBox); }
/** * calculates the minimum table width to satisfy all columns. * This uses each column's Width property to determine the minimum * required width to fit each column. * * pre-reqs: columns, column.Width and equalColumns have been set * readonly function */ private static float CalculateTableWidth(IFormattingContext ctx, MathMLTableElement table, Column[] columns, bool equalColumns, int effectiveColumns) { Length widthLength = table.Width; if (widthLength.Fixed) { return(ctx.Evaluate(widthLength)); } else { // length is auto, so need to calculate width from columns // sanity check Debug.Assert(widthLength.Type == LengthType.Auto, "table width is not fixed type but also is not auto"); // summed widths float sumFixWidth = 0; float sumScaleWidth = 0; if (equalColumns) { // equal spacing, space the largest column width equally // first find largest column width float maxWidth = 0; for (int i = 0; i < columns.Length; i++) { switch (columns[i].Type) { case ColumnType.Scale: sumScaleWidth += columns[i].ScaleWidth; break; case ColumnType.Fixed: sumFixWidth += columns[i].Width; break; default: // type is Auto or Fit if (columns[i].Width > maxWidth) { maxWidth = columns[i].Width; } break; } } return((((float)effectiveColumns * maxWidth) + sumFixWidth) / (1.0f - sumScaleWidth)); } else { // look for a column that may have a wide min width but a very small percentage // value. In this case, we could have a column that is specified to take up 1% // of the table width, in that case, the rest of the table must be stretched // to take up the 99% float maxEvaluatedWidth = 0; // summed widths float sumAutoFitWidth = 0; for (int i = 0; i < columns.Length; i++) { switch (columns[i].Type) { case ColumnType.Scale: sumScaleWidth += columns[i].ScaleWidth; // evaluate the width of the scaled column using the current width // of the column float evalWidth = columns[i].Width / columns[i].ScaleWidth; if (evalWidth > maxEvaluatedWidth) { maxEvaluatedWidth = evalWidth; } break; case ColumnType.Fixed: sumFixWidth += columns[i].FixedWidth; break; default: // column type is Auto or Fit sumAutoFitWidth += columns[i].Width; break; } } float width = (sumAutoFitWidth + sumFixWidth) / (1.0f - sumScaleWidth); return(Math.Max(width, maxEvaluatedWidth)); } } }
object MathML.MathMLVisitor.Visit(MathMLTableElement e, object args) { MathMLTableSizer sizer = new MathMLTableSizer((IFormattingContext)args, this, e); return sizer.BoundingBox; }