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::DidSetStyleContext(nsStyleContext
* aOldStyleContext
)
211 if (!aOldStyleContext
) //avoid this on init
214 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
216 if (tableFrame
->IsBorderCollapse() &&
217 tableFrame
->BCRecalcNeeded(aOldStyleContext
, GetStyleContext())) {
218 PRInt32 colCount
= GetColCount();
220 return; // this is a degenerated colgroup
221 nsRect
damageArea(GetFirstColumn()->GetColIndex(), 0, colCount
,
222 tableFrame
->GetRowCount());
223 tableFrame
->SetBCDamageArea(damageArea
);
229 nsTableColGroupFrame::AppendFrames(nsIAtom
* aListName
,
230 nsIFrame
* aFrameList
)
232 NS_ASSERTION(!aListName
, "unexpected child list");
234 nsTableColFrame
* col
= GetFirstColumn();
235 nsTableColFrame
* nextCol
;
236 while (col
&& col
->GetColType() == eColAnonymousColGroup
) {
237 // this colgroup spans one or more columns but now that there is a
238 // real column below, spanned anonymous columns should be removed,
239 // since the HTML spec says to ignore the span of a colgroup if it
240 // has content columns in it.
241 nextCol
= col
->GetNextCol();
242 RemoveFrame(nsnull
, col
);
246 mFrames
.AppendFrames(this, aFrameList
);
247 InsertColsReflow(GetStartColumnIndex() + mColCount
, aFrameList
);
252 nsTableColGroupFrame::InsertFrames(nsIAtom
* aListName
,
253 nsIFrame
* aPrevFrame
,
254 nsIFrame
* aFrameList
)
256 NS_ASSERTION(!aListName
, "unexpected child list");
257 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
258 "inserting after sibling frame with different parent");
260 nsFrameList
frames(aFrameList
); // convience for getting last frame
261 nsIFrame
* lastFrame
= frames
.LastChild();
263 nsTableColFrame
* col
= GetFirstColumn();
264 nsTableColFrame
* nextCol
;
265 while (col
&& col
->GetColType() == eColAnonymousColGroup
) {
266 // this colgroup spans one or more columns but now that there is a
267 // real column below, spanned anonymous columns should be removed,
268 // since the HTML spec says to ignore the span of a colgroup if it
269 // has content columns in it.
270 NS_ASSERTION(col
!= aPrevFrame
, "Bad aPrevFrame");
271 nextCol
= col
->GetNextCol();
272 RemoveFrame(nsnull
, col
);
276 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
== aPrevFrame
->GetLastContinuation(),
277 "Prev frame should be last in continuation chain");
278 NS_ASSERTION(!aPrevFrame
|| !GetNextColumn(aPrevFrame
) ||
279 GetNextColumn(aPrevFrame
)->GetColType() != eColAnonymousCol
,
280 "Shouldn't be inserting before a spanned colframe");
282 mFrames
.InsertFrames(this, aPrevFrame
, aFrameList
);
283 nsIFrame
* prevFrame
= nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame
,
284 nsGkAtoms::tableColFrame
);
286 PRInt32 colIndex
= (prevFrame
) ? ((nsTableColFrame
*)prevFrame
)->GetColIndex() + 1 : GetStartColumnIndex();
287 InsertColsReflow(colIndex
, aFrameList
, lastFrame
);
293 nsTableColGroupFrame::InsertColsReflow(PRInt32 aColIndex
,
294 nsIFrame
* aFirstFrame
,
295 nsIFrame
* aLastFrame
)
297 AddColsToTable(aColIndex
, PR_TRUE
, aFirstFrame
, aLastFrame
);
299 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
303 PresContext()->PresShell()->FrameNeedsReflow(tableFrame
,
304 nsIPresShell::eTreeChange
,
305 NS_FRAME_HAS_DIRTY_CHILDREN
);
309 nsTableColGroupFrame::RemoveChild(nsTableColFrame
& aChild
,
310 PRBool aResetSubsequentColIndices
)
312 PRInt32 colIndex
= 0;
313 nsIFrame
* nextChild
= nsnull
;
314 if (aResetSubsequentColIndices
) {
315 colIndex
= aChild
.GetColIndex();
316 nextChild
= aChild
.GetNextSibling();
318 if (mFrames
.DestroyFrame((nsIFrame
*)&aChild
)) {
320 if (aResetSubsequentColIndices
) {
321 if (nextChild
) { // reset inside this and all following colgroups
322 ResetColIndices(this, colIndex
, nextChild
);
325 nsIFrame
* nextGroup
= GetNextSibling();
326 if (nextGroup
) // reset next and all following colgroups
327 ResetColIndices(nextGroup
, colIndex
);
331 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
335 PresContext()->PresShell()->FrameNeedsReflow(tableFrame
,
336 nsIPresShell::eTreeChange
,
337 NS_FRAME_HAS_DIRTY_CHILDREN
);
341 nsTableColGroupFrame::RemoveFrame(nsIAtom
* aListName
,
344 NS_ASSERTION(!aListName
, "unexpected child list");
346 if (!aOldFrame
) return NS_OK
;
348 if (nsGkAtoms::tableColFrame
== aOldFrame
->GetType()) {
349 nsTableColFrame
* colFrame
= (nsTableColFrame
*)aOldFrame
;
350 if (colFrame
->GetColType() == eColContent
) {
351 // Remove any anonymous column frames this <col> produced via a colspan
352 nsTableColFrame
* col
= colFrame
->GetNextCol();
353 nsTableColFrame
* nextCol
;
354 while (col
&& col
->GetColType() == eColAnonymousCol
) {
355 NS_ASSERTION(col
->GetStyleContext() == colFrame
->GetStyleContext() &&
356 col
->GetContent() == colFrame
->GetContent(),
357 "How did that happen??");
358 nextCol
= col
->GetNextCol();
359 RemoveFrame(nsnull
, col
);
364 PRInt32 colIndex
= colFrame
->GetColIndex();
365 RemoveChild(*colFrame
, PR_TRUE
);
367 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
369 return NS_ERROR_NULL_POINTER
;
371 tableFrame
->RemoveCol(this, colIndex
, PR_TRUE
, PR_TRUE
);
373 PresContext()->PresShell()->FrameNeedsReflow(tableFrame
,
374 nsIPresShell::eTreeChange
,
375 NS_FRAME_HAS_DIRTY_CHILDREN
);
378 mFrames
.DestroyFrame(aOldFrame
);
385 nsTableColGroupFrame::GetSkipSides() const
388 if (nsnull
!= GetPrevInFlow()) {
389 skip
|= 1 << NS_SIDE_TOP
;
391 if (nsnull
!= GetNextInFlow()) {
392 skip
|= 1 << NS_SIDE_BOTTOM
;
397 NS_METHOD
nsTableColGroupFrame::Reflow(nsPresContext
* aPresContext
,
398 nsHTMLReflowMetrics
& aDesiredSize
,
399 const nsHTMLReflowState
& aReflowState
,
400 nsReflowStatus
& aStatus
)
402 DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame");
403 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
404 NS_ASSERTION(nsnull
!=mContent
, "bad state -- null content for frame");
407 const nsStyleVisibility
* groupVis
= GetStyleVisibility();
408 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
== groupVis
->mVisible
);
410 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
412 tableFrame
->SetNeedToCollapse(PR_TRUE
);;
415 // for every content child that (is a column thingy and does not already have a frame)
416 // create a frame and adjust it's style
418 for (nsIFrame
*kidFrame
= mFrames
.FirstChild(); kidFrame
;
419 kidFrame
= kidFrame
->GetNextSibling()) {
420 // Give the child frame a chance to reflow, even though we know it'll have 0 size
421 nsHTMLReflowMetrics kidSize
;
422 nsHTMLReflowState
kidReflowState(aPresContext
, aReflowState
, kidFrame
,
425 nsReflowStatus status
;
426 ReflowChild(kidFrame
, aPresContext
, kidSize
, kidReflowState
, 0, 0, 0, status
);
427 FinishReflowChild(kidFrame
, aPresContext
, nsnull
, kidSize
, 0, 0, 0);
430 aDesiredSize
.width
=0;
431 aDesiredSize
.height
=0;
432 aStatus
= NS_FRAME_COMPLETE
;
433 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
438 nsTableColGroupFrame::IsContainingBlock() const
443 nsTableColFrame
* nsTableColGroupFrame::GetFirstColumn()
445 return GetNextColumn(nsnull
);
448 nsTableColFrame
* nsTableColGroupFrame::GetNextColumn(nsIFrame
*aChildFrame
)
450 nsTableColFrame
*result
= nsnull
;
451 nsIFrame
*childFrame
= aChildFrame
;
453 childFrame
= mFrames
.FirstChild();
456 childFrame
= childFrame
->GetNextSibling();
460 if (NS_STYLE_DISPLAY_TABLE_COLUMN
==
461 childFrame
->GetStyleDisplay()->mDisplay
)
463 result
= (nsTableColFrame
*)childFrame
;
466 childFrame
= childFrame
->GetNextSibling();
471 PRInt32
nsTableColGroupFrame::GetSpan()
473 return GetStyleTable()->mSpan
;
476 void nsTableColGroupFrame::SetContinuousBCBorderWidth(PRUint8 aForSide
,
477 BCPixelSize aPixelValue
)
481 mTopContBorderWidth
= aPixelValue
;
484 mBottomContBorderWidth
= aPixelValue
;
487 NS_ERROR("invalid side arg");
491 void nsTableColGroupFrame::GetContinuousBCBorderWidth(nsMargin
& aBorder
)
493 PRInt32 aPixelsToTwips
= nsPresContext::AppUnitsPerCSSPixel();
494 nsTableFrame
* table
= nsTableFrame::GetTableFrame(this);
495 nsTableColFrame
* col
= table
->GetColFrame(mStartColIndex
+ mColCount
- 1);
496 col
->GetContinuousBCBorderWidth(aBorder
);
497 aBorder
.top
= BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips
,
498 mTopContBorderWidth
);
499 aBorder
.bottom
= BC_BORDER_TOP_HALF_COORD(aPixelsToTwips
,
500 mBottomContBorderWidth
);
504 /* ----- global methods ----- */
507 NS_NewTableColGroupFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
509 return new (aPresShell
) nsTableColGroupFrame(aContext
);
513 nsTableColGroupFrame::GetType() const
515 return nsGkAtoms::tableColGroupFrame
;
520 nsTableColGroupFrame::GetFrameName(nsAString
& aResult
) const
522 return MakeFrameName(NS_LITERAL_STRING("TableColGroup"), aResult
);
525 void nsTableColGroupFrame::Dump(PRInt32 aIndent
)
527 char* indent
= new char[aIndent
+ 1];
529 for (PRInt32 i
= 0; i
< aIndent
+ 1; i
++) {
534 printf("%s**START COLGROUP DUMP**\n%s startcolIndex=%d colcount=%d span=%d coltype=",
535 indent
, indent
, GetStartColumnIndex(), GetColCount(), GetSpan());
536 nsTableColGroupType colType
= GetColType();
538 case eColGroupContent
:
541 case eColGroupAnonymousCol
:
542 printf(" anonymous-column ");
544 case eColGroupAnonymousCell
:
545 printf(" anonymous-cell ");
548 // verify the colindices
549 PRInt32 j
= GetStartColumnIndex();
550 nsTableColFrame
* col
= GetFirstColumn();
552 NS_ASSERTION(j
== col
->GetColIndex(), "wrong colindex on col frame");
553 col
= col
->GetNextCol();
556 NS_ASSERTION((j
- GetStartColumnIndex()) == GetColCount(),
557 "number of cols out of sync");
558 printf("\n%s**END COLGROUP DUMP** ", indent
);