nsTableFrame.h (35636B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 #ifndef nsTableFrame_h__ 6 #define nsTableFrame_h__ 7 8 #include "TableArea.h" 9 #include "celldata.h" 10 #include "nsCellMap.h" 11 #include "nsContainerFrame.h" 12 #include "nsDisplayList.h" 13 #include "nsGkAtoms.h" 14 #include "nsStyleConsts.h" 15 #include "nscore.h" 16 17 struct BCPaintBorderAction; 18 class nsTableCellFrame; 19 class nsTableCellMap; 20 class nsTableColFrame; 21 class nsTableRowGroupFrame; 22 class nsTableRowFrame; 23 class nsTableColGroupFrame; 24 class nsITableLayoutStrategy; 25 26 namespace mozilla { 27 class LogicalMargin; 28 class PresShell; 29 class WritingMode; 30 struct TableBCData; 31 struct TableReflowInput; 32 33 namespace layers { 34 class StackingContextHelper; 35 } 36 37 // An input to nsTableFrame::ReflowTable() and TableReflowInput. 38 enum class TableReflowMode : uint8_t { 39 // A reflow to measure the block-size of the table. We use this value to 40 // request an unconstrained available block in the first reflow if a second 41 // special block-size reflow is needed later. 42 Measuring, 43 44 // A final reflow with the available block-size in the table frame's 45 // ReflowInput. 46 Final, 47 }; 48 49 class nsDisplayTableItem : public nsPaintedDisplayItem { 50 public: 51 nsDisplayTableItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) 52 : nsPaintedDisplayItem(aBuilder, aFrame) {} 53 54 // With collapsed borders, parts of the collapsed border can extend outside 55 // the table part frames, so allow this display element to blow out to our 56 // overflow rect. This is also useful for row frames that have spanning 57 // cells extending outside them. 58 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override; 59 }; 60 61 class nsDisplayTableBackgroundSet { 62 public: 63 nsDisplayList* ColGroupBackgrounds() { return &mColGroupBackgrounds; } 64 65 nsDisplayList* ColBackgrounds() { return &mColBackgrounds; } 66 67 nsDisplayTableBackgroundSet(nsDisplayListBuilder* aBuilder, nsIFrame* aTable); 68 69 ~nsDisplayTableBackgroundSet() { 70 mozilla::DebugOnly<nsDisplayTableBackgroundSet*> result = 71 mBuilder->SetTableBackgroundSet(mPrevTableBackgroundSet); 72 MOZ_ASSERT(result == this); 73 } 74 75 /** 76 * Move all display items in our lists to top of the corresponding lists in 77 * the destination. 78 */ 79 void MoveTo(const nsDisplayListSet& aDestination) { 80 aDestination.BorderBackground()->AppendToTop(ColGroupBackgrounds()); 81 aDestination.BorderBackground()->AppendToTop(ColBackgrounds()); 82 } 83 84 void AddColumn(nsTableColFrame* aFrame) { mColumns.AppendElement(aFrame); } 85 86 nsTableColFrame* GetColForIndex(int32_t aIndex) { return mColumns[aIndex]; } 87 88 const nsPoint& TableToReferenceFrame() { return mToReferenceFrame; } 89 90 const nsRect& GetDirtyRect() { return mDirtyRect; } 91 92 const DisplayItemClipChain* GetTableClipChain() { 93 return mCombinedTableClipChain; 94 } 95 96 const ActiveScrolledRoot* GetTableASR() { return mTableASR; } 97 98 private: 99 // This class is only used on stack, so we don't have to worry about leaking 100 // it. Don't let us be heap-allocated! 101 void* operator new(size_t sz) noexcept(true); 102 103 protected: 104 nsDisplayListBuilder* mBuilder; 105 nsDisplayTableBackgroundSet* mPrevTableBackgroundSet; 106 107 nsDisplayList mColGroupBackgrounds; 108 nsDisplayList mColBackgrounds; 109 110 nsTArray<nsTableColFrame*> mColumns; 111 nsPoint mToReferenceFrame; 112 nsRect mDirtyRect; 113 114 const DisplayItemClipChain* mCombinedTableClipChain; 115 const ActiveScrolledRoot* mTableASR; 116 }; 117 118 } // namespace mozilla 119 120 /* ========================================================================== */ 121 122 enum nsTableColType { 123 eColContent = 0, // there is real col content associated 124 eColAnonymousCol = 1, // the result of a span on a col 125 eColAnonymousColGroup = 2, // the result of a span on a col group 126 eColAnonymousCell = 3 // the result of a cell alone 127 }; 128 129 /** 130 * nsTableFrame maps the inner portion of a table (everything except captions.) 131 * Used as a pseudo-frame within nsTableWrapperFrame, it may also be used 132 * stand-alone as the top-level frame. 133 * 134 * The principal child list contains row group frames. There is also an 135 * additional child list, FrameChildListID::ColGroup, which contains the col 136 * group frames. 137 */ 138 class nsTableFrame : public nsContainerFrame { 139 typedef mozilla::image::ImgDrawResult ImgDrawResult; 140 typedef mozilla::WritingMode WritingMode; 141 typedef mozilla::LogicalMargin LogicalMargin; 142 143 public: 144 NS_DECL_FRAMEARENA_HELPERS(nsTableFrame) 145 146 using TablePartsArray = nsTArray<nsContainerFrame*>; 147 NS_DECLARE_FRAME_PROPERTY_DELETABLE(PositionedTablePartsProperty, 148 TablePartsArray) 149 150 /** nsTableWrapperFrame has intimate knowledge of the inner table frame */ 151 friend class nsTableWrapperFrame; 152 153 /** 154 * instantiate a new instance of nsTableRowFrame. 155 * 156 * @param aPresShell the pres shell for this frame 157 * 158 * @return the frame that was created 159 */ 160 friend nsTableFrame* NS_NewTableFrame(mozilla::PresShell* aPresShell, 161 ComputedStyle* aStyle); 162 163 /** sets defaults for table-specific style. 164 * @see nsIFrame::Init 165 */ 166 void Init(nsIContent* aContent, nsContainerFrame* aParent, 167 nsIFrame* aPrevInFlow) override; 168 169 // Return true if aParentReflowInput.frame or any of its ancestors within 170 // the containing table have non-auto bsize. (e.g. pct or fixed bsize) 171 static bool AncestorsHaveStyleBSize(const ReflowInput& aParentReflowInput); 172 173 // See if a special bsize reflow will occur due to having a pct bsize when 174 // the pct bsize basis may not yet be valid. 175 static void CheckRequestSpecialBSizeReflow(const ReflowInput& aReflowInput); 176 177 // Notify the frame and its ancestors (up to the containing table) that a 178 // special height reflow will occur. 179 static void RequestSpecialBSizeReflow(const ReflowInput& aReflowInput); 180 181 static bool PageBreakAfter(nsIFrame* aSourceFrame, nsIFrame* aNextFrame); 182 183 // Register or deregister a positioned table part with its nsTableFrame. 184 // These objects will be visited by FixupPositionedTableParts after reflow is 185 // complete. (See that function for more explanation.) Should be called 186 // during style recalculation. 187 static void PositionedTablePartMaybeChanged( 188 nsContainerFrame*, mozilla::ComputedStyle* aOldStyle); 189 190 // Unregister a positioned table part with its nsTableFrame, if needed. 191 static void MaybeUnregisterPositionedTablePart(nsContainerFrame* aFrame); 192 193 /* 194 * Notification that rowspan or colspan has changed for content inside a 195 * table cell 196 */ 197 void RowOrColSpanChanged(nsTableCellFrame* aCellFrame); 198 199 /** @see nsIFrame::DestroyFrom */ 200 void Destroy(DestroyContext&) override; 201 202 /** @see nsIFrame::DidSetComputedStyle */ 203 void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override; 204 205 void SetInitialChildList(ChildListID aListID, 206 nsFrameList&& aChildList) override; 207 void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) override; 208 void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, 209 const nsLineList::iterator* aPrevFrameLine, 210 nsFrameList&& aFrameList) override; 211 void RemoveFrame(DestroyContext&, ChildListID, nsIFrame*) override; 212 213 nsMargin GetUsedBorder() const override; 214 nsMargin GetUsedPadding() const override; 215 nsMargin GetUsedMargin() const override; 216 217 /** helper method to find the table parent of any table frame object */ 218 static nsTableFrame* GetTableFrame(nsIFrame* aSourceFrame); 219 220 // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) 221 // of type aChildType. 222 static nsIFrame* GetFrameAtOrBefore(nsIFrame* aParentFrame, 223 nsIFrame* aPriorChildFrame, 224 mozilla::LayoutFrameType aChildType); 225 bool IsAutoBSize(mozilla::WritingMode aWM); 226 227 /** @return true if aDisplayType represents a rowgroup of any sort 228 * (header, footer, or body) 229 */ 230 bool IsRowGroup(mozilla::StyleDisplay aDisplayType) const; 231 232 const nsFrameList& GetChildList(ChildListID aListID) const override; 233 void GetChildLists(nsTArray<ChildList>* aLists) const override; 234 235 void BuildDisplayList(nsDisplayListBuilder* aBuilder, 236 const nsDisplayListSet& aLists) override; 237 238 /** Get the outer half (i.e., the part outside the height and width of 239 * the table) of the largest segment (?) of border-collapsed border on 240 * the table on each side, or 0 for non border-collapsed tables. 241 */ 242 LogicalMargin GetOuterBCBorder(const WritingMode aWM) const; 243 244 /** 245 * Emplace our border and padding in aBorder and aPadding if we are 246 * border-collapsed. Otherwise, do nothing. 247 */ 248 void GetCollapsedBorderPadding( 249 mozilla::Maybe<mozilla::LogicalMargin>& aBorder, 250 mozilla::Maybe<mozilla::LogicalMargin>& aPadding) const; 251 252 friend class nsDelayedCalcBCBorders; 253 254 void AddBCDamageArea(const mozilla::TableArea& aValue); 255 bool BCRecalcNeeded(ComputedStyle* aOldComputedStyle, 256 ComputedStyle* aNewComputedStyle); 257 void PaintBCBorders(DrawTarget& aDrawTarget, const nsRect& aDirtyRect); 258 void CreateWebRenderCommandsForBCBorders( 259 mozilla::wr::DisplayListBuilder& aBuilder, 260 const mozilla::layers::StackingContextHelper& aSc, 261 const nsRect& aVisibleRect, const nsPoint& aOffsetToReferenceFrame); 262 263 void MarkIntrinsicISizesDirty() override; 264 // For border-collapse tables, the caller must not add padding and 265 // border to the results of these functions. 266 nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput, 267 mozilla::IntrinsicISizeType aType) override; 268 IntrinsicSizeOffsetData IntrinsicISizeOffsets( 269 nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) override; 270 271 SizeComputationResult ComputeSize( 272 const SizeComputationInput& aSizingInput, mozilla::WritingMode aWM, 273 const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize, 274 const mozilla::LogicalSize& aMargin, 275 const mozilla::LogicalSize& aBorderPadding, 276 const mozilla::StyleSizeOverrides& aSizeOverrides, 277 mozilla::ComputeSizeFlags aFlags) override; 278 279 mozilla::LogicalSize ComputeAutoSize( 280 const SizeComputationInput& aSizingInput, mozilla::WritingMode aWM, 281 const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize, 282 const mozilla::LogicalSize& aMargin, 283 const mozilla::LogicalSize& aBorderPadding, 284 const mozilla::StyleSizeOverrides& aSizeOverrides, 285 mozilla::ComputeSizeFlags aFlags) override; 286 287 /** 288 * A copy of nsIFrame::ShrinkISizeToFit that calls a different 289 * GetPrefISize, since tables have two different ones. 290 */ 291 nscoord TableShrinkISizeToFit(gfxContext* aRenderingContext, 292 nscoord aWidthInCB); 293 294 // XXXldb REWRITE THIS COMMENT! 295 // clang-format off 296 /** 297 * Inner tables are reflowed in two steps. 298 * <pre> 299 * if mFirstPassValid is false, this is our first time through since content was last changed 300 * set pass to 1 301 * do pass 1 302 * get min/max info for all cells in an infinite space 303 * do column balancing 304 * set mFirstPassValid to true 305 * do pass 2 306 * use column widths to Reflow cells 307 * </pre> 308 * 309 * @see nsIFrame::Reflow 310 */ 311 // clang-format on 312 void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 313 const ReflowInput& aReflowInput, 314 nsReflowStatus& aStatus) override; 315 316 void ReflowTable(ReflowOutput& aDesiredSize, const ReflowInput& aReflowInput, 317 const LogicalMargin& aBorderPadding, 318 mozilla::TableReflowMode aReflowMode, 319 nsIFrame*& aLastChildReflowed, nsReflowStatus& aStatus); 320 321 nsFrameList& GetColGroups(); 322 323 ComputedStyle* GetParentComputedStyle( 324 nsIFrame** aProviderFrame) const override; 325 326 #ifdef DEBUG_FRAME_DUMP 327 /** @see nsIFrame::GetFrameName */ 328 nsresult GetFrameName(nsAString& aResult) const override; 329 #endif 330 331 /** Return the isize of the column at aColIndex. 332 * This may only be called on the table's first-in-flow. 333 */ 334 nscoord GetColumnISizeFromFirstInFlow(int32_t aColIndex); 335 336 /** Helper to get the column spacing style value. 337 * The argument refers to the space between column aColIndex and column 338 * aColIndex + 1. An index of -1 indicates the padding between the table 339 * and the left border, an index equal to the number of columns indicates 340 * the padding between the table and the right border. 341 * 342 * Although in this class cell spacing does not depend on the index, it 343 * may be important for overriding classes. 344 */ 345 virtual nscoord GetColSpacing(int32_t aColIndex); 346 347 /** Helper to find the sum of the cell spacing between arbitrary columns. 348 * The argument refers to the space between column aColIndex and column 349 * aColIndex + 1. An index of -1 indicates the padding between the table 350 * and the left border, an index equal to the number of columns indicates 351 * the padding between the table and the right border. 352 * 353 * This method is equivalent to 354 * nscoord result = 0; 355 * for (i = aStartColIndex; i < aEndColIndex; i++) { 356 * result += GetColSpacing(i); 357 * } 358 * return result; 359 */ 360 virtual nscoord GetColSpacing(int32_t aStartColIndex, int32_t aEndColIndex); 361 362 /** Helper to get the row spacing style value. 363 * The argument refers to the space between row aRowIndex and row 364 * aRowIndex + 1. An index of -1 indicates the padding between the table 365 * and the top border, an index equal to the number of rows indicates 366 * the padding between the table and the bottom border. 367 * 368 * Although in this class cell spacing does not depend on the index, it 369 * may be important for overriding classes. 370 */ 371 virtual nscoord GetRowSpacing(int32_t aRowIndex); 372 373 /** Helper to find the sum of the cell spacing between arbitrary rows. 374 * The argument refers to the space between row aRowIndex and row 375 * aRowIndex + 1. An index of -1 indicates the padding between the table 376 * and the top border, an index equal to the number of rows indicates 377 * the padding between the table and the bottom border. 378 * 379 * This method is equivalent to 380 * nscoord result = 0; 381 * for (i = aStartRowIndex; i < aEndRowIndex; i++) { 382 * result += GetRowSpacing(i); 383 * } 384 * return result; 385 */ 386 virtual nscoord GetRowSpacing(int32_t aStartRowIndex, int32_t aEndRowIndex); 387 388 private: 389 /* For the base implementation of nsTableFrame, cell spacing does not depend 390 * on row/column indexing. 391 */ 392 nscoord GetColSpacing(); 393 nscoord GetRowSpacing(); 394 395 public: 396 nscoord SynthesizeFallbackBaseline( 397 mozilla::WritingMode aWM, 398 BaselineSharingGroup aBaselineGroup) const override; 399 Maybe<nscoord> GetNaturalBaselineBOffset( 400 mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, 401 BaselineExportContext) const override; 402 403 /** return the row span of a cell, taking into account row span magic at the 404 * bottom of a table. The row span equals the number of rows spanned by aCell 405 * starting at aStartRowIndex, and can be smaller if aStartRowIndex is greater 406 * than the row index in which aCell originates. 407 * 408 * @param aStartRowIndex the cell 409 * @param aCell the cell 410 * 411 * @return the row span, correcting for row spans that extend beyond the 412 * bottom of the table. 413 */ 414 int32_t GetEffectiveRowSpan(int32_t aStartRowIndex, 415 const nsTableCellFrame& aCell) const; 416 int32_t GetEffectiveRowSpan(const nsTableCellFrame& aCell, 417 nsCellMap* aCellMap = nullptr); 418 419 /** return the col span of a cell, taking into account col span magic at the 420 * edge of a table. 421 * 422 * @param aCell the cell 423 * 424 * @return the col span, correcting for col spans that extend beyond the edge 425 * of the table. 426 */ 427 int32_t GetEffectiveColSpan(const nsTableCellFrame& aCell, 428 nsCellMap* aCellMap = nullptr) const; 429 430 /** indicate whether the row has more than one cell that either originates 431 * or is spanned from the rows above 432 */ 433 bool HasMoreThanOneCell(int32_t aRowIndex) const; 434 435 /** return the column frame associated with aColIndex 436 * returns nullptr if the col frame has not yet been allocated, or if 437 * aColIndex is out of range 438 */ 439 nsTableColFrame* GetColFrame(int32_t aColIndex) const; 440 441 /** Insert a col frame reference into the colframe cache and adapt the cellmap 442 * @param aColFrame - the column frame 443 * @param aColIndex - index where the column should be inserted into the 444 * colframe cache 445 */ 446 void InsertCol(nsTableColFrame& aColFrame, int32_t aColIndex); 447 448 nsTableColGroupFrame* CreateSyntheticColGroupFrame(); 449 450 int32_t DestroyAnonymousColFrames(int32_t aNumFrames); 451 452 // Append aNumColsToAdd anonymous col frames of type eColAnonymousCell to our 453 // last synthetic colgroup. If we have no such colgroup, then create one. 454 void AppendAnonymousColFrames(int32_t aNumColsToAdd); 455 456 // Append aNumColsToAdd anonymous col frames of type aColType to 457 // aColGroupFrame. If aAddToTable is true, also call AddColsToTable on the 458 // new cols. 459 void AppendAnonymousColFrames(nsTableColGroupFrame* aColGroupFrame, 460 int32_t aNumColsToAdd, nsTableColType aColType, 461 bool aAddToTable); 462 463 void MatchCellMapToColCache(nsTableCellMap* aCellMap); 464 465 void DidResizeColumns(); 466 467 void AppendCell(nsTableCellFrame& aCellFrame, int32_t aRowIndex); 468 469 void InsertCells(nsTArray<nsTableCellFrame*>& aCellFrames, int32_t aRowIndex, 470 int32_t aColIndexBefore); 471 472 void RemoveCell(nsTableCellFrame* aCellFrame, int32_t aRowIndex); 473 474 void AppendRows(nsTableRowGroupFrame* aRowGroupFrame, int32_t aRowIndex, 475 nsTArray<nsTableRowFrame*>& aRowFrames); 476 477 int32_t InsertRows(nsTableRowGroupFrame* aRowGroupFrame, 478 nsTArray<nsTableRowFrame*>& aFrames, int32_t aRowIndex, 479 bool aConsiderSpans); 480 481 void RemoveRows(nsTableRowFrame& aFirstRowFrame, int32_t aNumRowsToRemove, 482 bool aConsiderSpans); 483 484 /** Insert multiple rowgroups into the table cellmap handling 485 * @param aRowGroups - iterator that iterates over the rowgroups to insert 486 */ 487 void InsertRowGroups(const nsFrameList::Slice& aRowGroups); 488 489 void InsertColGroups(int32_t aStartColIndex, 490 const nsFrameList::Slice& aColgroups); 491 492 void RemoveCol(nsTableColGroupFrame* aColGroupFrame, int32_t aColIndex, 493 bool aRemoveFromCache, bool aRemoveFromCellMap); 494 495 bool ColumnHasCellSpacingBefore(int32_t aColIndex) const; 496 497 bool HasPctCol() const; 498 void SetHasPctCol(bool aValue); 499 500 bool HasCellSpanningPctCol() const; 501 void SetHasCellSpanningPctCol(bool aValue); 502 503 /** 504 * To be called on a frame by its parent after setting its size/position and 505 * calling DidReflow (possibly via FinishReflowChild()). This can also be 506 * used for child frames which are not being reflowed but did have their size 507 * or position changed. 508 * 509 * @param aFrame The frame to invalidate 510 * @param aOrigRect The original rect of aFrame (before the change). 511 * @param aOrigInkOverflow The original overflow rect of aFrame. 512 * @param aIsFirstReflow True if the size/position change is due to the 513 * first reflow of aFrame. 514 */ 515 static void InvalidateTableFrame(nsIFrame* aFrame, const nsRect& aOrigRect, 516 const nsRect& aOrigInkOverflow, 517 bool aIsFirstReflow); 518 519 bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas) override; 520 521 // Return our wrapper frame. 522 void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override; 523 524 protected: 525 static void UpdateStyleOfOwnedAnonBoxesForTableWrapper( 526 nsIFrame* aOwningFrame, nsIFrame* aWrapperFrame, 527 mozilla::ServoRestyleState& aRestyleState); 528 529 /** protected constructor. 530 * @see NewFrame 531 */ 532 explicit nsTableFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, 533 ClassID aID = kClassID); 534 535 virtual ~nsTableFrame(); 536 537 void InitChildReflowInput(ReflowInput& aReflowInput); 538 539 LogicalSides GetLogicalSkipSides() const override; 540 541 void IterateBCBorders(BCPaintBorderAction& aAction, const nsRect& aDirtyRect); 542 543 public: 544 bool IsRowInserted() const; 545 void SetRowInserted(bool aValue); 546 547 protected: 548 // A helper function to reflow a header or footer with unconstrained 549 // block-size to see if it should be made repeatable. 550 // @return the desired block-size for a header or footer. 551 nscoord SetupHeaderFooterChild(const mozilla::TableReflowInput& aReflowInput, 552 nsTableRowGroupFrame* aFrame); 553 554 void ReflowChildren(mozilla::TableReflowInput& aReflowInput, 555 nsReflowStatus& aStatus, nsIFrame*& aLastChildReflowed, 556 mozilla::OverflowAreas& aOverflowAreas); 557 558 // This calls the col group and column reflow methods, which do two things: 559 // (1) set all the dimensions to 0 560 // (2) notify the table about colgroups or columns with hidden visibility 561 void ReflowColGroups(gfxContext* aRenderingContext); 562 563 /** return the isize of the table taking into account visibility collapse 564 * on columns and colgroups 565 * @param aBorderPadding the border and padding of the table 566 */ 567 nscoord GetCollapsedISize(const WritingMode aWM, 568 const LogicalMargin& aBorderPadding); 569 570 /** Adjust the table for visibility.collapse set on rowgroups, rows, 571 * colgroups and cols 572 * @param aDesiredSize the metrics of the table 573 * @param aBorderPadding the border and padding of the table 574 */ 575 void AdjustForCollapsingRowsCols(ReflowOutput& aDesiredSize, 576 const WritingMode aWM, 577 const LogicalMargin& aBorderPadding); 578 579 /** FixupPositionedTableParts is called at the end of table reflow to reflow 580 * the absolutely positioned descendants of positioned table parts. This is 581 * necessary because the dimensions of table parts may change after they've 582 * been reflowed (e.g. in AdjustForCollapsingRowsCols). 583 */ 584 void FixupPositionedTableParts(nsPresContext* aPresContext, 585 ReflowOutput& aDesiredSize, 586 const ReflowInput& aReflowInput); 587 588 nsITableLayoutStrategy* LayoutStrategy() const { 589 return static_cast<nsTableFrame*>(FirstInFlow()) 590 ->mTableLayoutStrategy.get(); 591 } 592 593 // Helper for InsertFrames. 594 void HomogenousInsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, 595 nsFrameList& aFrameList); 596 597 private: 598 /* Handle a row that got inserted during reflow. aNewHeight is the 599 new height of the table after reflow. */ 600 void ProcessRowInserted(nscoord aNewHeight); 601 602 protected: 603 // Calculate the border-box block-size of this table, with the min-block-size, 604 // max-block-size, and intrinsic border-box block considered. 605 nscoord CalcBorderBoxBSize(const ReflowInput& aReflowInput, 606 const LogicalMargin& aBorderPadding, 607 nscoord aIntrinsicBorderBoxBSize); 608 609 // Calculate the desired block-size of this table. 610 // 611 // Note: this method is accurate after the children are reflowed. It might 612 // distribute extra block-size to table rows if the table has a specified 613 // block-size larger than the intrinsic block-size. 614 nscoord CalcDesiredBSize(const ReflowInput& aReflowInput, 615 const LogicalMargin& aBorderPadding, 616 const nsReflowStatus& aStatus); 617 618 // The following is a helper for CalcDesiredBSize 619 void DistributeBSizeToRows(const ReflowInput& aReflowInput, nscoord aAmount); 620 621 void PlaceChild(mozilla::TableReflowInput& aReflowInput, nsIFrame* aKidFrame, 622 const ReflowInput& aKidReflowInput, 623 const mozilla::LogicalPoint& aKidPosition, 624 const nsSize& aContainerSize, ReflowOutput& aKidDesiredSize, 625 const nsRect& aOriginalKidRect, 626 const nsRect& aOriginalKidInkOverflow); 627 void PlaceRepeatedFooter(mozilla::TableReflowInput& aReflowInput, 628 nsTableRowGroupFrame* aTfoot, nscoord aFooterBSize); 629 630 public: 631 using RowGroupArray = AutoTArray<nsTableRowGroupFrame*, 8>; 632 633 protected: 634 // Push all our non-repeatable child frames from the aRowGroups array, in 635 // order, starting from the frame at aPushFrom to the end of the array. The 636 // pushed frames are put on our overflow list. This is a table specific 637 // version that takes into account repeated header and footer frames when 638 // continuing table frames. 639 void PushChildrenToOverflow(const RowGroupArray& aRowGroups, 640 size_t aPushFrom); 641 642 public: 643 // Return the children frames in the display order (e.g. thead before tbodies 644 // before tfoot). If there are multiple theads or tfoots, all but the first 645 // one are treated as tbodies instead. 646 // 647 // @param aHead Outparam for the first thead if there is any. 648 // @param aFoot Outparam for the first tfoot if there is any. 649 RowGroupArray OrderedRowGroups(nsTableRowGroupFrame** aHead = nullptr, 650 nsTableRowGroupFrame** aFoot = nullptr) const; 651 652 // Returns true if there are any cells above the row at 653 // aRowIndex and spanning into the row at aRowIndex, the number of 654 // effective columns limits the search up to that column 655 bool RowIsSpannedInto(int32_t aRowIndex, int32_t aNumEffCols); 656 657 // Returns true if there is a cell originating in aRowIndex 658 // which spans into the next row, the number of effective 659 // columns limits the search up to that column 660 bool RowHasSpanningCells(int32_t aRowIndex, int32_t aNumEffCols); 661 662 protected: 663 bool HaveReflowedColGroups() const; 664 void SetHaveReflowedColGroups(bool aValue); 665 666 public: 667 bool IsBorderCollapse() const; 668 669 bool NeedToCalcBCBorders() const; 670 void SetNeedToCalcBCBorders(bool aValue); 671 672 bool NeedToCollapse() const; 673 void SetNeedToCollapse(bool aValue); 674 675 bool NeedToCalcHasBCBorders() const; 676 void SetNeedToCalcHasBCBorders(bool aValue); 677 678 void CalcHasBCBorders(); 679 bool HasBCBorders(); 680 void SetHasBCBorders(bool aValue); 681 682 /** The GeometryDirty bit is similar to the NS_FRAME_IS_DIRTY frame 683 * state bit, which implies that all descendants are dirty. The 684 * GeometryDirty still implies that all the parts of the table are 685 * dirty, but resizing optimizations should still apply to the 686 * contents of the individual cells. 687 */ 688 void SetGeometryDirty() { mBits.mGeometryDirty = true; } 689 void ClearGeometryDirty() { mBits.mGeometryDirty = false; } 690 bool IsGeometryDirty() const { return mBits.mGeometryDirty; } 691 692 /** Get the cell map for this table frame. It is not always mCellMap. 693 * Only the firstInFlow has a legit cell map 694 */ 695 nsTableCellMap* GetCellMap() const; 696 697 /** Iterate over the row groups and adjust the row indices of all rows 698 * whose index is >= aRowIndex. 699 * @param aRowIndex - start adjusting with this index 700 * @param aAdjustment - shift the row index by this amount 701 */ 702 void AdjustRowIndices(int32_t aRowIndex, int32_t aAdjustment); 703 704 /** Reset the rowindices of all rows as they might have changed due to 705 * rowgroup reordering, exclude new row group frames that show in the 706 * reordering but are not yet inserted into the cellmap 707 * @param aRowGroupsToExclude - an iterator that will produce the row groups 708 * to exclude. 709 */ 710 void ResetRowIndices(const nsFrameList::Slice& aRowGroupsToExclude); 711 712 nsTArray<nsTableColFrame*>& GetColCache(); 713 714 mozilla::TableBCData* GetTableBCData() const; 715 716 protected: 717 void SetBorderCollapse(bool aValue); 718 719 mozilla::TableBCData* GetOrCreateTableBCData(); 720 void SetFullBCDamageArea(); 721 void CalcBCBorders(); 722 723 void ExpandBCDamageArea(mozilla::TableArea& aRect) const; 724 725 void SetColumnDimensions(nscoord aHeight, WritingMode aWM, 726 const LogicalMargin& aBorderPadding, 727 const nsSize& aContainerSize); 728 729 int32_t CollectRows(nsIFrame* aFrame, 730 nsTArray<nsTableRowFrame*>& aCollection); 731 732 public: /* ----- Cell Map public methods ----- */ 733 int32_t GetStartRowIndex(const nsTableRowGroupFrame* aRowGroupFrame) const; 734 735 /** returns the number of rows in this table. 736 */ 737 int32_t GetRowCount() const { return GetCellMap()->GetRowCount(); } 738 739 /** returns the number of columns in this table after redundant columns have 740 * been removed 741 */ 742 int32_t GetEffectiveColCount() const; 743 744 /* return the col count including dead cols */ 745 int32_t GetColCount() const { return GetCellMap()->GetColCount(); } 746 747 // return the last col index which isn't of type eColAnonymousCell 748 int32_t GetIndexOfLastRealCol(); 749 750 /** returns true if table-layout:auto */ 751 bool IsAutoLayout(); 752 753 public: 754 /* ---------- Row index management methods ------------ */ 755 756 /** Add the given index to the existing ranges of 757 * deleted row indices and merge ranges if, with the addition of the new 758 * index, they become consecutive. 759 * @param aDeletedRowStoredIndex - index of the row that was deleted 760 * Note - 'stored' index here refers to the index that was assigned to 761 * the row before any remove row operations were performed i.e. the 762 * value of mRowIndex and not the value returned by GetRowIndex() 763 */ 764 void AddDeletedRowIndex(int32_t aDeletedRowStoredIndex); 765 766 /** Calculate the change that aStoredIndex must be increased/decreased by 767 * to get new index. 768 * Note that aStoredIndex is always the index of an undeleted row (since 769 * rows that have already been deleted can never call this method). 770 * @param aStoredIndex - The stored index value that must be adjusted 771 * Note - 'stored' index here refers to the index that was assigned to 772 * the row before any remove row operations were performed i.e. the 773 * value of mRowIndex and not the value returned by GetRowIndex() 774 */ 775 int32_t GetAdjustmentForStoredIndex(int32_t aStoredIndex); 776 777 /** Returns whether mDeletedRowIndexRanges is empty 778 */ 779 bool IsDeletedRowIndexRangesEmpty() const { 780 return mDeletedRowIndexRanges.empty(); 781 } 782 783 bool IsDestroying() const { return mBits.mIsDestroying; } 784 785 public: 786 #ifdef DEBUG 787 void Dump(bool aDumpRows, bool aDumpCols, bool aDumpCellMap); 788 #endif 789 790 protected: 791 /** 792 * Helper method for RemoveFrame. 793 */ 794 void DoRemoveFrame(DestroyContext&, ChildListID, nsIFrame*); 795 #ifdef DEBUG 796 void DumpRowGroup(nsIFrame* aChildFrame); 797 #endif 798 // DATA MEMBERS 799 AutoTArray<nsTableColFrame*, 8> mColFrames; 800 801 struct TableBits { 802 uint32_t mHaveReflowedColGroups : 1; // have the col groups gotten their 803 // initial reflow 804 uint32_t mHasPctCol : 1; // does any cell or col have a pct width 805 uint32_t mCellSpansPctCol : 1; // does any cell span a col with a pct width 806 // (or containing a cell with a pct width) 807 uint32_t mIsBorderCollapse : 1; // border collapsing model vs. separate 808 // model 809 uint32_t mRowInserted : 1; 810 uint32_t mNeedToCalcBCBorders : 1; 811 uint32_t mGeometryDirty : 1; 812 uint32_t mNeedToCollapse : 1; // rows, cols that have visibility:collapse 813 // need to be collapsed 814 uint32_t mResizedColumns : 1; // have we resized columns since last reflow? 815 uint32_t mNeedToCalcHasBCBorders : 1; 816 uint32_t mHasBCBorders : 1; 817 uint32_t mIsDestroying : 1; // Whether we're in the process of destroying 818 // this table frame. 819 } mBits; 820 821 std::map<int32_t, int32_t> mDeletedRowIndexRanges; // maintains ranges of row 822 // indices of deleted rows 823 mozilla::UniquePtr<nsTableCellMap> mCellMap; // maintains the relationships 824 // between rows, cols, and cells 825 // the layout strategy for this frame 826 mozilla::UniquePtr<nsITableLayoutStrategy> mTableLayoutStrategy; 827 nsFrameList mColGroups; // the list of colgroup frames 828 }; 829 830 inline bool nsTableFrame::IsRowGroup(mozilla::StyleDisplay aDisplayType) const { 831 return mozilla::StyleDisplay::TableHeaderGroup == aDisplayType || 832 mozilla::StyleDisplay::TableFooterGroup == aDisplayType || 833 mozilla::StyleDisplay::TableRowGroup == aDisplayType; 834 } 835 836 inline void nsTableFrame::SetHaveReflowedColGroups(bool aValue) { 837 mBits.mHaveReflowedColGroups = aValue; 838 } 839 840 inline bool nsTableFrame::HaveReflowedColGroups() const { 841 return (bool)mBits.mHaveReflowedColGroups; 842 } 843 844 inline bool nsTableFrame::HasPctCol() const { return (bool)mBits.mHasPctCol; } 845 846 inline void nsTableFrame::SetHasPctCol(bool aValue) { 847 mBits.mHasPctCol = (unsigned)aValue; 848 } 849 850 inline bool nsTableFrame::HasCellSpanningPctCol() const { 851 return (bool)mBits.mCellSpansPctCol; 852 } 853 854 inline void nsTableFrame::SetHasCellSpanningPctCol(bool aValue) { 855 mBits.mCellSpansPctCol = (unsigned)aValue; 856 } 857 858 inline bool nsTableFrame::IsRowInserted() const { 859 return (bool)mBits.mRowInserted; 860 } 861 862 inline void nsTableFrame::SetRowInserted(bool aValue) { 863 mBits.mRowInserted = (unsigned)aValue; 864 } 865 866 inline void nsTableFrame::SetNeedToCollapse(bool aValue) { 867 static_cast<nsTableFrame*>(FirstInFlow())->mBits.mNeedToCollapse = 868 (unsigned)aValue; 869 } 870 871 inline bool nsTableFrame::NeedToCollapse() const { 872 return (bool)static_cast<nsTableFrame*>(FirstInFlow())->mBits.mNeedToCollapse; 873 } 874 875 inline nsFrameList& nsTableFrame::GetColGroups() { 876 return static_cast<nsTableFrame*>(FirstInFlow())->mColGroups; 877 } 878 879 inline nsTArray<nsTableColFrame*>& nsTableFrame::GetColCache() { 880 return mColFrames; 881 } 882 883 inline bool nsTableFrame::IsBorderCollapse() const { 884 return (bool)mBits.mIsBorderCollapse; 885 } 886 887 inline void nsTableFrame::SetBorderCollapse(bool aValue) { 888 mBits.mIsBorderCollapse = aValue; 889 } 890 891 inline bool nsTableFrame::NeedToCalcBCBorders() const { 892 return (bool)mBits.mNeedToCalcBCBorders; 893 } 894 895 inline void nsTableFrame::SetNeedToCalcBCBorders(bool aValue) { 896 mBits.mNeedToCalcBCBorders = (unsigned)aValue; 897 } 898 899 inline bool nsTableFrame::NeedToCalcHasBCBorders() const { 900 return (bool)mBits.mNeedToCalcHasBCBorders; 901 } 902 903 inline void nsTableFrame::SetNeedToCalcHasBCBorders(bool aValue) { 904 mBits.mNeedToCalcHasBCBorders = (unsigned)aValue; 905 } 906 907 inline bool nsTableFrame::HasBCBorders() { 908 if (NeedToCalcHasBCBorders()) { 909 CalcHasBCBorders(); 910 SetNeedToCalcHasBCBorders(false); 911 } 912 return (bool)mBits.mHasBCBorders; 913 } 914 915 inline void nsTableFrame::SetHasBCBorders(bool aValue) { 916 mBits.mHasBCBorders = (unsigned)aValue; 917 } 918 919 #define ABORT0() \ 920 { \ 921 NS_ASSERTION(false, "CellIterator program error"); \ 922 return; \ 923 } 924 925 #define ABORT1(aReturn) \ 926 { \ 927 NS_ASSERTION(false, "CellIterator program error"); \ 928 return aReturn; \ 929 } 930 931 #endif