diff --git a/layout/html/document/src/ua.css b/layout/html/document/src/ua.css index 141e80a30b19..ce7b1920e4e3 100644 --- a/layout/html/document/src/ua.css +++ b/layout/html/document/src/ua.css @@ -118,6 +118,7 @@ A:visited IMG { border: 2px solid purple; text-decoration: underline } A:active IMG { border: 2px solid lime; text-decoration: underline } A:out-of-date IMG { border: 2px solid red; text-decoration: underline } + //---------------------------------------------------------------------- // The real stuff diff --git a/layout/html/table/src/BasicTableLayoutStrategy.cpp b/layout/html/table/src/BasicTableLayoutStrategy.cpp index 3070448f1907..f726a4989aa2 100644 --- a/layout/html/table/src/BasicTableLayoutStrategy.cpp +++ b/layout/html/table/src/BasicTableLayoutStrategy.cpp @@ -116,112 +116,6 @@ PRBool BasicTableLayoutStrategy::IsAutoWidth(nsStylePosition* aStylePosition) } -// aSpecifiedTableWidth is filled if the table witdth is not auto -PRBool BasicTableLayoutStrategy::TableIsAutoWidth(nsIStyleContext *aTableStyle, - const nsReflowState& aReflowState, - nscoord& aSpecifiedTableWidth) -{ - NS_ASSERTION(nsnull!=aTableStyle, "bad arg - aTableStyle"); - PRBool result = PR_TRUE; // the default - if (nsnull!=aTableStyle) - { - //nsStylePosition* tablePosition = (nsStylePosition*)aTableStyle->GetData(eStyleStruct_Position); - /* this is sick and wrong, but what the hell - we grab the style of our parent (nsTableOuterFrame) and ask it for width info, - until the style resolution stuff does the cool stuff about splitting style between outer and inner - */ - // begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! - nsIStyleContext* parentStyle = nsnull; - nsIFrame * parent = nsnull; - mTableFrame->GetGeometricParent(parent); - parent->GetStyleContext(nsnull, parentStyle); - nsStylePosition* tablePosition = (nsStylePosition*)parentStyle->GetData(eStyleStruct_Position); - // end REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! - switch (tablePosition->mWidth.GetUnit()) { - case eStyleUnit_Auto: // specified auto width - case eStyleUnit_Proportional: // illegal for table, so ignored - break; - - case eStyleUnit_Inherit: - // get width of parent and see if it is a specified value or not - // XXX for now, just return true - break; - - case eStyleUnit_Coord: - aSpecifiedTableWidth = tablePosition->mWidth.GetCoordValue(); - result = PR_FALSE; - break; -#ifdef STEVES_WAY - case eStyleUnit_Percent: - // get the parent's width (available only from parent frames that claim they can provide it) - // note that we start with our parent's parent (the outer table frame's parent) - nscoord parentWidth = 0; - NS_ASSERTION(nsnull!=aReflowState.parentReflowState, "bad outer table reflow state."); - NS_ASSERTION(nsnull!=aReflowState.parentReflowState->parentReflowState, "bad table parent reflow state."); - if ((nsnull!=aReflowState.parentReflowState) && - (nsnull!=aReflowState.parentReflowState->parentReflowState)) - { - const nsReflowState *parentReflowState = aReflowState.parentReflowState->parentReflowState; - nsIFrame *parentFrame=parentReflowState->frame; - NS_ASSERTION(nsnull!=parentFrame, "bad parent frame in reflow state struct."); - while(nsnull!=parentFrame) - { - PRBool isPercentageBase=PR_FALSE; - parentFrame->IsPercentageBase(isPercentageBase); - if (PR_TRUE==isPercentageBase) - { // found the ancestor who claims to be the container to base my percentage width on - parentWidth = parentReflowState->maxSize.width; - if (PR_TRUE==gsDebug) printf(" ** width for parent frame %p = %d\n", parentFrame, parentWidth); - break; - } - parentReflowState = parentReflowState->parentReflowState; // get next ancestor - if (nsnull!=parentReflowState) - parentFrame = parentReflowState->frame; - else - parentFrame = nsnull; // terminates loop. - // TODO: do we need a backstop in case there are no IsPercentageBase==true frames? - } - } - -#else - case eStyleUnit_Percent: - // Get the parent's width (available only from parent frames - // that claim they can provide it, and assuming it's already - // specified; that is, top-down layout sets the widths on the - // way down.) - nscoord parentWidth = aReflowState.maxSize.width; - - // Walk up the reflow state chain until we find a block - // frame. Our width is computed relative to there. - const nsReflowState* rs = &aReflowState; - while (nsnull != rs) { - nsIFrame* block = nsnull; - rs->frame->QueryInterface(kBlockFrameCID, (void**) &block); - if (nsnull != block) { - // We found the nearest containing block which defines what - // a percentage size is relative to. Use the width that it - // will reflow to as the basis for computing our width. - parentWidth = rs->maxSize.width; - break; - } - rs = rs->parentReflowState; - } - -#endif - - // set aSpecifiedTableWidth to be the given percent of the parent. - float percent = tablePosition->mWidth.GetPercentValue(); - aSpecifiedTableWidth = (PRInt32)(parentWidth*percent); - if (PR_TRUE==gsDebug) printf(" ** aSpecifiedTableWidth = %d\n", aSpecifiedTableWidth); - result = PR_FALSE; - break; - } - } - - return result; -} - - BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame) { mTableFrame = aFrame; @@ -260,12 +154,12 @@ PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContex // Step 2 - determine how much space is really available PRInt32 availWidth = aMaxWidth - aTotalFixedWidth; nscoord tableWidth = 0; - if (PR_FALSE==TableIsAutoWidth(aTableStyle, aReflowState, tableWidth)) + if (PR_FALSE==nsTableFrame::TableIsAutoWidth(mTableFrame, aTableStyle, aReflowState, tableWidth)) availWidth = tableWidth - aTotalFixedWidth; // Step 3 - assign the width of all proportional-width columns in the remaining space if (gsDebug==PR_TRUE) printf ("Step 2...\n availWidth = %d\n", availWidth); - result = BalanceProportionalColumns(aPresContext, + result = BalanceProportionalColumns(aPresContext, aReflowState, availWidth, aMaxWidth, aMinTableWidth, aMaxTableWidth, tableWidth); @@ -525,6 +419,7 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPresContext, + const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, nscoord aMinTableWidth, @@ -538,7 +433,7 @@ PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPre if (NS_UNCONSTRAINEDSIZE==aMaxWidth || NS_UNCONSTRAINEDSIZE==aMinTableWidth) { // the max width of the table fits comfortably in the available space if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aAvailWidth, aMaxWidth, aTableFixedWidth); + result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, aMaxWidth, aTableFixedWidth); } else if (aMinTableWidth > aMaxWidth) { // the table doesn't fit in the available space @@ -548,7 +443,7 @@ PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPre else if (aMaxTableWidth <= aMaxWidth) { // the max width of the table fits comfortably in the available space if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aAvailWidth, aMaxWidth, aTableFixedWidth); + result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, aMaxWidth, aTableFixedWidth); } else { // the table fits somewhere between its min and desired size @@ -562,7 +457,7 @@ PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPre if (NS_UNCONSTRAINEDSIZE==aMinTableWidth) { // the table has empty content, and needs to be streched to the specified width if (gsDebug) printf (" * specified width table > maxTableWidth, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aAvailWidth, aMaxWidth, aTableFixedWidth); + result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, aMaxWidth, aTableFixedWidth); } else if (aTableFixedWidth= its max width, so give each column its max requested size if (gsDebug) printf (" * specified width table > maxTableWidth, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aAvailWidth, aMaxWidth, aTableFixedWidth); + result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, aMaxWidth, aTableFixedWidth); } } return result; @@ -639,7 +534,8 @@ PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresConte return result; } -PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresContext, +PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresContext, + const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, nscoord aTableFixedWidth) @@ -652,7 +548,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo PRBool result = PR_TRUE; nscoord tableWidth=0; // the width of the table as a result of setting column widths - nscoord numProportionalColumns = 0; // the total number of proportional-width columns PRInt32 totalSlices=0; // the total number of slices the proportional-width columns request nsVoidArray *proportionalColumnsList=nsnull; // a list of the columns that are proportional-width nsVoidArray *spanList=nsnull; // a list of the cells that span columns @@ -675,10 +570,11 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo nsIStyleContextPtr colSC; colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); nsStylePosition* colPosition = (nsStylePosition*) colSC->GetData(eStyleStruct_Position); + if (gsDebug) printf("col %d has frame %p with style %p and pos %p\n", + colIndex, colFrame, (nsIStyleContext *)colSC, colPosition); if (PR_FALSE==IsFixedWidth(colPosition)) { - numProportionalColumns++; // first, deal with any cells that span into this column from a pervious column if (nsnull!=spanList) { @@ -720,7 +616,48 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo nsresult result = data->GetMargin(margin); nscoord marginWidth = margin.left + margin.right; PRInt32 cellMinWidth = cellMinSize->width/colSpan + marginWidth; - PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan + marginWidth; + // first get the desired size info from reflow pass 1 + PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan + marginWidth; + // then get the desired size info factoring in the cell style attributes + nscoord specifiedCellWidth=-1; + nsIStyleContextPtr cellSC; + data->GetCellFrame()->GetStyleContext(aPresContext, cellSC.AssignRef()); + nsStylePosition* cellPosition = (nsStylePosition*) + cellSC->GetData(eStyleStruct_Position); + switch (cellPosition->mWidth.GetUnit()) { + case eStyleUnit_Coord: + specifiedCellWidth = cellPosition->mWidth.GetCoordValue(); + if (gsDebug) printf("cell has specified coord width = %d\n", specifiedCellWidth); + break; + + case eStyleUnit_Percent: + { + nscoord tableWidth=0; + nsIStyleContextPtr tableSC; + mTableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); + PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, tableSC, aReflowState, tableWidth); + float percent = cellPosition->mWidth.GetPercentValue(); + specifiedCellWidth = (PRInt32)(tableWidth*percent); + if (gsDebug) printf("specified percent width %f of %d = %d\n", + percent, tableWidth, specifiedCellWidth); + break; + } + + case eStyleUnit_Inherit: + // XXX for now, do nothing + default: + case eStyleUnit_Auto: + break; + } + if (-1!=specifiedCellWidth) + { + if (specifiedCellWidth>cellMinWidth) + { + if (gsDebug) printf("setting cellDesiredWidth from %d to %d\n", + cellDesiredWidth, specifiedCellWidth); + cellDesiredWidth = specifiedCellWidth; // TODO: some math needed here for colspans + } + } if (PR_TRUE==gsDebug) printf("factoring in cell %d with colSpan=%d\n factoring in min=%d and desired=%d\n", @@ -750,15 +687,22 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo } // Get column width if it has one - nscoord specifiedProportion = -1; + nscoord specifiedProportionColumnWidth = -1; float specifiedPercentageColWidth = -1.0f; + nscoord specifiedFixedColumnWidth = -1; PRBool isAutoWidth = PR_FALSE; switch (colPosition->mWidth.GetUnit()) { + case eStyleUnit_Coord: + specifiedFixedColumnWidth = colPosition->mWidth.GetCoordValue(); + if (gsDebug) printf("column %d has specified coord width = %d\n", colIndex, specifiedFixedColumnWidth); + break; case eStyleUnit_Percent: specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); + if (gsDebug) printf("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); break; case eStyleUnit_Proportional: - specifiedProportion = colPosition->mWidth.GetIntValue(); + specifiedProportionColumnWidth = colPosition->mWidth.GetIntValue(); + if (gsDebug) printf("column %d has specified percent width = %d\n", colIndex, specifiedProportionColumnWidth); break; case eStyleUnit_Auto: isAutoWidth = PR_TRUE; @@ -768,11 +712,11 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo } /* set the column width, knowing that the table fits in the available space */ - if (0==specifiedProportion || 0.0==specifiedPercentageColWidth) + if (0==specifiedProportionColumnWidth || 0.0==specifiedPercentageColWidth) { // col width is specified to be the minimum mTableFrame->SetColumnWidth(colIndex, minColWidth); if (gsDebug==PR_TRUE) - printf (" 3 (0): col %d set to min width = %d because style set proportionalWidth=0\n", + printf (" 3 min: col %d set to min width = %d because style set proportionalWidth=0\n", colIndex, mTableFrame->GetColumnWidth(colIndex)); } else if (PR_TRUE==isAutoWidth) @@ -781,10 +725,10 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo // if there is width left over, we'll factor that in after this loop is complete mTableFrame->SetColumnWidth(colIndex, maxColWidth); if (gsDebug==PR_TRUE) - printf (" 3a: col %d with availWidth %d, set to width = %d\n", + printf (" 3 auto: col %d with availWidth %d, set to width = %d\n", colIndex, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); } - else if (0!=specifiedProportion) + else if (-1!=specifiedProportionColumnWidth) { // we need to save these and do them after all other columns have been calculated /* the calculation will be: sum up n, the total number of slices for the columns with proportional width @@ -798,9 +742,23 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo if (nsnull==proportionalColumnsList) proportionalColumnsList = new nsVoidArray(); ProportionalColumnLayoutStruct * info = - new ProportionalColumnLayoutStruct(colIndex, minColWidth, maxColWidth, specifiedProportion); + new ProportionalColumnLayoutStruct(colIndex, minColWidth, + maxColWidth, specifiedProportionColumnWidth); proportionalColumnsList->AppendElement(info); - totalSlices += specifiedProportion; + totalSlices += specifiedProportionColumnWidth; // keep track of the total number of proportions + if (gsDebug==PR_TRUE) + printf (" 3 proportional: col %d with availWidth %d, gets %d slices with %d slices so far.\n", + colIndex, aAvailWidth, specifiedProportionColumnWidth, totalSlices); + } + else if (-1!=specifiedFixedColumnWidth) + { + // if the column was computed to be too small, enlarge the column + nscoord resolvedWidth = specifiedFixedColumnWidth; + if (specifiedFixedColumnWidth <= minColWidth) + resolvedWidth = minColWidth; + mTableFrame->SetColumnWidth(colIndex, resolvedWidth); + if (gsDebug==PR_TRUE) + printf (" 3 fixed: col %d given %d\n", colIndex, resolvedWidth); } else { // give each remaining column a percentage of the remaining space @@ -816,14 +774,14 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo if (-1==percentage) percentage = 100/numCols; // base the % on the total max width - mTableFrame->SetColumnWidth(colIndex, (percentage*aMaxWidth)/100); + mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth)/100); // if the column was computed to be too small, enlarge the column if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth) mTableFrame->SetColumnWidth(colIndex, minColWidth); } if (gsDebug==PR_TRUE) - printf (" 3b: col %d given %d percent of aMaxWidth %d, set to width = %d\n", - colIndex, percentage, aMaxWidth, mTableFrame->GetColumnWidth(colIndex)); + printf (" 3 percent: col %d given %d percent of aAvailWidth %d, set to width = %d\n", + colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); } } tableWidth += mTableFrame->GetColumnWidth(colIndex); @@ -845,7 +803,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo nscoord computedColWidth = info->mProportion*widthPerSlice; mTableFrame->SetColumnWidth(info->mColIndex, computedColWidth); if (gsDebug==PR_TRUE) - printf (" 3c: col %d given %d proportion of remaining space %d, set to width = %d\n", + printf (" 3 proportional step 2: col %d given %d proportion of remaining space %d, set to width = %d\n", info->mColIndex, info->mProportion, widthRemaining, computedColWidth); tableWidth += computedColWidth; delete info; @@ -859,26 +817,34 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo if (aTableFixedWidth > tableWidth) { nscoord excess = aTableFixedWidth - tableWidth; - // if there are proportionally-sized columns, give them the extra space - if (0!=numProportionalColumns) + if (gsDebug) printf ("fixed width %d > computed table width %d, excess = %d\n", + aTableFixedWidth, tableWidth, excess); + // if there are auto-sized columns, give them the extra space + PRInt32 numAutoColumns; + PRInt32 *autoColumns; + mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); + if (0!=numAutoColumns) { - nscoord excessPerColumn = excess/numProportionalColumns; - if (gsDebug==PR_TRUE) printf(" aTableFixedWidth specified as %d, expanding columns by excess = %d\n", aTableFixedWidth, excess); - for (PRInt32 colIndex = 0; colIndexGetColumnWidth(colIndex); - mTableFrame->SetColumnWidth(colIndex, colWidth); - } + PRInt32 colIndex = autoColumns[i]; + nscoord colWidth = excessPerColumn+mTableFrame->GetColumnWidth(colIndex); + if (gsDebug==PR_TRUE) + printf(" column %d was %d, now set to %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex), colWidth); + mTableFrame->SetColumnWidth(colIndex, colWidth); } } - // otherwise, distribute the space evenly between all the columns + // otherwise, distribute the space evenly between all the columns (they must be all fixed and percentage-width columns) + // TODO - should extra space be proportionately distributed? else { nscoord excessPerColumn = excess/numCols; - if (gsDebug==PR_TRUE) printf(" aTableFixedWidth specified as %d, expanding columns by excess = %d\n", aTableFixedWidth, excess); + if (gsDebug==PR_TRUE) + printf(" aTableFixedWidth specified as %d, expanding columns by excess = %d\n", aTableFixedWidth, excess); for (PRInt32 colIndex = 0; colIndexGetColumnWidth(colIndex); @@ -907,7 +873,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre PRBool result = PR_TRUE; PRInt32 maxOfAllMinColWidths = 0; // for the case where we have equal column widths, this is the smallest a column can be nscoord tableWidth=0; // the width of the table as a result of setting column widths - nscoord numProportionalColumns = 0; // the total number of proportional-width columns PRInt32 totalSlices=0; // the total number of slices the proportional-width columns request nsVoidArray *proportionalColumnsList=nsnull; // a list of the columns that are proportional-width PRBool equalWidthColumns = PR_TRUE; // remember if we're in the special case where all diff --git a/layout/html/table/src/BasicTableLayoutStrategy.h b/layout/html/table/src/BasicTableLayoutStrategy.h index acba3cf2a6e0..1fe2a9066b9e 100644 --- a/layout/html/table/src/BasicTableLayoutStrategy.h +++ b/layout/html/table/src/BasicTableLayoutStrategy.h @@ -103,6 +103,7 @@ public: * */ virtual PRBool BalanceProportionalColumns(nsIPresContext* aPresContext, + const nsReflowState& aReflowState, PRInt32 aAvailWidth, PRInt32 aMaxWidth, PRInt32 aMinTableWidth, @@ -132,6 +133,7 @@ public: * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error */ virtual PRBool BalanceColumnsTableFits(nsIPresContext* aPresContext, + const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, nscoord aTableFixedWidth); @@ -166,10 +168,6 @@ public: virtual PRBool IsAutoWidth(nsStylePosition* aStylePosition); - virtual PRBool TableIsAutoWidth(nsIStyleContext *aTableStyle, - const nsReflowState& aReflowState, - nscoord& aSpecifiedTableWidth); - protected: nsTableFrame * mTableFrame; diff --git a/layout/html/table/src/nsTableCell.cpp b/layout/html/table/src/nsTableCell.cpp index 72c1a21792e5..53b312d04f93 100644 --- a/layout/html/table/src/nsTableCell.cpp +++ b/layout/html/table/src/nsTableCell.cpp @@ -160,6 +160,11 @@ void nsTableCell::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) nsHTMLTagContent::SetAttribute(aAttribute, val); return; } + if ((aAttribute == nsHTMLAtoms::valign) && + ParseAlignParam(aValue, val)) { + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } if (aAttribute == nsHTMLAtoms::background) { nsAutoString href(aValue); href.StripWhitespace(); @@ -191,6 +196,11 @@ void nsTableCell::SetAttribute(nsIAtom* aAttribute, const nsString& aValue) nsHTMLTagContent::SetAttribute(aAttribute, val); return; } + if (aAttribute == nsHTMLAtoms::nowrap) { + val.SetEmptyValue(); + nsHTMLTagContent::SetAttribute(aAttribute, val); + return; + } // Use default attribute catching code nsTableContent::SetAttribute(aAttribute, aValue); } @@ -212,6 +222,15 @@ void nsTableCell::MapAttributesInto(nsIStyleContext* aContext, nsStyleText* text = (nsStyleText*)aContext->GetData(eStyleStruct_Text); text->mTextAlign = value.GetIntValue(); } + + // valign: enum + GetAttribute(nsHTMLAtoms::valign, value); + if (value.GetUnit() == eHTMLUnit_Enumerated) + { + nsStyleText* text = (nsStyleText*)aContext->GetData(eStyleStruct_Text); + text->mTextAlign = value.GetIntValue(); + } + MapBackgroundAttributesInto(aContext, aPresContext); // width: pixel @@ -223,6 +242,9 @@ void nsTableCell::MapAttributesInto(nsIStyleContext* aContext, nscoord twips = nscoord(p2t * value.GetPixelValue()); pos->mWidth.SetCoordValue(twips); } + else if (value.GetUnit() == eHTMLUnit_Percent) { + pos->mWidth.SetPercentValue(value.GetPercentValue()); + } // height: pixel GetAttribute(nsHTMLAtoms::height, value); diff --git a/layout/html/table/src/nsTableCellFrame.cpp b/layout/html/table/src/nsTableCellFrame.cpp index a1714692d267..24b28799bbed 100644 --- a/layout/html/table/src/nsTableCellFrame.cpp +++ b/layout/html/table/src/nsTableCellFrame.cpp @@ -27,8 +27,12 @@ #include "nsIContentDelegate.h" #include "nsCSSLayout.h" #include "nsHTMLAtoms.h" +#include "nsHTMLIIDs.h" +#include "nsIPtr.h" #include "nsIView.h" +NS_DEF_PTR(nsIStyleContext); + #ifdef NS_DEBUG static PRBool gsDebug = PR_FALSE; //#define NOISY_STYLE @@ -297,6 +301,42 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, CreatePsuedoFrame(aPresContext); } + // Determine the width we have to work with + nscoord cellWidth = -1; + if (NS_UNCONSTRAINEDSIZE!=availSize.width) + { + /* + nsStylePosition* kidPosition = (nsStylePosition*) + mStyleContext->GetData(eStyleStruct_Position); + switch (kidPosition->mWidth.GetUnit()) { + case eStyleUnit_Coord: + cellWidth = kidPosition->mWidth.GetCoordValue(); + break; + + case eStyleUnit_Percent: + { + nscoord tableWidth=0; + const nsReflowState *tableReflowState = aReflowState.parentReflowState->parentReflowState->parentReflowState; + nsTableFrame *tableFrame = (nsTableFrame *)(tableReflowState->frame); + nsIStyleContextPtr tableSC; + tableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); + PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(tableFrame, tableSC, *tableReflowState, tableWidth); + float percent = kidPosition->mWidth.GetPercentValue(); + cellWidth = (PRInt32)(tableWidth*percent); + break; + } + + case eStyleUnit_Inherit: + // XXX for now, do nothing + default: + case eStyleUnit_Auto: + break; + } + */ + if (-1!=cellWidth) + availSize.width = cellWidth; + } + // Try to reflow the child into the available space. It might not // fit or might need continuing. if (availSize.height < 0) @@ -325,14 +365,13 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, } SetFirstContentOffset(mFirstChild); - if (gsDebug) printf("CELL: set first content offset to %d\n", GetFirstContentOffset()); //@@@ + //if (gsDebug) printf("CELL: set first content offset to %d\n", GetFirstContentOffset()); //@@@ SetLastContentOffset(mFirstChild); - if (gsDebug) printf("CELL: set last content offset to %d\n", GetLastContentOffset()); //@@@ + //if (gsDebug) printf("CELL: set last content offset to %d\n", GetLastContentOffset()); //@@@ - // Place the child since some of it's content fit in us. + // Place the child mFirstChild->SetRect(nsRect(leftInset, topInset, - kidSize.width, kidSize.height)); - + kidSize.width, kidSize.height)); if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // If the child didn't finish layout then it means that it used @@ -341,19 +380,22 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, } // Return our size and our result - PRInt32 kidWidth = kidSize.width; - if (NS_UNCONSTRAINEDSIZE!=kidSize.width) //&& NS_UNCONSTRAINEDSIZE!=aMaxSize.width) - kidWidth += leftInset + rightInset; - PRInt32 kidHeight = kidSize.height; - // height can be set w/o being restricted by aMaxSize.height - if (NS_UNCONSTRAINEDSIZE!=kidSize.height) - kidHeight += topInset + bottomInset; - aDesiredSize.width = kidWidth; - aDesiredSize.height = kidHeight; + // first, compute the height + // the height can be set w/o being restricted by aMaxSize.height + nscoord cellHeight = kidSize.height; + if (NS_UNCONSTRAINEDSIZE!=cellHeight) + cellHeight += topInset + bottomInset; + // next determine the cell's width + cellWidth = kidSize.width; // at this point, we've factored in the cell's style attributes + if (NS_UNCONSTRAINEDSIZE!=cellWidth) + cellWidth += leftInset + rightInset; + + // set the cell's desired size and max element size + aDesiredSize.width = cellWidth; + aDesiredSize.height = cellHeight; aDesiredSize.ascent = topInset; aDesiredSize.descent = bottomInset; - if (nsnull!=aDesiredSize.maxElementSize) { *aDesiredSize.maxElementSize = *pMaxElementSize; diff --git a/layout/html/table/src/nsTableCol.cpp b/layout/html/table/src/nsTableCol.cpp index 1d29b5ad50a8..489dc655ef85 100644 --- a/layout/html/table/src/nsTableCol.cpp +++ b/layout/html/table/src/nsTableCol.cpp @@ -36,7 +36,11 @@ static const PRBool gsDebug = PR_FALSE; static const PRBool gsNoisyRefs = PR_FALSE; #endif - +// hack, remove when hack in nsTableCol constructor is removed +static PRInt32 HACKcounter=0; +static nsIAtom *HACKattribute=nsnull; +#include "prprf.h" // remove when nsTableCol constructor hack is removed +// end hack code nsTableColFrame::nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame) : nsFrame(aContent, aParentFrame) @@ -75,6 +79,17 @@ NS_METHOD nsTableColFrame::Reflow(nsIPresContext* aPresContext, return NS_OK; } +PRInt32 nsTableColFrame::GetColumnIndex() +{ + if (nsnull!=mContent) + return ((nsTableCol *)mContent)->GetColumnIndex(); + else + return 0; +} + + +/* ----- static methods ------ */ + nsresult nsTableColFrame::NewFrame(nsIFrame** aInstancePtrResult, nsIContent* aContent, nsIFrame* aParent) @@ -99,6 +114,7 @@ nsTableCol::nsTableCol(nsIAtom* aTag) mColIndex(0), mRepeat(0) { + Init(); } nsTableCol::nsTableCol() @@ -107,6 +123,7 @@ nsTableCol::nsTableCol() mColIndex(0), mRepeat(0) { + Init(); } nsTableCol::nsTableCol (PRBool aImplicit) @@ -116,6 +133,22 @@ nsTableCol::nsTableCol (PRBool aImplicit) mRepeat(0) { mImplicit = aImplicit; + Init(); +} + +void nsTableCol::Init() +{ + /* begin hack */ + // temporary hack to get around style sheet optimization that folds all + // col style context into one, unless there is a unique HTML attribute set + char out[40]; + PR_snprintf(out, 40, "%d", HACKcounter); + const nsString value(out); + if (nsnull==HACKattribute) + HACKattribute = NS_NewAtom("Steve's unbelievable hack attribute"); + SetAttribute(HACKattribute, value); + HACKcounter++; + /* end hack */ } nsTableCol::~nsTableCol() diff --git a/layout/html/table/src/nsTableCol.h b/layout/html/table/src/nsTableCol.h index 1109001d782e..ad43828399b7 100644 --- a/layout/html/table/src/nsTableCol.h +++ b/layout/html/table/src/nsTableCol.h @@ -105,6 +105,9 @@ public: virtual void ResetColumns (); +private: + void Init(); + }; diff --git a/layout/html/table/src/nsTableColFrame.h b/layout/html/table/src/nsTableColFrame.h index 80e0c761a4a5..29f554e1eb1d 100644 --- a/layout/html/table/src/nsTableColFrame.h +++ b/layout/html/table/src/nsTableColFrame.h @@ -37,6 +37,9 @@ public: const nsReflowState& aReflowState, nsReflowStatus& aStatus); + /** return the index of the column this content object represents. always >= 0 */ + virtual int GetColumnIndex (); + protected: nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame); diff --git a/layout/html/table/src/nsTableColGroup.cpp b/layout/html/table/src/nsTableColGroup.cpp index bc6ccadf32b4..6c43fedad2eb 100644 --- a/layout/html/table/src/nsTableColGroup.cpp +++ b/layout/html/table/src/nsTableColGroup.cpp @@ -35,6 +35,12 @@ static const PRBool gsDebug = PR_FALSE; static const PRBool gsNoisyRefs = PR_FALSE; #endif +// hack, remove when hack in nsTableCol constructor is removed +static PRInt32 HACKcounter=0; +static nsIAtom *HACKattribute=nsnull; +#include "prprf.h" // remove when nsTableCol constructor hack is removed +// end hack code + nsTableColGroup::nsTableColGroup(nsIAtom* aTag, int aSpan) : nsTableContent(aTag), @@ -42,6 +48,17 @@ nsTableColGroup::nsTableColGroup(nsIAtom* aTag, int aSpan) mStartColIndex(0), mColCount(0) { + /* begin hack */ + // temporary hack to get around style sheet optimization that folds all + // col style context into one, unless there is a unique HTML attribute set + char out[40]; + PR_snprintf(out, 40, "%d", HACKcounter); + const nsString value(out); + if (nsnull==HACKattribute) + HACKattribute = NS_NewAtom("Steve's unbelievable hack attribute"); + SetAttribute(HACKattribute, value); + HACKcounter++; + /* end hack */ } nsTableColGroup::nsTableColGroup (PRBool aImplicit) @@ -51,6 +68,17 @@ nsTableColGroup::nsTableColGroup (PRBool aImplicit) mColCount(0) { mImplicit = aImplicit; + /* begin hack */ + // temporary hack to get around style sheet optimization that folds all + // col style context into one, unless there is a unique HTML attribute set + char out[40]; + PR_snprintf(out, 40, "%d", HACKcounter); + const nsString value(out); + if (nsnull==HACKattribute) + HACKattribute = NS_NewAtom("Steve's unbelievable hack attribute"); + SetAttribute(HACKattribute, value); + HACKcounter++; + /* end hack */ } @@ -163,7 +191,7 @@ nsTableColGroup::AppendChild (nsIContent *aContent, PRBool aNotify) return NS_OK; } - PRBool result = PR_FALSE; + nsresult result = NS_ERROR_FAILURE; PRBool contentHandled = PR_FALSE; // SEC: TODO verify that aContent is table content nsTableContent *tableContent = (nsTableContent *)aContent; @@ -188,9 +216,10 @@ nsTableColGroup::AppendChild (nsIContent *aContent, PRBool aNotify) } if (PR_FALSE==contentHandled) result = nsTableContent::AppendChild (aContent, aNotify); - if (result) + if (NS_OK==result) { ((nsTableCol *)aContent)->SetColGroup (this); + ((nsTableCol *)aContent)->SetColumnIndex (mStartColIndex + mColCount); ResetColumns (); } @@ -214,8 +243,8 @@ nsTableColGroup::InsertChildAt (nsIContent *aContent, PRInt32 aIndex, } // if so, add the row to this group - PRBool result = nsTableContent::InsertChildAt (aContent, aIndex, aNotify); - if (result) + nsresult result = nsTableContent::InsertChildAt (aContent, aIndex, aNotify); + if (NS_OK==result) { ((nsTableCol *)aContent)->SetColGroup (this); ResetColumns (); @@ -245,8 +274,8 @@ nsTableColGroup::ReplaceChildAt (nsIContent * aContent, PRInt32 aIndex, nsIContent * lastChild = ChildAt (aIndex); // lastChild : REFCNT++ NS_ASSERTION(nsnull!=lastChild, "bad child"); - PRBool result = nsTableContent::ReplaceChildAt (aContent, aIndex, aNotify); - if (result) + nsresult result = nsTableContent::ReplaceChildAt (aContent, aIndex, aNotify); + if (NS_OK==result) { ((nsTableCol *)aContent)->SetColGroup (this); if (nsnull != lastChild) @@ -268,8 +297,8 @@ nsTableColGroup::RemoveChildAt (PRInt32 aIndex, PRBool aNotify) NS_ASSERTION((0<=aIndex && ChildCount()>aIndex), "bad arg"); nsIContent * lastChild = ChildAt (aIndex); // lastChild: REFCNT++ NS_ASSERTION(nsnull!=lastChild, "bad child"); - PRBool result = nsTableContent::RemoveChildAt (aIndex, aNotify); - if (result) + nsresult result = nsTableContent::RemoveChildAt (aIndex, aNotify); + if (NS_OK==result) { if (nsnull != lastChild) ((nsTableCol *)lastChild)->SetColGroup (nsnull); diff --git a/layout/html/table/src/nsTableContent.cpp b/layout/html/table/src/nsTableContent.cpp index d8a19f9fddad..e531dfdb0b44 100644 --- a/layout/html/table/src/nsTableContent.cpp +++ b/layout/html/table/src/nsTableContent.cpp @@ -135,15 +135,10 @@ PRBool nsTableContent::IsImplicit () const return mImplicit; } - -/* ----- overridable methods from nsHTMLContainer ----- */ - /** -* -* If the content is a nsTableContent then call SetTable on -* aContent, otherwise, do nothing. -* -*/ + * If the content is a nsTableContent then call SetTable on + * aContent, otherwise, do nothing. + */ void nsTableContent::SetTableForTableContent(nsIContent* aContent, nsTablePart *aTable) { if (aContent != nsnull) @@ -159,6 +154,8 @@ void nsTableContent::SetTableForTableContent(nsIContent* aContent, nsTablePart * } +/* ----- overridable methods from nsHTMLContainer ----- */ + void nsTableContent::List(FILE* out, PRInt32 aIndent) const { PRInt32 i; diff --git a/layout/html/table/src/nsTableFrame.cpp b/layout/html/table/src/nsTableFrame.cpp index 2ebcbdcc8f66..26db465bbc3f 100644 --- a/layout/html/table/src/nsTableFrame.cpp +++ b/layout/html/table/src/nsTableFrame.cpp @@ -26,6 +26,7 @@ #include "nsTableCell.h" #include "nsTableCellFrame.h" #include "nsTableCol.h" +#include "nsTableColFrame.h" #include "nsTableRowFrame.h" #include "nsTableRowGroupFrame.h" #include "nsColLayoutData.h" @@ -41,6 +42,7 @@ #include "nsIPtr.h" #include "nsIView.h" #include "nsHTMLAtoms.h" +#include "nsHTMLIIDs.h" #ifdef NS_DEBUG static PRBool gsDebug = PR_FALSE; @@ -135,6 +137,117 @@ struct InnerTableReflowState { } }; +/* ----------- ColumnInfoCache ---------- */ + +static const PRInt32 NUM_COL_WIDTH_TYPES=4; + +class ColumnInfoCache +{ +public: + ColumnInfoCache(PRInt32 aNumColumns); + ~ColumnInfoCache(); + + void AddColumnInfo(const nsStyleUnit aType, + PRInt32 aColumnIndex); + + void GetColumnsByType(const nsStyleUnit aType, + PRInt32& aOutNumColumns, + PRInt32 *& aOutColumnIndexes); + enum ColWidthType { + eColWidthType_Auto = 0, // width based on contents + eColWidthType_Percent = 1, // (float) 1.0 == 100% + eColWidthType_Coord = 2, // (nscoord) value is twips + eColWidthType_Proportional = 3, // (int) value has proportional meaning + }; + +private: + PRInt32 mColCounts [4]; + PRInt32 *mColIndexes[4]; + PRInt32 mNumColumns; +}; + +ColumnInfoCache::ColumnInfoCache(PRInt32 aNumColumns) +{ + mNumColumns = aNumColumns; + for (PRInt32 i=0; iGetSize(rowGroupFrameSize); rowGroupFrame->SizeTo(rowGroupFrameSize.width, rowGroupHeight); tableHeight += rowGroupHeight; + if (nsnull!=rowHeights) + delete [] rowHeights; } } if (0!=tableHeight) @@ -1904,12 +2022,61 @@ void nsTableFrame::ShrinkWrapChildren(nsIPresContext* aPresContext, } void nsTableFrame::VerticallyAlignChildren(nsIPresContext* aPresContext, - nscoord* aAscents, - nscoord aMaxAscent, - nscoord aMaxHeight) + nscoord* aAscents, + nscoord aMaxAscent, + nscoord aMaxHeight) { } +/* there's an easy way and a hard way. The easy way is to look in our + * cache and pull the frame from there. + * If the cache isn't built yet, then we have to go hunting. + */ +NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame) +{ + aColFrame = nsnull; // initialize out parameter + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + if (nsnull!=firstInFlow->mColumnLayoutData) + { // hooray, we get to do this the easy way because the info is cached + nsColLayoutData * colData = (nsColLayoutData *) + (firstInFlow->mColumnLayoutData->ElementAt(aColIndex)); + NS_ASSERTION(nsnull != colData, "bad column data"); + aColFrame = colData->GetColFrame(); + NS_ASSERTION(nsnull!=aColFrame, "bad col frame"); + } + else + { // ah shucks, we have to go hunt for the column frame brute-force style + nsIFrame *childFrame; + FirstChild(childFrame); + for (;;) + { + if (nsnull==childFrame) + { + NS_ASSERTION (PR_FALSE, "scanned the frame hierarchy and no column frame could be found."); + break; + } + nsIContentPtr kid; + childFrame->GetContent(kid.AssignRef()); + const PRInt32 contentType = ((nsTableContent *)(nsIContent*)kid)->GetType(); + if (contentType==nsITableContent::kTableColGroupType) + { + nsTableColGroup *colGroup = (nsTableColGroup *)((nsIContent*)kid); + PRInt32 colGroupStartingIndex = colGroup->GetStartColumnIndex(); + if (aColIndex >= colGroupStartingIndex) + { // the cell's col might be in this col group + if (aColIndex < colGroupStartingIndex + colGroup->ChildCount()) + { // yep, we've found it + childFrame->ChildAt(aColIndex-colGroupStartingIndex, (nsIFrame *&)aColFrame); + break; + } + } + } + childFrame->GetNextSibling(childFrame); + } + } + return NS_OK; +} + nsVoidArray * nsTableFrame::GetColumnLayoutData() { nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); @@ -1922,7 +2089,8 @@ nsVoidArray * nsTableFrame::GetColumnLayoutData() * @return PR_TRUE if the data was successfully associated with a Cell * PR_FALSE if there was an error, such as aRow or aCol being invalid */ -PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aCell) +PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext, + nsCellLayoutData * aData, nsTableCell *aCell) { NS_ASSERTION(nsnull != aData, "bad arg"); NS_ASSERTION(nsnull != aCell, "bad arg"); @@ -1932,7 +2100,7 @@ PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aC nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); if (this!=firstInFlow) - result = firstInFlow->SetCellLayoutData(aData, aCell); + result = firstInFlow->SetCellLayoutData(aPresContext, aData, aCell); else { if (kPASS_FIRST==GetReflowPass()) @@ -1943,6 +2111,7 @@ PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aC NS_ASSERTION(nsnull != mColumnLayoutData, "bad alloc"); nsTablePart * tablePart = (nsTablePart *)mContent; PRInt32 cols = tablePart->GetMaxColumns(); + mColCache = new ColumnInfoCache(cols); PRInt32 tableKidCount = tablePart->ChildCount(); nsIFrame * colGroupFrame = mFirstChild; for (PRInt32 i=0; iChildCount(); for (PRInt32 j=0; jChildAt(j); NS_ASSERTION(col.IsNotNull(), "bad content"); nsColLayoutData *colData = new nsColLayoutData(col); @@ -1962,6 +2134,13 @@ PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aC colGroupFrame->ChildAt(j, (nsIFrame *&)colFrame); colData->SetColFrame(colFrame); mColumnLayoutData->AppendElement((void *)colData); + + // also add the column to the column cache + // assumes that the col style has been twiddled to account for first cell width attribute + nsIStyleContextPtr colSC; + colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); + nsStylePosition* colPosition = (nsStylePosition*)colSC->GetData(eStyleStruct_Position); + mColCache->AddColumnInfo(colPosition->mWidth.GetUnit(), colFrame->GetColumnIndex()); } } // can't have col groups after row groups, so stop if you find a row group @@ -2349,6 +2528,14 @@ NS_METHOD nsTableFrame::GetCellMarginData(nsIFrame* aKidFrame, nsMargin& aMargin return result; } +void nsTableFrame::GetColumnsByType(const nsStyleUnit aType, + PRInt32& aOutNumColumns, + PRInt32 *& aOutColumnIndexes) +{ + mColCache->GetColumnsByType(aType, aOutNumColumns, aOutColumnIndexes); +} + + /* ---------- static methods ---------- */ nsresult nsTableFrame::NewFrame(nsIFrame** aInstancePtrResult, @@ -2367,6 +2554,115 @@ nsresult nsTableFrame::NewFrame(nsIFrame** aInstancePtrResult, return NS_OK; } +/* helper method for getting the width of the table's containing block */ +nscoord nsTableFrame::GetTableContainerWidth(const nsReflowState& aReflowState) +{ +#ifdef STEVES_WAY // from BasicTableLayoutStrategy::TableIsAutoWidth() + // get the parent's width (available only from parent frames that claim they can provide it) + // note that we start with our parent's parent (the outer table frame's parent) + nscoord parentWidth = 0; + NS_ASSERTION(nsnull!=aReflowState.parentReflowState, "bad outer table reflow state."); + NS_ASSERTION(nsnull!=aReflowState.parentReflowState->parentReflowState, "bad table parent reflow state."); + if ((nsnull!=aReflowState.parentReflowState) && + (nsnull!=aReflowState.parentReflowState->parentReflowState)) + { + const nsReflowState *parentReflowState = aReflowState.parentReflowState->parentReflowState; + nsIFrame *parentFrame=parentReflowState->frame; + NS_ASSERTION(nsnull!=parentFrame, "bad parent frame in reflow state struct."); + while(nsnull!=parentFrame) + { + PRBool isPercentageBase=PR_FALSE; + parentFrame->IsPercentageBase(isPercentageBase); + if (PR_TRUE==isPercentageBase) + { // found the ancestor who claims to be the container to base my percentage width on + parentWidth = parentReflowState->maxSize.width; + if (PR_TRUE==gsDebug) printf(" ** width for parent frame %p = %d\n", parentFrame, parentWidth); + break; + } + parentReflowState = parentReflowState->parentReflowState; // get next ancestor + if (nsnull!=parentReflowState) + parentFrame = parentReflowState->frame; + else + parentFrame = nsnull; // terminates loop. + // TODO: do we need a backstop in case there are no IsPercentageBase==true frames? + } + } + +#else + + nscoord parentWidth = aReflowState.maxSize.width; + + // Walk up the reflow state chain until we find a block + // frame. Our width is computed relative to there. + const nsReflowState* rs = &aReflowState; + while (nsnull != rs) { + nsIFrame* block = nsnull; + rs->frame->QueryInterface(kBlockFrameCID, (void**) &block); + if (nsnull != block) { + // We found the nearest containing block which defines what + // a percentage size is relative to. Use the width that it + // will reflow to as the basis for computing our width. + parentWidth = rs->maxSize.width; + break; + } + rs = rs->parentReflowState; + } + +#endif + return parentWidth; +} + +// aSpecifiedTableWidth is filled if the table witdth is not auto +PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, + nsIStyleContext *aTableStyle, + const nsReflowState& aReflowState, + nscoord& aSpecifiedTableWidth) +{ + NS_ASSERTION(nsnull!=aTableStyle, "bad arg - aTableStyle"); + PRBool result = PR_TRUE; // the default + if (nsnull!=aTableStyle) + { + //nsStylePosition* tablePosition = (nsStylePosition*)aTableStyle->GetData(eStyleStruct_Position); + /* this is sick and wrong, but what the hell + we grab the style of our parent (nsTableOuterFrame) and ask it for width info, + until the style resolution stuff does the cool stuff about splitting style between outer and inner + */ + // begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! + nsIStyleContext* parentStyle = nsnull; + nsIFrame * parent = nsnull; + aTableFrame->GetGeometricParent(parent); + parent->GetStyleContext(nsnull, parentStyle); + nsStylePosition* tablePosition = (nsStylePosition*)parentStyle->GetData(eStyleStruct_Position); + // end REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! + switch (tablePosition->mWidth.GetUnit()) { + case eStyleUnit_Auto: // specified auto width + case eStyleUnit_Proportional: // illegal for table, so ignored + break; + + case eStyleUnit_Inherit: + // get width of parent and see if it is a specified value or not + // XXX for now, just return true + break; + + case eStyleUnit_Coord: + aSpecifiedTableWidth = tablePosition->mWidth.GetCoordValue(); + result = PR_FALSE; + break; + + case eStyleUnit_Percent: + // set aSpecifiedTableWidth to be the given percent of the parent. + nscoord parentWidth = nsTableFrame::GetTableContainerWidth(aReflowState); + float percent = tablePosition->mWidth.GetPercentValue(); + aSpecifiedTableWidth = (PRInt32)(parentWidth*percent); + if (PR_TRUE==gsDebug) printf(" ** aSpecifiedTableWidth = %d\n", aSpecifiedTableWidth); + result = PR_FALSE; + break; + } + } + + return result; +} + /* valuable code not yet used anywhere // since the table is a specified width, we need to expand the columns to fill the table diff --git a/layout/html/table/src/nsTableFrame.h b/layout/html/table/src/nsTableFrame.h index 7dbc1fb8c49d..70657556236b 100644 --- a/layout/html/table/src/nsTableFrame.h +++ b/layout/html/table/src/nsTableFrame.h @@ -25,12 +25,15 @@ class nsCellLayoutData; class nsTableCell; class nsVoidArray; class nsTableCellFrame; +class nsTableColFrame; class CellData; class nsITableLayoutStrategy; class nsHTMLValue; +class ColumnInfoCache; struct InnerTableReflowState; struct nsStylePosition; struct nsStyleSpacing; +enum nsStyleUnit; /** nsTableFrame maps the inner portion of a table (everything except captions.) * Used as a pseudo-frame within nsTableOuterFrame, @@ -59,6 +62,15 @@ public: nsIContent* aContent, nsIFrame* aParent); + /** helper method for getting the width of the table's containing block */ + static nscoord GetTableContainerWidth(const nsReflowState& aState); + + + static PRBool TableIsAutoWidth(nsTableFrame *aTableFrame, + nsIStyleContext *aTableStyle, + const nsReflowState& aReflowState, + nscoord& aSpecifiedTableWidth); + /** @see nsIFrame::Paint */ NS_IMETHOD Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, @@ -108,16 +120,29 @@ public: nsReflowMetrics& aDesiredSize, nsSize* aMaxElementSize); + /** return the column frame corresponding to the given column index + * there are two ways to do this, depending on whether we have cached + * column information yet. + */ + NS_METHOD GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame); + /** return the column layout data for this inner table frame. * if this is a continuing frame, return the first-in-flow's column layout data. */ virtual nsVoidArray *GetColumnLayoutData(); /** Associate aData with the cell at (aRow,aCol) + * + * @param aPresContext -- used to resolve style when initializing caches + * @param aData -- the info to cache + * @param aCell -- the content object for which layout info is being cached + * * @return PR_TRUE if the data was successfully associated with a Cell * PR_FALSE if there was an error, such as aRow or aCol being invalid */ - virtual PRBool SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aCell); + virtual PRBool SetCellLayoutData(nsIPresContext* aPresContext, + nsCellLayoutData * aData, + nsTableCell *aCell); /** Get the layout data associated with the cell at (aRow,aCol) * @return PR_NULL if there was an error, such as aRow or aCol being invalid @@ -154,6 +179,18 @@ public: // Get cell margin information NS_IMETHOD GetCellMarginData(nsIFrame* aKidFrame, nsMargin& aMargin); + /** get cached column information for a subset of the columns + * + * @param aType -- information is returned for the subset of columns with aType style + * @param aOutNumColumns -- out param, the number of columns matching aType + * @param aOutColumnIndexes -- out param, the indexes of the columns matching aType + * + * TODO : make aOutColumnIndexes safe + */ + void GetColumnsByType(const nsStyleUnit aType, + PRInt32& aOutNumColumns, + PRInt32 *& aOutColumnIndexes); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); @@ -304,6 +341,8 @@ private: nsVoidArray *mColumnLayoutData; // array of array of cellLayoutData's PRInt32 *mColumnWidths; // widths of each column + //TODO: move all column info into this object + ColumnInfoCache *mColCache; // cached information about the table columns PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit PRInt32 mPass; // which Reflow pass are we currently in? PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change diff --git a/layout/html/table/src/nsTablePart.cpp b/layout/html/table/src/nsTablePart.cpp index 99b5048d48c5..faafdc1422ab 100644 --- a/layout/html/table/src/nsTablePart.cpp +++ b/layout/html/table/src/nsTablePart.cpp @@ -342,19 +342,18 @@ NS_IMETHODIMP nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) { NS_PRECONDITION(nsnull!=aContent, "bad arg"); - PRBool result = PR_FALSE; PRBool newCells = PR_FALSE; PRBool contentHandled = PR_FALSE; // wait, stop! need to check to see if this is really tableContent or not! nsITableContent *tableContentInterface = nsnull; + PRBool result = PR_TRUE; // to be removed when called methods are COM-ized nsresult rv = aContent->QueryInterface(kITableContentIID, (void **)&tableContentInterface); // tableContentInterface: REFCNT++ if (NS_FAILED(rv)) { // create an implicit cell and return the result of adding it to the table - if (gsDebug==PR_TRUE) - printf ("*** bad HTML in table, not yet implemented.\n"); - return PR_FALSE; + NS_ASSERTION(PR_FALSE, "non-table content insertion not implemented"); + return NS_ERROR_FAILURE; } else { @@ -394,18 +393,20 @@ nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) nsIAtom * rowGroupTag = NS_NewAtom(kRowGroupBodyTagString); // rowGroupTag: REFCNT++ group = new nsTableRowGroup (rowGroupTag, PR_TRUE); NS_ADDREF(group); // group: REFCNT++ - AppendChild (group, PR_FALSE); - group->SetTable(this); + rv = AppendChild (group, PR_FALSE); + if (NS_OK==rv) + group->SetTable(this); NS_RELEASE(rowGroupTag); // rowGroupTag: REFCNT-- } // group is guaranteed to be allocated at this point - result = group->AppendChild(aContent, PR_FALSE); - newCells = result; + rv = group->AppendChild(aContent, PR_FALSE); + newCells = (PRBool)(NS_OK==rv); contentHandled = PR_TRUE; NS_RELEASE(group); // group: REFCNT-- } else if (contentType == nsITableContent::kTableColType) { + // TODO: switch Append* to COM interfaces result = AppendColumn((nsTableCol *)aContent); newCells = result; contentHandled = PR_TRUE; @@ -422,6 +423,8 @@ nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) { newCells = PR_TRUE; } + else + rv=NS_ERROR_FAILURE; contentHandled = PR_TRUE; // whether we succeeded or not, we've "handled" this request } else if (contentType == nsITableContent::kTableColGroupType) @@ -431,6 +434,8 @@ nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) { newCells = PR_TRUE; } + else + rv = NS_ERROR_FAILURE; contentHandled = PR_TRUE; // whether we succeeded or not, we've "handled" this request } @@ -452,7 +457,8 @@ nsTablePart::AppendChild (nsIContent * aContent, PRBool aNotify) { if (gsDebug==PR_TRUE) printf ("nsTablePart::AppendChild -- adding an implicit caption.\n"); caption = new nsTableCaption (PR_TRUE); - AppendCaption (caption); + result = AppendCaption (caption); + // check result } result = caption->AppendChild (aContent, PR_FALSE); } @@ -625,8 +631,11 @@ PRBool nsTablePart::AppendRowGroup (nsTableRowGroup *aContent) NS_RELEASE(tHeadTag); NS_RELEASE(tBodyTag); - nsHTMLContainer::InsertChildAt(aContent, childIndex, PR_FALSE); - ((nsTableContent *)aContent)->SetTable (this); + nsresult rv = nsHTMLContainer::InsertChildAt(aContent, childIndex, PR_FALSE); + if (NS_OK==rv) + ((nsTableContent *)aContent)->SetTable (this); + else + result = PR_FALSE; return result; } @@ -634,6 +643,7 @@ PRBool nsTablePart::AppendRowGroup (nsTableRowGroup *aContent) /** protected method for appending a column group to this table */ PRBool nsTablePart::AppendColGroup(nsTableColGroup *aContent) { + PRBool result = PR_TRUE; // to be removed when I'm COM-ized PRInt32 childIndex; NS_PRECONDITION(nsnull!=aContent, "null arg."); if (gsDebug==PR_TRUE) @@ -651,27 +661,39 @@ PRBool nsTablePart::AppendColGroup(nsTableColGroup *aContent) (tableChildType == nsITableContent::kTableColGroupType))) break; } - nsHTMLContainer::InsertChildAt(aContent, childIndex, PR_FALSE); - ((nsTableContent *)aContent)->SetTable (this); + nsresult rv = nsHTMLContainer::InsertChildAt(aContent, childIndex, PR_FALSE); + if (NS_OK==rv) + ((nsTableContent *)aContent)->SetTable (this); + else + result = PR_FALSE; // if col group has a SPAN attribute, create implicit columns for // the value of SPAN what sucks is if we then get a COL for this // COLGROUP, we have to delete all the COLs we created for SPAN, and // just contain the explicit COLs. + + // TODO: move this into the OK clause above + PRInt32 span = 0; // SEC: TODO find a way to really get this for (PRInt32 i=0; iAppendChild (col, PR_FALSE); + rv = aContent->AppendChild (col, PR_FALSE); + if (NS_OK!=rv) + { + result = PR_FALSE; + break; + } } - return PR_TRUE; + return result; } /** protected method for appending a column group to this table */ PRBool nsTablePart::AppendColumn(nsTableCol *aContent) { NS_PRECONDITION(nsnull!=aContent, "null arg."); + nsresult rv = NS_OK; if (gsDebug==PR_TRUE) printf ("nsTablePart::AppendColumn -- adding a column.\n"); // find last col group, if ! implicit, make one, append there @@ -694,17 +716,20 @@ PRBool nsTablePart::AppendColumn(nsTableCol *aContent) if (gsDebug==PR_TRUE) printf ("nsTablePart::AppendChild -- creating an implicit column group.\n"); group = new nsTableColGroup (PR_TRUE); - AppendChild (group, PR_FALSE); - group->SetTable(this); + rv = AppendChild (group, PR_FALSE); + if (NS_OK==rv) + group->SetTable(this); } - group->AppendChild (aContent, PR_FALSE); + if (NS_OK==rv) + rv = group->AppendChild (aContent, PR_FALSE); - return PR_TRUE; + return (PRBool)(NS_OK==rv); } /** protected method for appending a column group to this table */ PRBool nsTablePart::AppendCaption(nsTableCaption *aContent) { + nsresult rv = NS_OK; PRInt32 childIndex; NS_PRECONDITION(nsnull!=aContent, "null arg."); if (gsDebug==PR_TRUE) @@ -720,10 +745,11 @@ PRBool nsTablePart::AppendCaption(nsTableCaption *aContent) if (tableChildType != nsITableContent::kTableCaptionType) break; } - nsHTMLContainer::InsertChildAt(aContent, childIndex, PR_FALSE); - ((nsTableContent *)aContent)->SetTable (this); + rv = nsHTMLContainer::InsertChildAt(aContent, childIndex, PR_FALSE); + if (NS_OK==rv) + ((nsTableContent *)aContent)->SetTable (this); - return PR_TRUE; + return (PRBool)(NS_OK==rv); } /* return the index of the first row group after aStartIndex */ diff --git a/layout/html/table/src/nsTableRow.cpp b/layout/html/table/src/nsTableRow.cpp index a36e2da51bee..1f4d9bd1003b 100644 --- a/layout/html/table/src/nsTableRow.cpp +++ b/layout/html/table/src/nsTableRow.cpp @@ -167,8 +167,10 @@ nsTableRow::InsertChildAt (nsIContent *aContent, PRInt32 aIndex, nsTableContent *tableContent = (nsTableContent *)aContent; const int contentType = tableContent->GetType(); if (contentType != nsITableContent::kTableCellType) - { - return NS_OK; + { // I only insert cells for now + // TODO: wrap whatever I'm given here in a cell and insert it + NS_ASSERTION(PR_FALSE, "unimplemented attempt to insert a non-cell into a row"); + return NS_ERROR_FAILURE; } else { @@ -193,17 +195,22 @@ nsTableRow::ReplaceChildAt (nsIContent *aContent, PRInt32 aIndex, NS_PRECONDITION(nsnull!=aContent, "bad aContent arg to ReplaceChildAt"); NS_PRECONDITION(0<=aIndex && aIndexGetType(); if (contentType != nsITableContent::kTableCellType) - { - return NS_OK; + { // I only insert cells for now + // TODO: wrap whatever I'm given here in a cell and insert it + NS_ASSERTION(PR_FALSE, "unimplemented attempt to insert a non-cell into a row"); + return NS_ERROR_FAILURE; } else - return NS_OK; + { + NS_ASSERTION(PR_FALSE, "unimplemented attempt to replace a cell in a row"); + return NS_ERROR_NOT_IMPLEMENTED; + } #if XXX nsIContent * oldChild = ChildAt (aIndex); // oldChild: REFCNT++ result = nsTableContent::ReplaceChildAt (aContent, aIndex, aNotify); @@ -229,7 +236,7 @@ nsTableRow::RemoveChildAt (int aIndex, PRBool aNotify) { NS_PRECONDITION(0<=aIndex && aIndexSetCellLayoutData(&kidLayoutData, cell); + aState.tableFrame->SetCellLayoutData(aPresContext, &kidLayoutData, cell); } else { // we're in a constrained situation, so get the avail width from the known column widths @@ -428,13 +430,11 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, case eStyleUnit_Coord: specifiedHeight = kidPosition->mHeight.GetCoordValue(); break; - case eStyleUnit_Percent: - case eStyleUnit_Proportional: - // XXX for now these fall through + case eStyleUnit_Inherit: + // XXX for now, do nothing default: case eStyleUnit_Auto: - case eStyleUnit_Inherit: break; } if (specifiedHeight>cellHeight) @@ -893,10 +893,9 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, break; } - nsIFrame* kidFrame; - // Create a child frame + // Create a child frame -- always an nsTableCell frame nsIStyleContext* kidStyleContext = aPresContext->ResolveStyleContextFor(cell, this); if (nsnull == kidPrevInFlow) { nsIContentDelegate* kidDel = nsnull; @@ -908,6 +907,11 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, kidPrevInFlow->CreateContinuingFrame(aPresContext, this, kidStyleContext, kidFrame); } + /* since I'm creating the cell frame, this is the first time through reflow + * it's a good time to set the column style from the cell's width attribute + * if this is the first row + */ + SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)kidFrame, kidStyleContext); NS_RELEASE(kidStyleContext); @@ -937,7 +941,7 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, kidFrame->WillReflow(*aPresContext); status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState); nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); - aState.tableFrame->SetCellLayoutData(&kidLayoutData, (nsTableCell *)cell); + aState.tableFrame->SetCellLayoutData(aPresContext, &kidLayoutData, (nsTableCell *)cell); } else { // we're in a constrained situation, so get the avail width from the known column widths @@ -1146,6 +1150,54 @@ nsTableRowFrame::CreateContinuingFrame(nsIPresContext* aPresContext, return NS_OK; } +NS_METHOD +nsTableRowFrame::SetColumnStyleFromCell(nsIPresContext* aPresContext, + nsTableCellFrame* aCellFrame, + nsIStyleContext* aCellSC) +{ + // if this cell is in the first row, then the width attribute + // also acts as the width attribute for the entire column + if ((nsnull!=aCellSC) && (nsnull!=aCellFrame)) + { + PRInt32 rowIndex = ((nsTableRow*)mContent)->GetRowIndex(); + if (0==rowIndex) + { + // get the cell style info + nsStylePosition* cellPosition = (nsStylePosition*) aCellSC->GetData(eStyleStruct_Position); + if ((eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) || + (eStyleUnit_Percent==cellPosition->mWidth.GetUnit())) { + + // compute the width per column spanned + PRInt32 colSpan = aCellFrame->GetColSpan(); + // get the appropriate column frame + nsTableFrame *tableFrame; + mGeometricParent->GetGeometricParent((nsIFrame *&)tableFrame); + nsTableColFrame *colFrame; + tableFrame->GetColumnFrame(aCellFrame->GetColIndex(), colFrame); + // get the column style and set the width attribute + nsIStyleContextPtr colSC; + colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); + nsStylePosition* colPosition = (nsStylePosition*) colSC->GetData(eStyleStruct_Position); + // set the column width attribute + colPosition->mWidth = cellPosition->mWidth; + /* + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + { + nscoord width = cellPosition->mWidth.GetCoordValue(); + colPosition->mWidth.SetCoordValue(width); + } + else + { + float width = cellPosition->mWidth.GetPercentValue(); + colPosition->mWidth.SetPercentValue(width); + } + */ + } + } + } + return NS_OK; +} + nsresult nsTableRowFrame::NewFrame( nsIFrame** aInstancePtrResult, nsIContent* aContent, nsIFrame* aParent) diff --git a/layout/html/table/src/nsTableRowFrame.h b/layout/html/table/src/nsTableRowFrame.h index 952af3bd04ad..b19de1c7311d 100644 --- a/layout/html/table/src/nsTableRowFrame.h +++ b/layout/html/table/src/nsTableRowFrame.h @@ -22,6 +22,7 @@ #include "nsContainerFrame.h" class nsTableFrame; +class nsTableCellFrame; struct RowReflowState; /** @@ -160,6 +161,9 @@ protected: RowReflowState& aState, nsSize* aMaxElementSize); + NS_METHOD SetColumnStyleFromCell(nsIPresContext * aPresContext, + nsTableCellFrame* aCellFrame, + nsIStyleContext * aCellSC); private: nscoord mTallestCell; // not my height, but the height of my tallest child diff --git a/layout/html/table/src/nsTableRowGroup.cpp b/layout/html/table/src/nsTableRowGroup.cpp index 19ffaf6c71e4..dc0a4f42b615 100644 --- a/layout/html/table/src/nsTableRowGroup.cpp +++ b/layout/html/table/src/nsTableRowGroup.cpp @@ -42,10 +42,27 @@ static const PRBool gsNoisyRefs = PR_FALSE; static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kITableContentIID, NS_ITABLECONTENT_IID); +// hack, remove when hack in nsTableCol constructor is removed +static PRInt32 HACKcounter=0; +static nsIAtom *HACKattribute=nsnull; +#include "prprf.h" // remove when nsTableCol constructor hack is removed +// end hack code + // nsTableContent checks aTag nsTableRowGroup::nsTableRowGroup(nsIAtom* aTag) : nsTableContent(aTag) { + /* begin hack */ + // temporary hack to get around style sheet optimization that folds all + // col style context into one, unless there is a unique HTML attribute set + char out[40]; + PR_snprintf(out, 40, "%d", HACKcounter); + const nsString value(out); + if (nsnull==HACKattribute) + HACKattribute = NS_NewAtom("Steve's unbelievable hack attribute"); + SetAttribute(HACKattribute, value); + HACKcounter++; + /* end hack */ } // nsTableContent checks aTag @@ -53,6 +70,17 @@ nsTableRowGroup::nsTableRowGroup(nsIAtom* aTag, PRBool aImplicit) : nsTableContent(aTag) { mImplicit = aImplicit; + /* begin hack */ + // temporary hack to get around style sheet optimization that folds all + // col style context into one, unless there is a unique HTML attribute set + char out[40]; + PR_snprintf(out, 40, "%d", HACKcounter); + const nsString value(out); + if (nsnull==HACKattribute) + HACKattribute = NS_NewAtom("Steve's unbelievable hack attribute"); + SetAttribute(HACKattribute, value); + HACKcounter++; + /* end hack */ } nsTableRowGroup::~nsTableRowGroup() @@ -124,7 +152,7 @@ NS_IMETHODIMP nsTableRowGroup::AppendChild (nsIContent *aContent, PRBool aNotify) { NS_PRECONDITION(nsnull!=aContent, "bad arg to AppendChild"); - PRBool result = PR_TRUE; + nsresult result = NS_OK; // is aContent a TableRow? PRBool isRow = IsRow(aContent); @@ -134,9 +162,16 @@ nsTableRowGroup::AppendChild (nsIContent *aContent, PRBool aNotify) { if (gsDebug==PR_TRUE) printf ("nsTableRowGroup::AppendChild -- inserting a row into this row group.\n"); // if it is, we'll add it here - nsTableContent::AppendChild (aContent, PR_FALSE); - ((nsTableRow *)aContent)->SetRowGroup (this); - ResetCellMap (); + result = nsTableContent::AppendChild (aContent, PR_FALSE); + if (NS_OK==result) + { + ((nsTableRow *)aContent)->SetRowGroup (this); + // after each row insertion, make sure we have corresponding column content objects + if (nsnull!=mTable) + mTable->EnsureColumns(); + // also make sure the table cell map gets rebuilt + ResetCellMap (); + } } // otherwise, if it's a cell, create an implicit row for it else @@ -165,20 +200,20 @@ nsTableRowGroup::AppendChild (nsIContent *aContent, PRBool aNotify) nsIAtom * trDefaultTag = NS_NewAtom(nsTablePart::kRowTagString); // trDefaultTag: REFCNT++ row = new nsTableRow (trDefaultTag, PR_TRUE); NS_RELEASE(trDefaultTag); // trDefaultTag: REFCNT-- - AppendChild (row, PR_FALSE); + result = AppendChild (row, PR_FALSE); // SEC: check result } // group is guaranteed to be allocated at this point - row->AppendChild(aContent, PR_FALSE); + result = row->AppendChild(aContent, PR_FALSE); } // otherwise, punt and let the table try to insert it. Or maybe just return a failure? else { // you should go talk to my parent if you want to insert something other than a row - result = PR_FALSE; + result = NS_ERROR_FAILURE; } } - return NS_OK; + return result; } NS_IMETHODIMP @@ -194,15 +229,18 @@ nsTableRowGroup::InsertChildAt (nsIContent *aContent, PRInt32 aIndex, if (PR_FALSE==isRow) { // you should go talk to my parent if you want to insert something other than a column - return NS_OK; + return NS_ERROR_FAILURE; } // if so, add the row to this group - nsTableContent::InsertChildAt (aContent, aIndex, PR_FALSE); - ((nsTableRow *)aContent)->SetRowGroup (this); - ResetCellMap (); + nsresult result = nsTableContent::InsertChildAt (aContent, aIndex, PR_FALSE); + if (NS_OK==result) + { + ((nsTableRow *)aContent)->SetRowGroup (this); + ResetCellMap (); + } - return NS_OK; + return result; } @@ -213,19 +251,21 @@ nsTableRowGroup::ReplaceChildAt (nsIContent *aContent, PRInt32 aIndex, NS_PRECONDITION(nsnull!=aContent, "bad aContent arg to ReplaceChildAt"); NS_PRECONDITION(0<=aIndex && aIndexSetRowGroup (this); if (nsnull != lastChild) @@ -233,7 +273,7 @@ nsTableRowGroup::ReplaceChildAt (nsIContent *aContent, PRInt32 aIndex, ResetCellMap (); } NS_IF_RELEASE(lastChild); // lastChild: REFCNT-- - return NS_OK; + return result; } /** @@ -245,17 +285,18 @@ nsTableRowGroup::RemoveChildAt (PRInt32 aIndex, PRBool aNotify) { NS_PRECONDITION(0<=aIndex && aIndexSetRowGroup (nsnull); ResetCellMap (); } NS_IF_RELEASE(lastChild); // lastChild: REFCNT-- - return NS_OK; + return result; } /** support method to determine if the param aContent is a TableRow object */ diff --git a/layout/style/ua.css b/layout/style/ua.css index 141e80a30b19..ce7b1920e4e3 100644 --- a/layout/style/ua.css +++ b/layout/style/ua.css @@ -118,6 +118,7 @@ A:visited IMG { border: 2px solid purple; text-decoration: underline } A:active IMG { border: 2px solid lime; text-decoration: underline } A:out-of-date IMG { border: 2px solid red; text-decoration: underline } + //---------------------------------------------------------------------- // The real stuff diff --git a/layout/tables/BasicTableLayoutStrategy.cpp b/layout/tables/BasicTableLayoutStrategy.cpp index 3070448f1907..f726a4989aa2 100644 --- a/layout/tables/BasicTableLayoutStrategy.cpp +++ b/layout/tables/BasicTableLayoutStrategy.cpp @@ -116,112 +116,6 @@ PRBool BasicTableLayoutStrategy::IsAutoWidth(nsStylePosition* aStylePosition) } -// aSpecifiedTableWidth is filled if the table witdth is not auto -PRBool BasicTableLayoutStrategy::TableIsAutoWidth(nsIStyleContext *aTableStyle, - const nsReflowState& aReflowState, - nscoord& aSpecifiedTableWidth) -{ - NS_ASSERTION(nsnull!=aTableStyle, "bad arg - aTableStyle"); - PRBool result = PR_TRUE; // the default - if (nsnull!=aTableStyle) - { - //nsStylePosition* tablePosition = (nsStylePosition*)aTableStyle->GetData(eStyleStruct_Position); - /* this is sick and wrong, but what the hell - we grab the style of our parent (nsTableOuterFrame) and ask it for width info, - until the style resolution stuff does the cool stuff about splitting style between outer and inner - */ - // begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! - nsIStyleContext* parentStyle = nsnull; - nsIFrame * parent = nsnull; - mTableFrame->GetGeometricParent(parent); - parent->GetStyleContext(nsnull, parentStyle); - nsStylePosition* tablePosition = (nsStylePosition*)parentStyle->GetData(eStyleStruct_Position); - // end REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! - switch (tablePosition->mWidth.GetUnit()) { - case eStyleUnit_Auto: // specified auto width - case eStyleUnit_Proportional: // illegal for table, so ignored - break; - - case eStyleUnit_Inherit: - // get width of parent and see if it is a specified value or not - // XXX for now, just return true - break; - - case eStyleUnit_Coord: - aSpecifiedTableWidth = tablePosition->mWidth.GetCoordValue(); - result = PR_FALSE; - break; -#ifdef STEVES_WAY - case eStyleUnit_Percent: - // get the parent's width (available only from parent frames that claim they can provide it) - // note that we start with our parent's parent (the outer table frame's parent) - nscoord parentWidth = 0; - NS_ASSERTION(nsnull!=aReflowState.parentReflowState, "bad outer table reflow state."); - NS_ASSERTION(nsnull!=aReflowState.parentReflowState->parentReflowState, "bad table parent reflow state."); - if ((nsnull!=aReflowState.parentReflowState) && - (nsnull!=aReflowState.parentReflowState->parentReflowState)) - { - const nsReflowState *parentReflowState = aReflowState.parentReflowState->parentReflowState; - nsIFrame *parentFrame=parentReflowState->frame; - NS_ASSERTION(nsnull!=parentFrame, "bad parent frame in reflow state struct."); - while(nsnull!=parentFrame) - { - PRBool isPercentageBase=PR_FALSE; - parentFrame->IsPercentageBase(isPercentageBase); - if (PR_TRUE==isPercentageBase) - { // found the ancestor who claims to be the container to base my percentage width on - parentWidth = parentReflowState->maxSize.width; - if (PR_TRUE==gsDebug) printf(" ** width for parent frame %p = %d\n", parentFrame, parentWidth); - break; - } - parentReflowState = parentReflowState->parentReflowState; // get next ancestor - if (nsnull!=parentReflowState) - parentFrame = parentReflowState->frame; - else - parentFrame = nsnull; // terminates loop. - // TODO: do we need a backstop in case there are no IsPercentageBase==true frames? - } - } - -#else - case eStyleUnit_Percent: - // Get the parent's width (available only from parent frames - // that claim they can provide it, and assuming it's already - // specified; that is, top-down layout sets the widths on the - // way down.) - nscoord parentWidth = aReflowState.maxSize.width; - - // Walk up the reflow state chain until we find a block - // frame. Our width is computed relative to there. - const nsReflowState* rs = &aReflowState; - while (nsnull != rs) { - nsIFrame* block = nsnull; - rs->frame->QueryInterface(kBlockFrameCID, (void**) &block); - if (nsnull != block) { - // We found the nearest containing block which defines what - // a percentage size is relative to. Use the width that it - // will reflow to as the basis for computing our width. - parentWidth = rs->maxSize.width; - break; - } - rs = rs->parentReflowState; - } - -#endif - - // set aSpecifiedTableWidth to be the given percent of the parent. - float percent = tablePosition->mWidth.GetPercentValue(); - aSpecifiedTableWidth = (PRInt32)(parentWidth*percent); - if (PR_TRUE==gsDebug) printf(" ** aSpecifiedTableWidth = %d\n", aSpecifiedTableWidth); - result = PR_FALSE; - break; - } - } - - return result; -} - - BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aFrame) { mTableFrame = aFrame; @@ -260,12 +154,12 @@ PRBool BasicTableLayoutStrategy::BalanceColumnWidths(nsIPresContext* aPresContex // Step 2 - determine how much space is really available PRInt32 availWidth = aMaxWidth - aTotalFixedWidth; nscoord tableWidth = 0; - if (PR_FALSE==TableIsAutoWidth(aTableStyle, aReflowState, tableWidth)) + if (PR_FALSE==nsTableFrame::TableIsAutoWidth(mTableFrame, aTableStyle, aReflowState, tableWidth)) availWidth = tableWidth - aTotalFixedWidth; // Step 3 - assign the width of all proportional-width columns in the remaining space if (gsDebug==PR_TRUE) printf ("Step 2...\n availWidth = %d\n", availWidth); - result = BalanceProportionalColumns(aPresContext, + result = BalanceProportionalColumns(aPresContext, aReflowState, availWidth, aMaxWidth, aMinTableWidth, aMaxTableWidth, tableWidth); @@ -525,6 +419,7 @@ PRBool BasicTableLayoutStrategy::AssignFixedColumnWidths(nsIPresContext* aPresCo PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPresContext, + const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, nscoord aMinTableWidth, @@ -538,7 +433,7 @@ PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPre if (NS_UNCONSTRAINEDSIZE==aMaxWidth || NS_UNCONSTRAINEDSIZE==aMinTableWidth) { // the max width of the table fits comfortably in the available space if (gsDebug) printf (" * table laying out in NS_UNCONSTRAINEDSIZE, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aAvailWidth, aMaxWidth, aTableFixedWidth); + result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, aMaxWidth, aTableFixedWidth); } else if (aMinTableWidth > aMaxWidth) { // the table doesn't fit in the available space @@ -548,7 +443,7 @@ PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPre else if (aMaxTableWidth <= aMaxWidth) { // the max width of the table fits comfortably in the available space if (gsDebug) printf (" * table desired size fits, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aAvailWidth, aMaxWidth, aTableFixedWidth); + result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, aMaxWidth, aTableFixedWidth); } else { // the table fits somewhere between its min and desired size @@ -562,7 +457,7 @@ PRBool BasicTableLayoutStrategy::BalanceProportionalColumns(nsIPresContext* aPre if (NS_UNCONSTRAINEDSIZE==aMinTableWidth) { // the table has empty content, and needs to be streched to the specified width if (gsDebug) printf (" * specified width table > maxTableWidth, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aAvailWidth, aMaxWidth, aTableFixedWidth); + result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, aMaxWidth, aTableFixedWidth); } else if (aTableFixedWidth= its max width, so give each column its max requested size if (gsDebug) printf (" * specified width table > maxTableWidth, calling BalanceColumnsTableFits\n"); - result = BalanceColumnsTableFits(aPresContext, aAvailWidth, aMaxWidth, aTableFixedWidth); + result = BalanceColumnsTableFits(aPresContext, aReflowState, aAvailWidth, aMaxWidth, aTableFixedWidth); } } return result; @@ -639,7 +534,8 @@ PRBool BasicTableLayoutStrategy::SetColumnsToMinWidth(nsIPresContext* aPresConte return result; } -PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresContext, +PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresContext, + const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, nscoord aTableFixedWidth) @@ -652,7 +548,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo PRBool result = PR_TRUE; nscoord tableWidth=0; // the width of the table as a result of setting column widths - nscoord numProportionalColumns = 0; // the total number of proportional-width columns PRInt32 totalSlices=0; // the total number of slices the proportional-width columns request nsVoidArray *proportionalColumnsList=nsnull; // a list of the columns that are proportional-width nsVoidArray *spanList=nsnull; // a list of the cells that span columns @@ -675,10 +570,11 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo nsIStyleContextPtr colSC; colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); nsStylePosition* colPosition = (nsStylePosition*) colSC->GetData(eStyleStruct_Position); + if (gsDebug) printf("col %d has frame %p with style %p and pos %p\n", + colIndex, colFrame, (nsIStyleContext *)colSC, colPosition); if (PR_FALSE==IsFixedWidth(colPosition)) { - numProportionalColumns++; // first, deal with any cells that span into this column from a pervious column if (nsnull!=spanList) { @@ -720,7 +616,48 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo nsresult result = data->GetMargin(margin); nscoord marginWidth = margin.left + margin.right; PRInt32 cellMinWidth = cellMinSize->width/colSpan + marginWidth; - PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan + marginWidth; + // first get the desired size info from reflow pass 1 + PRInt32 cellDesiredWidth = cellDesiredSize->width/colSpan + marginWidth; + // then get the desired size info factoring in the cell style attributes + nscoord specifiedCellWidth=-1; + nsIStyleContextPtr cellSC; + data->GetCellFrame()->GetStyleContext(aPresContext, cellSC.AssignRef()); + nsStylePosition* cellPosition = (nsStylePosition*) + cellSC->GetData(eStyleStruct_Position); + switch (cellPosition->mWidth.GetUnit()) { + case eStyleUnit_Coord: + specifiedCellWidth = cellPosition->mWidth.GetCoordValue(); + if (gsDebug) printf("cell has specified coord width = %d\n", specifiedCellWidth); + break; + + case eStyleUnit_Percent: + { + nscoord tableWidth=0; + nsIStyleContextPtr tableSC; + mTableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); + PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(mTableFrame, tableSC, aReflowState, tableWidth); + float percent = cellPosition->mWidth.GetPercentValue(); + specifiedCellWidth = (PRInt32)(tableWidth*percent); + if (gsDebug) printf("specified percent width %f of %d = %d\n", + percent, tableWidth, specifiedCellWidth); + break; + } + + case eStyleUnit_Inherit: + // XXX for now, do nothing + default: + case eStyleUnit_Auto: + break; + } + if (-1!=specifiedCellWidth) + { + if (specifiedCellWidth>cellMinWidth) + { + if (gsDebug) printf("setting cellDesiredWidth from %d to %d\n", + cellDesiredWidth, specifiedCellWidth); + cellDesiredWidth = specifiedCellWidth; // TODO: some math needed here for colspans + } + } if (PR_TRUE==gsDebug) printf("factoring in cell %d with colSpan=%d\n factoring in min=%d and desired=%d\n", @@ -750,15 +687,22 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo } // Get column width if it has one - nscoord specifiedProportion = -1; + nscoord specifiedProportionColumnWidth = -1; float specifiedPercentageColWidth = -1.0f; + nscoord specifiedFixedColumnWidth = -1; PRBool isAutoWidth = PR_FALSE; switch (colPosition->mWidth.GetUnit()) { + case eStyleUnit_Coord: + specifiedFixedColumnWidth = colPosition->mWidth.GetCoordValue(); + if (gsDebug) printf("column %d has specified coord width = %d\n", colIndex, specifiedFixedColumnWidth); + break; case eStyleUnit_Percent: specifiedPercentageColWidth = colPosition->mWidth.GetPercentValue(); + if (gsDebug) printf("column %d has specified percent width = %f\n", colIndex, specifiedPercentageColWidth); break; case eStyleUnit_Proportional: - specifiedProportion = colPosition->mWidth.GetIntValue(); + specifiedProportionColumnWidth = colPosition->mWidth.GetIntValue(); + if (gsDebug) printf("column %d has specified percent width = %d\n", colIndex, specifiedProportionColumnWidth); break; case eStyleUnit_Auto: isAutoWidth = PR_TRUE; @@ -768,11 +712,11 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo } /* set the column width, knowing that the table fits in the available space */ - if (0==specifiedProportion || 0.0==specifiedPercentageColWidth) + if (0==specifiedProportionColumnWidth || 0.0==specifiedPercentageColWidth) { // col width is specified to be the minimum mTableFrame->SetColumnWidth(colIndex, minColWidth); if (gsDebug==PR_TRUE) - printf (" 3 (0): col %d set to min width = %d because style set proportionalWidth=0\n", + printf (" 3 min: col %d set to min width = %d because style set proportionalWidth=0\n", colIndex, mTableFrame->GetColumnWidth(colIndex)); } else if (PR_TRUE==isAutoWidth) @@ -781,10 +725,10 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo // if there is width left over, we'll factor that in after this loop is complete mTableFrame->SetColumnWidth(colIndex, maxColWidth); if (gsDebug==PR_TRUE) - printf (" 3a: col %d with availWidth %d, set to width = %d\n", + printf (" 3 auto: col %d with availWidth %d, set to width = %d\n", colIndex, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); } - else if (0!=specifiedProportion) + else if (-1!=specifiedProportionColumnWidth) { // we need to save these and do them after all other columns have been calculated /* the calculation will be: sum up n, the total number of slices for the columns with proportional width @@ -798,9 +742,23 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo if (nsnull==proportionalColumnsList) proportionalColumnsList = new nsVoidArray(); ProportionalColumnLayoutStruct * info = - new ProportionalColumnLayoutStruct(colIndex, minColWidth, maxColWidth, specifiedProportion); + new ProportionalColumnLayoutStruct(colIndex, minColWidth, + maxColWidth, specifiedProportionColumnWidth); proportionalColumnsList->AppendElement(info); - totalSlices += specifiedProportion; + totalSlices += specifiedProportionColumnWidth; // keep track of the total number of proportions + if (gsDebug==PR_TRUE) + printf (" 3 proportional: col %d with availWidth %d, gets %d slices with %d slices so far.\n", + colIndex, aAvailWidth, specifiedProportionColumnWidth, totalSlices); + } + else if (-1!=specifiedFixedColumnWidth) + { + // if the column was computed to be too small, enlarge the column + nscoord resolvedWidth = specifiedFixedColumnWidth; + if (specifiedFixedColumnWidth <= minColWidth) + resolvedWidth = minColWidth; + mTableFrame->SetColumnWidth(colIndex, resolvedWidth); + if (gsDebug==PR_TRUE) + printf (" 3 fixed: col %d given %d\n", colIndex, resolvedWidth); } else { // give each remaining column a percentage of the remaining space @@ -816,14 +774,14 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo if (-1==percentage) percentage = 100/numCols; // base the % on the total max width - mTableFrame->SetColumnWidth(colIndex, (percentage*aMaxWidth)/100); + mTableFrame->SetColumnWidth(colIndex, (percentage*aAvailWidth)/100); // if the column was computed to be too small, enlarge the column if (mTableFrame->GetColumnWidth(colIndex) <= minColWidth) mTableFrame->SetColumnWidth(colIndex, minColWidth); } if (gsDebug==PR_TRUE) - printf (" 3b: col %d given %d percent of aMaxWidth %d, set to width = %d\n", - colIndex, percentage, aMaxWidth, mTableFrame->GetColumnWidth(colIndex)); + printf (" 3 percent: col %d given %d percent of aAvailWidth %d, set to width = %d\n", + colIndex, percentage, aAvailWidth, mTableFrame->GetColumnWidth(colIndex)); } } tableWidth += mTableFrame->GetColumnWidth(colIndex); @@ -845,7 +803,7 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo nscoord computedColWidth = info->mProportion*widthPerSlice; mTableFrame->SetColumnWidth(info->mColIndex, computedColWidth); if (gsDebug==PR_TRUE) - printf (" 3c: col %d given %d proportion of remaining space %d, set to width = %d\n", + printf (" 3 proportional step 2: col %d given %d proportion of remaining space %d, set to width = %d\n", info->mColIndex, info->mProportion, widthRemaining, computedColWidth); tableWidth += computedColWidth; delete info; @@ -859,26 +817,34 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsTableFits(nsIPresContext* aPresCo if (aTableFixedWidth > tableWidth) { nscoord excess = aTableFixedWidth - tableWidth; - // if there are proportionally-sized columns, give them the extra space - if (0!=numProportionalColumns) + if (gsDebug) printf ("fixed width %d > computed table width %d, excess = %d\n", + aTableFixedWidth, tableWidth, excess); + // if there are auto-sized columns, give them the extra space + PRInt32 numAutoColumns; + PRInt32 *autoColumns; + mTableFrame->GetColumnsByType(eStyleUnit_Auto, numAutoColumns, autoColumns); + if (0!=numAutoColumns) { - nscoord excessPerColumn = excess/numProportionalColumns; - if (gsDebug==PR_TRUE) printf(" aTableFixedWidth specified as %d, expanding columns by excess = %d\n", aTableFixedWidth, excess); - for (PRInt32 colIndex = 0; colIndexGetColumnWidth(colIndex); - mTableFrame->SetColumnWidth(colIndex, colWidth); - } + PRInt32 colIndex = autoColumns[i]; + nscoord colWidth = excessPerColumn+mTableFrame->GetColumnWidth(colIndex); + if (gsDebug==PR_TRUE) + printf(" column %d was %d, now set to %d\n", colIndex, mTableFrame->GetColumnWidth(colIndex), colWidth); + mTableFrame->SetColumnWidth(colIndex, colWidth); } } - // otherwise, distribute the space evenly between all the columns + // otherwise, distribute the space evenly between all the columns (they must be all fixed and percentage-width columns) + // TODO - should extra space be proportionately distributed? else { nscoord excessPerColumn = excess/numCols; - if (gsDebug==PR_TRUE) printf(" aTableFixedWidth specified as %d, expanding columns by excess = %d\n", aTableFixedWidth, excess); + if (gsDebug==PR_TRUE) + printf(" aTableFixedWidth specified as %d, expanding columns by excess = %d\n", aTableFixedWidth, excess); for (PRInt32 colIndex = 0; colIndexGetColumnWidth(colIndex); @@ -907,7 +873,6 @@ PRBool BasicTableLayoutStrategy::BalanceColumnsConstrained( nsIPresContext* aPre PRBool result = PR_TRUE; PRInt32 maxOfAllMinColWidths = 0; // for the case where we have equal column widths, this is the smallest a column can be nscoord tableWidth=0; // the width of the table as a result of setting column widths - nscoord numProportionalColumns = 0; // the total number of proportional-width columns PRInt32 totalSlices=0; // the total number of slices the proportional-width columns request nsVoidArray *proportionalColumnsList=nsnull; // a list of the columns that are proportional-width PRBool equalWidthColumns = PR_TRUE; // remember if we're in the special case where all diff --git a/layout/tables/BasicTableLayoutStrategy.h b/layout/tables/BasicTableLayoutStrategy.h index acba3cf2a6e0..1fe2a9066b9e 100644 --- a/layout/tables/BasicTableLayoutStrategy.h +++ b/layout/tables/BasicTableLayoutStrategy.h @@ -103,6 +103,7 @@ public: * */ virtual PRBool BalanceProportionalColumns(nsIPresContext* aPresContext, + const nsReflowState& aReflowState, PRInt32 aAvailWidth, PRInt32 aMaxWidth, PRInt32 aMinTableWidth, @@ -132,6 +133,7 @@ public: * @return PR_TRUE if all is well, PR_FALSE if there was an unrecoverable error */ virtual PRBool BalanceColumnsTableFits(nsIPresContext* aPresContext, + const nsReflowState& aReflowState, nscoord aAvailWidth, nscoord aMaxWidth, nscoord aTableFixedWidth); @@ -166,10 +168,6 @@ public: virtual PRBool IsAutoWidth(nsStylePosition* aStylePosition); - virtual PRBool TableIsAutoWidth(nsIStyleContext *aTableStyle, - const nsReflowState& aReflowState, - nscoord& aSpecifiedTableWidth); - protected: nsTableFrame * mTableFrame; diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index a1714692d267..24b28799bbed 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -27,8 +27,12 @@ #include "nsIContentDelegate.h" #include "nsCSSLayout.h" #include "nsHTMLAtoms.h" +#include "nsHTMLIIDs.h" +#include "nsIPtr.h" #include "nsIView.h" +NS_DEF_PTR(nsIStyleContext); + #ifdef NS_DEBUG static PRBool gsDebug = PR_FALSE; //#define NOISY_STYLE @@ -297,6 +301,42 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, CreatePsuedoFrame(aPresContext); } + // Determine the width we have to work with + nscoord cellWidth = -1; + if (NS_UNCONSTRAINEDSIZE!=availSize.width) + { + /* + nsStylePosition* kidPosition = (nsStylePosition*) + mStyleContext->GetData(eStyleStruct_Position); + switch (kidPosition->mWidth.GetUnit()) { + case eStyleUnit_Coord: + cellWidth = kidPosition->mWidth.GetCoordValue(); + break; + + case eStyleUnit_Percent: + { + nscoord tableWidth=0; + const nsReflowState *tableReflowState = aReflowState.parentReflowState->parentReflowState->parentReflowState; + nsTableFrame *tableFrame = (nsTableFrame *)(tableReflowState->frame); + nsIStyleContextPtr tableSC; + tableFrame->GetStyleContext(aPresContext, tableSC.AssignRef()); + PRBool tableIsAutoWidth = nsTableFrame::TableIsAutoWidth(tableFrame, tableSC, *tableReflowState, tableWidth); + float percent = kidPosition->mWidth.GetPercentValue(); + cellWidth = (PRInt32)(tableWidth*percent); + break; + } + + case eStyleUnit_Inherit: + // XXX for now, do nothing + default: + case eStyleUnit_Auto: + break; + } + */ + if (-1!=cellWidth) + availSize.width = cellWidth; + } + // Try to reflow the child into the available space. It might not // fit or might need continuing. if (availSize.height < 0) @@ -325,14 +365,13 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, } SetFirstContentOffset(mFirstChild); - if (gsDebug) printf("CELL: set first content offset to %d\n", GetFirstContentOffset()); //@@@ + //if (gsDebug) printf("CELL: set first content offset to %d\n", GetFirstContentOffset()); //@@@ SetLastContentOffset(mFirstChild); - if (gsDebug) printf("CELL: set last content offset to %d\n", GetLastContentOffset()); //@@@ + //if (gsDebug) printf("CELL: set last content offset to %d\n", GetLastContentOffset()); //@@@ - // Place the child since some of it's content fit in us. + // Place the child mFirstChild->SetRect(nsRect(leftInset, topInset, - kidSize.width, kidSize.height)); - + kidSize.width, kidSize.height)); if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // If the child didn't finish layout then it means that it used @@ -341,19 +380,22 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, } // Return our size and our result - PRInt32 kidWidth = kidSize.width; - if (NS_UNCONSTRAINEDSIZE!=kidSize.width) //&& NS_UNCONSTRAINEDSIZE!=aMaxSize.width) - kidWidth += leftInset + rightInset; - PRInt32 kidHeight = kidSize.height; - // height can be set w/o being restricted by aMaxSize.height - if (NS_UNCONSTRAINEDSIZE!=kidSize.height) - kidHeight += topInset + bottomInset; - aDesiredSize.width = kidWidth; - aDesiredSize.height = kidHeight; + // first, compute the height + // the height can be set w/o being restricted by aMaxSize.height + nscoord cellHeight = kidSize.height; + if (NS_UNCONSTRAINEDSIZE!=cellHeight) + cellHeight += topInset + bottomInset; + // next determine the cell's width + cellWidth = kidSize.width; // at this point, we've factored in the cell's style attributes + if (NS_UNCONSTRAINEDSIZE!=cellWidth) + cellWidth += leftInset + rightInset; + + // set the cell's desired size and max element size + aDesiredSize.width = cellWidth; + aDesiredSize.height = cellHeight; aDesiredSize.ascent = topInset; aDesiredSize.descent = bottomInset; - if (nsnull!=aDesiredSize.maxElementSize) { *aDesiredSize.maxElementSize = *pMaxElementSize; diff --git a/layout/tables/nsTableColFrame.h b/layout/tables/nsTableColFrame.h index 80e0c761a4a5..29f554e1eb1d 100644 --- a/layout/tables/nsTableColFrame.h +++ b/layout/tables/nsTableColFrame.h @@ -37,6 +37,9 @@ public: const nsReflowState& aReflowState, nsReflowStatus& aStatus); + /** return the index of the column this content object represents. always >= 0 */ + virtual int GetColumnIndex (); + protected: nsTableColFrame(nsIContent* aContent, nsIFrame* aParentFrame); diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 2ebcbdcc8f66..26db465bbc3f 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -26,6 +26,7 @@ #include "nsTableCell.h" #include "nsTableCellFrame.h" #include "nsTableCol.h" +#include "nsTableColFrame.h" #include "nsTableRowFrame.h" #include "nsTableRowGroupFrame.h" #include "nsColLayoutData.h" @@ -41,6 +42,7 @@ #include "nsIPtr.h" #include "nsIView.h" #include "nsHTMLAtoms.h" +#include "nsHTMLIIDs.h" #ifdef NS_DEBUG static PRBool gsDebug = PR_FALSE; @@ -135,6 +137,117 @@ struct InnerTableReflowState { } }; +/* ----------- ColumnInfoCache ---------- */ + +static const PRInt32 NUM_COL_WIDTH_TYPES=4; + +class ColumnInfoCache +{ +public: + ColumnInfoCache(PRInt32 aNumColumns); + ~ColumnInfoCache(); + + void AddColumnInfo(const nsStyleUnit aType, + PRInt32 aColumnIndex); + + void GetColumnsByType(const nsStyleUnit aType, + PRInt32& aOutNumColumns, + PRInt32 *& aOutColumnIndexes); + enum ColWidthType { + eColWidthType_Auto = 0, // width based on contents + eColWidthType_Percent = 1, // (float) 1.0 == 100% + eColWidthType_Coord = 2, // (nscoord) value is twips + eColWidthType_Proportional = 3, // (int) value has proportional meaning + }; + +private: + PRInt32 mColCounts [4]; + PRInt32 *mColIndexes[4]; + PRInt32 mNumColumns; +}; + +ColumnInfoCache::ColumnInfoCache(PRInt32 aNumColumns) +{ + mNumColumns = aNumColumns; + for (PRInt32 i=0; iGetSize(rowGroupFrameSize); rowGroupFrame->SizeTo(rowGroupFrameSize.width, rowGroupHeight); tableHeight += rowGroupHeight; + if (nsnull!=rowHeights) + delete [] rowHeights; } } if (0!=tableHeight) @@ -1904,12 +2022,61 @@ void nsTableFrame::ShrinkWrapChildren(nsIPresContext* aPresContext, } void nsTableFrame::VerticallyAlignChildren(nsIPresContext* aPresContext, - nscoord* aAscents, - nscoord aMaxAscent, - nscoord aMaxHeight) + nscoord* aAscents, + nscoord aMaxAscent, + nscoord aMaxHeight) { } +/* there's an easy way and a hard way. The easy way is to look in our + * cache and pull the frame from there. + * If the cache isn't built yet, then we have to go hunting. + */ +NS_METHOD nsTableFrame::GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame) +{ + aColFrame = nsnull; // initialize out parameter + nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); + if (nsnull!=firstInFlow->mColumnLayoutData) + { // hooray, we get to do this the easy way because the info is cached + nsColLayoutData * colData = (nsColLayoutData *) + (firstInFlow->mColumnLayoutData->ElementAt(aColIndex)); + NS_ASSERTION(nsnull != colData, "bad column data"); + aColFrame = colData->GetColFrame(); + NS_ASSERTION(nsnull!=aColFrame, "bad col frame"); + } + else + { // ah shucks, we have to go hunt for the column frame brute-force style + nsIFrame *childFrame; + FirstChild(childFrame); + for (;;) + { + if (nsnull==childFrame) + { + NS_ASSERTION (PR_FALSE, "scanned the frame hierarchy and no column frame could be found."); + break; + } + nsIContentPtr kid; + childFrame->GetContent(kid.AssignRef()); + const PRInt32 contentType = ((nsTableContent *)(nsIContent*)kid)->GetType(); + if (contentType==nsITableContent::kTableColGroupType) + { + nsTableColGroup *colGroup = (nsTableColGroup *)((nsIContent*)kid); + PRInt32 colGroupStartingIndex = colGroup->GetStartColumnIndex(); + if (aColIndex >= colGroupStartingIndex) + { // the cell's col might be in this col group + if (aColIndex < colGroupStartingIndex + colGroup->ChildCount()) + { // yep, we've found it + childFrame->ChildAt(aColIndex-colGroupStartingIndex, (nsIFrame *&)aColFrame); + break; + } + } + } + childFrame->GetNextSibling(childFrame); + } + } + return NS_OK; +} + nsVoidArray * nsTableFrame::GetColumnLayoutData() { nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); @@ -1922,7 +2089,8 @@ nsVoidArray * nsTableFrame::GetColumnLayoutData() * @return PR_TRUE if the data was successfully associated with a Cell * PR_FALSE if there was an error, such as aRow or aCol being invalid */ -PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aCell) +PRBool nsTableFrame::SetCellLayoutData(nsIPresContext* aPresContext, + nsCellLayoutData * aData, nsTableCell *aCell) { NS_ASSERTION(nsnull != aData, "bad arg"); NS_ASSERTION(nsnull != aCell, "bad arg"); @@ -1932,7 +2100,7 @@ PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aC nsTableFrame * firstInFlow = (nsTableFrame *)GetFirstInFlow(); NS_ASSERTION(nsnull!=firstInFlow, "illegal state -- no first in flow"); if (this!=firstInFlow) - result = firstInFlow->SetCellLayoutData(aData, aCell); + result = firstInFlow->SetCellLayoutData(aPresContext, aData, aCell); else { if (kPASS_FIRST==GetReflowPass()) @@ -1943,6 +2111,7 @@ PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aC NS_ASSERTION(nsnull != mColumnLayoutData, "bad alloc"); nsTablePart * tablePart = (nsTablePart *)mContent; PRInt32 cols = tablePart->GetMaxColumns(); + mColCache = new ColumnInfoCache(cols); PRInt32 tableKidCount = tablePart->ChildCount(); nsIFrame * colGroupFrame = mFirstChild; for (PRInt32 i=0; iChildCount(); for (PRInt32 j=0; jChildAt(j); NS_ASSERTION(col.IsNotNull(), "bad content"); nsColLayoutData *colData = new nsColLayoutData(col); @@ -1962,6 +2134,13 @@ PRBool nsTableFrame::SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aC colGroupFrame->ChildAt(j, (nsIFrame *&)colFrame); colData->SetColFrame(colFrame); mColumnLayoutData->AppendElement((void *)colData); + + // also add the column to the column cache + // assumes that the col style has been twiddled to account for first cell width attribute + nsIStyleContextPtr colSC; + colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); + nsStylePosition* colPosition = (nsStylePosition*)colSC->GetData(eStyleStruct_Position); + mColCache->AddColumnInfo(colPosition->mWidth.GetUnit(), colFrame->GetColumnIndex()); } } // can't have col groups after row groups, so stop if you find a row group @@ -2349,6 +2528,14 @@ NS_METHOD nsTableFrame::GetCellMarginData(nsIFrame* aKidFrame, nsMargin& aMargin return result; } +void nsTableFrame::GetColumnsByType(const nsStyleUnit aType, + PRInt32& aOutNumColumns, + PRInt32 *& aOutColumnIndexes) +{ + mColCache->GetColumnsByType(aType, aOutNumColumns, aOutColumnIndexes); +} + + /* ---------- static methods ---------- */ nsresult nsTableFrame::NewFrame(nsIFrame** aInstancePtrResult, @@ -2367,6 +2554,115 @@ nsresult nsTableFrame::NewFrame(nsIFrame** aInstancePtrResult, return NS_OK; } +/* helper method for getting the width of the table's containing block */ +nscoord nsTableFrame::GetTableContainerWidth(const nsReflowState& aReflowState) +{ +#ifdef STEVES_WAY // from BasicTableLayoutStrategy::TableIsAutoWidth() + // get the parent's width (available only from parent frames that claim they can provide it) + // note that we start with our parent's parent (the outer table frame's parent) + nscoord parentWidth = 0; + NS_ASSERTION(nsnull!=aReflowState.parentReflowState, "bad outer table reflow state."); + NS_ASSERTION(nsnull!=aReflowState.parentReflowState->parentReflowState, "bad table parent reflow state."); + if ((nsnull!=aReflowState.parentReflowState) && + (nsnull!=aReflowState.parentReflowState->parentReflowState)) + { + const nsReflowState *parentReflowState = aReflowState.parentReflowState->parentReflowState; + nsIFrame *parentFrame=parentReflowState->frame; + NS_ASSERTION(nsnull!=parentFrame, "bad parent frame in reflow state struct."); + while(nsnull!=parentFrame) + { + PRBool isPercentageBase=PR_FALSE; + parentFrame->IsPercentageBase(isPercentageBase); + if (PR_TRUE==isPercentageBase) + { // found the ancestor who claims to be the container to base my percentage width on + parentWidth = parentReflowState->maxSize.width; + if (PR_TRUE==gsDebug) printf(" ** width for parent frame %p = %d\n", parentFrame, parentWidth); + break; + } + parentReflowState = parentReflowState->parentReflowState; // get next ancestor + if (nsnull!=parentReflowState) + parentFrame = parentReflowState->frame; + else + parentFrame = nsnull; // terminates loop. + // TODO: do we need a backstop in case there are no IsPercentageBase==true frames? + } + } + +#else + + nscoord parentWidth = aReflowState.maxSize.width; + + // Walk up the reflow state chain until we find a block + // frame. Our width is computed relative to there. + const nsReflowState* rs = &aReflowState; + while (nsnull != rs) { + nsIFrame* block = nsnull; + rs->frame->QueryInterface(kBlockFrameCID, (void**) &block); + if (nsnull != block) { + // We found the nearest containing block which defines what + // a percentage size is relative to. Use the width that it + // will reflow to as the basis for computing our width. + parentWidth = rs->maxSize.width; + break; + } + rs = rs->parentReflowState; + } + +#endif + return parentWidth; +} + +// aSpecifiedTableWidth is filled if the table witdth is not auto +PRBool nsTableFrame::TableIsAutoWidth(nsTableFrame *aTableFrame, + nsIStyleContext *aTableStyle, + const nsReflowState& aReflowState, + nscoord& aSpecifiedTableWidth) +{ + NS_ASSERTION(nsnull!=aTableStyle, "bad arg - aTableStyle"); + PRBool result = PR_TRUE; // the default + if (nsnull!=aTableStyle) + { + //nsStylePosition* tablePosition = (nsStylePosition*)aTableStyle->GetData(eStyleStruct_Position); + /* this is sick and wrong, but what the hell + we grab the style of our parent (nsTableOuterFrame) and ask it for width info, + until the style resolution stuff does the cool stuff about splitting style between outer and inner + */ + // begin REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! + nsIStyleContext* parentStyle = nsnull; + nsIFrame * parent = nsnull; + aTableFrame->GetGeometricParent(parent); + parent->GetStyleContext(nsnull, parentStyle); + nsStylePosition* tablePosition = (nsStylePosition*)parentStyle->GetData(eStyleStruct_Position); + // end REMOVE_ME_WHEN_TABLE_STYLE_IS_RESOLVED! + switch (tablePosition->mWidth.GetUnit()) { + case eStyleUnit_Auto: // specified auto width + case eStyleUnit_Proportional: // illegal for table, so ignored + break; + + case eStyleUnit_Inherit: + // get width of parent and see if it is a specified value or not + // XXX for now, just return true + break; + + case eStyleUnit_Coord: + aSpecifiedTableWidth = tablePosition->mWidth.GetCoordValue(); + result = PR_FALSE; + break; + + case eStyleUnit_Percent: + // set aSpecifiedTableWidth to be the given percent of the parent. + nscoord parentWidth = nsTableFrame::GetTableContainerWidth(aReflowState); + float percent = tablePosition->mWidth.GetPercentValue(); + aSpecifiedTableWidth = (PRInt32)(parentWidth*percent); + if (PR_TRUE==gsDebug) printf(" ** aSpecifiedTableWidth = %d\n", aSpecifiedTableWidth); + result = PR_FALSE; + break; + } + } + + return result; +} + /* valuable code not yet used anywhere // since the table is a specified width, we need to expand the columns to fill the table diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index 7dbc1fb8c49d..70657556236b 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -25,12 +25,15 @@ class nsCellLayoutData; class nsTableCell; class nsVoidArray; class nsTableCellFrame; +class nsTableColFrame; class CellData; class nsITableLayoutStrategy; class nsHTMLValue; +class ColumnInfoCache; struct InnerTableReflowState; struct nsStylePosition; struct nsStyleSpacing; +enum nsStyleUnit; /** nsTableFrame maps the inner portion of a table (everything except captions.) * Used as a pseudo-frame within nsTableOuterFrame, @@ -59,6 +62,15 @@ public: nsIContent* aContent, nsIFrame* aParent); + /** helper method for getting the width of the table's containing block */ + static nscoord GetTableContainerWidth(const nsReflowState& aState); + + + static PRBool TableIsAutoWidth(nsTableFrame *aTableFrame, + nsIStyleContext *aTableStyle, + const nsReflowState& aReflowState, + nscoord& aSpecifiedTableWidth); + /** @see nsIFrame::Paint */ NS_IMETHOD Paint(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, @@ -108,16 +120,29 @@ public: nsReflowMetrics& aDesiredSize, nsSize* aMaxElementSize); + /** return the column frame corresponding to the given column index + * there are two ways to do this, depending on whether we have cached + * column information yet. + */ + NS_METHOD GetColumnFrame(PRInt32 aColIndex, nsTableColFrame *&aColFrame); + /** return the column layout data for this inner table frame. * if this is a continuing frame, return the first-in-flow's column layout data. */ virtual nsVoidArray *GetColumnLayoutData(); /** Associate aData with the cell at (aRow,aCol) + * + * @param aPresContext -- used to resolve style when initializing caches + * @param aData -- the info to cache + * @param aCell -- the content object for which layout info is being cached + * * @return PR_TRUE if the data was successfully associated with a Cell * PR_FALSE if there was an error, such as aRow or aCol being invalid */ - virtual PRBool SetCellLayoutData(nsCellLayoutData * aData, nsTableCell *aCell); + virtual PRBool SetCellLayoutData(nsIPresContext* aPresContext, + nsCellLayoutData * aData, + nsTableCell *aCell); /** Get the layout data associated with the cell at (aRow,aCol) * @return PR_NULL if there was an error, such as aRow or aCol being invalid @@ -154,6 +179,18 @@ public: // Get cell margin information NS_IMETHOD GetCellMarginData(nsIFrame* aKidFrame, nsMargin& aMargin); + /** get cached column information for a subset of the columns + * + * @param aType -- information is returned for the subset of columns with aType style + * @param aOutNumColumns -- out param, the number of columns matching aType + * @param aOutColumnIndexes -- out param, the indexes of the columns matching aType + * + * TODO : make aOutColumnIndexes safe + */ + void GetColumnsByType(const nsStyleUnit aType, + PRInt32& aOutNumColumns, + PRInt32 *& aOutColumnIndexes); + // For DEBUGGING Purposes Only NS_IMETHOD MoveTo(nscoord aX, nscoord aY); NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); @@ -304,6 +341,8 @@ private: nsVoidArray *mColumnLayoutData; // array of array of cellLayoutData's PRInt32 *mColumnWidths; // widths of each column + //TODO: move all column info into this object + ColumnInfoCache *mColCache; // cached information about the table columns PRBool mFirstPassValid; // PR_TRUE if first pass data is still legit PRInt32 mPass; // which Reflow pass are we currently in? PRBool mIsInvariantWidth; // PR_TRUE if table width cannot change diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index e85a2639ea2b..114f5f424488 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -23,9 +23,11 @@ #include "nsIContent.h" #include "nsIContentDelegate.h" #include "nsTableFrame.h" +#include "nsTableColFrame.h" #include "nsTableCellFrame.h" #include "nsTableCell.h" #include "nsCellLayoutData.h" +#include "nsColLayoutData.h" #include "nsIView.h" #include "nsIPtr.h" @@ -360,7 +362,7 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState); nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); - aState.tableFrame->SetCellLayoutData(&kidLayoutData, cell); + aState.tableFrame->SetCellLayoutData(aPresContext, &kidLayoutData, cell); } else { // we're in a constrained situation, so get the avail width from the known column widths @@ -428,13 +430,11 @@ PRBool nsTableRowFrame::ReflowMappedChildren(nsIPresContext* aPresContext, case eStyleUnit_Coord: specifiedHeight = kidPosition->mHeight.GetCoordValue(); break; - case eStyleUnit_Percent: - case eStyleUnit_Proportional: - // XXX for now these fall through + case eStyleUnit_Inherit: + // XXX for now, do nothing default: case eStyleUnit_Auto: - case eStyleUnit_Inherit: break; } if (specifiedHeight>cellHeight) @@ -893,10 +893,9 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, break; } - nsIFrame* kidFrame; - // Create a child frame + // Create a child frame -- always an nsTableCell frame nsIStyleContext* kidStyleContext = aPresContext->ResolveStyleContextFor(cell, this); if (nsnull == kidPrevInFlow) { nsIContentDelegate* kidDel = nsnull; @@ -908,6 +907,11 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, kidPrevInFlow->CreateContinuingFrame(aPresContext, this, kidStyleContext, kidFrame); } + /* since I'm creating the cell frame, this is the first time through reflow + * it's a good time to set the column style from the cell's width attribute + * if this is the first row + */ + SetColumnStyleFromCell(aPresContext, (nsTableCellFrame *)kidFrame, kidStyleContext); NS_RELEASE(kidStyleContext); @@ -937,7 +941,7 @@ nsTableRowFrame::ReflowUnmappedChildren( nsIPresContext* aPresContext, kidFrame->WillReflow(*aPresContext); status = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState); nsCellLayoutData kidLayoutData((nsTableCellFrame *)kidFrame, &desiredSize, pKidMaxElementSize); - aState.tableFrame->SetCellLayoutData(&kidLayoutData, (nsTableCell *)cell); + aState.tableFrame->SetCellLayoutData(aPresContext, &kidLayoutData, (nsTableCell *)cell); } else { // we're in a constrained situation, so get the avail width from the known column widths @@ -1146,6 +1150,54 @@ nsTableRowFrame::CreateContinuingFrame(nsIPresContext* aPresContext, return NS_OK; } +NS_METHOD +nsTableRowFrame::SetColumnStyleFromCell(nsIPresContext* aPresContext, + nsTableCellFrame* aCellFrame, + nsIStyleContext* aCellSC) +{ + // if this cell is in the first row, then the width attribute + // also acts as the width attribute for the entire column + if ((nsnull!=aCellSC) && (nsnull!=aCellFrame)) + { + PRInt32 rowIndex = ((nsTableRow*)mContent)->GetRowIndex(); + if (0==rowIndex) + { + // get the cell style info + nsStylePosition* cellPosition = (nsStylePosition*) aCellSC->GetData(eStyleStruct_Position); + if ((eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) || + (eStyleUnit_Percent==cellPosition->mWidth.GetUnit())) { + + // compute the width per column spanned + PRInt32 colSpan = aCellFrame->GetColSpan(); + // get the appropriate column frame + nsTableFrame *tableFrame; + mGeometricParent->GetGeometricParent((nsIFrame *&)tableFrame); + nsTableColFrame *colFrame; + tableFrame->GetColumnFrame(aCellFrame->GetColIndex(), colFrame); + // get the column style and set the width attribute + nsIStyleContextPtr colSC; + colFrame->GetStyleContext(aPresContext, colSC.AssignRef()); + nsStylePosition* colPosition = (nsStylePosition*) colSC->GetData(eStyleStruct_Position); + // set the column width attribute + colPosition->mWidth = cellPosition->mWidth; + /* + if (eStyleUnit_Coord == cellPosition->mWidth.GetUnit()) + { + nscoord width = cellPosition->mWidth.GetCoordValue(); + colPosition->mWidth.SetCoordValue(width); + } + else + { + float width = cellPosition->mWidth.GetPercentValue(); + colPosition->mWidth.SetPercentValue(width); + } + */ + } + } + } + return NS_OK; +} + nsresult nsTableRowFrame::NewFrame( nsIFrame** aInstancePtrResult, nsIContent* aContent, nsIFrame* aParent) diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h index 952af3bd04ad..b19de1c7311d 100644 --- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -22,6 +22,7 @@ #include "nsContainerFrame.h" class nsTableFrame; +class nsTableCellFrame; struct RowReflowState; /** @@ -160,6 +161,9 @@ protected: RowReflowState& aState, nsSize* aMaxElementSize); + NS_METHOD SetColumnStyleFromCell(nsIPresContext * aPresContext, + nsTableCellFrame* aCellFrame, + nsIStyleContext * aCellSC); private: nscoord mTallestCell; // not my height, but the height of my tallest child