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