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 nsTableCellFrame_h__
6 #define nsTableCellFrame_h__
7 
8 #include "mozilla/Attributes.h"
9 #include "celldata.h"
10 #include "nsITableCellLayout.h"
11 #include "nscore.h"
12 #include "nsContainerFrame.h"
13 #include "nsStyleContext.h"
14 #include "nsIPercentBSizeObserver.h"
15 #include "nsTArray.h"
16 #include "nsTableRowFrame.h"
17 #include "mozilla/WritingModes.h"
18 
19 /**
20  * nsTableCellFrame
21  * data structure to maintain information about a single table cell's frame
22  *
23  * NOTE:  frames are not ref counted.  We expose addref and release here
24  * so we can change that decsion in the future.  Users of nsITableCellLayout
25  * should refcount correctly as if this object is being ref counted, though
26  * no actual support is under the hood.
27  *
28  * @author  sclark
29  */
30 class nsTableCellFrame : public nsContainerFrame,
31                          public nsITableCellLayout,
32                          public nsIPercentBSizeObserver {
33   typedef mozilla::gfx::DrawTarget DrawTarget;
34   typedef mozilla::image::ImgDrawResult ImgDrawResult;
35 
36   friend nsTableCellFrame* NS_NewTableCellFrame(nsIPresShell* aPresShell,
37                                                 nsStyleContext* aContext,
38                                                 nsTableFrame* aTableFrame);
39 
nsTableCellFrame(nsStyleContext * aContext,nsTableFrame * aTableFrame)40   nsTableCellFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame)
41       : nsTableCellFrame(aContext, aTableFrame, kClassID) {}
42 
43  protected:
44   typedef mozilla::WritingMode WritingMode;
45   typedef mozilla::LogicalSide LogicalSide;
46   typedef mozilla::LogicalMargin LogicalMargin;
47 
48  public:
49   NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS(nsTableCellFrame)50   NS_DECL_FRAMEARENA_HELPERS(nsTableCellFrame)
51 
52   nsTableRowFrame* GetTableRowFrame() const {
53     nsIFrame* parent = GetParent();
54     MOZ_ASSERT(parent && parent->IsTableRowFrame());
55     return static_cast<nsTableRowFrame*>(parent);
56   }
57 
GetTableFrame()58   nsTableFrame* GetTableFrame() const {
59     return GetTableRowFrame()->GetTableFrame();
60   }
61 
62   virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
63                     nsIFrame* aPrevInFlow) override;
64 
65   virtual void DestroyFrom(nsIFrame* aDestructRoot,
66                            PostDestroyData& aPostDestroyData) override;
67 
68 #ifdef ACCESSIBILITY
69   virtual mozilla::a11y::AccType AccessibleType() override;
70 #endif
71 
72   virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
73                                     int32_t aModType) override;
74 
75   /** @see nsIFrame::DidSetStyleContext */
76   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
77 
78 #ifdef DEBUG
79   // Our anonymous block frame is the content insertion frame so these
80   // methods should never be called:
81   virtual void AppendFrames(ChildListID aListID,
82                             nsFrameList& aFrameList) override;
83   virtual void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
84                             nsFrameList& aFrameList) override;
85   virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override;
86 #endif
87 
GetContentInsertionFrame()88   virtual nsContainerFrame* GetContentInsertionFrame() override {
89     return PrincipalChildList().FirstChild()->GetContentInsertionFrame();
90   }
91 
92   virtual nsMargin GetUsedMargin() const override;
93 
94   virtual void NotifyPercentBSize(const ReflowInput& aReflowInput) override;
95 
96   virtual bool NeedsToObserve(const ReflowInput& aReflowInput) override;
97 
98   virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
99                                 const nsDisplayListSet& aLists) override;
100 
101   virtual nsresult ProcessBorders(nsTableFrame* aFrame,
102                                   nsDisplayListBuilder* aBuilder,
103                                   const nsDisplayListSet& aLists);
104 
105   virtual nscoord GetMinISize(gfxContext* aRenderingContext) override;
106   virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override;
107   virtual IntrinsicISizeOffsetData IntrinsicISizeOffsets() override;
108 
109   virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
110                       const ReflowInput& aReflowInput,
111                       nsReflowStatus& aStatus) override;
112 
113 #ifdef DEBUG_FRAME_DUMP
114   virtual nsresult GetFrameName(nsAString& aResult) const override;
115 #endif
116 
117   void BlockDirAlignChild(mozilla::WritingMode aWM, nscoord aMaxAscent);
118 
119   /*
120    * Get the value of vertical-align adjusted for CSS 2's rules for a
121    * table cell, which means the result is always
122    * NS_STYLE_VERTICAL_ALIGN_{TOP,MIDDLE,BOTTOM,BASELINE}.
123    */
124   virtual uint8_t GetVerticalAlign() const;
125 
HasVerticalAlignBaseline()126   bool HasVerticalAlignBaseline() const {
127     return GetVerticalAlign() == NS_STYLE_VERTICAL_ALIGN_BASELINE;
128   }
129 
130   bool CellHasVisibleContent(nscoord aBSize, nsTableFrame* tableFrame,
131                              nsIFrame* kidFrame);
132 
133   /**
134    * Get the first-line baseline of the cell relative to its block-start border
135    * edge, as if the cell were vertically aligned to the top of the row.
136    */
137   nscoord GetCellBaseline() const;
138 
139   /**
140    * return the cell's specified row span. this is what was specified in the
141    * content model or in the style info, and is always >= 0.
142    * to get the effective row span (the actual value that applies), use
143    * GetEffectiveRowSpan()
144    * @see nsTableFrame::GetEffectiveRowSpan()
145    */
146   int32_t GetRowSpan();
147 
148   // there is no set row index because row index depends on the cell's parent
149   // row only
150 
151   // Return our cell content frame.
152   void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
153 
154   /*---------------- nsITableCellLayout methods ------------------------*/
155 
156   /**
157    * return the cell's starting row index (starting at 0 for the first row).
158    * for continued cell frames the row index is that of the cell's first-in-flow
159    * and the column index (starting at 0 for the first column
160    */
161   NS_IMETHOD GetCellIndexes(int32_t& aRowIndex, int32_t& aColIndex) override;
162 
163   /** return the mapped cell's row index (starting at 0 for the first row) */
RowIndex()164   uint32_t RowIndex() const {
165     return static_cast<nsTableRowFrame*>(GetParent())->GetRowIndex();
166   }
167 
168   /**
169    * return the cell's specified col span. this is what was specified in the
170    * content model or in the style info, and is always >= 1.
171    * to get the effective col span (the actual value that applies), use
172    * GetEffectiveColSpan()
173    * @see nsTableFrame::GetEffectiveColSpan()
174    */
175   int32_t GetColSpan();
176 
177   /** return the cell's column index (starting at 0 for the first column) */
ColIndex()178   uint32_t ColIndex() const {
179     // NOTE: We copy this from previous continuations, and we don't ever have
180     // dynamic updates when tables split, so our mColIndex always matches our
181     // first continuation's.
182     MOZ_ASSERT(static_cast<nsTableCellFrame*>(FirstContinuation())->mColIndex ==
183                    mColIndex,
184                "mColIndex out of sync with first continuation");
185     return mColIndex;
186   }
187 
188   void SetColIndex(int32_t aColIndex);
189 
190   /** return the available isize given to this frame during its last reflow */
191   inline nscoord GetPriorAvailISize();
192 
193   /** set the available isize given to this frame during its last reflow */
194   inline void SetPriorAvailISize(nscoord aPriorAvailISize);
195 
196   /** return the desired size returned by this frame during its last reflow */
197   inline mozilla::LogicalSize GetDesiredSize();
198 
199   /** set the desired size returned by this frame during its last reflow */
200   inline void SetDesiredSize(const ReflowOutput& aDesiredSize);
201 
202   bool GetContentEmpty() const;
203   void SetContentEmpty(bool aContentEmpty);
204 
205   bool HasPctOverBSize();
206   void SetHasPctOverBSize(bool aValue);
207 
GetNextCell()208   nsTableCellFrame* GetNextCell() const {
209     nsIFrame* sibling = GetNextSibling();
210 #ifdef DEBUG
211     if (sibling) {
212       nsTableCellFrame* cellFrame = do_QueryFrame(sibling);
213       MOZ_ASSERT(cellFrame, "How do we have a non-cell sibling?");
214     }
215 #endif  // DEBUG
216     return static_cast<nsTableCellFrame*>(sibling);
217   }
218 
219   virtual LogicalMargin GetBorderWidth(WritingMode aWM) const;
220 
221   virtual ImgDrawResult PaintBackground(gfxContext& aRenderingContext,
222                                         const nsRect& aDirtyRect, nsPoint aPt,
223                                         uint32_t aFlags);
224 
225   void DecorateForSelection(DrawTarget* aDrawTarget, nsPoint aPt);
226 
227   virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
228 
IsFrameOfType(uint32_t aFlags)229   virtual bool IsFrameOfType(uint32_t aFlags) const override {
230     return nsContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eTablePart));
231   }
232 
233   virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) override;
234   virtual void InvalidateFrameWithRect(const nsRect& aRect,
235                                        uint32_t aDisplayItemKey = 0) override;
InvalidateFrameForRemoval()236   virtual void InvalidateFrameForRemoval() override {
237     InvalidateFrameSubtree();
238   }
239 
240   bool ShouldPaintBordersAndBackgrounds() const;
241 
242   bool ShouldPaintBackground(nsDisplayListBuilder* aBuilder);
243 
244  protected:
245   nsTableCellFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame,
246                    ClassID aID);
247   ~nsTableCellFrame();
248 
249   virtual LogicalSides GetLogicalSkipSides(
250       const ReflowInput* aReflowInput = nullptr) const override;
251 
252   /**
253    * GetBorderOverflow says how far the cell's own borders extend
254    * outside its own bounds.  In the separated borders model this should
255    * just be zero (as it is for most frames), but in the collapsed
256    * borders model (for which nsBCTableCellFrame overrides this virtual
257    * method), it considers the extents of the collapsed border.
258    */
259   virtual nsMargin GetBorderOverflow();
260 
261   friend class nsTableRowFrame;
262 
263   uint32_t mColIndex;  // the starting column for this cell
264 
265   nscoord mPriorAvailISize;           // the avail isize during the last reflow
266   mozilla::LogicalSize mDesiredSize;  // the last desired inline and block size
267 };
268 
GetPriorAvailISize()269 inline nscoord nsTableCellFrame::GetPriorAvailISize() {
270   return mPriorAvailISize;
271 }
272 
SetPriorAvailISize(nscoord aPriorAvailISize)273 inline void nsTableCellFrame::SetPriorAvailISize(nscoord aPriorAvailISize) {
274   mPriorAvailISize = aPriorAvailISize;
275 }
276 
GetDesiredSize()277 inline mozilla::LogicalSize nsTableCellFrame::GetDesiredSize() {
278   return mDesiredSize;
279 }
280 
SetDesiredSize(const ReflowOutput & aDesiredSize)281 inline void nsTableCellFrame::SetDesiredSize(const ReflowOutput& aDesiredSize) {
282   mozilla::WritingMode wm = aDesiredSize.GetWritingMode();
283   mDesiredSize = aDesiredSize.Size(wm).ConvertTo(GetWritingMode(), wm);
284 }
285 
GetContentEmpty()286 inline bool nsTableCellFrame::GetContentEmpty() const {
287   return HasAnyStateBits(NS_TABLE_CELL_CONTENT_EMPTY);
288 }
289 
SetContentEmpty(bool aContentEmpty)290 inline void nsTableCellFrame::SetContentEmpty(bool aContentEmpty) {
291   if (aContentEmpty) {
292     AddStateBits(NS_TABLE_CELL_CONTENT_EMPTY);
293   } else {
294     RemoveStateBits(NS_TABLE_CELL_CONTENT_EMPTY);
295   }
296 }
297 
HasPctOverBSize()298 inline bool nsTableCellFrame::HasPctOverBSize() {
299   return HasAnyStateBits(NS_TABLE_CELL_HAS_PCT_OVER_BSIZE);
300 }
301 
SetHasPctOverBSize(bool aValue)302 inline void nsTableCellFrame::SetHasPctOverBSize(bool aValue) {
303   if (aValue) {
304     AddStateBits(NS_TABLE_CELL_HAS_PCT_OVER_BSIZE);
305   } else {
306     RemoveStateBits(NS_TABLE_CELL_HAS_PCT_OVER_BSIZE);
307   }
308 }
309 
310 // nsBCTableCellFrame
311 class nsBCTableCellFrame final : public nsTableCellFrame {
312   typedef mozilla::image::ImgDrawResult ImgDrawResult;
313 
314  public:
315   NS_DECL_FRAMEARENA_HELPERS(nsBCTableCellFrame)
316 
317   nsBCTableCellFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame);
318 
319   ~nsBCTableCellFrame();
320 
321   virtual nsMargin GetUsedBorder() const override;
322 
323   // Get the *inner half of the border only*, in twips.
324   virtual LogicalMargin GetBorderWidth(WritingMode aWM) const override;
325 
326   // Get the *inner half of the border only*, in pixels.
327   BCPixelSize GetBorderWidth(LogicalSide aSide) const;
328 
329   // Set the full (both halves) width of the border
330   void SetBorderWidth(LogicalSide aSide, BCPixelSize aPixelValue);
331 
332   virtual nsMargin GetBorderOverflow() override;
333 
334 #ifdef DEBUG_FRAME_DUMP
335   virtual nsresult GetFrameName(nsAString& aResult) const override;
336 #endif
337 
338   virtual ImgDrawResult PaintBackground(gfxContext& aRenderingContext,
339                                         const nsRect& aDirtyRect, nsPoint aPt,
340                                         uint32_t aFlags) override;
341 
342  private:
343   // These are the entire width of the border (the cell edge contains only
344   // the inner half, per the macros in nsTablePainter.h).
345   BCPixelSize mBStartBorder;
346   BCPixelSize mIEndBorder;
347   BCPixelSize mBEndBorder;
348   BCPixelSize mIStartBorder;
349 };
350 
351 // Implemented here because that's a sane-ish way to make the includes work out.
GetFirstCell()352 inline nsTableCellFrame* nsTableRowFrame::GetFirstCell() const {
353   nsIFrame* firstChild = mFrames.FirstChild();
354 #ifdef DEBUG
355   if (firstChild) {
356     nsTableCellFrame* cellFrame = do_QueryFrame(firstChild);
357     MOZ_ASSERT(cellFrame, "How do we have a non-cell sibling?");
358   }
359 #endif  // DEBUG
360   return static_cast<nsTableCellFrame*>(firstChild);
361 }
362 
363 #endif
364