Line data Source code
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/Attributes.h"
9 : #include "nscore.h"
10 : #include "nsContainerFrame.h"
11 : #include "nsIAtom.h"
12 : #include "nsILineIterator.h"
13 : #include "nsTArray.h"
14 : #include "nsTableFrame.h"
15 : #include "mozilla/WritingModes.h"
16 :
17 : class nsTableRowFrame;
18 : namespace mozilla {
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, and
28 : * its children are nsTableRowFrames.
29 : *
30 : * @see nsTableFrame
31 : * @see nsTableRowFrame
32 : */
33 : class nsTableRowGroupFrame final
34 : : public nsContainerFrame
35 : , public nsILineIterator
36 : {
37 : using TableRowGroupReflowInput = mozilla::TableRowGroupReflowInput;
38 :
39 : public:
40 : NS_DECL_QUERYFRAME
41 0 : NS_DECL_FRAMEARENA_HELPERS(nsTableRowGroupFrame)
42 :
43 : /** instantiate a new instance of nsTableRowFrame.
44 : * @param aPresShell the pres shell for this frame
45 : *
46 : * @return the frame that was created
47 : */
48 : friend nsTableRowGroupFrame* NS_NewTableRowGroupFrame(nsIPresShell* aPresShell,
49 : nsStyleContext* aContext);
50 : virtual ~nsTableRowGroupFrame();
51 :
52 : // nsIFrame overrides
53 0 : virtual void Init(nsIContent* aContent,
54 : nsContainerFrame* aParent,
55 : nsIFrame* aPrevInFlow) override
56 : {
57 0 : nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
58 0 : if (!aPrevInFlow) {
59 0 : mWritingMode = GetTableFrame()->GetWritingMode();
60 : }
61 0 : }
62 :
63 : virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
64 :
65 : /** @see nsIFrame::DidSetStyleContext */
66 : virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
67 :
68 : virtual void AppendFrames(ChildListID aListID,
69 : nsFrameList& aFrameList) override;
70 : virtual void InsertFrames(ChildListID aListID,
71 : nsIFrame* aPrevFrame,
72 : nsFrameList& aFrameList) override;
73 : virtual void RemoveFrame(ChildListID aListID,
74 : nsIFrame* aOldFrame) override;
75 :
76 : virtual nsMargin GetUsedMargin() const override;
77 : virtual nsMargin GetUsedBorder() const override;
78 : virtual nsMargin GetUsedPadding() const override;
79 :
80 : virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
81 : const nsRect& aDirtyRect,
82 : const nsDisplayListSet& aLists) override;
83 :
84 : /** calls Reflow for all of its child rows.
85 : * Rows are all set to the same isize and stacked in the block direction.
86 : * <P> rows are not split unless absolutely necessary.
87 : *
88 : * @param aDesiredSize isize set to isize of rows, bsize set to
89 : * sum of bsize of rows that fit in AvailableBSize.
90 : *
91 : * @see nsIFrame::Reflow
92 : */
93 : virtual void Reflow(nsPresContext* aPresContext,
94 : ReflowOutput& aDesiredSize,
95 : const ReflowInput& aReflowInput,
96 : nsReflowStatus& aStatus) override;
97 :
98 : virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
99 :
100 : #ifdef DEBUG_FRAME_DUMP
101 : virtual nsresult GetFrameName(nsAString& aResult) const override;
102 : #endif
103 :
104 : nsTableRowFrame* GetFirstRow();
105 : nsTableRowFrame* GetLastRow();
106 :
107 0 : nsTableFrame* GetTableFrame() const
108 : {
109 0 : nsIFrame* parent = GetParent();
110 0 : MOZ_ASSERT(parent && parent->IsTableFrame());
111 0 : return static_cast<nsTableFrame*>(parent);
112 : }
113 :
114 : /** return the number of child rows (not necessarily == number of child frames) */
115 : int32_t GetRowCount();
116 :
117 : /** return the table-relative row index of the first row in this rowgroup.
118 : * if there are no rows, -1 is returned.
119 : */
120 : int32_t GetStartRowIndex();
121 :
122 : /** Adjust the row indices of all rows whose index is >= aRowIndex.
123 : * @param aRowIndex - start adjusting with this index
124 : * @param aAdjustment - shift the row index by this amount
125 : */
126 : void AdjustRowIndices(int32_t aRowIndex,
127 : int32_t anAdjustment);
128 :
129 : // See nsTableFrame.h
130 : int32_t GetAdjustmentForStoredIndex(int32_t aStoredIndex);
131 :
132 : /* mark rows starting from aStartRowFrame to the next 'aNumRowsToRemove-1'
133 : * number of rows as deleted
134 : */
135 : void MarkRowsAsDeleted(nsTableRowFrame& aStartRowFrame,
136 : int32_t aNumRowsToDelete);
137 :
138 : // See nsTableFrame.h
139 : void AddDeletedRowIndex(int32_t aDeletedRowStoredIndex);
140 :
141 :
142 : /**
143 : * Used for header and footer row group frames that are repeated when
144 : * splitting a table frame.
145 : *
146 : * Performs any table specific initialization
147 : *
148 : * @param aHeaderFooterFrame the original header or footer row group frame
149 : * that was repeated
150 : */
151 : nsresult InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame);
152 :
153 :
154 : /**
155 : * Get the total bsize of all the row rects
156 : */
157 : nscoord GetBSizeBasis(const ReflowInput& aReflowInput);
158 :
159 : mozilla::LogicalMargin GetBCBorderWidth(mozilla::WritingMode aWM);
160 :
161 : /**
162 : * Gets inner border widths before collapsing with cell borders
163 : * Caller must get bstart border from previous row group or from table
164 : * GetContinuousBCBorderWidth will not overwrite aBorder.BStart()
165 : * see nsTablePainter about continuous borders
166 : */
167 : void GetContinuousBCBorderWidth(mozilla::WritingMode aWM,
168 : mozilla::LogicalMargin& aBorder);
169 :
170 : /**
171 : * Sets full border widths before collapsing with cell borders
172 : * @param aForSide - side to set; only IEnd, IStart, BEnd are valid
173 : */
174 : void SetContinuousBCBorderWidth(mozilla::LogicalSide aForSide,
175 : BCPixelSize aPixelValue);
176 : /**
177 : * Adjust to the effect of visibility:collapse on the row group and
178 : * its children
179 : * @return additional shift bstart-wards that should be applied
180 : * to subsequent rowgroups due to rows and this
181 : * rowgroup being collapsed
182 : * @param aBTotalOffset the total amount that the rowgroup is shifted
183 : * @param aISize new isize of the rowgroup
184 : * @param aWM the table's writing mode
185 : */
186 : nscoord CollapseRowGroupIfNecessary(nscoord aBTotalOffset,
187 : nscoord aISize,
188 : mozilla::WritingMode aWM);
189 :
190 : // nsILineIterator methods
191 : public:
192 0 : virtual void DisposeLineIterator() override { }
193 :
194 : // The table row is the equivalent to a line in block layout.
195 : // The nsILineIterator assumes that a line resides in a block, this role is
196 : // fullfilled by the row group. Rows in table are counted relative to the
197 : // table. The row index of row corresponds to the cellmap coordinates. The
198 : // line index with respect to a row group can be computed by substracting the
199 : // row index of the first row in the row group.
200 :
201 : /** Get the number of rows in a row group
202 : * @return the number of lines in a row group
203 : */
204 : virtual int32_t GetNumLines() override;
205 :
206 : /** @see nsILineIterator.h GetDirection
207 : * @return true if the table is rtl
208 : */
209 : virtual bool GetDirection() override;
210 :
211 : /** Return structural information about a line.
212 : * @param aLineNumber - the index of the row relative to the row group
213 : * If the line-number is invalid then
214 : * aFirstFrameOnLine will be nullptr and
215 : * aNumFramesOnLine will be zero.
216 : * @param aFirstFrameOnLine - the first cell frame that originates in row
217 : * with a rowindex that matches a line number
218 : * @param aNumFramesOnLine - return the numbers of cells originating in
219 : * this row
220 : * @param aLineBounds - rect of the row
221 : */
222 : NS_IMETHOD GetLine(int32_t aLineNumber,
223 : nsIFrame** aFirstFrameOnLine,
224 : int32_t* aNumFramesOnLine,
225 : nsRect& aLineBounds) override;
226 :
227 : /** Given a frame that's a child of the rowgroup, find which line its on.
228 : * @param aFrame - frame, should be a row
229 : * @param aStartLine - minimal index to return
230 : * @return row index relative to the row group if this a row
231 : * frame and the index is at least aStartLine.
232 : * -1 if the frame cannot be found.
233 : */
234 : virtual int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) override;
235 :
236 : /** Find the orginating cell frame on a row that is the nearest to the
237 : * inline-dir coordinate of aPos.
238 : * @param aLineNumber - the index of the row relative to the row group
239 : * @param aPos - coordinate in twips relative to the
240 : * origin of the row group
241 : * @param aFrameFound - pointer to the cellframe
242 : * @param aPosIsBeforeFirstFrame - the point is before the first originating
243 : * cellframe
244 : * @param aPosIsAfterLastFrame - the point is after the last originating
245 : * cellframe
246 : */
247 : NS_IMETHOD FindFrameAt(int32_t aLineNumber,
248 : nsPoint aPos,
249 : nsIFrame** aFrameFound,
250 : bool* aPosIsBeforeFirstFrame,
251 : bool* aPosIsAfterLastFrame) override;
252 :
253 : /** Check whether visual and logical order of cell frames within a line are
254 : * identical. As the layout will reorder them this is always the case
255 : * @param aLine - the index of the row relative to the table
256 : * @param aIsReordered - returns false
257 : * @param aFirstVisual - if the table is rtl first originating cell frame
258 : * @param aLastVisual - if the table is rtl last originating cell frame
259 : */
260 :
261 : NS_IMETHOD CheckLineOrder(int32_t aLine,
262 : bool *aIsReordered,
263 : nsIFrame **aFirstVisual,
264 : nsIFrame **aLastVisual) override;
265 :
266 : /** Find the next originating cell frame that originates in the row.
267 : * @param aFrame - cell frame to start with, will return the next cell
268 : * originating in a row
269 : * @param aLineNumber - the index of the row relative to the table
270 : */
271 : NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) override;
272 :
273 : // row cursor methods to speed up searching for the row(s)
274 : // containing a point. The basic idea is that we set the cursor
275 : // property if the rows' y and yMosts are non-decreasing (considering only
276 : // rows with nonempty overflowAreas --- empty overflowAreas never participate
277 : // in event handling or painting), and the rowgroup has sufficient number of
278 : // rows. The cursor property points to a "recently used" row. If we get a
279 : // series of requests that work on rows "near" the cursor, then we can find
280 : // those nearby rows quickly by starting our search at the cursor.
281 : // This code is based on the line cursor code in nsBlockFrame. It's more general
282 : // though, and could be extracted and used elsewhere.
283 0 : struct FrameCursorData {
284 : nsTArray<nsIFrame*> mFrames;
285 : uint32_t mCursorIndex;
286 : nscoord mOverflowAbove;
287 : nscoord mOverflowBelow;
288 :
289 0 : FrameCursorData()
290 0 : : mFrames(MIN_ROWS_NEEDING_CURSOR), mCursorIndex(0), mOverflowAbove(0),
291 0 : mOverflowBelow(0) {}
292 :
293 : bool AppendFrame(nsIFrame* aFrame);
294 :
295 0 : void FinishBuildingCursor() {
296 0 : mFrames.Compact();
297 0 : }
298 : };
299 :
300 : // Clear out row cursor because we're disturbing the rows (e.g., Reflow)
301 : void ClearRowCursor();
302 :
303 : /**
304 : * Get the first row that might contain y-coord 'aY', or nullptr if you must search
305 : * all rows.
306 : * The actual row returned might not contain 'aY', but if not, it is guaranteed
307 : * to be before any row which does contain 'aY'.
308 : * aOverflowAbove is the maximum over all rows of -row.GetOverflowRect().y.
309 : * To find all rows that intersect the vertical interval aY/aYMost, call
310 : * GetFirstRowContaining(aY, &overflowAbove), and then iterate through all
311 : * rows until reaching a row where row->GetRect().y - overflowAbove >= aYMost.
312 : * That row and all subsequent rows cannot intersect the interval.
313 : */
314 : nsIFrame* GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove);
315 :
316 : /**
317 : * Set up the row cursor. After this, call AppendFrame for every
318 : * child frame in sibling order. Ensure that the child frame y and YMost values
319 : * form non-decreasing sequences (should always be true for table rows);
320 : * if this is violated, call ClearRowCursor(). If we return nullptr, then we
321 : * decided not to use a cursor or we already have one set up.
322 : */
323 : FrameCursorData* SetupRowCursor();
324 :
325 0 : virtual nsILineIterator* GetLineIterator() override { return this; }
326 :
327 0 : virtual bool IsFrameOfType(uint32_t aFlags) const override
328 : {
329 0 : return nsContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eTablePart));
330 : }
331 :
332 : virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) override;
333 : virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) override;
334 0 : virtual void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); }
335 :
336 : protected:
337 : explicit nsTableRowGroupFrame(nsStyleContext* aContext);
338 :
339 : void InitChildReflowInput(nsPresContext& aPresContext,
340 : bool aBorderCollapse,
341 : ReflowInput& aReflowInput);
342 :
343 : virtual LogicalSides GetLogicalSkipSides(const ReflowInput* aReflowInput = nullptr) const override;
344 :
345 : void PlaceChild(nsPresContext* aPresContext,
346 : TableRowGroupReflowInput& aReflowInput,
347 : nsIFrame* aKidFrame,
348 : mozilla::WritingMode aWM,
349 : const mozilla::LogicalPoint& aKidPosition,
350 : const nsSize& aContainerSize,
351 : ReflowOutput& aDesiredSize,
352 : const nsRect& aOriginalKidRect,
353 : const nsRect& aOriginalKidVisualOverflow);
354 :
355 : void CalculateRowBSizes(nsPresContext* aPresContext,
356 : ReflowOutput& aDesiredSize,
357 : const ReflowInput& aReflowInput);
358 :
359 : void DidResizeRows(ReflowOutput& aDesiredSize);
360 :
361 : void SlideChild(TableRowGroupReflowInput& aReflowInput,
362 : nsIFrame* aKidFrame);
363 :
364 : /**
365 : * Reflow the frames we've already created
366 : *
367 : * @param aPresContext presentation context to use
368 : * @param aReflowInput current inline state
369 : */
370 : void ReflowChildren(nsPresContext* aPresContext,
371 : ReflowOutput& aDesiredSize,
372 : TableRowGroupReflowInput& aReflowInput,
373 : nsReflowStatus& aStatus,
374 : bool* aPageBreakBeforeEnd = nullptr);
375 :
376 : nsresult SplitRowGroup(nsPresContext* aPresContext,
377 : ReflowOutput& aDesiredSize,
378 : const ReflowInput& aReflowInput,
379 : nsTableFrame* aTableFrame,
380 : nsReflowStatus& aStatus,
381 : bool aRowForcedPageBreak);
382 :
383 : void SplitSpanningCells(nsPresContext& aPresContext,
384 : const ReflowInput& aReflowInput,
385 : nsTableFrame& aTableFrame,
386 : nsTableRowFrame& aFirstRow,
387 : nsTableRowFrame& aLastRow,
388 : bool aFirstRowIsTopOfPage,
389 : nscoord aSpanningRowBottom,
390 : nsTableRowFrame*& aContRowFrame,
391 : nsTableRowFrame*& aFirstTruncatedRow,
392 : nscoord& aDesiredHeight);
393 :
394 : void CreateContinuingRowFrame(nsPresContext& aPresContext,
395 : nsIFrame& aRowFrame,
396 : nsIFrame** aContRowFrame);
397 :
398 : bool IsSimpleRowFrame(nsTableFrame* aTableFrame,
399 : nsTableRowFrame* aRowFrame);
400 :
401 : void GetNextRowSibling(nsIFrame** aRowFrame);
402 :
403 : void UndoContinuedRow(nsPresContext* aPresContext,
404 : nsTableRowFrame* aRow);
405 :
406 : private:
407 : // border widths in pixels in the collapsing border model
408 : BCPixelSize mIEndContBorderWidth;
409 : BCPixelSize mBEndContBorderWidth;
410 : BCPixelSize mIStartContBorderWidth;
411 :
412 : public:
413 : bool IsRepeatable() const;
414 : void SetRepeatable(bool aRepeatable);
415 : bool HasStyleBSize() const;
416 : void SetHasStyleBSize(bool aValue);
417 : bool HasInternalBreakBefore() const;
418 : bool HasInternalBreakAfter() const;
419 : };
420 :
421 :
422 0 : inline bool nsTableRowGroupFrame::IsRepeatable() const
423 : {
424 0 : return HasAnyStateBits(NS_ROWGROUP_REPEATABLE);
425 : }
426 :
427 0 : inline void nsTableRowGroupFrame::SetRepeatable(bool aRepeatable)
428 : {
429 0 : if (aRepeatable) {
430 0 : AddStateBits(NS_ROWGROUP_REPEATABLE);
431 : } else {
432 0 : RemoveStateBits(NS_ROWGROUP_REPEATABLE);
433 : }
434 0 : }
435 :
436 0 : inline bool nsTableRowGroupFrame::HasStyleBSize() const
437 : {
438 0 : return HasAnyStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE);
439 : }
440 :
441 0 : inline void nsTableRowGroupFrame::SetHasStyleBSize(bool aValue)
442 : {
443 0 : if (aValue) {
444 0 : AddStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE);
445 : } else {
446 0 : RemoveStateBits(NS_ROWGROUP_HAS_STYLE_BSIZE);
447 : }
448 0 : }
449 :
450 : inline void
451 : nsTableRowGroupFrame::GetContinuousBCBorderWidth(mozilla::WritingMode aWM,
452 : mozilla::LogicalMargin& aBorder)
453 : {
454 : int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
455 : aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
456 : mIEndContBorderWidth);
457 : aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
458 : mBEndContBorderWidth);
459 : aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
460 : mIStartContBorderWidth);
461 : }
462 : #endif
|