nsTableRowGroupFrame.cpp 75 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsCOMPtr.h"
  6. #include "nsTableRowGroupFrame.h"
  7. #include "nsTableRowFrame.h"
  8. #include "nsTableFrame.h"
  9. #include "nsTableCellFrame.h"
  10. #include "nsPresContext.h"
  11. #include "nsStyleContext.h"
  12. #include "nsStyleConsts.h"
  13. #include "nsIContent.h"
  14. #include "nsGkAtoms.h"
  15. #include "nsIPresShell.h"
  16. #include "nsCSSRendering.h"
  17. #include "nsHTMLParts.h"
  18. #include "nsCSSFrameConstructor.h"
  19. #include "nsDisplayList.h"
  20. #include "nsCellMap.h"//table cell navigation
  21. #include <algorithm>
  22. using namespace mozilla;
  23. using namespace mozilla::layout;
  24. namespace mozilla {
  25. struct TableRowGroupReflowInput {
  26. const ReflowInput& reflowInput; // Our reflow state
  27. nsTableFrame* tableFrame;
  28. // The available size (computed from the parent)
  29. mozilla::LogicalSize availSize;
  30. // Running block-offset
  31. nscoord bCoord;
  32. TableRowGroupReflowInput(const ReflowInput& aReflowInput,
  33. nsTableFrame* aTableFrame)
  34. : reflowInput(aReflowInput)
  35. , tableFrame(aTableFrame)
  36. , availSize(aReflowInput.GetWritingMode(),
  37. aReflowInput.AvailableISize(),
  38. aReflowInput.AvailableBSize())
  39. , bCoord(0)
  40. {
  41. }
  42. ~TableRowGroupReflowInput() {}
  43. };
  44. } // namespace mozilla
  45. nsTableRowGroupFrame::nsTableRowGroupFrame(nsStyleContext* aContext):
  46. nsContainerFrame(aContext)
  47. {
  48. SetRepeatable(false);
  49. }
  50. nsTableRowGroupFrame::~nsTableRowGroupFrame()
  51. {
  52. }
  53. void
  54. nsTableRowGroupFrame::DestroyFrom(nsIFrame* aDestructRoot)
  55. {
  56. if (HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
  57. nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot);
  58. }
  59. nsContainerFrame::DestroyFrom(aDestructRoot);
  60. }
  61. NS_QUERYFRAME_HEAD(nsTableRowGroupFrame)
  62. NS_QUERYFRAME_ENTRY(nsTableRowGroupFrame)
  63. NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
  64. int32_t
  65. nsTableRowGroupFrame::GetRowCount()
  66. {
  67. #ifdef DEBUG
  68. for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
  69. NS_ASSERTION(e.get()->StyleDisplay()->mDisplay ==
  70. mozilla::StyleDisplay::TableRow,
  71. "Unexpected display");
  72. NS_ASSERTION(e.get()->GetType() == nsGkAtoms::tableRowFrame,
  73. "Unexpected frame type");
  74. }
  75. #endif
  76. return mFrames.GetLength();
  77. }
  78. int32_t nsTableRowGroupFrame::GetStartRowIndex()
  79. {
  80. int32_t result = -1;
  81. if (mFrames.NotEmpty()) {
  82. NS_ASSERTION(mFrames.FirstChild()->GetType() == nsGkAtoms::tableRowFrame,
  83. "Unexpected frame type");
  84. result = static_cast<nsTableRowFrame*>(mFrames.FirstChild())->GetRowIndex();
  85. }
  86. // if the row group doesn't have any children, get it the hard way
  87. if (-1 == result) {
  88. return GetTableFrame()->GetStartRowIndex(this);
  89. }
  90. return result;
  91. }
  92. void nsTableRowGroupFrame::AdjustRowIndices(int32_t aRowIndex,
  93. int32_t anAdjustment)
  94. {
  95. for (nsIFrame* rowFrame : mFrames) {
  96. if (mozilla::StyleDisplay::TableRow == rowFrame->StyleDisplay()->mDisplay) {
  97. int32_t index = ((nsTableRowFrame*)rowFrame)->GetRowIndex();
  98. if (index >= aRowIndex)
  99. ((nsTableRowFrame *)rowFrame)->SetRowIndex(index+anAdjustment);
  100. }
  101. }
  102. }
  103. nsresult
  104. nsTableRowGroupFrame::InitRepeatedFrame(nsTableRowGroupFrame* aHeaderFooterFrame)
  105. {
  106. nsTableRowFrame* copyRowFrame = GetFirstRow();
  107. nsTableRowFrame* originalRowFrame = aHeaderFooterFrame->GetFirstRow();
  108. AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
  109. while (copyRowFrame && originalRowFrame) {
  110. copyRowFrame->AddStateBits(NS_REPEATED_ROW_OR_ROWGROUP);
  111. int rowIndex = originalRowFrame->GetRowIndex();
  112. copyRowFrame->SetRowIndex(rowIndex);
  113. // For each table cell frame set its column index
  114. nsTableCellFrame* originalCellFrame = originalRowFrame->GetFirstCell();
  115. nsTableCellFrame* copyCellFrame = copyRowFrame->GetFirstCell();
  116. while (copyCellFrame && originalCellFrame) {
  117. NS_ASSERTION(originalCellFrame->GetContent() == copyCellFrame->GetContent(),
  118. "cell frames have different content");
  119. uint32_t colIndex = originalCellFrame->ColIndex();
  120. copyCellFrame->SetColIndex(colIndex);
  121. // Move to the next cell frame
  122. copyCellFrame = copyCellFrame->GetNextCell();
  123. originalCellFrame = originalCellFrame->GetNextCell();
  124. }
  125. // Move to the next row frame
  126. originalRowFrame = originalRowFrame->GetNextRow();
  127. copyRowFrame = copyRowFrame->GetNextRow();
  128. }
  129. return NS_OK;
  130. }
  131. // Handle the child-traversal part of DisplayGenericTablePart
  132. static void
  133. DisplayRows(nsDisplayListBuilder* aBuilder, nsFrame* aFrame,
  134. const nsDisplayListSet& aLists)
  135. {
  136. nscoord overflowAbove;
  137. nsTableRowGroupFrame* f = static_cast<nsTableRowGroupFrame*>(aFrame);
  138. // Don't try to use the row cursor if we have to descend into placeholders;
  139. // we might have rows containing placeholders, where the row's overflow
  140. // area doesn't intersect the dirty rect but we need to descend into the row
  141. // to see out-of-flows.
  142. // Note that we really want to check ShouldDescendIntoFrame for all
  143. // the rows in |f|, but that's exactly what we're trying to avoid, so we
  144. // approximate it by checking it for |f|: if it's true for any row
  145. // in |f| then it's true for |f| itself.
  146. nsIFrame* kid = aBuilder->ShouldDescendIntoFrame(f) ?
  147. nullptr : f->GetFirstRowContaining(aBuilder->GetDirtyRect().y, &overflowAbove);
  148. if (kid) {
  149. // If we have a cursor, use it
  150. while (kid) {
  151. if (kid->GetRect().y - overflowAbove >= aBuilder->GetDirtyRect().YMost()) {
  152. break;
  153. }
  154. f->BuildDisplayListForChild(aBuilder, kid, aLists);
  155. kid = kid->GetNextSibling();
  156. }
  157. return;
  158. }
  159. // No cursor. Traverse children the hard way and build a cursor while we're at it
  160. nsTableRowGroupFrame::FrameCursorData* cursor = f->SetupRowCursor();
  161. kid = f->PrincipalChildList().FirstChild();
  162. while (kid) {
  163. f->BuildDisplayListForChild(aBuilder, kid, aLists);
  164. if (cursor) {
  165. if (!cursor->AppendFrame(kid)) {
  166. f->ClearRowCursor();
  167. return;
  168. }
  169. }
  170. kid = kid->GetNextSibling();
  171. }
  172. if (cursor) {
  173. cursor->FinishBuildingCursor();
  174. }
  175. }
  176. void
  177. nsTableRowGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
  178. const nsDisplayListSet& aLists)
  179. {
  180. if (IsVisibleForPainting(aBuilder)) {
  181. // XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted
  182. // just because we're visible? Or should it depend on the cell visibility
  183. // when we're not the whole table?
  184. // Paint the outset box-shadows for the table frames
  185. if (StyleEffects()->mBoxShadow) {
  186. aLists.BorderBackground()->AppendNewToTop(
  187. new (aBuilder) nsDisplayBoxShadowOuter
  188. (aBuilder, this));
  189. }
  190. }
  191. for (nsTableRowFrame* row = GetFirstRow(); row; row = row->GetNextRow()) {
  192. if (!aBuilder->GetDirtyRect().Intersects(row->GetVisualOverflowRect() + row->GetNormalPosition())) {
  193. continue;
  194. }
  195. row->PaintCellBackgroundsForFrame(this, aBuilder, aLists,
  196. row->GetNormalPosition());
  197. }
  198. if (IsVisibleForPainting(aBuilder)) {
  199. // XXXbz should box-shadow for rows/rowgroups/columns/colgroups get painted
  200. // just because we're visible? Or should it depend on the cell visibility
  201. // when we're not the whole table?
  202. // Paint the inset box-shadows for the table frames
  203. if (StyleEffects()->mBoxShadow) {
  204. aLists.BorderBackground()->AppendNewToTop(
  205. new (aBuilder) nsDisplayBoxShadowInner
  206. (aBuilder, this));
  207. }
  208. }
  209. DisplayOutline(aBuilder, aLists);
  210. DisplayRows(aBuilder, this, aLists);
  211. }
  212. nsIFrame::LogicalSides
  213. nsTableRowGroupFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const
  214. {
  215. if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
  216. StyleBoxDecorationBreak::Clone)) {
  217. return LogicalSides();
  218. }
  219. LogicalSides skip;
  220. if (nullptr != GetPrevInFlow()) {
  221. skip |= eLogicalSideBitsBStart;
  222. }
  223. if (nullptr != GetNextInFlow()) {
  224. skip |= eLogicalSideBitsBEnd;
  225. }
  226. return skip;
  227. }
  228. // Position and size aKidFrame and update our reflow state.
  229. void
  230. nsTableRowGroupFrame::PlaceChild(nsPresContext* aPresContext,
  231. TableRowGroupReflowInput& aReflowInput,
  232. nsIFrame* aKidFrame,
  233. WritingMode aWM,
  234. const LogicalPoint& aKidPosition,
  235. const nsSize& aContainerSize,
  236. ReflowOutput& aDesiredSize,
  237. const nsRect& aOriginalKidRect,
  238. const nsRect& aOriginalKidVisualOverflow)
  239. {
  240. bool isFirstReflow = aKidFrame->HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
  241. // Place and size the child
  242. FinishReflowChild(aKidFrame, aPresContext, aDesiredSize, nullptr,
  243. aWM, aKidPosition, aContainerSize, 0);
  244. nsTableFrame::InvalidateTableFrame(aKidFrame, aOriginalKidRect,
  245. aOriginalKidVisualOverflow, isFirstReflow);
  246. // Adjust the running block-offset
  247. aReflowInput.bCoord += aDesiredSize.BSize(aWM);
  248. // If our block-size is constrained then update the available bsize
  249. if (NS_UNCONSTRAINEDSIZE != aReflowInput.availSize.BSize(aWM)) {
  250. aReflowInput.availSize.BSize(aWM) -= aDesiredSize.BSize(aWM);
  251. }
  252. }
  253. void
  254. nsTableRowGroupFrame::InitChildReflowInput(nsPresContext& aPresContext,
  255. bool aBorderCollapse,
  256. ReflowInput& aReflowInput)
  257. {
  258. nsMargin collapseBorder;
  259. nsMargin padding(0,0,0,0);
  260. nsMargin* pCollapseBorder = nullptr;
  261. if (aBorderCollapse) {
  262. nsTableRowFrame *rowFrame = do_QueryFrame(aReflowInput.mFrame);
  263. if (rowFrame) {
  264. WritingMode wm = GetWritingMode();
  265. LogicalMargin border = rowFrame->GetBCBorderWidth(wm);
  266. collapseBorder = border.GetPhysicalMargin(wm);
  267. pCollapseBorder = &collapseBorder;
  268. }
  269. }
  270. aReflowInput.Init(&aPresContext, nullptr, pCollapseBorder, &padding);
  271. }
  272. static void
  273. CacheRowBSizesForPrinting(nsPresContext* aPresContext,
  274. nsTableRowFrame* aFirstRow,
  275. WritingMode aWM)
  276. {
  277. for (nsTableRowFrame* row = aFirstRow; row; row = row->GetNextRow()) {
  278. if (!row->GetPrevInFlow()) {
  279. row->SetHasUnpaginatedBSize(true);
  280. row->SetUnpaginatedBSize(aPresContext, row->BSize(aWM));
  281. }
  282. }
  283. }
  284. void
  285. nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext,
  286. ReflowOutput& aDesiredSize,
  287. TableRowGroupReflowInput& aReflowInput,
  288. nsReflowStatus& aStatus,
  289. bool* aPageBreakBeforeEnd)
  290. {
  291. if (aPageBreakBeforeEnd) {
  292. *aPageBreakBeforeEnd = false;
  293. }
  294. WritingMode wm = aReflowInput.reflowInput.GetWritingMode();
  295. nsTableFrame* tableFrame = GetTableFrame();
  296. const bool borderCollapse = tableFrame->IsBorderCollapse();
  297. // XXXldb Should we really be checking IsPaginated(),
  298. // or should we *only* check available block-size?
  299. // (Think about multi-column layout!)
  300. bool isPaginated = aPresContext->IsPaginated() &&
  301. NS_UNCONSTRAINEDSIZE != aReflowInput.availSize.BSize(wm);
  302. bool haveRow = false;
  303. bool reflowAllKids = aReflowInput.reflowInput.ShouldReflowAllKids() ||
  304. tableFrame->IsGeometryDirty();
  305. // in vertical-rl mode, we always need the row bsizes in order to
  306. // get the necessary containerSize for placing our kids
  307. bool needToCalcRowBSizes = reflowAllKids || wm.IsVerticalRL();
  308. nsSize containerSize =
  309. aReflowInput.reflowInput.ComputedSizeAsContainerIfConstrained();
  310. nsIFrame *prevKidFrame = nullptr;
  311. for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame;
  312. prevKidFrame = kidFrame, kidFrame = kidFrame->GetNextSibling()) {
  313. nsTableRowFrame *rowFrame = do_QueryFrame(kidFrame);
  314. if (!rowFrame) {
  315. // XXXldb nsCSSFrameConstructor needs to enforce this!
  316. NS_NOTREACHED("yikes, a non-row child");
  317. continue;
  318. }
  319. nscoord cellSpacingB = tableFrame->GetRowSpacing(rowFrame->GetRowIndex());
  320. haveRow = true;
  321. // Reflow the row frame
  322. if (reflowAllKids ||
  323. NS_SUBTREE_DIRTY(kidFrame) ||
  324. (aReflowInput.reflowInput.mFlags.mSpecialBSizeReflow &&
  325. (isPaginated ||
  326. kidFrame->HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)))) {
  327. LogicalRect oldKidRect = kidFrame->GetLogicalRect(wm, containerSize);
  328. nsRect oldKidVisualOverflow = kidFrame->GetVisualOverflowRect();
  329. // XXXldb We used to only pass aDesiredSize.mFlags through for the
  330. // incremental reflow codepath.
  331. ReflowOutput desiredSize(aReflowInput.reflowInput,
  332. aDesiredSize.mFlags);
  333. desiredSize.ClearSize();
  334. // Reflow the child into the available space, giving it as much bsize as
  335. // it wants. We'll deal with splitting later after we've computed the row
  336. // bsizes, taking into account cells with row spans...
  337. LogicalSize kidAvailSize = aReflowInput.availSize;
  338. kidAvailSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
  339. ReflowInput kidReflowInput(aPresContext, aReflowInput.reflowInput,
  340. kidFrame, kidAvailSize,
  341. nullptr,
  342. ReflowInput::CALLER_WILL_INIT);
  343. InitChildReflowInput(*aPresContext, borderCollapse, kidReflowInput);
  344. // This can indicate that columns were resized.
  345. if (aReflowInput.reflowInput.IsIResize()) {
  346. kidReflowInput.SetIResize(true);
  347. }
  348. NS_ASSERTION(kidFrame == mFrames.FirstChild() || prevKidFrame,
  349. "If we're not on the first frame, we should have a "
  350. "previous sibling...");
  351. // If prev row has nonzero YMost, then we can't be at the top of the page
  352. if (prevKidFrame && prevKidFrame->GetNormalRect().YMost() > 0) {
  353. kidReflowInput.mFlags.mIsTopOfPage = false;
  354. }
  355. LogicalPoint kidPosition(wm, 0, aReflowInput.bCoord);
  356. ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowInput,
  357. wm, kidPosition, containerSize, 0, aStatus);
  358. kidReflowInput.ApplyRelativePositioning(&kidPosition, containerSize);
  359. // Place the child
  360. PlaceChild(aPresContext, aReflowInput, kidFrame,
  361. wm, kidPosition, containerSize,
  362. desiredSize, oldKidRect.GetPhysicalRect(wm, containerSize),
  363. oldKidVisualOverflow);
  364. aReflowInput.bCoord += cellSpacingB;
  365. if (!reflowAllKids) {
  366. if (IsSimpleRowFrame(aReflowInput.tableFrame, rowFrame)) {
  367. // Inform the row of its new bsize.
  368. rowFrame->DidResize();
  369. // the overflow area may have changed inflate the overflow area
  370. const nsStylePosition *stylePos = StylePosition();
  371. nsStyleUnit unit = stylePos->BSize(wm).GetUnit();
  372. if (aReflowInput.tableFrame->IsAutoBSize(wm) &&
  373. unit != eStyleUnit_Coord) {
  374. // Because other cells in the row may need to be aligned
  375. // differently, repaint the entire row
  376. InvalidateFrame();
  377. } else if (oldKidRect.BSize(wm) != desiredSize.BSize(wm)) {
  378. needToCalcRowBSizes = true;
  379. }
  380. } else {
  381. needToCalcRowBSizes = true;
  382. }
  383. }
  384. if (isPaginated && aPageBreakBeforeEnd && !*aPageBreakBeforeEnd) {
  385. nsTableRowFrame* nextRow = rowFrame->GetNextRow();
  386. if (nextRow) {
  387. *aPageBreakBeforeEnd = nsTableFrame::PageBreakAfter(kidFrame, nextRow);
  388. }
  389. }
  390. } else {
  391. SlideChild(aReflowInput, kidFrame);
  392. // Adjust the running b-offset so we know where the next row should be placed
  393. nscoord bSize = kidFrame->BSize(wm) + cellSpacingB;
  394. aReflowInput.bCoord += bSize;
  395. if (NS_UNCONSTRAINEDSIZE != aReflowInput.availSize.BSize(wm)) {
  396. aReflowInput.availSize.BSize(wm) -= bSize;
  397. }
  398. }
  399. ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame);
  400. }
  401. if (haveRow) {
  402. aReflowInput.bCoord -= tableFrame->GetRowSpacing(GetStartRowIndex() +
  403. GetRowCount());
  404. }
  405. // Return our desired rect
  406. aDesiredSize.ISize(wm) = aReflowInput.reflowInput.AvailableISize();
  407. aDesiredSize.BSize(wm) = aReflowInput.bCoord;
  408. if (aReflowInput.reflowInput.mFlags.mSpecialBSizeReflow) {
  409. DidResizeRows(aDesiredSize);
  410. if (isPaginated) {
  411. CacheRowBSizesForPrinting(aPresContext, GetFirstRow(), wm);
  412. }
  413. }
  414. else if (needToCalcRowBSizes) {
  415. CalculateRowBSizes(aPresContext, aDesiredSize, aReflowInput.reflowInput);
  416. if (!reflowAllKids) {
  417. InvalidateFrame();
  418. }
  419. }
  420. }
  421. nsTableRowFrame*
  422. nsTableRowGroupFrame::GetFirstRow()
  423. {
  424. for (nsIFrame* childFrame : mFrames) {
  425. nsTableRowFrame* rowFrame = do_QueryFrame(childFrame);
  426. if (rowFrame) {
  427. return rowFrame;
  428. }
  429. }
  430. return nullptr;
  431. }
  432. nsTableRowFrame*
  433. nsTableRowGroupFrame::GetLastRow()
  434. {
  435. for (auto iter = mFrames.rbegin(), end = mFrames.rend(); iter != end; ++iter) {
  436. nsTableRowFrame* rowFrame = do_QueryFrame(*iter);
  437. if (rowFrame) {
  438. return rowFrame;
  439. }
  440. }
  441. return nullptr;
  442. }
  443. struct RowInfo {
  444. RowInfo() { bSize = pctBSize = hasStyleBSize = hasPctBSize = isSpecial = 0; }
  445. unsigned bSize; // content bsize or fixed bsize, excluding pct bsize
  446. unsigned pctBSize:29; // pct bsize
  447. unsigned hasStyleBSize:1;
  448. unsigned hasPctBSize:1;
  449. unsigned isSpecial:1; // there is no cell originating in the row with rowspan=1 and there are at
  450. // least 2 cells spanning the row and there is no style bsize on the row
  451. };
  452. static void
  453. UpdateBSizes(RowInfo& aRowInfo,
  454. nscoord aAdditionalBSize,
  455. nscoord& aTotal,
  456. nscoord& aUnconstrainedTotal)
  457. {
  458. aRowInfo.bSize += aAdditionalBSize;
  459. aTotal += aAdditionalBSize;
  460. if (!aRowInfo.hasStyleBSize) {
  461. aUnconstrainedTotal += aAdditionalBSize;
  462. }
  463. }
  464. void
  465. nsTableRowGroupFrame::DidResizeRows(ReflowOutput& aDesiredSize)
  466. {
  467. // Update the cells spanning rows with their new bsizes.
  468. // This is the place where all of the cells in the row get set to the bsize
  469. // of the row.
  470. // Reset the overflow area.
  471. aDesiredSize.mOverflowAreas.Clear();
  472. for (nsTableRowFrame* rowFrame = GetFirstRow();
  473. rowFrame; rowFrame = rowFrame->GetNextRow()) {
  474. rowFrame->DidResize();
  475. ConsiderChildOverflow(aDesiredSize.mOverflowAreas, rowFrame);
  476. }
  477. }
  478. // This calculates the bsize of all the rows and takes into account
  479. // style bsize on the row group, style bsizes on rows and cells, style bsizes on rowspans.
  480. // Actual row bsizes will be adjusted later if the table has a style bsize.
  481. // Even if rows don't change bsize, this method must be called to set the bsizes of each
  482. // cell in the row to the bsize of its row.
  483. void
  484. nsTableRowGroupFrame::CalculateRowBSizes(nsPresContext* aPresContext,
  485. ReflowOutput& aDesiredSize,
  486. const ReflowInput& aReflowInput)
  487. {
  488. nsTableFrame* tableFrame = GetTableFrame();
  489. const bool isPaginated = aPresContext->IsPaginated();
  490. int32_t numEffCols = tableFrame->GetEffectiveColCount();
  491. int32_t startRowIndex = GetStartRowIndex();
  492. // find the row corresponding to the row index we just found
  493. nsTableRowFrame* startRowFrame = GetFirstRow();
  494. if (!startRowFrame) {
  495. return;
  496. }
  497. // The current row group block-size is the block-origin of the 1st row
  498. // we are about to calculate a block-size for.
  499. WritingMode wm = aReflowInput.GetWritingMode();
  500. nsSize containerSize; // actual value is unimportant as we're initially
  501. // computing sizes, not physical positions
  502. nscoord startRowGroupBSize =
  503. startRowFrame->GetLogicalNormalPosition(wm, containerSize).B(wm);
  504. int32_t numRows = GetRowCount() - (startRowFrame->GetRowIndex() - GetStartRowIndex());
  505. // Collect the current bsize of each row.
  506. if (numRows <= 0)
  507. return;
  508. nsTArray<RowInfo> rowInfo;
  509. if (!rowInfo.AppendElements(numRows)) {
  510. return;
  511. }
  512. bool hasRowSpanningCell = false;
  513. nscoord bSizeOfRows = 0;
  514. nscoord bSizeOfUnStyledRows = 0;
  515. // Get the bsize of each row without considering rowspans. This will be the max of
  516. // the largest desired bsize of each cell, the largest style bsize of each cell,
  517. // the style bsize of the row.
  518. nscoord pctBSizeBasis = GetBSizeBasis(aReflowInput);
  519. int32_t rowIndex; // the index in rowInfo, not among the rows in the row group
  520. nsTableRowFrame* rowFrame;
  521. for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
  522. nscoord nonPctBSize = rowFrame->GetContentBSize();
  523. if (isPaginated) {
  524. nonPctBSize = std::max(nonPctBSize, rowFrame->BSize(wm));
  525. }
  526. if (!rowFrame->GetPrevInFlow()) {
  527. if (rowFrame->HasPctBSize()) {
  528. rowInfo[rowIndex].hasPctBSize = true;
  529. rowInfo[rowIndex].pctBSize = rowFrame->GetInitialBSize(pctBSizeBasis);
  530. }
  531. rowInfo[rowIndex].hasStyleBSize = rowFrame->HasStyleBSize();
  532. nonPctBSize = std::max(nonPctBSize, rowFrame->GetFixedBSize());
  533. }
  534. UpdateBSizes(rowInfo[rowIndex], nonPctBSize, bSizeOfRows, bSizeOfUnStyledRows);
  535. if (!rowInfo[rowIndex].hasStyleBSize) {
  536. if (isPaginated || tableFrame->HasMoreThanOneCell(rowIndex + startRowIndex)) {
  537. rowInfo[rowIndex].isSpecial = true;
  538. // iteratate the row's cell frames to see if any do not have rowspan > 1
  539. nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
  540. while (cellFrame) {
  541. int32_t rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
  542. if (1 == rowSpan) {
  543. rowInfo[rowIndex].isSpecial = false;
  544. break;
  545. }
  546. cellFrame = cellFrame->GetNextCell();
  547. }
  548. }
  549. }
  550. // See if a cell spans into the row. If so we'll have to do the next step
  551. if (!hasRowSpanningCell) {
  552. if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex, numEffCols)) {
  553. hasRowSpanningCell = true;
  554. }
  555. }
  556. }
  557. if (hasRowSpanningCell) {
  558. // Get the bsize of cells with rowspans and allocate any extra space to the rows they span
  559. // iteratate the child frames and process the row frames among them
  560. for (rowFrame = startRowFrame, rowIndex = 0; rowFrame; rowFrame = rowFrame->GetNextRow(), rowIndex++) {
  561. // See if the row has an originating cell with rowspan > 1. We cannot determine this for a row in a
  562. // continued row group by calling RowHasSpanningCells, because the row's fif may not have any originating
  563. // cells yet the row may have a continued cell which originates in it.
  564. if (GetPrevInFlow() || tableFrame->RowHasSpanningCells(startRowIndex + rowIndex, numEffCols)) {
  565. nsTableCellFrame* cellFrame = rowFrame->GetFirstCell();
  566. // iteratate the row's cell frames
  567. while (cellFrame) {
  568. nscoord cellSpacingB = tableFrame->GetRowSpacing(startRowIndex + rowIndex);
  569. int32_t rowSpan = tableFrame->GetEffectiveRowSpan(rowIndex + startRowIndex, *cellFrame);
  570. if ((rowIndex + rowSpan) > numRows) {
  571. // there might be rows pushed already to the nextInFlow
  572. rowSpan = numRows - rowIndex;
  573. }
  574. if (rowSpan > 1) { // a cell with rowspan > 1, determine the bsize of the rows it spans
  575. nscoord bsizeOfRowsSpanned = 0;
  576. nscoord bsizeOfUnStyledRowsSpanned = 0;
  577. nscoord numSpecialRowsSpanned = 0;
  578. nscoord cellSpacingTotal = 0;
  579. int32_t spanX;
  580. for (spanX = 0; spanX < rowSpan; spanX++) {
  581. bsizeOfRowsSpanned += rowInfo[rowIndex + spanX].bSize;
  582. if (!rowInfo[rowIndex + spanX].hasStyleBSize) {
  583. bsizeOfUnStyledRowsSpanned += rowInfo[rowIndex + spanX].bSize;
  584. }
  585. if (0 != spanX) {
  586. cellSpacingTotal += cellSpacingB;
  587. }
  588. if (rowInfo[rowIndex + spanX].isSpecial) {
  589. numSpecialRowsSpanned++;
  590. }
  591. }
  592. nscoord bsizeOfAreaSpanned = bsizeOfRowsSpanned + cellSpacingTotal;
  593. // get the bsize of the cell
  594. LogicalSize cellFrameSize = cellFrame->GetLogicalSize(wm);
  595. LogicalSize cellDesSize = cellFrame->GetDesiredSize();
  596. rowFrame->CalculateCellActualBSize(cellFrame, cellDesSize.BSize(wm), wm);
  597. cellFrameSize.BSize(wm) = cellDesSize.BSize(wm);
  598. if (cellFrame->HasVerticalAlignBaseline()) {
  599. // to ensure that a spanning cell with a long descender doesn't
  600. // collide with the next row, we need to take into account the shift
  601. // that will be done to align the cell on the baseline of the row.
  602. cellFrameSize.BSize(wm) += rowFrame->GetMaxCellAscent() -
  603. cellFrame->GetCellBaseline();
  604. }
  605. if (bsizeOfAreaSpanned < cellFrameSize.BSize(wm)) {
  606. // the cell's bsize is larger than the available space of the rows it
  607. // spans so distribute the excess bsize to the rows affected
  608. nscoord extra = cellFrameSize.BSize(wm) - bsizeOfAreaSpanned;
  609. nscoord extraUsed = 0;
  610. if (0 == numSpecialRowsSpanned) {
  611. //NS_ASSERTION(bsizeOfRowsSpanned > 0, "invalid row span situation");
  612. bool haveUnStyledRowsSpanned = (bsizeOfUnStyledRowsSpanned > 0);
  613. nscoord divisor = (haveUnStyledRowsSpanned)
  614. ? bsizeOfUnStyledRowsSpanned : bsizeOfRowsSpanned;
  615. if (divisor > 0) {
  616. for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
  617. if (!haveUnStyledRowsSpanned || !rowInfo[rowIndex + spanX].hasStyleBSize) {
  618. // The amount of additional space each row gets is proportional to its bsize
  619. float percent = ((float)rowInfo[rowIndex + spanX].bSize) / ((float)divisor);
  620. // give rows their percentage, except for the first row which gets the remainder
  621. nscoord extraForRow = (0 == spanX) ? extra - extraUsed
  622. : NSToCoordRound(((float)(extra)) * percent);
  623. extraForRow = std::min(extraForRow, extra - extraUsed);
  624. // update the row bsize
  625. UpdateBSizes(rowInfo[rowIndex + spanX], extraForRow, bSizeOfRows, bSizeOfUnStyledRows);
  626. extraUsed += extraForRow;
  627. if (extraUsed >= extra) {
  628. NS_ASSERTION((extraUsed == extra), "invalid row bsize calculation");
  629. break;
  630. }
  631. }
  632. }
  633. }
  634. else {
  635. // put everything in the last row
  636. UpdateBSizes(rowInfo[rowIndex + rowSpan - 1], extra, bSizeOfRows, bSizeOfUnStyledRows);
  637. }
  638. }
  639. else {
  640. // give the extra to the special rows
  641. nscoord numSpecialRowsAllocated = 0;
  642. for (spanX = rowSpan - 1; spanX >= 0; spanX--) {
  643. if (rowInfo[rowIndex + spanX].isSpecial) {
  644. // The amount of additional space each degenerate row gets is proportional to the number of them
  645. float percent = 1.0f / ((float)numSpecialRowsSpanned);
  646. // give rows their percentage, except for the first row which gets the remainder
  647. nscoord extraForRow = (numSpecialRowsSpanned - 1 == numSpecialRowsAllocated)
  648. ? extra - extraUsed
  649. : NSToCoordRound(((float)(extra)) * percent);
  650. extraForRow = std::min(extraForRow, extra - extraUsed);
  651. // update the row bsize
  652. UpdateBSizes(rowInfo[rowIndex + spanX], extraForRow, bSizeOfRows, bSizeOfUnStyledRows);
  653. extraUsed += extraForRow;
  654. if (extraUsed >= extra) {
  655. NS_ASSERTION((extraUsed == extra), "invalid row bsize calculation");
  656. break;
  657. }
  658. }
  659. }
  660. }
  661. }
  662. } // if (rowSpan > 1)
  663. cellFrame = cellFrame->GetNextCell();
  664. } // while (cellFrame)
  665. } // if (tableFrame->RowHasSpanningCells(startRowIndex + rowIndex) {
  666. } // while (rowFrame)
  667. }
  668. // pct bsize rows have already got their content bsizes.
  669. // Give them their pct bsizes up to pctBSizeBasis
  670. nscoord extra = pctBSizeBasis - bSizeOfRows;
  671. for (rowFrame = startRowFrame, rowIndex = 0; rowFrame && (extra > 0);
  672. rowFrame = rowFrame->GetNextRow(), rowIndex++) {
  673. RowInfo& rInfo = rowInfo[rowIndex];
  674. if (rInfo.hasPctBSize) {
  675. nscoord rowExtra = (rInfo.pctBSize > rInfo.bSize)
  676. ? rInfo.pctBSize - rInfo.bSize: 0;
  677. rowExtra = std::min(rowExtra, extra);
  678. UpdateBSizes(rInfo, rowExtra, bSizeOfRows, bSizeOfUnStyledRows);
  679. extra -= rowExtra;
  680. }
  681. }
  682. bool styleBSizeAllocation = false;
  683. nscoord rowGroupBSize = startRowGroupBSize + bSizeOfRows +
  684. tableFrame->GetRowSpacing(0, numRows-1);
  685. // if we have a style bsize, allocate the extra bsize to unconstrained rows
  686. if ((aReflowInput.ComputedBSize() > rowGroupBSize) &&
  687. (NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedBSize())) {
  688. nscoord extraComputedBSize = aReflowInput.ComputedBSize() - rowGroupBSize;
  689. nscoord extraUsed = 0;
  690. bool haveUnStyledRows = (bSizeOfUnStyledRows > 0);
  691. nscoord divisor = (haveUnStyledRows)
  692. ? bSizeOfUnStyledRows : bSizeOfRows;
  693. if (divisor > 0) {
  694. styleBSizeAllocation = true;
  695. for (rowIndex = 0; rowIndex < numRows; rowIndex++) {
  696. if (!haveUnStyledRows || !rowInfo[rowIndex].hasStyleBSize) {
  697. // The amount of additional space each row gets is based on the
  698. // percentage of space it occupies
  699. float percent = ((float)rowInfo[rowIndex].bSize) / ((float)divisor);
  700. // give rows their percentage, except for the last row which gets the remainder
  701. nscoord extraForRow = (numRows - 1 == rowIndex)
  702. ? extraComputedBSize - extraUsed
  703. : NSToCoordRound(((float)extraComputedBSize) * percent);
  704. extraForRow = std::min(extraForRow, extraComputedBSize - extraUsed);
  705. // update the row bsize
  706. UpdateBSizes(rowInfo[rowIndex], extraForRow, bSizeOfRows, bSizeOfUnStyledRows);
  707. extraUsed += extraForRow;
  708. if (extraUsed >= extraComputedBSize) {
  709. NS_ASSERTION((extraUsed == extraComputedBSize), "invalid row bsize calculation");
  710. break;
  711. }
  712. }
  713. }
  714. }
  715. rowGroupBSize = aReflowInput.ComputedBSize();
  716. }
  717. if (wm.IsVertical()) {
  718. // we need the correct containerSize below for block positioning in
  719. // vertical-rl writing mode
  720. containerSize.width = rowGroupBSize;
  721. }
  722. nscoord bOrigin = startRowGroupBSize;
  723. // update the rows with their (potentially) new bsizes
  724. for (rowFrame = startRowFrame, rowIndex = 0; rowFrame;
  725. rowFrame = rowFrame->GetNextRow(), rowIndex++) {
  726. nsRect rowBounds = rowFrame->GetRect();
  727. LogicalSize rowBoundsSize(wm, rowBounds.Size());
  728. nsRect rowVisualOverflow = rowFrame->GetVisualOverflowRect();
  729. nscoord deltaB =
  730. bOrigin - rowFrame->GetLogicalNormalPosition(wm, containerSize).B(wm);
  731. nscoord rowBSize = (rowInfo[rowIndex].bSize > 0) ? rowInfo[rowIndex].bSize : 0;
  732. if (deltaB != 0 || (rowBSize != rowBoundsSize.BSize(wm))) {
  733. // Resize/move the row to its final size and position
  734. if (deltaB != 0) {
  735. rowFrame->InvalidateFrameSubtree();
  736. }
  737. rowFrame->MovePositionBy(wm, LogicalPoint(wm, 0, deltaB));
  738. rowFrame->SetSize(LogicalSize(wm, rowBoundsSize.ISize(wm), rowBSize));
  739. nsTableFrame::InvalidateTableFrame(rowFrame, rowBounds, rowVisualOverflow,
  740. false);
  741. if (deltaB != 0) {
  742. nsTableFrame::RePositionViews(rowFrame);
  743. // XXXbz we don't need to update our overflow area?
  744. }
  745. }
  746. bOrigin += rowBSize + tableFrame->GetRowSpacing(startRowIndex + rowIndex);
  747. }
  748. if (isPaginated && styleBSizeAllocation) {
  749. // since the row group has a style bsize, cache the row bsizes,
  750. // so next in flows can honor them
  751. CacheRowBSizesForPrinting(aPresContext, GetFirstRow(), wm);
  752. }
  753. DidResizeRows(aDesiredSize);
  754. aDesiredSize.BSize(wm) = rowGroupBSize; // Adjust our desired size
  755. }
  756. nscoord
  757. nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aBTotalOffset,
  758. nscoord aISize,
  759. WritingMode aWM)
  760. {
  761. nsTableFrame* tableFrame = GetTableFrame();
  762. nsSize containerSize = tableFrame->GetSize();
  763. const nsStyleVisibility* groupVis = StyleVisibility();
  764. bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
  765. if (collapseGroup) {
  766. tableFrame->SetNeedToCollapse(true);
  767. }
  768. nsOverflowAreas overflow;
  769. nsTableRowFrame* rowFrame = GetFirstRow();
  770. bool didCollapse = false;
  771. nscoord bGroupOffset = 0;
  772. while (rowFrame) {
  773. bGroupOffset += rowFrame->CollapseRowIfNecessary(bGroupOffset,
  774. aISize, collapseGroup,
  775. didCollapse);
  776. ConsiderChildOverflow(overflow, rowFrame);
  777. rowFrame = rowFrame->GetNextRow();
  778. }
  779. LogicalRect groupRect = GetLogicalRect(aWM, containerSize);
  780. nsRect oldGroupRect = GetRect();
  781. nsRect oldGroupVisualOverflow = GetVisualOverflowRect();
  782. groupRect.BSize(aWM) -= bGroupOffset;
  783. if (didCollapse) {
  784. // add back the cellspacing between rowgroups
  785. groupRect.BSize(aWM) += tableFrame->GetRowSpacing(GetStartRowIndex() +
  786. GetRowCount());
  787. }
  788. groupRect.BStart(aWM) -= aBTotalOffset;
  789. groupRect.ISize(aWM) = aISize;
  790. if (aBTotalOffset != 0) {
  791. InvalidateFrameSubtree();
  792. }
  793. SetRect(aWM, groupRect, containerSize);
  794. overflow.UnionAllWith(nsRect(0, 0, groupRect.Width(aWM),
  795. groupRect.Height(aWM)));
  796. FinishAndStoreOverflow(overflow, groupRect.Size(aWM).GetPhysicalSize(aWM));
  797. nsTableFrame::RePositionViews(this);
  798. nsTableFrame::InvalidateTableFrame(this, oldGroupRect, oldGroupVisualOverflow,
  799. false);
  800. return bGroupOffset;
  801. }
  802. // Move a child that was skipped during a reflow.
  803. void
  804. nsTableRowGroupFrame::SlideChild(TableRowGroupReflowInput& aReflowInput,
  805. nsIFrame* aKidFrame)
  806. {
  807. // Move the frame if we need to.
  808. WritingMode wm = aReflowInput.reflowInput.GetWritingMode();
  809. const nsSize containerSize =
  810. aReflowInput.reflowInput.ComputedSizeAsContainerIfConstrained();
  811. LogicalPoint oldPosition =
  812. aKidFrame->GetLogicalNormalPosition(wm, containerSize);
  813. LogicalPoint newPosition = oldPosition;
  814. newPosition.B(wm) = aReflowInput.bCoord;
  815. if (oldPosition.B(wm) != newPosition.B(wm)) {
  816. aKidFrame->InvalidateFrameSubtree();
  817. aReflowInput.reflowInput.ApplyRelativePositioning(&newPosition,
  818. containerSize);
  819. aKidFrame->SetPosition(wm, newPosition, containerSize);
  820. nsTableFrame::RePositionViews(aKidFrame);
  821. aKidFrame->InvalidateFrameSubtree();
  822. }
  823. }
  824. // Create a continuing frame, add it to the child list, and then push it
  825. // and the frames that follow
  826. void
  827. nsTableRowGroupFrame::CreateContinuingRowFrame(nsPresContext& aPresContext,
  828. nsIFrame& aRowFrame,
  829. nsIFrame** aContRowFrame)
  830. {
  831. // XXX what is the row index?
  832. if (!aContRowFrame) {NS_ASSERTION(false, "bad call"); return;}
  833. // create the continuing frame which will create continuing cell frames
  834. *aContRowFrame = aPresContext.PresShell()->FrameConstructor()->
  835. CreateContinuingFrame(&aPresContext, &aRowFrame, this);
  836. // Add the continuing row frame to the child list
  837. mFrames.InsertFrame(nullptr, &aRowFrame, *aContRowFrame);
  838. // Push the continuing row frame and the frames that follow
  839. PushChildren(*aContRowFrame, &aRowFrame);
  840. }
  841. // Reflow the cells with rowspan > 1 which originate between aFirstRow
  842. // and end on or after aLastRow. aFirstTruncatedRow is the highest row on the
  843. // page that contains a cell which cannot split on this page
  844. void
  845. nsTableRowGroupFrame::SplitSpanningCells(nsPresContext& aPresContext,
  846. const ReflowInput& aReflowInput,
  847. nsTableFrame& aTable,
  848. nsTableRowFrame& aFirstRow,
  849. nsTableRowFrame& aLastRow,
  850. bool aFirstRowIsTopOfPage,
  851. nscoord aSpanningRowBEnd,
  852. nsTableRowFrame*& aContRow,
  853. nsTableRowFrame*& aFirstTruncatedRow,
  854. nscoord& aDesiredBSize)
  855. {
  856. NS_ASSERTION(aSpanningRowBEnd >= 0, "Can't split negative bsizes");
  857. aFirstTruncatedRow = nullptr;
  858. aDesiredBSize = 0;
  859. const bool borderCollapse = aTable.IsBorderCollapse();
  860. int32_t lastRowIndex = aLastRow.GetRowIndex();
  861. bool wasLast = false;
  862. bool haveRowSpan = false;
  863. // Iterate the rows between aFirstRow and aLastRow
  864. for (nsTableRowFrame* row = &aFirstRow; !wasLast; row = row->GetNextRow()) {
  865. wasLast = (row == &aLastRow);
  866. int32_t rowIndex = row->GetRowIndex();
  867. nsPoint rowPos = row->GetNormalPosition();
  868. // Iterate the cells looking for those that have rowspan > 1
  869. for (nsTableCellFrame* cell = row->GetFirstCell(); cell; cell = cell->GetNextCell()) {
  870. int32_t rowSpan = aTable.GetEffectiveRowSpan(rowIndex, *cell);
  871. // Only reflow rowspan > 1 cells which span aLastRow. Those which don't span aLastRow
  872. // were reflowed correctly during the unconstrained bsize reflow.
  873. if ((rowSpan > 1) && (rowIndex + rowSpan > lastRowIndex)) {
  874. haveRowSpan = true;
  875. nsReflowStatus status;
  876. // Ask the row to reflow the cell to the bsize of all the rows it spans up through aLastRow
  877. // cellAvailBSize is the space between the row group start and the end of the page
  878. nscoord cellAvailBSize = aSpanningRowBEnd - rowPos.y;
  879. NS_ASSERTION(cellAvailBSize >= 0, "No space for cell?");
  880. bool isTopOfPage = (row == &aFirstRow) && aFirstRowIsTopOfPage;
  881. nsRect rowRect = row->GetNormalRect();
  882. nsSize rowAvailSize(aReflowInput.AvailableWidth(),
  883. std::max(aReflowInput.AvailableHeight() - rowRect.y,
  884. 0));
  885. // don't let the available height exceed what
  886. // CalculateRowBSizes set for it
  887. rowAvailSize.height = std::min(rowAvailSize.height, rowRect.height);
  888. ReflowInput rowReflowInput(&aPresContext, aReflowInput, row,
  889. LogicalSize(row->GetWritingMode(),
  890. rowAvailSize),
  891. nullptr,
  892. ReflowInput::CALLER_WILL_INIT);
  893. InitChildReflowInput(aPresContext, borderCollapse, rowReflowInput);
  894. rowReflowInput.mFlags.mIsTopOfPage = isTopOfPage; // set top of page
  895. nscoord cellBSize = row->ReflowCellFrame(&aPresContext, rowReflowInput,
  896. isTopOfPage, cell,
  897. cellAvailBSize, status);
  898. aDesiredBSize = std::max(aDesiredBSize, rowPos.y + cellBSize);
  899. if (NS_FRAME_IS_COMPLETE(status)) {
  900. if (cellBSize > cellAvailBSize) {
  901. aFirstTruncatedRow = row;
  902. if ((row != &aFirstRow) || !aFirstRowIsTopOfPage) {
  903. // return now, since we will be getting another reflow after either (1) row is
  904. // moved to the next page or (2) the row group is moved to the next page
  905. return;
  906. }
  907. }
  908. }
  909. else {
  910. if (!aContRow) {
  911. CreateContinuingRowFrame(aPresContext, aLastRow, (nsIFrame**)&aContRow);
  912. }
  913. if (aContRow) {
  914. if (row != &aLastRow) {
  915. // aContRow needs a continuation for cell, since cell spanned into aLastRow
  916. // but does not originate there
  917. nsTableCellFrame* contCell = static_cast<nsTableCellFrame*>(
  918. aPresContext.PresShell()->FrameConstructor()->
  919. CreateContinuingFrame(&aPresContext, cell, &aLastRow));
  920. uint32_t colIndex = cell->ColIndex();
  921. aContRow->InsertCellFrame(contCell, colIndex);
  922. }
  923. }
  924. }
  925. }
  926. }
  927. }
  928. if (!haveRowSpan) {
  929. aDesiredBSize = aLastRow.GetNormalRect().YMost();
  930. }
  931. }
  932. // Remove the next-in-flow of the row, its cells and their cell blocks. This
  933. // is necessary in case the row doesn't need a continuation later on or needs
  934. // a continuation which doesn't have the same number of cells that now exist.
  935. void
  936. nsTableRowGroupFrame::UndoContinuedRow(nsPresContext* aPresContext,
  937. nsTableRowFrame* aRow)
  938. {
  939. if (!aRow) return; // allow null aRow to avoid callers doing null checks
  940. // rowBefore was the prev-sibling of aRow's next-sibling before aRow was created
  941. nsTableRowFrame* rowBefore = (nsTableRowFrame*)aRow->GetPrevInFlow();
  942. NS_PRECONDITION(mFrames.ContainsFrame(rowBefore),
  943. "rowBefore not in our frame list?");
  944. AutoFrameListPtr overflows(aPresContext, StealOverflowFrames());
  945. if (!rowBefore || !overflows || overflows->IsEmpty() ||
  946. overflows->FirstChild() != aRow) {
  947. NS_ERROR("invalid continued row");
  948. return;
  949. }
  950. // Destroy aRow, its cells, and their cell blocks. Cell blocks that have split
  951. // will not have reflowed yet to pick up content from any overflow lines.
  952. overflows->DestroyFrame(aRow);
  953. // Put the overflow rows into our child list
  954. if (!overflows->IsEmpty()) {
  955. mFrames.InsertFrames(nullptr, rowBefore, *overflows);
  956. }
  957. }
  958. static nsTableRowFrame*
  959. GetRowBefore(nsTableRowFrame& aStartRow,
  960. nsTableRowFrame& aRow)
  961. {
  962. nsTableRowFrame* rowBefore = nullptr;
  963. for (nsTableRowFrame* sib = &aStartRow; sib && (sib != &aRow); sib = sib->GetNextRow()) {
  964. rowBefore = sib;
  965. }
  966. return rowBefore;
  967. }
  968. nsresult
  969. nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext,
  970. ReflowOutput& aDesiredSize,
  971. const ReflowInput& aReflowInput,
  972. nsTableFrame* aTableFrame,
  973. nsReflowStatus& aStatus,
  974. bool aRowForcedPageBreak)
  975. {
  976. NS_PRECONDITION(aPresContext->IsPaginated(), "SplitRowGroup currently supports only paged media");
  977. nsTableRowFrame* prevRowFrame = nullptr;
  978. aDesiredSize.Height() = 0;
  979. nscoord availWidth = aReflowInput.AvailableWidth();
  980. nscoord availHeight = aReflowInput.AvailableHeight();
  981. const bool borderCollapse = aTableFrame->IsBorderCollapse();
  982. // get the page height
  983. nscoord pageHeight = aPresContext->GetPageSize().height;
  984. NS_ASSERTION(pageHeight != NS_UNCONSTRAINEDSIZE,
  985. "The table shouldn't be split when there should be space");
  986. bool isTopOfPage = aReflowInput.mFlags.mIsTopOfPage;
  987. nsTableRowFrame* firstRowThisPage = GetFirstRow();
  988. // Need to dirty the table's geometry, or else the row might skip
  989. // reflowing its cell as an optimization.
  990. aTableFrame->SetGeometryDirty();
  991. // Walk each of the row frames looking for the first row frame that doesn't fit
  992. // in the available space
  993. for (nsTableRowFrame* rowFrame = firstRowThisPage; rowFrame; rowFrame = rowFrame->GetNextRow()) {
  994. bool rowIsOnPage = true;
  995. nscoord cellSpacingB = aTableFrame->GetRowSpacing(rowFrame->GetRowIndex());
  996. nsRect rowRect = rowFrame->GetNormalRect();
  997. // See if the row fits on this page
  998. if (rowRect.YMost() > availHeight) {
  999. nsTableRowFrame* contRow = nullptr;
  1000. // Reflow the row in the availabe space and have it split if it is the 1st
  1001. // row (on the page) or there is at least 5% of the current page available
  1002. // XXX this 5% should be made a preference
  1003. if (!prevRowFrame || (availHeight - aDesiredSize.Height() > pageHeight / 20)) {
  1004. nsSize availSize(availWidth, std::max(availHeight - rowRect.y, 0));
  1005. // don't let the available height exceed what CalculateRowHeights set for it
  1006. availSize.height = std::min(availSize.height, rowRect.height);
  1007. ReflowInput rowReflowInput(aPresContext, aReflowInput, rowFrame,
  1008. LogicalSize(rowFrame->GetWritingMode(),
  1009. availSize),
  1010. nullptr,
  1011. ReflowInput::CALLER_WILL_INIT);
  1012. InitChildReflowInput(*aPresContext, borderCollapse, rowReflowInput);
  1013. rowReflowInput.mFlags.mIsTopOfPage = isTopOfPage; // set top of page
  1014. ReflowOutput rowMetrics(aReflowInput);
  1015. // Get the old size before we reflow.
  1016. nsRect oldRowRect = rowFrame->GetRect();
  1017. nsRect oldRowVisualOverflow = rowFrame->GetVisualOverflowRect();
  1018. // Reflow the cell with the constrained height. A cell with rowspan >1 will get this
  1019. // reflow later during SplitSpanningCells.
  1020. ReflowChild(rowFrame, aPresContext, rowMetrics, rowReflowInput,
  1021. 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
  1022. rowFrame->SetSize(nsSize(rowMetrics.Width(), rowMetrics.Height()));
  1023. rowFrame->DidReflow(aPresContext, nullptr, nsDidReflowStatus::FINISHED);
  1024. rowFrame->DidResize();
  1025. if (!aRowForcedPageBreak && !NS_FRAME_IS_FULLY_COMPLETE(aStatus) &&
  1026. ShouldAvoidBreakInside(aReflowInput)) {
  1027. aStatus = NS_INLINE_LINE_BREAK_BEFORE();
  1028. break;
  1029. }
  1030. nsTableFrame::InvalidateTableFrame(rowFrame, oldRowRect,
  1031. oldRowVisualOverflow,
  1032. false);
  1033. if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
  1034. // The row frame is incomplete and all of the rowspan 1 cells' block frames split
  1035. if ((rowMetrics.Height() <= rowReflowInput.AvailableHeight()) || isTopOfPage) {
  1036. // The row stays on this page because either it split ok or we're on the top of page.
  1037. // If top of page and the height exceeded the avail height, then there will be data loss
  1038. NS_ASSERTION(rowMetrics.Height() <= rowReflowInput.AvailableHeight(),
  1039. "data loss - incomplete row needed more height than available, on top of page");
  1040. CreateContinuingRowFrame(*aPresContext, *rowFrame, (nsIFrame**)&contRow);
  1041. if (contRow) {
  1042. aDesiredSize.Height() += rowMetrics.Height();
  1043. if (prevRowFrame)
  1044. aDesiredSize.Height() += cellSpacingB;
  1045. }
  1046. else return NS_ERROR_NULL_POINTER;
  1047. }
  1048. else {
  1049. // Put the row on the next page to give it more height
  1050. rowIsOnPage = false;
  1051. }
  1052. }
  1053. else {
  1054. // The row frame is complete because either (1) its minimum height is greater than the
  1055. // available height we gave it, or (2) it may have been given a larger height through
  1056. // style than its content, or (3) it contains a rowspan >1 cell which hasn't been
  1057. // reflowed with a constrained height yet (we will find out when SplitSpanningCells is
  1058. // called below)
  1059. if (rowMetrics.Height() > availSize.height ||
  1060. (NS_INLINE_IS_BREAK_BEFORE(aStatus) && !aRowForcedPageBreak)) {
  1061. // cases (1) and (2)
  1062. if (isTopOfPage) {
  1063. // We're on top of the page, so keep the row on this page. There will be data loss.
  1064. // Push the row frame that follows
  1065. nsTableRowFrame* nextRowFrame = rowFrame->GetNextRow();
  1066. if (nextRowFrame) {
  1067. aStatus = NS_FRAME_NOT_COMPLETE;
  1068. }
  1069. aDesiredSize.Height() += rowMetrics.Height();
  1070. if (prevRowFrame)
  1071. aDesiredSize.Height() += cellSpacingB;
  1072. NS_WARNING("data loss - complete row needed more height than available, on top of page");
  1073. }
  1074. else {
  1075. // We're not on top of the page, so put the row on the next page to give it more height
  1076. rowIsOnPage = false;
  1077. }
  1078. }
  1079. }
  1080. } //if (!prevRowFrame || (availHeight - aDesiredSize.Height() > pageHeight / 20))
  1081. else {
  1082. // put the row on the next page to give it more height
  1083. rowIsOnPage = false;
  1084. }
  1085. nsTableRowFrame* lastRowThisPage = rowFrame;
  1086. nscoord spanningRowBottom = availHeight;
  1087. if (!rowIsOnPage) {
  1088. NS_ASSERTION(!contRow, "We should not have created a continuation if none of this row fits");
  1089. if (!aRowForcedPageBreak && ShouldAvoidBreakInside(aReflowInput)) {
  1090. aStatus = NS_INLINE_LINE_BREAK_BEFORE();
  1091. break;
  1092. }
  1093. if (prevRowFrame) {
  1094. spanningRowBottom = prevRowFrame->GetNormalRect().YMost();
  1095. lastRowThisPage = prevRowFrame;
  1096. isTopOfPage = (lastRowThisPage == firstRowThisPage) && aReflowInput.mFlags.mIsTopOfPage;
  1097. aStatus = NS_FRAME_NOT_COMPLETE;
  1098. }
  1099. else {
  1100. // We can't push children, so let our parent reflow us again with more space
  1101. aDesiredSize.Height() = rowRect.YMost();
  1102. aStatus = NS_FRAME_COMPLETE;
  1103. break;
  1104. }
  1105. }
  1106. // reflow the cells with rowspan >1 that occur on the page
  1107. nsTableRowFrame* firstTruncatedRow;
  1108. nscoord bMost;
  1109. SplitSpanningCells(*aPresContext, aReflowInput, *aTableFrame, *firstRowThisPage,
  1110. *lastRowThisPage, aReflowInput.mFlags.mIsTopOfPage, spanningRowBottom, contRow,
  1111. firstTruncatedRow, bMost);
  1112. if (firstTruncatedRow) {
  1113. // A rowspan >1 cell did not fit (and could not split) in the space we gave it
  1114. if (firstTruncatedRow == firstRowThisPage) {
  1115. if (aReflowInput.mFlags.mIsTopOfPage) {
  1116. NS_WARNING("data loss in a row spanned cell");
  1117. }
  1118. else {
  1119. // We can't push children, so let our parent reflow us again with more space
  1120. aDesiredSize.Height() = rowRect.YMost();
  1121. aStatus = NS_FRAME_COMPLETE;
  1122. UndoContinuedRow(aPresContext, contRow);
  1123. contRow = nullptr;
  1124. }
  1125. }
  1126. else { // (firstTruncatedRow != firstRowThisPage)
  1127. // Try to put firstTruncateRow on the next page
  1128. nsTableRowFrame* rowBefore = ::GetRowBefore(*firstRowThisPage, *firstTruncatedRow);
  1129. nscoord oldSpanningRowBottom = spanningRowBottom;
  1130. spanningRowBottom = rowBefore->GetNormalRect().YMost();
  1131. UndoContinuedRow(aPresContext, contRow);
  1132. contRow = nullptr;
  1133. nsTableRowFrame* oldLastRowThisPage = lastRowThisPage;
  1134. lastRowThisPage = rowBefore;
  1135. aStatus = NS_FRAME_NOT_COMPLETE;
  1136. // Call SplitSpanningCells again with rowBefore as the last row on the page
  1137. SplitSpanningCells(*aPresContext, aReflowInput, *aTableFrame,
  1138. *firstRowThisPage, *rowBefore, aReflowInput.mFlags.mIsTopOfPage,
  1139. spanningRowBottom, contRow, firstTruncatedRow, aDesiredSize.Height());
  1140. if (firstTruncatedRow) {
  1141. if (aReflowInput.mFlags.mIsTopOfPage) {
  1142. // We were better off with the 1st call to SplitSpanningCells, do it again
  1143. UndoContinuedRow(aPresContext, contRow);
  1144. contRow = nullptr;
  1145. lastRowThisPage = oldLastRowThisPage;
  1146. spanningRowBottom = oldSpanningRowBottom;
  1147. SplitSpanningCells(*aPresContext, aReflowInput, *aTableFrame, *firstRowThisPage,
  1148. *lastRowThisPage, aReflowInput.mFlags.mIsTopOfPage, spanningRowBottom, contRow,
  1149. firstTruncatedRow, aDesiredSize.Height());
  1150. NS_WARNING("data loss in a row spanned cell");
  1151. }
  1152. else {
  1153. // Let our parent reflow us again with more space
  1154. aDesiredSize.Height() = rowRect.YMost();
  1155. aStatus = NS_FRAME_COMPLETE;
  1156. UndoContinuedRow(aPresContext, contRow);
  1157. contRow = nullptr;
  1158. }
  1159. }
  1160. } // if (firstTruncatedRow == firstRowThisPage)
  1161. } // if (firstTruncatedRow)
  1162. else {
  1163. aDesiredSize.Height() = std::max(aDesiredSize.Height(), bMost);
  1164. if (contRow) {
  1165. aStatus = NS_FRAME_NOT_COMPLETE;
  1166. }
  1167. }
  1168. if (NS_FRAME_IS_NOT_COMPLETE(aStatus) && !contRow) {
  1169. nsTableRowFrame* nextRow = lastRowThisPage->GetNextRow();
  1170. if (nextRow) {
  1171. PushChildren(nextRow, lastRowThisPage);
  1172. }
  1173. }
  1174. break;
  1175. } // if (rowRect.YMost() > availHeight)
  1176. else {
  1177. aDesiredSize.Height() = rowRect.YMost();
  1178. prevRowFrame = rowFrame;
  1179. // see if there is a page break after the row
  1180. nsTableRowFrame* nextRow = rowFrame->GetNextRow();
  1181. if (nextRow && nsTableFrame::PageBreakAfter(rowFrame, nextRow)) {
  1182. PushChildren(nextRow, rowFrame);
  1183. aStatus = NS_FRAME_NOT_COMPLETE;
  1184. break;
  1185. }
  1186. }
  1187. // after the 1st row that has a height, we can't be on top
  1188. // of the page anymore.
  1189. isTopOfPage = isTopOfPage && rowRect.YMost() == 0;
  1190. }
  1191. return NS_OK;
  1192. }
  1193. /** Layout the entire row group.
  1194. * This method stacks rows vertically according to HTML 4.0 rules.
  1195. * Rows are responsible for layout of their children.
  1196. */
  1197. void
  1198. nsTableRowGroupFrame::Reflow(nsPresContext* aPresContext,
  1199. ReflowOutput& aDesiredSize,
  1200. const ReflowInput& aReflowInput,
  1201. nsReflowStatus& aStatus)
  1202. {
  1203. MarkInReflow();
  1204. DO_GLOBAL_REFLOW_COUNT("nsTableRowGroupFrame");
  1205. DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
  1206. aStatus = NS_FRAME_COMPLETE;
  1207. // Row geometry may be going to change so we need to invalidate any row cursor.
  1208. ClearRowCursor();
  1209. // see if a special bsize reflow needs to occur due to having a pct bsize
  1210. nsTableFrame::CheckRequestSpecialBSizeReflow(aReflowInput);
  1211. nsTableFrame* tableFrame = GetTableFrame();
  1212. TableRowGroupReflowInput state(aReflowInput, tableFrame);
  1213. const nsStyleVisibility* groupVis = StyleVisibility();
  1214. bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
  1215. if (collapseGroup) {
  1216. tableFrame->SetNeedToCollapse(true);
  1217. }
  1218. // Check for an overflow list
  1219. MoveOverflowToChildList();
  1220. // Reflow the existing frames.
  1221. bool splitDueToPageBreak = false;
  1222. ReflowChildren(aPresContext, aDesiredSize, state, aStatus,
  1223. &splitDueToPageBreak);
  1224. // See if all the frames fit. Do not try to split anything if we're
  1225. // not paginated ... we can't split across columns yet.
  1226. if (aReflowInput.mFlags.mTableIsSplittable &&
  1227. NS_UNCONSTRAINEDSIZE != aReflowInput.AvailableHeight() &&
  1228. (NS_FRAME_NOT_COMPLETE == aStatus || splitDueToPageBreak ||
  1229. aDesiredSize.Height() > aReflowInput.AvailableHeight())) {
  1230. // Nope, find a place to split the row group
  1231. bool specialReflow = (bool)aReflowInput.mFlags.mSpecialBSizeReflow;
  1232. ((ReflowInput::ReflowInputFlags&)aReflowInput.mFlags).mSpecialBSizeReflow = false;
  1233. SplitRowGroup(aPresContext, aDesiredSize, aReflowInput, tableFrame, aStatus,
  1234. splitDueToPageBreak);
  1235. ((ReflowInput::ReflowInputFlags&)aReflowInput.mFlags).mSpecialBSizeReflow = specialReflow;
  1236. }
  1237. // XXXmats The following is just bogus. We leave it here for now because
  1238. // ReflowChildren should pull up rows from our next-in-flow before returning
  1239. // a Complete status, but doesn't (bug 804888).
  1240. if (GetNextInFlow() && GetNextInFlow()->PrincipalChildList().FirstChild()) {
  1241. NS_FRAME_SET_INCOMPLETE(aStatus);
  1242. }
  1243. SetHasStyleBSize((NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedBSize()) &&
  1244. (aReflowInput.ComputedBSize() > 0));
  1245. // Just set our isize to what was available.
  1246. // The table will calculate the isize and not use our value.
  1247. WritingMode wm = aReflowInput.GetWritingMode();
  1248. aDesiredSize.ISize(wm) = aReflowInput.AvailableISize();
  1249. aDesiredSize.UnionOverflowAreasWithDesiredBounds();
  1250. // If our parent is in initial reflow, it'll handle invalidating our
  1251. // entire overflow rect.
  1252. if (!GetParent()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW) &&
  1253. nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
  1254. InvalidateFrame();
  1255. }
  1256. FinishAndStoreOverflow(&aDesiredSize);
  1257. // Any absolutely-positioned children will get reflowed in
  1258. // nsFrame::FixupPositionedTableParts in another pass, so propagate our
  1259. // dirtiness to them before our parent clears our dirty bits.
  1260. PushDirtyBitToAbsoluteFrames();
  1261. NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
  1262. }
  1263. bool
  1264. nsTableRowGroupFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas)
  1265. {
  1266. // Row cursor invariants depend on the visual overflow area of the rows,
  1267. // which may have changed, so we need to clear the cursor now.
  1268. ClearRowCursor();
  1269. return nsContainerFrame::ComputeCustomOverflow(aOverflowAreas);
  1270. }
  1271. /* virtual */ void
  1272. nsTableRowGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
  1273. {
  1274. nsContainerFrame::DidSetStyleContext(aOldStyleContext);
  1275. if (!aOldStyleContext) //avoid this on init
  1276. return;
  1277. nsTableFrame* tableFrame = GetTableFrame();
  1278. if (tableFrame->IsBorderCollapse() &&
  1279. tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
  1280. TableArea damageArea(0, GetStartRowIndex(), tableFrame->GetColCount(),
  1281. GetRowCount());
  1282. tableFrame->AddBCDamageArea(damageArea);
  1283. }
  1284. }
  1285. void
  1286. nsTableRowGroupFrame::AppendFrames(ChildListID aListID,
  1287. nsFrameList& aFrameList)
  1288. {
  1289. NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
  1290. DrainSelfOverflowList(); // ensure the last frame is in mFrames
  1291. ClearRowCursor();
  1292. // collect the new row frames in an array
  1293. // XXXbz why are we doing the QI stuff? There shouldn't be any non-rows here.
  1294. AutoTArray<nsTableRowFrame*, 8> rows;
  1295. for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
  1296. nsTableRowFrame *rowFrame = do_QueryFrame(e.get());
  1297. NS_ASSERTION(rowFrame, "Unexpected frame; frame constructor screwed up");
  1298. if (rowFrame) {
  1299. NS_ASSERTION(mozilla::StyleDisplay::TableRow ==
  1300. e.get()->StyleDisplay()->mDisplay,
  1301. "wrong display type on rowframe");
  1302. rows.AppendElement(rowFrame);
  1303. }
  1304. }
  1305. int32_t rowIndex = GetRowCount();
  1306. // Append the frames to the sibling chain
  1307. mFrames.AppendFrames(nullptr, aFrameList);
  1308. if (rows.Length() > 0) {
  1309. nsTableFrame* tableFrame = GetTableFrame();
  1310. tableFrame->AppendRows(this, rowIndex, rows);
  1311. PresContext()->PresShell()->
  1312. FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1313. NS_FRAME_HAS_DIRTY_CHILDREN);
  1314. tableFrame->SetGeometryDirty();
  1315. }
  1316. }
  1317. void
  1318. nsTableRowGroupFrame::InsertFrames(ChildListID aListID,
  1319. nsIFrame* aPrevFrame,
  1320. nsFrameList& aFrameList)
  1321. {
  1322. NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
  1323. NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
  1324. "inserting after sibling frame with different parent");
  1325. DrainSelfOverflowList(); // ensure aPrevFrame is in mFrames
  1326. ClearRowCursor();
  1327. // collect the new row frames in an array
  1328. // XXXbz why are we doing the QI stuff? There shouldn't be any non-rows here.
  1329. nsTableFrame* tableFrame = GetTableFrame();
  1330. nsTArray<nsTableRowFrame*> rows;
  1331. bool gotFirstRow = false;
  1332. for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
  1333. nsTableRowFrame *rowFrame = do_QueryFrame(e.get());
  1334. NS_ASSERTION(rowFrame, "Unexpected frame; frame constructor screwed up");
  1335. if (rowFrame) {
  1336. NS_ASSERTION(mozilla::StyleDisplay::TableRow ==
  1337. e.get()->StyleDisplay()->mDisplay,
  1338. "wrong display type on rowframe");
  1339. rows.AppendElement(rowFrame);
  1340. if (!gotFirstRow) {
  1341. rowFrame->SetFirstInserted(true);
  1342. gotFirstRow = true;
  1343. tableFrame->SetRowInserted(true);
  1344. }
  1345. }
  1346. }
  1347. int32_t startRowIndex = GetStartRowIndex();
  1348. // Insert the frames in the sibling chain
  1349. mFrames.InsertFrames(nullptr, aPrevFrame, aFrameList);
  1350. int32_t numRows = rows.Length();
  1351. if (numRows > 0) {
  1352. nsTableRowFrame* prevRow = (nsTableRowFrame *)nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame, nsGkAtoms::tableRowFrame);
  1353. int32_t rowIndex = (prevRow) ? prevRow->GetRowIndex() + 1 : startRowIndex;
  1354. tableFrame->InsertRows(this, rows, rowIndex, true);
  1355. PresContext()->PresShell()->
  1356. FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1357. NS_FRAME_HAS_DIRTY_CHILDREN);
  1358. tableFrame->SetGeometryDirty();
  1359. }
  1360. }
  1361. void
  1362. nsTableRowGroupFrame::RemoveFrame(ChildListID aListID,
  1363. nsIFrame* aOldFrame)
  1364. {
  1365. NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
  1366. ClearRowCursor();
  1367. // XXX why are we doing the QI stuff? There shouldn't be any non-rows here.
  1368. nsTableRowFrame* rowFrame = do_QueryFrame(aOldFrame);
  1369. if (rowFrame) {
  1370. nsTableFrame* tableFrame = GetTableFrame();
  1371. // remove the rows from the table (and flag a rebalance)
  1372. tableFrame->RemoveRows(*rowFrame, 1, true);
  1373. PresContext()->PresShell()->
  1374. FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  1375. NS_FRAME_HAS_DIRTY_CHILDREN);
  1376. tableFrame->SetGeometryDirty();
  1377. }
  1378. mFrames.DestroyFrame(aOldFrame);
  1379. }
  1380. /* virtual */ nsMargin
  1381. nsTableRowGroupFrame::GetUsedMargin() const
  1382. {
  1383. return nsMargin(0,0,0,0);
  1384. }
  1385. /* virtual */ nsMargin
  1386. nsTableRowGroupFrame::GetUsedBorder() const
  1387. {
  1388. return nsMargin(0,0,0,0);
  1389. }
  1390. /* virtual */ nsMargin
  1391. nsTableRowGroupFrame::GetUsedPadding() const
  1392. {
  1393. return nsMargin(0,0,0,0);
  1394. }
  1395. nscoord
  1396. nsTableRowGroupFrame::GetBSizeBasis(const ReflowInput& aReflowInput)
  1397. {
  1398. nscoord result = 0;
  1399. nsTableFrame* tableFrame = GetTableFrame();
  1400. int32_t startRowIndex = GetStartRowIndex();
  1401. if ((aReflowInput.ComputedBSize() > 0) && (aReflowInput.ComputedBSize() < NS_UNCONSTRAINEDSIZE)) {
  1402. nscoord cellSpacing = tableFrame->GetRowSpacing(startRowIndex,
  1403. std::max(startRowIndex,
  1404. startRowIndex + GetRowCount() - 1));
  1405. result = aReflowInput.ComputedBSize() - cellSpacing;
  1406. }
  1407. else {
  1408. const ReflowInput* parentRI = aReflowInput.mParentReflowInput;
  1409. if (parentRI && (tableFrame != parentRI->mFrame)) {
  1410. parentRI = parentRI->mParentReflowInput;
  1411. }
  1412. if (parentRI && (tableFrame == parentRI->mFrame) &&
  1413. (parentRI->ComputedBSize() > 0) && (parentRI->ComputedBSize() < NS_UNCONSTRAINEDSIZE)) {
  1414. nscoord cellSpacing = tableFrame->GetRowSpacing(-1, tableFrame->GetRowCount());
  1415. result = parentRI->ComputedBSize() - cellSpacing;
  1416. }
  1417. }
  1418. return result;
  1419. }
  1420. bool
  1421. nsTableRowGroupFrame::IsSimpleRowFrame(nsTableFrame* aTableFrame,
  1422. nsTableRowFrame* aRowFrame)
  1423. {
  1424. int32_t rowIndex = aRowFrame->GetRowIndex();
  1425. // It's a simple row frame if there are no cells that span into or
  1426. // across the row
  1427. int32_t numEffCols = aTableFrame->GetEffectiveColCount();
  1428. if (!aTableFrame->RowIsSpannedInto(rowIndex, numEffCols) &&
  1429. !aTableFrame->RowHasSpanningCells(rowIndex, numEffCols)) {
  1430. return true;
  1431. }
  1432. return false;
  1433. }
  1434. nsIAtom*
  1435. nsTableRowGroupFrame::GetType() const
  1436. {
  1437. return nsGkAtoms::tableRowGroupFrame;
  1438. }
  1439. /** find page break before the first row **/
  1440. bool
  1441. nsTableRowGroupFrame::HasInternalBreakBefore() const
  1442. {
  1443. nsIFrame* firstChild = mFrames.FirstChild();
  1444. if (!firstChild)
  1445. return false;
  1446. return firstChild->StyleDisplay()->mBreakBefore;
  1447. }
  1448. /** find page break after the last row **/
  1449. bool
  1450. nsTableRowGroupFrame::HasInternalBreakAfter() const
  1451. {
  1452. nsIFrame* lastChild = mFrames.LastChild();
  1453. if (!lastChild)
  1454. return false;
  1455. return lastChild->StyleDisplay()->mBreakAfter;
  1456. }
  1457. /* ----- global methods ----- */
  1458. nsTableRowGroupFrame*
  1459. NS_NewTableRowGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  1460. {
  1461. return new (aPresShell) nsTableRowGroupFrame(aContext);
  1462. }
  1463. NS_IMPL_FRAMEARENA_HELPERS(nsTableRowGroupFrame)
  1464. #ifdef DEBUG_FRAME_DUMP
  1465. nsresult
  1466. nsTableRowGroupFrame::GetFrameName(nsAString& aResult) const
  1467. {
  1468. return MakeFrameName(NS_LITERAL_STRING("TableRowGroup"), aResult);
  1469. }
  1470. #endif
  1471. LogicalMargin
  1472. nsTableRowGroupFrame::GetBCBorderWidth(WritingMode aWM)
  1473. {
  1474. LogicalMargin border(aWM);
  1475. nsTableRowFrame* firstRowFrame = nullptr;
  1476. nsTableRowFrame* lastRowFrame = nullptr;
  1477. for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
  1478. if (!firstRowFrame) {
  1479. firstRowFrame = rowFrame;
  1480. }
  1481. lastRowFrame = rowFrame;
  1482. }
  1483. if (firstRowFrame) {
  1484. border.BStart(aWM) = nsPresContext::
  1485. CSSPixelsToAppUnits(firstRowFrame->GetBStartBCBorderWidth());
  1486. border.BEnd(aWM) = nsPresContext::
  1487. CSSPixelsToAppUnits(lastRowFrame->GetBEndBCBorderWidth());
  1488. }
  1489. return border;
  1490. }
  1491. void nsTableRowGroupFrame::SetContinuousBCBorderWidth(LogicalSide aForSide,
  1492. BCPixelSize aPixelValue)
  1493. {
  1494. switch (aForSide) {
  1495. case eLogicalSideIEnd:
  1496. mIEndContBorderWidth = aPixelValue;
  1497. return;
  1498. case eLogicalSideBEnd:
  1499. mBEndContBorderWidth = aPixelValue;
  1500. return;
  1501. case eLogicalSideIStart:
  1502. mIStartContBorderWidth = aPixelValue;
  1503. return;
  1504. default:
  1505. NS_ERROR("invalid LogicalSide argument");
  1506. }
  1507. }
  1508. //nsILineIterator methods
  1509. int32_t
  1510. nsTableRowGroupFrame::GetNumLines()
  1511. {
  1512. return GetRowCount();
  1513. }
  1514. bool
  1515. nsTableRowGroupFrame::GetDirection()
  1516. {
  1517. return (NS_STYLE_DIRECTION_RTL ==
  1518. GetTableFrame()->StyleVisibility()->mDirection);
  1519. }
  1520. NS_IMETHODIMP
  1521. nsTableRowGroupFrame::GetLine(int32_t aLineNumber,
  1522. nsIFrame** aFirstFrameOnLine,
  1523. int32_t* aNumFramesOnLine,
  1524. nsRect& aLineBounds)
  1525. {
  1526. NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);
  1527. NS_ENSURE_ARG_POINTER(aNumFramesOnLine);
  1528. nsTableFrame* table = GetTableFrame();
  1529. nsTableCellMap* cellMap = table->GetCellMap();
  1530. *aFirstFrameOnLine = nullptr;
  1531. *aNumFramesOnLine = 0;
  1532. aLineBounds.SetRect(0, 0, 0, 0);
  1533. if ((aLineNumber < 0) || (aLineNumber >= GetRowCount())) {
  1534. return NS_OK;
  1535. }
  1536. aLineNumber += GetStartRowIndex();
  1537. *aNumFramesOnLine = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
  1538. if (*aNumFramesOnLine == 0) {
  1539. return NS_OK;
  1540. }
  1541. int32_t colCount = table->GetColCount();
  1542. for (int32_t i = 0; i < colCount; i++) {
  1543. CellData* data = cellMap->GetDataAt(aLineNumber, i);
  1544. if (data && data->IsOrig()) {
  1545. *aFirstFrameOnLine = (nsIFrame*)data->GetCellFrame();
  1546. nsIFrame* parent = (*aFirstFrameOnLine)->GetParent();
  1547. aLineBounds = parent->GetRect();
  1548. return NS_OK;
  1549. }
  1550. }
  1551. NS_ERROR("cellmap is lying");
  1552. return NS_ERROR_FAILURE;
  1553. }
  1554. int32_t
  1555. nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame, int32_t aStartLine)
  1556. {
  1557. NS_ENSURE_TRUE(aFrame, -1);
  1558. nsTableRowFrame *rowFrame = do_QueryFrame(aFrame);
  1559. NS_ASSERTION(rowFrame, "RowGroup contains a frame that is not a row");
  1560. int32_t rowIndexInGroup = rowFrame->GetRowIndex() - GetStartRowIndex();
  1561. return rowIndexInGroup >= aStartLine ? rowIndexInGroup : -1;
  1562. }
  1563. NS_IMETHODIMP
  1564. nsTableRowGroupFrame::CheckLineOrder(int32_t aLine,
  1565. bool *aIsReordered,
  1566. nsIFrame **aFirstVisual,
  1567. nsIFrame **aLastVisual)
  1568. {
  1569. *aIsReordered = false;
  1570. *aFirstVisual = nullptr;
  1571. *aLastVisual = nullptr;
  1572. return NS_OK;
  1573. }
  1574. NS_IMETHODIMP
  1575. nsTableRowGroupFrame::FindFrameAt(int32_t aLineNumber,
  1576. nsPoint aPos,
  1577. nsIFrame** aFrameFound,
  1578. bool* aPosIsBeforeFirstFrame,
  1579. bool* aPosIsAfterLastFrame)
  1580. {
  1581. nsTableFrame* table = GetTableFrame();
  1582. nsTableCellMap* cellMap = table->GetCellMap();
  1583. WritingMode wm = table->GetWritingMode();
  1584. nsSize containerSize = table->GetSize();
  1585. LogicalPoint pos(wm, aPos, containerSize);
  1586. *aFrameFound = nullptr;
  1587. *aPosIsBeforeFirstFrame = true;
  1588. *aPosIsAfterLastFrame = false;
  1589. aLineNumber += GetStartRowIndex();
  1590. int32_t numCells = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
  1591. if (numCells == 0) {
  1592. return NS_OK;
  1593. }
  1594. nsIFrame* frame = nullptr;
  1595. int32_t colCount = table->GetColCount();
  1596. for (int32_t i = 0; i < colCount; i++) {
  1597. CellData* data = cellMap->GetDataAt(aLineNumber, i);
  1598. if (data && data->IsOrig()) {
  1599. frame = (nsIFrame*)data->GetCellFrame();
  1600. break;
  1601. }
  1602. }
  1603. NS_ASSERTION(frame, "cellmap is lying");
  1604. bool isRTL = (NS_STYLE_DIRECTION_RTL ==
  1605. table->StyleVisibility()->mDirection);
  1606. nsIFrame* closestFromStart = nullptr;
  1607. nsIFrame* closestFromEnd = nullptr;
  1608. int32_t n = numCells;
  1609. nsIFrame* firstFrame = frame;
  1610. while (n--) {
  1611. LogicalRect rect = frame->GetLogicalRect(wm, containerSize);
  1612. if (rect.ISize(wm) > 0) {
  1613. // If pos.I() is inside this frame - this is it
  1614. if (rect.IStart(wm) <= pos.I(wm) && rect.IEnd(wm) > pos.I(wm)) {
  1615. closestFromStart = closestFromEnd = frame;
  1616. break;
  1617. }
  1618. if (rect.IStart(wm) < pos.I(wm)) {
  1619. if (!closestFromStart ||
  1620. rect.IEnd(wm) > closestFromStart->
  1621. GetLogicalRect(wm, containerSize).IEnd(wm))
  1622. closestFromStart = frame;
  1623. }
  1624. else {
  1625. if (!closestFromEnd ||
  1626. rect.IStart(wm) < closestFromEnd->
  1627. GetLogicalRect(wm, containerSize).IStart(wm))
  1628. closestFromEnd = frame;
  1629. }
  1630. }
  1631. frame = frame->GetNextSibling();
  1632. }
  1633. if (!closestFromStart && !closestFromEnd) {
  1634. // All frames were zero-width. Just take the first one.
  1635. closestFromStart = closestFromEnd = firstFrame;
  1636. }
  1637. *aPosIsBeforeFirstFrame = isRTL ? !closestFromEnd : !closestFromStart;
  1638. *aPosIsAfterLastFrame = isRTL ? !closestFromStart : !closestFromEnd;
  1639. if (closestFromStart == closestFromEnd) {
  1640. *aFrameFound = closestFromStart;
  1641. }
  1642. else if (!closestFromStart) {
  1643. *aFrameFound = closestFromEnd;
  1644. }
  1645. else if (!closestFromEnd) {
  1646. *aFrameFound = closestFromStart;
  1647. }
  1648. else { // we're between two frames
  1649. nscoord delta =
  1650. closestFromEnd->GetLogicalRect(wm, containerSize).IStart(wm) -
  1651. closestFromStart->GetLogicalRect(wm, containerSize).IEnd(wm);
  1652. if (pos.I(wm) < closestFromStart->
  1653. GetLogicalRect(wm, containerSize).IEnd(wm) + delta/2) {
  1654. *aFrameFound = closestFromStart;
  1655. } else {
  1656. *aFrameFound = closestFromEnd;
  1657. }
  1658. }
  1659. return NS_OK;
  1660. }
  1661. NS_IMETHODIMP
  1662. nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame,
  1663. int32_t aLineNumber)
  1664. {
  1665. NS_ENSURE_ARG_POINTER(aFrame);
  1666. aFrame = aFrame->GetNextSibling();
  1667. return NS_OK;
  1668. }
  1669. //end nsLineIterator methods
  1670. NS_DECLARE_FRAME_PROPERTY_DELETABLE(RowCursorProperty,
  1671. nsTableRowGroupFrame::FrameCursorData)
  1672. void
  1673. nsTableRowGroupFrame::ClearRowCursor()
  1674. {
  1675. if (!HasAnyStateBits(NS_ROWGROUP_HAS_ROW_CURSOR)) {
  1676. return;
  1677. }
  1678. RemoveStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
  1679. DeleteProperty(RowCursorProperty());
  1680. }
  1681. nsTableRowGroupFrame::FrameCursorData*
  1682. nsTableRowGroupFrame::SetupRowCursor()
  1683. {
  1684. if (HasAnyStateBits(NS_ROWGROUP_HAS_ROW_CURSOR)) {
  1685. // We already have a valid row cursor. Don't waste time rebuilding it.
  1686. return nullptr;
  1687. }
  1688. nsIFrame* f = mFrames.FirstChild();
  1689. int32_t count;
  1690. for (count = 0; f && count < MIN_ROWS_NEEDING_CURSOR; ++count) {
  1691. f = f->GetNextSibling();
  1692. }
  1693. if (!f) {
  1694. // Less than MIN_ROWS_NEEDING_CURSOR rows, so just don't bother
  1695. return nullptr;
  1696. }
  1697. FrameCursorData* data = new FrameCursorData();
  1698. if (!data)
  1699. return nullptr;
  1700. SetProperty(RowCursorProperty(), data);
  1701. AddStateBits(NS_ROWGROUP_HAS_ROW_CURSOR);
  1702. return data;
  1703. }
  1704. nsIFrame*
  1705. nsTableRowGroupFrame::GetFirstRowContaining(nscoord aY, nscoord* aOverflowAbove)
  1706. {
  1707. if (!HasAnyStateBits(NS_ROWGROUP_HAS_ROW_CURSOR)) {
  1708. return nullptr;
  1709. }
  1710. FrameCursorData* property = GetProperty(RowCursorProperty());
  1711. uint32_t cursorIndex = property->mCursorIndex;
  1712. uint32_t frameCount = property->mFrames.Length();
  1713. if (cursorIndex >= frameCount)
  1714. return nullptr;
  1715. nsIFrame* cursorFrame = property->mFrames[cursorIndex];
  1716. // The cursor's frame list excludes frames with empty overflow-area, so
  1717. // we don't need to check that here.
  1718. // We use property->mOverflowBelow here instead of computing the frame's
  1719. // true overflowArea.YMost(), because it is essential for the thresholds
  1720. // to form a monotonically increasing sequence. Otherwise we would break
  1721. // encountering a row whose overflowArea.YMost() is <= aY but which has
  1722. // a row above it containing cell(s) that span to include aY.
  1723. while (cursorIndex > 0 &&
  1724. cursorFrame->GetRect().YMost() + property->mOverflowBelow > aY) {
  1725. --cursorIndex;
  1726. cursorFrame = property->mFrames[cursorIndex];
  1727. }
  1728. while (cursorIndex + 1 < frameCount &&
  1729. cursorFrame->GetRect().YMost() + property->mOverflowBelow <= aY) {
  1730. ++cursorIndex;
  1731. cursorFrame = property->mFrames[cursorIndex];
  1732. }
  1733. property->mCursorIndex = cursorIndex;
  1734. *aOverflowAbove = property->mOverflowAbove;
  1735. return cursorFrame;
  1736. }
  1737. bool
  1738. nsTableRowGroupFrame::FrameCursorData::AppendFrame(nsIFrame* aFrame)
  1739. {
  1740. // Relative positioning can cause table parts to move, which can cause issues
  1741. // with the cursor position to know which rows can be skipped.
  1742. // To make this work, use the max difference between the frame's rect and the
  1743. // union of the frame's "normal" position and the overflow rect to cover the
  1744. // area of relatively positioned elements even if they are out of order.
  1745. nsRect positionedOverflowRect = aFrame->GetVisualOverflowRect();
  1746. nsPoint positionedToNormal = aFrame->GetNormalPosition() - aFrame->GetPosition();
  1747. nsRect normalOverflowRect = positionedOverflowRect + positionedToNormal;
  1748. nsRect overflowRect = positionedOverflowRect.Union(normalOverflowRect);
  1749. if (overflowRect.IsEmpty())
  1750. return true;
  1751. nscoord overflowAbove = -overflowRect.y;
  1752. nscoord overflowBelow = overflowRect.YMost() - aFrame->GetSize().height;
  1753. mOverflowAbove = std::max(mOverflowAbove, overflowAbove);
  1754. mOverflowBelow = std::max(mOverflowBelow, overflowBelow);
  1755. return mFrames.AppendElement(aFrame) != nullptr;
  1756. }
  1757. void
  1758. nsTableRowGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey)
  1759. {
  1760. nsIFrame::InvalidateFrame(aDisplayItemKey);
  1761. GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
  1762. }
  1763. void
  1764. nsTableRowGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
  1765. {
  1766. nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
  1767. // If we have filters applied that would affects our bounds, then
  1768. // we get an inactive layer created and this is computed
  1769. // within FrameLayerBuilder
  1770. GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
  1771. }