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 nsTableRowFrame_h__
6 #define nsTableRowFrame_h__
7 
8 #include "mozilla/Attributes.h"
9 #include "nscore.h"
10 #include "nsContainerFrame.h"
11 #include "nsTablePainter.h"
12 #include "nsTableRowGroupFrame.h"
13 #include "mozilla/WritingModes.h"
14 
15 class  nsTableCellFrame;
16 namespace mozilla {
17 struct TableCellReflowInput;
18 } // namespace mozilla
19 
20 /**
21  * nsTableRowFrame is the frame that maps table rows
22  * (HTML tag TR). This class cannot be reused
23  * outside of an nsTableRowGroupFrame.  It assumes that its parent is an nsTableRowGroupFrame,
24  * and its children are nsTableCellFrames.
25  *
26  * @see nsTableFrame
27  * @see nsTableRowGroupFrame
28  * @see nsTableCellFrame
29  */
30 class nsTableRowFrame : public nsContainerFrame
31 {
32   using TableCellReflowInput = mozilla::TableCellReflowInput;
33 
34 public:
35   NS_DECL_QUERYFRAME_TARGET(nsTableRowFrame)
36   NS_DECL_QUERYFRAME
37   NS_DECL_FRAMEARENA_HELPERS
38 
39   virtual ~nsTableRowFrame();
40 
41   virtual void Init(nsIContent*       aContent,
42                     nsContainerFrame* aParent,
43                     nsIFrame*         aPrevInFlow) override;
44 
45   virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
46 
47   /** @see nsIFrame::DidSetStyleContext */
48   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
49 
50   virtual void AppendFrames(ChildListID     aListID,
51                             nsFrameList&    aFrameList) override;
52   virtual void InsertFrames(ChildListID     aListID,
53                             nsIFrame*       aPrevFrame,
54                             nsFrameList&    aFrameList) override;
55   virtual void RemoveFrame(ChildListID     aListID,
56                            nsIFrame*       aOldFrame) override;
57 
58   /** instantiate a new instance of nsTableRowFrame.
59     * @param aPresShell the pres shell for this frame
60     *
61     * @return           the frame that was created
62     */
63   friend nsTableRowFrame* NS_NewTableRowFrame(nsIPresShell* aPresShell,
64                                               nsStyleContext* aContext);
65 
GetTableRowGroupFrame()66   nsTableRowGroupFrame* GetTableRowGroupFrame() const
67   {
68     nsIFrame* parent = GetParent();
69     MOZ_ASSERT(parent && parent->GetType() == nsGkAtoms::tableRowGroupFrame);
70     return static_cast<nsTableRowGroupFrame*>(parent);
71   }
72 
GetTableFrame()73   nsTableFrame* GetTableFrame() const
74   {
75     return GetTableRowGroupFrame()->GetTableFrame();
76   }
77 
78   virtual nsMargin GetUsedMargin() const override;
79   virtual nsMargin GetUsedBorder() const override;
80   virtual nsMargin GetUsedPadding() const override;
81 
82   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
83                                 const nsRect&           aDirtyRect,
84                                 const nsDisplayListSet& aLists) override;
85 
86   nsTableCellFrame* GetFirstCell() ;
87 
88   /** calls Reflow for all of its child cells.
89     * Cells with rowspan=1 are all set to the same height and stacked horizontally.
90     * <P> Cells are not split unless absolutely necessary.
91     * <P> Cells are resized in nsTableFrame::BalanceColumnWidths
92     * and nsTableFrame::ShrinkWrapChildren
93     *
94     * @param aDesiredSize width set to width of the sum of the cells, height set to
95     *                     height of cells with rowspan=1.
96     *
97     * @see nsIFrame::Reflow
98     * @see nsTableFrame::BalanceColumnWidths
99     * @see nsTableFrame::ShrinkWrapChildren
100     */
101   virtual void Reflow(nsPresContext*           aPresContext,
102                       ReflowOutput&     aDesiredSize,
103                       const ReflowInput& aReflowInput,
104                       nsReflowStatus&          aStatus) override;
105 
106   void DidResize();
107 
108   /**
109    * Get the "type" of the frame
110    *
111    * @see nsGkAtoms::tableRowFrame
112    */
113   virtual nsIAtom* GetType() const override;
114 
115 #ifdef DEBUG_FRAME_DUMP
116   virtual nsresult GetFrameName(nsAString& aResult) const override;
117 #endif
118 
GetWritingMode()119   virtual mozilla::WritingMode GetWritingMode() const override
120     { return GetTableFrame()->GetWritingMode(); }
121 
122   void UpdateBSize(nscoord           aBSize,
123                    nscoord           aAscent,
124                    nscoord           aDescent,
125                    nsTableFrame*     aTableFrame = nullptr,
126                    nsTableCellFrame* aCellFrame  = nullptr);
127 
128   void ResetBSize(nscoord aRowStyleBSize);
129 
130   // calculate the bsize, considering content bsize of the
131   // cells and the style bsize of the row and cells, excluding pct bsizes
132   nscoord CalcBSize(const ReflowInput& aReflowInput);
133 
134   // Support for cells with 'vertical-align: baseline'.
135 
136   /**
137    * returns the max-ascent amongst all the cells that have
138    * 'vertical-align: baseline', *including* cells with rowspans.
139    * returns 0 if we don't have any cell with 'vertical-align: baseline'
140    */
141   nscoord GetMaxCellAscent() const;
142 
143   /* return the row ascent
144    */
145   nscoord GetRowBaseline(mozilla::WritingMode aWritingMode);
146 
147   /** returns the ordinal position of this row in its table */
148   virtual int32_t GetRowIndex() const;
149 
150   /** set this row's starting row index */
151   void SetRowIndex (int aRowIndex);
152 
153   /** used by row group frame code */
154   nscoord ReflowCellFrame(nsPresContext*           aPresContext,
155                           const ReflowInput& aReflowInput,
156                           bool                     aIsTopOfPage,
157                           nsTableCellFrame*        aCellFrame,
158                           nscoord                  aAvailableBSize,
159                           nsReflowStatus&          aStatus);
160   /**
161     * Collapse the row if required, apply col and colgroup visibility: collapse
162     * info to the cells in the row.
163     * @return the amount to shift bstart-wards all following rows
164     * @param aRowOffset     - shift the row bstart-wards by this amount
165     * @param aISize         - new isize of the row
166     * @param aCollapseGroup - parent rowgroup is collapsed so this row needs
167     *                         to be collapsed
168     * @param aDidCollapse   - the row has been collapsed
169     */
170   nscoord CollapseRowIfNecessary(nscoord aRowOffset,
171                                  nscoord aISize,
172                                  bool    aCollapseGroup,
173                                  bool&   aDidCollapse);
174 
175   /**
176    * Insert a cell frame after the last cell frame that has a col index
177    * that is less than aColIndex.  If no such cell frame is found the
178    * frame to insert is prepended to the child list.
179    * @param aFrame the cell frame to insert
180    * @param aColIndex the col index
181    */
182   void InsertCellFrame(nsTableCellFrame* aFrame,
183                        int32_t           aColIndex);
184 
185   nsresult CalculateCellActualBSize(nsTableCellFrame*    aCellFrame,
186                                     nscoord&             aDesiredBSize,
187                                     mozilla::WritingMode aWM);
188 
189   bool IsFirstInserted() const;
190   void   SetFirstInserted(bool aValue);
191 
192   nscoord GetContentBSize() const;
193   void    SetContentBSize(nscoord aTwipValue);
194 
195   bool HasStyleBSize() const;
196 
197   bool HasFixedBSize() const;
198   void   SetHasFixedBSize(bool aValue);
199 
200   bool HasPctBSize() const;
201   void   SetHasPctBSize(bool aValue);
202 
203   nscoord GetFixedBSize() const;
204   void    SetFixedBSize(nscoord aValue);
205 
206   float   GetPctBSize() const;
207   void    SetPctBSize(float  aPctValue,
208                        bool aForce = false);
209 
210   nscoord GetInitialBSize(nscoord aBasis = 0) const;
211 
212   nsTableRowFrame* GetNextRow() const;
213 
214   bool    HasUnpaginatedBSize();
215   void    SetHasUnpaginatedBSize(bool aValue);
216   nscoord GetUnpaginatedBSize();
217   void    SetUnpaginatedBSize(nsPresContext* aPresContext, nscoord aValue);
218 
GetBStartBCBorderWidth()219   nscoord GetBStartBCBorderWidth() const { return mBStartBorderWidth; }
GetBEndBCBorderWidth()220   nscoord GetBEndBCBorderWidth() const { return mBEndBorderWidth; }
SetBStartBCBorderWidth(BCPixelSize aWidth)221   void SetBStartBCBorderWidth(BCPixelSize aWidth) { mBStartBorderWidth = aWidth; }
SetBEndBCBorderWidth(BCPixelSize aWidth)222   void SetBEndBCBorderWidth(BCPixelSize aWidth) { mBEndBorderWidth = aWidth; }
223   mozilla::LogicalMargin GetBCBorderWidth(mozilla::WritingMode aWM);
224 
225   /**
226    * Gets inner border widths before collapsing with cell borders
227    * Caller must get block-end border from next row or from table
228    * GetContinuousBCBorderWidth will not overwrite that border
229    * see nsTablePainter about continuous borders
230    */
231   void GetContinuousBCBorderWidth(mozilla::WritingMode aWM,
232                                   mozilla::LogicalMargin& aBorder);
233 
234   /**
235    * @returns outer block-start bc border == prev row's block-end inner
236    */
237   nscoord GetOuterBStartContBCBorderWidth();
238   /**
239    * Sets full border widths before collapsing with cell borders
240    * @param aForSide - side to set; only accepts iend, istart, and bstart
241    */
242   void SetContinuousBCBorderWidth(mozilla::LogicalSide aForSide,
243                                   BCPixelSize aPixelValue);
244 
IsFrameOfType(uint32_t aFlags)245   virtual bool IsFrameOfType(uint32_t aFlags) const override
246   {
247     return nsContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eTablePart));
248   }
249 
250   virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) override;
251   virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) override;
InvalidateFrameForRemoval()252   virtual void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); }
253 
254 #ifdef ACCESSIBILITY
255   virtual mozilla::a11y::AccType AccessibleType() override;
256 #endif
257 
258 protected:
259 
260   /** protected constructor.
261     * @see NewFrame
262     */
263   explicit nsTableRowFrame(nsStyleContext *aContext);
264 
265   void InitChildReflowInput(nsPresContext&              aPresContext,
266                             const mozilla::LogicalSize& aAvailSize,
267                             bool                        aBorderCollapse,
268                             TableCellReflowInput&     aReflowInput);
269 
270   virtual LogicalSides GetLogicalSkipSides(const ReflowInput* aReflowInput = nullptr) const override;
271 
272   // row-specific methods
273 
274   nscoord ComputeCellXOffset(const ReflowInput& aState,
275                              nsIFrame*                aKidFrame,
276                              const nsMargin&          aKidMargin) const;
277   /**
278    * Called for incremental/dirty and resize reflows. If aDirtyOnly is true then
279    * only reflow dirty cells.
280    */
281   void ReflowChildren(nsPresContext*           aPresContext,
282                       ReflowOutput&     aDesiredSize,
283                       const ReflowInput& aReflowInput,
284                       nsTableFrame&            aTableFrame,
285                       nsReflowStatus&          aStatus);
286 
287 private:
288   struct RowBits {
289     unsigned mRowIndex:29;
290     unsigned mHasFixedBSize:1; // set if the dominating style bsize on the row or any cell is pixel based
291     unsigned mHasPctBSize:1;   // set if the dominating style bsize on the row or any cell is pct based
292     unsigned mFirstInserted:1; // if true, then it was the bstart-most newly inserted row
293   } mBits;
294 
295   // the desired bsize based on the content of the tallest cell in the row
296   nscoord mContentBSize;
297   // the bsize based on a style percentage bsize on either the row or any cell
298   // if mHasPctBSize is set
299   nscoord mStylePctBSize;
300   // the bsize based on a style pixel bsize on the row or any
301   // cell if mHasFixedBSize is set
302   nscoord mStyleFixedBSize;
303 
304   // max-ascent and max-descent amongst all cells that have 'vertical-align: baseline'
305   nscoord mMaxCellAscent;  // does include cells with rowspan > 1
306   nscoord mMaxCellDescent; // does *not* include cells with rowspan > 1
307 
308   // border widths in pixels in the collapsing border model of the *inner*
309   // half of the border only
310   BCPixelSize mBStartBorderWidth;
311   BCPixelSize mBEndBorderWidth;
312   BCPixelSize mIEndContBorderWidth;
313   BCPixelSize mBStartContBorderWidth;
314   BCPixelSize mIStartContBorderWidth;
315 
316   /**
317    * Sets the NS_ROW_HAS_CELL_WITH_STYLE_BSIZE bit to indicate whether
318    * this row has any cells that have non-auto-bsize.  (Row-spanning
319    * cells are ignored.)
320    */
321   void InitHasCellWithStyleBSize(nsTableFrame* aTableFrame);
322 
323 };
324 
GetRowIndex()325 inline int32_t nsTableRowFrame::GetRowIndex() const
326 {
327   return int32_t(mBits.mRowIndex);
328 }
329 
SetRowIndex(int aRowIndex)330 inline void nsTableRowFrame::SetRowIndex (int aRowIndex)
331 {
332   mBits.mRowIndex = aRowIndex;
333 }
334 
IsFirstInserted()335 inline bool nsTableRowFrame::IsFirstInserted() const
336 {
337   return bool(mBits.mFirstInserted);
338 }
339 
SetFirstInserted(bool aValue)340 inline void nsTableRowFrame::SetFirstInserted(bool aValue)
341 {
342   mBits.mFirstInserted = aValue;
343 }
344 
HasStyleBSize()345 inline bool nsTableRowFrame::HasStyleBSize() const
346 {
347   return (bool)mBits.mHasFixedBSize || (bool)mBits.mHasPctBSize;
348 }
349 
HasFixedBSize()350 inline bool nsTableRowFrame::HasFixedBSize() const
351 {
352   return (bool)mBits.mHasFixedBSize;
353 }
354 
SetHasFixedBSize(bool aValue)355 inline void nsTableRowFrame::SetHasFixedBSize(bool aValue)
356 {
357   mBits.mHasFixedBSize = aValue;
358 }
359 
HasPctBSize()360 inline bool nsTableRowFrame::HasPctBSize() const
361 {
362   return (bool)mBits.mHasPctBSize;
363 }
364 
SetHasPctBSize(bool aValue)365 inline void nsTableRowFrame::SetHasPctBSize(bool aValue)
366 {
367   mBits.mHasPctBSize = aValue;
368 }
369 
GetContentBSize()370 inline nscoord nsTableRowFrame::GetContentBSize() const
371 {
372   return mContentBSize;
373 }
374 
SetContentBSize(nscoord aValue)375 inline void nsTableRowFrame::SetContentBSize(nscoord aValue)
376 {
377   mContentBSize = aValue;
378 }
379 
GetFixedBSize()380 inline nscoord nsTableRowFrame::GetFixedBSize() const
381 {
382   if (mBits.mHasFixedBSize) {
383     return mStyleFixedBSize;
384   }
385   return 0;
386 }
387 
GetPctBSize()388 inline float nsTableRowFrame::GetPctBSize() const
389 {
390   if (mBits.mHasPctBSize) {
391     return (float)mStylePctBSize / 100.0f;
392   }
393   return 0.0f;
394 }
395 
HasUnpaginatedBSize()396 inline bool nsTableRowFrame::HasUnpaginatedBSize()
397 {
398   return HasAnyStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE);
399 }
400 
SetHasUnpaginatedBSize(bool aValue)401 inline void nsTableRowFrame::SetHasUnpaginatedBSize(bool aValue)
402 {
403   if (aValue) {
404     AddStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE);
405   } else {
406     RemoveStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE);
407   }
408 }
409 
410 inline mozilla::LogicalMargin
GetBCBorderWidth(mozilla::WritingMode aWM)411 nsTableRowFrame::GetBCBorderWidth(mozilla::WritingMode aWM)
412 {
413   return mozilla::LogicalMargin(
414     aWM, nsPresContext::CSSPixelsToAppUnits(mBStartBorderWidth), 0,
415     nsPresContext::CSSPixelsToAppUnits(mBEndBorderWidth), 0);
416 }
417 
418 inline void
GetContinuousBCBorderWidth(mozilla::WritingMode aWM,mozilla::LogicalMargin & aBorder)419 nsTableRowFrame::GetContinuousBCBorderWidth(mozilla::WritingMode aWM,
420                                             mozilla::LogicalMargin& aBorder)
421 {
422   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
423   aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
424                                                  mIStartContBorderWidth);
425   aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
426                                                  mBStartContBorderWidth);
427   aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
428                                                  mIEndContBorderWidth);
429 }
430 
GetOuterBStartContBCBorderWidth()431 inline nscoord nsTableRowFrame::GetOuterBStartContBCBorderWidth()
432 {
433   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
434   return BC_BORDER_START_HALF_COORD(aPixelsToTwips, mBStartContBorderWidth);
435 }
436 
437 #endif
438