michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // michael@0: // Eric Vaughan michael@0: // Netscape Communications michael@0: // michael@0: // See documentation in associated header file michael@0: // michael@0: michael@0: #include "nsGrid.h" michael@0: #include "nsGridRowGroupLayout.h" michael@0: #include "nsBox.h" michael@0: #include "nsIScrollableFrame.h" michael@0: #include "nsSprocketLayout.h" michael@0: #include "nsGridLayout2.h" michael@0: #include "nsGridRow.h" michael@0: #include "nsGridCell.h" michael@0: #include "nsHTMLReflowState.h" michael@0: michael@0: /* michael@0: The grid control expands the idea of boxes from 1 dimension to 2 dimensions. michael@0: It works by allowing the XUL to define a collection of rows and columns and then michael@0: stacking them on top of each other. Here is and example. michael@0: michael@0: Example 1: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: example 2: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: example 3: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: Usually the columns are first and the rows are second, so the rows will be drawn on top of the columns. michael@0: You can reverse this by defining the rows first. michael@0: Other tags are then placed in the or tags causing the grid to accommodate everyone. michael@0: It does this by creating 3 things: A cellmap, a row list, and a column list. The cellmap is a 2 michael@0: dimensional array of nsGridCells. Each cell contains 2 boxes. One cell from the column list michael@0: and one from the row list. When a cell is asked for its size it returns that smallest size it can michael@0: be to accommodate the 2 cells. Row lists and Column lists use the same data structure: nsGridRow. michael@0: Essentially a row and column are the same except a row goes alone the x axis and a column the y. michael@0: To make things easier and save code everything is written in terms of the x dimension. A flag is michael@0: passed in called "isHorizontal" that can flip the calculations to the y axis. michael@0: michael@0: Usually the number of cells in a row match the number of columns, but not always. michael@0: It is possible to define 5 columns for a grid but have 10 cells in one of the rows. michael@0: In this case 5 extra columns will be added to the column list to handle the situation. michael@0: These are called extraColumns/Rows. michael@0: */ michael@0: michael@0: nsGrid::nsGrid():mBox(nullptr), michael@0: mRows(nullptr), michael@0: mColumns(nullptr), michael@0: mRowsBox(nullptr), michael@0: mColumnsBox(nullptr), michael@0: mNeedsRebuild(true), michael@0: mRowCount(0), michael@0: mColumnCount(0), michael@0: mExtraRowCount(0), michael@0: mExtraColumnCount(0), michael@0: mCellMap(nullptr), michael@0: mMarkingDirty(false) michael@0: { michael@0: MOZ_COUNT_CTOR(nsGrid); michael@0: } michael@0: michael@0: nsGrid::~nsGrid() michael@0: { michael@0: FreeMap(); michael@0: MOZ_COUNT_DTOR(nsGrid); michael@0: } michael@0: michael@0: /* michael@0: * This is called whenever something major happens in the grid. And example michael@0: * might be when many cells or row are added. It sets a flag signaling that michael@0: * all the grids caches information should be recalculated. michael@0: */ michael@0: void michael@0: nsGrid::NeedsRebuild(nsBoxLayoutState& aState) michael@0: { michael@0: if (mNeedsRebuild) michael@0: return; michael@0: michael@0: // iterate through columns and rows and dirty them michael@0: mNeedsRebuild = true; michael@0: michael@0: // find the new row and column box. They could have michael@0: // been changed. michael@0: mRowsBox = nullptr; michael@0: mColumnsBox = nullptr; michael@0: FindRowsAndColumns(&mRowsBox, &mColumnsBox); michael@0: michael@0: // tell all the rows and columns they are dirty michael@0: DirtyRows(mRowsBox, aState); michael@0: DirtyRows(mColumnsBox, aState); michael@0: } michael@0: michael@0: michael@0: michael@0: /** michael@0: * If we are marked for rebuild. Then build everything michael@0: */ michael@0: void michael@0: nsGrid::RebuildIfNeeded() michael@0: { michael@0: if (!mNeedsRebuild) michael@0: return; michael@0: michael@0: mNeedsRebuild = false; michael@0: michael@0: // find the row and columns frames michael@0: FindRowsAndColumns(&mRowsBox, &mColumnsBox); michael@0: michael@0: // count the rows and columns michael@0: int32_t computedRowCount = 0; michael@0: int32_t computedColumnCount = 0; michael@0: int32_t rowCount = 0; michael@0: int32_t columnCount = 0; michael@0: michael@0: CountRowsColumns(mRowsBox, rowCount, computedColumnCount); michael@0: CountRowsColumns(mColumnsBox, columnCount, computedRowCount); michael@0: michael@0: // computedRowCount are the actual number of rows as determined by the michael@0: // columns children. michael@0: // computedColumnCount are the number of columns as determined by the number michael@0: // of rows children. michael@0: // We can use this information to see how many extra columns or rows we need. michael@0: // This can happen if there are are more children in a row that number of columns michael@0: // defined. Example: michael@0: // michael@0: // michael@0: // michael@0: // michael@0: // michael@0: // michael@0: // michael@0: //