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