1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/tables/nsTableRowFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1451 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 +#include "nsTableRowFrame.h" 1.9 +#include "nsTableRowGroupFrame.h" 1.10 +#include "nsIPresShell.h" 1.11 +#include "nsPresContext.h" 1.12 +#include "nsStyleContext.h" 1.13 +#include "nsStyleConsts.h" 1.14 +#include "nsGkAtoms.h" 1.15 +#include "nsIContent.h" 1.16 +#include "nsTableFrame.h" 1.17 +#include "nsTableCellFrame.h" 1.18 +#include "nsCSSRendering.h" 1.19 +#include "nsHTMLParts.h" 1.20 +#include "nsTableColGroupFrame.h" 1.21 +#include "nsTableColFrame.h" 1.22 +#include "nsCOMPtr.h" 1.23 +#include "nsDisplayList.h" 1.24 +#include "nsIFrameInlines.h" 1.25 +#include <algorithm> 1.26 + 1.27 +using namespace mozilla; 1.28 + 1.29 +struct nsTableCellReflowState : public nsHTMLReflowState 1.30 +{ 1.31 + nsTableCellReflowState(nsPresContext* aPresContext, 1.32 + const nsHTMLReflowState& aParentReflowState, 1.33 + nsIFrame* aFrame, 1.34 + const nsSize& aAvailableSpace, 1.35 + uint32_t aFlags = 0) 1.36 + : nsHTMLReflowState(aPresContext, aParentReflowState, aFrame, 1.37 + aAvailableSpace, -1, -1, aFlags) 1.38 + { 1.39 + } 1.40 + 1.41 + void FixUp(const nsSize& aAvailSpace); 1.42 +}; 1.43 + 1.44 +void nsTableCellReflowState::FixUp(const nsSize& aAvailSpace) 1.45 +{ 1.46 + // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base 1.47 + NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aAvailSpace.width, 1.48 + "have unconstrained width; this should only result from " 1.49 + "very large sizes, not attempts at intrinsic width " 1.50 + "calculation"); 1.51 + if (NS_UNCONSTRAINEDSIZE != ComputedWidth()) { 1.52 + nscoord computedWidth = 1.53 + aAvailSpace.width - mComputedBorderPadding.LeftRight(); 1.54 + computedWidth = std::max(0, computedWidth); 1.55 + SetComputedWidth(computedWidth); 1.56 + } 1.57 + if (NS_UNCONSTRAINEDSIZE != ComputedHeight() && 1.58 + NS_UNCONSTRAINEDSIZE != aAvailSpace.height) { 1.59 + nscoord computedHeight = 1.60 + aAvailSpace.height - mComputedBorderPadding.TopBottom(); 1.61 + computedHeight = std::max(0, computedHeight); 1.62 + SetComputedHeight(computedHeight); 1.63 + } 1.64 +} 1.65 + 1.66 +void 1.67 +nsTableRowFrame::InitChildReflowState(nsPresContext& aPresContext, 1.68 + const nsSize& aAvailSize, 1.69 + bool aBorderCollapse, 1.70 + nsTableCellReflowState& aReflowState) 1.71 +{ 1.72 + nsMargin collapseBorder; 1.73 + nsMargin* pCollapseBorder = nullptr; 1.74 + if (aBorderCollapse) { 1.75 + // we only reflow cells, so don't need to check frame type 1.76 + nsBCTableCellFrame* bcCellFrame = (nsBCTableCellFrame*)aReflowState.frame; 1.77 + if (bcCellFrame) { 1.78 + pCollapseBorder = bcCellFrame->GetBorderWidth(collapseBorder); 1.79 + } 1.80 + } 1.81 + aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder); 1.82 + aReflowState.FixUp(aAvailSize); 1.83 +} 1.84 + 1.85 +void 1.86 +nsTableRowFrame::SetFixedHeight(nscoord aValue) 1.87 +{ 1.88 + nscoord height = std::max(0, aValue); 1.89 + if (HasFixedHeight()) { 1.90 + if (height > mStyleFixedHeight) { 1.91 + mStyleFixedHeight = height; 1.92 + } 1.93 + } 1.94 + else { 1.95 + mStyleFixedHeight = height; 1.96 + if (height > 0) { 1.97 + SetHasFixedHeight(true); 1.98 + } 1.99 + } 1.100 +} 1.101 + 1.102 +void 1.103 +nsTableRowFrame::SetPctHeight(float aPctValue, 1.104 + bool aForce) 1.105 +{ 1.106 + nscoord height = std::max(0, NSToCoordRound(aPctValue * 100.0f)); 1.107 + if (HasPctHeight()) { 1.108 + if ((height > mStylePctHeight) || aForce) { 1.109 + mStylePctHeight = height; 1.110 + } 1.111 + } 1.112 + else { 1.113 + mStylePctHeight = height; 1.114 + if (height > 0) { 1.115 + SetHasPctHeight(true); 1.116 + } 1.117 + } 1.118 +} 1.119 + 1.120 +/* ----------- nsTableRowFrame ---------- */ 1.121 + 1.122 +NS_QUERYFRAME_HEAD(nsTableRowFrame) 1.123 + NS_QUERYFRAME_ENTRY(nsTableRowFrame) 1.124 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) 1.125 + 1.126 +nsTableRowFrame::nsTableRowFrame(nsStyleContext* aContext) 1.127 + : nsContainerFrame(aContext) 1.128 +{ 1.129 + mBits.mRowIndex = mBits.mFirstInserted = 0; 1.130 + ResetHeight(0); 1.131 +} 1.132 + 1.133 +nsTableRowFrame::~nsTableRowFrame() 1.134 +{ 1.135 +} 1.136 + 1.137 +void 1.138 +nsTableRowFrame::Init(nsIContent* aContent, 1.139 + nsIFrame* aParent, 1.140 + nsIFrame* aPrevInFlow) 1.141 +{ 1.142 + // Let the base class do its initialization 1.143 + nsContainerFrame::Init(aContent, aParent, aPrevInFlow); 1.144 + 1.145 + NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW == StyleDisplay()->mDisplay, 1.146 + "wrong display on table row frame"); 1.147 + 1.148 + if (aPrevInFlow) { 1.149 + // Set the row index 1.150 + nsTableRowFrame* rowFrame = (nsTableRowFrame*)aPrevInFlow; 1.151 + 1.152 + SetRowIndex(rowFrame->GetRowIndex()); 1.153 + } 1.154 +} 1.155 + 1.156 +void 1.157 +nsTableRowFrame::DestroyFrom(nsIFrame* aDestructRoot) 1.158 +{ 1.159 + if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { 1.160 + nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot); 1.161 + } 1.162 + 1.163 + nsContainerFrame::DestroyFrom(aDestructRoot); 1.164 +} 1.165 + 1.166 +/* virtual */ void 1.167 +nsTableRowFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) 1.168 +{ 1.169 + nsContainerFrame::DidSetStyleContext(aOldStyleContext); 1.170 + 1.171 + if (!aOldStyleContext) //avoid this on init 1.172 + return; 1.173 + 1.174 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.175 + if (tableFrame->IsBorderCollapse() && 1.176 + tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) { 1.177 + nsIntRect damageArea(0, GetRowIndex(), tableFrame->GetColCount(), 1); 1.178 + tableFrame->AddBCDamageArea(damageArea); 1.179 + } 1.180 +} 1.181 + 1.182 +nsresult 1.183 +nsTableRowFrame::AppendFrames(ChildListID aListID, 1.184 + nsFrameList& aFrameList) 1.185 +{ 1.186 + NS_ASSERTION(aListID == kPrincipalList, "unexpected child list"); 1.187 + 1.188 + const nsFrameList::Slice& newCells = mFrames.AppendFrames(nullptr, aFrameList); 1.189 + 1.190 + // Add the new cell frames to the table 1.191 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.192 + for (nsFrameList::Enumerator e(newCells) ; !e.AtEnd(); e.Next()) { 1.193 + nsIFrame *childFrame = e.get(); 1.194 + NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure"); 1.195 + tableFrame->AppendCell(static_cast<nsTableCellFrame&>(*childFrame), GetRowIndex()); 1.196 + } 1.197 + 1.198 + PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange, 1.199 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.200 + tableFrame->SetGeometryDirty(); 1.201 + 1.202 + return NS_OK; 1.203 +} 1.204 + 1.205 + 1.206 +nsresult 1.207 +nsTableRowFrame::InsertFrames(ChildListID aListID, 1.208 + nsIFrame* aPrevFrame, 1.209 + nsFrameList& aFrameList) 1.210 +{ 1.211 + NS_ASSERTION(aListID == kPrincipalList, "unexpected child list"); 1.212 + NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this, 1.213 + "inserting after sibling frame with different parent"); 1.214 + //Insert Frames in the frame list 1.215 + const nsFrameList::Slice& newCells = mFrames.InsertFrames(nullptr, aPrevFrame, aFrameList); 1.216 + 1.217 + // Get the table frame 1.218 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.219 + nsIAtom* cellFrameType = tableFrame->IsBorderCollapse() ? nsGkAtoms::bcTableCellFrame : nsGkAtoms::tableCellFrame; 1.220 + nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, cellFrameType); 1.221 + nsTArray<nsTableCellFrame*> cellChildren; 1.222 + for (nsFrameList::Enumerator e(newCells); !e.AtEnd(); e.Next()) { 1.223 + nsIFrame *childFrame = e.get(); 1.224 + NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure"); 1.225 + cellChildren.AppendElement(static_cast<nsTableCellFrame*>(childFrame)); 1.226 + } 1.227 + // insert the cells into the cell map 1.228 + int32_t colIndex = -1; 1.229 + if (prevCellFrame) { 1.230 + prevCellFrame->GetColIndex(colIndex); 1.231 + } 1.232 + tableFrame->InsertCells(cellChildren, GetRowIndex(), colIndex); 1.233 + 1.234 + PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange, 1.235 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.236 + tableFrame->SetGeometryDirty(); 1.237 + 1.238 + return NS_OK; 1.239 +} 1.240 + 1.241 +nsresult 1.242 +nsTableRowFrame::RemoveFrame(ChildListID aListID, 1.243 + nsIFrame* aOldFrame) 1.244 +{ 1.245 + NS_ASSERTION(aListID == kPrincipalList, "unexpected child list"); 1.246 + 1.247 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.248 + nsTableCellFrame *cellFrame = do_QueryFrame(aOldFrame); 1.249 + if (cellFrame) { 1.250 + int32_t colIndex; 1.251 + cellFrame->GetColIndex(colIndex); 1.252 + // remove the cell from the cell map 1.253 + tableFrame->RemoveCell(cellFrame, GetRowIndex()); 1.254 + 1.255 + // Remove the frame and destroy it 1.256 + mFrames.DestroyFrame(aOldFrame); 1.257 + 1.258 + PresContext()->PresShell()-> 1.259 + FrameNeedsReflow(this, nsIPresShell::eTreeChange, 1.260 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.261 + tableFrame->SetGeometryDirty(); 1.262 + } 1.263 + else { 1.264 + NS_ERROR("unexpected frame type"); 1.265 + return NS_ERROR_INVALID_ARG; 1.266 + } 1.267 + 1.268 + return NS_OK; 1.269 +} 1.270 + 1.271 +/* virtual */ nsMargin 1.272 +nsTableRowFrame::GetUsedMargin() const 1.273 +{ 1.274 + return nsMargin(0,0,0,0); 1.275 +} 1.276 + 1.277 +/* virtual */ nsMargin 1.278 +nsTableRowFrame::GetUsedBorder() const 1.279 +{ 1.280 + return nsMargin(0,0,0,0); 1.281 +} 1.282 + 1.283 +/* virtual */ nsMargin 1.284 +nsTableRowFrame::GetUsedPadding() const 1.285 +{ 1.286 + return nsMargin(0,0,0,0); 1.287 +} 1.288 + 1.289 +nscoord 1.290 +GetHeightOfRowsSpannedBelowFirst(nsTableCellFrame& aTableCellFrame, 1.291 + nsTableFrame& aTableFrame) 1.292 +{ 1.293 + nscoord height = 0; 1.294 + nscoord cellSpacingY = aTableFrame.GetCellSpacingY(); 1.295 + int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(aTableCellFrame); 1.296 + // add in height of rows spanned beyond the 1st one 1.297 + nsIFrame* nextRow = aTableCellFrame.GetParent()->GetNextSibling(); 1.298 + for (int32_t rowX = 1; ((rowX < rowSpan) && nextRow);) { 1.299 + if (nsGkAtoms::tableRowFrame == nextRow->GetType()) { 1.300 + height += nextRow->GetSize().height; 1.301 + rowX++; 1.302 + } 1.303 + height += cellSpacingY; 1.304 + nextRow = nextRow->GetNextSibling(); 1.305 + } 1.306 + return height; 1.307 +} 1.308 + 1.309 +nsTableCellFrame* 1.310 +nsTableRowFrame::GetFirstCell() 1.311 +{ 1.312 + nsIFrame* childFrame = mFrames.FirstChild(); 1.313 + while (childFrame) { 1.314 + nsTableCellFrame *cellFrame = do_QueryFrame(childFrame); 1.315 + if (cellFrame) { 1.316 + return cellFrame; 1.317 + } 1.318 + childFrame = childFrame->GetNextSibling(); 1.319 + } 1.320 + return nullptr; 1.321 +} 1.322 + 1.323 +/** 1.324 + * Post-reflow hook. This is where the table row does its post-processing 1.325 + */ 1.326 +void 1.327 +nsTableRowFrame::DidResize() 1.328 +{ 1.329 + // Resize and re-align the cell frames based on our row height 1.330 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.331 + nsTableIterator iter(*this); 1.332 + nsIFrame* childFrame = iter.First(); 1.333 + 1.334 + nsHTMLReflowMetrics desiredSize(GetWritingMode()); // ??? 1.335 + desiredSize.Width() = mRect.width; 1.336 + desiredSize.Height() = mRect.height; 1.337 + desiredSize.SetOverflowAreasToDesiredBounds(); 1.338 + 1.339 + while (childFrame) { 1.340 + nsTableCellFrame *cellFrame = do_QueryFrame(childFrame); 1.341 + if (cellFrame) { 1.342 + nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame); 1.343 + 1.344 + // resize the cell's height 1.345 + nsRect cellRect = cellFrame->GetRect(); 1.346 + nsRect cellVisualOverflow = cellFrame->GetVisualOverflowRect(); 1.347 + if (cellRect.height != cellHeight) 1.348 + { 1.349 + cellFrame->SetSize(nsSize(cellRect.width, cellHeight)); 1.350 + nsTableFrame::InvalidateTableFrame(cellFrame, cellRect, 1.351 + cellVisualOverflow, 1.352 + false); 1.353 + } 1.354 + 1.355 + // realign cell content based on the new height. We might be able to 1.356 + // skip this if the height didn't change... maybe. Hard to tell. 1.357 + cellFrame->VerticallyAlignChild(mMaxCellAscent); 1.358 + 1.359 + // Always store the overflow, even if the height didn't change, since 1.360 + // we'll lose part of our overflow area otherwise. 1.361 + ConsiderChildOverflow(desiredSize.mOverflowAreas, cellFrame); 1.362 + 1.363 + // Note that if the cell's *content* needs to change in response 1.364 + // to this height, it will get a special height reflow. 1.365 + } 1.366 + // Get the next child 1.367 + childFrame = iter.Next(); 1.368 + } 1.369 + FinishAndStoreOverflow(&desiredSize); 1.370 + if (HasView()) { 1.371 + nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, GetView(), 1.372 + desiredSize.VisualOverflow(), 0); 1.373 + } 1.374 + // Let our base class do the usual work 1.375 +} 1.376 + 1.377 +// returns max-ascent amongst all cells that have 'vertical-align: baseline' 1.378 +// *including* cells with rowspans 1.379 +nscoord nsTableRowFrame::GetMaxCellAscent() const 1.380 +{ 1.381 + return mMaxCellAscent; 1.382 +} 1.383 + 1.384 +nscoord nsTableRowFrame::GetRowBaseline() 1.385 +{ 1.386 + if(mMaxCellAscent) 1.387 + return mMaxCellAscent; 1.388 + 1.389 + // If we don't have a baseline on any of the cells we go for the lowest 1.390 + // content edge of the inner block frames. 1.391 + // Every table cell has a cell frame with its border and padding. Inside 1.392 + // the cell is a block frame. The cell is as high as the tallest cell in 1.393 + // the parent row. As a consequence the block frame might not touch both 1.394 + // the top and the bottom padding of it parent cell frame at the same time. 1.395 + // 1.396 + // bbbbbbbbbbbbbbbbbb cell border: b 1.397 + // bppppppppppppppppb cell padding: p 1.398 + // bpxxxxxxxxxxxxxxpb inner block: x 1.399 + // bpx xpb 1.400 + // bpx xpb 1.401 + // bpx xpb 1.402 + // bpxxxxxxxxxxxxxxpb base line 1.403 + // bp pb 1.404 + // bp pb 1.405 + // bppppppppppppppppb 1.406 + // bbbbbbbbbbbbbbbbbb 1.407 + 1.408 + nsTableIterator iter(*this); 1.409 + nsIFrame* childFrame = iter.First(); 1.410 + nscoord ascent = 0; 1.411 + while (childFrame) { 1.412 + if (IS_TABLE_CELL(childFrame->GetType())) { 1.413 + nsIFrame* firstKid = childFrame->GetFirstPrincipalChild(); 1.414 + ascent = std::max(ascent, firstKid->GetRect().YMost()); 1.415 + } 1.416 + // Get the next child 1.417 + childFrame = iter.Next(); 1.418 + } 1.419 + return ascent; 1.420 +} 1.421 +nscoord 1.422 +nsTableRowFrame::GetHeight(nscoord aPctBasis) const 1.423 +{ 1.424 + nscoord height = 0; 1.425 + if ((aPctBasis > 0) && HasPctHeight()) { 1.426 + height = NSToCoordRound(GetPctHeight() * (float)aPctBasis); 1.427 + } 1.428 + if (HasFixedHeight()) { 1.429 + height = std::max(height, GetFixedHeight()); 1.430 + } 1.431 + return std::max(height, GetContentHeight()); 1.432 +} 1.433 + 1.434 +void 1.435 +nsTableRowFrame::ResetHeight(nscoord aFixedHeight) 1.436 +{ 1.437 + SetHasFixedHeight(false); 1.438 + SetHasPctHeight(false); 1.439 + SetFixedHeight(0); 1.440 + SetPctHeight(0); 1.441 + SetContentHeight(0); 1.442 + 1.443 + if (aFixedHeight > 0) { 1.444 + SetFixedHeight(aFixedHeight); 1.445 + } 1.446 + 1.447 + mMaxCellAscent = 0; 1.448 + mMaxCellDescent = 0; 1.449 +} 1.450 + 1.451 +void 1.452 +nsTableRowFrame::UpdateHeight(nscoord aHeight, 1.453 + nscoord aAscent, 1.454 + nscoord aDescent, 1.455 + nsTableFrame* aTableFrame, 1.456 + nsTableCellFrame* aCellFrame) 1.457 +{ 1.458 + if (!aTableFrame || !aCellFrame) { 1.459 + NS_ASSERTION(false , "invalid call"); 1.460 + return; 1.461 + } 1.462 + 1.463 + if (aHeight != NS_UNCONSTRAINEDSIZE) { 1.464 + if (!(aCellFrame->HasVerticalAlignBaseline())) { // only the cell's height matters 1.465 + if (GetHeight() < aHeight) { 1.466 + int32_t rowSpan = aTableFrame->GetEffectiveRowSpan(*aCellFrame); 1.467 + if (rowSpan == 1) { 1.468 + SetContentHeight(aHeight); 1.469 + } 1.470 + } 1.471 + } 1.472 + else { // the alignment on the baseline can change the height 1.473 + NS_ASSERTION((aAscent != NS_UNCONSTRAINEDSIZE) && (aDescent != NS_UNCONSTRAINEDSIZE), "invalid call"); 1.474 + // see if this is a long ascender 1.475 + if (mMaxCellAscent < aAscent) { 1.476 + mMaxCellAscent = aAscent; 1.477 + } 1.478 + // see if this is a long descender and without rowspan 1.479 + if (mMaxCellDescent < aDescent) { 1.480 + int32_t rowSpan = aTableFrame->GetEffectiveRowSpan(*aCellFrame); 1.481 + if (rowSpan == 1) { 1.482 + mMaxCellDescent = aDescent; 1.483 + } 1.484 + } 1.485 + // keep the tallest height in sync 1.486 + if (GetHeight() < mMaxCellAscent + mMaxCellDescent) { 1.487 + SetContentHeight(mMaxCellAscent + mMaxCellDescent); 1.488 + } 1.489 + } 1.490 + } 1.491 +} 1.492 + 1.493 +nscoord 1.494 +nsTableRowFrame::CalcHeight(const nsHTMLReflowState& aReflowState) 1.495 +{ 1.496 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.497 + nscoord computedHeight = (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedHeight()) 1.498 + ? 0 : aReflowState.ComputedHeight(); 1.499 + ResetHeight(computedHeight); 1.500 + 1.501 + const nsStylePosition* position = StylePosition(); 1.502 + if (position->mHeight.ConvertsToLength()) { 1.503 + SetFixedHeight(nsRuleNode::ComputeCoordPercentCalc(position->mHeight, 0)); 1.504 + } 1.505 + else if (eStyleUnit_Percent == position->mHeight.GetUnit()) { 1.506 + SetPctHeight(position->mHeight.GetPercentValue()); 1.507 + } 1.508 + // calc() with percentages is treated like 'auto' on table rows. 1.509 + 1.510 + for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame; 1.511 + kidFrame = kidFrame->GetNextSibling()) { 1.512 + nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); 1.513 + if (cellFrame) { 1.514 + nsSize desSize = cellFrame->GetDesiredSize(); 1.515 + if ((NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) && !GetPrevInFlow()) { 1.516 + CalculateCellActualHeight(cellFrame, desSize.height); 1.517 + } 1.518 + // height may have changed, adjust descent to absorb any excess difference 1.519 + nscoord ascent; 1.520 + if (!kidFrame->GetFirstPrincipalChild()->GetFirstPrincipalChild()) 1.521 + ascent = desSize.height; 1.522 + else 1.523 + ascent = cellFrame->GetCellBaseline(); 1.524 + nscoord descent = desSize.height - ascent; 1.525 + UpdateHeight(desSize.height, ascent, descent, tableFrame, cellFrame); 1.526 + } 1.527 + } 1.528 + return GetHeight(); 1.529 +} 1.530 + 1.531 +/** 1.532 + * We need a custom display item for table row backgrounds. This is only used 1.533 + * when the table row is the root of a stacking context (e.g., has 'opacity'). 1.534 + * Table row backgrounds can extend beyond the row frame bounds, when 1.535 + * the row contains row-spanning cells. 1.536 + */ 1.537 +class nsDisplayTableRowBackground : public nsDisplayTableItem { 1.538 +public: 1.539 + nsDisplayTableRowBackground(nsDisplayListBuilder* aBuilder, 1.540 + nsTableRowFrame* aFrame) : 1.541 + nsDisplayTableItem(aBuilder, aFrame) { 1.542 + MOZ_COUNT_CTOR(nsDisplayTableRowBackground); 1.543 + } 1.544 +#ifdef NS_BUILD_REFCNT_LOGGING 1.545 + virtual ~nsDisplayTableRowBackground() { 1.546 + MOZ_COUNT_DTOR(nsDisplayTableRowBackground); 1.547 + } 1.548 +#endif 1.549 + 1.550 + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.551 + const nsDisplayItemGeometry* aGeometry, 1.552 + nsRegion *aInvalidRegion) MOZ_OVERRIDE; 1.553 + virtual void Paint(nsDisplayListBuilder* aBuilder, 1.554 + nsRenderingContext* aCtx) MOZ_OVERRIDE; 1.555 + NS_DISPLAY_DECL_NAME("TableRowBackground", TYPE_TABLE_ROW_BACKGROUND) 1.556 +}; 1.557 + 1.558 +void 1.559 +nsDisplayTableRowBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.560 + const nsDisplayItemGeometry* aGeometry, 1.561 + nsRegion *aInvalidRegion) 1.562 +{ 1.563 + if (aBuilder->ShouldSyncDecodeImages()) { 1.564 + if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame, mFrame->GetNextSibling())) { 1.565 + bool snap; 1.566 + aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap)); 1.567 + } 1.568 + } 1.569 + 1.570 + nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); 1.571 +} 1.572 + 1.573 +void 1.574 +nsDisplayTableRowBackground::Paint(nsDisplayListBuilder* aBuilder, 1.575 + nsRenderingContext* aCtx) 1.576 +{ 1.577 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame); 1.578 + TableBackgroundPainter painter(tableFrame, 1.579 + TableBackgroundPainter::eOrigin_TableRow, 1.580 + mFrame->PresContext(), *aCtx, 1.581 + mVisibleRect, ToReferenceFrame(), 1.582 + aBuilder->GetBackgroundPaintFlags()); 1.583 + painter.PaintRow(static_cast<nsTableRowFrame*>(mFrame)); 1.584 +} 1.585 + 1.586 +void 1.587 +nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.588 + const nsRect& aDirtyRect, 1.589 + const nsDisplayListSet& aLists) 1.590 +{ 1.591 + nsDisplayTableItem* item = nullptr; 1.592 + if (IsVisibleInSelection(aBuilder)) { 1.593 + bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext(); 1.594 + if (isRoot) { 1.595 + // This background is created regardless of whether this frame is 1.596 + // visible or not. Visibility decisions are delegated to the 1.597 + // table background painter. 1.598 + // We would use nsDisplayGeneric for this rare case except that we 1.599 + // need the background to be larger than the row frame in some 1.600 + // cases. 1.601 + item = new (aBuilder) nsDisplayTableRowBackground(aBuilder, this); 1.602 + aLists.BorderBackground()->AppendNewToTop(item); 1.603 + } 1.604 + } 1.605 + nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item); 1.606 +} 1.607 + 1.608 +int 1.609 +nsTableRowFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const 1.610 +{ 1.611 + int skip = 0; 1.612 + if (nullptr != GetPrevInFlow()) { 1.613 + skip |= LOGICAL_SIDE_B_START; 1.614 + } 1.615 + if (nullptr != GetNextInFlow()) { 1.616 + skip |= LOGICAL_SIDE_B_END; 1.617 + } 1.618 + return skip; 1.619 +} 1.620 + 1.621 +// Calculate the cell's actual height given its pass2 height. 1.622 +// Takes into account the specified height (in the style). 1.623 +// Modifies the desired height that is passed in. 1.624 +nsresult 1.625 +nsTableRowFrame::CalculateCellActualHeight(nsTableCellFrame* aCellFrame, 1.626 + nscoord& aDesiredHeight) 1.627 +{ 1.628 + nscoord specifiedHeight = 0; 1.629 + 1.630 + // Get the height specified in the style information 1.631 + const nsStylePosition* position = aCellFrame->StylePosition(); 1.632 + 1.633 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.634 + int32_t rowSpan = tableFrame->GetEffectiveRowSpan(*aCellFrame); 1.635 + 1.636 + switch (position->mHeight.GetUnit()) { 1.637 + case eStyleUnit_Calc: { 1.638 + if (position->mHeight.CalcHasPercent()) { 1.639 + // Treat this like "auto" 1.640 + break; 1.641 + } 1.642 + // Fall through to the coord case 1.643 + } 1.644 + case eStyleUnit_Coord: { 1.645 + nscoord outsideBoxSizing = 0; 1.646 + // In quirks mode, table cell width should be content-box, but height 1.647 + // should be border-box. 1.648 + // Because of this historic anomaly, we do not use quirk.css 1.649 + // (since we can't specify one value of box-sizing for width and another 1.650 + // for height) 1.651 + if (PresContext()->CompatibilityMode() != eCompatibility_NavQuirks) { 1.652 + switch (position->mBoxSizing) { 1.653 + case NS_STYLE_BOX_SIZING_CONTENT: 1.654 + outsideBoxSizing = aCellFrame->GetUsedBorderAndPadding().TopBottom(); 1.655 + break; 1.656 + case NS_STYLE_BOX_SIZING_PADDING: 1.657 + outsideBoxSizing = aCellFrame->GetUsedBorder().TopBottom(); 1.658 + break; 1.659 + default: 1.660 + // NS_STYLE_BOX_SIZING_BORDER 1.661 + break; 1.662 + } 1.663 + } 1.664 + 1.665 + specifiedHeight = 1.666 + nsRuleNode::ComputeCoordPercentCalc(position->mHeight, 0) + 1.667 + outsideBoxSizing; 1.668 + 1.669 + if (1 == rowSpan) 1.670 + SetFixedHeight(specifiedHeight); 1.671 + break; 1.672 + } 1.673 + case eStyleUnit_Percent: { 1.674 + if (1 == rowSpan) 1.675 + SetPctHeight(position->mHeight.GetPercentValue()); 1.676 + // pct heights are handled when all of the cells are finished, so don't set specifiedHeight 1.677 + break; 1.678 + } 1.679 + case eStyleUnit_Auto: 1.680 + default: 1.681 + break; 1.682 + } 1.683 + 1.684 + // If the specified height is greater than the desired height, then use the specified height 1.685 + if (specifiedHeight > aDesiredHeight) 1.686 + aDesiredHeight = specifiedHeight; 1.687 + 1.688 + return NS_OK; 1.689 +} 1.690 + 1.691 +// Calculates the available width for the table cell based on the known 1.692 +// column widths taking into account column spans and column spacing 1.693 +static nscoord 1.694 +CalcAvailWidth(nsTableFrame& aTableFrame, 1.695 + nsTableCellFrame& aCellFrame, 1.696 + nscoord aCellSpacingX) 1.697 +{ 1.698 + nscoord cellAvailWidth = 0; 1.699 + int32_t colIndex; 1.700 + aCellFrame.GetColIndex(colIndex); 1.701 + int32_t colspan = aTableFrame.GetEffectiveColSpan(aCellFrame); 1.702 + NS_ASSERTION(colspan > 0, "effective colspan should be positive"); 1.703 + 1.704 + for (int32_t spanX = 0; spanX < colspan; spanX++) { 1.705 + cellAvailWidth += aTableFrame.GetColumnWidth(colIndex + spanX); 1.706 + if (spanX > 0 && 1.707 + aTableFrame.ColumnHasCellSpacingBefore(colIndex + spanX)) { 1.708 + cellAvailWidth += aCellSpacingX; 1.709 + } 1.710 + } 1.711 + return cellAvailWidth; 1.712 +} 1.713 + 1.714 +nscoord 1.715 +GetSpaceBetween(int32_t aPrevColIndex, 1.716 + int32_t aColIndex, 1.717 + int32_t aColSpan, 1.718 + nsTableFrame& aTableFrame, 1.719 + nscoord aCellSpacingX, 1.720 + bool aIsLeftToRight, 1.721 + bool aCheckVisibility) 1.722 +{ 1.723 + nscoord space = 0; 1.724 + int32_t colX; 1.725 + if (aIsLeftToRight) { 1.726 + for (colX = aPrevColIndex + 1; aColIndex > colX; colX++) { 1.727 + bool isCollapsed = false; 1.728 + if (!aCheckVisibility) { 1.729 + space += aTableFrame.GetColumnWidth(colX); 1.730 + } 1.731 + else { 1.732 + nsTableColFrame* colFrame = aTableFrame.GetColFrame(colX); 1.733 + const nsStyleVisibility* colVis = colFrame->StyleVisibility(); 1.734 + bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible); 1.735 + nsIFrame* cgFrame = colFrame->GetParent(); 1.736 + const nsStyleVisibility* groupVis = cgFrame->StyleVisibility(); 1.737 + bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == 1.738 + groupVis->mVisible); 1.739 + isCollapsed = collapseCol || collapseGroup; 1.740 + if (!isCollapsed) 1.741 + space += aTableFrame.GetColumnWidth(colX); 1.742 + } 1.743 + if (!isCollapsed && aTableFrame.ColumnHasCellSpacingBefore(colX)) { 1.744 + space += aCellSpacingX; 1.745 + } 1.746 + } 1.747 + } 1.748 + else { 1.749 + int32_t lastCol = aColIndex + aColSpan - 1; 1.750 + for (colX = aPrevColIndex - 1; colX > lastCol; colX--) { 1.751 + bool isCollapsed = false; 1.752 + if (!aCheckVisibility) { 1.753 + space += aTableFrame.GetColumnWidth(colX); 1.754 + } 1.755 + else { 1.756 + nsTableColFrame* colFrame = aTableFrame.GetColFrame(colX); 1.757 + const nsStyleVisibility* colVis = colFrame->StyleVisibility(); 1.758 + bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible); 1.759 + nsIFrame* cgFrame = colFrame->GetParent(); 1.760 + const nsStyleVisibility* groupVis = cgFrame->StyleVisibility(); 1.761 + bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == 1.762 + groupVis->mVisible); 1.763 + isCollapsed = collapseCol || collapseGroup; 1.764 + if (!isCollapsed) 1.765 + space += aTableFrame.GetColumnWidth(colX); 1.766 + } 1.767 + if (!isCollapsed && aTableFrame.ColumnHasCellSpacingBefore(colX)) { 1.768 + space += aCellSpacingX; 1.769 + } 1.770 + } 1.771 + } 1.772 + return space; 1.773 +} 1.774 + 1.775 +// subtract the heights of aRow's prev in flows from the unpaginated height 1.776 +static 1.777 +nscoord CalcHeightFromUnpaginatedHeight(nsPresContext* aPresContext, 1.778 + nsTableRowFrame& aRow) 1.779 +{ 1.780 + nscoord height = 0; 1.781 + nsTableRowFrame* firstInFlow = 1.782 + static_cast<nsTableRowFrame*>(aRow.FirstInFlow()); 1.783 + if (firstInFlow->HasUnpaginatedHeight()) { 1.784 + height = firstInFlow->GetUnpaginatedHeight(aPresContext); 1.785 + for (nsIFrame* prevInFlow = aRow.GetPrevInFlow(); prevInFlow; 1.786 + prevInFlow = prevInFlow->GetPrevInFlow()) { 1.787 + height -= prevInFlow->GetSize().height; 1.788 + } 1.789 + } 1.790 + return std::max(height, 0); 1.791 +} 1.792 + 1.793 +nsresult 1.794 +nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, 1.795 + nsHTMLReflowMetrics& aDesiredSize, 1.796 + const nsHTMLReflowState& aReflowState, 1.797 + nsTableFrame& aTableFrame, 1.798 + nsReflowStatus& aStatus) 1.799 +{ 1.800 + aStatus = NS_FRAME_COMPLETE; 1.801 + 1.802 + // XXXldb Should we be checking constrained height instead? 1.803 + const bool isPaginated = aPresContext->IsPaginated(); 1.804 + const bool borderCollapse = aTableFrame.IsBorderCollapse(); 1.805 + nsresult rv = NS_OK; 1.806 + nscoord cellSpacingX = aTableFrame.GetCellSpacingX(); 1.807 + int32_t cellColSpan = 1; // must be defined here so it's set properly for non-cell kids 1.808 + 1.809 + nsTableIterator iter(*this); 1.810 + // remember the col index of the previous cell to handle rowspans into this row 1.811 + int32_t firstPrevColIndex = (iter.IsLeftToRight()) ? -1 : aTableFrame.GetColCount(); 1.812 + int32_t prevColIndex = firstPrevColIndex; 1.813 + nscoord x = 0; // running total of children x offset 1.814 + 1.815 + // This computes the max of all cell heights 1.816 + nscoord cellMaxHeight = 0; 1.817 + 1.818 + // Reflow each of our existing cell frames 1.819 + for (nsIFrame* kidFrame = iter.First(); kidFrame; kidFrame = iter.Next()) { 1.820 + nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); 1.821 + if (!cellFrame) { 1.822 + // XXXldb nsCSSFrameConstructor needs to enforce this! 1.823 + NS_NOTREACHED("yikes, a non-row child"); 1.824 + 1.825 + // it's an unknown frame type, give it a generic reflow and ignore the results 1.826 + nsTableCellReflowState kidReflowState(aPresContext, aReflowState, 1.827 + kidFrame, nsSize(0,0), 1.828 + nsHTMLReflowState::CALLER_WILL_INIT); 1.829 + InitChildReflowState(*aPresContext, nsSize(0,0), false, kidReflowState); 1.830 + nsHTMLReflowMetrics desiredSize(aReflowState); 1.831 + nsReflowStatus status; 1.832 + ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, 0, 0, 0, status); 1.833 + kidFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED); 1.834 + 1.835 + continue; 1.836 + } 1.837 + 1.838 + // See if we should only reflow the dirty child frames 1.839 + bool doReflowChild = true; 1.840 + if (!aReflowState.ShouldReflowAllKids() && 1.841 + !aTableFrame.IsGeometryDirty() && 1.842 + !NS_SUBTREE_DIRTY(kidFrame)) { 1.843 + if (!aReflowState.mFlags.mSpecialHeightReflow) 1.844 + doReflowChild = false; 1.845 + } 1.846 + else if ((NS_UNCONSTRAINEDSIZE != aReflowState.AvailableHeight())) { 1.847 + // We don't reflow a rowspan >1 cell here with a constrained height. 1.848 + // That happens in nsTableRowGroupFrame::SplitSpanningCells. 1.849 + if (aTableFrame.GetEffectiveRowSpan(*cellFrame) > 1) { 1.850 + doReflowChild = false; 1.851 + } 1.852 + } 1.853 + if (aReflowState.mFlags.mSpecialHeightReflow) { 1.854 + if (!isPaginated && !(cellFrame->GetStateBits() & 1.855 + NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) { 1.856 + continue; 1.857 + } 1.858 + } 1.859 + 1.860 + int32_t cellColIndex; 1.861 + cellFrame->GetColIndex(cellColIndex); 1.862 + cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame); 1.863 + 1.864 + // If the adjacent cell is in a prior row (because of a rowspan) add in the space 1.865 + if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) || 1.866 + (!iter.IsLeftToRight() && (prevColIndex != cellColIndex + cellColSpan))) { 1.867 + x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, aTableFrame, 1.868 + cellSpacingX, iter.IsLeftToRight(), false); 1.869 + } 1.870 + 1.871 + // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into 1.872 + prevColIndex = (iter.IsLeftToRight()) ? cellColIndex + (cellColSpan - 1) : cellColIndex; 1.873 + 1.874 + // Reflow the child frame 1.875 + nsRect kidRect = kidFrame->GetRect(); 1.876 + nsRect kidVisualOverflow = kidFrame->GetVisualOverflowRect(); 1.877 + bool firstReflow = 1.878 + (kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; 1.879 + 1.880 + if (doReflowChild) { 1.881 + // Calculate the available width for the table cell using the known column widths 1.882 + nscoord availCellWidth = 1.883 + CalcAvailWidth(aTableFrame, *cellFrame, cellSpacingX); 1.884 + 1.885 + nsHTMLReflowMetrics desiredSize(aReflowState); 1.886 + 1.887 + // If the avail width is not the same as last time we reflowed the cell or 1.888 + // the cell wants to be bigger than what was available last time or 1.889 + // it is a style change reflow or we are printing, then we must reflow the 1.890 + // cell. Otherwise we can skip the reflow. 1.891 + // XXXldb Why is this condition distinct from doReflowChild above? 1.892 + nsSize cellDesiredSize = cellFrame->GetDesiredSize(); 1.893 + if ((availCellWidth != cellFrame->GetPriorAvailWidth()) || 1.894 + (cellDesiredSize.width > cellFrame->GetPriorAvailWidth()) || 1.895 + (GetStateBits() & NS_FRAME_IS_DIRTY) || 1.896 + isPaginated || 1.897 + NS_SUBTREE_DIRTY(cellFrame) || 1.898 + // See if it needs a special reflow, or if it had one that we need to undo. 1.899 + (cellFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT) || 1.900 + HasPctHeight()) { 1.901 + // Reflow the cell to fit the available width, height 1.902 + // XXX The old IR_ChildIsDirty code used availCellWidth here. 1.903 + nsSize kidAvailSize(availCellWidth, aReflowState.AvailableHeight()); 1.904 + 1.905 + // Reflow the child 1.906 + nsTableCellReflowState kidReflowState(aPresContext, aReflowState, 1.907 + kidFrame, kidAvailSize, 1.908 + nsHTMLReflowState::CALLER_WILL_INIT); 1.909 + InitChildReflowState(*aPresContext, kidAvailSize, borderCollapse, 1.910 + kidReflowState); 1.911 + 1.912 + nsReflowStatus status; 1.913 + rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, 1.914 + x, 0, 0, status); 1.915 + 1.916 + // allow the table to determine if/how the table needs to be rebalanced 1.917 + // If any of the cells are not complete, then we're not complete 1.918 + if (NS_FRAME_IS_NOT_COMPLETE(status)) { 1.919 + aStatus = NS_FRAME_NOT_COMPLETE; 1.920 + } 1.921 + } 1.922 + else { 1.923 + if (x != kidRect.x) { 1.924 + kidFrame->InvalidateFrameSubtree(); 1.925 + } 1.926 + 1.927 + desiredSize.Width() = cellDesiredSize.width; 1.928 + desiredSize.Height() = cellDesiredSize.height; 1.929 + desiredSize.mOverflowAreas = cellFrame->GetOverflowAreas(); 1.930 + 1.931 + // if we are in a floated table, our position is not yet established, so we cannot reposition our views 1.932 + // the containing block will do this for us after positioning the table 1.933 + if (!aTableFrame.IsFloating()) { 1.934 + // Because we may have moved the frame we need to make sure any views are 1.935 + // positioned properly. We have to do this, because any one of our parent 1.936 + // frames could have moved and we have no way of knowing... 1.937 + nsTableFrame::RePositionViews(kidFrame); 1.938 + } 1.939 + } 1.940 + 1.941 + if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) { 1.942 + if (!GetPrevInFlow()) { 1.943 + // Calculate the cell's actual height given its pass2 height. This 1.944 + // function takes into account the specified height (in the style) 1.945 + CalculateCellActualHeight(cellFrame, desiredSize.Height()); 1.946 + } 1.947 + // height may have changed, adjust descent to absorb any excess difference 1.948 + nscoord ascent; 1.949 + if (!kidFrame->GetFirstPrincipalChild()->GetFirstPrincipalChild()) 1.950 + ascent = desiredSize.Height(); 1.951 + else 1.952 + ascent = ((nsTableCellFrame *)kidFrame)->GetCellBaseline(); 1.953 + nscoord descent = desiredSize.Height() - ascent; 1.954 + UpdateHeight(desiredSize.Height(), ascent, descent, &aTableFrame, cellFrame); 1.955 + } 1.956 + else { 1.957 + cellMaxHeight = std::max(cellMaxHeight, desiredSize.Height()); 1.958 + int32_t rowSpan = aTableFrame.GetEffectiveRowSpan((nsTableCellFrame&)*kidFrame); 1.959 + if (1 == rowSpan) { 1.960 + SetContentHeight(cellMaxHeight); 1.961 + } 1.962 + } 1.963 + 1.964 + // Place the child 1.965 + desiredSize.Width() = availCellWidth; 1.966 + 1.967 + FinishReflowChild(kidFrame, aPresContext, desiredSize, nullptr, x, 0, 0); 1.968 + 1.969 + nsTableFrame::InvalidateTableFrame(kidFrame, kidRect, kidVisualOverflow, 1.970 + firstReflow); 1.971 + 1.972 + x += desiredSize.Width(); 1.973 + } 1.974 + else { 1.975 + if (kidRect.x != x) { 1.976 + // Invalidate the old position 1.977 + kidFrame->InvalidateFrameSubtree(); 1.978 + // move to the new position 1.979 + kidFrame->SetPosition(nsPoint(x, kidRect.y)); 1.980 + nsTableFrame::RePositionViews(kidFrame); 1.981 + // invalidate the new position 1.982 + kidFrame->InvalidateFrameSubtree(); 1.983 + } 1.984 + // we need to account for the cell's width even if it isn't reflowed 1.985 + x += kidRect.width; 1.986 + 1.987 + if (kidFrame->GetNextInFlow()) { 1.988 + aStatus = NS_FRAME_NOT_COMPLETE; 1.989 + } 1.990 + } 1.991 + ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame); 1.992 + x += cellSpacingX; 1.993 + } 1.994 + 1.995 + // just set our width to what was available. The table will calculate the width and not use our value. 1.996 + aDesiredSize.Width() = aReflowState.AvailableWidth(); 1.997 + 1.998 + if (aReflowState.mFlags.mSpecialHeightReflow) { 1.999 + aDesiredSize.Height() = mRect.height; 1.1000 + } 1.1001 + else if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) { 1.1002 + aDesiredSize.Height() = CalcHeight(aReflowState); 1.1003 + if (GetPrevInFlow()) { 1.1004 + nscoord height = CalcHeightFromUnpaginatedHeight(aPresContext, *this); 1.1005 + aDesiredSize.Height() = std::max(aDesiredSize.Height(), height); 1.1006 + } 1.1007 + else { 1.1008 + if (isPaginated && HasStyleHeight()) { 1.1009 + // set the unpaginated height so next in flows can try to honor it 1.1010 + SetHasUnpaginatedHeight(true); 1.1011 + SetUnpaginatedHeight(aPresContext, aDesiredSize.Height()); 1.1012 + } 1.1013 + if (isPaginated && HasUnpaginatedHeight()) { 1.1014 + aDesiredSize.Height() = std::max(aDesiredSize.Height(), GetUnpaginatedHeight(aPresContext)); 1.1015 + } 1.1016 + } 1.1017 + } 1.1018 + else { // constrained height, paginated 1.1019 + // Compute the height we should have from style (subtracting the 1.1020 + // height from our prev-in-flows from the style height) 1.1021 + nscoord styleHeight = CalcHeightFromUnpaginatedHeight(aPresContext, *this); 1.1022 + if (styleHeight > aReflowState.AvailableHeight()) { 1.1023 + styleHeight = aReflowState.AvailableHeight(); 1.1024 + NS_FRAME_SET_INCOMPLETE(aStatus); 1.1025 + } 1.1026 + aDesiredSize.Height() = std::max(cellMaxHeight, styleHeight); 1.1027 + } 1.1028 + aDesiredSize.UnionOverflowAreasWithDesiredBounds(); 1.1029 + FinishAndStoreOverflow(&aDesiredSize); 1.1030 + return rv; 1.1031 +} 1.1032 + 1.1033 +/** Layout the entire row. 1.1034 + * This method stacks cells horizontally according to HTML 4.0 rules. 1.1035 + */ 1.1036 +nsresult 1.1037 +nsTableRowFrame::Reflow(nsPresContext* aPresContext, 1.1038 + nsHTMLReflowMetrics& aDesiredSize, 1.1039 + const nsHTMLReflowState& aReflowState, 1.1040 + nsReflowStatus& aStatus) 1.1041 +{ 1.1042 + DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame"); 1.1043 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); 1.1044 + nsresult rv = NS_OK; 1.1045 + 1.1046 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.1047 + const nsStyleVisibility* rowVis = StyleVisibility(); 1.1048 + bool collapseRow = (NS_STYLE_VISIBILITY_COLLAPSE == rowVis->mVisible); 1.1049 + if (collapseRow) { 1.1050 + tableFrame->SetNeedToCollapse(true); 1.1051 + } 1.1052 + 1.1053 + // see if a special height reflow needs to occur due to having a pct height 1.1054 + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); 1.1055 + 1.1056 + // See if we have a cell with specified/pct height 1.1057 + InitHasCellWithStyleHeight(tableFrame); 1.1058 + 1.1059 + rv = ReflowChildren(aPresContext, aDesiredSize, aReflowState, *tableFrame, 1.1060 + aStatus); 1.1061 + 1.1062 + if (aPresContext->IsPaginated() && !NS_FRAME_IS_FULLY_COMPLETE(aStatus) && 1.1063 + ShouldAvoidBreakInside(aReflowState)) { 1.1064 + aStatus = NS_INLINE_LINE_BREAK_BEFORE(); 1.1065 + } 1.1066 + 1.1067 + // just set our width to what was available. The table will calculate the width and not use our value. 1.1068 + aDesiredSize.Width() = aReflowState.AvailableWidth(); 1.1069 + 1.1070 + // If our parent is in initial reflow, it'll handle invalidating our 1.1071 + // entire overflow rect. 1.1072 + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) && 1.1073 + nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) { 1.1074 + InvalidateFrame(); 1.1075 + } 1.1076 + 1.1077 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.1078 + return rv; 1.1079 +} 1.1080 + 1.1081 +/** 1.1082 + * This function is called by the row group frame's SplitRowGroup() code when 1.1083 + * pushing a row frame that has cell frames that span into it. The cell frame 1.1084 + * should be reflowed with the specified height 1.1085 + */ 1.1086 +nscoord 1.1087 +nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext, 1.1088 + const nsHTMLReflowState& aReflowState, 1.1089 + bool aIsTopOfPage, 1.1090 + nsTableCellFrame* aCellFrame, 1.1091 + nscoord aAvailableHeight, 1.1092 + nsReflowStatus& aStatus) 1.1093 +{ 1.1094 + // Reflow the cell frame with the specified height. Use the existing width 1.1095 + nsRect cellRect = aCellFrame->GetRect(); 1.1096 + nsRect cellVisualOverflow = aCellFrame->GetVisualOverflowRect(); 1.1097 + 1.1098 + nsSize availSize(cellRect.width, aAvailableHeight); 1.1099 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.1100 + bool borderCollapse = tableFrame->IsBorderCollapse(); 1.1101 + nsTableCellReflowState cellReflowState(aPresContext, aReflowState, 1.1102 + aCellFrame, availSize, 1.1103 + nsHTMLReflowState::CALLER_WILL_INIT); 1.1104 + InitChildReflowState(*aPresContext, availSize, borderCollapse, cellReflowState); 1.1105 + cellReflowState.mFlags.mIsTopOfPage = aIsTopOfPage; 1.1106 + 1.1107 + nsHTMLReflowMetrics desiredSize(aReflowState); 1.1108 + 1.1109 + ReflowChild(aCellFrame, aPresContext, desiredSize, cellReflowState, 1.1110 + 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); 1.1111 + bool fullyComplete = NS_FRAME_IS_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus); 1.1112 + if (fullyComplete) { 1.1113 + desiredSize.Height() = aAvailableHeight; 1.1114 + } 1.1115 + aCellFrame->SetSize(nsSize(cellRect.width, desiredSize.Height())); 1.1116 + 1.1117 + // Note: VerticallyAlignChild can affect the overflow rect. 1.1118 + // XXX What happens if this cell has 'vertical-align: baseline' ? 1.1119 + // XXX Why is it assumed that the cell's ascent hasn't changed ? 1.1120 + if (fullyComplete) { 1.1121 + aCellFrame->VerticallyAlignChild(mMaxCellAscent); 1.1122 + } 1.1123 + 1.1124 + nsTableFrame::InvalidateTableFrame(aCellFrame, cellRect, 1.1125 + cellVisualOverflow, 1.1126 + (aCellFrame->GetStateBits() & 1.1127 + NS_FRAME_FIRST_REFLOW) != 0); 1.1128 + 1.1129 + aCellFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED); 1.1130 + 1.1131 + return desiredSize.Height(); 1.1132 +} 1.1133 + 1.1134 +nscoord 1.1135 +nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, 1.1136 + nscoord aWidth, 1.1137 + bool aCollapseGroup, 1.1138 + bool& aDidCollapse) 1.1139 +{ 1.1140 + const nsStyleVisibility* rowVis = StyleVisibility(); 1.1141 + bool collapseRow = (NS_STYLE_VISIBILITY_COLLAPSE == rowVis->mVisible); 1.1142 + nsTableFrame* tableFrame = static_cast<nsTableFrame*>( 1.1143 + nsTableFrame::GetTableFrame(this)->FirstInFlow()); 1.1144 + if (collapseRow) { 1.1145 + tableFrame->SetNeedToCollapse(true); 1.1146 + } 1.1147 + 1.1148 + if (aRowOffset != 0) { 1.1149 + // We're moving, so invalidate our old position 1.1150 + InvalidateFrameSubtree(); 1.1151 + } 1.1152 + 1.1153 + nsRect rowRect = GetRect(); 1.1154 + nsRect oldRect = rowRect; 1.1155 + nsRect oldVisualOverflow = GetVisualOverflowRect(); 1.1156 + 1.1157 + rowRect.y -= aRowOffset; 1.1158 + rowRect.width = aWidth; 1.1159 + nsOverflowAreas overflow; 1.1160 + nscoord shift = 0; 1.1161 + nscoord cellSpacingX = tableFrame->GetCellSpacingX(); 1.1162 + nscoord cellSpacingY = tableFrame->GetCellSpacingY(); 1.1163 + 1.1164 + if (aCollapseGroup || collapseRow) { 1.1165 + nsTableCellFrame* cellFrame = GetFirstCell(); 1.1166 + aDidCollapse = true; 1.1167 + shift = rowRect.height + cellSpacingY; 1.1168 + while (cellFrame) { 1.1169 + nsRect cRect = cellFrame->GetRect(); 1.1170 + // If aRowOffset != 0, there's no point in invalidating the cells, since 1.1171 + // we've already invalidated our overflow area. Note that we _do_ still 1.1172 + // need to invalidate if our row is not moving, because the cell might 1.1173 + // span out of this row, so invalidating our row rect won't do enough. 1.1174 + if (aRowOffset == 0) { 1.1175 + InvalidateFrame(); 1.1176 + } 1.1177 + cRect.height = 0; 1.1178 + cellFrame->SetRect(cRect); 1.1179 + cellFrame = cellFrame->GetNextCell(); 1.1180 + } 1.1181 + rowRect.height = 0; 1.1182 + } 1.1183 + else { // row is not collapsed 1.1184 + nsTableIterator iter(*this); 1.1185 + // remember the col index of the previous cell to handle rowspans into this 1.1186 + // row 1.1187 + int32_t firstPrevColIndex = (iter.IsLeftToRight()) ? -1 : 1.1188 + tableFrame->GetColCount(); 1.1189 + int32_t prevColIndex = firstPrevColIndex; 1.1190 + nscoord x = 0; // running total of children x offset 1.1191 + 1.1192 + int32_t colIncrement = iter.IsLeftToRight() ? 1 : -1; 1.1193 + 1.1194 + //nscoord x = cellSpacingX; 1.1195 + 1.1196 + nsIFrame* kidFrame = iter.First(); 1.1197 + while (kidFrame) { 1.1198 + nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); 1.1199 + if (cellFrame) { 1.1200 + int32_t cellColIndex; 1.1201 + cellFrame->GetColIndex(cellColIndex); 1.1202 + int32_t cellColSpan = tableFrame->GetEffectiveColSpan(*cellFrame); 1.1203 + 1.1204 + // If the adjacent cell is in a prior row (because of a rowspan) add in 1.1205 + // the space 1.1206 + if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) || 1.1207 + (!iter.IsLeftToRight() && 1.1208 + (prevColIndex != cellColIndex + cellColSpan))) { 1.1209 + x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, 1.1210 + *tableFrame, cellSpacingX, iter.IsLeftToRight(), 1.1211 + true); 1.1212 + } 1.1213 + nsRect cRect(x, 0, 0, rowRect.height); 1.1214 + 1.1215 + // remember the rightmost (ltr) or leftmost (rtl) column this cell 1.1216 + // spans into 1.1217 + prevColIndex = (iter.IsLeftToRight()) ? 1.1218 + cellColIndex + (cellColSpan - 1) : cellColIndex; 1.1219 + int32_t startIndex = (iter.IsLeftToRight()) ? 1.1220 + cellColIndex : cellColIndex + (cellColSpan - 1); 1.1221 + int32_t actualColSpan = cellColSpan; 1.1222 + bool isVisible = false; 1.1223 + for (int32_t colX = startIndex; actualColSpan > 0; 1.1224 + colX += colIncrement, actualColSpan--) { 1.1225 + 1.1226 + nsTableColFrame* colFrame = tableFrame->GetColFrame(colX); 1.1227 + const nsStyleVisibility* colVis = colFrame->StyleVisibility(); 1.1228 + bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == 1.1229 + colVis->mVisible); 1.1230 + nsIFrame* cgFrame = colFrame->GetParent(); 1.1231 + const nsStyleVisibility* groupVis = cgFrame->StyleVisibility(); 1.1232 + bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == 1.1233 + groupVis->mVisible); 1.1234 + bool isCollapsed = collapseCol || collapseGroup; 1.1235 + if (!isCollapsed) { 1.1236 + cRect.width += tableFrame->GetColumnWidth(colX); 1.1237 + isVisible = true; 1.1238 + if ((actualColSpan > 1)) { 1.1239 + nsTableColFrame* nextColFrame = 1.1240 + tableFrame->GetColFrame(colX + colIncrement); 1.1241 + const nsStyleVisibility* nextColVis = 1.1242 + nextColFrame->StyleVisibility(); 1.1243 + if ( (NS_STYLE_VISIBILITY_COLLAPSE != nextColVis->mVisible) && 1.1244 + tableFrame->ColumnHasCellSpacingBefore(colX + colIncrement)) { 1.1245 + cRect.width += cellSpacingX; 1.1246 + } 1.1247 + } 1.1248 + } 1.1249 + } 1.1250 + x += cRect.width; 1.1251 + if (isVisible) 1.1252 + x += cellSpacingX; 1.1253 + int32_t actualRowSpan = tableFrame->GetEffectiveRowSpan(*cellFrame); 1.1254 + nsTableRowFrame* rowFrame = GetNextRow(); 1.1255 + for (actualRowSpan--; actualRowSpan > 0 && rowFrame; actualRowSpan--) { 1.1256 + const nsStyleVisibility* nextRowVis = rowFrame->StyleVisibility(); 1.1257 + bool collapseNextRow = (NS_STYLE_VISIBILITY_COLLAPSE == 1.1258 + nextRowVis->mVisible); 1.1259 + if (!collapseNextRow) { 1.1260 + nsRect nextRect = rowFrame->GetRect(); 1.1261 + cRect.height += nextRect.height + cellSpacingY; 1.1262 + } 1.1263 + rowFrame = rowFrame->GetNextRow(); 1.1264 + } 1.1265 + 1.1266 + nsRect oldCellRect = cellFrame->GetRect(); 1.1267 + nsRect oldCellVisualOverflow = cellFrame->GetVisualOverflowRect(); 1.1268 + 1.1269 + if (aRowOffset == 0 && cRect.TopLeft() != oldCellRect.TopLeft()) { 1.1270 + // We're moving the cell. Invalidate the old overflow area 1.1271 + cellFrame->InvalidateFrameSubtree(); 1.1272 + } 1.1273 + 1.1274 + cellFrame->SetRect(cRect); 1.1275 + 1.1276 + // XXXbz This looks completely bogus in the cases when we didn't 1.1277 + // collapse the cell! 1.1278 + nsRect cellBounds(0, 0, cRect.width, cRect.height); 1.1279 + nsOverflowAreas cellOverflow(cellBounds, cellBounds); 1.1280 + cellFrame->FinishAndStoreOverflow(cellOverflow, cRect.Size()); 1.1281 + nsTableFrame::RePositionViews(cellFrame); 1.1282 + ConsiderChildOverflow(overflow, cellFrame); 1.1283 + 1.1284 + if (aRowOffset == 0) { 1.1285 + nsTableFrame::InvalidateTableFrame(cellFrame, oldCellRect, 1.1286 + oldCellVisualOverflow, 1.1287 + false); 1.1288 + } 1.1289 + } 1.1290 + kidFrame = iter.Next(); // Get the next child 1.1291 + } 1.1292 + } 1.1293 + 1.1294 + SetRect(rowRect); 1.1295 + overflow.UnionAllWith(nsRect(0, 0, rowRect.width, rowRect.height)); 1.1296 + FinishAndStoreOverflow(overflow, rowRect.Size()); 1.1297 + 1.1298 + nsTableFrame::RePositionViews(this); 1.1299 + nsTableFrame::InvalidateTableFrame(this, oldRect, oldVisualOverflow, false); 1.1300 + return shift; 1.1301 +} 1.1302 + 1.1303 +/* 1.1304 + * The following method is called by the row group frame's SplitRowGroup() 1.1305 + * when it creates a continuing cell frame and wants to insert it into the 1.1306 + * row's child list. 1.1307 + */ 1.1308 +void 1.1309 +nsTableRowFrame::InsertCellFrame(nsTableCellFrame* aFrame, 1.1310 + int32_t aColIndex) 1.1311 +{ 1.1312 + // Find the cell frame where col index < aColIndex 1.1313 + nsTableCellFrame* priorCell = nullptr; 1.1314 + for (nsIFrame* child = mFrames.FirstChild(); child; 1.1315 + child = child->GetNextSibling()) { 1.1316 + nsTableCellFrame *cellFrame = do_QueryFrame(child); 1.1317 + if (cellFrame) { 1.1318 + int32_t colIndex; 1.1319 + cellFrame->GetColIndex(colIndex); 1.1320 + if (colIndex < aColIndex) { 1.1321 + priorCell = cellFrame; 1.1322 + } 1.1323 + else break; 1.1324 + } 1.1325 + } 1.1326 + mFrames.InsertFrame(this, priorCell, aFrame); 1.1327 +} 1.1328 + 1.1329 +nsIAtom* 1.1330 +nsTableRowFrame::GetType() const 1.1331 +{ 1.1332 + return nsGkAtoms::tableRowFrame; 1.1333 +} 1.1334 + 1.1335 +nsTableRowFrame* 1.1336 +nsTableRowFrame::GetNextRow() const 1.1337 +{ 1.1338 + nsIFrame* childFrame = GetNextSibling(); 1.1339 + while (childFrame) { 1.1340 + nsTableRowFrame *rowFrame = do_QueryFrame(childFrame); 1.1341 + if (rowFrame) { 1.1342 + NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW == childFrame->StyleDisplay()->mDisplay, "wrong display type on rowframe"); 1.1343 + return rowFrame; 1.1344 + } 1.1345 + childFrame = childFrame->GetNextSibling(); 1.1346 + } 1.1347 + return nullptr; 1.1348 +} 1.1349 + 1.1350 +NS_DECLARE_FRAME_PROPERTY(RowUnpaginatedHeightProperty, nullptr) 1.1351 + 1.1352 +void 1.1353 +nsTableRowFrame::SetUnpaginatedHeight(nsPresContext* aPresContext, 1.1354 + nscoord aValue) 1.1355 +{ 1.1356 + NS_ASSERTION(!GetPrevInFlow(), "program error"); 1.1357 + // Get the property 1.1358 + aPresContext->PropertyTable()-> 1.1359 + Set(this, RowUnpaginatedHeightProperty(), NS_INT32_TO_PTR(aValue)); 1.1360 +} 1.1361 + 1.1362 +nscoord 1.1363 +nsTableRowFrame::GetUnpaginatedHeight(nsPresContext* aPresContext) 1.1364 +{ 1.1365 + FrameProperties props = FirstInFlow()->Properties(); 1.1366 + return NS_PTR_TO_INT32(props.Get(RowUnpaginatedHeightProperty())); 1.1367 +} 1.1368 + 1.1369 +void nsTableRowFrame::SetContinuousBCBorderWidth(uint8_t aForSide, 1.1370 + BCPixelSize aPixelValue) 1.1371 +{ 1.1372 + switch (aForSide) { 1.1373 + case NS_SIDE_RIGHT: 1.1374 + mRightContBorderWidth = aPixelValue; 1.1375 + return; 1.1376 + case NS_SIDE_TOP: 1.1377 + mTopContBorderWidth = aPixelValue; 1.1378 + return; 1.1379 + case NS_SIDE_LEFT: 1.1380 + mLeftContBorderWidth = aPixelValue; 1.1381 + return; 1.1382 + default: 1.1383 + NS_ERROR("invalid NS_SIDE arg"); 1.1384 + } 1.1385 +} 1.1386 +#ifdef ACCESSIBILITY 1.1387 +a11y::AccType 1.1388 +nsTableRowFrame::AccessibleType() 1.1389 +{ 1.1390 + return a11y::eHTMLTableRowType; 1.1391 +} 1.1392 +#endif 1.1393 +/** 1.1394 + * Sets the NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT bit to indicate whether 1.1395 + * this row has any cells that have non-auto-height. (Row-spanning 1.1396 + * cells are ignored.) 1.1397 + */ 1.1398 +void nsTableRowFrame::InitHasCellWithStyleHeight(nsTableFrame* aTableFrame) 1.1399 +{ 1.1400 + nsTableIterator iter(*this); 1.1401 + 1.1402 + for (nsIFrame* kidFrame = iter.First(); kidFrame; kidFrame = iter.Next()) { 1.1403 + nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame); 1.1404 + if (!cellFrame) { 1.1405 + NS_NOTREACHED("Table row has a non-cell child."); 1.1406 + continue; 1.1407 + } 1.1408 + // Ignore row-spanning cells 1.1409 + const nsStyleCoord &cellHeight = cellFrame->StylePosition()->mHeight; 1.1410 + if (aTableFrame->GetEffectiveRowSpan(*cellFrame) == 1 && 1.1411 + cellHeight.GetUnit() != eStyleUnit_Auto && 1.1412 + /* calc() with percentages treated like 'auto' */ 1.1413 + (!cellHeight.IsCalcUnit() || !cellHeight.HasPercent())) { 1.1414 + AddStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT); 1.1415 + return; 1.1416 + } 1.1417 + } 1.1418 + RemoveStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT); 1.1419 +} 1.1420 + 1.1421 +void 1.1422 +nsTableRowFrame::InvalidateFrame(uint32_t aDisplayItemKey) 1.1423 +{ 1.1424 + nsIFrame::InvalidateFrame(aDisplayItemKey); 1.1425 + GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey); 1.1426 +} 1.1427 + 1.1428 +void 1.1429 +nsTableRowFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) 1.1430 +{ 1.1431 + nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey); 1.1432 + // If we have filters applied that would affects our bounds, then 1.1433 + // we get an inactive layer created and this is computed 1.1434 + // within FrameLayerBuilder 1.1435 + GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey); 1.1436 +} 1.1437 + 1.1438 +/* ----- global methods ----- */ 1.1439 + 1.1440 +nsIFrame* 1.1441 +NS_NewTableRowFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.1442 +{ 1.1443 + return new (aPresShell) nsTableRowFrame(aContext); 1.1444 +} 1.1445 + 1.1446 +NS_IMPL_FRAMEARENA_HELPERS(nsTableRowFrame) 1.1447 + 1.1448 +#ifdef DEBUG_FRAME_DUMP 1.1449 +nsresult 1.1450 +nsTableRowFrame::GetFrameName(nsAString& aResult) const 1.1451 +{ 1.1452 + return MakeFrameName(NS_LITERAL_STRING("TableRow"), aResult); 1.1453 +} 1.1454 +#endif