Bug 563259: Fix shark/dtrace enabled combo. (r=me)
[mozilla-central.git] / layout / tables / nsTableColGroupFrame.cpp
blob5442b8025f325d24cd528b71d996fd7edc292c0c
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
13 * License.
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.
22 * Contributor(s):
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"
46 #include "nsCOMPtr.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
53 nsTableColGroupType
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()) ||
78 !aStartColFrame) {
79 colGroupFrame->SetStartColumnIndex(colIndex);
81 nsIFrame* colFrame = aStartColFrame;
82 if (!colFrame || (colIndex != aFirstColIndex)) {
83 colFrame = colGroupFrame->GetFirstChild(nsnull);
85 while (colFrame) {
86 if (nsGkAtoms::tableColFrame == colFrame->GetType()) {
87 ((nsTableColFrame*)colFrame)->SetColIndex(colIndex);
88 colIndex++;
90 colFrame = colFrame->GetNextSibling();
93 colGroupFrame = static_cast<nsTableColGroupFrame*>
94 (colGroupFrame->GetNextSibling());
99 nsresult
100 nsTableColGroupFrame::AddColsToTable(PRInt32 aFirstColIndex,
101 PRBool aResetSubsequentColIndices,
102 const nsFrameList::Slice& aCols)
104 nsresult rv = NS_OK;
105 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
106 if (!tableFrame)
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);
114 mColCount++;
115 tableFrame->InsertCol((nsTableColFrame &)*e.get(), colIndex);
116 colIndex++;
119 for (nsFrameList::Enumerator eTail = e.GetUnlimitedEnumerator();
120 !eTail.AtEnd();
121 eTail.Next()) {
122 ((nsTableColFrame*)eTail.get())->SetColIndex(colIndex);
123 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);
134 return rv;
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
163 NS_IMETHODIMP
164 nsTableColGroupFrame::SetInitialChildList(nsIAtom* aListName,
165 nsFrameList& aChildList)
167 if (!mFrames.IsEmpty()) {
168 // We already have child frames which means we've already been
169 // initialized
170 NS_NOTREACHED("unexpected second call to SetInitialChildList");
171 return NS_ERROR_UNEXPECTED;
173 if (aListName) {
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);
179 if (!tableFrame)
180 return NS_ERROR_NULL_POINTER;
182 if (aChildList.IsEmpty()) {
183 tableFrame->AppendAnonymousColFrames(this, GetSpan(), eColAnonymousColGroup,
184 PR_FALSE);
185 return NS_OK;
188 mFrames.AppendFrames(this, aChildList);
189 return NS_OK;
192 /* virtual */ void
193 nsTableColGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
195 if (!aOldStyleContext) //avoid this on init
196 return;
198 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
200 if (tableFrame->IsBorderCollapse() &&
201 tableFrame->BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
202 PRInt32 colCount = GetColCount();
203 if (!colCount)
204 return; // this is a degenerated colgroup
205 nsRect damageArea(GetFirstColumn()->GetColIndex(), 0, colCount,
206 tableFrame->GetRowCount());
207 tableFrame->SetBCDamageArea(damageArea);
209 return;
212 NS_IMETHODIMP
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);
227 col = nextCol;
230 const nsFrameList::Slice& newFrames =
231 mFrames.AppendFrames(this, aFrameList);
232 InsertColsReflow(GetStartColumnIndex() + mColCount, newFrames);
233 return NS_OK;
236 NS_IMETHODIMP
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
258 aPrevFrame = nsnull;
260 RemoveFrame(nsnull, col);
261 col = nextCol;
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);
278 return NS_OK;
281 void
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);
292 void
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);
303 mColCount--;
304 if (aResetSubsequentColIndices) {
305 if (nextChild) { // reset inside this and all following colgroups
306 ResetColIndices(this, colIndex, nextChild);
308 else {
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);
320 NS_IMETHODIMP
321 nsTableColGroupFrame::RemoveFrame(nsIAtom* aListName,
322 nsIFrame* aOldFrame)
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);
342 col = nextCol;
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);
351 if (!tableFrame)
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);
361 else {
362 mFrames.DestroyFrame(aOldFrame);
365 return NS_OK;
368 PRIntn
369 nsTableColGroupFrame::GetSkipSides() const
371 PRIntn skip = 0;
372 if (nsnull != GetPrevInFlow()) {
373 skip |= 1 << NS_SIDE_TOP;
375 if (nsnull != GetNextInFlow()) {
376 skip |= 1 << NS_SIDE_BOTTOM;
378 return skip;
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");
389 nsresult rv=NS_OK;
391 const nsStyleVisibility* groupVis = GetStyleVisibility();
392 PRBool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
393 if (collapseGroup) {
394 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
395 if (tableFrame) {
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,
407 nsSize(0,0));
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);
418 return rv;
421 /* virtual */ PRBool
422 nsTableColGroupFrame::IsContainingBlock() const
424 return PR_TRUE;
427 nsTableColFrame * nsTableColGroupFrame::GetFirstColumn()
429 return GetNextColumn(nsnull);
432 nsTableColFrame * nsTableColGroupFrame::GetNextColumn(nsIFrame *aChildFrame)
434 nsTableColFrame *result = nsnull;
435 nsIFrame *childFrame = aChildFrame;
436 if (!childFrame) {
437 childFrame = mFrames.FirstChild();
439 else {
440 childFrame = childFrame->GetNextSibling();
442 while (childFrame)
444 if (NS_STYLE_DISPLAY_TABLE_COLUMN ==
445 childFrame->GetStyleDisplay()->mDisplay)
447 result = (nsTableColFrame *)childFrame;
448 break;
450 childFrame = childFrame->GetNextSibling();
452 return result;
455 PRInt32 nsTableColGroupFrame::GetSpan()
457 return GetStyleTable()->mSpan;
460 void nsTableColGroupFrame::SetContinuousBCBorderWidth(PRUint8 aForSide,
461 BCPixelSize aPixelValue)
463 switch (aForSide) {
464 case NS_SIDE_TOP:
465 mTopContBorderWidth = aPixelValue;
466 return;
467 case NS_SIDE_BOTTOM:
468 mBottomContBorderWidth = aPixelValue;
469 return;
470 default:
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);
485 return;
488 /* ----- global methods ----- */
490 nsIFrame*
491 NS_NewTableColGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
493 return new (aPresShell) nsTableColGroupFrame(aContext);
496 NS_IMPL_FRAMEARENA_HELPERS(nsTableColGroupFrame)
498 nsIAtom*
499 nsTableColGroupFrame::GetType() const
501 return nsGkAtoms::tableColGroupFrame;
504 #ifdef DEBUG
505 NS_IMETHODIMP
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];
514 if (!indent) return;
515 for (PRInt32 i = 0; i < aIndent + 1; i++) {
516 indent[i] = ' ';
518 indent[aIndent] = 0;
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();
523 switch (colType) {
524 case eColGroupContent:
525 printf(" content ");
526 break;
527 case eColGroupAnonymousCol:
528 printf(" anonymous-column ");
529 break;
530 case eColGroupAnonymousCell:
531 printf(" anonymous-cell ");
532 break;
534 // verify the colindices
535 PRInt32 j = GetStartColumnIndex();
536 nsTableColFrame* col = GetFirstColumn();
537 while (col) {
538 NS_ASSERTION(j == col->GetColIndex(), "wrong colindex on col frame");
539 col = col->GetNextCol();
540 j++;
542 NS_ASSERTION((j - GetStartColumnIndex()) == GetColCount(),
543 "number of cols out of sync");
544 printf("\n%s**END COLGROUP DUMP** ", indent);
545 delete [] indent;
547 #endif