1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : #ifndef nsTableRowGroupFrame_h__
38 : #define nsTableRowGroupFrame_h__
39 :
40 : #include "nscore.h"
41 : #include "nsContainerFrame.h"
42 : #include "nsIAtom.h"
43 : #include "nsILineIterator.h"
44 : #include "nsTablePainter.h"
45 : #include "nsTArray.h"
46 :
47 : class nsTableFrame;
48 : class nsTableRowFrame;
49 : class nsTableCellFrame;
50 :
51 : struct nsRowGroupReflowState {
52 : const nsHTMLReflowState& reflowState; // Our reflow state
53 :
54 : nsTableFrame* tableFrame;
55 :
56 : // The available size (computed from the parent)
57 : nsSize availSize;
58 :
59 : // Running y-offset
60 : nscoord y;
61 :
62 0 : nsRowGroupReflowState(const nsHTMLReflowState& aReflowState,
63 : nsTableFrame* aTableFrame)
64 0 : :reflowState(aReflowState), tableFrame(aTableFrame)
65 : {
66 0 : availSize.width = reflowState.availableWidth;
67 0 : availSize.height = reflowState.availableHeight;
68 0 : y = 0;
69 0 : }
70 :
71 0 : ~nsRowGroupReflowState() {}
72 : };
73 :
74 : // use the following bits from nsFrame's frame state
75 :
76 : // thead or tfoot should be repeated on every printed page
77 : #define NS_ROWGROUP_REPEATABLE NS_FRAME_STATE_BIT(31)
78 : #define NS_ROWGROUP_HAS_STYLE_HEIGHT NS_FRAME_STATE_BIT(30)
79 : // the next is also used on rows (see nsTableRowGroupFrame::InitRepeatedFrame)
80 : #define NS_REPEATED_ROW_OR_ROWGROUP NS_FRAME_STATE_BIT(28)
81 : #define NS_ROWGROUP_HAS_ROW_CURSOR NS_FRAME_STATE_BIT(27)
82 :
83 : #define MIN_ROWS_NEEDING_CURSOR 20
84 :
85 : /**
86 : * nsTableRowGroupFrame is the frame that maps row groups
87 : * (HTML tags THEAD, TFOOT, and TBODY). This class cannot be reused
88 : * outside of an nsTableFrame. It assumes that its parent is an nsTableFrame, and
89 : * its children are nsTableRowFrames.
90 : *
91 : * @see nsTableFrame
92 : * @see nsTableRowFrame
93 : */
94 : class nsTableRowGroupFrame
95 : : public nsContainerFrame
96 : , public nsILineIterator
97 : {
98 : public:
99 : NS_DECL_QUERYFRAME_TARGET(nsTableRowGroupFrame)
100 : NS_DECL_QUERYFRAME
101 : NS_DECL_FRAMEARENA_HELPERS
102 :
103 : /** instantiate a new instance of nsTableRowFrame.
104 : * @param aPresShell the pres shell for this frame
105 : *
106 : * @return the frame that was created
107 : */
108 : friend nsIFrame* NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
109 : virtual ~nsTableRowGroupFrame();
110 : /** @see nsIFrame::DidSetStyleContext */
111 : virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext);
112 :
113 : NS_IMETHOD AppendFrames(ChildListID aListID,
114 : nsFrameList& aFrameList);
115 :
116 : NS_IMETHOD InsertFrames(ChildListID aListID,
117 : nsIFrame* aPrevFrame,
118 : nsFrameList& aFrameList);
119 :
120 : NS_IMETHOD RemoveFrame(ChildListID aListID,
121 : nsIFrame* aOldFrame);
122 :
123 : virtual nsMargin GetUsedMargin() const;
124 : virtual nsMargin GetUsedBorder() const;
125 : virtual nsMargin GetUsedPadding() const;
126 :
127 : NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
128 : const nsRect& aDirtyRect,
129 : const nsDisplayListSet& aLists);
130 :
131 : /** calls Reflow for all of its child rows.
132 : * Rows are all set to the same width and stacked vertically.
133 : * <P> rows are not split unless absolutely necessary.
134 : *
135 : * @param aDesiredSize width set to width of rows, height set to
136 : * sum of height of rows that fit in aMaxSize.height.
137 : *
138 : * @see nsIFrame::Reflow
139 : */
140 : NS_IMETHOD Reflow(nsPresContext* aPresContext,
141 : nsHTMLReflowMetrics& aDesiredSize,
142 : const nsHTMLReflowState& aReflowState,
143 : nsReflowStatus& aStatus);
144 :
145 : /**
146 : * Get the "type" of the frame
147 : *
148 : * @see nsGkAtoms::tableRowGroupFrame
149 : */
150 : virtual nsIAtom* GetType() const;
151 :
152 : nsTableRowFrame* GetFirstRow();
153 :
154 : #ifdef DEBUG
155 : NS_IMETHOD GetFrameName(nsAString& aResult) const;
156 : #endif
157 :
158 : /** return the number of child rows (not necessarily == number of child frames) */
159 : PRInt32 GetRowCount();
160 :
161 : /** return the table-relative row index of the first row in this rowgroup.
162 : * if there are no rows, -1 is returned.
163 : */
164 : PRInt32 GetStartRowIndex();
165 :
166 : /** Adjust the row indices of all rows whose index is >= aRowIndex.
167 : * @param aRowIndex - start adjusting with this index
168 : * @param aAdjustment - shift the row index by this amount
169 : */
170 : void AdjustRowIndices(PRInt32 aRowIndex,
171 : PRInt32 anAdjustment);
172 :
173 : /**
174 : * Used for header and footer row group frames that are repeated when
175 : * splitting a table frame.
176 : *
177 : * Performs any table specific initialization
178 : *
179 : * @param aHeaderFooterFrame the original header or footer row group frame
180 : * that was repeated
181 : */
182 : nsresult InitRepeatedFrame(nsPresContext* aPresContext,
183 : nsTableRowGroupFrame* aHeaderFooterFrame);
184 :
185 :
186 : /**
187 : * Get the total height of all the row rects
188 : */
189 : nscoord GetHeightBasis(const nsHTMLReflowState& aReflowState);
190 :
191 : nsMargin* GetBCBorderWidth(nsMargin& aBorder);
192 :
193 : /**
194 : * Gets inner border widths before collapsing with cell borders
195 : * Caller must get top border from previous row group or from table
196 : * GetContinuousBCBorderWidth will not overwrite aBorder.top
197 : * see nsTablePainter about continuous borders
198 : */
199 : void GetContinuousBCBorderWidth(nsMargin& aBorder);
200 : /**
201 : * Sets full border widths before collapsing with cell borders
202 : * @param aForSide - side to set; only right, left, and bottom valid
203 : */
204 : void SetContinuousBCBorderWidth(PRUint8 aForSide,
205 : BCPixelSize aPixelValue);
206 : /**
207 : * Adjust to the effect of visibibility:collapse on the row group and
208 : * its children
209 : * @return additional shift upward that should be applied to
210 : * subsequent rowgroups due to rows and this rowgroup
211 : * being collapsed
212 : * @param aYTotalOffset the total amount that the rowgroup is shifted up
213 : * @param aWidth new width of the rowgroup
214 : */
215 : nscoord CollapseRowGroupIfNecessary(nscoord aYTotalOffset,
216 : nscoord aWidth);
217 :
218 : // nsILineIterator methods
219 : public:
220 0 : virtual void DisposeLineIterator() { }
221 :
222 : // The table row is the equivalent to a line in block layout.
223 : // The nsILineIterator assumes that a line resides in a block, this role is
224 : // fullfilled by the row group. Rows in table are counted relative to the
225 : // table. The row index of row corresponds to the cellmap coordinates. The
226 : // line index with respect to a row group can be computed by substracting the
227 : // row index of the first row in the row group.
228 :
229 : /** Get the number of rows in a row group
230 : * @return the number of lines in a row group
231 : */
232 : virtual PRInt32 GetNumLines();
233 :
234 : /** @see nsILineIterator.h GetDirection
235 : * @return true if the table is rtl
236 : */
237 : virtual bool GetDirection();
238 :
239 : /** Return structural information about a line.
240 : * @param aLineNumber - the index of the row relative to the row group
241 : * If the line-number is invalid then
242 : * aFirstFrameOnLine will be nsnull and
243 : * aNumFramesOnLine will be zero.
244 : * @param aFirstFrameOnLine - the first cell frame that originates in row
245 : * with a rowindex that matches a line number
246 : * @param aNumFramesOnLine - return the numbers of cells originating in
247 : * this row
248 : * @param aLineBounds - rect of the row
249 : * @param aLineFlags - unused set to 0
250 : */
251 : NS_IMETHOD GetLine(PRInt32 aLineNumber,
252 : nsIFrame** aFirstFrameOnLine,
253 : PRInt32* aNumFramesOnLine,
254 : nsRect& aLineBounds,
255 : PRUint32* aLineFlags);
256 :
257 : /** Given a frame that's a child of the rowgroup, find which line its on.
258 : * @param aFrame - frame, should be a row
259 : * @param aStartLine - minimal index to return
260 : * @return row index relative to the row group if this a row
261 : * frame and the index is at least aStartLine.
262 : * -1 if the frame cannot be found.
263 : */
264 : virtual PRInt32 FindLineContaining(nsIFrame* aFrame, PRInt32 aStartLine = 0);
265 :
266 : /** Find the orginating cell frame on a row that is the nearest to the
267 : * coordinate X.
268 : * @param aLineNumber - the index of the row relative to the row group
269 : * @param aX - X coordinate in twips relative to the
270 : * origin of the row group
271 : * @param aFrameFound - pointer to the cellframe
272 : * @param aXIsBeforeFirstFrame - the point is before the first originating
273 : * cellframe
274 : * @param aXIsAfterLastFrame - the point is after the last originating
275 : * cellframe
276 : */
277 : NS_IMETHOD FindFrameAt(PRInt32 aLineNumber,
278 : nscoord aX,
279 : nsIFrame** aFrameFound,
280 : bool* aXIsBeforeFirstFrame,
281 : bool* aXIsAfterLastFrame);
282 :
283 : #ifdef IBMBIDI
284 : /** Check whether visual and logical order of cell frames within a line are
285 : * identical. As the layout will reorder them this is always the case
286 : * @param aLine - the index of the row relative to the table
287 : * @param aIsReordered - returns false
288 : * @param aFirstVisual - if the table is rtl first originating cell frame
289 : * @param aLastVisual - if the table is rtl last originating cell frame
290 : */
291 :
292 : NS_IMETHOD CheckLineOrder(PRInt32 aLine,
293 : bool *aIsReordered,
294 : nsIFrame **aFirstVisual,
295 : nsIFrame **aLastVisual);
296 : #endif
297 :
298 : /** Find the next originating cell frame that originates in the row.
299 : * @param aFrame - cell frame to start with, will return the next cell
300 : * originating in a row
301 : * @param aLineNumber - the index of the row relative to the table
302 : */
303 : NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, PRInt32 aLineNumber);
304 :
305 : // row cursor methods to speed up searching for the row(s)
306 : // containing a point. The basic idea is that we set the cursor
307 : // property if the rows' y and yMosts are non-decreasing (considering only
308 : // rows with nonempty overflowAreas --- empty overflowAreas never participate
309 : // in event handling or painting), and the rowgroup has sufficient number of
310 : // rows. The cursor property points to a "recently used" row. If we get a
311 : // series of requests that work on rows "near" the cursor, then we can find
312 : // those nearby rows quickly by starting our search at the cursor.
313 : // This code is based on the line cursor code in nsBlockFrame. It's more general
314 : // though, and could be extracted and used elsewhere.
315 0 : struct FrameCursorData {
316 : nsTArray<nsIFrame*> mFrames;
317 : PRUint32 mCursorIndex;
318 : nscoord mOverflowAbove;
319 : nscoord mOverflowBelow;
320 :
321 0 : FrameCursorData()
322 : : mFrames(MIN_ROWS_NEEDING_CURSOR), mCursorIndex(0), mOverflowAbove(0),
323 0 : mOverflowBelow(0) {}
324 :
325 : bool AppendFrame(nsIFrame* aFrame);
326 :
327 0 : void FinishBuildingCursor() {
328 0 : mFrames.Compact();
329 0 : }
330 : };
331 :
332 : // Clear out row cursor because we're disturbing the rows (e.g., Reflow)
333 : void ClearRowCursor();
334 :
335 : /**
336 : * Get the first row that might contain y-coord 'aY', or nsnull if you must search
337 : * all rows.
338 : * The actual row returned might not contain 'aY', but if not, it is guaranteed
339 : * to be before any row which does contain 'aY'.
340 : * aOverflowAbove is the maximum over all rows of -row.GetOverflowRect().y.
341 : * To find all rows that intersect the vertical interval aY/aYMost, call
342 : * GetFirstRowContaining(aY, &overflowAbove), and then iterate through all
343 : * rows until reaching a row where row->GetRect().y - overflowAbove >= aYMost.
344 : * That row and all subsequent rows cannot intersect the interval.
345 : */
346 : nsIFrame* GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove);
347 :
348 : /**
349 : * Set up the row cursor. After this, call AppendFrame for every
350 : * child frame in sibling order. Ensure that the child frame y and YMost values
351 : * form non-decreasing sequences (should always be true for table rows);
352 : * if this is violated, call ClearRowCursor(). If we return nsnull, then we
353 : * decided not to use a cursor or we already have one set up.
354 : */
355 : FrameCursorData* SetupRowCursor();
356 :
357 0 : virtual nsILineIterator* GetLineIterator() { return this; }
358 :
359 : protected:
360 : nsTableRowGroupFrame(nsStyleContext* aContext);
361 :
362 : void InitChildReflowState(nsPresContext& aPresContext,
363 : bool aBorderCollapse,
364 : nsHTMLReflowState& aReflowState);
365 :
366 : /** implement abstract method on nsContainerFrame */
367 : virtual PRIntn GetSkipSides() const;
368 :
369 : void PlaceChild(nsPresContext* aPresContext,
370 : nsRowGroupReflowState& aReflowState,
371 : nsIFrame* aKidFrame,
372 : nsHTMLReflowMetrics& aDesiredSize,
373 : const nsRect& aOriginalKidRect,
374 : const nsRect& aOriginalKidVisualOverflow);
375 :
376 : void CalculateRowHeights(nsPresContext* aPresContext,
377 : nsHTMLReflowMetrics& aDesiredSize,
378 : const nsHTMLReflowState& aReflowState);
379 :
380 : void DidResizeRows(nsHTMLReflowMetrics& aDesiredSize);
381 :
382 : void SlideChild(nsRowGroupReflowState& aReflowState,
383 : nsIFrame* aKidFrame);
384 :
385 : /**
386 : * Reflow the frames we've already created
387 : *
388 : * @param aPresContext presentation context to use
389 : * @param aReflowState current inline state
390 : * @return true if we successfully reflowed all the mapped children and false
391 : * otherwise, e.g. we pushed children to the next in flow
392 : */
393 : nsresult ReflowChildren(nsPresContext* aPresContext,
394 : nsHTMLReflowMetrics& aDesiredSize,
395 : nsRowGroupReflowState& aReflowState,
396 : nsReflowStatus& aStatus,
397 : bool* aPageBreakBeforeEnd = nsnull);
398 :
399 : nsresult SplitRowGroup(nsPresContext* aPresContext,
400 : nsHTMLReflowMetrics& aDesiredSize,
401 : const nsHTMLReflowState& aReflowState,
402 : nsTableFrame* aTableFrame,
403 : nsReflowStatus& aStatus);
404 :
405 : void SplitSpanningCells(nsPresContext& aPresContext,
406 : const nsHTMLReflowState& aReflowState,
407 : nsTableFrame& aTableFrame,
408 : nsTableRowFrame& aFirstRow,
409 : nsTableRowFrame& aLastRow,
410 : bool aFirstRowIsTopOfPage,
411 : nscoord aSpanningRowBottom,
412 : nsTableRowFrame*& aContRowFrame,
413 : nsTableRowFrame*& aFirstTruncatedRow,
414 : nscoord& aDesiredHeight);
415 :
416 : void CreateContinuingRowFrame(nsPresContext& aPresContext,
417 : nsIFrame& aRowFrame,
418 : nsIFrame** aContRowFrame);
419 :
420 : bool IsSimpleRowFrame(nsTableFrame* aTableFrame,
421 : nsIFrame* aFrame);
422 :
423 : void GetNextRowSibling(nsIFrame** aRowFrame);
424 :
425 : void UndoContinuedRow(nsPresContext* aPresContext,
426 : nsTableRowFrame* aRow);
427 :
428 : private:
429 : // border widths in pixels in the collapsing border model
430 : BCPixelSize mRightContBorderWidth;
431 : BCPixelSize mBottomContBorderWidth;
432 : BCPixelSize mLeftContBorderWidth;
433 :
434 : public:
435 : bool IsRepeatable() const;
436 : void SetRepeatable(bool aRepeatable);
437 : bool HasStyleHeight() const;
438 : void SetHasStyleHeight(bool aValue);
439 : bool HasInternalBreakBefore() const;
440 : bool HasInternalBreakAfter() const;
441 : };
442 :
443 :
444 0 : inline bool nsTableRowGroupFrame::IsRepeatable() const
445 : {
446 0 : return (mState & NS_ROWGROUP_REPEATABLE) == NS_ROWGROUP_REPEATABLE;
447 : }
448 :
449 0 : inline void nsTableRowGroupFrame::SetRepeatable(bool aRepeatable)
450 : {
451 0 : if (aRepeatable) {
452 0 : mState |= NS_ROWGROUP_REPEATABLE;
453 : } else {
454 0 : mState &= ~NS_ROWGROUP_REPEATABLE;
455 : }
456 0 : }
457 :
458 0 : inline bool nsTableRowGroupFrame::HasStyleHeight() const
459 : {
460 0 : return (mState & NS_ROWGROUP_HAS_STYLE_HEIGHT) == NS_ROWGROUP_HAS_STYLE_HEIGHT;
461 : }
462 :
463 0 : inline void nsTableRowGroupFrame::SetHasStyleHeight(bool aValue)
464 : {
465 0 : if (aValue) {
466 0 : mState |= NS_ROWGROUP_HAS_STYLE_HEIGHT;
467 : } else {
468 0 : mState &= ~NS_ROWGROUP_HAS_STYLE_HEIGHT;
469 : }
470 0 : }
471 :
472 : inline void
473 0 : nsTableRowGroupFrame::GetContinuousBCBorderWidth(nsMargin& aBorder)
474 : {
475 0 : PRInt32 aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
476 : aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips,
477 0 : mRightContBorderWidth);
478 : aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips,
479 0 : mBottomContBorderWidth);
480 : aBorder.left = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips,
481 0 : mLeftContBorderWidth);
482 : return;
483 : }
484 : #endif
|