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