nsTableCellFrame.h (11569B)
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 "celldata.h" 9 #include "mozilla/ComputedStyle.h" 10 #include "mozilla/WritingModes.h" 11 #include "nsContainerFrame.h" 12 #include "nsIPercentBSizeObserver.h" 13 #include "nsITableCellLayout.h" 14 #include "nsTArray.h" 15 #include "nsTableRowFrame.h" 16 #include "nscore.h" 17 18 namespace mozilla { 19 class PresShell; 20 class ScrollContainerFrame; 21 } // namespace mozilla 22 23 enum class TableCellAlignment : uint8_t { 24 Top, 25 Middle, 26 Bottom, 27 Baseline, 28 }; 29 30 /** 31 * nsTableCellFrame 32 * data structure to maintain information about a single table cell's frame 33 * 34 * NOTE: frames are not ref counted. We expose addref and release here 35 * so we can change that decsion in the future. Users of nsITableCellLayout 36 * should refcount correctly as if this object is being ref counted, though 37 * no actual support is under the hood. 38 * 39 * @author sclark 40 */ 41 class nsTableCellFrame : public nsContainerFrame, 42 public nsITableCellLayout, 43 public nsIPercentBSizeObserver { 44 friend nsTableCellFrame* NS_NewTableCellFrame(mozilla::PresShell* aPresShell, 45 ComputedStyle* aStyle, 46 nsTableFrame* aTableFrame); 47 48 nsTableCellFrame(ComputedStyle* aStyle, nsTableFrame* aTableFrame) 49 : nsTableCellFrame(aStyle, aTableFrame, kClassID) {} 50 51 public: 52 NS_DECL_QUERYFRAME 53 NS_DECL_FRAMEARENA_HELPERS(nsTableCellFrame) 54 55 mozilla::ScrollContainerFrame* GetScrollTargetFrame() const final; 56 57 nsTableRowFrame* GetTableRowFrame() const { 58 nsIFrame* parent = GetParent(); 59 MOZ_ASSERT(parent && parent->IsTableRowFrame()); 60 return static_cast<nsTableRowFrame*>(parent); 61 } 62 63 nsTableFrame* GetTableFrame() const { 64 return GetTableRowFrame()->GetTableFrame(); 65 } 66 67 void Init(nsIContent* aContent, nsContainerFrame* aParent, 68 nsIFrame* aPrevInFlow) override; 69 70 void Destroy(DestroyContext&) override; 71 72 #ifdef ACCESSIBILITY 73 mozilla::a11y::AccType AccessibleType() override; 74 #endif 75 76 nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute, 77 AttrModType aModType) override; 78 79 /** @see nsIFrame::DidSetComputedStyle */ 80 void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override; 81 82 #ifdef DEBUG 83 // Our anonymous block frame is the content insertion frame so these 84 // methods should never be called: 85 void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) override; 86 void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, 87 const nsLineList::iterator* aPrevFrameLine, 88 nsFrameList&& aFrameList) override; 89 void RemoveFrame(DestroyContext&, ChildListID, nsIFrame*) override; 90 #endif 91 92 nsContainerFrame* GetContentInsertionFrame() override { 93 return Inner()->GetContentInsertionFrame(); 94 } 95 96 // Return our anonymous inner frame. 97 nsIFrame* Inner() const; 98 99 nsIFrame* CellContentFrame() const; 100 101 nsMargin GetUsedMargin() const override; 102 103 void NotifyPercentBSize(const ReflowInput& aReflowInput) override; 104 105 bool NeedsToObserve(const ReflowInput& aReflowInput) override; 106 107 void BuildDisplayList(nsDisplayListBuilder* aBuilder, 108 const nsDisplayListSet& aLists) override; 109 110 virtual void ProcessBorders(nsTableFrame* aFrame, 111 nsDisplayListBuilder* aBuilder, 112 const nsDisplayListSet& aLists); 113 114 nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput, 115 mozilla::IntrinsicISizeType aType) override; 116 117 IntrinsicSizeOffsetData IntrinsicISizeOffsets( 118 nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) override; 119 120 void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 121 const ReflowInput& aReflowInput, 122 nsReflowStatus& aStatus) override; 123 124 #ifdef DEBUG_FRAME_DUMP 125 nsresult GetFrameName(nsAString& aResult) const override; 126 #endif 127 128 // Align the cell's anonymous-block child within the cell. This applies the 129 // CSS `vertical-align` property to position the child frame appropriately 130 // (in terms of the writing mode of the cell contents, which may be different 131 // from the table's WM). 132 // This also resets the child's inline position, which in the case of an 133 // orthogonal child may have been based on an unknown container size when 134 // it was initially reflowed. 135 void AlignChildWithinCell(nscoord aMaxAscent, 136 mozilla::ForceAlignTopForTableCell aForceAlignTop); 137 138 /* 139 * Map the CSS vertical-align to the corresponding table cell alignment value. 140 */ 141 virtual TableCellAlignment GetTableCellAlignment() const; 142 143 bool HasTableCellAlignmentBaseline() const { 144 return GetTableCellAlignment() == TableCellAlignment::Baseline && 145 !GetContentEmpty(); 146 } 147 148 /** 149 * Get the first-line baseline of the cell relative to its block-start border 150 * edge, as if the cell were vertically aligned to the top of the row. 151 */ 152 Maybe<nscoord> GetCellBaseline() const; 153 154 /** 155 * return the cell's specified row span. this is what was specified in the 156 * content model or in the style info, and is always >= 0. 157 * to get the effective row span (the actual value that applies), use 158 * GetEffectiveRowSpan() 159 * @see nsTableFrame::GetEffectiveRowSpan() 160 */ 161 int32_t GetRowSpan(); 162 163 // there is no set row index because row index depends on the cell's parent 164 // row only 165 166 // Return our cell content frame. 167 void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override; 168 169 /*---------------- nsITableCellLayout methods ------------------------*/ 170 171 /** 172 * return the cell's starting row index (starting at 0 for the first row). 173 * for continued cell frames the row index is that of the cell's first-in-flow 174 * and the column index (starting at 0 for the first column 175 */ 176 NS_IMETHOD GetCellIndexes(int32_t& aRowIndex, int32_t& aColIndex) override; 177 178 /** return the mapped cell's row index (starting at 0 for the first row) */ 179 uint32_t RowIndex() const { 180 return static_cast<nsTableRowFrame*>(GetParent())->GetRowIndex(); 181 } 182 183 /** 184 * return the cell's specified col span. this is what was specified in the 185 * content model or in the style info, and is always >= 1. 186 * to get the effective col span (the actual value that applies), use 187 * GetEffectiveColSpan() 188 * @see nsTableFrame::GetEffectiveColSpan() 189 */ 190 int32_t GetColSpan(); 191 192 /** return the cell's column index (starting at 0 for the first column) */ 193 uint32_t ColIndex() const { 194 // NOTE: We copy this from previous continuations, and we don't ever have 195 // dynamic updates when tables split, so our mColIndex always matches our 196 // first continuation's. 197 MOZ_ASSERT(static_cast<nsTableCellFrame*>(FirstContinuation())->mColIndex == 198 mColIndex, 199 "mColIndex out of sync with first continuation"); 200 return mColIndex; 201 } 202 203 void SetColIndex(int32_t aColIndex); 204 205 // Get or set the available isize given to this frame during its last reflow. 206 nscoord GetPriorAvailISize() const { return mPriorAvailISize; } 207 void SetPriorAvailISize(nscoord aPriorAvailISize) { 208 mPriorAvailISize = aPriorAvailISize; 209 } 210 211 // Get or set the desired size returned by this frame during its last reflow. 212 mozilla::LogicalSize GetDesiredSize() const { return mDesiredSize; } 213 void SetDesiredSize(const ReflowOutput& aDesiredSize) { 214 mDesiredSize = aDesiredSize.Size(GetWritingMode()); 215 } 216 217 bool GetContentEmpty() const { 218 return HasAnyStateBits(NS_TABLE_CELL_CONTENT_EMPTY); 219 } 220 void SetContentEmpty(bool aContentEmpty) { 221 AddOrRemoveStateBits(NS_TABLE_CELL_CONTENT_EMPTY, aContentEmpty); 222 } 223 224 nsTableCellFrame* GetNextCell() const { 225 nsIFrame* sibling = GetNextSibling(); 226 MOZ_ASSERT( 227 !sibling || static_cast<nsTableCellFrame*>(do_QueryFrame(sibling)), 228 "How do we have a non-cell sibling?"); 229 return static_cast<nsTableCellFrame*>(sibling); 230 } 231 232 virtual mozilla::LogicalMargin GetBorderWidth(mozilla::WritingMode aWM) const; 233 virtual bool BCBordersChanged() const { return false; } 234 235 void DecorateForSelection(DrawTarget* aDrawTarget, nsPoint aPt); 236 237 bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas) override; 238 239 void InvalidateFrame(uint32_t aDisplayItemKey = 0, 240 bool aRebuildDisplayItems = true) override; 241 void InvalidateFrameWithRect(const nsRect& aRect, 242 uint32_t aDisplayItemKey = 0, 243 bool aRebuildDisplayItems = true) override; 244 void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); } 245 246 bool ShouldPaintBordersAndBackgrounds() const; 247 248 bool ShouldPaintBackground(nsDisplayListBuilder* aBuilder); 249 250 protected: 251 nsTableCellFrame(ComputedStyle* aStyle, nsTableFrame* aTableFrame, 252 ClassID aID); 253 ~nsTableCellFrame(); 254 255 LogicalSides GetLogicalSkipSides() const override; 256 257 /** 258 * GetBorderOverflow says how far the cell's own borders extend 259 * outside its own bounds. In the separated borders model this should 260 * just be zero (as it is for most frames), but in the collapsed 261 * borders model (for which nsBCTableCellFrame overrides this virtual 262 * method), it considers the extents of the collapsed border. 263 */ 264 virtual nsMargin GetBorderOverflow(); 265 266 friend class nsTableRowFrame; 267 268 // The starting column for this cell 269 uint32_t mColIndex = 0; 270 271 // The avail isize during the last reflow 272 nscoord mPriorAvailISize = 0; 273 274 // The last desired inline and block size 275 mozilla::LogicalSize mDesiredSize; 276 }; 277 278 class nsBCTableCellFrame final : public nsTableCellFrame { 279 public: 280 NS_DECL_FRAMEARENA_HELPERS(nsBCTableCellFrame) 281 282 nsBCTableCellFrame(ComputedStyle* aStyle, nsTableFrame* aTableFrame); 283 void Reflow(nsPresContext*, ReflowOutput&, const ReflowInput&, 284 nsReflowStatus&) override; 285 286 ~nsBCTableCellFrame(); 287 288 nsMargin GetUsedBorder() const override; 289 bool BCBordersChanged() const override { 290 return GetUsedBorder() != mLastUsedBorder; 291 } 292 293 // Get the *inner half of the border only*, in twips. 294 mozilla::LogicalMargin GetBorderWidth( 295 mozilla::WritingMode aWM) const override; 296 297 // Get the *inner half of the border only* 298 nscoord GetBorderWidth(mozilla::LogicalSide aSide) const; 299 300 // Set the full (both halves) width of the border 301 void SetBorderWidth(mozilla::LogicalSide aSide, nscoord aValue); 302 303 nsMargin GetBorderOverflow() override; 304 305 #ifdef DEBUG_FRAME_DUMP 306 nsresult GetFrameName(nsAString& aResult) const override; 307 #endif 308 309 private: 310 // These are the entire width of the border (the cell edge contains only 311 // the inner half). 312 nscoord mBStartBorder = 0; 313 nscoord mIEndBorder = 0; 314 nscoord mBEndBorder = 0; 315 nscoord mIStartBorder = 0; 316 317 nsMargin mLastUsedBorder; 318 }; 319 320 // Implemented here because that's a sane-ish way to make the includes work out. 321 inline nsTableCellFrame* nsTableRowFrame::GetFirstCell() const { 322 nsIFrame* firstChild = mFrames.FirstChild(); 323 MOZ_ASSERT( 324 !firstChild || static_cast<nsTableCellFrame*>(do_QueryFrame(firstChild)), 325 "How do we have a non-cell child?"); 326 return static_cast<nsTableCellFrame*>(firstChild); 327 } 328 329 #endif