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