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