layout/tables/nsTableRowFrame.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5 #include "nsTableRowFrame.h"
michael@0 6 #include "nsTableRowGroupFrame.h"
michael@0 7 #include "nsIPresShell.h"
michael@0 8 #include "nsPresContext.h"
michael@0 9 #include "nsStyleContext.h"
michael@0 10 #include "nsStyleConsts.h"
michael@0 11 #include "nsGkAtoms.h"
michael@0 12 #include "nsIContent.h"
michael@0 13 #include "nsTableFrame.h"
michael@0 14 #include "nsTableCellFrame.h"
michael@0 15 #include "nsCSSRendering.h"
michael@0 16 #include "nsHTMLParts.h"
michael@0 17 #include "nsTableColGroupFrame.h"
michael@0 18 #include "nsTableColFrame.h"
michael@0 19 #include "nsCOMPtr.h"
michael@0 20 #include "nsDisplayList.h"
michael@0 21 #include "nsIFrameInlines.h"
michael@0 22 #include <algorithm>
michael@0 23
michael@0 24 using namespace mozilla;
michael@0 25
michael@0 26 struct nsTableCellReflowState : public nsHTMLReflowState
michael@0 27 {
michael@0 28 nsTableCellReflowState(nsPresContext* aPresContext,
michael@0 29 const nsHTMLReflowState& aParentReflowState,
michael@0 30 nsIFrame* aFrame,
michael@0 31 const nsSize& aAvailableSpace,
michael@0 32 uint32_t aFlags = 0)
michael@0 33 : nsHTMLReflowState(aPresContext, aParentReflowState, aFrame,
michael@0 34 aAvailableSpace, -1, -1, aFlags)
michael@0 35 {
michael@0 36 }
michael@0 37
michael@0 38 void FixUp(const nsSize& aAvailSpace);
michael@0 39 };
michael@0 40
michael@0 41 void nsTableCellReflowState::FixUp(const nsSize& aAvailSpace)
michael@0 42 {
michael@0 43 // fix the mComputed values during a pass 2 reflow since the cell can be a percentage base
michael@0 44 NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != aAvailSpace.width,
michael@0 45 "have unconstrained width; this should only result from "
michael@0 46 "very large sizes, not attempts at intrinsic width "
michael@0 47 "calculation");
michael@0 48 if (NS_UNCONSTRAINEDSIZE != ComputedWidth()) {
michael@0 49 nscoord computedWidth =
michael@0 50 aAvailSpace.width - mComputedBorderPadding.LeftRight();
michael@0 51 computedWidth = std::max(0, computedWidth);
michael@0 52 SetComputedWidth(computedWidth);
michael@0 53 }
michael@0 54 if (NS_UNCONSTRAINEDSIZE != ComputedHeight() &&
michael@0 55 NS_UNCONSTRAINEDSIZE != aAvailSpace.height) {
michael@0 56 nscoord computedHeight =
michael@0 57 aAvailSpace.height - mComputedBorderPadding.TopBottom();
michael@0 58 computedHeight = std::max(0, computedHeight);
michael@0 59 SetComputedHeight(computedHeight);
michael@0 60 }
michael@0 61 }
michael@0 62
michael@0 63 void
michael@0 64 nsTableRowFrame::InitChildReflowState(nsPresContext& aPresContext,
michael@0 65 const nsSize& aAvailSize,
michael@0 66 bool aBorderCollapse,
michael@0 67 nsTableCellReflowState& aReflowState)
michael@0 68 {
michael@0 69 nsMargin collapseBorder;
michael@0 70 nsMargin* pCollapseBorder = nullptr;
michael@0 71 if (aBorderCollapse) {
michael@0 72 // we only reflow cells, so don't need to check frame type
michael@0 73 nsBCTableCellFrame* bcCellFrame = (nsBCTableCellFrame*)aReflowState.frame;
michael@0 74 if (bcCellFrame) {
michael@0 75 pCollapseBorder = bcCellFrame->GetBorderWidth(collapseBorder);
michael@0 76 }
michael@0 77 }
michael@0 78 aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder);
michael@0 79 aReflowState.FixUp(aAvailSize);
michael@0 80 }
michael@0 81
michael@0 82 void
michael@0 83 nsTableRowFrame::SetFixedHeight(nscoord aValue)
michael@0 84 {
michael@0 85 nscoord height = std::max(0, aValue);
michael@0 86 if (HasFixedHeight()) {
michael@0 87 if (height > mStyleFixedHeight) {
michael@0 88 mStyleFixedHeight = height;
michael@0 89 }
michael@0 90 }
michael@0 91 else {
michael@0 92 mStyleFixedHeight = height;
michael@0 93 if (height > 0) {
michael@0 94 SetHasFixedHeight(true);
michael@0 95 }
michael@0 96 }
michael@0 97 }
michael@0 98
michael@0 99 void
michael@0 100 nsTableRowFrame::SetPctHeight(float aPctValue,
michael@0 101 bool aForce)
michael@0 102 {
michael@0 103 nscoord height = std::max(0, NSToCoordRound(aPctValue * 100.0f));
michael@0 104 if (HasPctHeight()) {
michael@0 105 if ((height > mStylePctHeight) || aForce) {
michael@0 106 mStylePctHeight = height;
michael@0 107 }
michael@0 108 }
michael@0 109 else {
michael@0 110 mStylePctHeight = height;
michael@0 111 if (height > 0) {
michael@0 112 SetHasPctHeight(true);
michael@0 113 }
michael@0 114 }
michael@0 115 }
michael@0 116
michael@0 117 /* ----------- nsTableRowFrame ---------- */
michael@0 118
michael@0 119 NS_QUERYFRAME_HEAD(nsTableRowFrame)
michael@0 120 NS_QUERYFRAME_ENTRY(nsTableRowFrame)
michael@0 121 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
michael@0 122
michael@0 123 nsTableRowFrame::nsTableRowFrame(nsStyleContext* aContext)
michael@0 124 : nsContainerFrame(aContext)
michael@0 125 {
michael@0 126 mBits.mRowIndex = mBits.mFirstInserted = 0;
michael@0 127 ResetHeight(0);
michael@0 128 }
michael@0 129
michael@0 130 nsTableRowFrame::~nsTableRowFrame()
michael@0 131 {
michael@0 132 }
michael@0 133
michael@0 134 void
michael@0 135 nsTableRowFrame::Init(nsIContent* aContent,
michael@0 136 nsIFrame* aParent,
michael@0 137 nsIFrame* aPrevInFlow)
michael@0 138 {
michael@0 139 // Let the base class do its initialization
michael@0 140 nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
michael@0 141
michael@0 142 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW == StyleDisplay()->mDisplay,
michael@0 143 "wrong display on table row frame");
michael@0 144
michael@0 145 if (aPrevInFlow) {
michael@0 146 // Set the row index
michael@0 147 nsTableRowFrame* rowFrame = (nsTableRowFrame*)aPrevInFlow;
michael@0 148
michael@0 149 SetRowIndex(rowFrame->GetRowIndex());
michael@0 150 }
michael@0 151 }
michael@0 152
michael@0 153 void
michael@0 154 nsTableRowFrame::DestroyFrom(nsIFrame* aDestructRoot)
michael@0 155 {
michael@0 156 if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
michael@0 157 nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot);
michael@0 158 }
michael@0 159
michael@0 160 nsContainerFrame::DestroyFrom(aDestructRoot);
michael@0 161 }
michael@0 162
michael@0 163 /* virtual */ void
michael@0 164 nsTableRowFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
michael@0 165 {
michael@0 166 nsContainerFrame::DidSetStyleContext(aOldStyleContext);
michael@0 167
michael@0 168 if (!aOldStyleContext) //avoid this on init
michael@0 169 return;
michael@0 170
michael@0 171 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
michael@0 172 if (tableFrame->IsBorderCollapse() &&
michael@0 173 tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
michael@0 174 nsIntRect damageArea(0, GetRowIndex(), tableFrame->GetColCount(), 1);
michael@0 175 tableFrame->AddBCDamageArea(damageArea);
michael@0 176 }
michael@0 177 }
michael@0 178
michael@0 179 nsresult
michael@0 180 nsTableRowFrame::AppendFrames(ChildListID aListID,
michael@0 181 nsFrameList& aFrameList)
michael@0 182 {
michael@0 183 NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
michael@0 184
michael@0 185 const nsFrameList::Slice& newCells = mFrames.AppendFrames(nullptr, aFrameList);
michael@0 186
michael@0 187 // Add the new cell frames to the table
michael@0 188 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
michael@0 189 for (nsFrameList::Enumerator e(newCells) ; !e.AtEnd(); e.Next()) {
michael@0 190 nsIFrame *childFrame = e.get();
michael@0 191 NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure");
michael@0 192 tableFrame->AppendCell(static_cast<nsTableCellFrame&>(*childFrame), GetRowIndex());
michael@0 193 }
michael@0 194
michael@0 195 PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
michael@0 196 NS_FRAME_HAS_DIRTY_CHILDREN);
michael@0 197 tableFrame->SetGeometryDirty();
michael@0 198
michael@0 199 return NS_OK;
michael@0 200 }
michael@0 201
michael@0 202
michael@0 203 nsresult
michael@0 204 nsTableRowFrame::InsertFrames(ChildListID aListID,
michael@0 205 nsIFrame* aPrevFrame,
michael@0 206 nsFrameList& aFrameList)
michael@0 207 {
michael@0 208 NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
michael@0 209 NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
michael@0 210 "inserting after sibling frame with different parent");
michael@0 211 //Insert Frames in the frame list
michael@0 212 const nsFrameList::Slice& newCells = mFrames.InsertFrames(nullptr, aPrevFrame, aFrameList);
michael@0 213
michael@0 214 // Get the table frame
michael@0 215 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
michael@0 216 nsIAtom* cellFrameType = tableFrame->IsBorderCollapse() ? nsGkAtoms::bcTableCellFrame : nsGkAtoms::tableCellFrame;
michael@0 217 nsTableCellFrame* prevCellFrame = (nsTableCellFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, cellFrameType);
michael@0 218 nsTArray<nsTableCellFrame*> cellChildren;
michael@0 219 for (nsFrameList::Enumerator e(newCells); !e.AtEnd(); e.Next()) {
michael@0 220 nsIFrame *childFrame = e.get();
michael@0 221 NS_ASSERTION(IS_TABLE_CELL(childFrame->GetType()),"Not a table cell frame/pseudo frame construction failure");
michael@0 222 cellChildren.AppendElement(static_cast<nsTableCellFrame*>(childFrame));
michael@0 223 }
michael@0 224 // insert the cells into the cell map
michael@0 225 int32_t colIndex = -1;
michael@0 226 if (prevCellFrame) {
michael@0 227 prevCellFrame->GetColIndex(colIndex);
michael@0 228 }
michael@0 229 tableFrame->InsertCells(cellChildren, GetRowIndex(), colIndex);
michael@0 230
michael@0 231 PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
michael@0 232 NS_FRAME_HAS_DIRTY_CHILDREN);
michael@0 233 tableFrame->SetGeometryDirty();
michael@0 234
michael@0 235 return NS_OK;
michael@0 236 }
michael@0 237
michael@0 238 nsresult
michael@0 239 nsTableRowFrame::RemoveFrame(ChildListID aListID,
michael@0 240 nsIFrame* aOldFrame)
michael@0 241 {
michael@0 242 NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
michael@0 243
michael@0 244 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
michael@0 245 nsTableCellFrame *cellFrame = do_QueryFrame(aOldFrame);
michael@0 246 if (cellFrame) {
michael@0 247 int32_t colIndex;
michael@0 248 cellFrame->GetColIndex(colIndex);
michael@0 249 // remove the cell from the cell map
michael@0 250 tableFrame->RemoveCell(cellFrame, GetRowIndex());
michael@0 251
michael@0 252 // Remove the frame and destroy it
michael@0 253 mFrames.DestroyFrame(aOldFrame);
michael@0 254
michael@0 255 PresContext()->PresShell()->
michael@0 256 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
michael@0 257 NS_FRAME_HAS_DIRTY_CHILDREN);
michael@0 258 tableFrame->SetGeometryDirty();
michael@0 259 }
michael@0 260 else {
michael@0 261 NS_ERROR("unexpected frame type");
michael@0 262 return NS_ERROR_INVALID_ARG;
michael@0 263 }
michael@0 264
michael@0 265 return NS_OK;
michael@0 266 }
michael@0 267
michael@0 268 /* virtual */ nsMargin
michael@0 269 nsTableRowFrame::GetUsedMargin() const
michael@0 270 {
michael@0 271 return nsMargin(0,0,0,0);
michael@0 272 }
michael@0 273
michael@0 274 /* virtual */ nsMargin
michael@0 275 nsTableRowFrame::GetUsedBorder() const
michael@0 276 {
michael@0 277 return nsMargin(0,0,0,0);
michael@0 278 }
michael@0 279
michael@0 280 /* virtual */ nsMargin
michael@0 281 nsTableRowFrame::GetUsedPadding() const
michael@0 282 {
michael@0 283 return nsMargin(0,0,0,0);
michael@0 284 }
michael@0 285
michael@0 286 nscoord
michael@0 287 GetHeightOfRowsSpannedBelowFirst(nsTableCellFrame& aTableCellFrame,
michael@0 288 nsTableFrame& aTableFrame)
michael@0 289 {
michael@0 290 nscoord height = 0;
michael@0 291 nscoord cellSpacingY = aTableFrame.GetCellSpacingY();
michael@0 292 int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(aTableCellFrame);
michael@0 293 // add in height of rows spanned beyond the 1st one
michael@0 294 nsIFrame* nextRow = aTableCellFrame.GetParent()->GetNextSibling();
michael@0 295 for (int32_t rowX = 1; ((rowX < rowSpan) && nextRow);) {
michael@0 296 if (nsGkAtoms::tableRowFrame == nextRow->GetType()) {
michael@0 297 height += nextRow->GetSize().height;
michael@0 298 rowX++;
michael@0 299 }
michael@0 300 height += cellSpacingY;
michael@0 301 nextRow = nextRow->GetNextSibling();
michael@0 302 }
michael@0 303 return height;
michael@0 304 }
michael@0 305
michael@0 306 nsTableCellFrame*
michael@0 307 nsTableRowFrame::GetFirstCell()
michael@0 308 {
michael@0 309 nsIFrame* childFrame = mFrames.FirstChild();
michael@0 310 while (childFrame) {
michael@0 311 nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
michael@0 312 if (cellFrame) {
michael@0 313 return cellFrame;
michael@0 314 }
michael@0 315 childFrame = childFrame->GetNextSibling();
michael@0 316 }
michael@0 317 return nullptr;
michael@0 318 }
michael@0 319
michael@0 320 /**
michael@0 321 * Post-reflow hook. This is where the table row does its post-processing
michael@0 322 */
michael@0 323 void
michael@0 324 nsTableRowFrame::DidResize()
michael@0 325 {
michael@0 326 // Resize and re-align the cell frames based on our row height
michael@0 327 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
michael@0 328 nsTableIterator iter(*this);
michael@0 329 nsIFrame* childFrame = iter.First();
michael@0 330
michael@0 331 nsHTMLReflowMetrics desiredSize(GetWritingMode()); // ???
michael@0 332 desiredSize.Width() = mRect.width;
michael@0 333 desiredSize.Height() = mRect.height;
michael@0 334 desiredSize.SetOverflowAreasToDesiredBounds();
michael@0 335
michael@0 336 while (childFrame) {
michael@0 337 nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
michael@0 338 if (cellFrame) {
michael@0 339 nscoord cellHeight = mRect.height + GetHeightOfRowsSpannedBelowFirst(*cellFrame, *tableFrame);
michael@0 340
michael@0 341 // resize the cell's height
michael@0 342 nsRect cellRect = cellFrame->GetRect();
michael@0 343 nsRect cellVisualOverflow = cellFrame->GetVisualOverflowRect();
michael@0 344 if (cellRect.height != cellHeight)
michael@0 345 {
michael@0 346 cellFrame->SetSize(nsSize(cellRect.width, cellHeight));
michael@0 347 nsTableFrame::InvalidateTableFrame(cellFrame, cellRect,
michael@0 348 cellVisualOverflow,
michael@0 349 false);
michael@0 350 }
michael@0 351
michael@0 352 // realign cell content based on the new height. We might be able to
michael@0 353 // skip this if the height didn't change... maybe. Hard to tell.
michael@0 354 cellFrame->VerticallyAlignChild(mMaxCellAscent);
michael@0 355
michael@0 356 // Always store the overflow, even if the height didn't change, since
michael@0 357 // we'll lose part of our overflow area otherwise.
michael@0 358 ConsiderChildOverflow(desiredSize.mOverflowAreas, cellFrame);
michael@0 359
michael@0 360 // Note that if the cell's *content* needs to change in response
michael@0 361 // to this height, it will get a special height reflow.
michael@0 362 }
michael@0 363 // Get the next child
michael@0 364 childFrame = iter.Next();
michael@0 365 }
michael@0 366 FinishAndStoreOverflow(&desiredSize);
michael@0 367 if (HasView()) {
michael@0 368 nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, GetView(),
michael@0 369 desiredSize.VisualOverflow(), 0);
michael@0 370 }
michael@0 371 // Let our base class do the usual work
michael@0 372 }
michael@0 373
michael@0 374 // returns max-ascent amongst all cells that have 'vertical-align: baseline'
michael@0 375 // *including* cells with rowspans
michael@0 376 nscoord nsTableRowFrame::GetMaxCellAscent() const
michael@0 377 {
michael@0 378 return mMaxCellAscent;
michael@0 379 }
michael@0 380
michael@0 381 nscoord nsTableRowFrame::GetRowBaseline()
michael@0 382 {
michael@0 383 if(mMaxCellAscent)
michael@0 384 return mMaxCellAscent;
michael@0 385
michael@0 386 // If we don't have a baseline on any of the cells we go for the lowest
michael@0 387 // content edge of the inner block frames.
michael@0 388 // Every table cell has a cell frame with its border and padding. Inside
michael@0 389 // the cell is a block frame. The cell is as high as the tallest cell in
michael@0 390 // the parent row. As a consequence the block frame might not touch both
michael@0 391 // the top and the bottom padding of it parent cell frame at the same time.
michael@0 392 //
michael@0 393 // bbbbbbbbbbbbbbbbbb cell border: b
michael@0 394 // bppppppppppppppppb cell padding: p
michael@0 395 // bpxxxxxxxxxxxxxxpb inner block: x
michael@0 396 // bpx xpb
michael@0 397 // bpx xpb
michael@0 398 // bpx xpb
michael@0 399 // bpxxxxxxxxxxxxxxpb base line
michael@0 400 // bp pb
michael@0 401 // bp pb
michael@0 402 // bppppppppppppppppb
michael@0 403 // bbbbbbbbbbbbbbbbbb
michael@0 404
michael@0 405 nsTableIterator iter(*this);
michael@0 406 nsIFrame* childFrame = iter.First();
michael@0 407 nscoord ascent = 0;
michael@0 408 while (childFrame) {
michael@0 409 if (IS_TABLE_CELL(childFrame->GetType())) {
michael@0 410 nsIFrame* firstKid = childFrame->GetFirstPrincipalChild();
michael@0 411 ascent = std::max(ascent, firstKid->GetRect().YMost());
michael@0 412 }
michael@0 413 // Get the next child
michael@0 414 childFrame = iter.Next();
michael@0 415 }
michael@0 416 return ascent;
michael@0 417 }
michael@0 418 nscoord
michael@0 419 nsTableRowFrame::GetHeight(nscoord aPctBasis) const
michael@0 420 {
michael@0 421 nscoord height = 0;
michael@0 422 if ((aPctBasis > 0) && HasPctHeight()) {
michael@0 423 height = NSToCoordRound(GetPctHeight() * (float)aPctBasis);
michael@0 424 }
michael@0 425 if (HasFixedHeight()) {
michael@0 426 height = std::max(height, GetFixedHeight());
michael@0 427 }
michael@0 428 return std::max(height, GetContentHeight());
michael@0 429 }
michael@0 430
michael@0 431 void
michael@0 432 nsTableRowFrame::ResetHeight(nscoord aFixedHeight)
michael@0 433 {
michael@0 434 SetHasFixedHeight(false);
michael@0 435 SetHasPctHeight(false);
michael@0 436 SetFixedHeight(0);
michael@0 437 SetPctHeight(0);
michael@0 438 SetContentHeight(0);
michael@0 439
michael@0 440 if (aFixedHeight > 0) {
michael@0 441 SetFixedHeight(aFixedHeight);
michael@0 442 }
michael@0 443
michael@0 444 mMaxCellAscent = 0;
michael@0 445 mMaxCellDescent = 0;
michael@0 446 }
michael@0 447
michael@0 448 void
michael@0 449 nsTableRowFrame::UpdateHeight(nscoord aHeight,
michael@0 450 nscoord aAscent,
michael@0 451 nscoord aDescent,
michael@0 452 nsTableFrame* aTableFrame,
michael@0 453 nsTableCellFrame* aCellFrame)
michael@0 454 {
michael@0 455 if (!aTableFrame || !aCellFrame) {
michael@0 456 NS_ASSERTION(false , "invalid call");
michael@0 457 return;
michael@0 458 }
michael@0 459
michael@0 460 if (aHeight != NS_UNCONSTRAINEDSIZE) {
michael@0 461 if (!(aCellFrame->HasVerticalAlignBaseline())) { // only the cell's height matters
michael@0 462 if (GetHeight() < aHeight) {
michael@0 463 int32_t rowSpan = aTableFrame->GetEffectiveRowSpan(*aCellFrame);
michael@0 464 if (rowSpan == 1) {
michael@0 465 SetContentHeight(aHeight);
michael@0 466 }
michael@0 467 }
michael@0 468 }
michael@0 469 else { // the alignment on the baseline can change the height
michael@0 470 NS_ASSERTION((aAscent != NS_UNCONSTRAINEDSIZE) && (aDescent != NS_UNCONSTRAINEDSIZE), "invalid call");
michael@0 471 // see if this is a long ascender
michael@0 472 if (mMaxCellAscent < aAscent) {
michael@0 473 mMaxCellAscent = aAscent;
michael@0 474 }
michael@0 475 // see if this is a long descender and without rowspan
michael@0 476 if (mMaxCellDescent < aDescent) {
michael@0 477 int32_t rowSpan = aTableFrame->GetEffectiveRowSpan(*aCellFrame);
michael@0 478 if (rowSpan == 1) {
michael@0 479 mMaxCellDescent = aDescent;
michael@0 480 }
michael@0 481 }
michael@0 482 // keep the tallest height in sync
michael@0 483 if (GetHeight() < mMaxCellAscent + mMaxCellDescent) {
michael@0 484 SetContentHeight(mMaxCellAscent + mMaxCellDescent);
michael@0 485 }
michael@0 486 }
michael@0 487 }
michael@0 488 }
michael@0 489
michael@0 490 nscoord
michael@0 491 nsTableRowFrame::CalcHeight(const nsHTMLReflowState& aReflowState)
michael@0 492 {
michael@0 493 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
michael@0 494 nscoord computedHeight = (NS_UNCONSTRAINEDSIZE == aReflowState.ComputedHeight())
michael@0 495 ? 0 : aReflowState.ComputedHeight();
michael@0 496 ResetHeight(computedHeight);
michael@0 497
michael@0 498 const nsStylePosition* position = StylePosition();
michael@0 499 if (position->mHeight.ConvertsToLength()) {
michael@0 500 SetFixedHeight(nsRuleNode::ComputeCoordPercentCalc(position->mHeight, 0));
michael@0 501 }
michael@0 502 else if (eStyleUnit_Percent == position->mHeight.GetUnit()) {
michael@0 503 SetPctHeight(position->mHeight.GetPercentValue());
michael@0 504 }
michael@0 505 // calc() with percentages is treated like 'auto' on table rows.
michael@0 506
michael@0 507 for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame;
michael@0 508 kidFrame = kidFrame->GetNextSibling()) {
michael@0 509 nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
michael@0 510 if (cellFrame) {
michael@0 511 nsSize desSize = cellFrame->GetDesiredSize();
michael@0 512 if ((NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) && !GetPrevInFlow()) {
michael@0 513 CalculateCellActualHeight(cellFrame, desSize.height);
michael@0 514 }
michael@0 515 // height may have changed, adjust descent to absorb any excess difference
michael@0 516 nscoord ascent;
michael@0 517 if (!kidFrame->GetFirstPrincipalChild()->GetFirstPrincipalChild())
michael@0 518 ascent = desSize.height;
michael@0 519 else
michael@0 520 ascent = cellFrame->GetCellBaseline();
michael@0 521 nscoord descent = desSize.height - ascent;
michael@0 522 UpdateHeight(desSize.height, ascent, descent, tableFrame, cellFrame);
michael@0 523 }
michael@0 524 }
michael@0 525 return GetHeight();
michael@0 526 }
michael@0 527
michael@0 528 /**
michael@0 529 * We need a custom display item for table row backgrounds. This is only used
michael@0 530 * when the table row is the root of a stacking context (e.g., has 'opacity').
michael@0 531 * Table row backgrounds can extend beyond the row frame bounds, when
michael@0 532 * the row contains row-spanning cells.
michael@0 533 */
michael@0 534 class nsDisplayTableRowBackground : public nsDisplayTableItem {
michael@0 535 public:
michael@0 536 nsDisplayTableRowBackground(nsDisplayListBuilder* aBuilder,
michael@0 537 nsTableRowFrame* aFrame) :
michael@0 538 nsDisplayTableItem(aBuilder, aFrame) {
michael@0 539 MOZ_COUNT_CTOR(nsDisplayTableRowBackground);
michael@0 540 }
michael@0 541 #ifdef NS_BUILD_REFCNT_LOGGING
michael@0 542 virtual ~nsDisplayTableRowBackground() {
michael@0 543 MOZ_COUNT_DTOR(nsDisplayTableRowBackground);
michael@0 544 }
michael@0 545 #endif
michael@0 546
michael@0 547 virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
michael@0 548 const nsDisplayItemGeometry* aGeometry,
michael@0 549 nsRegion *aInvalidRegion) MOZ_OVERRIDE;
michael@0 550 virtual void Paint(nsDisplayListBuilder* aBuilder,
michael@0 551 nsRenderingContext* aCtx) MOZ_OVERRIDE;
michael@0 552 NS_DISPLAY_DECL_NAME("TableRowBackground", TYPE_TABLE_ROW_BACKGROUND)
michael@0 553 };
michael@0 554
michael@0 555 void
michael@0 556 nsDisplayTableRowBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
michael@0 557 const nsDisplayItemGeometry* aGeometry,
michael@0 558 nsRegion *aInvalidRegion)
michael@0 559 {
michael@0 560 if (aBuilder->ShouldSyncDecodeImages()) {
michael@0 561 if (nsTableFrame::AnyTablePartHasUndecodedBackgroundImage(mFrame, mFrame->GetNextSibling())) {
michael@0 562 bool snap;
michael@0 563 aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
michael@0 564 }
michael@0 565 }
michael@0 566
michael@0 567 nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
michael@0 568 }
michael@0 569
michael@0 570 void
michael@0 571 nsDisplayTableRowBackground::Paint(nsDisplayListBuilder* aBuilder,
michael@0 572 nsRenderingContext* aCtx)
michael@0 573 {
michael@0 574 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(mFrame);
michael@0 575 TableBackgroundPainter painter(tableFrame,
michael@0 576 TableBackgroundPainter::eOrigin_TableRow,
michael@0 577 mFrame->PresContext(), *aCtx,
michael@0 578 mVisibleRect, ToReferenceFrame(),
michael@0 579 aBuilder->GetBackgroundPaintFlags());
michael@0 580 painter.PaintRow(static_cast<nsTableRowFrame*>(mFrame));
michael@0 581 }
michael@0 582
michael@0 583 void
michael@0 584 nsTableRowFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
michael@0 585 const nsRect& aDirtyRect,
michael@0 586 const nsDisplayListSet& aLists)
michael@0 587 {
michael@0 588 nsDisplayTableItem* item = nullptr;
michael@0 589 if (IsVisibleInSelection(aBuilder)) {
michael@0 590 bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
michael@0 591 if (isRoot) {
michael@0 592 // This background is created regardless of whether this frame is
michael@0 593 // visible or not. Visibility decisions are delegated to the
michael@0 594 // table background painter.
michael@0 595 // We would use nsDisplayGeneric for this rare case except that we
michael@0 596 // need the background to be larger than the row frame in some
michael@0 597 // cases.
michael@0 598 item = new (aBuilder) nsDisplayTableRowBackground(aBuilder, this);
michael@0 599 aLists.BorderBackground()->AppendNewToTop(item);
michael@0 600 }
michael@0 601 }
michael@0 602 nsTableFrame::DisplayGenericTablePart(aBuilder, this, aDirtyRect, aLists, item);
michael@0 603 }
michael@0 604
michael@0 605 int
michael@0 606 nsTableRowFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
michael@0 607 {
michael@0 608 int skip = 0;
michael@0 609 if (nullptr != GetPrevInFlow()) {
michael@0 610 skip |= LOGICAL_SIDE_B_START;
michael@0 611 }
michael@0 612 if (nullptr != GetNextInFlow()) {
michael@0 613 skip |= LOGICAL_SIDE_B_END;
michael@0 614 }
michael@0 615 return skip;
michael@0 616 }
michael@0 617
michael@0 618 // Calculate the cell's actual height given its pass2 height.
michael@0 619 // Takes into account the specified height (in the style).
michael@0 620 // Modifies the desired height that is passed in.
michael@0 621 nsresult
michael@0 622 nsTableRowFrame::CalculateCellActualHeight(nsTableCellFrame* aCellFrame,
michael@0 623 nscoord& aDesiredHeight)
michael@0 624 {
michael@0 625 nscoord specifiedHeight = 0;
michael@0 626
michael@0 627 // Get the height specified in the style information
michael@0 628 const nsStylePosition* position = aCellFrame->StylePosition();
michael@0 629
michael@0 630 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
michael@0 631 int32_t rowSpan = tableFrame->GetEffectiveRowSpan(*aCellFrame);
michael@0 632
michael@0 633 switch (position->mHeight.GetUnit()) {
michael@0 634 case eStyleUnit_Calc: {
michael@0 635 if (position->mHeight.CalcHasPercent()) {
michael@0 636 // Treat this like "auto"
michael@0 637 break;
michael@0 638 }
michael@0 639 // Fall through to the coord case
michael@0 640 }
michael@0 641 case eStyleUnit_Coord: {
michael@0 642 nscoord outsideBoxSizing = 0;
michael@0 643 // In quirks mode, table cell width should be content-box, but height
michael@0 644 // should be border-box.
michael@0 645 // Because of this historic anomaly, we do not use quirk.css
michael@0 646 // (since we can't specify one value of box-sizing for width and another
michael@0 647 // for height)
michael@0 648 if (PresContext()->CompatibilityMode() != eCompatibility_NavQuirks) {
michael@0 649 switch (position->mBoxSizing) {
michael@0 650 case NS_STYLE_BOX_SIZING_CONTENT:
michael@0 651 outsideBoxSizing = aCellFrame->GetUsedBorderAndPadding().TopBottom();
michael@0 652 break;
michael@0 653 case NS_STYLE_BOX_SIZING_PADDING:
michael@0 654 outsideBoxSizing = aCellFrame->GetUsedBorder().TopBottom();
michael@0 655 break;
michael@0 656 default:
michael@0 657 // NS_STYLE_BOX_SIZING_BORDER
michael@0 658 break;
michael@0 659 }
michael@0 660 }
michael@0 661
michael@0 662 specifiedHeight =
michael@0 663 nsRuleNode::ComputeCoordPercentCalc(position->mHeight, 0) +
michael@0 664 outsideBoxSizing;
michael@0 665
michael@0 666 if (1 == rowSpan)
michael@0 667 SetFixedHeight(specifiedHeight);
michael@0 668 break;
michael@0 669 }
michael@0 670 case eStyleUnit_Percent: {
michael@0 671 if (1 == rowSpan)
michael@0 672 SetPctHeight(position->mHeight.GetPercentValue());
michael@0 673 // pct heights are handled when all of the cells are finished, so don't set specifiedHeight
michael@0 674 break;
michael@0 675 }
michael@0 676 case eStyleUnit_Auto:
michael@0 677 default:
michael@0 678 break;
michael@0 679 }
michael@0 680
michael@0 681 // If the specified height is greater than the desired height, then use the specified height
michael@0 682 if (specifiedHeight > aDesiredHeight)
michael@0 683 aDesiredHeight = specifiedHeight;
michael@0 684
michael@0 685 return NS_OK;
michael@0 686 }
michael@0 687
michael@0 688 // Calculates the available width for the table cell based on the known
michael@0 689 // column widths taking into account column spans and column spacing
michael@0 690 static nscoord
michael@0 691 CalcAvailWidth(nsTableFrame& aTableFrame,
michael@0 692 nsTableCellFrame& aCellFrame,
michael@0 693 nscoord aCellSpacingX)
michael@0 694 {
michael@0 695 nscoord cellAvailWidth = 0;
michael@0 696 int32_t colIndex;
michael@0 697 aCellFrame.GetColIndex(colIndex);
michael@0 698 int32_t colspan = aTableFrame.GetEffectiveColSpan(aCellFrame);
michael@0 699 NS_ASSERTION(colspan > 0, "effective colspan should be positive");
michael@0 700
michael@0 701 for (int32_t spanX = 0; spanX < colspan; spanX++) {
michael@0 702 cellAvailWidth += aTableFrame.GetColumnWidth(colIndex + spanX);
michael@0 703 if (spanX > 0 &&
michael@0 704 aTableFrame.ColumnHasCellSpacingBefore(colIndex + spanX)) {
michael@0 705 cellAvailWidth += aCellSpacingX;
michael@0 706 }
michael@0 707 }
michael@0 708 return cellAvailWidth;
michael@0 709 }
michael@0 710
michael@0 711 nscoord
michael@0 712 GetSpaceBetween(int32_t aPrevColIndex,
michael@0 713 int32_t aColIndex,
michael@0 714 int32_t aColSpan,
michael@0 715 nsTableFrame& aTableFrame,
michael@0 716 nscoord aCellSpacingX,
michael@0 717 bool aIsLeftToRight,
michael@0 718 bool aCheckVisibility)
michael@0 719 {
michael@0 720 nscoord space = 0;
michael@0 721 int32_t colX;
michael@0 722 if (aIsLeftToRight) {
michael@0 723 for (colX = aPrevColIndex + 1; aColIndex > colX; colX++) {
michael@0 724 bool isCollapsed = false;
michael@0 725 if (!aCheckVisibility) {
michael@0 726 space += aTableFrame.GetColumnWidth(colX);
michael@0 727 }
michael@0 728 else {
michael@0 729 nsTableColFrame* colFrame = aTableFrame.GetColFrame(colX);
michael@0 730 const nsStyleVisibility* colVis = colFrame->StyleVisibility();
michael@0 731 bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible);
michael@0 732 nsIFrame* cgFrame = colFrame->GetParent();
michael@0 733 const nsStyleVisibility* groupVis = cgFrame->StyleVisibility();
michael@0 734 bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE ==
michael@0 735 groupVis->mVisible);
michael@0 736 isCollapsed = collapseCol || collapseGroup;
michael@0 737 if (!isCollapsed)
michael@0 738 space += aTableFrame.GetColumnWidth(colX);
michael@0 739 }
michael@0 740 if (!isCollapsed && aTableFrame.ColumnHasCellSpacingBefore(colX)) {
michael@0 741 space += aCellSpacingX;
michael@0 742 }
michael@0 743 }
michael@0 744 }
michael@0 745 else {
michael@0 746 int32_t lastCol = aColIndex + aColSpan - 1;
michael@0 747 for (colX = aPrevColIndex - 1; colX > lastCol; colX--) {
michael@0 748 bool isCollapsed = false;
michael@0 749 if (!aCheckVisibility) {
michael@0 750 space += aTableFrame.GetColumnWidth(colX);
michael@0 751 }
michael@0 752 else {
michael@0 753 nsTableColFrame* colFrame = aTableFrame.GetColFrame(colX);
michael@0 754 const nsStyleVisibility* colVis = colFrame->StyleVisibility();
michael@0 755 bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE == colVis->mVisible);
michael@0 756 nsIFrame* cgFrame = colFrame->GetParent();
michael@0 757 const nsStyleVisibility* groupVis = cgFrame->StyleVisibility();
michael@0 758 bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE ==
michael@0 759 groupVis->mVisible);
michael@0 760 isCollapsed = collapseCol || collapseGroup;
michael@0 761 if (!isCollapsed)
michael@0 762 space += aTableFrame.GetColumnWidth(colX);
michael@0 763 }
michael@0 764 if (!isCollapsed && aTableFrame.ColumnHasCellSpacingBefore(colX)) {
michael@0 765 space += aCellSpacingX;
michael@0 766 }
michael@0 767 }
michael@0 768 }
michael@0 769 return space;
michael@0 770 }
michael@0 771
michael@0 772 // subtract the heights of aRow's prev in flows from the unpaginated height
michael@0 773 static
michael@0 774 nscoord CalcHeightFromUnpaginatedHeight(nsPresContext* aPresContext,
michael@0 775 nsTableRowFrame& aRow)
michael@0 776 {
michael@0 777 nscoord height = 0;
michael@0 778 nsTableRowFrame* firstInFlow =
michael@0 779 static_cast<nsTableRowFrame*>(aRow.FirstInFlow());
michael@0 780 if (firstInFlow->HasUnpaginatedHeight()) {
michael@0 781 height = firstInFlow->GetUnpaginatedHeight(aPresContext);
michael@0 782 for (nsIFrame* prevInFlow = aRow.GetPrevInFlow(); prevInFlow;
michael@0 783 prevInFlow = prevInFlow->GetPrevInFlow()) {
michael@0 784 height -= prevInFlow->GetSize().height;
michael@0 785 }
michael@0 786 }
michael@0 787 return std::max(height, 0);
michael@0 788 }
michael@0 789
michael@0 790 nsresult
michael@0 791 nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext,
michael@0 792 nsHTMLReflowMetrics& aDesiredSize,
michael@0 793 const nsHTMLReflowState& aReflowState,
michael@0 794 nsTableFrame& aTableFrame,
michael@0 795 nsReflowStatus& aStatus)
michael@0 796 {
michael@0 797 aStatus = NS_FRAME_COMPLETE;
michael@0 798
michael@0 799 // XXXldb Should we be checking constrained height instead?
michael@0 800 const bool isPaginated = aPresContext->IsPaginated();
michael@0 801 const bool borderCollapse = aTableFrame.IsBorderCollapse();
michael@0 802 nsresult rv = NS_OK;
michael@0 803 nscoord cellSpacingX = aTableFrame.GetCellSpacingX();
michael@0 804 int32_t cellColSpan = 1; // must be defined here so it's set properly for non-cell kids
michael@0 805
michael@0 806 nsTableIterator iter(*this);
michael@0 807 // remember the col index of the previous cell to handle rowspans into this row
michael@0 808 int32_t firstPrevColIndex = (iter.IsLeftToRight()) ? -1 : aTableFrame.GetColCount();
michael@0 809 int32_t prevColIndex = firstPrevColIndex;
michael@0 810 nscoord x = 0; // running total of children x offset
michael@0 811
michael@0 812 // This computes the max of all cell heights
michael@0 813 nscoord cellMaxHeight = 0;
michael@0 814
michael@0 815 // Reflow each of our existing cell frames
michael@0 816 for (nsIFrame* kidFrame = iter.First(); kidFrame; kidFrame = iter.Next()) {
michael@0 817 nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
michael@0 818 if (!cellFrame) {
michael@0 819 // XXXldb nsCSSFrameConstructor needs to enforce this!
michael@0 820 NS_NOTREACHED("yikes, a non-row child");
michael@0 821
michael@0 822 // it's an unknown frame type, give it a generic reflow and ignore the results
michael@0 823 nsTableCellReflowState kidReflowState(aPresContext, aReflowState,
michael@0 824 kidFrame, nsSize(0,0),
michael@0 825 nsHTMLReflowState::CALLER_WILL_INIT);
michael@0 826 InitChildReflowState(*aPresContext, nsSize(0,0), false, kidReflowState);
michael@0 827 nsHTMLReflowMetrics desiredSize(aReflowState);
michael@0 828 nsReflowStatus status;
michael@0 829 ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, 0, 0, 0, status);
michael@0 830 kidFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
michael@0 831
michael@0 832 continue;
michael@0 833 }
michael@0 834
michael@0 835 // See if we should only reflow the dirty child frames
michael@0 836 bool doReflowChild = true;
michael@0 837 if (!aReflowState.ShouldReflowAllKids() &&
michael@0 838 !aTableFrame.IsGeometryDirty() &&
michael@0 839 !NS_SUBTREE_DIRTY(kidFrame)) {
michael@0 840 if (!aReflowState.mFlags.mSpecialHeightReflow)
michael@0 841 doReflowChild = false;
michael@0 842 }
michael@0 843 else if ((NS_UNCONSTRAINEDSIZE != aReflowState.AvailableHeight())) {
michael@0 844 // We don't reflow a rowspan >1 cell here with a constrained height.
michael@0 845 // That happens in nsTableRowGroupFrame::SplitSpanningCells.
michael@0 846 if (aTableFrame.GetEffectiveRowSpan(*cellFrame) > 1) {
michael@0 847 doReflowChild = false;
michael@0 848 }
michael@0 849 }
michael@0 850 if (aReflowState.mFlags.mSpecialHeightReflow) {
michael@0 851 if (!isPaginated && !(cellFrame->GetStateBits() &
michael@0 852 NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
michael@0 853 continue;
michael@0 854 }
michael@0 855 }
michael@0 856
michael@0 857 int32_t cellColIndex;
michael@0 858 cellFrame->GetColIndex(cellColIndex);
michael@0 859 cellColSpan = aTableFrame.GetEffectiveColSpan(*cellFrame);
michael@0 860
michael@0 861 // If the adjacent cell is in a prior row (because of a rowspan) add in the space
michael@0 862 if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) ||
michael@0 863 (!iter.IsLeftToRight() && (prevColIndex != cellColIndex + cellColSpan))) {
michael@0 864 x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan, aTableFrame,
michael@0 865 cellSpacingX, iter.IsLeftToRight(), false);
michael@0 866 }
michael@0 867
michael@0 868 // remember the rightmost (ltr) or leftmost (rtl) column this cell spans into
michael@0 869 prevColIndex = (iter.IsLeftToRight()) ? cellColIndex + (cellColSpan - 1) : cellColIndex;
michael@0 870
michael@0 871 // Reflow the child frame
michael@0 872 nsRect kidRect = kidFrame->GetRect();
michael@0 873 nsRect kidVisualOverflow = kidFrame->GetVisualOverflowRect();
michael@0 874 bool firstReflow =
michael@0 875 (kidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
michael@0 876
michael@0 877 if (doReflowChild) {
michael@0 878 // Calculate the available width for the table cell using the known column widths
michael@0 879 nscoord availCellWidth =
michael@0 880 CalcAvailWidth(aTableFrame, *cellFrame, cellSpacingX);
michael@0 881
michael@0 882 nsHTMLReflowMetrics desiredSize(aReflowState);
michael@0 883
michael@0 884 // If the avail width is not the same as last time we reflowed the cell or
michael@0 885 // the cell wants to be bigger than what was available last time or
michael@0 886 // it is a style change reflow or we are printing, then we must reflow the
michael@0 887 // cell. Otherwise we can skip the reflow.
michael@0 888 // XXXldb Why is this condition distinct from doReflowChild above?
michael@0 889 nsSize cellDesiredSize = cellFrame->GetDesiredSize();
michael@0 890 if ((availCellWidth != cellFrame->GetPriorAvailWidth()) ||
michael@0 891 (cellDesiredSize.width > cellFrame->GetPriorAvailWidth()) ||
michael@0 892 (GetStateBits() & NS_FRAME_IS_DIRTY) ||
michael@0 893 isPaginated ||
michael@0 894 NS_SUBTREE_DIRTY(cellFrame) ||
michael@0 895 // See if it needs a special reflow, or if it had one that we need to undo.
michael@0 896 (cellFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT) ||
michael@0 897 HasPctHeight()) {
michael@0 898 // Reflow the cell to fit the available width, height
michael@0 899 // XXX The old IR_ChildIsDirty code used availCellWidth here.
michael@0 900 nsSize kidAvailSize(availCellWidth, aReflowState.AvailableHeight());
michael@0 901
michael@0 902 // Reflow the child
michael@0 903 nsTableCellReflowState kidReflowState(aPresContext, aReflowState,
michael@0 904 kidFrame, kidAvailSize,
michael@0 905 nsHTMLReflowState::CALLER_WILL_INIT);
michael@0 906 InitChildReflowState(*aPresContext, kidAvailSize, borderCollapse,
michael@0 907 kidReflowState);
michael@0 908
michael@0 909 nsReflowStatus status;
michael@0 910 rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState,
michael@0 911 x, 0, 0, status);
michael@0 912
michael@0 913 // allow the table to determine if/how the table needs to be rebalanced
michael@0 914 // If any of the cells are not complete, then we're not complete
michael@0 915 if (NS_FRAME_IS_NOT_COMPLETE(status)) {
michael@0 916 aStatus = NS_FRAME_NOT_COMPLETE;
michael@0 917 }
michael@0 918 }
michael@0 919 else {
michael@0 920 if (x != kidRect.x) {
michael@0 921 kidFrame->InvalidateFrameSubtree();
michael@0 922 }
michael@0 923
michael@0 924 desiredSize.Width() = cellDesiredSize.width;
michael@0 925 desiredSize.Height() = cellDesiredSize.height;
michael@0 926 desiredSize.mOverflowAreas = cellFrame->GetOverflowAreas();
michael@0 927
michael@0 928 // if we are in a floated table, our position is not yet established, so we cannot reposition our views
michael@0 929 // the containing block will do this for us after positioning the table
michael@0 930 if (!aTableFrame.IsFloating()) {
michael@0 931 // Because we may have moved the frame we need to make sure any views are
michael@0 932 // positioned properly. We have to do this, because any one of our parent
michael@0 933 // frames could have moved and we have no way of knowing...
michael@0 934 nsTableFrame::RePositionViews(kidFrame);
michael@0 935 }
michael@0 936 }
michael@0 937
michael@0 938 if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) {
michael@0 939 if (!GetPrevInFlow()) {
michael@0 940 // Calculate the cell's actual height given its pass2 height. This
michael@0 941 // function takes into account the specified height (in the style)
michael@0 942 CalculateCellActualHeight(cellFrame, desiredSize.Height());
michael@0 943 }
michael@0 944 // height may have changed, adjust descent to absorb any excess difference
michael@0 945 nscoord ascent;
michael@0 946 if (!kidFrame->GetFirstPrincipalChild()->GetFirstPrincipalChild())
michael@0 947 ascent = desiredSize.Height();
michael@0 948 else
michael@0 949 ascent = ((nsTableCellFrame *)kidFrame)->GetCellBaseline();
michael@0 950 nscoord descent = desiredSize.Height() - ascent;
michael@0 951 UpdateHeight(desiredSize.Height(), ascent, descent, &aTableFrame, cellFrame);
michael@0 952 }
michael@0 953 else {
michael@0 954 cellMaxHeight = std::max(cellMaxHeight, desiredSize.Height());
michael@0 955 int32_t rowSpan = aTableFrame.GetEffectiveRowSpan((nsTableCellFrame&)*kidFrame);
michael@0 956 if (1 == rowSpan) {
michael@0 957 SetContentHeight(cellMaxHeight);
michael@0 958 }
michael@0 959 }
michael@0 960
michael@0 961 // Place the child
michael@0 962 desiredSize.Width() = availCellWidth;
michael@0 963
michael@0 964 FinishReflowChild(kidFrame, aPresContext, desiredSize, nullptr, x, 0, 0);
michael@0 965
michael@0 966 nsTableFrame::InvalidateTableFrame(kidFrame, kidRect, kidVisualOverflow,
michael@0 967 firstReflow);
michael@0 968
michael@0 969 x += desiredSize.Width();
michael@0 970 }
michael@0 971 else {
michael@0 972 if (kidRect.x != x) {
michael@0 973 // Invalidate the old position
michael@0 974 kidFrame->InvalidateFrameSubtree();
michael@0 975 // move to the new position
michael@0 976 kidFrame->SetPosition(nsPoint(x, kidRect.y));
michael@0 977 nsTableFrame::RePositionViews(kidFrame);
michael@0 978 // invalidate the new position
michael@0 979 kidFrame->InvalidateFrameSubtree();
michael@0 980 }
michael@0 981 // we need to account for the cell's width even if it isn't reflowed
michael@0 982 x += kidRect.width;
michael@0 983
michael@0 984 if (kidFrame->GetNextInFlow()) {
michael@0 985 aStatus = NS_FRAME_NOT_COMPLETE;
michael@0 986 }
michael@0 987 }
michael@0 988 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame);
michael@0 989 x += cellSpacingX;
michael@0 990 }
michael@0 991
michael@0 992 // just set our width to what was available. The table will calculate the width and not use our value.
michael@0 993 aDesiredSize.Width() = aReflowState.AvailableWidth();
michael@0 994
michael@0 995 if (aReflowState.mFlags.mSpecialHeightReflow) {
michael@0 996 aDesiredSize.Height() = mRect.height;
michael@0 997 }
michael@0 998 else if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) {
michael@0 999 aDesiredSize.Height() = CalcHeight(aReflowState);
michael@0 1000 if (GetPrevInFlow()) {
michael@0 1001 nscoord height = CalcHeightFromUnpaginatedHeight(aPresContext, *this);
michael@0 1002 aDesiredSize.Height() = std::max(aDesiredSize.Height(), height);
michael@0 1003 }
michael@0 1004 else {
michael@0 1005 if (isPaginated && HasStyleHeight()) {
michael@0 1006 // set the unpaginated height so next in flows can try to honor it
michael@0 1007 SetHasUnpaginatedHeight(true);
michael@0 1008 SetUnpaginatedHeight(aPresContext, aDesiredSize.Height());
michael@0 1009 }
michael@0 1010 if (isPaginated && HasUnpaginatedHeight()) {
michael@0 1011 aDesiredSize.Height() = std::max(aDesiredSize.Height(), GetUnpaginatedHeight(aPresContext));
michael@0 1012 }
michael@0 1013 }
michael@0 1014 }
michael@0 1015 else { // constrained height, paginated
michael@0 1016 // Compute the height we should have from style (subtracting the
michael@0 1017 // height from our prev-in-flows from the style height)
michael@0 1018 nscoord styleHeight = CalcHeightFromUnpaginatedHeight(aPresContext, *this);
michael@0 1019 if (styleHeight > aReflowState.AvailableHeight()) {
michael@0 1020 styleHeight = aReflowState.AvailableHeight();
michael@0 1021 NS_FRAME_SET_INCOMPLETE(aStatus);
michael@0 1022 }
michael@0 1023 aDesiredSize.Height() = std::max(cellMaxHeight, styleHeight);
michael@0 1024 }
michael@0 1025 aDesiredSize.UnionOverflowAreasWithDesiredBounds();
michael@0 1026 FinishAndStoreOverflow(&aDesiredSize);
michael@0 1027 return rv;
michael@0 1028 }
michael@0 1029
michael@0 1030 /** Layout the entire row.
michael@0 1031 * This method stacks cells horizontally according to HTML 4.0 rules.
michael@0 1032 */
michael@0 1033 nsresult
michael@0 1034 nsTableRowFrame::Reflow(nsPresContext* aPresContext,
michael@0 1035 nsHTMLReflowMetrics& aDesiredSize,
michael@0 1036 const nsHTMLReflowState& aReflowState,
michael@0 1037 nsReflowStatus& aStatus)
michael@0 1038 {
michael@0 1039 DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame");
michael@0 1040 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
michael@0 1041 nsresult rv = NS_OK;
michael@0 1042
michael@0 1043 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
michael@0 1044 const nsStyleVisibility* rowVis = StyleVisibility();
michael@0 1045 bool collapseRow = (NS_STYLE_VISIBILITY_COLLAPSE == rowVis->mVisible);
michael@0 1046 if (collapseRow) {
michael@0 1047 tableFrame->SetNeedToCollapse(true);
michael@0 1048 }
michael@0 1049
michael@0 1050 // see if a special height reflow needs to occur due to having a pct height
michael@0 1051 nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
michael@0 1052
michael@0 1053 // See if we have a cell with specified/pct height
michael@0 1054 InitHasCellWithStyleHeight(tableFrame);
michael@0 1055
michael@0 1056 rv = ReflowChildren(aPresContext, aDesiredSize, aReflowState, *tableFrame,
michael@0 1057 aStatus);
michael@0 1058
michael@0 1059 if (aPresContext->IsPaginated() && !NS_FRAME_IS_FULLY_COMPLETE(aStatus) &&
michael@0 1060 ShouldAvoidBreakInside(aReflowState)) {
michael@0 1061 aStatus = NS_INLINE_LINE_BREAK_BEFORE();
michael@0 1062 }
michael@0 1063
michael@0 1064 // just set our width to what was available. The table will calculate the width and not use our value.
michael@0 1065 aDesiredSize.Width() = aReflowState.AvailableWidth();
michael@0 1066
michael@0 1067 // If our parent is in initial reflow, it'll handle invalidating our
michael@0 1068 // entire overflow rect.
michael@0 1069 if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
michael@0 1070 nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
michael@0 1071 InvalidateFrame();
michael@0 1072 }
michael@0 1073
michael@0 1074 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
michael@0 1075 return rv;
michael@0 1076 }
michael@0 1077
michael@0 1078 /**
michael@0 1079 * This function is called by the row group frame's SplitRowGroup() code when
michael@0 1080 * pushing a row frame that has cell frames that span into it. The cell frame
michael@0 1081 * should be reflowed with the specified height
michael@0 1082 */
michael@0 1083 nscoord
michael@0 1084 nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext,
michael@0 1085 const nsHTMLReflowState& aReflowState,
michael@0 1086 bool aIsTopOfPage,
michael@0 1087 nsTableCellFrame* aCellFrame,
michael@0 1088 nscoord aAvailableHeight,
michael@0 1089 nsReflowStatus& aStatus)
michael@0 1090 {
michael@0 1091 // Reflow the cell frame with the specified height. Use the existing width
michael@0 1092 nsRect cellRect = aCellFrame->GetRect();
michael@0 1093 nsRect cellVisualOverflow = aCellFrame->GetVisualOverflowRect();
michael@0 1094
michael@0 1095 nsSize availSize(cellRect.width, aAvailableHeight);
michael@0 1096 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
michael@0 1097 bool borderCollapse = tableFrame->IsBorderCollapse();
michael@0 1098 nsTableCellReflowState cellReflowState(aPresContext, aReflowState,
michael@0 1099 aCellFrame, availSize,
michael@0 1100 nsHTMLReflowState::CALLER_WILL_INIT);
michael@0 1101 InitChildReflowState(*aPresContext, availSize, borderCollapse, cellReflowState);
michael@0 1102 cellReflowState.mFlags.mIsTopOfPage = aIsTopOfPage;
michael@0 1103
michael@0 1104 nsHTMLReflowMetrics desiredSize(aReflowState);
michael@0 1105
michael@0 1106 ReflowChild(aCellFrame, aPresContext, desiredSize, cellReflowState,
michael@0 1107 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
michael@0 1108 bool fullyComplete = NS_FRAME_IS_COMPLETE(aStatus) && !NS_FRAME_IS_TRUNCATED(aStatus);
michael@0 1109 if (fullyComplete) {
michael@0 1110 desiredSize.Height() = aAvailableHeight;
michael@0 1111 }
michael@0 1112 aCellFrame->SetSize(nsSize(cellRect.width, desiredSize.Height()));
michael@0 1113
michael@0 1114 // Note: VerticallyAlignChild can affect the overflow rect.
michael@0 1115 // XXX What happens if this cell has 'vertical-align: baseline' ?
michael@0 1116 // XXX Why is it assumed that the cell's ascent hasn't changed ?
michael@0 1117 if (fullyComplete) {
michael@0 1118 aCellFrame->VerticallyAlignChild(mMaxCellAscent);
michael@0 1119 }
michael@0 1120
michael@0 1121 nsTableFrame::InvalidateTableFrame(aCellFrame, cellRect,
michael@0 1122 cellVisualOverflow,
michael@0 1123 (aCellFrame->GetStateBits() &
michael@0 1124 NS_FRAME_FIRST_REFLOW) != 0);
michael@0 1125
michael@0 1126 aCellFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
michael@0 1127
michael@0 1128 return desiredSize.Height();
michael@0 1129 }
michael@0 1130
michael@0 1131 nscoord
michael@0 1132 nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset,
michael@0 1133 nscoord aWidth,
michael@0 1134 bool aCollapseGroup,
michael@0 1135 bool& aDidCollapse)
michael@0 1136 {
michael@0 1137 const nsStyleVisibility* rowVis = StyleVisibility();
michael@0 1138 bool collapseRow = (NS_STYLE_VISIBILITY_COLLAPSE == rowVis->mVisible);
michael@0 1139 nsTableFrame* tableFrame = static_cast<nsTableFrame*>(
michael@0 1140 nsTableFrame::GetTableFrame(this)->FirstInFlow());
michael@0 1141 if (collapseRow) {
michael@0 1142 tableFrame->SetNeedToCollapse(true);
michael@0 1143 }
michael@0 1144
michael@0 1145 if (aRowOffset != 0) {
michael@0 1146 // We're moving, so invalidate our old position
michael@0 1147 InvalidateFrameSubtree();
michael@0 1148 }
michael@0 1149
michael@0 1150 nsRect rowRect = GetRect();
michael@0 1151 nsRect oldRect = rowRect;
michael@0 1152 nsRect oldVisualOverflow = GetVisualOverflowRect();
michael@0 1153
michael@0 1154 rowRect.y -= aRowOffset;
michael@0 1155 rowRect.width = aWidth;
michael@0 1156 nsOverflowAreas overflow;
michael@0 1157 nscoord shift = 0;
michael@0 1158 nscoord cellSpacingX = tableFrame->GetCellSpacingX();
michael@0 1159 nscoord cellSpacingY = tableFrame->GetCellSpacingY();
michael@0 1160
michael@0 1161 if (aCollapseGroup || collapseRow) {
michael@0 1162 nsTableCellFrame* cellFrame = GetFirstCell();
michael@0 1163 aDidCollapse = true;
michael@0 1164 shift = rowRect.height + cellSpacingY;
michael@0 1165 while (cellFrame) {
michael@0 1166 nsRect cRect = cellFrame->GetRect();
michael@0 1167 // If aRowOffset != 0, there's no point in invalidating the cells, since
michael@0 1168 // we've already invalidated our overflow area. Note that we _do_ still
michael@0 1169 // need to invalidate if our row is not moving, because the cell might
michael@0 1170 // span out of this row, so invalidating our row rect won't do enough.
michael@0 1171 if (aRowOffset == 0) {
michael@0 1172 InvalidateFrame();
michael@0 1173 }
michael@0 1174 cRect.height = 0;
michael@0 1175 cellFrame->SetRect(cRect);
michael@0 1176 cellFrame = cellFrame->GetNextCell();
michael@0 1177 }
michael@0 1178 rowRect.height = 0;
michael@0 1179 }
michael@0 1180 else { // row is not collapsed
michael@0 1181 nsTableIterator iter(*this);
michael@0 1182 // remember the col index of the previous cell to handle rowspans into this
michael@0 1183 // row
michael@0 1184 int32_t firstPrevColIndex = (iter.IsLeftToRight()) ? -1 :
michael@0 1185 tableFrame->GetColCount();
michael@0 1186 int32_t prevColIndex = firstPrevColIndex;
michael@0 1187 nscoord x = 0; // running total of children x offset
michael@0 1188
michael@0 1189 int32_t colIncrement = iter.IsLeftToRight() ? 1 : -1;
michael@0 1190
michael@0 1191 //nscoord x = cellSpacingX;
michael@0 1192
michael@0 1193 nsIFrame* kidFrame = iter.First();
michael@0 1194 while (kidFrame) {
michael@0 1195 nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
michael@0 1196 if (cellFrame) {
michael@0 1197 int32_t cellColIndex;
michael@0 1198 cellFrame->GetColIndex(cellColIndex);
michael@0 1199 int32_t cellColSpan = tableFrame->GetEffectiveColSpan(*cellFrame);
michael@0 1200
michael@0 1201 // If the adjacent cell is in a prior row (because of a rowspan) add in
michael@0 1202 // the space
michael@0 1203 if ((iter.IsLeftToRight() && (prevColIndex != (cellColIndex - 1))) ||
michael@0 1204 (!iter.IsLeftToRight() &&
michael@0 1205 (prevColIndex != cellColIndex + cellColSpan))) {
michael@0 1206 x += GetSpaceBetween(prevColIndex, cellColIndex, cellColSpan,
michael@0 1207 *tableFrame, cellSpacingX, iter.IsLeftToRight(),
michael@0 1208 true);
michael@0 1209 }
michael@0 1210 nsRect cRect(x, 0, 0, rowRect.height);
michael@0 1211
michael@0 1212 // remember the rightmost (ltr) or leftmost (rtl) column this cell
michael@0 1213 // spans into
michael@0 1214 prevColIndex = (iter.IsLeftToRight()) ?
michael@0 1215 cellColIndex + (cellColSpan - 1) : cellColIndex;
michael@0 1216 int32_t startIndex = (iter.IsLeftToRight()) ?
michael@0 1217 cellColIndex : cellColIndex + (cellColSpan - 1);
michael@0 1218 int32_t actualColSpan = cellColSpan;
michael@0 1219 bool isVisible = false;
michael@0 1220 for (int32_t colX = startIndex; actualColSpan > 0;
michael@0 1221 colX += colIncrement, actualColSpan--) {
michael@0 1222
michael@0 1223 nsTableColFrame* colFrame = tableFrame->GetColFrame(colX);
michael@0 1224 const nsStyleVisibility* colVis = colFrame->StyleVisibility();
michael@0 1225 bool collapseCol = (NS_STYLE_VISIBILITY_COLLAPSE ==
michael@0 1226 colVis->mVisible);
michael@0 1227 nsIFrame* cgFrame = colFrame->GetParent();
michael@0 1228 const nsStyleVisibility* groupVis = cgFrame->StyleVisibility();
michael@0 1229 bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE ==
michael@0 1230 groupVis->mVisible);
michael@0 1231 bool isCollapsed = collapseCol || collapseGroup;
michael@0 1232 if (!isCollapsed) {
michael@0 1233 cRect.width += tableFrame->GetColumnWidth(colX);
michael@0 1234 isVisible = true;
michael@0 1235 if ((actualColSpan > 1)) {
michael@0 1236 nsTableColFrame* nextColFrame =
michael@0 1237 tableFrame->GetColFrame(colX + colIncrement);
michael@0 1238 const nsStyleVisibility* nextColVis =
michael@0 1239 nextColFrame->StyleVisibility();
michael@0 1240 if ( (NS_STYLE_VISIBILITY_COLLAPSE != nextColVis->mVisible) &&
michael@0 1241 tableFrame->ColumnHasCellSpacingBefore(colX + colIncrement)) {
michael@0 1242 cRect.width += cellSpacingX;
michael@0 1243 }
michael@0 1244 }
michael@0 1245 }
michael@0 1246 }
michael@0 1247 x += cRect.width;
michael@0 1248 if (isVisible)
michael@0 1249 x += cellSpacingX;
michael@0 1250 int32_t actualRowSpan = tableFrame->GetEffectiveRowSpan(*cellFrame);
michael@0 1251 nsTableRowFrame* rowFrame = GetNextRow();
michael@0 1252 for (actualRowSpan--; actualRowSpan > 0 && rowFrame; actualRowSpan--) {
michael@0 1253 const nsStyleVisibility* nextRowVis = rowFrame->StyleVisibility();
michael@0 1254 bool collapseNextRow = (NS_STYLE_VISIBILITY_COLLAPSE ==
michael@0 1255 nextRowVis->mVisible);
michael@0 1256 if (!collapseNextRow) {
michael@0 1257 nsRect nextRect = rowFrame->GetRect();
michael@0 1258 cRect.height += nextRect.height + cellSpacingY;
michael@0 1259 }
michael@0 1260 rowFrame = rowFrame->GetNextRow();
michael@0 1261 }
michael@0 1262
michael@0 1263 nsRect oldCellRect = cellFrame->GetRect();
michael@0 1264 nsRect oldCellVisualOverflow = cellFrame->GetVisualOverflowRect();
michael@0 1265
michael@0 1266 if (aRowOffset == 0 && cRect.TopLeft() != oldCellRect.TopLeft()) {
michael@0 1267 // We're moving the cell. Invalidate the old overflow area
michael@0 1268 cellFrame->InvalidateFrameSubtree();
michael@0 1269 }
michael@0 1270
michael@0 1271 cellFrame->SetRect(cRect);
michael@0 1272
michael@0 1273 // XXXbz This looks completely bogus in the cases when we didn't
michael@0 1274 // collapse the cell!
michael@0 1275 nsRect cellBounds(0, 0, cRect.width, cRect.height);
michael@0 1276 nsOverflowAreas cellOverflow(cellBounds, cellBounds);
michael@0 1277 cellFrame->FinishAndStoreOverflow(cellOverflow, cRect.Size());
michael@0 1278 nsTableFrame::RePositionViews(cellFrame);
michael@0 1279 ConsiderChildOverflow(overflow, cellFrame);
michael@0 1280
michael@0 1281 if (aRowOffset == 0) {
michael@0 1282 nsTableFrame::InvalidateTableFrame(cellFrame, oldCellRect,
michael@0 1283 oldCellVisualOverflow,
michael@0 1284 false);
michael@0 1285 }
michael@0 1286 }
michael@0 1287 kidFrame = iter.Next(); // Get the next child
michael@0 1288 }
michael@0 1289 }
michael@0 1290
michael@0 1291 SetRect(rowRect);
michael@0 1292 overflow.UnionAllWith(nsRect(0, 0, rowRect.width, rowRect.height));
michael@0 1293 FinishAndStoreOverflow(overflow, rowRect.Size());
michael@0 1294
michael@0 1295 nsTableFrame::RePositionViews(this);
michael@0 1296 nsTableFrame::InvalidateTableFrame(this, oldRect, oldVisualOverflow, false);
michael@0 1297 return shift;
michael@0 1298 }
michael@0 1299
michael@0 1300 /*
michael@0 1301 * The following method is called by the row group frame's SplitRowGroup()
michael@0 1302 * when it creates a continuing cell frame and wants to insert it into the
michael@0 1303 * row's child list.
michael@0 1304 */
michael@0 1305 void
michael@0 1306 nsTableRowFrame::InsertCellFrame(nsTableCellFrame* aFrame,
michael@0 1307 int32_t aColIndex)
michael@0 1308 {
michael@0 1309 // Find the cell frame where col index < aColIndex
michael@0 1310 nsTableCellFrame* priorCell = nullptr;
michael@0 1311 for (nsIFrame* child = mFrames.FirstChild(); child;
michael@0 1312 child = child->GetNextSibling()) {
michael@0 1313 nsTableCellFrame *cellFrame = do_QueryFrame(child);
michael@0 1314 if (cellFrame) {
michael@0 1315 int32_t colIndex;
michael@0 1316 cellFrame->GetColIndex(colIndex);
michael@0 1317 if (colIndex < aColIndex) {
michael@0 1318 priorCell = cellFrame;
michael@0 1319 }
michael@0 1320 else break;
michael@0 1321 }
michael@0 1322 }
michael@0 1323 mFrames.InsertFrame(this, priorCell, aFrame);
michael@0 1324 }
michael@0 1325
michael@0 1326 nsIAtom*
michael@0 1327 nsTableRowFrame::GetType() const
michael@0 1328 {
michael@0 1329 return nsGkAtoms::tableRowFrame;
michael@0 1330 }
michael@0 1331
michael@0 1332 nsTableRowFrame*
michael@0 1333 nsTableRowFrame::GetNextRow() const
michael@0 1334 {
michael@0 1335 nsIFrame* childFrame = GetNextSibling();
michael@0 1336 while (childFrame) {
michael@0 1337 nsTableRowFrame *rowFrame = do_QueryFrame(childFrame);
michael@0 1338 if (rowFrame) {
michael@0 1339 NS_ASSERTION(NS_STYLE_DISPLAY_TABLE_ROW == childFrame->StyleDisplay()->mDisplay, "wrong display type on rowframe");
michael@0 1340 return rowFrame;
michael@0 1341 }
michael@0 1342 childFrame = childFrame->GetNextSibling();
michael@0 1343 }
michael@0 1344 return nullptr;
michael@0 1345 }
michael@0 1346
michael@0 1347 NS_DECLARE_FRAME_PROPERTY(RowUnpaginatedHeightProperty, nullptr)
michael@0 1348
michael@0 1349 void
michael@0 1350 nsTableRowFrame::SetUnpaginatedHeight(nsPresContext* aPresContext,
michael@0 1351 nscoord aValue)
michael@0 1352 {
michael@0 1353 NS_ASSERTION(!GetPrevInFlow(), "program error");
michael@0 1354 // Get the property
michael@0 1355 aPresContext->PropertyTable()->
michael@0 1356 Set(this, RowUnpaginatedHeightProperty(), NS_INT32_TO_PTR(aValue));
michael@0 1357 }
michael@0 1358
michael@0 1359 nscoord
michael@0 1360 nsTableRowFrame::GetUnpaginatedHeight(nsPresContext* aPresContext)
michael@0 1361 {
michael@0 1362 FrameProperties props = FirstInFlow()->Properties();
michael@0 1363 return NS_PTR_TO_INT32(props.Get(RowUnpaginatedHeightProperty()));
michael@0 1364 }
michael@0 1365
michael@0 1366 void nsTableRowFrame::SetContinuousBCBorderWidth(uint8_t aForSide,
michael@0 1367 BCPixelSize aPixelValue)
michael@0 1368 {
michael@0 1369 switch (aForSide) {
michael@0 1370 case NS_SIDE_RIGHT:
michael@0 1371 mRightContBorderWidth = aPixelValue;
michael@0 1372 return;
michael@0 1373 case NS_SIDE_TOP:
michael@0 1374 mTopContBorderWidth = aPixelValue;
michael@0 1375 return;
michael@0 1376 case NS_SIDE_LEFT:
michael@0 1377 mLeftContBorderWidth = aPixelValue;
michael@0 1378 return;
michael@0 1379 default:
michael@0 1380 NS_ERROR("invalid NS_SIDE arg");
michael@0 1381 }
michael@0 1382 }
michael@0 1383 #ifdef ACCESSIBILITY
michael@0 1384 a11y::AccType
michael@0 1385 nsTableRowFrame::AccessibleType()
michael@0 1386 {
michael@0 1387 return a11y::eHTMLTableRowType;
michael@0 1388 }
michael@0 1389 #endif
michael@0 1390 /**
michael@0 1391 * Sets the NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT bit to indicate whether
michael@0 1392 * this row has any cells that have non-auto-height. (Row-spanning
michael@0 1393 * cells are ignored.)
michael@0 1394 */
michael@0 1395 void nsTableRowFrame::InitHasCellWithStyleHeight(nsTableFrame* aTableFrame)
michael@0 1396 {
michael@0 1397 nsTableIterator iter(*this);
michael@0 1398
michael@0 1399 for (nsIFrame* kidFrame = iter.First(); kidFrame; kidFrame = iter.Next()) {
michael@0 1400 nsTableCellFrame *cellFrame = do_QueryFrame(kidFrame);
michael@0 1401 if (!cellFrame) {
michael@0 1402 NS_NOTREACHED("Table row has a non-cell child.");
michael@0 1403 continue;
michael@0 1404 }
michael@0 1405 // Ignore row-spanning cells
michael@0 1406 const nsStyleCoord &cellHeight = cellFrame->StylePosition()->mHeight;
michael@0 1407 if (aTableFrame->GetEffectiveRowSpan(*cellFrame) == 1 &&
michael@0 1408 cellHeight.GetUnit() != eStyleUnit_Auto &&
michael@0 1409 /* calc() with percentages treated like 'auto' */
michael@0 1410 (!cellHeight.IsCalcUnit() || !cellHeight.HasPercent())) {
michael@0 1411 AddStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT);
michael@0 1412 return;
michael@0 1413 }
michael@0 1414 }
michael@0 1415 RemoveStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT);
michael@0 1416 }
michael@0 1417
michael@0 1418 void
michael@0 1419 nsTableRowFrame::InvalidateFrame(uint32_t aDisplayItemKey)
michael@0 1420 {
michael@0 1421 nsIFrame::InvalidateFrame(aDisplayItemKey);
michael@0 1422 GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
michael@0 1423 }
michael@0 1424
michael@0 1425 void
michael@0 1426 nsTableRowFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
michael@0 1427 {
michael@0 1428 nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
michael@0 1429 // If we have filters applied that would affects our bounds, then
michael@0 1430 // we get an inactive layer created and this is computed
michael@0 1431 // within FrameLayerBuilder
michael@0 1432 GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
michael@0 1433 }
michael@0 1434
michael@0 1435 /* ----- global methods ----- */
michael@0 1436
michael@0 1437 nsIFrame*
michael@0 1438 NS_NewTableRowFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 1439 {
michael@0 1440 return new (aPresShell) nsTableRowFrame(aContext);
michael@0 1441 }
michael@0 1442
michael@0 1443 NS_IMPL_FRAMEARENA_HELPERS(nsTableRowFrame)
michael@0 1444
michael@0 1445 #ifdef DEBUG_FRAME_DUMP
michael@0 1446 nsresult
michael@0 1447 nsTableRowFrame::GetFrameName(nsAString& aResult) const
michael@0 1448 {
michael@0 1449 return MakeFrameName(NS_LITERAL_STRING("TableRow"), aResult);
michael@0 1450 }
michael@0 1451 #endif

mercurial