All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.itextpdf.layout.renderer.GridSizer Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2024 Apryse Group NV
    Authors: Apryse Software.

    This program is offered under a commercial and under the AGPL license.
    For commercial licensing, contact us at https://itextpdf.com/sales.  For AGPL licensing, see below.

    AGPL licensing:
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see .
 */
package com.itextpdf.layout.renderer;

import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.layout.properties.grid.AutoValue;
import com.itextpdf.layout.properties.grid.GridValue;
import com.itextpdf.layout.renderer.Grid.GridOrder;
import com.itextpdf.layout.renderer.GridTrackSizer.TrackSizingResult;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

// 12.1. Grid Sizing Algorithm
/**
 * Class representing grid sizing algorithm.
 */
class GridSizer {
    private final Grid grid;
    private final List templateColumns;
    private final List templateRows;
    private final GridValue columnAutoWidth;
    private final GridValue rowAutoHeight;
    private final float columnGap;
    private final float rowGap;
    private final Rectangle actualBBox;
    private float containerHeight;

    /**
     * Creates new grid sizer instance.
     *
     * @param grid grid to size
     * @param templateColumns template values for columns
     * @param templateRows template values for rows
     * @param columnAutoWidth value which used to size columns out of template range
     * @param rowAutoHeight value which used to size rows out of template range
     * @param columnGap gap size between columns
     * @param rowGap gap size between rows
     * @param actualBBox actual bbox which restricts sizing algorithm
     */
    GridSizer(Grid grid, List templateColumns, List templateRows,
              GridValue columnAutoWidth, GridValue rowAutoHeight, float columnGap, float rowGap,
              Rectangle actualBBox) {
        this.grid = grid;
        this.templateColumns = templateColumns;
        this.templateRows = templateRows;
        this.columnAutoWidth = columnAutoWidth;
        this.rowAutoHeight = rowAutoHeight;
        this.columnGap = columnGap;
        this.rowGap = rowGap;
        this.actualBBox = actualBBox;
    }

    /**
     * Resolves grid track sizes.
     */
    public void sizeGrid() {
        // 1. First, the track sizing algorithm is used to resolve the sizes of the grid columns.
        resolveGridColumns();
        // 2. Next, the track sizing algorithm resolves the sizes of the grid rows.
        resolveGridRows();
    }

    /**
     * Gets grid container height.
     * Use this method only after calling {@link GridSizer#sizeGrid()}.
     *
     * @return grid container height covered by row template
     */
    public float getContainerHeight() {
        return containerHeight;
    }

    private void resolveGridRows() {
        List rowsValues = new ArrayList<>();
        for (int i = 0; i < grid.getNumberOfRows(); i++) {
            if (templateRows != null
                    && i - grid.getRowOffset() < templateRows.size()
                    && i - grid.getRowOffset() >= 0) {
                rowsValues.add(templateRows.get(i - grid.getRowOffset()));
            } else if (rowAutoHeight != null) {
                rowsValues.add(rowAutoHeight);
            } else {
                rowsValues.add(AutoValue.VALUE);
            }
        }

        GridTrackSizer gridTrackSizer = new GridTrackSizer(grid, rowsValues, rowGap,
                actualBBox.getHeight(), GridOrder.ROW);
        TrackSizingResult result = gridTrackSizer.sizeTracks();
        List rows = result.getTrackSizesAndExpandPercents(rowsValues);
        for (GridCell cell : grid.getUniqueGridCells(GridOrder.ROW)) {
            float y = 0.0f;
            for (int currentRow = 0; currentRow < cell.getRowStart(); ++currentRow) {
                y += (float) rows.get(currentRow);
                y += rowGap;
            }
            cell.getLayoutArea().setY(y);

            float cellHeight = 0.0f;
            float[] rowSizes = new float[cell.getRowEnd() - cell.getRowStart()];
            int rowSizesIdx = 0;
            for (int i = cell.getRowStart(); i < cell.getRowEnd(); ++i) {
                rowSizes[rowSizesIdx] = (float) rows.get(i);
                if (rowSizesIdx != 0) {
                    // We take into account only top gap and not bottom one
                    rowSizes[rowSizesIdx] += rowGap;
                }
                ++rowSizesIdx;
                cellHeight += (float) rows.get(i);
            }
            //Preserve row sizes for split
            cell.setRowSizes(rowSizes);
            cellHeight += (cell.getGridHeight() - 1) * rowGap;
            cell.getLayoutArea().setHeight(cellHeight);
        }

        containerHeight = calculateGridOccupiedHeight(result.getTrackSizes());
    }

    /**
     * Calculate grid container occupied area based on original (non-expanded percentages) track sizes.
     *
     * @param originalSizes original track sizes
     * @return grid container occupied area
     */
    private float calculateGridOccupiedHeight(List originalSizes) {
        // Calculate explicit height to ensure that even empty rows which covered by template would be considered
        float minHeight = 0.0f;
        for (int i = 0; i < (templateRows == null ? 0 : Math.min(templateRows.size(), originalSizes.size())); ++i) {
            minHeight += (float) originalSizes.get(i);
        }
        float maxHeight = sum(originalSizes);
        // Add gaps
        minHeight += (grid.getNumberOfRows() - 1) * rowGap;
        maxHeight += (grid.getNumberOfRows() - 1) * rowGap;
        float occupiedHeight = 0.0f;
        Collection cells = grid.getUniqueGridCells(GridOrder.ROW);
        for (GridCell cell : cells) {
            occupiedHeight = Math.max(occupiedHeight, cell.getLayoutArea().getTop());
        }
        return Math.max(Math.min(maxHeight, occupiedHeight), minHeight);
    }

    private float sum(List trackSizes) {
        float sum = 0.0f;
        for (Float size : trackSizes) {
            sum += (float) size;
        }
        return sum;
    }

    private void resolveGridColumns() {
        List colsValues = new ArrayList<>();
        for (int i = 0; i < grid.getNumberOfColumns(); i++) {
            if (templateColumns != null
                    && i - grid.getColumnOffset() < templateColumns.size()
                    && i - grid.getColumnOffset() >= 0) {
                colsValues.add(templateColumns.get(i - grid.getColumnOffset()));
            } else if (columnAutoWidth != null) {
                colsValues.add(columnAutoWidth);
            } else {
                colsValues.add(AutoValue.VALUE);
            }
        }
        GridTrackSizer gridTrackSizer = new GridTrackSizer(grid, colsValues, columnGap,
                actualBBox.getWidth(), GridOrder.COLUMN);
        List columns = gridTrackSizer.sizeTracks().getTrackSizesAndExpandPercents(colsValues);

        for (GridCell cell : grid.getUniqueGridCells(GridOrder.COLUMN)) {
            float x = 0.0f;
            for (int currentColumn = 0; currentColumn < cell.getColumnStart(); ++currentColumn) {
                x += (float) columns.get(currentColumn);
                x += columnGap;
            }
            cell.getLayoutArea().setX(x);

            float cellWidth = 0.0f;
            for (int i = cell.getColumnStart(); i < cell.getColumnEnd(); ++i) {
                cellWidth += (float) columns.get(i);
            }
            cellWidth += (cell.getGridWidth() - 1) * columnGap;
            cell.getLayoutArea().setWidth(cellWidth);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy