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 const nsFrameList::Slice
& aCols
)
105 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
107 return NS_ERROR_NULL_POINTER
;
109 // set the col indices of the col frames and and add col info to the table
110 PRInt32 colIndex
= aFirstColIndex
;
111 nsFrameList::Enumerator
e(aCols
);
112 for (; !e
.AtEnd(); e
.Next()) {
113 ((nsTableColFrame
*)e
.get())->SetColIndex(colIndex
);
115 tableFrame
->InsertCol((nsTableColFrame
&)*e
.get(), colIndex
);
119 for (nsFrameList::Enumerator eTail
= e
.GetUnlimitedEnumerator();
122 ((nsTableColFrame
*)eTail
.get())->SetColIndex(colIndex
);
126 // We have already set the colindex for all the colframes in this
127 // colgroup that come after the first inserted colframe, but there could
128 // be other colgroups following this one and their colframes need
129 // correct colindices too.
130 if (aResetSubsequentColIndices
&& GetNextSibling()) {
131 ResetColIndices(GetNextSibling(), colIndex
);
138 nsTableColGroupFrame
*
139 nsTableColGroupFrame::GetLastRealColGroup(nsTableFrame
* aTableFrame
)
141 nsFrameList colGroups
= aTableFrame
->GetColGroups();
143 nsIFrame
* nextToLastColGroup
= nsnull
;
144 nsFrameList::FrameLinkEnumerator
link(colGroups
);
145 for ( ; !link
.AtEnd(); link
.Next()) {
146 nextToLastColGroup
= link
.PrevFrame();
149 if (!link
.PrevFrame()) {
150 return nsnull
; // there are no col group frames
153 nsTableColGroupType lastColGroupType
=
154 static_cast<nsTableColGroupFrame
*>(link
.PrevFrame())->GetColType();
155 if (eColGroupAnonymousCell
== lastColGroupType
) {
156 return static_cast<nsTableColGroupFrame
*>(nextToLastColGroup
);
159 return static_cast<nsTableColGroupFrame
*>(link
.PrevFrame());
162 // don't set mColCount here, it is done in AddColsToTable
164 nsTableColGroupFrame::SetInitialChildList(nsIAtom
* aListName
,
165 nsFrameList
& aChildList
)
167 if (!mFrames
.IsEmpty()) {
168 // We already have child frames which means we've already been
170 NS_NOTREACHED("unexpected second call to SetInitialChildList");
171 return NS_ERROR_UNEXPECTED
;
174 // All we know about is the unnamed principal child list
175 NS_NOTREACHED("unknown frame list");
176 return NS_ERROR_INVALID_ARG
;
178 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
180 return NS_ERROR_NULL_POINTER
;
182 if (aChildList
.IsEmpty()) {
183 tableFrame
->AppendAnonymousColFrames(this, GetSpan(), eColAnonymousColGroup
,
188 mFrames
.AppendFrames(this, aChildList
);
193 nsTableColGroupFrame::DidSetStyleContext(nsStyleContext
* aOldStyleContext
)
195 if (!aOldStyleContext
) //avoid this on init
198 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
200 if (tableFrame
->IsBorderCollapse() &&
201 tableFrame
->BCRecalcNeeded(aOldStyleContext
, GetStyleContext())) {
202 PRInt32 colCount
= GetColCount();
204 return; // this is a degenerated colgroup
205 nsRect
damageArea(GetFirstColumn()->GetColIndex(), 0, colCount
,
206 tableFrame
->GetRowCount());
207 tableFrame
->SetBCDamageArea(damageArea
);
213 nsTableColGroupFrame::AppendFrames(nsIAtom
* aListName
,
214 nsFrameList
& aFrameList
)
216 NS_ASSERTION(!aListName
, "unexpected child list");
218 nsTableColFrame
* col
= GetFirstColumn();
219 nsTableColFrame
* nextCol
;
220 while (col
&& col
->GetColType() == eColAnonymousColGroup
) {
221 // this colgroup spans one or more columns but now that there is a
222 // real column below, spanned anonymous columns should be removed,
223 // since the HTML spec says to ignore the span of a colgroup if it
224 // has content columns in it.
225 nextCol
= col
->GetNextCol();
226 RemoveFrame(nsnull
, col
);
230 const nsFrameList::Slice
& newFrames
=
231 mFrames
.AppendFrames(this, aFrameList
);
232 InsertColsReflow(GetStartColumnIndex() + mColCount
, newFrames
);
237 nsTableColGroupFrame::InsertFrames(nsIAtom
* aListName
,
238 nsIFrame
* aPrevFrame
,
239 nsFrameList
& aFrameList
)
241 NS_ASSERTION(!aListName
, "unexpected child list");
242 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
243 "inserting after sibling frame with different parent");
245 nsTableColFrame
* col
= GetFirstColumn();
246 nsTableColFrame
* nextCol
;
247 while (col
&& col
->GetColType() == eColAnonymousColGroup
) {
248 // this colgroup spans one or more columns but now that there is a
249 // real column below, spanned anonymous columns should be removed,
250 // since the HTML spec says to ignore the span of a colgroup if it
251 // has content columns in it.
252 nextCol
= col
->GetNextCol();
253 if (col
== aPrevFrame
) {
254 // This can happen when we're being appended to
255 NS_ASSERTION(!nextCol
|| nextCol
->GetColType() != eColAnonymousColGroup
,
256 "Inserting in the middle of our anonymous cols?");
257 // We'll want to insert at the beginning
260 RemoveFrame(nsnull
, col
);
264 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
== aPrevFrame
->GetLastContinuation(),
265 "Prev frame should be last in continuation chain");
266 NS_ASSERTION(!aPrevFrame
|| !GetNextColumn(aPrevFrame
) ||
267 GetNextColumn(aPrevFrame
)->GetColType() != eColAnonymousCol
,
268 "Shouldn't be inserting before a spanned colframe");
270 const nsFrameList::Slice
& newFrames
=
271 mFrames
.InsertFrames(this, aPrevFrame
, aFrameList
);
272 nsIFrame
* prevFrame
= nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame
,
273 nsGkAtoms::tableColFrame
);
275 PRInt32 colIndex
= (prevFrame
) ? ((nsTableColFrame
*)prevFrame
)->GetColIndex() + 1 : GetStartColumnIndex();
276 InsertColsReflow(colIndex
, newFrames
);
282 nsTableColGroupFrame::InsertColsReflow(PRInt32 aColIndex
,
283 const nsFrameList::Slice
& aCols
)
285 AddColsToTable(aColIndex
, PR_TRUE
, aCols
);
287 PresContext()->PresShell()->FrameNeedsReflow(this,
288 nsIPresShell::eTreeChange
,
289 NS_FRAME_HAS_DIRTY_CHILDREN
);
293 nsTableColGroupFrame::RemoveChild(nsTableColFrame
& aChild
,
294 PRBool aResetSubsequentColIndices
)
296 PRInt32 colIndex
= 0;
297 nsIFrame
* nextChild
= nsnull
;
298 if (aResetSubsequentColIndices
) {
299 colIndex
= aChild
.GetColIndex();
300 nextChild
= aChild
.GetNextSibling();
302 mFrames
.DestroyFrame(&aChild
);
304 if (aResetSubsequentColIndices
) {
305 if (nextChild
) { // reset inside this and all following colgroups
306 ResetColIndices(this, colIndex
, nextChild
);
309 nsIFrame
* nextGroup
= GetNextSibling();
310 if (nextGroup
) // reset next and all following colgroups
311 ResetColIndices(nextGroup
, colIndex
);
315 PresContext()->PresShell()->FrameNeedsReflow(this,
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
;
327 PRBool contentRemoval
= PR_FALSE
;
329 if (nsGkAtoms::tableColFrame
== aOldFrame
->GetType()) {
330 nsTableColFrame
* colFrame
= (nsTableColFrame
*)aOldFrame
;
331 if (colFrame
->GetColType() == eColContent
) {
332 contentRemoval
= PR_TRUE
;
333 // Remove any anonymous column frames this <col> produced via a colspan
334 nsTableColFrame
* col
= colFrame
->GetNextCol();
335 nsTableColFrame
* nextCol
;
336 while (col
&& col
->GetColType() == eColAnonymousCol
) {
337 NS_ASSERTION(col
->GetStyleContext() == colFrame
->GetStyleContext() &&
338 col
->GetContent() == colFrame
->GetContent(),
339 "How did that happen??");
340 nextCol
= col
->GetNextCol();
341 RemoveFrame(nsnull
, col
);
346 PRInt32 colIndex
= colFrame
->GetColIndex();
347 // The RemoveChild call handles calling FrameNeedsReflow on us.
348 RemoveChild(*colFrame
, PR_TRUE
);
350 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
352 return NS_ERROR_NULL_POINTER
;
354 tableFrame
->RemoveCol(this, colIndex
, PR_TRUE
, PR_TRUE
);
355 if (mFrames
.IsEmpty() && contentRemoval
&&
356 GetColType() == eColGroupContent
) {
357 tableFrame
->AppendAnonymousColFrames(this, GetSpan(),
358 eColAnonymousColGroup
, PR_TRUE
);
362 mFrames
.DestroyFrame(aOldFrame
);
369 nsTableColGroupFrame::GetSkipSides() const
372 if (nsnull
!= GetPrevInFlow()) {
373 skip
|= 1 << NS_SIDE_TOP
;
375 if (nsnull
!= GetNextInFlow()) {
376 skip
|= 1 << NS_SIDE_BOTTOM
;
381 NS_METHOD
nsTableColGroupFrame::Reflow(nsPresContext
* aPresContext
,
382 nsHTMLReflowMetrics
& aDesiredSize
,
383 const nsHTMLReflowState
& aReflowState
,
384 nsReflowStatus
& aStatus
)
386 DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame");
387 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
388 NS_ASSERTION(nsnull
!=mContent
, "bad state -- null content for frame");
391 const nsStyleVisibility
* groupVis
= GetStyleVisibility();
392 PRBool collapseGroup
= (NS_STYLE_VISIBILITY_COLLAPSE
== groupVis
->mVisible
);
394 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
396 tableFrame
->SetNeedToCollapse(PR_TRUE
);;
399 // for every content child that (is a column thingy and does not already have a frame)
400 // create a frame and adjust it's style
402 for (nsIFrame
*kidFrame
= mFrames
.FirstChild(); kidFrame
;
403 kidFrame
= kidFrame
->GetNextSibling()) {
404 // Give the child frame a chance to reflow, even though we know it'll have 0 size
405 nsHTMLReflowMetrics kidSize
;
406 nsHTMLReflowState
kidReflowState(aPresContext
, aReflowState
, kidFrame
,
409 nsReflowStatus status
;
410 ReflowChild(kidFrame
, aPresContext
, kidSize
, kidReflowState
, 0, 0, 0, status
);
411 FinishReflowChild(kidFrame
, aPresContext
, nsnull
, kidSize
, 0, 0, 0);
414 aDesiredSize
.width
=0;
415 aDesiredSize
.height
=0;
416 aStatus
= NS_FRAME_COMPLETE
;
417 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
422 nsTableColGroupFrame::IsContainingBlock() const
427 nsTableColFrame
* nsTableColGroupFrame::GetFirstColumn()
429 return GetNextColumn(nsnull
);
432 nsTableColFrame
* nsTableColGroupFrame::GetNextColumn(nsIFrame
*aChildFrame
)
434 nsTableColFrame
*result
= nsnull
;
435 nsIFrame
*childFrame
= aChildFrame
;
437 childFrame
= mFrames
.FirstChild();
440 childFrame
= childFrame
->GetNextSibling();
444 if (NS_STYLE_DISPLAY_TABLE_COLUMN
==
445 childFrame
->GetStyleDisplay()->mDisplay
)
447 result
= (nsTableColFrame
*)childFrame
;
450 childFrame
= childFrame
->GetNextSibling();
455 PRInt32
nsTableColGroupFrame::GetSpan()
457 return GetStyleTable()->mSpan
;
460 void nsTableColGroupFrame::SetContinuousBCBorderWidth(PRUint8 aForSide
,
461 BCPixelSize aPixelValue
)
465 mTopContBorderWidth
= aPixelValue
;
468 mBottomContBorderWidth
= aPixelValue
;
471 NS_ERROR("invalid side arg");
475 void nsTableColGroupFrame::GetContinuousBCBorderWidth(nsMargin
& aBorder
)
477 PRInt32 aPixelsToTwips
= nsPresContext::AppUnitsPerCSSPixel();
478 nsTableFrame
* table
= nsTableFrame::GetTableFrame(this);
479 nsTableColFrame
* col
= table
->GetColFrame(mStartColIndex
+ mColCount
- 1);
480 col
->GetContinuousBCBorderWidth(aBorder
);
481 aBorder
.top
= BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips
,
482 mTopContBorderWidth
);
483 aBorder
.bottom
= BC_BORDER_TOP_HALF_COORD(aPixelsToTwips
,
484 mBottomContBorderWidth
);
488 /* ----- global methods ----- */
491 NS_NewTableColGroupFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
493 return new (aPresShell
) nsTableColGroupFrame(aContext
);
496 NS_IMPL_FRAMEARENA_HELPERS(nsTableColGroupFrame
)
499 nsTableColGroupFrame::GetType() const
501 return nsGkAtoms::tableColGroupFrame
;
506 nsTableColGroupFrame::GetFrameName(nsAString
& aResult
) const
508 return MakeFrameName(NS_LITERAL_STRING("TableColGroup"), aResult
);
511 void nsTableColGroupFrame::Dump(PRInt32 aIndent
)
513 char* indent
= new char[aIndent
+ 1];
515 for (PRInt32 i
= 0; i
< aIndent
+ 1; i
++) {
520 printf("%s**START COLGROUP DUMP**\n%s startcolIndex=%d colcount=%d span=%d coltype=",
521 indent
, indent
, GetStartColumnIndex(), GetColCount(), GetSpan());
522 nsTableColGroupType colType
= GetColType();
524 case eColGroupContent
:
527 case eColGroupAnonymousCol
:
528 printf(" anonymous-column ");
530 case eColGroupAnonymousCell
:
531 printf(" anonymous-cell ");
534 // verify the colindices
535 PRInt32 j
= GetStartColumnIndex();
536 nsTableColFrame
* col
= GetFirstColumn();
538 NS_ASSERTION(j
== col
->GetColIndex(), "wrong colindex on col frame");
539 col
= col
->GetNextCol();
542 NS_ASSERTION((j
- GetStartColumnIndex()) == GetColCount(),
543 "number of cols out of sync");
544 printf("\n%s**END COLGROUP DUMP** ", indent
);