layout/xul/grid/nsGrid.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/xul/grid/nsGrid.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1299 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +//
    1.10 +// Eric Vaughan
    1.11 +// Netscape Communications
    1.12 +//
    1.13 +// See documentation in associated header file
    1.14 +//
    1.15 +
    1.16 +#include "nsGrid.h"
    1.17 +#include "nsGridRowGroupLayout.h"
    1.18 +#include "nsBox.h"
    1.19 +#include "nsIScrollableFrame.h"
    1.20 +#include "nsSprocketLayout.h"
    1.21 +#include "nsGridLayout2.h"
    1.22 +#include "nsGridRow.h"
    1.23 +#include "nsGridCell.h"
    1.24 +#include "nsHTMLReflowState.h"
    1.25 +
    1.26 +/*
    1.27 +The grid control expands the idea of boxes from 1 dimension to 2 dimensions. 
    1.28 +It works by allowing the XUL to define a collection of rows and columns and then 
    1.29 +stacking them on top of each other. Here is and example.
    1.30 +
    1.31 +Example 1:
    1.32 +
    1.33 +<grid>
    1.34 +   <columns>
    1.35 +      <column/>
    1.36 +      <column/>
    1.37 +   </columns>
    1.38 +
    1.39 +   <rows>
    1.40 +      <row/>
    1.41 +      <row/>
    1.42 +   </rows>
    1.43 +</grid>
    1.44 +
    1.45 +example 2:
    1.46 +
    1.47 +<grid>
    1.48 +   <columns>
    1.49 +      <column flex="1"/>
    1.50 +      <column flex="1"/>
    1.51 +   </columns>
    1.52 +
    1.53 +   <rows>
    1.54 +      <row>
    1.55 +         <text value="hello"/>
    1.56 +         <text value="there"/>
    1.57 +      </row>
    1.58 +   </rows>
    1.59 +</grid>
    1.60 +
    1.61 +example 3:
    1.62 +
    1.63 +<grid>
    1.64 +
    1.65 +<rows>
    1.66 +      <row>
    1.67 +         <text value="hello"/>
    1.68 +         <text value="there"/>
    1.69 +      </row>
    1.70 +   </rows>
    1.71 +
    1.72 +   <columns>
    1.73 +      <column>
    1.74 +         <text value="Hey I'm in the column and I'm on top!"/>
    1.75 +      </column>
    1.76 +      <column/>
    1.77 +   </columns>
    1.78 +
    1.79 +</grid>
    1.80 +
    1.81 +Usually the columns are first and the rows are second, so the rows will be drawn on top of the columns. 
    1.82 +You can reverse this by defining the rows first.
    1.83 +Other tags are then placed in the <row> or <column> tags causing the grid to accommodate everyone.  
    1.84 +It does this by creating 3 things: A cellmap, a row list, and a column list. The cellmap is a 2 
    1.85 +dimensional array of nsGridCells. Each cell contains 2 boxes.  One cell from the column list 
    1.86 +and one from the row list. When a cell is asked for its size it returns that smallest size it can 
    1.87 +be to accommodate the 2 cells. Row lists and Column lists use the same data structure: nsGridRow. 
    1.88 +Essentially a row and column are the same except a row goes alone the x axis and a column the y. 
    1.89 +To make things easier and save code everything is written in terms of the x dimension. A flag is 
    1.90 +passed in called "isHorizontal" that can flip the calculations to the y axis.
    1.91 +
    1.92 +Usually the number of cells in a row match the number of columns, but not always. 
    1.93 +It is possible to define 5 columns for a grid but have 10 cells in one of the rows. 
    1.94 +In this case 5 extra columns will be added to the column list to handle the situation. 
    1.95 +These are called extraColumns/Rows.
    1.96 +*/
    1.97 +
    1.98 +nsGrid::nsGrid():mBox(nullptr),
    1.99 +                 mRows(nullptr),
   1.100 +                 mColumns(nullptr), 
   1.101 +                 mRowsBox(nullptr),
   1.102 +                 mColumnsBox(nullptr),
   1.103 +                 mNeedsRebuild(true),
   1.104 +                 mRowCount(0),
   1.105 +                 mColumnCount(0),
   1.106 +                 mExtraRowCount(0),
   1.107 +                 mExtraColumnCount(0),
   1.108 +                 mCellMap(nullptr),
   1.109 +                 mMarkingDirty(false)
   1.110 +{
   1.111 +    MOZ_COUNT_CTOR(nsGrid);
   1.112 +}
   1.113 +
   1.114 +nsGrid::~nsGrid()
   1.115 +{
   1.116 +    FreeMap();
   1.117 +    MOZ_COUNT_DTOR(nsGrid);
   1.118 +}
   1.119 +
   1.120 +/*
   1.121 + * This is called whenever something major happens in the grid. And example 
   1.122 + * might be when many cells or row are added. It sets a flag signaling that 
   1.123 + * all the grids caches information should be recalculated.
   1.124 + */
   1.125 +void
   1.126 +nsGrid::NeedsRebuild(nsBoxLayoutState& aState)
   1.127 +{
   1.128 +  if (mNeedsRebuild)
   1.129 +    return;
   1.130 +
   1.131 +  // iterate through columns and rows and dirty them
   1.132 +  mNeedsRebuild = true;
   1.133 +
   1.134 +  // find the new row and column box. They could have 
   1.135 +  // been changed.
   1.136 +  mRowsBox = nullptr;
   1.137 +  mColumnsBox = nullptr;
   1.138 +  FindRowsAndColumns(&mRowsBox, &mColumnsBox);
   1.139 +
   1.140 +  // tell all the rows and columns they are dirty
   1.141 +  DirtyRows(mRowsBox, aState);
   1.142 +  DirtyRows(mColumnsBox, aState);
   1.143 +}
   1.144 +
   1.145 +
   1.146 +
   1.147 +/**
   1.148 + * If we are marked for rebuild. Then build everything
   1.149 + */
   1.150 +void
   1.151 +nsGrid::RebuildIfNeeded()
   1.152 +{
   1.153 +  if (!mNeedsRebuild)
   1.154 +    return;
   1.155 +
   1.156 +  mNeedsRebuild = false;
   1.157 +
   1.158 +  // find the row and columns frames
   1.159 +  FindRowsAndColumns(&mRowsBox, &mColumnsBox);
   1.160 +
   1.161 +  // count the rows and columns
   1.162 +  int32_t computedRowCount = 0;
   1.163 +  int32_t computedColumnCount = 0;
   1.164 +  int32_t rowCount = 0;
   1.165 +  int32_t columnCount = 0;
   1.166 +
   1.167 +  CountRowsColumns(mRowsBox, rowCount, computedColumnCount);
   1.168 +  CountRowsColumns(mColumnsBox, columnCount, computedRowCount);
   1.169 +
   1.170 +  // computedRowCount are the actual number of rows as determined by the 
   1.171 +  // columns children.
   1.172 +  // computedColumnCount are the number of columns as determined by the number
   1.173 +  // of rows children.
   1.174 +  // We can use this information to see how many extra columns or rows we need.
   1.175 +  // This can happen if there are are more children in a row that number of columns
   1.176 +  // defined. Example:
   1.177 +  //
   1.178 +  // <columns>
   1.179 +  //   <column/>
   1.180 +  // </columns>
   1.181 +  //
   1.182 +  // <rows>
   1.183 +  //   <row>
   1.184 +  //     <button/><button/>
   1.185 +  //   </row>
   1.186 +  // </rows>
   1.187 +  //
   1.188 +  // computedColumnCount = 2 // for the 2 buttons in the row tag
   1.189 +  // computedRowCount = 0 // there is nothing in the  column tag
   1.190 +  // mColumnCount = 1 // one column defined
   1.191 +  // mRowCount = 1 // one row defined
   1.192 +  // 
   1.193 +  // So in this case we need to make 1 extra column.
   1.194 +  //
   1.195 +
   1.196 +  // Make sure to update mExtraColumnCount no matter what, since it might
   1.197 +  // happen that we now have as many columns as are defined, and we wouldn't
   1.198 +  // want to have a positive mExtraColumnCount hanging about in that case!
   1.199 +  mExtraColumnCount = computedColumnCount - columnCount;
   1.200 +  if (computedColumnCount > columnCount) {
   1.201 +     columnCount = computedColumnCount;
   1.202 +  }
   1.203 +
   1.204 +  // Same for rows.
   1.205 +  mExtraRowCount = computedRowCount - rowCount;
   1.206 +  if (computedRowCount > rowCount) {
   1.207 +     rowCount = computedRowCount;
   1.208 +  }
   1.209 +
   1.210 +  // build and poplulate row and columns arrays
   1.211 +  BuildRows(mRowsBox, rowCount, &mRows, true);
   1.212 +  BuildRows(mColumnsBox, columnCount, &mColumns, false);
   1.213 +
   1.214 +  // build and populate the cell map
   1.215 +  mCellMap = BuildCellMap(rowCount, columnCount);
   1.216 +
   1.217 +  mRowCount = rowCount;
   1.218 +  mColumnCount = columnCount;
   1.219 +
   1.220 +  // populate the cell map from column and row children
   1.221 +  PopulateCellMap(mRows, mColumns, mRowCount, mColumnCount, true);
   1.222 +  PopulateCellMap(mColumns, mRows, mColumnCount, mRowCount, false);
   1.223 +}
   1.224 +
   1.225 +void
   1.226 +nsGrid::FreeMap()
   1.227 +{
   1.228 +  if (mRows) 
   1.229 +    delete[] mRows;
   1.230 +
   1.231 +  if (mColumns)
   1.232 +    delete[] mColumns;
   1.233 +
   1.234 +  if (mCellMap)
   1.235 +    delete[] mCellMap;
   1.236 +
   1.237 +  mRows = nullptr;
   1.238 +  mColumns = nullptr;
   1.239 +  mCellMap = nullptr;
   1.240 +  mColumnCount = 0;
   1.241 +  mRowCount = 0;
   1.242 +  mExtraColumnCount = 0;
   1.243 +  mExtraRowCount = 0;
   1.244 +  mRowsBox = nullptr;
   1.245 +  mColumnsBox = nullptr;
   1.246 +}
   1.247 +
   1.248 +/**
   1.249 + * finds the first <rows> and <columns> tags in the <grid> tag
   1.250 + */
   1.251 +void
   1.252 +nsGrid::FindRowsAndColumns(nsIFrame** aRows, nsIFrame** aColumns)
   1.253 +{
   1.254 +  *aRows = nullptr;
   1.255 +  *aColumns = nullptr;
   1.256 +
   1.257 +  // find the boxes that contain our rows and columns
   1.258 +  nsIFrame* child = nullptr;
   1.259 +  // if we have <grid></grid> then mBox will be null (bug 125689)
   1.260 +  if (mBox)
   1.261 +    child = mBox->GetChildBox();
   1.262 +
   1.263 +  while(child)
   1.264 +  {
   1.265 +    nsIFrame* oldBox = child;
   1.266 +    nsIScrollableFrame *scrollFrame = do_QueryFrame(child);
   1.267 +    if (scrollFrame) {
   1.268 +       nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
   1.269 +       NS_ASSERTION(scrolledFrame,"Error no scroll frame!!");
   1.270 +       child = do_QueryFrame(scrolledFrame);
   1.271 +    }
   1.272 +
   1.273 +    nsCOMPtr<nsIGridPart> monument = GetPartFromBox(child);
   1.274 +    if (monument)
   1.275 +    {
   1.276 +      nsGridRowGroupLayout* rowGroup = monument->CastToRowGroupLayout();
   1.277 +      if (rowGroup) {
   1.278 +         bool isHorizontal = !nsSprocketLayout::IsHorizontal(child);
   1.279 +         if (isHorizontal)
   1.280 +           *aRows = child;
   1.281 +         else
   1.282 +           *aColumns = child;
   1.283 +
   1.284 +         if (*aRows && *aColumns)
   1.285 +           return;
   1.286 +      }
   1.287 +    }
   1.288 +
   1.289 +    if (scrollFrame) {
   1.290 +      child = oldBox;
   1.291 +    }
   1.292 +
   1.293 +    child = child->GetNextBox();
   1.294 +  }
   1.295 +}
   1.296 +
   1.297 +/**
   1.298 + * Count the number of rows and columns in the given box. aRowCount well become the actual number
   1.299 + * rows defined in the xul. aComputedColumnCount will become the number of columns by counting the number
   1.300 + * of cells in each row.
   1.301 + */
   1.302 +void
   1.303 +nsGrid::CountRowsColumns(nsIFrame* aRowBox, int32_t& aRowCount, int32_t& aComputedColumnCount)
   1.304 +{
   1.305 +  aRowCount = 0;
   1.306 +  aComputedColumnCount = 0;
   1.307 +  // get the rowboxes layout manager. Then ask it to do the work for us
   1.308 +  if (aRowBox) {
   1.309 +    nsCOMPtr<nsIGridPart> monument = GetPartFromBox(aRowBox);
   1.310 +    if (monument) 
   1.311 +       monument->CountRowsColumns(aRowBox, aRowCount, aComputedColumnCount);
   1.312 +  }
   1.313 +}
   1.314 +
   1.315 +
   1.316 +/**
   1.317 + * Given the number of rows create nsGridRow objects for them and full them out.
   1.318 + */
   1.319 +void
   1.320 +nsGrid::BuildRows(nsIFrame* aBox, int32_t aRowCount, nsGridRow** aRows, bool aIsHorizontal)
   1.321 +{
   1.322 +  // if no rows then return null
   1.323 +  if (aRowCount == 0) {
   1.324 +
   1.325 +    // make sure we free up the memory.
   1.326 +    if (*aRows)
   1.327 +      delete[] (*aRows);
   1.328 +
   1.329 +    *aRows = nullptr;
   1.330 +    return;
   1.331 +  }
   1.332 +
   1.333 +  // create the array
   1.334 +  nsGridRow* row;
   1.335 +  
   1.336 +  // only create new rows if we have to. Reuse old rows.
   1.337 +  if (aIsHorizontal)
   1.338 +  { 
   1.339 +    if (aRowCount > mRowCount) {
   1.340 +       delete[] mRows;
   1.341 +       row = new nsGridRow[aRowCount];
   1.342 +    } else {
   1.343 +      for (int32_t i=0; i < mRowCount; i++)
   1.344 +        mRows[i].Init(nullptr, false);
   1.345 +
   1.346 +      row = mRows;
   1.347 +    }
   1.348 +  } else {
   1.349 +    if (aRowCount > mColumnCount) {
   1.350 +       delete[] mColumns;
   1.351 +       row = new nsGridRow[aRowCount];
   1.352 +    } else {
   1.353 +       for (int32_t i=0; i < mColumnCount; i++)
   1.354 +         mColumns[i].Init(nullptr, false);
   1.355 +
   1.356 +       row = mColumns;
   1.357 +    }
   1.358 +  }
   1.359 +
   1.360 +  // populate it if we can. If not it will contain only dynamic columns
   1.361 +  if (aBox)
   1.362 +  {
   1.363 +    nsCOMPtr<nsIGridPart> monument = GetPartFromBox(aBox);
   1.364 +    if (monument) {
   1.365 +       monument->BuildRows(aBox, row);
   1.366 +    }
   1.367 +  }
   1.368 +
   1.369 +  *aRows = row;
   1.370 +}
   1.371 +
   1.372 +
   1.373 +/**
   1.374 + * Given the number of rows and columns. Build a cellmap
   1.375 + */
   1.376 +nsGridCell*
   1.377 +nsGrid::BuildCellMap(int32_t aRows, int32_t aColumns)
   1.378 +{
   1.379 +  int32_t size = aRows*aColumns;
   1.380 +  int32_t oldsize = mRowCount*mColumnCount;
   1.381 +  if (size == 0) {
   1.382 +    delete[] mCellMap;
   1.383 +  }
   1.384 +  else {
   1.385 +    if (size > oldsize) {
   1.386 +      delete[] mCellMap;
   1.387 +      return new nsGridCell[size];
   1.388 +    } else {
   1.389 +      // clear out cellmap
   1.390 +      for (int32_t i=0; i < oldsize; i++)
   1.391 +      {
   1.392 +        mCellMap[i].SetBoxInRow(nullptr);
   1.393 +        mCellMap[i].SetBoxInColumn(nullptr);
   1.394 +      }
   1.395 +      return mCellMap;
   1.396 +    }
   1.397 +  }
   1.398 +  return nullptr;
   1.399 +}
   1.400 +
   1.401 +/** 
   1.402 + * Run through all the cells in the rows and columns and populate then with 2 cells. One from the row and one
   1.403 + * from the column
   1.404 + */
   1.405 +void
   1.406 +nsGrid::PopulateCellMap(nsGridRow* aRows, nsGridRow* aColumns, int32_t aRowCount, int32_t aColumnCount, bool aIsHorizontal)
   1.407 +{
   1.408 +  if (!aRows)
   1.409 +    return;
   1.410 +
   1.411 +   // look through the columns
   1.412 +  int32_t j = 0;
   1.413 +
   1.414 +  for(int32_t i=0; i < aRowCount; i++) 
   1.415 +  {
   1.416 +     nsIFrame* child = nullptr;
   1.417 +     nsGridRow* row = &aRows[i];
   1.418 +
   1.419 +     // skip bogus rows. They have no cells
   1.420 +     if (row->mIsBogus) 
   1.421 +       continue;
   1.422 +
   1.423 +     child = row->mBox;
   1.424 +     if (child) {
   1.425 +       child = child->GetChildBox();
   1.426 +
   1.427 +       j = 0;
   1.428 +
   1.429 +       while(child && j < aColumnCount)
   1.430 +       {
   1.431 +         // skip bogus column. They have no cells
   1.432 +         nsGridRow* column = &aColumns[j];
   1.433 +         if (column->mIsBogus) 
   1.434 +         {
   1.435 +           j++;
   1.436 +           continue;
   1.437 +         }
   1.438 +
   1.439 +         if (aIsHorizontal)
   1.440 +           GetCellAt(j,i)->SetBoxInRow(child);
   1.441 +         else
   1.442 +           GetCellAt(i,j)->SetBoxInColumn(child);
   1.443 +
   1.444 +         child = child->GetNextBox();
   1.445 +
   1.446 +         j++;
   1.447 +       }
   1.448 +     }
   1.449 +  }
   1.450 +}
   1.451 +
   1.452 +/**
   1.453 + * Run through the rows in the given box and mark them dirty so they 
   1.454 + * will get recalculated and get a layout.
   1.455 + */
   1.456 +void 
   1.457 +nsGrid::DirtyRows(nsIFrame* aRowBox, nsBoxLayoutState& aState)
   1.458 +{
   1.459 +  // make sure we prevent others from dirtying things.
   1.460 +  mMarkingDirty = true;
   1.461 +
   1.462 +  // if the box is a grid part have it recursively hand it.
   1.463 +  if (aRowBox) {
   1.464 +    nsCOMPtr<nsIGridPart> part = GetPartFromBox(aRowBox);
   1.465 +    if (part) 
   1.466 +       part->DirtyRows(aRowBox, aState);
   1.467 +  }
   1.468 +
   1.469 +  mMarkingDirty = false;
   1.470 +}
   1.471 +
   1.472 +nsGridRow*
   1.473 +nsGrid::GetColumnAt(int32_t aIndex, bool aIsHorizontal)
   1.474 +{
   1.475 +  return GetRowAt(aIndex, !aIsHorizontal);
   1.476 +}
   1.477 +
   1.478 +nsGridRow*
   1.479 +nsGrid::GetRowAt(int32_t aIndex, bool aIsHorizontal)
   1.480 +{
   1.481 +  RebuildIfNeeded();
   1.482 +
   1.483 +  if (aIsHorizontal) {
   1.484 +    NS_ASSERTION(aIndex < mRowCount && aIndex >= 0, "Index out of range");
   1.485 +    return &mRows[aIndex];
   1.486 +  } else {
   1.487 +    NS_ASSERTION(aIndex < mColumnCount && aIndex >= 0, "Index out of range");
   1.488 +    return &mColumns[aIndex];
   1.489 +  }
   1.490 +}
   1.491 +
   1.492 +nsGridCell*
   1.493 +nsGrid::GetCellAt(int32_t aX, int32_t aY)
   1.494 +{
   1.495 +  RebuildIfNeeded();
   1.496 +
   1.497 +  NS_ASSERTION(aY < mRowCount && aY >= 0, "Index out of range");
   1.498 +  NS_ASSERTION(aX < mColumnCount && aX >= 0, "Index out of range");
   1.499 +  return &mCellMap[aY*mColumnCount+aX];
   1.500 +}
   1.501 +
   1.502 +int32_t
   1.503 +nsGrid::GetExtraColumnCount(bool aIsHorizontal)
   1.504 +{
   1.505 +  return GetExtraRowCount(!aIsHorizontal);
   1.506 +}
   1.507 +
   1.508 +int32_t
   1.509 +nsGrid::GetExtraRowCount(bool aIsHorizontal)
   1.510 +{
   1.511 +  RebuildIfNeeded();
   1.512 +
   1.513 +  if (aIsHorizontal)
   1.514 +    return mExtraRowCount;
   1.515 +  else
   1.516 +    return mExtraColumnCount;
   1.517 +}
   1.518 +
   1.519 +
   1.520 +/**
   1.521 + * These methods return the preferred, min, max sizes for a given row index.
   1.522 + * aIsHorizontal if aIsHorizontal is true. If you pass false you will get the inverse.
   1.523 + * As if you called GetPrefColumnSize(aState, index, aPref)
   1.524 + */
   1.525 +nsSize
   1.526 +nsGrid::GetPrefRowSize(nsBoxLayoutState& aState, int32_t aRowIndex, bool aIsHorizontal)
   1.527 +{ 
   1.528 +  nsSize size(0,0);
   1.529 +  if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
   1.530 +    return size;
   1.531 +
   1.532 +  nscoord height = GetPrefRowHeight(aState, aRowIndex, aIsHorizontal);
   1.533 +  SetLargestSize(size, height, aIsHorizontal);
   1.534 +
   1.535 +  return size;
   1.536 +}
   1.537 +
   1.538 +nsSize
   1.539 +nsGrid::GetMinRowSize(nsBoxLayoutState& aState, int32_t aRowIndex, bool aIsHorizontal)
   1.540 +{ 
   1.541 +  nsSize size(0,0);
   1.542 +  if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
   1.543 +    return size;
   1.544 +
   1.545 +  nscoord height = GetMinRowHeight(aState, aRowIndex, aIsHorizontal);
   1.546 +  SetLargestSize(size, height, aIsHorizontal);
   1.547 +
   1.548 +  return size;
   1.549 +}
   1.550 +
   1.551 +nsSize
   1.552 +nsGrid::GetMaxRowSize(nsBoxLayoutState& aState, int32_t aRowIndex, bool aIsHorizontal)
   1.553 +{ 
   1.554 +  nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
   1.555 +  if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
   1.556 +    return size;
   1.557 +
   1.558 +  nscoord height = GetMaxRowHeight(aState, aRowIndex, aIsHorizontal);
   1.559 +  SetSmallestSize(size, height, aIsHorizontal);
   1.560 +
   1.561 +  return size;
   1.562 +}
   1.563 +
   1.564 +// static
   1.565 +nsIGridPart*
   1.566 +nsGrid::GetPartFromBox(nsIFrame* aBox)
   1.567 +{
   1.568 +  if (!aBox)
   1.569 +    return nullptr;
   1.570 +
   1.571 +  nsBoxLayout* layout = aBox->GetLayoutManager();
   1.572 +  return layout ? layout->AsGridPart() : nullptr;
   1.573 +}
   1.574 +
   1.575 +nsMargin
   1.576 +nsGrid::GetBoxTotalMargin(nsIFrame* aBox, bool aIsHorizontal)
   1.577 +{
   1.578 +  nsMargin margin(0,0,0,0);
   1.579 +  // walk the boxes parent chain getting the border/padding/margin of our parent rows
   1.580 +  
   1.581 +  // first get the layour manager
   1.582 +  nsIGridPart* part = GetPartFromBox(aBox);
   1.583 +  if (part)
   1.584 +    margin = part->GetTotalMargin(aBox, aIsHorizontal);
   1.585 +
   1.586 +  return margin;
   1.587 +}
   1.588 +
   1.589 +/**
   1.590 + * The first and last rows can be affected by <rows> tags with borders or margin
   1.591 + * gets first and last rows and their indexes.
   1.592 + * If it fails because there are no rows then:
   1.593 + * FirstRow is nullptr
   1.594 + * LastRow is nullptr
   1.595 + * aFirstIndex = -1
   1.596 + * aLastIndex = -1
   1.597 + */
   1.598 +void
   1.599 +nsGrid::GetFirstAndLastRow(nsBoxLayoutState& aState, 
   1.600 +                          int32_t& aFirstIndex, 
   1.601 +                          int32_t& aLastIndex, 
   1.602 +                          nsGridRow*& aFirstRow,
   1.603 +                          nsGridRow*& aLastRow,
   1.604 +                          bool aIsHorizontal)
   1.605 +{
   1.606 +  aFirstRow = nullptr;
   1.607 +  aLastRow = nullptr;
   1.608 +  aFirstIndex = -1;
   1.609 +  aLastIndex = -1;
   1.610 +
   1.611 +  int32_t count = GetRowCount(aIsHorizontal);
   1.612 +
   1.613 +  if (count == 0)
   1.614 +    return;
   1.615 +
   1.616 +
   1.617 +  // We could have collapsed columns either before or after our index.
   1.618 +  // they should not count. So if we are the 5th row and the first 4 are
   1.619 +  // collaped we become the first row. Or if we are the 9th row and
   1.620 +  // 10 up to the last row are collapsed we then become the last.
   1.621 +
   1.622 +  // see if we are first
   1.623 +  int32_t i;
   1.624 +  for (i=0; i < count; i++)
   1.625 +  {
   1.626 +     nsGridRow* row = GetRowAt(i,aIsHorizontal);
   1.627 +     if (!row->IsCollapsed()) {
   1.628 +       aFirstIndex = i;
   1.629 +       aFirstRow = row;
   1.630 +       break;
   1.631 +     }
   1.632 +  }
   1.633 +
   1.634 +  // see if we are last
   1.635 +  for (i=count-1; i >= 0; i--)
   1.636 +  {
   1.637 +     nsGridRow* row = GetRowAt(i,aIsHorizontal);
   1.638 +     if (!row->IsCollapsed()) {
   1.639 +       aLastIndex = i;
   1.640 +       aLastRow = row;
   1.641 +       break;
   1.642 +     }
   1.643 +
   1.644 +  }
   1.645 +}
   1.646 +
   1.647 +/**
   1.648 + * A row can have a top and bottom offset. Usually this is just the top and bottom border/padding.
   1.649 + * However if the row is the first or last it could be affected by the fact a column or columns could
   1.650 + * have a top or bottom margin. 
   1.651 + */
   1.652 +void
   1.653 +nsGrid::GetRowOffsets(nsBoxLayoutState& aState, int32_t aIndex, nscoord& aTop, nscoord& aBottom, bool aIsHorizontal)
   1.654 +{
   1.655 +
   1.656 +  RebuildIfNeeded();
   1.657 +
   1.658 +  nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
   1.659 +
   1.660 +  if (row->IsOffsetSet()) 
   1.661 +  {
   1.662 +    aTop    = row->mTop;
   1.663 +    aBottom = row->mBottom;
   1.664 +    return;
   1.665 +  }
   1.666 +
   1.667 +  // first get the rows top and bottom border and padding
   1.668 +  nsIFrame* box = row->GetBox();
   1.669 +
   1.670 +  // add up all the padding
   1.671 +  nsMargin margin(0,0,0,0);
   1.672 +  nsMargin border(0,0,0,0);
   1.673 +  nsMargin padding(0,0,0,0);
   1.674 +  nsMargin totalBorderPadding(0,0,0,0);
   1.675 +  nsMargin totalMargin(0,0,0,0);
   1.676 +
   1.677 +  // if there is a box and it's not bogus take its
   1.678 +  // borders padding into account
   1.679 +  if (box && !row->mIsBogus)
   1.680 +  {
   1.681 +    if (!box->IsCollapsed())
   1.682 +    {
   1.683 +       // get real border and padding. GetBorderAndPadding
   1.684 +       // is redefined on nsGridRowLeafFrame. If we called it here
   1.685 +       // we would be in finite recurson.
   1.686 +       box->GetBorder(border);
   1.687 +       box->GetPadding(padding);
   1.688 +
   1.689 +       totalBorderPadding += border;
   1.690 +       totalBorderPadding += padding;
   1.691 +     }
   1.692 +
   1.693 +     // if we are the first or last row
   1.694 +     // take into account <rows> tags around us
   1.695 +     // that could have borders or margins.
   1.696 +     // fortunately they only affect the first
   1.697 +     // and last row inside the <rows> tag
   1.698 +
   1.699 +     totalMargin = GetBoxTotalMargin(box, aIsHorizontal);
   1.700 +  }
   1.701 +
   1.702 +  if (aIsHorizontal) {
   1.703 +    row->mTop = totalBorderPadding.top;
   1.704 +    row->mBottom = totalBorderPadding.bottom;
   1.705 +    row->mTopMargin = totalMargin.top;
   1.706 +    row->mBottomMargin = totalMargin.bottom;
   1.707 +  } else {
   1.708 +    row->mTop = totalBorderPadding.left;
   1.709 +    row->mBottom = totalBorderPadding.right;
   1.710 +    row->mTopMargin = totalMargin.left;
   1.711 +    row->mBottomMargin = totalMargin.right;
   1.712 +  }
   1.713 +
   1.714 +  // if we are the first or last row take into account the top and bottom borders
   1.715 +  // of each columns. 
   1.716 +
   1.717 +  // If we are the first row then get the largest top border/padding in 
   1.718 +  // our columns. If that's larger than the rows top border/padding use it.
   1.719 +
   1.720 +  // If we are the last row then get the largest bottom border/padding in 
   1.721 +  // our columns. If that's larger than the rows bottom border/padding use it.
   1.722 +  int32_t firstIndex = 0;
   1.723 +  int32_t lastIndex = 0;
   1.724 +  nsGridRow* firstRow = nullptr;
   1.725 +  nsGridRow* lastRow = nullptr;
   1.726 +  GetFirstAndLastRow(aState, firstIndex, lastIndex, firstRow, lastRow, aIsHorizontal);
   1.727 +
   1.728 +  if (aIndex == firstIndex || aIndex == lastIndex) {
   1.729 +    nscoord maxTop = 0;
   1.730 +    nscoord maxBottom = 0;
   1.731 +
   1.732 +    // run through the columns. Look at each column
   1.733 +    // pick the largest top border or bottom border
   1.734 +    int32_t count = GetColumnCount(aIsHorizontal); 
   1.735 +
   1.736 +    for (int32_t i=0; i < count; i++)
   1.737 +    {  
   1.738 +      nsMargin totalChildBorderPadding(0,0,0,0);
   1.739 +
   1.740 +      nsGridRow* column = GetColumnAt(i,aIsHorizontal);
   1.741 +      nsIFrame* box = column->GetBox();
   1.742 +
   1.743 +      if (box) 
   1.744 +      {
   1.745 +        // ignore collapsed children
   1.746 +        if (!box->IsCollapsed())
   1.747 +        {
   1.748 +           // include the margin of the columns. To the row
   1.749 +           // at this point border/padding and margins all added
   1.750 +           // up to more needed space.
   1.751 +           margin = GetBoxTotalMargin(box, !aIsHorizontal);
   1.752 +           // get real border and padding. GetBorderAndPadding
   1.753 +           // is redefined on nsGridRowLeafFrame. If we called it here
   1.754 +           // we would be in finite recurson.
   1.755 +           box->GetBorder(border);
   1.756 +           box->GetPadding(padding);
   1.757 +           totalChildBorderPadding += border;
   1.758 +           totalChildBorderPadding += padding;
   1.759 +           totalChildBorderPadding += margin;
   1.760 +        }
   1.761 +
   1.762 +        nscoord top;
   1.763 +        nscoord bottom;
   1.764 +
   1.765 +        // pick the largest top margin
   1.766 +        if (aIndex == firstIndex) {
   1.767 +          if (aIsHorizontal) {
   1.768 +            top = totalChildBorderPadding.top;
   1.769 +          } else {
   1.770 +            top = totalChildBorderPadding.left;
   1.771 +          }
   1.772 +          if (top > maxTop)
   1.773 +            maxTop = top;
   1.774 +        } 
   1.775 +
   1.776 +        // pick the largest bottom margin
   1.777 +        if (aIndex == lastIndex) {
   1.778 +          if (aIsHorizontal) {
   1.779 +            bottom = totalChildBorderPadding.bottom;
   1.780 +          } else {
   1.781 +            bottom = totalChildBorderPadding.right;
   1.782 +          }
   1.783 +          if (bottom > maxBottom)
   1.784 +             maxBottom = bottom;
   1.785 +        }
   1.786 +
   1.787 +      }
   1.788 +    
   1.789 +      // If the biggest top border/padding the columns is larger than this rows top border/padding
   1.790 +      // the use it.
   1.791 +      if (aIndex == firstIndex) {
   1.792 +        if (maxTop > (row->mTop + row->mTopMargin))
   1.793 +          row->mTop = maxTop - row->mTopMargin;
   1.794 +      }
   1.795 +
   1.796 +      // If the biggest bottom border/padding the columns is larger than this rows bottom border/padding
   1.797 +      // the use it.
   1.798 +      if (aIndex == lastIndex) {
   1.799 +        if (maxBottom > (row->mBottom + row->mBottomMargin))
   1.800 +          row->mBottom = maxBottom - row->mBottomMargin;
   1.801 +      }
   1.802 +    }
   1.803 +  }
   1.804 +  
   1.805 +  aTop    = row->mTop;
   1.806 +  aBottom = row->mBottom;
   1.807 +}
   1.808 +
   1.809 +/**
   1.810 + * These methods return the preferred, min, max coord for a given row index if
   1.811 + * aIsHorizontal is true. If you pass false you will get the inverse.
   1.812 + * As if you called GetPrefColumnHeight(aState, index, aPref).
   1.813 + */
   1.814 +nscoord
   1.815 +nsGrid::GetPrefRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
   1.816 +{
   1.817 +  RebuildIfNeeded();
   1.818 +
   1.819 +  nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
   1.820 +
   1.821 +  if (row->IsCollapsed())
   1.822 +    return 0;
   1.823 +
   1.824 +  if (row->IsPrefSet()) 
   1.825 +    return row->mPref;
   1.826 +
   1.827 +  nsIFrame* box = row->mBox;
   1.828 +
   1.829 +  // set in CSS?
   1.830 +  if (box) 
   1.831 +  {
   1.832 +    bool widthSet, heightSet;
   1.833 +    nsSize cssSize(-1, -1);
   1.834 +    nsIFrame::AddCSSPrefSize(box, cssSize, widthSet, heightSet);
   1.835 +
   1.836 +    row->mPref = GET_HEIGHT(cssSize, aIsHorizontal);
   1.837 +
   1.838 +    // yep do nothing.
   1.839 +    if (row->mPref != -1)
   1.840 +      return row->mPref;
   1.841 +  }
   1.842 +
   1.843 +  // get the offsets so they are cached.
   1.844 +  nscoord top;
   1.845 +  nscoord bottom;
   1.846 +  GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
   1.847 +
   1.848 +  // is the row bogus? If so then just ask it for its size
   1.849 +  // it should not be affected by cells in the grid. 
   1.850 +  if (row->mIsBogus)
   1.851 +  {
   1.852 +     nsSize size(0,0);
   1.853 +     if (box) 
   1.854 +     {
   1.855 +       size = box->GetPrefSize(aState);
   1.856 +       nsBox::AddMargin(box, size);
   1.857 +       nsGridLayout2::AddOffset(aState, box, size);
   1.858 +     }
   1.859 +
   1.860 +     row->mPref = GET_HEIGHT(size, aIsHorizontal);
   1.861 +     return row->mPref;
   1.862 +  }
   1.863 +
   1.864 +  nsSize size(0,0);
   1.865 +
   1.866 +  nsGridCell* child;
   1.867 +
   1.868 +  int32_t count = GetColumnCount(aIsHorizontal); 
   1.869 +
   1.870 +  for (int32_t i=0; i < count; i++)
   1.871 +  {  
   1.872 +    if (aIsHorizontal)
   1.873 +     child = GetCellAt(i,aIndex);
   1.874 +    else
   1.875 +     child = GetCellAt(aIndex,i);
   1.876 +
   1.877 +    // ignore collapsed children
   1.878 +    if (!child->IsCollapsed())
   1.879 +    {
   1.880 +      nsSize childSize = child->GetPrefSize(aState);
   1.881 +
   1.882 +      nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
   1.883 +    }
   1.884 +  }
   1.885 +
   1.886 +  row->mPref = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
   1.887 +
   1.888 +  return row->mPref;
   1.889 +}
   1.890 +
   1.891 +nscoord
   1.892 +nsGrid::GetMinRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
   1.893 +{
   1.894 +  RebuildIfNeeded();
   1.895 +
   1.896 +  nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
   1.897 +
   1.898 +  if (row->IsCollapsed())
   1.899 +    return 0;
   1.900 +
   1.901 +  if (row->IsMinSet()) 
   1.902 +    return row->mMin;
   1.903 +
   1.904 +  nsIFrame* box = row->mBox;
   1.905 +
   1.906 +  // set in CSS?
   1.907 +  if (box) {
   1.908 +    bool widthSet, heightSet;
   1.909 +    nsSize cssSize(-1, -1);
   1.910 +    nsIFrame::AddCSSMinSize(aState, box, cssSize, widthSet, heightSet);
   1.911 +
   1.912 +    row->mMin = GET_HEIGHT(cssSize, aIsHorizontal);
   1.913 +
   1.914 +    // yep do nothing.
   1.915 +    if (row->mMin != -1)
   1.916 +      return row->mMin;
   1.917 +  }
   1.918 +
   1.919 +  // get the offsets so they are cached.
   1.920 +  nscoord top;
   1.921 +  nscoord bottom;
   1.922 +  GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
   1.923 +
   1.924 +  // is the row bogus? If so then just ask it for its size
   1.925 +  // it should not be affected by cells in the grid. 
   1.926 +  if (row->mIsBogus)
   1.927 +  {
   1.928 +     nsSize size(0,0);
   1.929 +     if (box) {
   1.930 +       size = box->GetPrefSize(aState);
   1.931 +       nsBox::AddMargin(box, size);
   1.932 +       nsGridLayout2::AddOffset(aState, box, size);
   1.933 +     }
   1.934 +
   1.935 +     row->mMin = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
   1.936 +     return row->mMin;
   1.937 +  }
   1.938 +
   1.939 +  nsSize size(0,0);
   1.940 +
   1.941 +  nsGridCell* child;
   1.942 +
   1.943 +  int32_t count = GetColumnCount(aIsHorizontal); 
   1.944 +
   1.945 +  for (int32_t i=0; i < count; i++)
   1.946 +  {  
   1.947 +    if (aIsHorizontal)
   1.948 +     child = GetCellAt(i,aIndex);
   1.949 +    else
   1.950 +     child = GetCellAt(aIndex,i);
   1.951 +
   1.952 +    // ignore collapsed children
   1.953 +    if (!child->IsCollapsed())
   1.954 +    {
   1.955 +      nsSize childSize = child->GetMinSize(aState);
   1.956 +
   1.957 +      nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
   1.958 +    }
   1.959 +  }
   1.960 +
   1.961 +  row->mMin = GET_HEIGHT(size, aIsHorizontal);
   1.962 +
   1.963 +  return row->mMin;
   1.964 +}
   1.965 +
   1.966 +nscoord
   1.967 +nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
   1.968 +{
   1.969 +  RebuildIfNeeded();
   1.970 +
   1.971 +  nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
   1.972 +
   1.973 +  if (row->IsCollapsed())
   1.974 +    return 0;
   1.975 +
   1.976 +  if (row->IsMaxSet()) 
   1.977 +    return row->mMax;
   1.978 +
   1.979 +  nsIFrame* box = row->mBox;
   1.980 +
   1.981 +  // set in CSS?
   1.982 +  if (box) {
   1.983 +    bool widthSet, heightSet;
   1.984 +    nsSize cssSize(-1, -1);
   1.985 +    nsIFrame::AddCSSMaxSize(box, cssSize, widthSet, heightSet);
   1.986 +
   1.987 +    row->mMax = GET_HEIGHT(cssSize, aIsHorizontal);
   1.988 +
   1.989 +    // yep do nothing.
   1.990 +    if (row->mMax != -1)
   1.991 +      return row->mMax;
   1.992 +  }
   1.993 +
   1.994 +  // get the offsets so they are cached.
   1.995 +  nscoord top;
   1.996 +  nscoord bottom;
   1.997 +  GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
   1.998 +
   1.999 +  // is the row bogus? If so then just ask it for its size
  1.1000 +  // it should not be affected by cells in the grid. 
  1.1001 +  if (row->mIsBogus)
  1.1002 +  {
  1.1003 +     nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
  1.1004 +     if (box) {
  1.1005 +       size = box->GetPrefSize(aState);
  1.1006 +       nsBox::AddMargin(box, size);
  1.1007 +       nsGridLayout2::AddOffset(aState, box, size);
  1.1008 +     }
  1.1009 +
  1.1010 +     row->mMax = GET_HEIGHT(size, aIsHorizontal);
  1.1011 +     return row->mMax;
  1.1012 +  }
  1.1013 +
  1.1014 +  nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
  1.1015 +
  1.1016 +  nsGridCell* child;
  1.1017 +
  1.1018 +  int32_t count = GetColumnCount(aIsHorizontal); 
  1.1019 +
  1.1020 +  for (int32_t i=0; i < count; i++)
  1.1021 +  {  
  1.1022 +    if (aIsHorizontal)
  1.1023 +     child = GetCellAt(i,aIndex);
  1.1024 +    else
  1.1025 +     child = GetCellAt(aIndex,i);
  1.1026 +
  1.1027 +    // ignore collapsed children
  1.1028 +    if (!child->IsCollapsed())
  1.1029 +    {
  1.1030 +      nsSize min = child->GetMinSize(aState);
  1.1031 +      nsSize childSize = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState));
  1.1032 +      nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
  1.1033 +    }
  1.1034 +  }
  1.1035 +
  1.1036 +  row->mMax = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
  1.1037 +
  1.1038 +  return row->mMax;
  1.1039 +}
  1.1040 +
  1.1041 +bool
  1.1042 +nsGrid::IsGrid(nsIFrame* aBox)
  1.1043 +{
  1.1044 +  nsIGridPart* part = GetPartFromBox(aBox);
  1.1045 +  if (!part)
  1.1046 +    return false;
  1.1047 +
  1.1048 +  nsGridLayout2* grid = part->CastToGridLayout();
  1.1049 +
  1.1050 +  if (grid)
  1.1051 +    return true;
  1.1052 +
  1.1053 +  return false;
  1.1054 +}
  1.1055 +
  1.1056 +/**
  1.1057 + * This get the flexibilty of the row at aIndex. It's not trivial. There are a few
  1.1058 + * things we need to look at. Specifically we need to see if any <rows> or <columns>
  1.1059 + * tags are around us. Their flexibilty will affect ours.
  1.1060 + */
  1.1061 +nscoord
  1.1062 +nsGrid::GetRowFlex(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
  1.1063 +{
  1.1064 +  RebuildIfNeeded();
  1.1065 +
  1.1066 +  nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
  1.1067 +
  1.1068 +  if (row->IsFlexSet()) 
  1.1069 +    return row->mFlex;
  1.1070 +
  1.1071 +  nsIFrame* box = row->mBox;
  1.1072 +  row->mFlex = 0;
  1.1073 +
  1.1074 +  if (box) {
  1.1075 +
  1.1076 +    // We need our flex but a inflexible row could be around us. If so
  1.1077 +    // neither are we. However if its the row tag just inside the grid it won't 
  1.1078 +    // affect us. We need to do this for this case:
  1.1079 +    // <grid> 
  1.1080 +    //   <rows> 
  1.1081 +    //     <rows> // this is not flexible. So our children should not be flexible
  1.1082 +    //        <row flex="1"/>
  1.1083 +    //        <row flex="1"/>
  1.1084 +    //     </rows>
  1.1085 +    //        <row/>
  1.1086 +    //   </rows>
  1.1087 +    // </grid>
  1.1088 +    //
  1.1089 +    // or..
  1.1090 +    //
  1.1091 +    // <grid> 
  1.1092 +    //  <rows>
  1.1093 +    //   <rows> // this is not flexible. So our children should not be flexible
  1.1094 +    //     <rows flex="1"> 
  1.1095 +    //        <row flex="1"/>
  1.1096 +    //        <row flex="1"/>
  1.1097 +    //     </rows>
  1.1098 +    //        <row/>
  1.1099 +    //   </rows>
  1.1100 +    //  </row>
  1.1101 +    // </grid>
  1.1102 +
  1.1103 +
  1.1104 +    // So here is how it looks
  1.1105 +    //
  1.1106 +    // <grid>     
  1.1107 +    //   <rows>   // parentsParent
  1.1108 +    //     <rows> // parent
  1.1109 +    //        <row flex="1"/> 
  1.1110 +    //        <row flex="1"/>
  1.1111 +    //     </rows>
  1.1112 +    //        <row/>
  1.1113 +    //   </rows>
  1.1114 +    // </grid>
  1.1115 +
  1.1116 +    // so the answer is simple: 1) Walk our parent chain. 2) If we find
  1.1117 +    // someone who is not flexible and they aren't the rows immediately in
  1.1118 +    // the grid. 3) Then we are not flexible
  1.1119 +
  1.1120 +    box = GetScrollBox(box);
  1.1121 +    nsIFrame* parent = box->GetParentBox();
  1.1122 +    nsIFrame* parentsParent=nullptr;
  1.1123 +
  1.1124 +    while(parent)
  1.1125 +    {
  1.1126 +      parent = GetScrollBox(parent);
  1.1127 +      parentsParent = parent->GetParentBox();
  1.1128 +
  1.1129 +      // if our parents parent is not a grid
  1.1130 +      // the get its flex. If its 0 then we are
  1.1131 +      // not flexible.
  1.1132 +      if (parentsParent) {
  1.1133 +        if (!IsGrid(parentsParent)) {
  1.1134 +          nscoord flex = parent->GetFlex(aState);
  1.1135 +          nsIFrame::AddCSSFlex(aState, parent, flex);
  1.1136 +          if (flex == 0) {
  1.1137 +            row->mFlex = 0;
  1.1138 +            return row->mFlex;
  1.1139 +          }
  1.1140 +        } else 
  1.1141 +          break;
  1.1142 +      }
  1.1143 +
  1.1144 +      parent = parentsParent;
  1.1145 +    }
  1.1146 +    
  1.1147 +    // get the row flex.
  1.1148 +    row->mFlex = box->GetFlex(aState);
  1.1149 +    nsIFrame::AddCSSFlex(aState, box, row->mFlex);
  1.1150 +  }
  1.1151 +
  1.1152 +  return row->mFlex;
  1.1153 +}
  1.1154 +
  1.1155 +void
  1.1156 +nsGrid::SetLargestSize(nsSize& aSize, nscoord aHeight, bool aIsHorizontal)
  1.1157 +{
  1.1158 +  if (aIsHorizontal) {
  1.1159 +    if (aSize.height < aHeight)
  1.1160 +      aSize.height = aHeight;
  1.1161 +  } else {
  1.1162 +    if (aSize.width < aHeight)
  1.1163 +      aSize.width = aHeight;
  1.1164 +  }
  1.1165 +}
  1.1166 +
  1.1167 +void
  1.1168 +nsGrid::SetSmallestSize(nsSize& aSize, nscoord aHeight, bool aIsHorizontal)
  1.1169 +{
  1.1170 +  if (aIsHorizontal) {
  1.1171 +    if (aSize.height > aHeight)
  1.1172 +      aSize.height = aHeight;
  1.1173 +  } else {
  1.1174 +    if (aSize.width < aHeight)
  1.1175 +      aSize.width = aHeight;
  1.1176 +  }
  1.1177 +}
  1.1178 +
  1.1179 +int32_t 
  1.1180 +nsGrid::GetRowCount(int32_t aIsHorizontal)
  1.1181 +{
  1.1182 +  RebuildIfNeeded();
  1.1183 +
  1.1184 +  if (aIsHorizontal)
  1.1185 +    return mRowCount;
  1.1186 +  else
  1.1187 +    return mColumnCount;
  1.1188 +}
  1.1189 +
  1.1190 +int32_t 
  1.1191 +nsGrid::GetColumnCount(int32_t aIsHorizontal)
  1.1192 +{
  1.1193 +  return GetRowCount(!aIsHorizontal);
  1.1194 +}
  1.1195 +
  1.1196 +/*
  1.1197 + * A cell in the given row or columns at the given index has had a child added or removed
  1.1198 + */
  1.1199 +void 
  1.1200 +nsGrid::CellAddedOrRemoved(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
  1.1201 +{
  1.1202 +  // TBD see if the cell will fit in our current row. If it will
  1.1203 +  // just add it in. 
  1.1204 +  // but for now rebuild everything.
  1.1205 +  if (mMarkingDirty)
  1.1206 +    return;
  1.1207 +
  1.1208 +  NeedsRebuild(aState);
  1.1209 +}
  1.1210 +
  1.1211 +/**
  1.1212 + * A row or columns at the given index had been added or removed
  1.1213 + */
  1.1214 +void 
  1.1215 +nsGrid::RowAddedOrRemoved(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
  1.1216 +{
  1.1217 +  // TBD see if we have extra room in the table and just add the new row in
  1.1218 +  // for now rebuild the world
  1.1219 +  if (mMarkingDirty)
  1.1220 +    return;
  1.1221 +
  1.1222 +  NeedsRebuild(aState);
  1.1223 +}
  1.1224 +
  1.1225 +/*
  1.1226 + * Scrollframes are tranparent. If this is given a scrollframe is will return the
  1.1227 + * frame inside. If there is no scrollframe it does nothing.
  1.1228 + */
  1.1229 +nsIFrame*
  1.1230 +nsGrid::GetScrolledBox(nsIFrame* aChild)
  1.1231 +{
  1.1232 +  // first see if it is a scrollframe. If so walk down into it and get the scrolled child
  1.1233 +      nsIScrollableFrame *scrollFrame = do_QueryFrame(aChild);
  1.1234 +      if (scrollFrame) {
  1.1235 +         nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
  1.1236 +         NS_ASSERTION(scrolledFrame,"Error no scroll frame!!");
  1.1237 +         return scrolledFrame;
  1.1238 +      }
  1.1239 +
  1.1240 +      return aChild;
  1.1241 +}
  1.1242 +
  1.1243 +/*
  1.1244 + * Scrollframes are tranparent. If this is given a child in a scrollframe is will return the
  1.1245 + * scrollframe ourside it. If there is no scrollframe it does nothing.
  1.1246 + */
  1.1247 +nsIFrame*
  1.1248 +nsGrid::GetScrollBox(nsIFrame* aChild)
  1.1249 +{
  1.1250 +  if (!aChild)
  1.1251 +    return nullptr;
  1.1252 +
  1.1253 +  // get parent
  1.1254 +  nsIFrame* parent = aChild->GetParentBox();
  1.1255 +
  1.1256 +  // walk up until we find a scrollframe or a part
  1.1257 +  // if it's a scrollframe return it.
  1.1258 +  // if it's a parent then the child passed does not
  1.1259 +  // have a scroll frame immediately wrapped around it.
  1.1260 +  while (parent) {
  1.1261 +    nsIScrollableFrame *scrollFrame = do_QueryFrame(parent);
  1.1262 +    // scrollframe? Yep return it.
  1.1263 +    if (scrollFrame)
  1.1264 +      return parent;
  1.1265 +
  1.1266 +    nsCOMPtr<nsIGridPart> parentGridRow = GetPartFromBox(parent);
  1.1267 +    // if a part then just return the child
  1.1268 +    if (parentGridRow) 
  1.1269 +      break;
  1.1270 +
  1.1271 +    parent = parent->GetParentBox();
  1.1272 +  }
  1.1273 +
  1.1274 +  return aChild;
  1.1275 +}
  1.1276 +
  1.1277 +
  1.1278 +
  1.1279 +#ifdef DEBUG_grid
  1.1280 +void
  1.1281 +nsGrid::PrintCellMap()
  1.1282 +{
  1.1283 +  
  1.1284 +  printf("-----Columns------\n");
  1.1285 +  for (int x=0; x < mColumnCount; x++) 
  1.1286 +  {
  1.1287 +   
  1.1288 +    nsGridRow* column = GetColumnAt(x);
  1.1289 +    printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax);
  1.1290 +  }
  1.1291 +
  1.1292 +  printf("\n-----Rows------\n");
  1.1293 +  for (x=0; x < mRowCount; x++) 
  1.1294 +  {
  1.1295 +    nsGridRow* column = GetRowAt(x);
  1.1296 +    printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax);
  1.1297 +  }
  1.1298 +
  1.1299 +  printf("\n");
  1.1300 +  
  1.1301 +}
  1.1302 +#endif

mercurial