layout/xul/grid/nsGrid.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 //
michael@0 7 // Eric Vaughan
michael@0 8 // Netscape Communications
michael@0 9 //
michael@0 10 // See documentation in associated header file
michael@0 11 //
michael@0 12
michael@0 13 #include "nsGrid.h"
michael@0 14 #include "nsGridRowGroupLayout.h"
michael@0 15 #include "nsBox.h"
michael@0 16 #include "nsIScrollableFrame.h"
michael@0 17 #include "nsSprocketLayout.h"
michael@0 18 #include "nsGridLayout2.h"
michael@0 19 #include "nsGridRow.h"
michael@0 20 #include "nsGridCell.h"
michael@0 21 #include "nsHTMLReflowState.h"
michael@0 22
michael@0 23 /*
michael@0 24 The grid control expands the idea of boxes from 1 dimension to 2 dimensions.
michael@0 25 It works by allowing the XUL to define a collection of rows and columns and then
michael@0 26 stacking them on top of each other. Here is and example.
michael@0 27
michael@0 28 Example 1:
michael@0 29
michael@0 30 <grid>
michael@0 31 <columns>
michael@0 32 <column/>
michael@0 33 <column/>
michael@0 34 </columns>
michael@0 35
michael@0 36 <rows>
michael@0 37 <row/>
michael@0 38 <row/>
michael@0 39 </rows>
michael@0 40 </grid>
michael@0 41
michael@0 42 example 2:
michael@0 43
michael@0 44 <grid>
michael@0 45 <columns>
michael@0 46 <column flex="1"/>
michael@0 47 <column flex="1"/>
michael@0 48 </columns>
michael@0 49
michael@0 50 <rows>
michael@0 51 <row>
michael@0 52 <text value="hello"/>
michael@0 53 <text value="there"/>
michael@0 54 </row>
michael@0 55 </rows>
michael@0 56 </grid>
michael@0 57
michael@0 58 example 3:
michael@0 59
michael@0 60 <grid>
michael@0 61
michael@0 62 <rows>
michael@0 63 <row>
michael@0 64 <text value="hello"/>
michael@0 65 <text value="there"/>
michael@0 66 </row>
michael@0 67 </rows>
michael@0 68
michael@0 69 <columns>
michael@0 70 <column>
michael@0 71 <text value="Hey I'm in the column and I'm on top!"/>
michael@0 72 </column>
michael@0 73 <column/>
michael@0 74 </columns>
michael@0 75
michael@0 76 </grid>
michael@0 77
michael@0 78 Usually the columns are first and the rows are second, so the rows will be drawn on top of the columns.
michael@0 79 You can reverse this by defining the rows first.
michael@0 80 Other tags are then placed in the <row> or <column> tags causing the grid to accommodate everyone.
michael@0 81 It does this by creating 3 things: A cellmap, a row list, and a column list. The cellmap is a 2
michael@0 82 dimensional array of nsGridCells. Each cell contains 2 boxes. One cell from the column list
michael@0 83 and one from the row list. When a cell is asked for its size it returns that smallest size it can
michael@0 84 be to accommodate the 2 cells. Row lists and Column lists use the same data structure: nsGridRow.
michael@0 85 Essentially a row and column are the same except a row goes alone the x axis and a column the y.
michael@0 86 To make things easier and save code everything is written in terms of the x dimension. A flag is
michael@0 87 passed in called "isHorizontal" that can flip the calculations to the y axis.
michael@0 88
michael@0 89 Usually the number of cells in a row match the number of columns, but not always.
michael@0 90 It is possible to define 5 columns for a grid but have 10 cells in one of the rows.
michael@0 91 In this case 5 extra columns will be added to the column list to handle the situation.
michael@0 92 These are called extraColumns/Rows.
michael@0 93 */
michael@0 94
michael@0 95 nsGrid::nsGrid():mBox(nullptr),
michael@0 96 mRows(nullptr),
michael@0 97 mColumns(nullptr),
michael@0 98 mRowsBox(nullptr),
michael@0 99 mColumnsBox(nullptr),
michael@0 100 mNeedsRebuild(true),
michael@0 101 mRowCount(0),
michael@0 102 mColumnCount(0),
michael@0 103 mExtraRowCount(0),
michael@0 104 mExtraColumnCount(0),
michael@0 105 mCellMap(nullptr),
michael@0 106 mMarkingDirty(false)
michael@0 107 {
michael@0 108 MOZ_COUNT_CTOR(nsGrid);
michael@0 109 }
michael@0 110
michael@0 111 nsGrid::~nsGrid()
michael@0 112 {
michael@0 113 FreeMap();
michael@0 114 MOZ_COUNT_DTOR(nsGrid);
michael@0 115 }
michael@0 116
michael@0 117 /*
michael@0 118 * This is called whenever something major happens in the grid. And example
michael@0 119 * might be when many cells or row are added. It sets a flag signaling that
michael@0 120 * all the grids caches information should be recalculated.
michael@0 121 */
michael@0 122 void
michael@0 123 nsGrid::NeedsRebuild(nsBoxLayoutState& aState)
michael@0 124 {
michael@0 125 if (mNeedsRebuild)
michael@0 126 return;
michael@0 127
michael@0 128 // iterate through columns and rows and dirty them
michael@0 129 mNeedsRebuild = true;
michael@0 130
michael@0 131 // find the new row and column box. They could have
michael@0 132 // been changed.
michael@0 133 mRowsBox = nullptr;
michael@0 134 mColumnsBox = nullptr;
michael@0 135 FindRowsAndColumns(&mRowsBox, &mColumnsBox);
michael@0 136
michael@0 137 // tell all the rows and columns they are dirty
michael@0 138 DirtyRows(mRowsBox, aState);
michael@0 139 DirtyRows(mColumnsBox, aState);
michael@0 140 }
michael@0 141
michael@0 142
michael@0 143
michael@0 144 /**
michael@0 145 * If we are marked for rebuild. Then build everything
michael@0 146 */
michael@0 147 void
michael@0 148 nsGrid::RebuildIfNeeded()
michael@0 149 {
michael@0 150 if (!mNeedsRebuild)
michael@0 151 return;
michael@0 152
michael@0 153 mNeedsRebuild = false;
michael@0 154
michael@0 155 // find the row and columns frames
michael@0 156 FindRowsAndColumns(&mRowsBox, &mColumnsBox);
michael@0 157
michael@0 158 // count the rows and columns
michael@0 159 int32_t computedRowCount = 0;
michael@0 160 int32_t computedColumnCount = 0;
michael@0 161 int32_t rowCount = 0;
michael@0 162 int32_t columnCount = 0;
michael@0 163
michael@0 164 CountRowsColumns(mRowsBox, rowCount, computedColumnCount);
michael@0 165 CountRowsColumns(mColumnsBox, columnCount, computedRowCount);
michael@0 166
michael@0 167 // computedRowCount are the actual number of rows as determined by the
michael@0 168 // columns children.
michael@0 169 // computedColumnCount are the number of columns as determined by the number
michael@0 170 // of rows children.
michael@0 171 // We can use this information to see how many extra columns or rows we need.
michael@0 172 // This can happen if there are are more children in a row that number of columns
michael@0 173 // defined. Example:
michael@0 174 //
michael@0 175 // <columns>
michael@0 176 // <column/>
michael@0 177 // </columns>
michael@0 178 //
michael@0 179 // <rows>
michael@0 180 // <row>
michael@0 181 // <button/><button/>
michael@0 182 // </row>
michael@0 183 // </rows>
michael@0 184 //
michael@0 185 // computedColumnCount = 2 // for the 2 buttons in the row tag
michael@0 186 // computedRowCount = 0 // there is nothing in the column tag
michael@0 187 // mColumnCount = 1 // one column defined
michael@0 188 // mRowCount = 1 // one row defined
michael@0 189 //
michael@0 190 // So in this case we need to make 1 extra column.
michael@0 191 //
michael@0 192
michael@0 193 // Make sure to update mExtraColumnCount no matter what, since it might
michael@0 194 // happen that we now have as many columns as are defined, and we wouldn't
michael@0 195 // want to have a positive mExtraColumnCount hanging about in that case!
michael@0 196 mExtraColumnCount = computedColumnCount - columnCount;
michael@0 197 if (computedColumnCount > columnCount) {
michael@0 198 columnCount = computedColumnCount;
michael@0 199 }
michael@0 200
michael@0 201 // Same for rows.
michael@0 202 mExtraRowCount = computedRowCount - rowCount;
michael@0 203 if (computedRowCount > rowCount) {
michael@0 204 rowCount = computedRowCount;
michael@0 205 }
michael@0 206
michael@0 207 // build and poplulate row and columns arrays
michael@0 208 BuildRows(mRowsBox, rowCount, &mRows, true);
michael@0 209 BuildRows(mColumnsBox, columnCount, &mColumns, false);
michael@0 210
michael@0 211 // build and populate the cell map
michael@0 212 mCellMap = BuildCellMap(rowCount, columnCount);
michael@0 213
michael@0 214 mRowCount = rowCount;
michael@0 215 mColumnCount = columnCount;
michael@0 216
michael@0 217 // populate the cell map from column and row children
michael@0 218 PopulateCellMap(mRows, mColumns, mRowCount, mColumnCount, true);
michael@0 219 PopulateCellMap(mColumns, mRows, mColumnCount, mRowCount, false);
michael@0 220 }
michael@0 221
michael@0 222 void
michael@0 223 nsGrid::FreeMap()
michael@0 224 {
michael@0 225 if (mRows)
michael@0 226 delete[] mRows;
michael@0 227
michael@0 228 if (mColumns)
michael@0 229 delete[] mColumns;
michael@0 230
michael@0 231 if (mCellMap)
michael@0 232 delete[] mCellMap;
michael@0 233
michael@0 234 mRows = nullptr;
michael@0 235 mColumns = nullptr;
michael@0 236 mCellMap = nullptr;
michael@0 237 mColumnCount = 0;
michael@0 238 mRowCount = 0;
michael@0 239 mExtraColumnCount = 0;
michael@0 240 mExtraRowCount = 0;
michael@0 241 mRowsBox = nullptr;
michael@0 242 mColumnsBox = nullptr;
michael@0 243 }
michael@0 244
michael@0 245 /**
michael@0 246 * finds the first <rows> and <columns> tags in the <grid> tag
michael@0 247 */
michael@0 248 void
michael@0 249 nsGrid::FindRowsAndColumns(nsIFrame** aRows, nsIFrame** aColumns)
michael@0 250 {
michael@0 251 *aRows = nullptr;
michael@0 252 *aColumns = nullptr;
michael@0 253
michael@0 254 // find the boxes that contain our rows and columns
michael@0 255 nsIFrame* child = nullptr;
michael@0 256 // if we have <grid></grid> then mBox will be null (bug 125689)
michael@0 257 if (mBox)
michael@0 258 child = mBox->GetChildBox();
michael@0 259
michael@0 260 while(child)
michael@0 261 {
michael@0 262 nsIFrame* oldBox = child;
michael@0 263 nsIScrollableFrame *scrollFrame = do_QueryFrame(child);
michael@0 264 if (scrollFrame) {
michael@0 265 nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
michael@0 266 NS_ASSERTION(scrolledFrame,"Error no scroll frame!!");
michael@0 267 child = do_QueryFrame(scrolledFrame);
michael@0 268 }
michael@0 269
michael@0 270 nsCOMPtr<nsIGridPart> monument = GetPartFromBox(child);
michael@0 271 if (monument)
michael@0 272 {
michael@0 273 nsGridRowGroupLayout* rowGroup = monument->CastToRowGroupLayout();
michael@0 274 if (rowGroup) {
michael@0 275 bool isHorizontal = !nsSprocketLayout::IsHorizontal(child);
michael@0 276 if (isHorizontal)
michael@0 277 *aRows = child;
michael@0 278 else
michael@0 279 *aColumns = child;
michael@0 280
michael@0 281 if (*aRows && *aColumns)
michael@0 282 return;
michael@0 283 }
michael@0 284 }
michael@0 285
michael@0 286 if (scrollFrame) {
michael@0 287 child = oldBox;
michael@0 288 }
michael@0 289
michael@0 290 child = child->GetNextBox();
michael@0 291 }
michael@0 292 }
michael@0 293
michael@0 294 /**
michael@0 295 * Count the number of rows and columns in the given box. aRowCount well become the actual number
michael@0 296 * rows defined in the xul. aComputedColumnCount will become the number of columns by counting the number
michael@0 297 * of cells in each row.
michael@0 298 */
michael@0 299 void
michael@0 300 nsGrid::CountRowsColumns(nsIFrame* aRowBox, int32_t& aRowCount, int32_t& aComputedColumnCount)
michael@0 301 {
michael@0 302 aRowCount = 0;
michael@0 303 aComputedColumnCount = 0;
michael@0 304 // get the rowboxes layout manager. Then ask it to do the work for us
michael@0 305 if (aRowBox) {
michael@0 306 nsCOMPtr<nsIGridPart> monument = GetPartFromBox(aRowBox);
michael@0 307 if (monument)
michael@0 308 monument->CountRowsColumns(aRowBox, aRowCount, aComputedColumnCount);
michael@0 309 }
michael@0 310 }
michael@0 311
michael@0 312
michael@0 313 /**
michael@0 314 * Given the number of rows create nsGridRow objects for them and full them out.
michael@0 315 */
michael@0 316 void
michael@0 317 nsGrid::BuildRows(nsIFrame* aBox, int32_t aRowCount, nsGridRow** aRows, bool aIsHorizontal)
michael@0 318 {
michael@0 319 // if no rows then return null
michael@0 320 if (aRowCount == 0) {
michael@0 321
michael@0 322 // make sure we free up the memory.
michael@0 323 if (*aRows)
michael@0 324 delete[] (*aRows);
michael@0 325
michael@0 326 *aRows = nullptr;
michael@0 327 return;
michael@0 328 }
michael@0 329
michael@0 330 // create the array
michael@0 331 nsGridRow* row;
michael@0 332
michael@0 333 // only create new rows if we have to. Reuse old rows.
michael@0 334 if (aIsHorizontal)
michael@0 335 {
michael@0 336 if (aRowCount > mRowCount) {
michael@0 337 delete[] mRows;
michael@0 338 row = new nsGridRow[aRowCount];
michael@0 339 } else {
michael@0 340 for (int32_t i=0; i < mRowCount; i++)
michael@0 341 mRows[i].Init(nullptr, false);
michael@0 342
michael@0 343 row = mRows;
michael@0 344 }
michael@0 345 } else {
michael@0 346 if (aRowCount > mColumnCount) {
michael@0 347 delete[] mColumns;
michael@0 348 row = new nsGridRow[aRowCount];
michael@0 349 } else {
michael@0 350 for (int32_t i=0; i < mColumnCount; i++)
michael@0 351 mColumns[i].Init(nullptr, false);
michael@0 352
michael@0 353 row = mColumns;
michael@0 354 }
michael@0 355 }
michael@0 356
michael@0 357 // populate it if we can. If not it will contain only dynamic columns
michael@0 358 if (aBox)
michael@0 359 {
michael@0 360 nsCOMPtr<nsIGridPart> monument = GetPartFromBox(aBox);
michael@0 361 if (monument) {
michael@0 362 monument->BuildRows(aBox, row);
michael@0 363 }
michael@0 364 }
michael@0 365
michael@0 366 *aRows = row;
michael@0 367 }
michael@0 368
michael@0 369
michael@0 370 /**
michael@0 371 * Given the number of rows and columns. Build a cellmap
michael@0 372 */
michael@0 373 nsGridCell*
michael@0 374 nsGrid::BuildCellMap(int32_t aRows, int32_t aColumns)
michael@0 375 {
michael@0 376 int32_t size = aRows*aColumns;
michael@0 377 int32_t oldsize = mRowCount*mColumnCount;
michael@0 378 if (size == 0) {
michael@0 379 delete[] mCellMap;
michael@0 380 }
michael@0 381 else {
michael@0 382 if (size > oldsize) {
michael@0 383 delete[] mCellMap;
michael@0 384 return new nsGridCell[size];
michael@0 385 } else {
michael@0 386 // clear out cellmap
michael@0 387 for (int32_t i=0; i < oldsize; i++)
michael@0 388 {
michael@0 389 mCellMap[i].SetBoxInRow(nullptr);
michael@0 390 mCellMap[i].SetBoxInColumn(nullptr);
michael@0 391 }
michael@0 392 return mCellMap;
michael@0 393 }
michael@0 394 }
michael@0 395 return nullptr;
michael@0 396 }
michael@0 397
michael@0 398 /**
michael@0 399 * Run through all the cells in the rows and columns and populate then with 2 cells. One from the row and one
michael@0 400 * from the column
michael@0 401 */
michael@0 402 void
michael@0 403 nsGrid::PopulateCellMap(nsGridRow* aRows, nsGridRow* aColumns, int32_t aRowCount, int32_t aColumnCount, bool aIsHorizontal)
michael@0 404 {
michael@0 405 if (!aRows)
michael@0 406 return;
michael@0 407
michael@0 408 // look through the columns
michael@0 409 int32_t j = 0;
michael@0 410
michael@0 411 for(int32_t i=0; i < aRowCount; i++)
michael@0 412 {
michael@0 413 nsIFrame* child = nullptr;
michael@0 414 nsGridRow* row = &aRows[i];
michael@0 415
michael@0 416 // skip bogus rows. They have no cells
michael@0 417 if (row->mIsBogus)
michael@0 418 continue;
michael@0 419
michael@0 420 child = row->mBox;
michael@0 421 if (child) {
michael@0 422 child = child->GetChildBox();
michael@0 423
michael@0 424 j = 0;
michael@0 425
michael@0 426 while(child && j < aColumnCount)
michael@0 427 {
michael@0 428 // skip bogus column. They have no cells
michael@0 429 nsGridRow* column = &aColumns[j];
michael@0 430 if (column->mIsBogus)
michael@0 431 {
michael@0 432 j++;
michael@0 433 continue;
michael@0 434 }
michael@0 435
michael@0 436 if (aIsHorizontal)
michael@0 437 GetCellAt(j,i)->SetBoxInRow(child);
michael@0 438 else
michael@0 439 GetCellAt(i,j)->SetBoxInColumn(child);
michael@0 440
michael@0 441 child = child->GetNextBox();
michael@0 442
michael@0 443 j++;
michael@0 444 }
michael@0 445 }
michael@0 446 }
michael@0 447 }
michael@0 448
michael@0 449 /**
michael@0 450 * Run through the rows in the given box and mark them dirty so they
michael@0 451 * will get recalculated and get a layout.
michael@0 452 */
michael@0 453 void
michael@0 454 nsGrid::DirtyRows(nsIFrame* aRowBox, nsBoxLayoutState& aState)
michael@0 455 {
michael@0 456 // make sure we prevent others from dirtying things.
michael@0 457 mMarkingDirty = true;
michael@0 458
michael@0 459 // if the box is a grid part have it recursively hand it.
michael@0 460 if (aRowBox) {
michael@0 461 nsCOMPtr<nsIGridPart> part = GetPartFromBox(aRowBox);
michael@0 462 if (part)
michael@0 463 part->DirtyRows(aRowBox, aState);
michael@0 464 }
michael@0 465
michael@0 466 mMarkingDirty = false;
michael@0 467 }
michael@0 468
michael@0 469 nsGridRow*
michael@0 470 nsGrid::GetColumnAt(int32_t aIndex, bool aIsHorizontal)
michael@0 471 {
michael@0 472 return GetRowAt(aIndex, !aIsHorizontal);
michael@0 473 }
michael@0 474
michael@0 475 nsGridRow*
michael@0 476 nsGrid::GetRowAt(int32_t aIndex, bool aIsHorizontal)
michael@0 477 {
michael@0 478 RebuildIfNeeded();
michael@0 479
michael@0 480 if (aIsHorizontal) {
michael@0 481 NS_ASSERTION(aIndex < mRowCount && aIndex >= 0, "Index out of range");
michael@0 482 return &mRows[aIndex];
michael@0 483 } else {
michael@0 484 NS_ASSERTION(aIndex < mColumnCount && aIndex >= 0, "Index out of range");
michael@0 485 return &mColumns[aIndex];
michael@0 486 }
michael@0 487 }
michael@0 488
michael@0 489 nsGridCell*
michael@0 490 nsGrid::GetCellAt(int32_t aX, int32_t aY)
michael@0 491 {
michael@0 492 RebuildIfNeeded();
michael@0 493
michael@0 494 NS_ASSERTION(aY < mRowCount && aY >= 0, "Index out of range");
michael@0 495 NS_ASSERTION(aX < mColumnCount && aX >= 0, "Index out of range");
michael@0 496 return &mCellMap[aY*mColumnCount+aX];
michael@0 497 }
michael@0 498
michael@0 499 int32_t
michael@0 500 nsGrid::GetExtraColumnCount(bool aIsHorizontal)
michael@0 501 {
michael@0 502 return GetExtraRowCount(!aIsHorizontal);
michael@0 503 }
michael@0 504
michael@0 505 int32_t
michael@0 506 nsGrid::GetExtraRowCount(bool aIsHorizontal)
michael@0 507 {
michael@0 508 RebuildIfNeeded();
michael@0 509
michael@0 510 if (aIsHorizontal)
michael@0 511 return mExtraRowCount;
michael@0 512 else
michael@0 513 return mExtraColumnCount;
michael@0 514 }
michael@0 515
michael@0 516
michael@0 517 /**
michael@0 518 * These methods return the preferred, min, max sizes for a given row index.
michael@0 519 * aIsHorizontal if aIsHorizontal is true. If you pass false you will get the inverse.
michael@0 520 * As if you called GetPrefColumnSize(aState, index, aPref)
michael@0 521 */
michael@0 522 nsSize
michael@0 523 nsGrid::GetPrefRowSize(nsBoxLayoutState& aState, int32_t aRowIndex, bool aIsHorizontal)
michael@0 524 {
michael@0 525 nsSize size(0,0);
michael@0 526 if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
michael@0 527 return size;
michael@0 528
michael@0 529 nscoord height = GetPrefRowHeight(aState, aRowIndex, aIsHorizontal);
michael@0 530 SetLargestSize(size, height, aIsHorizontal);
michael@0 531
michael@0 532 return size;
michael@0 533 }
michael@0 534
michael@0 535 nsSize
michael@0 536 nsGrid::GetMinRowSize(nsBoxLayoutState& aState, int32_t aRowIndex, bool aIsHorizontal)
michael@0 537 {
michael@0 538 nsSize size(0,0);
michael@0 539 if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
michael@0 540 return size;
michael@0 541
michael@0 542 nscoord height = GetMinRowHeight(aState, aRowIndex, aIsHorizontal);
michael@0 543 SetLargestSize(size, height, aIsHorizontal);
michael@0 544
michael@0 545 return size;
michael@0 546 }
michael@0 547
michael@0 548 nsSize
michael@0 549 nsGrid::GetMaxRowSize(nsBoxLayoutState& aState, int32_t aRowIndex, bool aIsHorizontal)
michael@0 550 {
michael@0 551 nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
michael@0 552 if (!(aRowIndex >=0 && aRowIndex < GetRowCount(aIsHorizontal)))
michael@0 553 return size;
michael@0 554
michael@0 555 nscoord height = GetMaxRowHeight(aState, aRowIndex, aIsHorizontal);
michael@0 556 SetSmallestSize(size, height, aIsHorizontal);
michael@0 557
michael@0 558 return size;
michael@0 559 }
michael@0 560
michael@0 561 // static
michael@0 562 nsIGridPart*
michael@0 563 nsGrid::GetPartFromBox(nsIFrame* aBox)
michael@0 564 {
michael@0 565 if (!aBox)
michael@0 566 return nullptr;
michael@0 567
michael@0 568 nsBoxLayout* layout = aBox->GetLayoutManager();
michael@0 569 return layout ? layout->AsGridPart() : nullptr;
michael@0 570 }
michael@0 571
michael@0 572 nsMargin
michael@0 573 nsGrid::GetBoxTotalMargin(nsIFrame* aBox, bool aIsHorizontal)
michael@0 574 {
michael@0 575 nsMargin margin(0,0,0,0);
michael@0 576 // walk the boxes parent chain getting the border/padding/margin of our parent rows
michael@0 577
michael@0 578 // first get the layour manager
michael@0 579 nsIGridPart* part = GetPartFromBox(aBox);
michael@0 580 if (part)
michael@0 581 margin = part->GetTotalMargin(aBox, aIsHorizontal);
michael@0 582
michael@0 583 return margin;
michael@0 584 }
michael@0 585
michael@0 586 /**
michael@0 587 * The first and last rows can be affected by <rows> tags with borders or margin
michael@0 588 * gets first and last rows and their indexes.
michael@0 589 * If it fails because there are no rows then:
michael@0 590 * FirstRow is nullptr
michael@0 591 * LastRow is nullptr
michael@0 592 * aFirstIndex = -1
michael@0 593 * aLastIndex = -1
michael@0 594 */
michael@0 595 void
michael@0 596 nsGrid::GetFirstAndLastRow(nsBoxLayoutState& aState,
michael@0 597 int32_t& aFirstIndex,
michael@0 598 int32_t& aLastIndex,
michael@0 599 nsGridRow*& aFirstRow,
michael@0 600 nsGridRow*& aLastRow,
michael@0 601 bool aIsHorizontal)
michael@0 602 {
michael@0 603 aFirstRow = nullptr;
michael@0 604 aLastRow = nullptr;
michael@0 605 aFirstIndex = -1;
michael@0 606 aLastIndex = -1;
michael@0 607
michael@0 608 int32_t count = GetRowCount(aIsHorizontal);
michael@0 609
michael@0 610 if (count == 0)
michael@0 611 return;
michael@0 612
michael@0 613
michael@0 614 // We could have collapsed columns either before or after our index.
michael@0 615 // they should not count. So if we are the 5th row and the first 4 are
michael@0 616 // collaped we become the first row. Or if we are the 9th row and
michael@0 617 // 10 up to the last row are collapsed we then become the last.
michael@0 618
michael@0 619 // see if we are first
michael@0 620 int32_t i;
michael@0 621 for (i=0; i < count; i++)
michael@0 622 {
michael@0 623 nsGridRow* row = GetRowAt(i,aIsHorizontal);
michael@0 624 if (!row->IsCollapsed()) {
michael@0 625 aFirstIndex = i;
michael@0 626 aFirstRow = row;
michael@0 627 break;
michael@0 628 }
michael@0 629 }
michael@0 630
michael@0 631 // see if we are last
michael@0 632 for (i=count-1; i >= 0; i--)
michael@0 633 {
michael@0 634 nsGridRow* row = GetRowAt(i,aIsHorizontal);
michael@0 635 if (!row->IsCollapsed()) {
michael@0 636 aLastIndex = i;
michael@0 637 aLastRow = row;
michael@0 638 break;
michael@0 639 }
michael@0 640
michael@0 641 }
michael@0 642 }
michael@0 643
michael@0 644 /**
michael@0 645 * A row can have a top and bottom offset. Usually this is just the top and bottom border/padding.
michael@0 646 * However if the row is the first or last it could be affected by the fact a column or columns could
michael@0 647 * have a top or bottom margin.
michael@0 648 */
michael@0 649 void
michael@0 650 nsGrid::GetRowOffsets(nsBoxLayoutState& aState, int32_t aIndex, nscoord& aTop, nscoord& aBottom, bool aIsHorizontal)
michael@0 651 {
michael@0 652
michael@0 653 RebuildIfNeeded();
michael@0 654
michael@0 655 nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
michael@0 656
michael@0 657 if (row->IsOffsetSet())
michael@0 658 {
michael@0 659 aTop = row->mTop;
michael@0 660 aBottom = row->mBottom;
michael@0 661 return;
michael@0 662 }
michael@0 663
michael@0 664 // first get the rows top and bottom border and padding
michael@0 665 nsIFrame* box = row->GetBox();
michael@0 666
michael@0 667 // add up all the padding
michael@0 668 nsMargin margin(0,0,0,0);
michael@0 669 nsMargin border(0,0,0,0);
michael@0 670 nsMargin padding(0,0,0,0);
michael@0 671 nsMargin totalBorderPadding(0,0,0,0);
michael@0 672 nsMargin totalMargin(0,0,0,0);
michael@0 673
michael@0 674 // if there is a box and it's not bogus take its
michael@0 675 // borders padding into account
michael@0 676 if (box && !row->mIsBogus)
michael@0 677 {
michael@0 678 if (!box->IsCollapsed())
michael@0 679 {
michael@0 680 // get real border and padding. GetBorderAndPadding
michael@0 681 // is redefined on nsGridRowLeafFrame. If we called it here
michael@0 682 // we would be in finite recurson.
michael@0 683 box->GetBorder(border);
michael@0 684 box->GetPadding(padding);
michael@0 685
michael@0 686 totalBorderPadding += border;
michael@0 687 totalBorderPadding += padding;
michael@0 688 }
michael@0 689
michael@0 690 // if we are the first or last row
michael@0 691 // take into account <rows> tags around us
michael@0 692 // that could have borders or margins.
michael@0 693 // fortunately they only affect the first
michael@0 694 // and last row inside the <rows> tag
michael@0 695
michael@0 696 totalMargin = GetBoxTotalMargin(box, aIsHorizontal);
michael@0 697 }
michael@0 698
michael@0 699 if (aIsHorizontal) {
michael@0 700 row->mTop = totalBorderPadding.top;
michael@0 701 row->mBottom = totalBorderPadding.bottom;
michael@0 702 row->mTopMargin = totalMargin.top;
michael@0 703 row->mBottomMargin = totalMargin.bottom;
michael@0 704 } else {
michael@0 705 row->mTop = totalBorderPadding.left;
michael@0 706 row->mBottom = totalBorderPadding.right;
michael@0 707 row->mTopMargin = totalMargin.left;
michael@0 708 row->mBottomMargin = totalMargin.right;
michael@0 709 }
michael@0 710
michael@0 711 // if we are the first or last row take into account the top and bottom borders
michael@0 712 // of each columns.
michael@0 713
michael@0 714 // If we are the first row then get the largest top border/padding in
michael@0 715 // our columns. If that's larger than the rows top border/padding use it.
michael@0 716
michael@0 717 // If we are the last row then get the largest bottom border/padding in
michael@0 718 // our columns. If that's larger than the rows bottom border/padding use it.
michael@0 719 int32_t firstIndex = 0;
michael@0 720 int32_t lastIndex = 0;
michael@0 721 nsGridRow* firstRow = nullptr;
michael@0 722 nsGridRow* lastRow = nullptr;
michael@0 723 GetFirstAndLastRow(aState, firstIndex, lastIndex, firstRow, lastRow, aIsHorizontal);
michael@0 724
michael@0 725 if (aIndex == firstIndex || aIndex == lastIndex) {
michael@0 726 nscoord maxTop = 0;
michael@0 727 nscoord maxBottom = 0;
michael@0 728
michael@0 729 // run through the columns. Look at each column
michael@0 730 // pick the largest top border or bottom border
michael@0 731 int32_t count = GetColumnCount(aIsHorizontal);
michael@0 732
michael@0 733 for (int32_t i=0; i < count; i++)
michael@0 734 {
michael@0 735 nsMargin totalChildBorderPadding(0,0,0,0);
michael@0 736
michael@0 737 nsGridRow* column = GetColumnAt(i,aIsHorizontal);
michael@0 738 nsIFrame* box = column->GetBox();
michael@0 739
michael@0 740 if (box)
michael@0 741 {
michael@0 742 // ignore collapsed children
michael@0 743 if (!box->IsCollapsed())
michael@0 744 {
michael@0 745 // include the margin of the columns. To the row
michael@0 746 // at this point border/padding and margins all added
michael@0 747 // up to more needed space.
michael@0 748 margin = GetBoxTotalMargin(box, !aIsHorizontal);
michael@0 749 // get real border and padding. GetBorderAndPadding
michael@0 750 // is redefined on nsGridRowLeafFrame. If we called it here
michael@0 751 // we would be in finite recurson.
michael@0 752 box->GetBorder(border);
michael@0 753 box->GetPadding(padding);
michael@0 754 totalChildBorderPadding += border;
michael@0 755 totalChildBorderPadding += padding;
michael@0 756 totalChildBorderPadding += margin;
michael@0 757 }
michael@0 758
michael@0 759 nscoord top;
michael@0 760 nscoord bottom;
michael@0 761
michael@0 762 // pick the largest top margin
michael@0 763 if (aIndex == firstIndex) {
michael@0 764 if (aIsHorizontal) {
michael@0 765 top = totalChildBorderPadding.top;
michael@0 766 } else {
michael@0 767 top = totalChildBorderPadding.left;
michael@0 768 }
michael@0 769 if (top > maxTop)
michael@0 770 maxTop = top;
michael@0 771 }
michael@0 772
michael@0 773 // pick the largest bottom margin
michael@0 774 if (aIndex == lastIndex) {
michael@0 775 if (aIsHorizontal) {
michael@0 776 bottom = totalChildBorderPadding.bottom;
michael@0 777 } else {
michael@0 778 bottom = totalChildBorderPadding.right;
michael@0 779 }
michael@0 780 if (bottom > maxBottom)
michael@0 781 maxBottom = bottom;
michael@0 782 }
michael@0 783
michael@0 784 }
michael@0 785
michael@0 786 // If the biggest top border/padding the columns is larger than this rows top border/padding
michael@0 787 // the use it.
michael@0 788 if (aIndex == firstIndex) {
michael@0 789 if (maxTop > (row->mTop + row->mTopMargin))
michael@0 790 row->mTop = maxTop - row->mTopMargin;
michael@0 791 }
michael@0 792
michael@0 793 // If the biggest bottom border/padding the columns is larger than this rows bottom border/padding
michael@0 794 // the use it.
michael@0 795 if (aIndex == lastIndex) {
michael@0 796 if (maxBottom > (row->mBottom + row->mBottomMargin))
michael@0 797 row->mBottom = maxBottom - row->mBottomMargin;
michael@0 798 }
michael@0 799 }
michael@0 800 }
michael@0 801
michael@0 802 aTop = row->mTop;
michael@0 803 aBottom = row->mBottom;
michael@0 804 }
michael@0 805
michael@0 806 /**
michael@0 807 * These methods return the preferred, min, max coord for a given row index if
michael@0 808 * aIsHorizontal is true. If you pass false you will get the inverse.
michael@0 809 * As if you called GetPrefColumnHeight(aState, index, aPref).
michael@0 810 */
michael@0 811 nscoord
michael@0 812 nsGrid::GetPrefRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
michael@0 813 {
michael@0 814 RebuildIfNeeded();
michael@0 815
michael@0 816 nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
michael@0 817
michael@0 818 if (row->IsCollapsed())
michael@0 819 return 0;
michael@0 820
michael@0 821 if (row->IsPrefSet())
michael@0 822 return row->mPref;
michael@0 823
michael@0 824 nsIFrame* box = row->mBox;
michael@0 825
michael@0 826 // set in CSS?
michael@0 827 if (box)
michael@0 828 {
michael@0 829 bool widthSet, heightSet;
michael@0 830 nsSize cssSize(-1, -1);
michael@0 831 nsIFrame::AddCSSPrefSize(box, cssSize, widthSet, heightSet);
michael@0 832
michael@0 833 row->mPref = GET_HEIGHT(cssSize, aIsHorizontal);
michael@0 834
michael@0 835 // yep do nothing.
michael@0 836 if (row->mPref != -1)
michael@0 837 return row->mPref;
michael@0 838 }
michael@0 839
michael@0 840 // get the offsets so they are cached.
michael@0 841 nscoord top;
michael@0 842 nscoord bottom;
michael@0 843 GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
michael@0 844
michael@0 845 // is the row bogus? If so then just ask it for its size
michael@0 846 // it should not be affected by cells in the grid.
michael@0 847 if (row->mIsBogus)
michael@0 848 {
michael@0 849 nsSize size(0,0);
michael@0 850 if (box)
michael@0 851 {
michael@0 852 size = box->GetPrefSize(aState);
michael@0 853 nsBox::AddMargin(box, size);
michael@0 854 nsGridLayout2::AddOffset(aState, box, size);
michael@0 855 }
michael@0 856
michael@0 857 row->mPref = GET_HEIGHT(size, aIsHorizontal);
michael@0 858 return row->mPref;
michael@0 859 }
michael@0 860
michael@0 861 nsSize size(0,0);
michael@0 862
michael@0 863 nsGridCell* child;
michael@0 864
michael@0 865 int32_t count = GetColumnCount(aIsHorizontal);
michael@0 866
michael@0 867 for (int32_t i=0; i < count; i++)
michael@0 868 {
michael@0 869 if (aIsHorizontal)
michael@0 870 child = GetCellAt(i,aIndex);
michael@0 871 else
michael@0 872 child = GetCellAt(aIndex,i);
michael@0 873
michael@0 874 // ignore collapsed children
michael@0 875 if (!child->IsCollapsed())
michael@0 876 {
michael@0 877 nsSize childSize = child->GetPrefSize(aState);
michael@0 878
michael@0 879 nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
michael@0 880 }
michael@0 881 }
michael@0 882
michael@0 883 row->mPref = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
michael@0 884
michael@0 885 return row->mPref;
michael@0 886 }
michael@0 887
michael@0 888 nscoord
michael@0 889 nsGrid::GetMinRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
michael@0 890 {
michael@0 891 RebuildIfNeeded();
michael@0 892
michael@0 893 nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
michael@0 894
michael@0 895 if (row->IsCollapsed())
michael@0 896 return 0;
michael@0 897
michael@0 898 if (row->IsMinSet())
michael@0 899 return row->mMin;
michael@0 900
michael@0 901 nsIFrame* box = row->mBox;
michael@0 902
michael@0 903 // set in CSS?
michael@0 904 if (box) {
michael@0 905 bool widthSet, heightSet;
michael@0 906 nsSize cssSize(-1, -1);
michael@0 907 nsIFrame::AddCSSMinSize(aState, box, cssSize, widthSet, heightSet);
michael@0 908
michael@0 909 row->mMin = GET_HEIGHT(cssSize, aIsHorizontal);
michael@0 910
michael@0 911 // yep do nothing.
michael@0 912 if (row->mMin != -1)
michael@0 913 return row->mMin;
michael@0 914 }
michael@0 915
michael@0 916 // get the offsets so they are cached.
michael@0 917 nscoord top;
michael@0 918 nscoord bottom;
michael@0 919 GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
michael@0 920
michael@0 921 // is the row bogus? If so then just ask it for its size
michael@0 922 // it should not be affected by cells in the grid.
michael@0 923 if (row->mIsBogus)
michael@0 924 {
michael@0 925 nsSize size(0,0);
michael@0 926 if (box) {
michael@0 927 size = box->GetPrefSize(aState);
michael@0 928 nsBox::AddMargin(box, size);
michael@0 929 nsGridLayout2::AddOffset(aState, box, size);
michael@0 930 }
michael@0 931
michael@0 932 row->mMin = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
michael@0 933 return row->mMin;
michael@0 934 }
michael@0 935
michael@0 936 nsSize size(0,0);
michael@0 937
michael@0 938 nsGridCell* child;
michael@0 939
michael@0 940 int32_t count = GetColumnCount(aIsHorizontal);
michael@0 941
michael@0 942 for (int32_t i=0; i < count; i++)
michael@0 943 {
michael@0 944 if (aIsHorizontal)
michael@0 945 child = GetCellAt(i,aIndex);
michael@0 946 else
michael@0 947 child = GetCellAt(aIndex,i);
michael@0 948
michael@0 949 // ignore collapsed children
michael@0 950 if (!child->IsCollapsed())
michael@0 951 {
michael@0 952 nsSize childSize = child->GetMinSize(aState);
michael@0 953
michael@0 954 nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
michael@0 955 }
michael@0 956 }
michael@0 957
michael@0 958 row->mMin = GET_HEIGHT(size, aIsHorizontal);
michael@0 959
michael@0 960 return row->mMin;
michael@0 961 }
michael@0 962
michael@0 963 nscoord
michael@0 964 nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
michael@0 965 {
michael@0 966 RebuildIfNeeded();
michael@0 967
michael@0 968 nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
michael@0 969
michael@0 970 if (row->IsCollapsed())
michael@0 971 return 0;
michael@0 972
michael@0 973 if (row->IsMaxSet())
michael@0 974 return row->mMax;
michael@0 975
michael@0 976 nsIFrame* box = row->mBox;
michael@0 977
michael@0 978 // set in CSS?
michael@0 979 if (box) {
michael@0 980 bool widthSet, heightSet;
michael@0 981 nsSize cssSize(-1, -1);
michael@0 982 nsIFrame::AddCSSMaxSize(box, cssSize, widthSet, heightSet);
michael@0 983
michael@0 984 row->mMax = GET_HEIGHT(cssSize, aIsHorizontal);
michael@0 985
michael@0 986 // yep do nothing.
michael@0 987 if (row->mMax != -1)
michael@0 988 return row->mMax;
michael@0 989 }
michael@0 990
michael@0 991 // get the offsets so they are cached.
michael@0 992 nscoord top;
michael@0 993 nscoord bottom;
michael@0 994 GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal);
michael@0 995
michael@0 996 // is the row bogus? If so then just ask it for its size
michael@0 997 // it should not be affected by cells in the grid.
michael@0 998 if (row->mIsBogus)
michael@0 999 {
michael@0 1000 nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
michael@0 1001 if (box) {
michael@0 1002 size = box->GetPrefSize(aState);
michael@0 1003 nsBox::AddMargin(box, size);
michael@0 1004 nsGridLayout2::AddOffset(aState, box, size);
michael@0 1005 }
michael@0 1006
michael@0 1007 row->mMax = GET_HEIGHT(size, aIsHorizontal);
michael@0 1008 return row->mMax;
michael@0 1009 }
michael@0 1010
michael@0 1011 nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
michael@0 1012
michael@0 1013 nsGridCell* child;
michael@0 1014
michael@0 1015 int32_t count = GetColumnCount(aIsHorizontal);
michael@0 1016
michael@0 1017 for (int32_t i=0; i < count; i++)
michael@0 1018 {
michael@0 1019 if (aIsHorizontal)
michael@0 1020 child = GetCellAt(i,aIndex);
michael@0 1021 else
michael@0 1022 child = GetCellAt(aIndex,i);
michael@0 1023
michael@0 1024 // ignore collapsed children
michael@0 1025 if (!child->IsCollapsed())
michael@0 1026 {
michael@0 1027 nsSize min = child->GetMinSize(aState);
michael@0 1028 nsSize childSize = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState));
michael@0 1029 nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
michael@0 1030 }
michael@0 1031 }
michael@0 1032
michael@0 1033 row->mMax = GET_HEIGHT(size, aIsHorizontal) + top + bottom;
michael@0 1034
michael@0 1035 return row->mMax;
michael@0 1036 }
michael@0 1037
michael@0 1038 bool
michael@0 1039 nsGrid::IsGrid(nsIFrame* aBox)
michael@0 1040 {
michael@0 1041 nsIGridPart* part = GetPartFromBox(aBox);
michael@0 1042 if (!part)
michael@0 1043 return false;
michael@0 1044
michael@0 1045 nsGridLayout2* grid = part->CastToGridLayout();
michael@0 1046
michael@0 1047 if (grid)
michael@0 1048 return true;
michael@0 1049
michael@0 1050 return false;
michael@0 1051 }
michael@0 1052
michael@0 1053 /**
michael@0 1054 * This get the flexibilty of the row at aIndex. It's not trivial. There are a few
michael@0 1055 * things we need to look at. Specifically we need to see if any <rows> or <columns>
michael@0 1056 * tags are around us. Their flexibilty will affect ours.
michael@0 1057 */
michael@0 1058 nscoord
michael@0 1059 nsGrid::GetRowFlex(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
michael@0 1060 {
michael@0 1061 RebuildIfNeeded();
michael@0 1062
michael@0 1063 nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
michael@0 1064
michael@0 1065 if (row->IsFlexSet())
michael@0 1066 return row->mFlex;
michael@0 1067
michael@0 1068 nsIFrame* box = row->mBox;
michael@0 1069 row->mFlex = 0;
michael@0 1070
michael@0 1071 if (box) {
michael@0 1072
michael@0 1073 // We need our flex but a inflexible row could be around us. If so
michael@0 1074 // neither are we. However if its the row tag just inside the grid it won't
michael@0 1075 // affect us. We need to do this for this case:
michael@0 1076 // <grid>
michael@0 1077 // <rows>
michael@0 1078 // <rows> // this is not flexible. So our children should not be flexible
michael@0 1079 // <row flex="1"/>
michael@0 1080 // <row flex="1"/>
michael@0 1081 // </rows>
michael@0 1082 // <row/>
michael@0 1083 // </rows>
michael@0 1084 // </grid>
michael@0 1085 //
michael@0 1086 // or..
michael@0 1087 //
michael@0 1088 // <grid>
michael@0 1089 // <rows>
michael@0 1090 // <rows> // this is not flexible. So our children should not be flexible
michael@0 1091 // <rows flex="1">
michael@0 1092 // <row flex="1"/>
michael@0 1093 // <row flex="1"/>
michael@0 1094 // </rows>
michael@0 1095 // <row/>
michael@0 1096 // </rows>
michael@0 1097 // </row>
michael@0 1098 // </grid>
michael@0 1099
michael@0 1100
michael@0 1101 // So here is how it looks
michael@0 1102 //
michael@0 1103 // <grid>
michael@0 1104 // <rows> // parentsParent
michael@0 1105 // <rows> // parent
michael@0 1106 // <row flex="1"/>
michael@0 1107 // <row flex="1"/>
michael@0 1108 // </rows>
michael@0 1109 // <row/>
michael@0 1110 // </rows>
michael@0 1111 // </grid>
michael@0 1112
michael@0 1113 // so the answer is simple: 1) Walk our parent chain. 2) If we find
michael@0 1114 // someone who is not flexible and they aren't the rows immediately in
michael@0 1115 // the grid. 3) Then we are not flexible
michael@0 1116
michael@0 1117 box = GetScrollBox(box);
michael@0 1118 nsIFrame* parent = box->GetParentBox();
michael@0 1119 nsIFrame* parentsParent=nullptr;
michael@0 1120
michael@0 1121 while(parent)
michael@0 1122 {
michael@0 1123 parent = GetScrollBox(parent);
michael@0 1124 parentsParent = parent->GetParentBox();
michael@0 1125
michael@0 1126 // if our parents parent is not a grid
michael@0 1127 // the get its flex. If its 0 then we are
michael@0 1128 // not flexible.
michael@0 1129 if (parentsParent) {
michael@0 1130 if (!IsGrid(parentsParent)) {
michael@0 1131 nscoord flex = parent->GetFlex(aState);
michael@0 1132 nsIFrame::AddCSSFlex(aState, parent, flex);
michael@0 1133 if (flex == 0) {
michael@0 1134 row->mFlex = 0;
michael@0 1135 return row->mFlex;
michael@0 1136 }
michael@0 1137 } else
michael@0 1138 break;
michael@0 1139 }
michael@0 1140
michael@0 1141 parent = parentsParent;
michael@0 1142 }
michael@0 1143
michael@0 1144 // get the row flex.
michael@0 1145 row->mFlex = box->GetFlex(aState);
michael@0 1146 nsIFrame::AddCSSFlex(aState, box, row->mFlex);
michael@0 1147 }
michael@0 1148
michael@0 1149 return row->mFlex;
michael@0 1150 }
michael@0 1151
michael@0 1152 void
michael@0 1153 nsGrid::SetLargestSize(nsSize& aSize, nscoord aHeight, bool aIsHorizontal)
michael@0 1154 {
michael@0 1155 if (aIsHorizontal) {
michael@0 1156 if (aSize.height < aHeight)
michael@0 1157 aSize.height = aHeight;
michael@0 1158 } else {
michael@0 1159 if (aSize.width < aHeight)
michael@0 1160 aSize.width = aHeight;
michael@0 1161 }
michael@0 1162 }
michael@0 1163
michael@0 1164 void
michael@0 1165 nsGrid::SetSmallestSize(nsSize& aSize, nscoord aHeight, bool aIsHorizontal)
michael@0 1166 {
michael@0 1167 if (aIsHorizontal) {
michael@0 1168 if (aSize.height > aHeight)
michael@0 1169 aSize.height = aHeight;
michael@0 1170 } else {
michael@0 1171 if (aSize.width < aHeight)
michael@0 1172 aSize.width = aHeight;
michael@0 1173 }
michael@0 1174 }
michael@0 1175
michael@0 1176 int32_t
michael@0 1177 nsGrid::GetRowCount(int32_t aIsHorizontal)
michael@0 1178 {
michael@0 1179 RebuildIfNeeded();
michael@0 1180
michael@0 1181 if (aIsHorizontal)
michael@0 1182 return mRowCount;
michael@0 1183 else
michael@0 1184 return mColumnCount;
michael@0 1185 }
michael@0 1186
michael@0 1187 int32_t
michael@0 1188 nsGrid::GetColumnCount(int32_t aIsHorizontal)
michael@0 1189 {
michael@0 1190 return GetRowCount(!aIsHorizontal);
michael@0 1191 }
michael@0 1192
michael@0 1193 /*
michael@0 1194 * A cell in the given row or columns at the given index has had a child added or removed
michael@0 1195 */
michael@0 1196 void
michael@0 1197 nsGrid::CellAddedOrRemoved(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
michael@0 1198 {
michael@0 1199 // TBD see if the cell will fit in our current row. If it will
michael@0 1200 // just add it in.
michael@0 1201 // but for now rebuild everything.
michael@0 1202 if (mMarkingDirty)
michael@0 1203 return;
michael@0 1204
michael@0 1205 NeedsRebuild(aState);
michael@0 1206 }
michael@0 1207
michael@0 1208 /**
michael@0 1209 * A row or columns at the given index had been added or removed
michael@0 1210 */
michael@0 1211 void
michael@0 1212 nsGrid::RowAddedOrRemoved(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizontal)
michael@0 1213 {
michael@0 1214 // TBD see if we have extra room in the table and just add the new row in
michael@0 1215 // for now rebuild the world
michael@0 1216 if (mMarkingDirty)
michael@0 1217 return;
michael@0 1218
michael@0 1219 NeedsRebuild(aState);
michael@0 1220 }
michael@0 1221
michael@0 1222 /*
michael@0 1223 * Scrollframes are tranparent. If this is given a scrollframe is will return the
michael@0 1224 * frame inside. If there is no scrollframe it does nothing.
michael@0 1225 */
michael@0 1226 nsIFrame*
michael@0 1227 nsGrid::GetScrolledBox(nsIFrame* aChild)
michael@0 1228 {
michael@0 1229 // first see if it is a scrollframe. If so walk down into it and get the scrolled child
michael@0 1230 nsIScrollableFrame *scrollFrame = do_QueryFrame(aChild);
michael@0 1231 if (scrollFrame) {
michael@0 1232 nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
michael@0 1233 NS_ASSERTION(scrolledFrame,"Error no scroll frame!!");
michael@0 1234 return scrolledFrame;
michael@0 1235 }
michael@0 1236
michael@0 1237 return aChild;
michael@0 1238 }
michael@0 1239
michael@0 1240 /*
michael@0 1241 * Scrollframes are tranparent. If this is given a child in a scrollframe is will return the
michael@0 1242 * scrollframe ourside it. If there is no scrollframe it does nothing.
michael@0 1243 */
michael@0 1244 nsIFrame*
michael@0 1245 nsGrid::GetScrollBox(nsIFrame* aChild)
michael@0 1246 {
michael@0 1247 if (!aChild)
michael@0 1248 return nullptr;
michael@0 1249
michael@0 1250 // get parent
michael@0 1251 nsIFrame* parent = aChild->GetParentBox();
michael@0 1252
michael@0 1253 // walk up until we find a scrollframe or a part
michael@0 1254 // if it's a scrollframe return it.
michael@0 1255 // if it's a parent then the child passed does not
michael@0 1256 // have a scroll frame immediately wrapped around it.
michael@0 1257 while (parent) {
michael@0 1258 nsIScrollableFrame *scrollFrame = do_QueryFrame(parent);
michael@0 1259 // scrollframe? Yep return it.
michael@0 1260 if (scrollFrame)
michael@0 1261 return parent;
michael@0 1262
michael@0 1263 nsCOMPtr<nsIGridPart> parentGridRow = GetPartFromBox(parent);
michael@0 1264 // if a part then just return the child
michael@0 1265 if (parentGridRow)
michael@0 1266 break;
michael@0 1267
michael@0 1268 parent = parent->GetParentBox();
michael@0 1269 }
michael@0 1270
michael@0 1271 return aChild;
michael@0 1272 }
michael@0 1273
michael@0 1274
michael@0 1275
michael@0 1276 #ifdef DEBUG_grid
michael@0 1277 void
michael@0 1278 nsGrid::PrintCellMap()
michael@0 1279 {
michael@0 1280
michael@0 1281 printf("-----Columns------\n");
michael@0 1282 for (int x=0; x < mColumnCount; x++)
michael@0 1283 {
michael@0 1284
michael@0 1285 nsGridRow* column = GetColumnAt(x);
michael@0 1286 printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax);
michael@0 1287 }
michael@0 1288
michael@0 1289 printf("\n-----Rows------\n");
michael@0 1290 for (x=0; x < mRowCount; x++)
michael@0 1291 {
michael@0 1292 nsGridRow* column = GetRowAt(x);
michael@0 1293 printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax);
michael@0 1294 }
michael@0 1295
michael@0 1296 printf("\n");
michael@0 1297
michael@0 1298 }
michael@0 1299 #endif

mercurial