nsTableRowGroupFrame.h (14700B)
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 nsTableRowGroupFrame_h__ 6 #define nsTableRowGroupFrame_h__ 7 8 #include "mozilla/WritingModes.h" 9 #include "nsAtom.h" 10 #include "nsContainerFrame.h" 11 #include "nsILineIterator.h" 12 #include "nsTArray.h" 13 #include "nsTableFrame.h" 14 #include "nscore.h" 15 16 class nsTableRowFrame; 17 namespace mozilla { 18 class PresShell; 19 struct TableRowGroupReflowInput; 20 } // namespace mozilla 21 22 #define MIN_ROWS_NEEDING_CURSOR 20 23 24 /** 25 * nsTableRowGroupFrame is the frame that maps row groups 26 * (HTML tags THEAD, TFOOT, and TBODY). This class cannot be reused 27 * outside of an nsTableFrame. It assumes that its parent is an nsTableFrame, 28 * and its children are nsTableRowFrames. 29 * 30 * @see nsTableFrame 31 * @see nsTableRowFrame 32 */ 33 class nsTableRowGroupFrame final : public nsContainerFrame, 34 public nsILineIterator { 35 public: 36 NS_DECL_QUERYFRAME 37 NS_DECL_FRAMEARENA_HELPERS(nsTableRowGroupFrame) 38 39 /** instantiate a new instance of nsTableRowFrame. 40 * @param aPresShell the pres shell for this frame 41 * 42 * @return the frame that was created 43 */ 44 friend nsTableRowGroupFrame* NS_NewTableRowGroupFrame( 45 mozilla::PresShell* aPresShell, ComputedStyle* aStyle); 46 virtual ~nsTableRowGroupFrame(); 47 48 // nsIFrame overrides 49 void Init(nsIContent* aContent, nsContainerFrame* aParent, 50 nsIFrame* aPrevInFlow) override { 51 nsContainerFrame::Init(aContent, aParent, aPrevInFlow); 52 if (!aPrevInFlow) { 53 mWritingMode = GetTableFrame()->GetWritingMode(); 54 } 55 } 56 57 void Destroy(DestroyContext&) override; 58 59 /** @see nsIFrame::DidSetComputedStyle */ 60 void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override; 61 62 void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) override; 63 void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, 64 const nsLineList::iterator* aPrevFrameLine, 65 nsFrameList&& aFrameList) override; 66 void RemoveFrame(DestroyContext&, ChildListID, nsIFrame*) override; 67 68 nsMargin GetUsedMargin() const override; 69 nsMargin GetUsedBorder() const override; 70 nsMargin GetUsedPadding() const override; 71 72 void BuildDisplayList(nsDisplayListBuilder* aBuilder, 73 const nsDisplayListSet& aLists) override; 74 75 /** 76 * Calls Reflow for all of its child rows. 77 * 78 * Rows are all set to the same isize and stacked in the block direction. 79 * 80 * Rows are not split unless absolutely necessary. 81 * 82 * @param aDesiredSize isize set to isize of rows, bsize set to 83 * sum of bsize of rows that fit in AvailableBSize. 84 * 85 * @see nsIFrame::Reflow 86 */ 87 void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 88 const ReflowInput& aReflowInput, 89 nsReflowStatus& aStatus) override; 90 91 bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas) override; 92 93 #ifdef DEBUG_FRAME_DUMP 94 nsresult GetFrameName(nsAString& aResult) const override; 95 #endif 96 97 nsTableRowFrame* GetFirstRow() const; 98 nsTableRowFrame* GetLastRow() const; 99 100 nsTableFrame* GetTableFrame() const { 101 nsIFrame* parent = GetParent(); 102 MOZ_ASSERT(parent && parent->IsTableFrame()); 103 return static_cast<nsTableFrame*>(parent); 104 } 105 106 /** return the number of child rows (not necessarily == number of child 107 * frames) */ 108 int32_t GetRowCount() const; 109 110 /** return the table-relative row index of the first row in this rowgroup. 111 * if there are no rows, -1 is returned. 112 */ 113 int32_t GetStartRowIndex() const; 114 115 /** Adjust the row indices of all rows whose index is >= aRowIndex. 116 * @param aRowIndex - start adjusting with this index 117 * @param aAdjustment - shift the row index by this amount 118 */ 119 void AdjustRowIndices(int32_t aRowIndex, int32_t anAdjustment); 120 121 // See nsTableFrame.h 122 int32_t GetAdjustmentForStoredIndex(int32_t aStoredIndex); 123 124 /* mark rows starting from aStartRowFrame to the next 'aNumRowsToRemove-1' 125 * number of rows as deleted 126 */ 127 void MarkRowsAsDeleted(nsTableRowFrame& aStartRowFrame, 128 int32_t aNumRowsToDelete); 129 130 // See nsTableFrame.h 131 void AddDeletedRowIndex(int32_t aDeletedRowStoredIndex); 132 133 /** 134 * Used for header and footer row group frames that are repeated when 135 * splitting a table frame. 136 * 137 * Performs any table specific initialization 138 * 139 * @param aHeaderFooterFrame the original header or footer row group frame 140 * that was repeated 141 */ 142 void InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame); 143 144 /** 145 * Get the total bsize of all the row rects 146 */ 147 nscoord GetBSizeBasis(const ReflowInput& aReflowInput); 148 149 mozilla::LogicalMargin GetBCBorderWidth(mozilla::WritingMode aWM); 150 151 /** 152 * Adjust to the effect of visibility:collapse on the row group and 153 * its children 154 * @return additional shift bstart-wards that should be applied 155 * to subsequent rowgroups due to rows and this 156 * rowgroup being collapsed 157 * @param aBTotalOffset the total amount that the rowgroup is shifted 158 * @param aISize new isize of the rowgroup 159 * @param aWM the table's writing mode 160 */ 161 nscoord CollapseRowGroupIfNecessary(nscoord aBTotalOffset, nscoord aISize, 162 mozilla::WritingMode aWM); 163 164 // nsILineIterator methods 165 public: 166 // The table row is the equivalent to a line in block layout. 167 // The nsILineIterator assumes that a line resides in a block, this role is 168 // fullfilled by the row group. Rows in table are counted relative to the 169 // table. The row index of row corresponds to the cellmap coordinates. The 170 // line index with respect to a row group can be computed by substracting the 171 // row index of the first row in the row group. 172 173 /** Get the number of rows in a row group 174 * @return the number of lines in a row group 175 */ 176 int32_t GetNumLines() const final; 177 178 /** @see nsILineIterator.h IsLineIteratorFlowRTL */ 179 bool IsLineIteratorFlowRTL() final; 180 181 /** Return structural information about a line. */ 182 Result<LineInfo, nsresult> GetLine(int32_t aLineNumber) final; 183 184 /** Given a frame that's a child of the rowgroup, find which line its on. 185 * @param aFrame - frame, should be a row 186 * @param aStartLine - minimal index to return 187 * @return row index relative to the row group if this a row 188 * frame and the index is at least aStartLine. 189 * -1 if the frame cannot be found. 190 */ 191 int32_t FindLineContaining(const nsIFrame* aFrame, 192 int32_t aStartLine = 0) final; 193 194 /** Find the orginating cell frame on a row that is the nearest to the 195 * inline-dir coordinate of aPos. 196 * @param aLineNumber - the index of the row relative to the row group 197 * @param aPos - coordinate in twips relative to the 198 * origin of the row group 199 * @param aFrameFound - pointer to the cellframe 200 * @param aPosIsBeforeFirstFrame - the point is before the first originating 201 * cellframe 202 * @param aPosIsAfterLastFrame - the point is after the last originating 203 * cellframe 204 */ 205 NS_IMETHOD FindFrameAt(int32_t aLineNumber, nsPoint aPos, 206 nsIFrame** aFrameFound, bool* aPosIsBeforeFirstFrame, 207 bool* aPosIsAfterLastFrame) final; 208 209 /** Check whether visual and logical order of cell frames within a line are 210 * identical. As the layout will reorder them this is always the case 211 * @param aLine - the index of the row relative to the table 212 * @param aIsReordered - returns false 213 * @param aFirstVisual - if the table is rtl first originating cell frame 214 * @param aLastVisual - if the table is rtl last originating cell frame 215 */ 216 217 NS_IMETHOD CheckLineOrder(int32_t aLine, bool* aIsReordered, 218 nsIFrame** aFirstVisual, 219 nsIFrame** aLastVisual) final; 220 221 // row cursor methods to speed up searching for the row(s) 222 // containing a point. The basic idea is that we set the cursor 223 // property if the rows' y and yMosts are non-decreasing (considering only 224 // rows with nonempty overflowAreas --- empty overflowAreas never participate 225 // in event handling or painting), and the rowgroup has sufficient number of 226 // rows. The cursor property points to a "recently used" row. If we get a 227 // series of requests that work on rows "near" the cursor, then we can find 228 // those nearby rows quickly by starting our search at the cursor. 229 // This code is based on the line cursor code in nsBlockFrame. It's more 230 // general though, and could be extracted and used elsewhere. 231 struct FrameCursorData { 232 nsTArray<nsIFrame*> mFrames; 233 uint32_t mCursorIndex; 234 nscoord mOverflowAbove; 235 nscoord mOverflowBelow; 236 237 FrameCursorData() 238 : mFrames(MIN_ROWS_NEEDING_CURSOR), 239 mCursorIndex(0), 240 mOverflowAbove(0), 241 mOverflowBelow(0) {} 242 243 bool AppendFrame(nsIFrame* aFrame); 244 245 void FinishBuildingCursor() { mFrames.Compact(); } 246 }; 247 248 // Clear out row cursor because we're disturbing the rows (e.g., Reflow) 249 void ClearRowCursor(); 250 251 /** 252 * Get the first row that might contain y-coord 'aY', or nullptr if you must 253 * search all rows. 254 * The actual row returned might not contain 'aY', but if not, it is 255 * guaranteed to be before any row which does contain 'aY'. 256 * aOverflowAbove is the maximum over all rows of -row.GetOverflowRect().y. 257 * To find all rows that intersect the vertical interval aY/aYMost, call 258 * GetFirstRowContaining(aY, &overflowAbove), and then iterate through all 259 * rows until reaching a row where row->GetRect().y - overflowAbove >= aYMost. 260 * That row and all subsequent rows cannot intersect the interval. 261 */ 262 nsIFrame* GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove); 263 264 /** 265 * Set up the row cursor. After this, call AppendFrame for every 266 * child frame in sibling order. Ensure that the child frame y and YMost 267 * values form non-decreasing sequences (should always be true for table 268 * rows); if this is violated, call ClearRowCursor(). If we return nullptr, 269 * then we decided not to use a cursor or we already have one set up. 270 */ 271 FrameCursorData* SetupRowCursor(); 272 273 bool CanProvideLineIterator() const final { return true; } 274 nsILineIterator* GetLineIterator() final { return this; } 275 276 void InvalidateFrame(uint32_t aDisplayItemKey = 0, 277 bool aRebuildDisplayItems = true) override; 278 void InvalidateFrameWithRect(const nsRect& aRect, 279 uint32_t aDisplayItemKey = 0, 280 bool aRebuildDisplayItems = true) override; 281 void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); } 282 283 protected: 284 explicit nsTableRowGroupFrame(ComputedStyle* aStyle, 285 nsPresContext* aPresContext); 286 287 void InitChildReflowInput(nsPresContext* aPresContext, bool aBorderCollapse, 288 ReflowInput& aReflowInput); 289 290 LogicalSides GetLogicalSkipSides() const override; 291 292 void PlaceChild(nsPresContext* aPresContext, 293 mozilla::TableRowGroupReflowInput& aReflowInput, 294 nsIFrame* aKidFrame, const ReflowInput& aKidReflowInput, 295 mozilla::WritingMode aWM, 296 const mozilla::LogicalPoint& aKidPosition, 297 const nsSize& aContainerSize, ReflowOutput& aDesiredSize, 298 const nsRect& aOriginalKidRect, 299 const nsRect& aOriginalKidInkOverflow); 300 301 void CalculateRowBSizes(nsPresContext* aPresContext, 302 ReflowOutput& aDesiredSize, 303 const ReflowInput& aReflowInput); 304 305 void DidResizeRows(ReflowOutput& aDesiredSize); 306 307 /** 308 * Reflow the frames we've already created 309 * 310 * @param aPresContext presentation context to use 311 * @param aReflowInput current inline state 312 */ 313 void ReflowChildren(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 314 mozilla::TableRowGroupReflowInput& aReflowInput, 315 nsReflowStatus& aStatus, 316 bool* aPageBreakBeforeEnd = nullptr); 317 318 void SplitRowGroup(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, 319 const ReflowInput& aReflowInput, nsTableFrame* aTableFrame, 320 nsReflowStatus& aStatus, bool aRowForcedPageBreak); 321 322 void SplitSpanningCells(nsPresContext* aPresContext, 323 const ReflowInput& aReflowInput, 324 nsTableFrame* aTableFrame, nsTableRowFrame* aFirstRow, 325 nsTableRowFrame* aLastRow, bool aFirstRowIsTopOfPage, 326 nscoord aSpanningRowBEnd, 327 const nsSize& aContainerSize, 328 nsTableRowFrame*& aContRowFrame, 329 nsTableRowFrame*& aFirstTruncatedRow, 330 nscoord& aDesiredBSize); 331 332 /** 333 * Create a continuing table row frame, add it to the child list, and then 334 * push it and its later siblings to our overflow frames list. 335 */ 336 nsTableRowFrame* CreateContinuingRowFrame(nsIFrame* aRowFrame); 337 338 bool IsSimpleRowFrame(nsTableFrame* aTableFrame, nsTableRowFrame* aRowFrame); 339 340 void GetNextRowSibling(nsIFrame** aRowFrame); 341 342 void UndoContinuedRow(nsPresContext* aPresContext, nsTableRowFrame* aRow); 343 344 public: 345 bool IsRepeatable() const; 346 void SetRepeatable(bool aRepeatable); 347 bool HasStyleBSize() const; 348 void SetHasStyleBSize(bool aValue); 349 bool HasInternalBreakBefore() const; 350 bool HasInternalBreakAfter() const; 351 }; 352 353 inline bool nsTableRowGroupFrame::IsRepeatable() const { 354 return HasAnyStateBits(NS_ROWGROUP_REPEATABLE); 355 } 356 357 inline void nsTableRowGroupFrame::SetRepeatable(bool aRepeatable) { 358 if (aRepeatable) { 359 AddStateBits(NS_ROWGROUP_REPEATABLE); 360 } else { 361 RemoveStateBits(NS_ROWGROUP_REPEATABLE); 362 } 363 } 364 365 inline bool nsTableRowGroupFrame::HasStyleBSize() const { 366 return HasAnyStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE); 367 } 368 369 inline void nsTableRowGroupFrame::SetHasStyleBSize(bool aValue) { 370 if (aValue) { 371 AddStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE); 372 } else { 373 RemoveStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE); 374 } 375 } 376 377 #endif