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