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: michael@0: /* michael@0: * The nsGridRowGroupLayout implements the or tag in a grid. michael@0: */ michael@0: michael@0: #include "nsGridRowGroupLayout.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIScrollableFrame.h" michael@0: #include "nsBoxLayoutState.h" michael@0: #include "nsGridLayout2.h" michael@0: #include "nsGridRow.h" michael@0: #include "nsHTMLReflowState.h" michael@0: michael@0: already_AddRefed NS_NewGridRowGroupLayout() michael@0: { michael@0: nsRefPtr layout = new nsGridRowGroupLayout(); michael@0: return layout.forget(); michael@0: } michael@0: michael@0: nsGridRowGroupLayout::nsGridRowGroupLayout():nsGridRowLayout(), mRowCount(0) michael@0: { michael@0: } michael@0: michael@0: nsGridRowGroupLayout::~nsGridRowGroupLayout() michael@0: { michael@0: } michael@0: michael@0: void michael@0: nsGridRowGroupLayout::ChildAddedOrRemoved(nsIFrame* aBox, nsBoxLayoutState& aState) michael@0: { michael@0: int32_t index = 0; michael@0: nsGrid* grid = GetGrid(aBox, &index); michael@0: bool isHorizontal = IsHorizontal(aBox); michael@0: michael@0: if (grid) michael@0: grid->RowAddedOrRemoved(aState, index, isHorizontal); michael@0: } michael@0: michael@0: void michael@0: nsGridRowGroupLayout::AddWidth(nsSize& aSize, nscoord aSize2, bool aIsHorizontal) michael@0: { michael@0: nscoord& size = GET_WIDTH(aSize, aIsHorizontal); michael@0: michael@0: if (size == NS_INTRINSICSIZE || aSize2 == NS_INTRINSICSIZE) michael@0: size = NS_INTRINSICSIZE; michael@0: else michael@0: size += aSize2; michael@0: } michael@0: michael@0: nsSize michael@0: nsGridRowGroupLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState) michael@0: { michael@0: nsSize vpref = nsGridRowLayout::GetPrefSize(aBox, aState); michael@0: michael@0: michael@0: /* It is possible that we could have some extra columns. This is when less columns in XUL were michael@0: * defined that needed. And example might be a grid with 3 defined columns but a row with 4 cells in michael@0: * it. We would need an extra column to make the grid work. But because that extra column does not michael@0: * have a box associated with it we must add its size in manually. Remember we could have extra rows michael@0: * as well. michael@0: */ michael@0: michael@0: int32_t index = 0; michael@0: nsGrid* grid = GetGrid(aBox, &index); michael@0: michael@0: if (grid) michael@0: { michael@0: // make sure we add in extra columns sizes as well michael@0: bool isHorizontal = IsHorizontal(aBox); michael@0: int32_t extraColumns = grid->GetExtraColumnCount(isHorizontal); michael@0: int32_t start = grid->GetColumnCount(isHorizontal) - grid->GetExtraColumnCount(isHorizontal); michael@0: for (int32_t i=0; i < extraColumns; i++) michael@0: { michael@0: nscoord pref = michael@0: grid->GetPrefRowHeight(aState, i+start, !isHorizontal); // GetPrefColumnWidth michael@0: michael@0: AddWidth(vpref, pref, isHorizontal); michael@0: } michael@0: } michael@0: michael@0: return vpref; michael@0: } michael@0: michael@0: nsSize michael@0: nsGridRowGroupLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState) michael@0: { michael@0: nsSize maxSize = nsGridRowLayout::GetMaxSize(aBox, aState); michael@0: michael@0: int32_t index = 0; michael@0: nsGrid* grid = GetGrid(aBox, &index); michael@0: michael@0: if (grid) michael@0: { michael@0: // make sure we add in extra columns sizes as well michael@0: bool isHorizontal = IsHorizontal(aBox); michael@0: int32_t extraColumns = grid->GetExtraColumnCount(isHorizontal); michael@0: int32_t start = grid->GetColumnCount(isHorizontal) - grid->GetExtraColumnCount(isHorizontal); michael@0: for (int32_t i=0; i < extraColumns; i++) michael@0: { michael@0: nscoord max = michael@0: grid->GetMaxRowHeight(aState, i+start, !isHorizontal); // GetMaxColumnWidth michael@0: michael@0: AddWidth(maxSize, max, isHorizontal); michael@0: } michael@0: } michael@0: michael@0: return maxSize; michael@0: } michael@0: michael@0: nsSize michael@0: nsGridRowGroupLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aState) michael@0: { michael@0: nsSize minSize = nsGridRowLayout::GetMinSize(aBox, aState); michael@0: michael@0: int32_t index = 0; michael@0: nsGrid* grid = GetGrid(aBox, &index); michael@0: michael@0: if (grid) michael@0: { michael@0: // make sure we add in extra columns sizes as well michael@0: bool isHorizontal = IsHorizontal(aBox); michael@0: int32_t extraColumns = grid->GetExtraColumnCount(isHorizontal); michael@0: int32_t start = grid->GetColumnCount(isHorizontal) - grid->GetExtraColumnCount(isHorizontal); michael@0: for (int32_t i=0; i < extraColumns; i++) michael@0: { michael@0: nscoord min = michael@0: grid->GetMinRowHeight(aState, i+start, !isHorizontal); // GetMinColumnWidth michael@0: AddWidth(minSize, min, isHorizontal); michael@0: } michael@0: } michael@0: michael@0: return minSize; michael@0: } michael@0: michael@0: /* michael@0: * Run down through our children dirtying them recursively. michael@0: */ michael@0: void michael@0: nsGridRowGroupLayout::DirtyRows(nsIFrame* aBox, nsBoxLayoutState& aState) michael@0: { michael@0: if (aBox) { michael@0: // mark us dirty michael@0: // XXXldb We probably don't want to walk up the ancestor chain michael@0: // calling MarkIntrinsicWidthsDirty for every row group. michael@0: aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange, michael@0: NS_FRAME_IS_DIRTY); michael@0: nsIFrame* child = aBox->GetChildBox(); michael@0: michael@0: while(child) { michael@0: michael@0: // walk into scrollframes michael@0: nsIFrame* deepChild = nsGrid::GetScrolledBox(child); michael@0: michael@0: // walk into other monuments michael@0: nsIGridPart* monument = nsGrid::GetPartFromBox(deepChild); michael@0: if (monument) michael@0: monument->DirtyRows(deepChild, aState); michael@0: michael@0: child = child->GetNextBox(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: void michael@0: nsGridRowGroupLayout::CountRowsColumns(nsIFrame* aBox, int32_t& aRowCount, int32_t& aComputedColumnCount) michael@0: { michael@0: if (aBox) { michael@0: int32_t startCount = aRowCount; michael@0: michael@0: nsIFrame* child = aBox->GetChildBox(); michael@0: michael@0: while(child) { michael@0: michael@0: // first see if it is a scrollframe. If so walk down into it and get the scrolled child michael@0: nsIFrame* deepChild = nsGrid::GetScrolledBox(child); michael@0: michael@0: nsIGridPart* monument = nsGrid::GetPartFromBox(deepChild); michael@0: if (monument) { michael@0: monument->CountRowsColumns(deepChild, aRowCount, aComputedColumnCount); michael@0: child = child->GetNextBox(); michael@0: deepChild = child; michael@0: continue; michael@0: } michael@0: michael@0: child = child->GetNextBox(); michael@0: michael@0: // if not a monument. Then count it. It will be a bogus row michael@0: aRowCount++; michael@0: } michael@0: michael@0: mRowCount = aRowCount - startCount; michael@0: } michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Fill out the given row structure recursively michael@0: */ michael@0: int32_t michael@0: nsGridRowGroupLayout::BuildRows(nsIFrame* aBox, nsGridRow* aRows) michael@0: { michael@0: int32_t rowCount = 0; michael@0: michael@0: if (aBox) { michael@0: nsIFrame* child = aBox->GetChildBox(); michael@0: michael@0: while(child) { michael@0: michael@0: // first see if it is a scrollframe. If so walk down into it and get the scrolled child michael@0: nsIFrame* deepChild = nsGrid::GetScrolledBox(child); michael@0: michael@0: nsIGridPart* monument = nsGrid::GetPartFromBox(deepChild); michael@0: if (monument) { michael@0: rowCount += monument->BuildRows(deepChild, &aRows[rowCount]); michael@0: child = child->GetNextBox(); michael@0: deepChild = child; michael@0: continue; michael@0: } michael@0: michael@0: aRows[rowCount].Init(child, true); michael@0: michael@0: child = child->GetNextBox(); michael@0: michael@0: // if not a monument. Then count it. It will be a bogus row michael@0: rowCount++; michael@0: } michael@0: } michael@0: michael@0: return rowCount; michael@0: } michael@0: michael@0: nsMargin michael@0: nsGridRowGroupLayout::GetTotalMargin(nsIFrame* aBox, bool aIsHorizontal) michael@0: { michael@0: // group have border and padding added to the total margin michael@0: michael@0: nsMargin margin = nsGridRowLayout::GetTotalMargin(aBox, aIsHorizontal); michael@0: michael@0: // make sure we have the scrollframe on the outside if it has one. michael@0: // that's where the border is. michael@0: aBox = nsGrid::GetScrollBox(aBox); michael@0: michael@0: // add our border/padding to it michael@0: nsMargin borderPadding(0,0,0,0); michael@0: aBox->GetBorderAndPadding(borderPadding); michael@0: margin += borderPadding; michael@0: michael@0: return margin; michael@0: } michael@0: michael@0: