nsTableColGroupFrame.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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 "nsTableColGroupFrame.h"
  6. #include "nsTableColFrame.h"
  7. #include "nsTableFrame.h"
  8. #include "nsStyleContext.h"
  9. #include "nsStyleConsts.h"
  10. #include "nsPresContext.h"
  11. #include "nsHTMLParts.h"
  12. #include "nsGkAtoms.h"
  13. #include "nsCOMPtr.h"
  14. #include "nsCSSRendering.h"
  15. #include "nsIPresShell.h"
  16. using namespace mozilla;
  17. #define COL_GROUP_TYPE_BITS (NS_FRAME_STATE_BIT(30) | \
  18. NS_FRAME_STATE_BIT(31))
  19. #define COL_GROUP_TYPE_OFFSET 30
  20. nsTableColGroupType
  21. nsTableColGroupFrame::GetColType() const
  22. {
  23. return (nsTableColGroupType)((mState & COL_GROUP_TYPE_BITS) >> COL_GROUP_TYPE_OFFSET);
  24. }
  25. void nsTableColGroupFrame::SetColType(nsTableColGroupType aType)
  26. {
  27. NS_ASSERTION(GetColType() == eColGroupContent,
  28. "should only call nsTableColGroupFrame::SetColType with aType "
  29. "!= eColGroupContent once");
  30. uint32_t type = aType - eColGroupContent;
  31. RemoveStateBits(COL_GROUP_TYPE_BITS);
  32. AddStateBits(nsFrameState(type << COL_GROUP_TYPE_OFFSET));
  33. }
  34. void nsTableColGroupFrame::ResetColIndices(nsIFrame* aFirstColGroup,
  35. int32_t aFirstColIndex,
  36. nsIFrame* aStartColFrame)
  37. {
  38. nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame*)aFirstColGroup;
  39. int32_t colIndex = aFirstColIndex;
  40. while (colGroupFrame) {
  41. if (nsGkAtoms::tableColGroupFrame == colGroupFrame->GetType()) {
  42. // reset the starting col index for the first cg only if we should reset
  43. // the whole colgroup (aStartColFrame defaults to nullptr) or if
  44. // aFirstColIndex is smaller than the existing starting col index
  45. if ((colIndex != aFirstColIndex) ||
  46. (colIndex < colGroupFrame->GetStartColumnIndex()) ||
  47. !aStartColFrame) {
  48. colGroupFrame->SetStartColumnIndex(colIndex);
  49. }
  50. nsIFrame* colFrame = aStartColFrame;
  51. if (!colFrame || (colIndex != aFirstColIndex)) {
  52. colFrame = colGroupFrame->PrincipalChildList().FirstChild();
  53. }
  54. while (colFrame) {
  55. if (nsGkAtoms::tableColFrame == colFrame->GetType()) {
  56. ((nsTableColFrame*)colFrame)->SetColIndex(colIndex);
  57. colIndex++;
  58. }
  59. colFrame = colFrame->GetNextSibling();
  60. }
  61. }
  62. colGroupFrame = static_cast<nsTableColGroupFrame*>
  63. (colGroupFrame->GetNextSibling());
  64. }
  65. }
  66. nsresult
  67. nsTableColGroupFrame::AddColsToTable(int32_t aFirstColIndex,
  68. bool aResetSubsequentColIndices,
  69. const nsFrameList::Slice& aCols)
  70. {
  71. nsTableFrame* tableFrame = GetTableFrame();
  72. tableFrame->InvalidateFrameSubtree();
  73. // set the col indices of the col frames and and add col info to the table
  74. int32_t colIndex = aFirstColIndex;
  75. nsFrameList::Enumerator e(aCols);
  76. for (; !e.AtEnd(); e.Next()) {
  77. ((nsTableColFrame*)e.get())->SetColIndex(colIndex);
  78. mColCount++;
  79. tableFrame->InsertCol((nsTableColFrame &)*e.get(), colIndex);
  80. colIndex++;
  81. }
  82. for (nsFrameList::Enumerator eTail = e.GetUnlimitedEnumerator();
  83. !eTail.AtEnd();
  84. eTail.Next()) {
  85. ((nsTableColFrame*)eTail.get())->SetColIndex(colIndex);
  86. colIndex++;
  87. }
  88. // We have already set the colindex for all the colframes in this
  89. // colgroup that come after the first inserted colframe, but there could
  90. // be other colgroups following this one and their colframes need
  91. // correct colindices too.
  92. if (aResetSubsequentColIndices && GetNextSibling()) {
  93. ResetColIndices(GetNextSibling(), colIndex);
  94. }
  95. return NS_OK;
  96. }
  97. nsTableColGroupFrame*
  98. nsTableColGroupFrame::GetLastRealColGroup(nsTableFrame* aTableFrame)
  99. {
  100. nsFrameList colGroups = aTableFrame->GetColGroups();
  101. nsIFrame* nextToLastColGroup = nullptr;
  102. nsFrameList::FrameLinkEnumerator link(colGroups);
  103. for ( ; !link.AtEnd(); link.Next()) {
  104. nextToLastColGroup = link.PrevFrame();
  105. }
  106. if (!link.PrevFrame()) {
  107. return nullptr; // there are no col group frames
  108. }
  109. nsTableColGroupType lastColGroupType =
  110. static_cast<nsTableColGroupFrame*>(link.PrevFrame())->GetColType();
  111. if (eColGroupAnonymousCell == lastColGroupType) {
  112. return static_cast<nsTableColGroupFrame*>(nextToLastColGroup);
  113. }
  114. return static_cast<nsTableColGroupFrame*>(link.PrevFrame());
  115. }
  116. // don't set mColCount here, it is done in AddColsToTable
  117. void
  118. nsTableColGroupFrame::SetInitialChildList(ChildListID aListID,
  119. nsFrameList& aChildList)
  120. {
  121. MOZ_ASSERT(mFrames.IsEmpty(),
  122. "unexpected second call to SetInitialChildList");
  123. MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
  124. if (aChildList.IsEmpty()) {
  125. GetTableFrame()->AppendAnonymousColFrames(this, GetSpan(),
  126. eColAnonymousColGroup, false);
  127. return;
  128. }
  129. mFrames.AppendFrames(this, aChildList);
  130. }
  131. /* virtual */ void
  132. nsTableColGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
  133. {
  134. nsContainerFrame::DidSetStyleContext(aOldStyleContext);
  135. if (!aOldStyleContext) //avoid this on init
  136. return;
  137. nsTableFrame* tableFrame = GetTableFrame();
  138. if (tableFrame->IsBorderCollapse() &&
  139. tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
  140. int32_t colCount = GetColCount();
  141. if (!colCount)
  142. return; // this is a degenerated colgroup
  143. TableArea damageArea(GetFirstColumn()->GetColIndex(), 0, colCount,
  144. tableFrame->GetRowCount());
  145. tableFrame->AddBCDamageArea(damageArea);
  146. }
  147. }
  148. void
  149. nsTableColGroupFrame::AppendFrames(ChildListID aListID,
  150. nsFrameList& aFrameList)
  151. {
  152. NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
  153. nsTableColFrame* col = GetFirstColumn();
  154. nsTableColFrame* nextCol;
  155. while (col && col->GetColType() == eColAnonymousColGroup) {
  156. // this colgroup spans one or more columns but now that there is a
  157. // real column below, spanned anonymous columns should be removed,
  158. // since the HTML spec says to ignore the span of a colgroup if it
  159. // has content columns in it.
  160. nextCol = col->GetNextCol();
  161. RemoveFrame(kPrincipalList, col);
  162. col = nextCol;
  163. }
  164. const nsFrameList::Slice& newFrames =
  165. mFrames.AppendFrames(this, aFrameList);
  166. InsertColsReflow(GetStartColumnIndex() + mColCount, newFrames);
  167. }
  168. void
  169. nsTableColGroupFrame::InsertFrames(ChildListID aListID,
  170. nsIFrame* aPrevFrame,
  171. nsFrameList& aFrameList)
  172. {
  173. NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
  174. NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
  175. "inserting after sibling frame with different parent");
  176. nsTableColFrame* col = GetFirstColumn();
  177. nsTableColFrame* nextCol;
  178. while (col && col->GetColType() == eColAnonymousColGroup) {
  179. // this colgroup spans one or more columns but now that there is a
  180. // real column below, spanned anonymous columns should be removed,
  181. // since the HTML spec says to ignore the span of a colgroup if it
  182. // has content columns in it.
  183. nextCol = col->GetNextCol();
  184. if (col == aPrevFrame) {
  185. // This can happen when we're being appended to
  186. NS_ASSERTION(!nextCol || nextCol->GetColType() != eColAnonymousColGroup,
  187. "Inserting in the middle of our anonymous cols?");
  188. // We'll want to insert at the beginning
  189. aPrevFrame = nullptr;
  190. }
  191. RemoveFrame(kPrincipalList, col);
  192. col = nextCol;
  193. }
  194. NS_ASSERTION(!aPrevFrame || aPrevFrame == aPrevFrame->LastContinuation(),
  195. "Prev frame should be last in continuation chain");
  196. NS_ASSERTION(!aPrevFrame || !GetNextColumn(aPrevFrame) ||
  197. GetNextColumn(aPrevFrame)->GetColType() != eColAnonymousCol,
  198. "Shouldn't be inserting before a spanned colframe");
  199. const nsFrameList::Slice& newFrames =
  200. mFrames.InsertFrames(this, aPrevFrame, aFrameList);
  201. nsIFrame* prevFrame = nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame,
  202. nsGkAtoms::tableColFrame);
  203. int32_t colIndex = (prevFrame) ? ((nsTableColFrame*)prevFrame)->GetColIndex() + 1 : GetStartColumnIndex();
  204. InsertColsReflow(colIndex, newFrames);
  205. }
  206. void
  207. nsTableColGroupFrame::InsertColsReflow(int32_t aColIndex,
  208. const nsFrameList::Slice& aCols)
  209. {
  210. AddColsToTable(aColIndex, true, aCols);
  211. PresContext()->PresShell()->FrameNeedsReflow(this,
  212. nsIPresShell::eTreeChange,
  213. NS_FRAME_HAS_DIRTY_CHILDREN);
  214. }
  215. void
  216. nsTableColGroupFrame::RemoveChild(nsTableColFrame& aChild,
  217. bool aResetSubsequentColIndices)
  218. {
  219. int32_t colIndex = 0;
  220. nsIFrame* nextChild = nullptr;
  221. if (aResetSubsequentColIndices) {
  222. colIndex = aChild.GetColIndex();
  223. nextChild = aChild.GetNextSibling();
  224. }
  225. mFrames.DestroyFrame(&aChild);
  226. mColCount--;
  227. if (aResetSubsequentColIndices) {
  228. if (nextChild) { // reset inside this and all following colgroups
  229. ResetColIndices(this, colIndex, nextChild);
  230. }
  231. else {
  232. nsIFrame* nextGroup = GetNextSibling();
  233. if (nextGroup) // reset next and all following colgroups
  234. ResetColIndices(nextGroup, colIndex);
  235. }
  236. }
  237. PresContext()->PresShell()->FrameNeedsReflow(this,
  238. nsIPresShell::eTreeChange,
  239. NS_FRAME_HAS_DIRTY_CHILDREN);
  240. }
  241. void
  242. nsTableColGroupFrame::RemoveFrame(ChildListID aListID,
  243. nsIFrame* aOldFrame)
  244. {
  245. NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
  246. if (!aOldFrame) {
  247. return;
  248. }
  249. bool contentRemoval = false;
  250. if (nsGkAtoms::tableColFrame == aOldFrame->GetType()) {
  251. nsTableColFrame* colFrame = (nsTableColFrame*)aOldFrame;
  252. if (colFrame->GetColType() == eColContent) {
  253. contentRemoval = true;
  254. // Remove any anonymous column frames this <col> produced via a colspan
  255. nsTableColFrame* col = colFrame->GetNextCol();
  256. nsTableColFrame* nextCol;
  257. while (col && col->GetColType() == eColAnonymousCol) {
  258. #ifdef DEBUG
  259. nsIFrame* providerFrame;
  260. nsStyleContext* psc = colFrame->GetParentStyleContext(&providerFrame);
  261. if (colFrame->StyleContext()->GetParent() == psc) {
  262. NS_ASSERTION(col->StyleContext() == colFrame->StyleContext() &&
  263. col->GetContent() == colFrame->GetContent(),
  264. "How did that happen??");
  265. }
  266. // else colFrame is being removed because of a frame
  267. // reconstruct on it, and its style context is still the old
  268. // one, so we can't assert anything about how it compares to
  269. // col's style context.
  270. #endif
  271. nextCol = col->GetNextCol();
  272. RemoveFrame(kPrincipalList, col);
  273. col = nextCol;
  274. }
  275. }
  276. int32_t colIndex = colFrame->GetColIndex();
  277. // The RemoveChild call handles calling FrameNeedsReflow on us.
  278. RemoveChild(*colFrame, true);
  279. nsTableFrame* tableFrame = GetTableFrame();
  280. tableFrame->RemoveCol(this, colIndex, true, true);
  281. if (mFrames.IsEmpty() && contentRemoval &&
  282. GetColType() == eColGroupContent) {
  283. tableFrame->AppendAnonymousColFrames(this, GetSpan(),
  284. eColAnonymousColGroup, true);
  285. }
  286. }
  287. else {
  288. mFrames.DestroyFrame(aOldFrame);
  289. }
  290. }
  291. nsIFrame::LogicalSides
  292. nsTableColGroupFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const
  293. {
  294. if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
  295. StyleBoxDecorationBreak::Clone)) {
  296. return LogicalSides();
  297. }
  298. LogicalSides skip;
  299. if (nullptr != GetPrevInFlow()) {
  300. skip |= eLogicalSideBitsBStart;
  301. }
  302. if (nullptr != GetNextInFlow()) {
  303. skip |= eLogicalSideBitsBEnd;
  304. }
  305. return skip;
  306. }
  307. void
  308. nsTableColGroupFrame::Reflow(nsPresContext* aPresContext,
  309. ReflowOutput& aDesiredSize,
  310. const ReflowInput& aReflowInput,
  311. nsReflowStatus& aStatus)
  312. {
  313. MarkInReflow();
  314. DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame");
  315. DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
  316. NS_ASSERTION(nullptr!=mContent, "bad state -- null content for frame");
  317. const nsStyleVisibility* groupVis = StyleVisibility();
  318. bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
  319. if (collapseGroup) {
  320. GetTableFrame()->SetNeedToCollapse(true);
  321. }
  322. // for every content child that (is a column thingy and does not already have a frame)
  323. // create a frame and adjust it's style
  324. for (nsIFrame *kidFrame = mFrames.FirstChild(); kidFrame;
  325. kidFrame = kidFrame->GetNextSibling()) {
  326. // Give the child frame a chance to reflow, even though we know it'll have 0 size
  327. ReflowOutput kidSize(aReflowInput);
  328. ReflowInput kidReflowInput(aPresContext, aReflowInput, kidFrame,
  329. LogicalSize(kidFrame->GetWritingMode()));
  330. nsReflowStatus status;
  331. ReflowChild(kidFrame, aPresContext, kidSize, kidReflowInput, 0, 0, 0, status);
  332. FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, 0, 0, 0);
  333. }
  334. aDesiredSize.ClearSize();
  335. aStatus = NS_FRAME_COMPLETE;
  336. NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
  337. }
  338. void
  339. nsTableColGroupFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
  340. const nsDisplayListSet& aLists)
  341. {
  342. // Per https://drafts.csswg.org/css-tables-3/#global-style-overrides:
  343. // "All css properties of table-column and table-column-group boxes are
  344. // ignored, except when explicitly specified by this specification."
  345. // CSS outlines and box-shadows fall into this category, so we skip them
  346. // on these boxes.
  347. MOZ_ASSERT_UNREACHABLE("Colgroups don't paint themselves");
  348. }
  349. nsTableColFrame * nsTableColGroupFrame::GetFirstColumn()
  350. {
  351. return GetNextColumn(nullptr);
  352. }
  353. nsTableColFrame * nsTableColGroupFrame::GetNextColumn(nsIFrame *aChildFrame)
  354. {
  355. nsTableColFrame *result = nullptr;
  356. nsIFrame *childFrame = aChildFrame;
  357. if (!childFrame) {
  358. childFrame = mFrames.FirstChild();
  359. }
  360. else {
  361. childFrame = childFrame->GetNextSibling();
  362. }
  363. while (childFrame)
  364. {
  365. if (mozilla::StyleDisplay::TableColumn ==
  366. childFrame->StyleDisplay()->mDisplay)
  367. {
  368. result = (nsTableColFrame *)childFrame;
  369. break;
  370. }
  371. childFrame = childFrame->GetNextSibling();
  372. }
  373. return result;
  374. }
  375. int32_t nsTableColGroupFrame::GetSpan()
  376. {
  377. return StyleTable()->mSpan;
  378. }
  379. void nsTableColGroupFrame::SetContinuousBCBorderWidth(LogicalSide aForSide,
  380. BCPixelSize aPixelValue)
  381. {
  382. switch (aForSide) {
  383. case eLogicalSideBStart:
  384. mBStartContBorderWidth = aPixelValue;
  385. return;
  386. case eLogicalSideBEnd:
  387. mBEndContBorderWidth = aPixelValue;
  388. return;
  389. default:
  390. NS_ERROR("invalid side arg");
  391. }
  392. }
  393. void nsTableColGroupFrame::GetContinuousBCBorderWidth(WritingMode aWM,
  394. LogicalMargin& aBorder)
  395. {
  396. int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
  397. nsTableColFrame* col = GetTableFrame()->
  398. GetColFrame(mStartColIndex + mColCount - 1);
  399. col->GetContinuousBCBorderWidth(aWM, aBorder);
  400. aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
  401. mBStartContBorderWidth);
  402. aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
  403. mBEndContBorderWidth);
  404. }
  405. /* ----- global methods ----- */
  406. nsTableColGroupFrame*
  407. NS_NewTableColGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  408. {
  409. return new (aPresShell) nsTableColGroupFrame(aContext);
  410. }
  411. NS_IMPL_FRAMEARENA_HELPERS(nsTableColGroupFrame)
  412. nsIAtom*
  413. nsTableColGroupFrame::GetType() const
  414. {
  415. return nsGkAtoms::tableColGroupFrame;
  416. }
  417. void
  418. nsTableColGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey)
  419. {
  420. nsIFrame::InvalidateFrame(aDisplayItemKey);
  421. GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
  422. }
  423. void
  424. nsTableColGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
  425. {
  426. nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
  427. // If we have filters applied that would affects our bounds, then
  428. // we get an inactive layer created and this is computed
  429. // within FrameLayerBuilder
  430. GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
  431. }
  432. #ifdef DEBUG_FRAME_DUMP
  433. nsresult
  434. nsTableColGroupFrame::GetFrameName(nsAString& aResult) const
  435. {
  436. return MakeFrameName(NS_LITERAL_STRING("TableColGroup"), aResult);
  437. }
  438. void nsTableColGroupFrame::Dump(int32_t aIndent)
  439. {
  440. char* indent = new char[aIndent + 1];
  441. if (!indent) return;
  442. for (int32_t i = 0; i < aIndent + 1; i++) {
  443. indent[i] = ' ';
  444. }
  445. indent[aIndent] = 0;
  446. printf("%s**START COLGROUP DUMP**\n%s startcolIndex=%d colcount=%d span=%d coltype=",
  447. indent, indent, GetStartColumnIndex(), GetColCount(), GetSpan());
  448. nsTableColGroupType colType = GetColType();
  449. switch (colType) {
  450. case eColGroupContent:
  451. printf(" content ");
  452. break;
  453. case eColGroupAnonymousCol:
  454. printf(" anonymous-column ");
  455. break;
  456. case eColGroupAnonymousCell:
  457. printf(" anonymous-cell ");
  458. break;
  459. }
  460. // verify the colindices
  461. int32_t j = GetStartColumnIndex();
  462. nsTableColFrame* col = GetFirstColumn();
  463. while (col) {
  464. NS_ASSERTION(j == col->GetColIndex(), "wrong colindex on col frame");
  465. col = col->GetNextCol();
  466. j++;
  467. }
  468. NS_ASSERTION((j - GetStartColumnIndex()) == GetColCount(),
  469. "number of cols out of sync");
  470. printf("\n%s**END COLGROUP DUMP** ", indent);
  471. delete [] indent;
  472. }
  473. #endif