mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
c1d7d36582
--HG-- rename : layout/xul/base/src/grid/Makefile.in => layout/xul/grid/Makefile.in rename : layout/xul/base/src/grid/crashtests/306911-crash.xul => layout/xul/grid/crashtests/306911-crash.xul rename : layout/xul/base/src/grid/crashtests/306911-grid-testcases.xul => layout/xul/grid/crashtests/306911-grid-testcases.xul rename : layout/xul/base/src/grid/crashtests/306911-grid-testcases2.xul => layout/xul/grid/crashtests/306911-grid-testcases2.xul rename : layout/xul/base/src/grid/crashtests/311710-1.xul => layout/xul/grid/crashtests/311710-1.xul rename : layout/xul/base/src/grid/crashtests/312784-1.xul => layout/xul/grid/crashtests/312784-1.xul rename : layout/xul/base/src/grid/crashtests/313173-1-inner.xul => layout/xul/grid/crashtests/313173-1-inner.xul rename : layout/xul/base/src/grid/crashtests/313173-1.html => layout/xul/grid/crashtests/313173-1.html rename : layout/xul/base/src/grid/crashtests/321066-1.xul => layout/xul/grid/crashtests/321066-1.xul rename : layout/xul/base/src/grid/crashtests/321073-1.xul => layout/xul/grid/crashtests/321073-1.xul rename : layout/xul/base/src/grid/crashtests/382750-1.xul => layout/xul/grid/crashtests/382750-1.xul rename : layout/xul/base/src/grid/crashtests/400790-1.xul => layout/xul/grid/crashtests/400790-1.xul rename : layout/xul/base/src/grid/crashtests/423802-crash.xul => layout/xul/grid/crashtests/423802-crash.xul rename : layout/xul/base/src/grid/crashtests/crashtests.list => layout/xul/grid/crashtests/crashtests.list rename : layout/xul/base/src/grid/examples/borderedcolumns.xul => layout/xul/grid/examples/borderedcolumns.xul rename : layout/xul/base/src/grid/examples/borderedrowscolumns.xul => layout/xul/grid/examples/borderedrowscolumns.xul rename : layout/xul/base/src/grid/examples/borderedrowscolumns2.xul => layout/xul/grid/examples/borderedrowscolumns2.xul rename : layout/xul/base/src/grid/examples/borderedrowscolumns3.xul => layout/xul/grid/examples/borderedrowscolumns3.xul rename : layout/xul/base/src/grid/examples/bordermargincolumns1.xul => layout/xul/grid/examples/bordermargincolumns1.xul rename : layout/xul/base/src/grid/examples/collapsetest.xul => layout/xul/grid/examples/collapsetest.xul rename : layout/xul/base/src/grid/examples/divcolumngrid.xul => layout/xul/grid/examples/divcolumngrid.xul rename : layout/xul/base/src/grid/examples/divrowgrid.xul => layout/xul/grid/examples/divrowgrid.xul rename : layout/xul/base/src/grid/examples/dynamicgrid.xul => layout/xul/grid/examples/dynamicgrid.xul rename : layout/xul/base/src/grid/examples/flexgroupgrid.xul => layout/xul/grid/examples/flexgroupgrid.xul rename : layout/xul/base/src/grid/examples/javascriptappend.xul => layout/xul/grid/examples/javascriptappend.xul rename : layout/xul/base/src/grid/examples/jumpygrid.xul => layout/xul/grid/examples/jumpygrid.xul rename : layout/xul/base/src/grid/examples/nestedrows.xul => layout/xul/grid/examples/nestedrows.xul rename : layout/xul/base/src/grid/examples/rowspan.xul => layout/xul/grid/examples/rowspan.xul rename : layout/xul/base/src/grid/examples/scrollingcolumns.xul => layout/xul/grid/examples/scrollingcolumns.xul rename : layout/xul/base/src/grid/examples/scrollingrows.xul => layout/xul/grid/examples/scrollingrows.xul rename : layout/xul/base/src/grid/examples/splitter.xul => layout/xul/grid/examples/splitter.xul rename : layout/xul/base/src/grid/nsGrid.cpp => layout/xul/grid/nsGrid.cpp rename : layout/xul/base/src/grid/nsGrid.h => layout/xul/grid/nsGrid.h rename : layout/xul/base/src/grid/nsGridCell.cpp => layout/xul/grid/nsGridCell.cpp rename : layout/xul/base/src/grid/nsGridCell.h => layout/xul/grid/nsGridCell.h rename : layout/xul/base/src/grid/nsGridLayout2.cpp => layout/xul/grid/nsGridLayout2.cpp rename : layout/xul/base/src/grid/nsGridLayout2.h => layout/xul/grid/nsGridLayout2.h rename : layout/xul/base/src/grid/nsGridRow.cpp => layout/xul/grid/nsGridRow.cpp rename : layout/xul/base/src/grid/nsGridRow.h => layout/xul/grid/nsGridRow.h rename : layout/xul/base/src/grid/nsGridRowGroupFrame.cpp => layout/xul/grid/nsGridRowGroupFrame.cpp rename : layout/xul/base/src/grid/nsGridRowGroupFrame.h => layout/xul/grid/nsGridRowGroupFrame.h rename : layout/xul/base/src/grid/nsGridRowGroupLayout.cpp => layout/xul/grid/nsGridRowGroupLayout.cpp rename : layout/xul/base/src/grid/nsGridRowGroupLayout.h => layout/xul/grid/nsGridRowGroupLayout.h rename : layout/xul/base/src/grid/nsGridRowLayout.cpp => layout/xul/grid/nsGridRowLayout.cpp rename : layout/xul/base/src/grid/nsGridRowLayout.h => layout/xul/grid/nsGridRowLayout.h rename : layout/xul/base/src/grid/nsGridRowLeafFrame.cpp => layout/xul/grid/nsGridRowLeafFrame.cpp rename : layout/xul/base/src/grid/nsGridRowLeafFrame.h => layout/xul/grid/nsGridRowLeafFrame.h rename : layout/xul/base/src/grid/nsGridRowLeafLayout.cpp => layout/xul/grid/nsGridRowLeafLayout.cpp rename : layout/xul/base/src/grid/nsGridRowLeafLayout.h => layout/xul/grid/nsGridRowLeafLayout.h rename : layout/xul/base/src/grid/nsIGridPart.h => layout/xul/grid/nsIGridPart.h rename : layout/xul/base/src/grid/reftests/column-sizing-1-ref.xul => layout/xul/grid/reftests/column-sizing-1-ref.xul rename : layout/xul/base/src/grid/reftests/column-sizing-1.xul => layout/xul/grid/reftests/column-sizing-1.xul rename : layout/xul/base/src/grid/reftests/not-full-basic-ref.xhtml => layout/xul/grid/reftests/not-full-basic-ref.xhtml rename : layout/xul/base/src/grid/reftests/not-full-basic.xul => layout/xul/grid/reftests/not-full-basic.xul rename : layout/xul/base/src/grid/reftests/not-full-grid-pack-align.xul => layout/xul/grid/reftests/not-full-grid-pack-align.xul rename : layout/xul/base/src/grid/reftests/not-full-row-group-align-ref.xhtml => layout/xul/grid/reftests/not-full-row-group-align-ref.xhtml rename : layout/xul/base/src/grid/reftests/not-full-row-group-align.xul => layout/xul/grid/reftests/not-full-row-group-align.xul rename : layout/xul/base/src/grid/reftests/not-full-row-group-direction-ref.xhtml => layout/xul/grid/reftests/not-full-row-group-direction-ref.xhtml rename : layout/xul/base/src/grid/reftests/not-full-row-group-direction.xul => layout/xul/grid/reftests/not-full-row-group-direction.xul rename : layout/xul/base/src/grid/reftests/not-full-row-group-pack-ref.xhtml => layout/xul/grid/reftests/not-full-row-group-pack-ref.xhtml rename : layout/xul/base/src/grid/reftests/not-full-row-group-pack.xul => layout/xul/grid/reftests/not-full-row-group-pack.xul rename : layout/xul/base/src/grid/reftests/not-full-row-leaf-align.xul => layout/xul/grid/reftests/not-full-row-leaf-align.xul rename : layout/xul/base/src/grid/reftests/not-full-row-leaf-direction.xul => layout/xul/grid/reftests/not-full-row-leaf-direction.xul rename : layout/xul/base/src/grid/reftests/not-full-row-leaf-pack-ref.xhtml => layout/xul/grid/reftests/not-full-row-leaf-pack-ref.xhtml rename : layout/xul/base/src/grid/reftests/not-full-row-leaf-pack.xul => layout/xul/grid/reftests/not-full-row-leaf-pack.xul rename : layout/xul/base/src/grid/reftests/reftest.list => layout/xul/grid/reftests/reftest.list rename : layout/xul/base/src/grid/reftests/row-or-column-sizing-1.xul => layout/xul/grid/reftests/row-or-column-sizing-1.xul rename : layout/xul/base/src/grid/reftests/row-or-column-sizing-2.xul => layout/xul/grid/reftests/row-or-column-sizing-2.xul rename : layout/xul/base/src/grid/reftests/row-or-column-sizing-3.xul => layout/xul/grid/reftests/row-or-column-sizing-3.xul rename : layout/xul/base/src/grid/reftests/row-or-column-sizing-4.xul => layout/xul/grid/reftests/row-or-column-sizing-4.xul rename : layout/xul/base/src/grid/reftests/row-sizing-1-ref.xul => layout/xul/grid/reftests/row-sizing-1-ref.xul rename : layout/xul/base/src/grid/reftests/row-sizing-1.xul => layout/xul/grid/reftests/row-sizing-1.xul rename : layout/xul/base/src/grid/reftests/scrollable-columns-ref.xhtml => layout/xul/grid/reftests/scrollable-columns-ref.xhtml rename : layout/xul/base/src/grid/reftests/scrollable-columns.xul => layout/xul/grid/reftests/scrollable-columns.xul rename : layout/xul/base/src/grid/reftests/scrollable-rows-ref.xhtml => layout/xul/grid/reftests/scrollable-rows-ref.xhtml rename : layout/xul/base/src/grid/reftests/scrollable-rows.xul => layout/xul/grid/reftests/scrollable-rows.xul rename : layout/xul/base/src/grid/reftests/sizing-2d-ref.xul => layout/xul/grid/reftests/sizing-2d-ref.xul rename : layout/xul/base/src/grid/reftests/sizing-2d.xul => layout/xul/grid/reftests/sizing-2d.xul rename : layout/xul/base/src/grid/reftests/z-order-1-ref.xul => layout/xul/grid/reftests/z-order-1-ref.xul rename : layout/xul/base/src/grid/reftests/z-order-1.xul => layout/xul/grid/reftests/z-order-1.xul rename : layout/xul/base/src/grid/reftests/z-order-2-ref.xul => layout/xul/grid/reftests/z-order-2-ref.xul rename : layout/xul/base/src/grid/reftests/z-order-2.xul => layout/xul/grid/reftests/z-order-2.xul rename : layout/xul/base/src/tree/src/Makefile.in => layout/xul/tree/Makefile.in rename : layout/xul/base/src/tree/src/crashtests/307298-1.xul => layout/xul/tree/crashtests/307298-1.xul rename : layout/xul/base/src/tree/src/crashtests/309732-1.xul => layout/xul/tree/crashtests/309732-1.xul rename : layout/xul/base/src/tree/src/crashtests/309732-2.xul => layout/xul/tree/crashtests/309732-2.xul rename : layout/xul/base/src/tree/src/crashtests/366583-1.xul => layout/xul/tree/crashtests/366583-1.xul rename : layout/xul/base/src/tree/src/crashtests/380217-1.xul => layout/xul/tree/crashtests/380217-1.xul rename : layout/xul/base/src/tree/src/crashtests/382444-1-inner.html => layout/xul/tree/crashtests/382444-1-inner.html rename : layout/xul/base/src/tree/src/crashtests/382444-1.html => layout/xul/tree/crashtests/382444-1.html rename : layout/xul/base/src/tree/src/crashtests/391178-1.xhtml => layout/xul/tree/crashtests/391178-1.xhtml rename : layout/xul/base/src/tree/src/crashtests/391178-2.xul => layout/xul/tree/crashtests/391178-2.xul rename : layout/xul/base/src/tree/src/crashtests/393665-1.xul => layout/xul/tree/crashtests/393665-1.xul rename : layout/xul/base/src/tree/src/crashtests/399227-1.xul => layout/xul/tree/crashtests/399227-1.xul rename : layout/xul/base/src/tree/src/crashtests/399227-2.xul => layout/xul/tree/crashtests/399227-2.xul rename : layout/xul/base/src/tree/src/crashtests/399692-1.xhtml => layout/xul/tree/crashtests/399692-1.xhtml rename : layout/xul/base/src/tree/src/crashtests/399715-1.xhtml => layout/xul/tree/crashtests/399715-1.xhtml rename : layout/xul/base/src/tree/src/crashtests/409807-1.xul => layout/xul/tree/crashtests/409807-1.xul rename : layout/xul/base/src/tree/src/crashtests/414170-1.xul => layout/xul/tree/crashtests/414170-1.xul rename : layout/xul/base/src/tree/src/crashtests/430394-1.xul => layout/xul/tree/crashtests/430394-1.xul rename : layout/xul/base/src/tree/src/crashtests/454186-1.xul => layout/xul/tree/crashtests/454186-1.xul rename : layout/xul/base/src/tree/src/crashtests/479931-1.xhtml => layout/xul/tree/crashtests/479931-1.xhtml rename : layout/xul/base/src/tree/src/crashtests/509602-1-overlay.xul => layout/xul/tree/crashtests/509602-1-overlay.xul rename : layout/xul/base/src/tree/src/crashtests/509602-1.xul => layout/xul/tree/crashtests/509602-1.xul rename : layout/xul/base/src/tree/src/crashtests/601427.html => layout/xul/tree/crashtests/601427.html rename : layout/xul/base/src/tree/src/crashtests/crashtests.list => layout/xul/tree/crashtests/crashtests.list rename : layout/xul/base/src/tree/public/nsITreeBoxObject.idl => layout/xul/tree/nsITreeBoxObject.idl rename : layout/xul/base/src/tree/public/nsITreeColumns.idl => layout/xul/tree/nsITreeColumns.idl rename : layout/xul/base/src/tree/public/nsITreeContentView.idl => layout/xul/tree/nsITreeContentView.idl rename : layout/xul/base/src/tree/public/nsITreeSelection.idl => layout/xul/tree/nsITreeSelection.idl rename : layout/xul/base/src/tree/public/nsITreeView.idl => layout/xul/tree/nsITreeView.idl rename : layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp => layout/xul/tree/nsTreeBodyFrame.cpp rename : layout/xul/base/src/tree/src/nsTreeBodyFrame.h => layout/xul/tree/nsTreeBodyFrame.h rename : layout/xul/base/src/tree/src/nsTreeBoxObject.cpp => layout/xul/tree/nsTreeBoxObject.cpp rename : layout/xul/base/src/tree/src/nsTreeBoxObject.h => layout/xul/tree/nsTreeBoxObject.h rename : layout/xul/base/src/tree/src/nsTreeColFrame.cpp => layout/xul/tree/nsTreeColFrame.cpp rename : layout/xul/base/src/tree/src/nsTreeColFrame.h => layout/xul/tree/nsTreeColFrame.h rename : layout/xul/base/src/tree/src/nsTreeColumns.cpp => layout/xul/tree/nsTreeColumns.cpp rename : layout/xul/base/src/tree/src/nsTreeColumns.h => layout/xul/tree/nsTreeColumns.h rename : layout/xul/base/src/tree/src/nsTreeContentView.cpp => layout/xul/tree/nsTreeContentView.cpp rename : layout/xul/base/src/tree/src/nsTreeContentView.h => layout/xul/tree/nsTreeContentView.h rename : layout/xul/base/src/tree/src/nsTreeImageListener.cpp => layout/xul/tree/nsTreeImageListener.cpp rename : layout/xul/base/src/tree/src/nsTreeImageListener.h => layout/xul/tree/nsTreeImageListener.h rename : layout/xul/base/src/tree/src/nsTreeSelection.cpp => layout/xul/tree/nsTreeSelection.cpp rename : layout/xul/base/src/tree/src/nsTreeSelection.h => layout/xul/tree/nsTreeSelection.h rename : layout/xul/base/src/tree/src/nsTreeStyleCache.cpp => layout/xul/tree/nsTreeStyleCache.cpp rename : layout/xul/base/src/tree/src/nsTreeStyleCache.h => layout/xul/tree/nsTreeStyleCache.h rename : layout/xul/base/src/tree/src/nsTreeUtils.cpp => layout/xul/tree/nsTreeUtils.cpp rename : layout/xul/base/src/tree/src/nsTreeUtils.h => layout/xul/tree/nsTreeUtils.h
1300 lines
32 KiB
C++
1300 lines
32 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
//
|
|
// Eric Vaughan
|
|
// Netscape Communications
|
|
//
|
|
// See documentation in associated header file
|
|
//
|
|
|
|
#include "nsGrid.h"
|
|
#include "nsGridRowGroupLayout.h"
|
|
#include "nsBox.h"
|
|
#include "nsIScrollableFrame.h"
|
|
#include "nsSprocketLayout.h"
|
|
#include "nsGridLayout2.h"
|
|
#include "nsGridRow.h"
|
|
#include "nsGridCell.h"
|
|
#include "nsHTMLReflowState.h"
|
|
|
|
/*
|
|
The grid control expands the idea of boxes from 1 dimension to 2 dimensions.
|
|
It works by allowing the XUL to define a collection of rows and columns and then
|
|
stacking them on top of each other. Here is and example.
|
|
|
|
Example 1:
|
|
|
|
<grid>
|
|
<columns>
|
|
<column/>
|
|
<column/>
|
|
</columns>
|
|
|
|
<rows>
|
|
<row/>
|
|
<row/>
|
|
</rows>
|
|
</grid>
|
|
|
|
example 2:
|
|
|
|
<grid>
|
|
<columns>
|
|
<column flex="1"/>
|
|
<column flex="1"/>
|
|
</columns>
|
|
|
|
<rows>
|
|
<row>
|
|
<text value="hello"/>
|
|
<text value="there"/>
|
|
</row>
|
|
</rows>
|
|
</grid>
|
|
|
|
example 3:
|
|
|
|
<grid>
|
|
|
|
<rows>
|
|
<row>
|
|
<text value="hello"/>
|
|
<text value="there"/>
|
|
</row>
|
|
</rows>
|
|
|
|
<columns>
|
|
<column>
|
|
<text value="Hey I'm in the column and I'm on top!"/>
|
|
</column>
|
|
<column/>
|
|
</columns>
|
|
|
|
</grid>
|
|
|
|
Usually the columns are first and the rows are second, so the rows will be drawn on top of the columns.
|
|
You can reverse this by defining the rows first.
|
|
Other tags are then placed in the <row> or <column> tags causing the grid to accommodate everyone.
|
|
It does this by creating 3 things: A cellmap, a row list, and a column list. The cellmap is a 2
|
|
dimensional array of nsGridCells. Each cell contains 2 boxes. One cell from the column list
|
|
and one from the row list. When a cell is asked for its size it returns that smallest size it can
|
|
be to accommodate the 2 cells. Row lists and Column lists use the same data structure: nsGridRow.
|
|
Essentially a row and column are the same except a row goes alone the x axis and a column the y.
|
|
To make things easier and save code everything is written in terms of the x dimension. A flag is
|
|
passed in called "isHorizontal" that can flip the calculations to the y axis.
|
|
|
|
Usually the number of cells in a row match the number of columns, but not always.
|
|
It is possible to define 5 columns for a grid but have 10 cells in one of the rows.
|
|
In this case 5 extra columns will be added to the column list to handle the situation.
|
|
These are called extraColumns/Rows.
|
|
*/
|
|
|
|
nsGrid::nsGrid():mBox(nullptr),
|
|
mRows(nullptr),
|
|
mColumns(nullptr),
|
|
mRowsBox(nullptr),
|
|
mColumnsBox(nullptr),
|
|
mNeedsRebuild(true),
|
|
mRowCount(0),
|
|
mColumnCount(0),
|
|
mExtraRowCount(0),
|
|
mExtraColumnCount(0),
|
|
mCellMap(nullptr),
|
|
mMarkingDirty(false)
|
|
{
|
|
MOZ_COUNT_CTOR(nsGrid);
|
|
}
|
|
|
|
nsGrid::~nsGrid()
|
|
{
|
|
FreeMap();
|
|
MOZ_COUNT_DTOR(nsGrid);
|
|
}
|
|
|
|
/*
|
|
* This is called whenever something major happens in the grid. And example
|
|
* might be when many cells or row are added. It sets a flag signaling that
|
|
* all the grids caches information should be recalculated.
|
|
*/
|
|
void
|
|
nsGrid::NeedsRebuild(nsBoxLayoutState& aState)
|
|
{
|
|
if (mNeedsRebuild)
|
|
return;
|
|
|
|
// iterate through columns and rows and dirty them
|
|
mNeedsRebuild = true;
|
|
|
|
// find the new row and column box. They could have
|
|
// been changed.
|
|
mRowsBox = nullptr;
|
|
mColumnsBox = nullptr;
|
|
FindRowsAndColumns(&mRowsBox, &mColumnsBox);
|
|
|
|
// tell all the rows and columns they are dirty
|
|
DirtyRows(mRowsBox, aState);
|
|
DirtyRows(mColumnsBox, aState);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* If we are marked for rebuild. Then build everything
|
|
*/
|
|
void
|
|
nsGrid::RebuildIfNeeded()
|
|
{
|
|
if (!mNeedsRebuild)
|
|
return;
|
|
|
|
mNeedsRebuild = false;
|
|
|
|
// find the row and columns frames
|
|
FindRowsAndColumns(&mRowsBox, &mColumnsBox);
|
|
|
|
// count the rows and columns
|
|
int32_t computedRowCount = 0;
|
|
int32_t computedColumnCount = 0;
|
|
int32_t rowCount = 0;
|
|
int32_t columnCount = 0;
|
|
|
|
CountRowsColumns(mRowsBox, rowCount, computedColumnCount);
|
|
CountRowsColumns(mColumnsBox, columnCount, computedRowCount);
|
|
|
|
// computedRowCount are the actual number of rows as determined by the
|
|
// columns children.
|
|
// computedColumnCount are the number of columns as determined by the number
|
|
// of rows children.
|
|
// We can use this information to see how many extra columns or rows we need.
|
|
// This can happen if there are are more children in a row that number of columns
|
|
// defined. Example:
|
|
//
|
|
// <columns>
|
|
// <column/>
|
|
// </columns>
|
|
//
|
|
// <rows>
|
|
// <row>
|
|
// <button/><button/>
|
|
// </row>
|
|
// </rows>
|
|
//
|
|
// computedColumnCount = 2 // for the 2 buttons in the row tag
|
|
// computedRowCount = 0 // there is nothing in the column tag
|
|
// mColumnCount = 1 // one column defined
|
|
// mRowCount = 1 // one row defined
|
|
//
|
|
// So in this case we need to make 1 extra column.
|
|
//
|
|
|
|
// Make sure to update mExtraColumnCount no matter what, since it might
|
|
// happen that we now have as many columns as are defined, and we wouldn't
|
|
// want to have a positive mExtraColumnCount hanging about in that case!
|
|
mExtraColumnCount = computedColumnCount - columnCount;
|
|
if (computedColumnCount > columnCount) {
|
|
columnCount = computedColumnCount;
|
|
}
|
|
|
|
// Same for rows.
|
|
mExtraRowCount = computedRowCount - rowCount;
|
|
if (computedRowCount > rowCount) {
|
|
rowCount = computedRowCount;
|
|
}
|
|
|
|
// build and poplulate row and columns arrays
|
|
BuildRows(mRowsBox, rowCount, &mRows, true);
|
|
BuildRows(mColumnsBox, columnCount, &mColumns, false);
|
|
|
|
// build and populate the cell map
|
|
mCellMap = BuildCellMap(rowCount, columnCount);
|
|
|
|
mRowCount = rowCount;
|
|
mColumnCount = columnCount;
|
|
|
|
// populate the cell map from column and row children
|
|
PopulateCellMap(mRows, mColumns, mRowCount, mColumnCount, true);
|
|
PopulateCellMap(mColumns, mRows, mColumnCount, mRowCount, false);
|
|
}
|
|
|
|
void
|
|
nsGrid::FreeMap()
|
|
{
|
|
if (mRows)
|
|
delete[] mRows;
|
|
|
|
if (mColumns)
|
|
delete[] mColumns;
|
|
|
|
if (mCellMap)
|
|
delete[] mCellMap;
|
|
|
|
mRows = nullptr;
|
|
mColumns = nullptr;
|
|
mCellMap = nullptr;
|
|
mColumnCount = 0;
|
|
mRowCount = 0;
|
|
mExtraColumnCount = 0;
|
|
mExtraRowCount = 0;
|
|
mRowsBox = nullptr;
|
|
mColumnsBox = nullptr;
|
|
}
|
|
|
|
/**
|
|
* finds the first <rows> and <columns> tags in the <grid> tag
|
|
*/
|
|
void
|
|
nsGrid::FindRowsAndColumns(nsIFrame** aRows, nsIFrame** aColumns)
|
|
{
|
|
*aRows = nullptr;
|
|
*aColumns = nullptr;
|
|
|
|
// find the boxes that contain our rows and columns
|
|
nsIFrame* child = nullptr;
|
|
// if we have <grid></grid> then mBox will be null (bug 125689)
|
|
if (mBox)
|
|
child = mBox->GetChildBox();
|
|
|
|
while(child)
|
|
{
|
|
nsIFrame* oldBox = child;
|
|
nsIScrollableFrame *scrollFrame = do_QueryFrame(child);
|
|
if (scrollFrame) {
|
|
nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
|
|
NS_ASSERTION(scrolledFrame,"Error no scroll frame!!");
|
|
child = do_QueryFrame(scrolledFrame);
|
|
}
|
|
|
|
nsCOMPtr<nsIGridPart> monument = GetPartFromBox(child);
|
|
if (monument)
|
|
{
|
|
nsGridRowGroupLayout* rowGroup = monument->CastToRowGroupLayout();
|
|
if (rowGroup) {
|
|
bool isHorizontal = !nsSprocketLayout::IsHorizontal(child);
|
|
if (isHorizontal)
|
|
*aRows = child;
|
|
else
|
|
*aColumns = child;
|
|
|
|
if (*aRows && *aColumns)
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (scrollFrame) {
|
|
child = oldBox;
|
|
}
|
|
|
|
child = child->GetNextBox();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Count the number of rows and columns in the given box. aRowCount well become the actual number
|
|
* rows defined in the xul. aComputedColumnCount will become the number of columns by counting the number
|
|
* of cells in each row.
|
|
*/
|
|
void
|
|
nsGrid::CountRowsColumns(nsIFrame* aRowBox, int32_t& aRowCount, int32_t& aComputedColumnCount)
|
|
{
|
|
aRowCount = 0;
|
|
aComputedColumnCount = 0;
|
|
// get the rowboxes layout manager. Then ask it to do the work for us
|
|
if (aRowBox) {
|
|
nsCOMPtr<nsIGridPart> monument = GetPartFromBox(aRowBox);
|
|
if (monument)
|
|
monument->CountRowsColumns(aRowBox, aRowCount, aComputedColumnCount);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Given the number of rows create nsGridRow objects for them and full them out.
|
|
*/
|
|
void
|
|
nsGrid::BuildRows(nsIFrame* aBox, int32_t aRowCount, nsGridRow** aRows, bool aIsHorizontal)
|
|
{
|
|
// if no rows then return null
|
|
if (aRowCount == 0) {
|
|
|
|
// make sure we free up the memory.
|
|
if (*aRows)
|
|
delete[] (*aRows);
|
|
|
|
*aRows = nullptr;
|
|
return;
|
|
}
|
|
|
|
// create the array
|
|
nsGridRow* row;
|
|
|
|
// only create new rows if we have to. Reuse old rows.
|
|
if (aIsHorizontal)
|
|
{
|
|
if (aRowCount > mRowCount) {
|
|
delete[] mRows;
|
|
row = new nsGridRow[aRowCount];
|
|
} else {
|
|
for (int32_t i=0; i < mRowCount; i++)
|
|
mRows[i].Init(nullptr, false);
|
|
|
|
row = mRows;
|
|
}
|
|
} else {
|
|
if (aRowCount > mColumnCount) {
|
|
delete[] mColumns;
|
|
row = new nsGridRow[aRowCount];
|
|
} else {
|
|
for (int32_t i=0; i < mColumnCount; i++)
|
|
mColumns[i].Init(nullptr, false);
|
|
|
|
row = mColumns;
|
|
}
|
|
}
|
|
|
|
// populate it if we can. If not it will contain only dynamic columns
|
|
if (aBox)
|
|
{
|
|
nsCOMPtr<nsIGridPart> monument = GetPartFromBox(aBox);
|
|
if (monument) {
|
|
monument->BuildRows(aBox, row);
|
|
}
|
|
}
|
|
|
|
*aRows = row;
|
|
}
|
|
|
|
|
|
/**
|
|
* Given the number of rows and columns. Build a cellmap
|
|
*/
|
|
nsGridCell*
|
|
nsGrid::BuildCellMap(int32_t aRows, int32_t aColumns)
|
|
{
|
|
int32_t size = aRows*aColumns;
|
|
int32_t oldsize = mRowCount*mColumnCount;
|
|
if (size == 0) {
|
|
delete[] mCellMap;
|
|
}
|
|
else {
|
|
if (size > oldsize) {
|
|
delete[] mCellMap;
|
|
return new nsGridCell[size];
|
|
} else {
|
|
// clear out cellmap
|
|
for (int32_t i=0; i < oldsize; i++)
|
|
{
|
|
mCellMap[i].SetBoxInRow(nullptr);
|
|
mCellMap[i].SetBoxInColumn(nullptr);
|
|
}
|
|
return mCellMap;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/**
|
|
* Run through all the cells in the rows and columns and populate then with 2 cells. One from the row and one
|
|
* from the column
|
|
*/
|
|
void
|
|
nsGrid::PopulateCellMap(nsGridRow* aRows, nsGridRow* aColumns, int32_t aRowCount, int32_t aColumnCount, bool aIsHorizontal)
|
|
{
|
|
if (!aRows)
|
|
return;
|
|
|
|
// look through the columns
|
|
int32_t j = 0;
|
|
|
|
for(int32_t i=0; i < aRowCount; i++)
|
|
{
|
|
nsIFrame* child = nullptr;
|
|
nsGridRow* row = &aRows[i];
|
|
|
|
// skip bogus rows. They have no cells
|
|
if (row->mIsBogus)
|
|
continue;
|
|
|
|
child = row->mBox;
|
|
if (child) {
|
|
child = child->GetChildBox();
|
|
|
|
j = 0;
|
|
|
|
while(child && j < aColumnCount)
|
|
{
|
|
// skip bogus column. They have no cells
|
|
nsGridRow* column = &aColumns[j];
|
|
if (column->mIsBogus)
|
|
{
|
|
j++;
|
|
continue;
|
|
}
|
|
|
|
if (aIsHorizontal)
|
|
GetCellAt(j,i)->SetBoxInRow(child);
|
|
else
|
|
GetCellAt(i,j)->SetBoxInColumn(child);
|
|
|
|
child = child->GetNextBox();
|
|
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run through the rows in the given box and mark them dirty so they
|
|
* will get recalculated and get a layout.
|
|
*/
|
|
void
|
|
nsGrid::DirtyRows(nsIFrame* aRowBox, nsBoxLayoutState& aState)
|
|
{
|
|
// make sure we prevent others from dirtying things.
|
|
mMarkingDirty = true;
|
|
|
|
// if the box is a grid part have it recursively hand it.
|
|
if (aRowBox) {
|
|
nsCOMPtr<nsIGridPart> part = GetPartFromBox(aRowBox);
|
|
if (part)
|
|
part->DirtyRows(aRowBox, aState);
|
|
}
|
|
|
|
mMarkingDirty = false;
|
|
}
|
|
|
|
nsGridRow*
|
|
nsGrid::GetColumnAt(int32_t aIndex, bool aIsHorizontal)
|
|
{
|
|
return GetRowAt(aIndex, !aIsHorizontal);
|
|
}
|
|
|
|
nsGridRow*
|
|
nsGrid::GetRowAt(int32_t aIndex, bool aIsHorizontal)
|
|
{
|
|
RebuildIfNeeded();
|
|
|
|
if (aIsHorizontal) {
|
|
NS_ASSERTION(aIndex < mRowCount && aIndex >= 0, "Index out of range");
|
|
return &mRows[aIndex];
|
|
} else {
|
|
NS_ASSERTION(aIndex < mColumnCount && aIndex >= 0, "Index out of range");
|
|
return &mColumns[aIndex];
|
|
}
|
|
}
|
|
|
|
nsGridCell*
|
|
nsGrid::GetCellAt(int32_t aX, int32_t aY)
|
|
{
|
|
RebuildIfNeeded();
|
|
|
|
NS_ASSERTION(aY < mRowCount && aY >= 0, "Index out of range");
|
|
NS_ASSERTION(aX < mColumnCount && aX >= 0, "Index out of range");
|
|
return &mCellMap[aY*mColumnCount+aX];
|
|
}
|
|
|
|
int32_t
|
|
nsGrid::GetExtraColumnCount(bool aIsHorizontal)
|
|
{
|
|
return GetExtraRowCount(!aIsHorizontal);
|
|
}
|
|
|
|
int32_t
|
|
nsGrid::GetExtraRowCount(bool aIsHorizontal)
|
|
{
|
|
RebuildIfNeeded();
|
|
|
|
if (aIsHorizontal)
|
|
return mExtraRowCount;
|
|
else
|
|
return mExtraColumnCount;
|
|
}
|
|
|
|
|
|
/**
|
|
* These methods return the preferred, min, max sizes for a given row index.
|
|
* aIsHorizontal if aIsHorizontal is true. If you pass false you will get the inverse.
|
|
* As if you called GetPrefColumnSize(aState, index, aPref)
|
|
*/
|
|
nsSize
|
|
nsGrid::GetPrefRowSize(nsBoxLayoutState& aState, int32_t aRowIndex, bool aIsHorizontal)
|
|
{
|
|
nsSize size(0,0);
|
|
if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
|
|
return size;
|
|
|
|
nscoord height = GetPrefRowHeight(aState, aRowIndex, aIsHorizontal);
|
|
SetLargestSize(size, height, aIsHorizontal);
|
|
|
|
return size;
|
|
}
|
|
|
|
nsSize
|
|
nsGrid::GetMinRowSize(nsBoxLayoutState& aState, int32_t aRowIndex, bool aIsHorizontal)
|
|
{
|
|
nsSize size(0,0);
|
|
if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
|
|
return size;
|
|
|
|
nscoord height = GetMinRowHeight(aState, aRowIndex, aIsHorizontal);
|
|
SetLargestSize(size, height, aIsHorizontal);
|
|
|
|
return size;
|
|
}
|
|
|
|
nsSize
|
|
nsGrid::GetMaxRowSize(nsBoxLayoutState& aState, int32_t aRowIndex, bool aIsHorizontal)
|
|
{
|
|
nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
|
|
if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
|
|
return size;
|
|
|
|
nscoord height = GetMaxRowHeight(aState, aRowIndex, aIsHorizontal);
|
|
SetSmallestSize(size, height, aIsHorizontal);
|
|
|
|
return size;
|
|
}
|
|
|
|
// static
|
|
nsIGridPart*
|
|
nsGrid::GetPartFromBox(nsIFrame* aBox)
|
|
{
|
|
if (!aBox)
|
|
return nullptr;
|
|
|
|
nsBoxLayout* layout = aBox->GetLayoutManager();
|
|
return layout ? layout->AsGridPart() : nullptr;
|
|
}
|
|
|
|
nsMargin
|
|
nsGrid::GetBoxTotalMargin(nsIFrame* aBox, bool aIsHorizontal)
|
|
{
|
|
nsMargin margin(0,0,0,0);
|
|
// walk the boxes parent chain getting the border/padding/margin of our parent rows
|
|
|
|
// first get the layour manager
|
|
nsIGridPart* part = GetPartFromBox(aBox);
|
|
if (part)
|
|
margin = part->GetTotalMargin(aBox, aIsHorizontal);
|
|
|
|
return margin;
|
|
}
|
|
|
|
/**
|
|
* The first and last rows can be affected by <rows> tags with borders or margin
|
|
* gets first and last rows and their indexes.
|
|
* If it fails because there are no rows then:
|
|
* FirstRow is nullptr
|
|
* LastRow is nullptr
|
|
* aFirstIndex = -1
|
|
* aLastIndex = -1
|
|
*/
|
|
void
|
|
nsGrid::GetFirstAndLastRow(nsBoxLayoutState& aState,
|
|
int32_t& aFirstIndex,
|
|
int32_t& aLastIndex,
|
|
nsGridRow*& aFirstRow,
|
|
nsGridRow*& aLastRow,
|
|
bool aIsHorizontal)
|
|
{
|
|
aFirstRow = nullptr;
|
|
aLastRow = nullptr;
|
|
aFirstIndex = -1;
|
|
aLastIndex = -1;
|
|
|
|
int32_t count = GetRowCount(aIsHorizontal);
|
|
|
|
if (count == 0)
|
|
return;
|
|
|
|
|
|
// We could have collapsed columns either before or after our index.
|
|
// they should not count. So if we are the 5th row and the first 4 are
|
|
// collaped we become the first row. Or if we are the 9th row and
|
|
// 10 up to the last row are collapsed we then become the last.
|
|
|
|
// see if we are first
|
|
int32_t i;
|
|
for (i=0; i < count; i++)
|
|
{
|
|
nsGridRow* row = GetRowAt(i,aIsHorizontal);
|
|
if (!row->IsCollapsed()) {
|
|
aFirstIndex = i;
|
|
aFirstRow = row;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// see if we are last
|
|
for (i=count-1; i >= 0; i--)
|
|
{
|
|
nsGridRow* row = GetRowAt(i,aIsHorizontal);
|
|
if (!row->IsCollapsed()) {
|
|
aLastIndex = i;
|
|
aLastRow = row;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A row can have a top and bottom offset. Usually this is just the top and bottom border/padding.
|
|
* However if the row is the first or last it could be affected by the fact a column or columns could
|
|
* have a top or bottom margin.
|
|
*/
|
|
void
|
|
nsGrid::GetRowOffsets(nsBoxLayoutState& aState, int32_t aIndex, nscoord& aTop, nscoord& aBottom, bool aIsHorizontal)
|
|
{
|
|
|
|
RebuildIfNeeded();
|
|
|
|
nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
|
|
|
|
if (row->IsOffsetSet())
|
|
{
|
|
aTop = row->mTop;
|
|
aBottom = row->mBottom;
|
|
return;
|
|
}
|
|
|
|
// first get the rows top and bottom border and padding
|
|
nsIFrame* box = row->GetBox();
|
|
|
|
// add up all the padding
|
|
nsMargin margin(0,0,0,0);
|
|
nsMargin border(0,0,0,0);
|
|
nsMargin padding(0,0,0,0);
|
|
nsMargin totalBorderPadding(0,0,0,0);
|
|
nsMargin totalMargin(0,0,0,0);
|
|
|
|
// if there is a box and it's not bogus take its
|
|
// borders padding into account
|
|
if (box && !row->mIsBogus)
|
|
{
|
|
if (!box->IsCollapsed())
|
|
{
|
|
// get real border and padding. GetBorderAndPadding
|
|
// is redefined on nsGridRowLeafFrame. If we called it here
|
|
// we would be in finite recurson.
|
|
box->GetBorder(border);
|
|
box->GetPadding(padding);
|
|
|
|
totalBorderPadding += border;
|
|
totalBorderPadding += padding;
|
|
}
|
|
|
|
// if we are the first or last row
|
|
// take into account <rows> tags around us
|
|
// that could have borders or margins.
|
|
// fortunately they only affect the first
|
|
// and last row inside the <rows> tag
|
|
|
|
totalMargin = GetBoxTotalMargin(box, aIsHorizontal);
|
|
}
|
|
|
|
if (aIsHorizontal) {
|
|
row->mTop = totalBorderPadding.top;
|
|
row->mBottom = totalBorderPadding.bottom;
|
|
row->mTopMargin = totalMargin.top;
|
|
row->mBottomMargin = totalMargin.bottom;
|
|
} else {
|
|
row->mTop = totalBorderPadding.left;
|
|
row->mBottom = totalBorderPadding.right;
|
|
row->mTopMargin = totalMargin.left;
|
|
row->mBottomMargin = totalMargin.right;
|
|
}
|
|
|
|
// if we are the first or last row take into account the top and bottom borders
|
|
// of each columns.
|
|
|
|
// If we are the first row then get the largest top border/padding in
|
|
// our columns. If that's larger than the rows top border/padding use it.
|
|
|
|
// If we are the last row then get the largest bottom border/padding in
|
|
// our columns. If that's larger than the rows bottom border/padding use it.
|
|
int32_t firstIndex = 0;
|
|
int32_t lastIndex = 0;
|
|
nsGridRow* firstRow = nullptr;
|
|
nsGridRow* lastRow = nullptr;
|
|
GetFirstAndLastRow(aState, firstIndex, lastIndex, firstRow, lastRow, aIsHorizontal);
|
|
|
|
if (aIndex == firstIndex || aIndex == lastIndex) {
|
|
nscoord maxTop = 0;
|
|
nscoord maxBottom = 0;
|
|
|
|
// run through the columns. Look at each column
|
|
// pick the largest top border or bottom border
|
|
int32_t count = GetColumnCount(aIsHorizontal);
|
|
|
|
for (int32_t i=0; i < count; i++)
|
|
{
|
|
nsMargin totalChildBorderPadding(0,0,0,0);
|
|
|
|
nsGridRow* column = GetColumnAt(i,aIsHorizontal);
|
|
nsIFrame* box = column->GetBox();
|
|
|
|
if (box)
|
|
{
|
|
// ignore collapsed children
|
|
if (!box->IsCollapsed())
|
|
{
|
|
// include the margin of the columns. To the row
|
|
// at this point border/padding and margins all added
|
|
// up to more needed space.
|
|
margin = GetBoxTotalMargin(box, !aIsHorizontal);
|
|
// get real border and padding. GetBorderAndPadding
|
|
// is redefined on nsGridRowLeafFrame. If we called it here
|
|
// we would be in finite recurson.
|
|
box->GetBorder(border);
|
|
box->GetPadding(padding);
|
|
totalChildBorderPadding += border;
|
|
totalChildBorderPadding += padding;
|
|
totalChildBorderPadding += margin;
|
|
}
|
|
|
|
nscoord top;
|
|
nscoord bottom;
|
|
|
|
// pick the largest top margin
|
|
if (aIndex == firstIndex) {
|
|
if (aIsHorizontal) {
|
|
top = totalChildBorderPadding.top;
|
|
} else {
|
|
top = totalChildBorderPadding.left;
|
|
}
|
|
if (top > maxTop)
|
|
maxTop = top;
|
|
}
|
|
|
|
// pick the largest bottom margin
|
|
if (aIndex == lastIndex) {
|
|
if (aIsHorizontal) {
|
|
bottom = totalChildBorderPadding.bottom;
|
|
} else {
|
|
bottom = totalChildBorderPadding.right;
|
|
}
|
|
if (bottom > maxBottom)
|
|
maxBottom = bottom;
|
|
}
|
|
|
|
}
|
|
|
|
// If the biggest top border/padding the columns is larger than this rows top border/padding
|
|
// the use it.
|
|
if (aIndex == firstIndex) {
|
|
if (maxTop > (row->mTop + row->mTopMargin))
|
|
row->mTop = maxTop - row->mTopMargin;
|
|
}
|
|
|
|
// If the biggest bottom border/padding the columns is larger than this rows bottom border/padding
|
|
// the use it.
|
|
if (aIndex == lastIndex) {
|
|
if (maxBottom > (row->mBottom + row->mBottomMargin))
|
|
row->mBottom = maxBottom - row->mBottomMargin;
|
|
}
|
|
}
|
|
}
|
|
|
|
aTop = row->mTop;
|
|
aBottom = row->mBottom;
|
|
}
|
|
|
|
/**
|
|
* These methods return the preferred, min, max coord for a given row index if
|
|
* aIsHorizontal is true. If you pass false you will get the inverse.
|
|
* As if you called GetPrefColumnHeight(aState, index, aPref).
|
|
*/
|
|
nscoord
|
|
nsGrid::GetPrefRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
|
|
{
|
|
RebuildIfNeeded();
|
|
|
|
nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
|
|
|
|
if (row->IsCollapsed())
|
|
return 0;
|
|
|
|
if (row->IsPrefSet())
|
|
return row->mPref;
|
|
|
|
nsIFrame* box = row->mBox;
|
|
|
|
// set in CSS?
|
|
if (box)
|
|
{
|
|
bool widthSet, heightSet;
|
|
nsSize cssSize(-1, -1);
|
|
nsIFrame::AddCSSPrefSize(box, cssSize, widthSet, heightSet);
|
|
|
|
row->mPref = GET_HEIGHT(cssSize, aIsHorizontal);
|
|
|
|
// yep do nothing.
|
|
if (row->mPref != -1)
|
|
return row->mPref;
|
|
}
|
|
|
|
// get the offsets so they are cached.
|
|
nscoord top;
|
|
nscoord bottom;
|
|
GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
|
|
|
|
// is the row bogus? If so then just ask it for its size
|
|
// it should not be affected by cells in the grid.
|
|
if (row->mIsBogus)
|
|
{
|
|
nsSize size(0,0);
|
|
if (box)
|
|
{
|
|
size = box->GetPrefSize(aState);
|
|
nsBox::AddMargin(box, size);
|
|
nsGridLayout2::AddOffset(aState, box, size);
|
|
}
|
|
|
|
row->mPref = GET_HEIGHT(size, aIsHorizontal);
|
|
return row->mPref;
|
|
}
|
|
|
|
nsSize size(0,0);
|
|
|
|
nsGridCell* child;
|
|
|
|
int32_t count = GetColumnCount(aIsHorizontal);
|
|
|
|
for (int32_t i=0; i < count; i++)
|
|
{
|
|
if (aIsHorizontal)
|
|
child = GetCellAt(i,aIndex);
|
|
else
|
|
child = GetCellAt(aIndex,i);
|
|
|
|
// ignore collapsed children
|
|
if (!child->IsCollapsed())
|
|
{
|
|
nsSize childSize = child->GetPrefSize(aState);
|
|
|
|
nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
|
|
}
|
|
}
|
|
|
|
row->mPref = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
|
|
|
|
return row->mPref;
|
|
}
|
|
|
|
nscoord
|
|
nsGrid::GetMinRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
|
|
{
|
|
RebuildIfNeeded();
|
|
|
|
nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
|
|
|
|
if (row->IsCollapsed())
|
|
return 0;
|
|
|
|
if (row->IsMinSet())
|
|
return row->mMin;
|
|
|
|
nsIFrame* box = row->mBox;
|
|
|
|
// set in CSS?
|
|
if (box) {
|
|
bool widthSet, heightSet;
|
|
nsSize cssSize(-1, -1);
|
|
nsIFrame::AddCSSMinSize(aState, box, cssSize, widthSet, heightSet);
|
|
|
|
row->mMin = GET_HEIGHT(cssSize, aIsHorizontal);
|
|
|
|
// yep do nothing.
|
|
if (row->mMin != -1)
|
|
return row->mMin;
|
|
}
|
|
|
|
// get the offsets so they are cached.
|
|
nscoord top;
|
|
nscoord bottom;
|
|
GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
|
|
|
|
// is the row bogus? If so then just ask it for its size
|
|
// it should not be affected by cells in the grid.
|
|
if (row->mIsBogus)
|
|
{
|
|
nsSize size(0,0);
|
|
if (box) {
|
|
size = box->GetPrefSize(aState);
|
|
nsBox::AddMargin(box, size);
|
|
nsGridLayout2::AddOffset(aState, box, size);
|
|
}
|
|
|
|
row->mMin = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
|
|
return row->mMin;
|
|
}
|
|
|
|
nsSize size(0,0);
|
|
|
|
nsGridCell* child;
|
|
|
|
int32_t count = GetColumnCount(aIsHorizontal);
|
|
|
|
for (int32_t i=0; i < count; i++)
|
|
{
|
|
if (aIsHorizontal)
|
|
child = GetCellAt(i,aIndex);
|
|
else
|
|
child = GetCellAt(aIndex,i);
|
|
|
|
// ignore collapsed children
|
|
if (!child->IsCollapsed())
|
|
{
|
|
nsSize childSize = child->GetMinSize(aState);
|
|
|
|
nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
|
|
}
|
|
}
|
|
|
|
row->mMin = GET_HEIGHT(size, aIsHorizontal);
|
|
|
|
return row->mMin;
|
|
}
|
|
|
|
nscoord
|
|
nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
|
|
{
|
|
RebuildIfNeeded();
|
|
|
|
nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
|
|
|
|
if (row->IsCollapsed())
|
|
return 0;
|
|
|
|
if (row->IsMaxSet())
|
|
return row->mMax;
|
|
|
|
nsIFrame* box = row->mBox;
|
|
|
|
// set in CSS?
|
|
if (box) {
|
|
bool widthSet, heightSet;
|
|
nsSize cssSize(-1, -1);
|
|
nsIFrame::AddCSSMaxSize(box, cssSize, widthSet, heightSet);
|
|
|
|
row->mMax = GET_HEIGHT(cssSize, aIsHorizontal);
|
|
|
|
// yep do nothing.
|
|
if (row->mMax != -1)
|
|
return row->mMax;
|
|
}
|
|
|
|
// get the offsets so they are cached.
|
|
nscoord top;
|
|
nscoord bottom;
|
|
GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
|
|
|
|
// is the row bogus? If so then just ask it for its size
|
|
// it should not be affected by cells in the grid.
|
|
if (row->mIsBogus)
|
|
{
|
|
nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
|
|
if (box) {
|
|
size = box->GetPrefSize(aState);
|
|
nsBox::AddMargin(box, size);
|
|
nsGridLayout2::AddOffset(aState, box, size);
|
|
}
|
|
|
|
row->mMax = GET_HEIGHT(size, aIsHorizontal);
|
|
return row->mMax;
|
|
}
|
|
|
|
nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
|
|
|
|
nsGridCell* child;
|
|
|
|
int32_t count = GetColumnCount(aIsHorizontal);
|
|
|
|
for (int32_t i=0; i < count; i++)
|
|
{
|
|
if (aIsHorizontal)
|
|
child = GetCellAt(i,aIndex);
|
|
else
|
|
child = GetCellAt(aIndex,i);
|
|
|
|
// ignore collapsed children
|
|
if (!child->IsCollapsed())
|
|
{
|
|
nsSize min = child->GetMinSize(aState);
|
|
nsSize childSize = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState));
|
|
nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
|
|
}
|
|
}
|
|
|
|
row->mMax = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
|
|
|
|
return row->mMax;
|
|
}
|
|
|
|
bool
|
|
nsGrid::IsGrid(nsIFrame* aBox)
|
|
{
|
|
nsIGridPart* part = GetPartFromBox(aBox);
|
|
if (!part)
|
|
return false;
|
|
|
|
nsGridLayout2* grid = part->CastToGridLayout();
|
|
|
|
if (grid)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* This get the flexibilty of the row at aIndex. It's not trivial. There are a few
|
|
* things we need to look at. Specifically we need to see if any <rows> or <columns>
|
|
* tags are around us. Their flexibilty will affect ours.
|
|
*/
|
|
nscoord
|
|
nsGrid::GetRowFlex(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
|
|
{
|
|
RebuildIfNeeded();
|
|
|
|
nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
|
|
|
|
if (row->IsFlexSet())
|
|
return row->mFlex;
|
|
|
|
nsIFrame* box = row->mBox;
|
|
row->mFlex = 0;
|
|
|
|
if (box) {
|
|
|
|
// We need our flex but a inflexible row could be around us. If so
|
|
// neither are we. However if its the row tag just inside the grid it won't
|
|
// affect us. We need to do this for this case:
|
|
// <grid>
|
|
// <rows>
|
|
// <rows> // this is not flexible. So our children should not be flexible
|
|
// <row flex="1"/>
|
|
// <row flex="1"/>
|
|
// </rows>
|
|
// <row/>
|
|
// </rows>
|
|
// </grid>
|
|
//
|
|
// or..
|
|
//
|
|
// <grid>
|
|
// <rows>
|
|
// <rows> // this is not flexible. So our children should not be flexible
|
|
// <rows flex="1">
|
|
// <row flex="1"/>
|
|
// <row flex="1"/>
|
|
// </rows>
|
|
// <row/>
|
|
// </rows>
|
|
// </row>
|
|
// </grid>
|
|
|
|
|
|
// So here is how it looks
|
|
//
|
|
// <grid>
|
|
// <rows> // parentsParent
|
|
// <rows> // parent
|
|
// <row flex="1"/>
|
|
// <row flex="1"/>
|
|
// </rows>
|
|
// <row/>
|
|
// </rows>
|
|
// </grid>
|
|
|
|
// so the answer is simple: 1) Walk our parent chain. 2) If we find
|
|
// someone who is not flexible and they aren't the rows immediately in
|
|
// the grid. 3) Then we are not flexible
|
|
|
|
box = GetScrollBox(box);
|
|
nsIFrame* parent = box->GetParentBox();
|
|
nsIFrame* parentsParent=nullptr;
|
|
|
|
while(parent)
|
|
{
|
|
parent = GetScrollBox(parent);
|
|
parentsParent = parent->GetParentBox();
|
|
|
|
// if our parents parent is not a grid
|
|
// the get its flex. If its 0 then we are
|
|
// not flexible.
|
|
if (parentsParent) {
|
|
if (!IsGrid(parentsParent)) {
|
|
nscoord flex = parent->GetFlex(aState);
|
|
nsIFrame::AddCSSFlex(aState, parent, flex);
|
|
if (flex == 0) {
|
|
row->mFlex = 0;
|
|
return row->mFlex;
|
|
}
|
|
} else
|
|
break;
|
|
}
|
|
|
|
parent = parentsParent;
|
|
}
|
|
|
|
// get the row flex.
|
|
row->mFlex = box->GetFlex(aState);
|
|
nsIFrame::AddCSSFlex(aState, box, row->mFlex);
|
|
}
|
|
|
|
return row->mFlex;
|
|
}
|
|
|
|
void
|
|
nsGrid::SetLargestSize(nsSize& aSize, nscoord aHeight, bool aIsHorizontal)
|
|
{
|
|
if (aIsHorizontal) {
|
|
if (aSize.height < aHeight)
|
|
aSize.height = aHeight;
|
|
} else {
|
|
if (aSize.width < aHeight)
|
|
aSize.width = aHeight;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGrid::SetSmallestSize(nsSize& aSize, nscoord aHeight, bool aIsHorizontal)
|
|
{
|
|
if (aIsHorizontal) {
|
|
if (aSize.height > aHeight)
|
|
aSize.height = aHeight;
|
|
} else {
|
|
if (aSize.width < aHeight)
|
|
aSize.width = aHeight;
|
|
}
|
|
}
|
|
|
|
int32_t
|
|
nsGrid::GetRowCount(int32_t aIsHorizontal)
|
|
{
|
|
RebuildIfNeeded();
|
|
|
|
if (aIsHorizontal)
|
|
return mRowCount;
|
|
else
|
|
return mColumnCount;
|
|
}
|
|
|
|
int32_t
|
|
nsGrid::GetColumnCount(int32_t aIsHorizontal)
|
|
{
|
|
return GetRowCount(!aIsHorizontal);
|
|
}
|
|
|
|
/*
|
|
* A cell in the given row or columns at the given index has had a child added or removed
|
|
*/
|
|
void
|
|
nsGrid::CellAddedOrRemoved(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
|
|
{
|
|
// TBD see if the cell will fit in our current row. If it will
|
|
// just add it in.
|
|
// but for now rebuild everything.
|
|
if (mMarkingDirty)
|
|
return;
|
|
|
|
NeedsRebuild(aState);
|
|
}
|
|
|
|
/**
|
|
* A row or columns at the given index had been added or removed
|
|
*/
|
|
void
|
|
nsGrid::RowAddedOrRemoved(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
|
|
{
|
|
// TBD see if we have extra room in the table and just add the new row in
|
|
// for now rebuild the world
|
|
if (mMarkingDirty)
|
|
return;
|
|
|
|
NeedsRebuild(aState);
|
|
}
|
|
|
|
/*
|
|
* Scrollframes are tranparent. If this is given a scrollframe is will return the
|
|
* frame inside. If there is no scrollframe it does nothing.
|
|
*/
|
|
nsIFrame*
|
|
nsGrid::GetScrolledBox(nsIFrame* aChild)
|
|
{
|
|
// first see if it is a scrollframe. If so walk down into it and get the scrolled child
|
|
nsIScrollableFrame *scrollFrame = do_QueryFrame(aChild);
|
|
if (scrollFrame) {
|
|
nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
|
|
NS_ASSERTION(scrolledFrame,"Error no scroll frame!!");
|
|
return scrolledFrame;
|
|
}
|
|
|
|
return aChild;
|
|
}
|
|
|
|
/*
|
|
* Scrollframes are tranparent. If this is given a child in a scrollframe is will return the
|
|
* scrollframe ourside it. If there is no scrollframe it does nothing.
|
|
*/
|
|
nsIFrame*
|
|
nsGrid::GetScrollBox(nsIFrame* aChild)
|
|
{
|
|
if (!aChild)
|
|
return nullptr;
|
|
|
|
// get parent
|
|
nsIFrame* parent = aChild->GetParentBox();
|
|
|
|
// walk up until we find a scrollframe or a part
|
|
// if it's a scrollframe return it.
|
|
// if it's a parent then the child passed does not
|
|
// have a scroll frame immediately wrapped around it.
|
|
while (parent) {
|
|
nsIScrollableFrame *scrollFrame = do_QueryFrame(parent);
|
|
// scrollframe? Yep return it.
|
|
if (scrollFrame)
|
|
return parent;
|
|
|
|
nsCOMPtr<nsIGridPart> parentGridRow = GetPartFromBox(parent);
|
|
// if a part then just return the child
|
|
if (parentGridRow)
|
|
break;
|
|
|
|
parent = parent->GetParentBox();
|
|
}
|
|
|
|
return aChild;
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_grid
|
|
void
|
|
nsGrid::PrintCellMap()
|
|
{
|
|
|
|
printf("-----Columns------\n");
|
|
for (int x=0; x < mColumnCount; x++)
|
|
{
|
|
|
|
nsGridRow* column = GetColumnAt(x);
|
|
printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax);
|
|
}
|
|
|
|
printf("\n-----Rows------\n");
|
|
for (x=0; x < mRowCount; x++)
|
|
{
|
|
nsGridRow* column = GetRowAt(x);
|
|
printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
#endif
|