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
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/
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
15 * The Original Code is mozilla.org code.
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.
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.
36 * ***** END LICENSE BLOCK ***** */
37 #include "nsTableColGroupFrame.h"
38 #include "nsTableColFrame.h"
39 #include "nsTableFrame.h"
40 #include "nsIDOMHTMLTableColElement.h"
41 #include "nsStyleContext.h"
42 #include "nsStyleConsts.h"
43 #include "nsPresContext.h"
44 #include "nsHTMLParts.h"
45 #include "nsGkAtoms.h"
47 #include "nsCSSRendering.h"
48 #include "nsIPresShell.h"
50 #define COL_GROUP_TYPE_BITS 0xC0000000 // uses bits 31-32 from mState
51 #define COL_GROUP_TYPE_OFFSET 30
54 nsTableColGroupFrame::GetColType() const
56 return (nsTableColGroupType
)((mState
& COL_GROUP_TYPE_BITS
) >> COL_GROUP_TYPE_OFFSET
);
59 void nsTableColGroupFrame::SetColType(nsTableColGroupType aType
)
61 PRUint32 type
= aType
- eColGroupContent
;
62 mState
|= (type
<< COL_GROUP_TYPE_OFFSET
);
65 void nsTableColGroupFrame::ResetColIndices(nsIFrame
* aFirstColGroup
,
66 PRInt32 aFirstColIndex
,
67 nsIFrame
* aStartColFrame
)
69 nsTableColGroupFrame
* colGroupFrame
= (nsTableColGroupFrame
*)aFirstColGroup
;
70 PRInt32 colIndex
= aFirstColIndex
;
71 while (colGroupFrame
) {
72 if (nsGkAtoms::tableColGroupFrame
== colGroupFrame
->GetType()) {
73 // reset the starting col index for the first cg only if we should reset
74 // the whole colgroup (aStartColFrame defaults to nsnull) or if
75 // aFirstColIndex is smaller than the existing starting col index
76 if ((colIndex
!= aFirstColIndex
) ||
77 (colIndex
< colGroupFrame
->GetStartColumnIndex()) ||
79 colGroupFrame
->SetStartColumnIndex(colIndex
);
81 nsIFrame
* colFrame
= aStartColFrame
;
82 if (!colFrame
|| (colIndex
!= aFirstColIndex
)) {
83 colFrame
= colGroupFrame
->GetFirstChild(nsnull
);
86 if (nsGkAtoms::tableColFrame
== colFrame
->GetType()) {
87 ((nsTableColFrame
*)colFrame
)->SetColIndex(colIndex
);
90 colFrame
= colFrame
->GetNextSibling();
93 colGroupFrame
= static_cast<nsTableColGroupFrame
*>
94 (colGroupFrame
->GetNextSibling());
100 nsTableColGroupFrame::AddColsToTable(PRInt32 aFirstColIndex
,
101 PRBool aResetSubsequentColIndices
,
102 nsIFrame
* aFirstFrame
,
103 nsIFrame
* aLastFrame
)
106 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
107 if (!tableFrame
|| !aFirstFrame
)
108 return NS_ERROR_NULL_POINTER
;
110 // set the col indices of the col frames and and add col info to the table
111 PRInt32 colIndex
= aFirstColIndex
;
112 nsIFrame
* kidFrame
= aFirstFrame
;
113 PRBool foundLastFrame
= PR_FALSE
;
115 if (nsGkAtoms::tableColFrame
== kidFrame
->GetType()) {
116 ((nsTableColFrame
*)kidFrame
)->SetColIndex(colIndex
);
117 if (!foundLastFrame
) {
119 tableFrame
->InsertCol((nsTableColFrame
&)*kidFrame
, colIndex
);
123 if (kidFrame
== aLastFrame
) {
124 foundLastFrame
= PR_TRUE
;
126 kidFrame
= kidFrame
->GetNextSibling();
128 // We have already set the colindex for all the colframes in this
129 // colgroup that come after the first inserted colframe, but there could
130 // be other colgroups following this one and their colframes need
131 // correct colindices too.
132 if (aResetSubsequentColIndices
&& GetNextSibling()) {
133 ResetColIndices(GetNextSibling(), colIndex
);
141 nsTableColGroupFrame::GetLastRealColGroup(nsTableFrame
* aTableFrame
,
142 nsIFrame
** aLastColGroup
)
144 *aLastColGroup
= nsnull
;
145 nsFrameList colGroups
= aTableFrame
->GetColGroups();
147 nsIFrame
* nextToLastColGroup
= nsnull
;
148 nsIFrame
* lastColGroup
= colGroups
.FirstChild();
149 while(lastColGroup
) {
150 nsIFrame
* next
= lastColGroup
->GetNextSibling();
152 nextToLastColGroup
= lastColGroup
;
160 if (!lastColGroup
) return PR_TRUE
; // there are no col group frames
162 nsTableColGroupType lastColGroupType
=
163 ((nsTableColGroupFrame
*)lastColGroup
)->GetColType();
164 if (eColGroupAnonymousCell
== lastColGroupType
) {
165 *aLastColGroup
= nextToLastColGroup
;
169 *aLastColGroup
= lastColGroup
;
174 // don't set mColCount here, it is done in AddColsToTable
176 nsTableColGroupFrame::SetInitialChildList(nsIAtom
* aListName
,
177 nsIFrame
* aChildList
)
179 if (!mFrames
.IsEmpty()) {
180 // We already have child frames which means we've already been
182 NS_NOTREACHED("unexpected second call to SetInitialChildList");
183 return NS_ERROR_UNEXPECTED
;
186 // All we know about is the unnamed principal child list
187 NS_NOTREACHED("unknown frame list");
188 return NS_ERROR_INVALID_ARG
;
190 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
192 return NS_ERROR_NULL_POINTER
;
195 nsIFrame
* firstChild
;
196 tableFrame
->CreateAnonymousColFrames(this, GetSpan(), eColAnonymousColGroup
,
197 PR_FALSE
, nsnull
, &firstChild
);
199 SetInitialChildList(aListName
, firstChild
);
204 mFrames
.AppendFrames(this, aChildList
);
209 nsTableColGroupFrame::AppendFrames(nsIAtom
* aListName
,
210 nsIFrame
* aFrameList
)
212 NS_ASSERTION(!aListName
, "unexpected child list");
214 nsTableColFrame
* col
= GetFirstColumn();
215 nsTableColFrame
* nextCol
;
216 while (col
&& col
->GetColType() == eColAnonymousColGroup
) {
217 // this colgroup spans one or more columns but now that there is a
218 // real column below, spanned anonymous columns should be removed,
219 // since the HTML spec says to ignore the span of a colgroup if it
220 // has content columns in it.
221 nextCol
= col
->GetNextCol();
222 RemoveFrame(nsnull
, col
);
226 mFrames
.AppendFrames(this, aFrameList
);
227 InsertColsReflow(GetStartColumnIndex() + mColCount
, aFrameList
);
232 nsTableColGroupFrame::InsertFrames(nsIAtom
* aListName
,
233 nsIFrame
* aPrevFrame
,
234 nsIFrame
* aFrameList
)
236 NS_ASSERTION(!aListName
, "unexpected child list");
237 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
238 "inserting after sibling frame with different parent");
240 nsFrameList
frames(aFrameList
); // convience for getting last frame
241 nsIFrame
* lastFrame
= frames
.LastChild();
243 nsTableColFrame
* col
= GetFirstColumn();
244 nsTableColFrame
* nextCol
;
245 while (col
&& col
->GetColType() == eColAnonymousColGroup
) {
246 // this colgroup spans one or more columns but now that there is a
247 // real column below, spanned anonymous columns should be removed,
248 // since the HTML spec says to ignore the span of a colgroup if it
249 // has content columns in it.
250 NS_ASSERTION(col
!= aPrevFrame
, "Bad aPrevFrame");
251 nextCol
= col
->GetNextCol();
252 RemoveFrame(nsnull
, col
);
256 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
== aPrevFrame
->GetLastContinuation(),
257 "Prev frame should be last in continuation chain");
258 NS_ASSERTION(!aPrevFrame
|| !GetNextColumn(aPrevFrame
) ||
259 GetNextColumn(aPrevFrame
)->GetColType() != eColAnonymousCol
,
260 "Shouldn't be inserting before a spanned colframe");
262 mFrames
.InsertFrames(this, aPrevFrame
, aFrameList
);
263 nsIFrame
* prevFrame
= nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame
,
264 nsGkAtoms::tableColFrame
);
266 PRInt32 colIndex
= (prevFrame
) ? ((nsTableColFrame
*)prevFrame
)->GetColIndex() + 1 : GetStartColumnIndex();
267 InsertColsReflow(colIndex
, aFrameList
, lastFrame
);
273 nsTableColGroupFrame::InsertColsReflow(PRInt32 aColIndex
,
274 nsIFrame
* aFirstFrame
,
275 nsIFrame
* aLastFrame
)
277 AddColsToTable(aColIndex
, PR_TRUE
, aFirstFrame
, aLastFrame
);
279 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
283 PresContext()->PresShell()->FrameNeedsReflow(tableFrame
,
284 nsIPresShell::eTreeChange
,
285 NS_FRAME_HAS_DIRTY_CHILDREN
);
289 nsTableColGroupFrame::RemoveChild(nsTableColFrame
& aChild
,
290 PRBool aResetSubsequentColIndices
)
292 PRInt32 colIndex
= 0;
293 nsIFrame
* nextChild
= nsnull
;
294 if (aResetSubsequentColIndices
) {
295 colIndex
= aChild
.GetColIndex();
296 nextChild
= aChild
.GetNextSibling();
298 if (mFrames
.DestroyFrame((nsIFrame
*)&aChild
)) {
300 if (aResetSubsequentColIndices
) {
301 if (nextChild
) { // reset inside this and all following colgroups
302 ResetColIndices(this, colIndex
, nextChild
);
305 nsIFrame
* nextGroup
= GetNextSibling();
306 if (nextGroup
) // reset next and all following colgroups
307 ResetColIndices(nextGroup
, colIndex
);
311 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
315 PresContext()->PresShell()->FrameNeedsReflow(tableFrame
,
316 nsIPresShell::eTreeChange
,
317 NS_FRAME_HAS_DIRTY_CHILDREN
);
321 nsTableColGroupFrame::RemoveFrame(nsIAtom
* aListName
,
324 NS_ASSERTION(!aListName
, "unexpected child list");
326 if (!aOldFrame
) return NS_OK
;
328 if (nsGkAtoms::tableColFrame
== aOldFrame
->GetType()) {
329 nsTableColFrame
* colFrame
= (nsTableColFrame
*)aOldFrame
;
330 if (colFrame
->GetColType() == eColContent
) {
331 // Remove any anonymous column frames this <col> produced via a colspan
332 nsTableColFrame
* col
= colFrame
->GetNextCol();
333 nsTableColFrame
* nextCol
;
334 while (col
&& col
->GetColType() == eColAnonymousCol
) {
335 NS_ASSERTION(col
->GetStyleContext() == colFrame
->GetStyleContext() &&
336 col
->GetContent() == colFrame
->GetContent(),
337 "How did that happen??");
338 nextCol
= col
->GetNextCol();
339 RemoveFrame(nsnull
, col
);
344 PRInt32 colIndex
= colFrame
->GetColIndex();
345 RemoveChild(*colFrame
, PR_TRUE
);
347 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
349 return NS_ERROR_NULL_POINTER
;
351 tableFrame
->RemoveCol(this, colIndex
, PR_TRUE
, PR_TRUE
);
353 PresContext()->PresShell()->FrameNeedsReflow(tableFrame
,
354 nsIPresShell::eTreeChange
,
355 NS_FRAME_HAS_DIRTY_CHILDREN
);
358 mFrames
.DestroyFrame(aOldFrame
);
365 nsTableColGroupFrame::GetSkipSides() const
368 if (nsnull
!= GetPrevInFlow()) {
369 skip
|= 1 << NS_SIDE_TOP
;
371 if (nsnull
!= GetNextInFlow()) {
372 skip
|= 1 << NS_SIDE_BOTTOM
;
377 NS_METHOD
nsTableColGroupFrame::Reflow(nsPresContext
* aPresContext
,
378 nsHTMLReflowMetrics
& aDesiredSize
,
379 const nsHTMLReflowState
& aReflowState
,
380 nsReflowStatus
& aStatus
)
382 DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame");
383 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
384 NS_ASSERTION(nsnull
!=mContent
, "bad state -- null content for frame");
387 const nsStyleVisibility
* groupVis
= GetStyleVisibility();
388 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
== groupVis
->mVisible
);
390 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
392 tableFrame
->SetNeedToCollapse(PR_TRUE
);;
395 // for every content child that (is a column thingy and does not already have a frame)
396 // create a frame and adjust it's style
398 for (nsIFrame
*kidFrame
= mFrames
.FirstChild(); kidFrame
;
399 kidFrame
= kidFrame
->GetNextSibling()) {
400 // Give the child frame a chance to reflow, even though we know it'll have 0 size
401 nsHTMLReflowMetrics kidSize
;
402 nsHTMLReflowState
kidReflowState(aPresContext
, aReflowState
, kidFrame
,
405 nsReflowStatus status
;
406 ReflowChild(kidFrame
, aPresContext
, kidSize
, kidReflowState
, 0, 0, 0, status
);
407 FinishReflowChild(kidFrame
, aPresContext
, nsnull
, kidSize
, 0, 0, 0);
410 aDesiredSize
.width
=0;
411 aDesiredSize
.height
=0;
412 aStatus
= NS_FRAME_COMPLETE
;
413 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
418 nsTableColGroupFrame::IsContainingBlock() const
423 nsTableColFrame
* nsTableColGroupFrame::GetFirstColumn()
425 return GetNextColumn(nsnull
);
428 nsTableColFrame
* nsTableColGroupFrame::GetNextColumn(nsIFrame
*aChildFrame
)
430 nsTableColFrame
*result
= nsnull
;
431 nsIFrame
*childFrame
= aChildFrame
;
433 childFrame
= mFrames
.FirstChild();
436 childFrame
= childFrame
->GetNextSibling();
440 if (NS_STYLE_DISPLAY_TABLE_COLUMN
==
441 childFrame
->GetStyleDisplay()->mDisplay
)
443 result
= (nsTableColFrame
*)childFrame
;
446 childFrame
= childFrame
->GetNextSibling();
451 PRInt32
nsTableColGroupFrame::GetSpan()
453 return GetStyleTable()->mSpan
;
456 void nsTableColGroupFrame::SetContinuousBCBorderWidth(PRUint8 aForSide
,
457 BCPixelSize aPixelValue
)
461 mTopContBorderWidth
= aPixelValue
;
464 mBottomContBorderWidth
= aPixelValue
;
467 NS_ERROR("invalid side arg");
471 void nsTableColGroupFrame::GetContinuousBCBorderWidth(nsMargin
& aBorder
)
473 PRInt32 aPixelsToTwips
= nsPresContext::AppUnitsPerCSSPixel();
474 nsTableFrame
* table
= nsTableFrame::GetTableFrame(this);
475 nsTableColFrame
* col
= table
->GetColFrame(mStartColIndex
+ mColCount
- 1);
476 col
->GetContinuousBCBorderWidth(aBorder
);
477 aBorder
.top
= BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips
,
478 mTopContBorderWidth
);
479 aBorder
.bottom
= BC_BORDER_TOP_HALF_COORD(aPixelsToTwips
,
480 mBottomContBorderWidth
);
484 /* ----- global methods ----- */
487 NS_NewTableColGroupFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
489 return new (aPresShell
) nsTableColGroupFrame(aContext
);
493 nsTableColGroupFrame::GetType() const
495 return nsGkAtoms::tableColGroupFrame
;
500 nsTableColGroupFrame::GetFrameName(nsAString
& aResult
) const
502 return MakeFrameName(NS_LITERAL_STRING("TableColGroup"), aResult
);
505 void nsTableColGroupFrame::Dump(PRInt32 aIndent
)
507 char* indent
= new char[aIndent
+ 1];
509 for (PRInt32 i
= 0; i
< aIndent
+ 1; i
++) {
514 printf("%s**START COLGROUP DUMP**\n%s startcolIndex=%d colcount=%d span=%d coltype=",
515 indent
, indent
, GetStartColumnIndex(), GetColCount(), GetSpan());
516 nsTableColGroupType colType
= GetColType();
518 case eColGroupContent
:
521 case eColGroupAnonymousCol
:
522 printf(" anonymous-column ");
524 case eColGroupAnonymousCell
:
525 printf(" anonymous-cell ");
528 // verify the colindices
529 PRInt32 j
= GetStartColumnIndex();
530 nsTableColFrame
* col
= GetFirstColumn();
532 NS_ASSERTION(j
== col
->GetColIndex(), "wrong colindex on col frame");
533 col
= col
->GetNextCol();
536 NS_ASSERTION((j
- GetStartColumnIndex()) == GetColCount(),
537 "number of cols out of sync");
538 printf("\n%s**END COLGROUP DUMP** ", indent
);