nsTableWrapperFrame.cpp 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106
  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 "nsTableWrapperFrame.h"
  6. #include "nsFrameManager.h"
  7. #include "nsTableFrame.h"
  8. #include "nsTableCellFrame.h"
  9. #include "nsStyleContext.h"
  10. #include "nsStyleConsts.h"
  11. #include "nsPresContext.h"
  12. #include "nsCSSRendering.h"
  13. #include "nsIContent.h"
  14. #include "prinrval.h"
  15. #include "nsGkAtoms.h"
  16. #include "nsHTMLParts.h"
  17. #include "nsIPresShell.h"
  18. #include "nsIServiceManager.h"
  19. #include "nsIDOMNode.h"
  20. #include "nsDisplayList.h"
  21. #include "nsLayoutUtils.h"
  22. #include "nsIFrameInlines.h"
  23. #include <algorithm>
  24. using namespace mozilla;
  25. using namespace mozilla::layout;
  26. #define NO_SIDE 100
  27. /* virtual */ nscoord
  28. nsTableWrapperFrame::GetLogicalBaseline(WritingMode aWritingMode) const
  29. {
  30. nsIFrame* kid = mFrames.FirstChild();
  31. if (!kid) {
  32. NS_NOTREACHED("no inner table");
  33. return nsContainerFrame::GetLogicalBaseline(aWritingMode);
  34. }
  35. return kid->GetLogicalBaseline(aWritingMode) +
  36. kid->BStart(aWritingMode, mRect.Size());
  37. }
  38. nsTableWrapperFrame::nsTableWrapperFrame(nsStyleContext* aContext)
  39. : nsContainerFrame(aContext)
  40. {
  41. }
  42. nsTableWrapperFrame::~nsTableWrapperFrame()
  43. {
  44. }
  45. NS_QUERYFRAME_HEAD(nsTableWrapperFrame)
  46. NS_QUERYFRAME_ENTRY(nsTableWrapperFrame)
  47. NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
  48. #ifdef ACCESSIBILITY
  49. a11y::AccType
  50. nsTableWrapperFrame::AccessibleType()
  51. {
  52. return a11y::eHTMLTableType;
  53. }
  54. #endif
  55. void
  56. nsTableWrapperFrame::DestroyFrom(nsIFrame* aDestructRoot)
  57. {
  58. DestroyAbsoluteFrames(aDestructRoot);
  59. mCaptionFrames.DestroyFramesFrom(aDestructRoot);
  60. nsContainerFrame::DestroyFrom(aDestructRoot);
  61. }
  62. const nsFrameList&
  63. nsTableWrapperFrame::GetChildList(ChildListID aListID) const
  64. {
  65. if (aListID == kCaptionList) {
  66. return mCaptionFrames;
  67. }
  68. return nsContainerFrame::GetChildList(aListID);
  69. }
  70. void
  71. nsTableWrapperFrame::GetChildLists(nsTArray<ChildList>* aLists) const
  72. {
  73. nsContainerFrame::GetChildLists(aLists);
  74. mCaptionFrames.AppendIfNonempty(aLists, kCaptionList);
  75. }
  76. void
  77. nsTableWrapperFrame::SetInitialChildList(ChildListID aListID,
  78. nsFrameList& aChildList)
  79. {
  80. if (kCaptionList == aListID) {
  81. // the frame constructor already checked for table-caption display type
  82. MOZ_ASSERT(mCaptionFrames.IsEmpty(),
  83. "already have child frames in CaptionList");
  84. mCaptionFrames.SetFrames(aChildList);
  85. } else {
  86. MOZ_ASSERT(kPrincipalList != aListID ||
  87. (aChildList.FirstChild() &&
  88. aChildList.FirstChild() == aChildList.LastChild() &&
  89. nsGkAtoms::tableFrame == aChildList.FirstChild()->GetType()),
  90. "expected a single table frame in principal child list");
  91. nsContainerFrame::SetInitialChildList(aListID, aChildList);
  92. }
  93. }
  94. void
  95. nsTableWrapperFrame::AppendFrames(ChildListID aListID,
  96. nsFrameList& aFrameList)
  97. {
  98. // We only have two child frames: the inner table and a caption frame.
  99. // The inner frame is provided when we're initialized, and it cannot change
  100. MOZ_ASSERT(kCaptionList == aListID, "unexpected child list");
  101. MOZ_ASSERT(aFrameList.IsEmpty() ||
  102. aFrameList.FirstChild()->IsTableCaption(),
  103. "appending non-caption frame to captionList");
  104. mCaptionFrames.AppendFrames(this, aFrameList);
  105. // Reflow the new caption frame. It's already marked dirty, so
  106. // just tell the pres shell.
  107. PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  108. NS_FRAME_HAS_DIRTY_CHILDREN);
  109. }
  110. void
  111. nsTableWrapperFrame::InsertFrames(ChildListID aListID,
  112. nsIFrame* aPrevFrame,
  113. nsFrameList& aFrameList)
  114. {
  115. MOZ_ASSERT(kCaptionList == aListID, "unexpected child list");
  116. MOZ_ASSERT(aFrameList.IsEmpty() ||
  117. aFrameList.FirstChild()->IsTableCaption(),
  118. "inserting non-caption frame into captionList");
  119. MOZ_ASSERT(!aPrevFrame || aPrevFrame->GetParent() == this,
  120. "inserting after sibling frame with different parent");
  121. mCaptionFrames.InsertFrames(nullptr, aPrevFrame, aFrameList);
  122. // Reflow the new caption frame. It's already marked dirty, so
  123. // just tell the pres shell.
  124. PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  125. NS_FRAME_HAS_DIRTY_CHILDREN);
  126. }
  127. void
  128. nsTableWrapperFrame::RemoveFrame(ChildListID aListID,
  129. nsIFrame* aOldFrame)
  130. {
  131. // We only have two child frames: the inner table and one caption frame.
  132. // The inner frame can't be removed so this should be the caption
  133. NS_PRECONDITION(kCaptionList == aListID, "can't remove inner frame");
  134. if (HasSideCaption()) {
  135. // The old caption isize had an effect on the inner table isize, so
  136. // we're going to need to reflow it. Mark it dirty
  137. InnerTableFrame()->AddStateBits(NS_FRAME_IS_DIRTY);
  138. }
  139. // Remove the frame and destroy it
  140. mCaptionFrames.DestroyFrame(aOldFrame);
  141. PresContext()->PresShell()->
  142. FrameNeedsReflow(this, nsIPresShell::eTreeChange,
  143. NS_FRAME_HAS_DIRTY_CHILDREN); // also means child removed
  144. }
  145. void
  146. nsTableWrapperFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
  147. const nsDisplayListSet& aLists)
  148. {
  149. // No border, background or outline are painted because they all belong
  150. // to the inner table.
  151. // If there's no caption, take a short cut to avoid having to create
  152. // the special display list set and then sort it.
  153. if (mCaptionFrames.IsEmpty()) {
  154. BuildDisplayListForInnerTable(aBuilder, aLists);
  155. return;
  156. }
  157. nsDisplayListCollection set(aBuilder);
  158. BuildDisplayListForInnerTable(aBuilder, set);
  159. nsDisplayListSet captionSet(set, set.BlockBorderBackgrounds());
  160. BuildDisplayListForChild(aBuilder, mCaptionFrames.FirstChild(), captionSet);
  161. // Now we have to sort everything by content order, since the caption
  162. // may be somewhere inside the table.
  163. // We don't sort BlockBorderBackgrounds and BorderBackgrounds because the
  164. // display items in those lists should stay out of content order in order to
  165. // follow the rules in https://www.w3.org/TR/CSS21/zindex.html#painting-order
  166. // and paint the caption background after all of the rest.
  167. set.Floats()->SortByContentOrder(GetContent());
  168. set.Content()->SortByContentOrder(GetContent());
  169. set.PositionedDescendants()->SortByContentOrder(GetContent());
  170. set.Outlines()->SortByContentOrder(GetContent());
  171. set.MoveTo(aLists);
  172. }
  173. void
  174. nsTableWrapperFrame::BuildDisplayListForInnerTable(nsDisplayListBuilder* aBuilder,
  175. const nsDisplayListSet& aLists)
  176. {
  177. // Just paint the regular children, but the children's background is our
  178. // true background (there should only be one, the real table)
  179. nsIFrame* kid = mFrames.FirstChild();
  180. // The children should be in content order
  181. while (kid) {
  182. BuildDisplayListForChild(aBuilder, kid, aLists);
  183. kid = kid->GetNextSibling();
  184. }
  185. }
  186. nsStyleContext*
  187. nsTableWrapperFrame::GetParentStyleContext(nsIFrame** aProviderFrame) const
  188. {
  189. // The table wrapper frame and the (inner) table frame split the style
  190. // data by giving the table frame the style context associated with
  191. // the table content node and creating a style context for the wrapper
  192. // frame that is a *child* of the table frame's style context,
  193. // matching the ::-moz-table-wrapper pseudo-element. html.css has a
  194. // rule that causes that pseudo-element (and thus the wrapper table)
  195. // to inherit *some* style properties from the table frame. The
  196. // children of the table inherit directly from the inner table, and
  197. // the table wrapper's style context is a leaf.
  198. return (*aProviderFrame = InnerTableFrame())->StyleContext();
  199. }
  200. // INCREMENTAL REFLOW HELPER FUNCTIONS
  201. void
  202. nsTableWrapperFrame::InitChildReflowInput(nsPresContext& aPresContext,
  203. ReflowInput& aReflowInput)
  204. {
  205. nsMargin collapseBorder;
  206. nsMargin collapsePadding(0,0,0,0);
  207. nsMargin* pCollapseBorder = nullptr;
  208. nsMargin* pCollapsePadding = nullptr;
  209. Maybe<LogicalSize> cbSize;
  210. if (aReflowInput.mFrame == InnerTableFrame()) {
  211. WritingMode wm = aReflowInput.GetWritingMode();
  212. if (InnerTableFrame()->IsBorderCollapse()) {
  213. LogicalMargin border = InnerTableFrame()->GetIncludedOuterBCBorder(wm);
  214. collapseBorder = border.GetPhysicalMargin(wm);
  215. pCollapseBorder = &collapseBorder;
  216. pCollapsePadding = &collapsePadding;
  217. }
  218. // Propagate our stored CB size if present, minus any margins.
  219. if (!HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
  220. LogicalSize* cb = GetProperty(GridItemCBSizeProperty());
  221. if (cb) {
  222. cbSize.emplace(*cb);
  223. *cbSize -= aReflowInput.ComputedLogicalMargin().Size(wm);
  224. }
  225. }
  226. }
  227. aReflowInput.Init(&aPresContext, cbSize.ptrOr(nullptr), pCollapseBorder,
  228. pCollapsePadding);
  229. }
  230. // get the margin and padding data. ReflowInput doesn't handle the
  231. // case of auto margins
  232. void
  233. nsTableWrapperFrame::GetChildMargin(nsPresContext* aPresContext,
  234. const ReflowInput& aOuterRI,
  235. nsIFrame* aChildFrame,
  236. nscoord aAvailISize,
  237. LogicalMargin& aMargin)
  238. {
  239. NS_ASSERTION(!aChildFrame->IsTableCaption(),
  240. "didn't expect caption frame; writing-mode may be wrong!");
  241. // construct a reflow state to compute margin and padding. Auto margins
  242. // will not be computed at this time.
  243. // create and init the child reflow state
  244. // XXX We really shouldn't construct a reflow state to do this.
  245. WritingMode wm = aOuterRI.GetWritingMode();
  246. LogicalSize availSize(wm, aAvailISize, aOuterRI.AvailableSize(wm).BSize(wm));
  247. ReflowInput childRI(aPresContext, aOuterRI, aChildFrame, availSize,
  248. nullptr, ReflowInput::CALLER_WILL_INIT);
  249. InitChildReflowInput(*aPresContext, childRI);
  250. aMargin = childRI.ComputedLogicalMargin();
  251. }
  252. static nsSize
  253. GetContainingBlockSize(const ReflowInput& aOuterRI)
  254. {
  255. nsSize size(0,0);
  256. const ReflowInput* containRS = aOuterRI.mCBReflowInput;
  257. if (containRS) {
  258. size.width = containRS->ComputedWidth();
  259. if (NS_UNCONSTRAINEDSIZE == size.width) {
  260. size.width = 0;
  261. }
  262. size.height = containRS->ComputedHeight();
  263. if (NS_UNCONSTRAINEDSIZE == size.height) {
  264. size.height = 0;
  265. }
  266. }
  267. return size;
  268. }
  269. /* virtual */ nscoord
  270. nsTableWrapperFrame::GetMinISize(nsRenderingContext *aRenderingContext)
  271. {
  272. nscoord iSize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
  273. InnerTableFrame(), nsLayoutUtils::MIN_ISIZE);
  274. DISPLAY_MIN_WIDTH(this, iSize);
  275. if (mCaptionFrames.NotEmpty()) {
  276. nscoord capISize =
  277. nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
  278. mCaptionFrames.FirstChild(),
  279. nsLayoutUtils::MIN_ISIZE);
  280. if (HasSideCaption()) {
  281. iSize += capISize;
  282. } else {
  283. if (capISize > iSize) {
  284. iSize = capISize;
  285. }
  286. }
  287. }
  288. return iSize;
  289. }
  290. /* virtual */ nscoord
  291. nsTableWrapperFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
  292. {
  293. nscoord maxISize;
  294. DISPLAY_PREF_WIDTH(this, maxISize);
  295. maxISize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
  296. InnerTableFrame(), nsLayoutUtils::PREF_ISIZE);
  297. if (mCaptionFrames.NotEmpty()) {
  298. uint8_t captionSide = GetCaptionSide();
  299. switch (captionSide) {
  300. case NS_STYLE_CAPTION_SIDE_LEFT:
  301. case NS_STYLE_CAPTION_SIDE_RIGHT:
  302. {
  303. nscoord capMin =
  304. nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
  305. mCaptionFrames.FirstChild(),
  306. nsLayoutUtils::MIN_ISIZE);
  307. maxISize += capMin;
  308. }
  309. break;
  310. default:
  311. {
  312. nsLayoutUtils::IntrinsicISizeType iwt;
  313. if (captionSide == NS_STYLE_CAPTION_SIDE_TOP ||
  314. captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) {
  315. // Don't let the caption's pref isize expand the table's pref
  316. // isize.
  317. iwt = nsLayoutUtils::MIN_ISIZE;
  318. } else {
  319. NS_ASSERTION(captionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE ||
  320. captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE,
  321. "unexpected caption side");
  322. iwt = nsLayoutUtils::PREF_ISIZE;
  323. }
  324. nscoord capPref =
  325. nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
  326. mCaptionFrames.FirstChild(),
  327. iwt);
  328. maxISize = std::max(maxISize, capPref);
  329. }
  330. break;
  331. }
  332. }
  333. return maxISize;
  334. }
  335. nscoord
  336. nsTableWrapperFrame::ChildShrinkWrapISize(nsRenderingContext* aRenderingContext,
  337. nsIFrame* aChildFrame,
  338. WritingMode aWM,
  339. LogicalSize aCBSize,
  340. nscoord aAvailableISize,
  341. nscoord* aMarginResult) const
  342. {
  343. AutoMaybeDisableFontInflation an(aChildFrame);
  344. // For the caption frame, child's WM may differ from the table's main WM.
  345. WritingMode childWM = aChildFrame->GetWritingMode();
  346. SizeComputationInput offsets(aChildFrame, aRenderingContext, aWM,
  347. aCBSize.ISize(aWM));
  348. LogicalSize marginSize =
  349. offsets.ComputedLogicalMargin().Size(childWM).ConvertTo(aWM, childWM);
  350. LogicalSize paddingSize =
  351. offsets.ComputedLogicalPadding().Size(childWM).ConvertTo(aWM, childWM);
  352. LogicalSize bpSize =
  353. offsets.ComputedLogicalBorderPadding().Size(childWM).ConvertTo(aWM, childWM);
  354. // Shrink-wrap aChildFrame by default, except if we're a stretched grid item.
  355. auto flags = ComputeSizeFlags::eShrinkWrap;
  356. auto parent = GetParent();
  357. nsIAtom* parentFrameType = parent ? parent->GetType() : nullptr;
  358. bool isGridItem = (parentFrameType == nsGkAtoms::gridContainerFrame &&
  359. !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
  360. if (MOZ_UNLIKELY(isGridItem) &&
  361. !StyleMargin()->HasInlineAxisAuto(aWM)) {
  362. auto inlineAxisAlignment = aWM.IsOrthogonalTo(parent->GetWritingMode()) ?
  363. StylePosition()->UsedAlignSelf(parent->StyleContext()) :
  364. StylePosition()->UsedJustifySelf(parent->StyleContext());
  365. if (inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
  366. inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
  367. flags = nsIFrame::ComputeSizeFlags::eDefault;
  368. }
  369. }
  370. LogicalSize size =
  371. aChildFrame->ComputeSize(aRenderingContext, aWM, aCBSize, aAvailableISize,
  372. marginSize, bpSize - paddingSize, paddingSize,
  373. flags);
  374. if (aMarginResult) {
  375. *aMarginResult = offsets.ComputedLogicalMargin().IStartEnd(aWM);
  376. }
  377. return size.ISize(aWM) + marginSize.ISize(aWM) + bpSize.ISize(aWM);
  378. }
  379. /* virtual */
  380. LogicalSize
  381. nsTableWrapperFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
  382. WritingMode aWM,
  383. const LogicalSize& aCBSize,
  384. nscoord aAvailableISize,
  385. const LogicalSize& aMargin,
  386. const LogicalSize& aBorder,
  387. const LogicalSize& aPadding,
  388. ComputeSizeFlags aFlags)
  389. {
  390. nscoord kidAvailableISize = aAvailableISize - aMargin.ISize(aWM);
  391. NS_ASSERTION(aBorder.IsAllZero() && aPadding.IsAllZero(),
  392. "Table wrapper frames cannot have borders or paddings");
  393. // When we're shrink-wrapping, our auto size needs to wrap around the
  394. // actual size of the table, which (if it is specified as a percent)
  395. // could be something that is not reflected in our GetMinISize and
  396. // GetPrefISize. See bug 349457 for an example.
  397. // Match the availableISize logic in Reflow.
  398. uint8_t captionSide = GetCaptionSide();
  399. nscoord inlineSize;
  400. if (captionSide == NO_SIDE) {
  401. inlineSize = ChildShrinkWrapISize(aRenderingContext, InnerTableFrame(), aWM,
  402. aCBSize, kidAvailableISize);
  403. } else if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
  404. captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) {
  405. nscoord capISize = ChildShrinkWrapISize(aRenderingContext,
  406. mCaptionFrames.FirstChild(), aWM,
  407. aCBSize, kidAvailableISize);
  408. inlineSize = capISize + ChildShrinkWrapISize(aRenderingContext,
  409. InnerTableFrame(), aWM,
  410. aCBSize,
  411. kidAvailableISize - capISize);
  412. } else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP ||
  413. captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) {
  414. nscoord margin;
  415. inlineSize = ChildShrinkWrapISize(aRenderingContext, InnerTableFrame(), aWM,
  416. aCBSize, kidAvailableISize, &margin);
  417. nscoord capISize = ChildShrinkWrapISize(aRenderingContext,
  418. mCaptionFrames.FirstChild(), aWM,
  419. aCBSize, inlineSize - margin);
  420. if (capISize > inlineSize) {
  421. inlineSize = capISize;
  422. }
  423. } else {
  424. NS_ASSERTION(captionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE ||
  425. captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE,
  426. "unexpected caption-side");
  427. inlineSize = ChildShrinkWrapISize(aRenderingContext, InnerTableFrame(), aWM,
  428. aCBSize, kidAvailableISize);
  429. nscoord capISize = ChildShrinkWrapISize(aRenderingContext,
  430. mCaptionFrames.FirstChild(), aWM,
  431. aCBSize, kidAvailableISize);
  432. if (capISize > inlineSize) {
  433. inlineSize = capISize;
  434. }
  435. }
  436. return LogicalSize(aWM, inlineSize, NS_UNCONSTRAINEDSIZE);
  437. }
  438. uint8_t
  439. nsTableWrapperFrame::GetCaptionSide()
  440. {
  441. if (mCaptionFrames.NotEmpty()) {
  442. return mCaptionFrames.FirstChild()->StyleTableBorder()->mCaptionSide;
  443. }
  444. else {
  445. return NO_SIDE; // no caption
  446. }
  447. }
  448. uint8_t
  449. nsTableWrapperFrame::GetCaptionVerticalAlign()
  450. {
  451. const nsStyleCoord& va =
  452. mCaptionFrames.FirstChild()->StyleDisplay()->mVerticalAlign;
  453. return (va.GetUnit() == eStyleUnit_Enumerated)
  454. ? va.GetIntValue()
  455. : NS_STYLE_VERTICAL_ALIGN_TOP;
  456. }
  457. void
  458. nsTableWrapperFrame::SetDesiredSize(uint8_t aCaptionSide,
  459. const LogicalSize& aInnerSize,
  460. const LogicalSize& aCaptionSize,
  461. const LogicalMargin& aInnerMargin,
  462. const LogicalMargin& aCaptionMargin,
  463. nscoord& aISize,
  464. nscoord& aBSize,
  465. WritingMode aWM)
  466. {
  467. aISize = aBSize = 0;
  468. // compute the overall inline-size
  469. switch (aCaptionSide) {
  470. case NS_STYLE_CAPTION_SIDE_LEFT:
  471. aISize =
  472. std::max(aInnerMargin.LineLeft(aWM),
  473. aCaptionMargin.IStartEnd(aWM) + aCaptionSize.ISize(aWM)) +
  474. aInnerSize.ISize(aWM) + aInnerMargin.LineRight(aWM);
  475. break;
  476. case NS_STYLE_CAPTION_SIDE_RIGHT:
  477. aISize =
  478. std::max(aInnerMargin.LineRight(aWM),
  479. aCaptionMargin.IStartEnd(aWM) + aCaptionSize.ISize(aWM)) +
  480. aInnerSize.ISize(aWM) + aInnerMargin.LineLeft(aWM);
  481. break;
  482. default:
  483. aISize =
  484. std::max(aInnerMargin.IStartEnd(aWM) + aInnerSize.ISize(aWM),
  485. aCaptionMargin.IStartEnd(aWM) + aCaptionSize.ISize(aWM));
  486. break;
  487. }
  488. // compute the overall block-size
  489. switch (aCaptionSide) {
  490. case NS_STYLE_CAPTION_SIDE_TOP:
  491. case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE:
  492. aBSize = aInnerSize.BSize(aWM) + aInnerMargin.BEnd(aWM);
  493. aBSize +=
  494. std::max(aInnerMargin.BStart(aWM),
  495. aCaptionSize.BSize(aWM) + aCaptionMargin.BStartEnd(aWM));
  496. break;
  497. case NS_STYLE_CAPTION_SIDE_BOTTOM:
  498. case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE:
  499. aBSize = aInnerSize.BSize(aWM) + aInnerMargin.BStart(aWM);
  500. aBSize +=
  501. std::max(aInnerMargin.BEnd(aWM),
  502. aCaptionSize.BSize(aWM) + aCaptionMargin.BStartEnd(aWM));
  503. break;
  504. case NS_STYLE_CAPTION_SIDE_LEFT:
  505. case NS_STYLE_CAPTION_SIDE_RIGHT:
  506. aBSize = aInnerMargin.BStart(aWM);
  507. aBSize +=
  508. std::max(aInnerSize.BSize(aWM) + aInnerMargin.BEnd(aWM),
  509. aCaptionSize.BSize(aWM) + aCaptionMargin.BEnd(aWM));
  510. break;
  511. default:
  512. NS_ASSERTION(aCaptionSide == NO_SIDE, "unexpected caption side");
  513. aBSize = aInnerSize.BSize(aWM) + aInnerMargin.BStartEnd(aWM);
  514. break;
  515. }
  516. // negative sizes can upset overflow-area code
  517. aISize = std::max(aISize, 0);
  518. aBSize = std::max(aBSize, 0);
  519. }
  520. nsresult
  521. nsTableWrapperFrame::GetCaptionOrigin(uint32_t aCaptionSide,
  522. const LogicalSize& aContainBlockSize,
  523. const LogicalSize& aInnerSize,
  524. const LogicalMargin& aInnerMargin,
  525. const LogicalSize& aCaptionSize,
  526. LogicalMargin& aCaptionMargin,
  527. LogicalPoint& aOrigin,
  528. WritingMode aWM)
  529. {
  530. aOrigin.I(aWM) = aOrigin.B(aWM) = 0;
  531. if ((NS_UNCONSTRAINEDSIZE == aInnerSize.ISize(aWM)) ||
  532. (NS_UNCONSTRAINEDSIZE == aInnerSize.BSize(aWM)) ||
  533. (NS_UNCONSTRAINEDSIZE == aCaptionSize.ISize(aWM)) ||
  534. (NS_UNCONSTRAINEDSIZE == aCaptionSize.BSize(aWM))) {
  535. return NS_OK;
  536. }
  537. if (mCaptionFrames.IsEmpty()) {
  538. return NS_OK;
  539. }
  540. NS_ASSERTION(NS_AUTOMARGIN != aCaptionMargin.IStart(aWM) &&
  541. NS_AUTOMARGIN != aCaptionMargin.BStart(aWM) &&
  542. NS_AUTOMARGIN != aCaptionMargin.BEnd(aWM),
  543. "The computed caption margin is auto?");
  544. // inline-dir computation
  545. switch (aCaptionSide) {
  546. case NS_STYLE_CAPTION_SIDE_BOTTOM:
  547. case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE:
  548. aOrigin.I(aWM) = aCaptionMargin.IStart(aWM);
  549. if (aCaptionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) {
  550. // We placed the caption using only the table's isize as available
  551. // isize, and we should position it this way as well.
  552. aOrigin.I(aWM) += aInnerMargin.IStart(aWM);
  553. }
  554. break;
  555. case NS_STYLE_CAPTION_SIDE_LEFT:
  556. case NS_STYLE_CAPTION_SIDE_RIGHT:
  557. aOrigin.I(aWM) = aCaptionMargin.IStart(aWM);
  558. if (aWM.IsBidiLTR() == (aCaptionSide == NS_STYLE_CAPTION_SIDE_RIGHT)) {
  559. aOrigin.I(aWM) += aInnerMargin.IStart(aWM) + aInnerSize.ISize(aWM);
  560. }
  561. break;
  562. default: // block-start
  563. NS_ASSERTION(aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP ||
  564. aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE,
  565. "unexpected caption side");
  566. aOrigin.I(aWM) = aCaptionMargin.IStart(aWM);
  567. if (aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP) {
  568. // We placed the caption using only the table's isize as available
  569. // isize, and we should position it this way as well.
  570. aOrigin.I(aWM) += aInnerMargin.IStart(aWM);
  571. }
  572. break;
  573. }
  574. // block-dir computation
  575. switch (aCaptionSide) {
  576. case NS_STYLE_CAPTION_SIDE_RIGHT:
  577. case NS_STYLE_CAPTION_SIDE_LEFT:
  578. aOrigin.B(aWM) = aInnerMargin.BStart(aWM);
  579. switch (GetCaptionVerticalAlign()) {
  580. case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
  581. aOrigin.B(aWM) = std::max(0, aInnerMargin.BStart(aWM) +
  582. ((aInnerSize.BSize(aWM) -
  583. aCaptionSize.BSize(aWM)) / 2));
  584. break;
  585. case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
  586. aOrigin.B(aWM) = std::max(0, aInnerMargin.BStart(aWM) +
  587. aInnerSize.BSize(aWM) -
  588. aCaptionSize.BSize(aWM));
  589. break;
  590. default:
  591. break;
  592. }
  593. break;
  594. case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE:
  595. case NS_STYLE_CAPTION_SIDE_BOTTOM:
  596. aOrigin.B(aWM) = aInnerMargin.BStart(aWM) + aInnerSize.BSize(aWM) +
  597. aCaptionMargin.BStart(aWM);
  598. break;
  599. case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE:
  600. case NS_STYLE_CAPTION_SIDE_TOP:
  601. aOrigin.B(aWM) = aInnerMargin.BStart(aWM) + aCaptionMargin.BStart(aWM);
  602. break;
  603. default:
  604. NS_NOTREACHED("Unknown caption alignment type");
  605. break;
  606. }
  607. return NS_OK;
  608. }
  609. nsresult
  610. nsTableWrapperFrame::GetInnerOrigin(uint32_t aCaptionSide,
  611. const LogicalSize& aContainBlockSize,
  612. const LogicalSize& aCaptionSize,
  613. const LogicalMargin& aCaptionMargin,
  614. const LogicalSize& aInnerSize,
  615. LogicalMargin& aInnerMargin,
  616. LogicalPoint& aOrigin,
  617. WritingMode aWM)
  618. {
  619. NS_ASSERTION(NS_AUTOMARGIN != aCaptionMargin.IStart(aWM) &&
  620. NS_AUTOMARGIN != aCaptionMargin.IEnd(aWM),
  621. "The computed caption margin is auto?");
  622. NS_ASSERTION(NS_AUTOMARGIN != aInnerMargin.IStart(aWM) &&
  623. NS_AUTOMARGIN != aInnerMargin.IEnd(aWM) &&
  624. NS_AUTOMARGIN != aInnerMargin.BStart(aWM) &&
  625. NS_AUTOMARGIN != aInnerMargin.BEnd(aWM),
  626. "The computed inner margin is auto?");
  627. aOrigin.I(aWM) = aOrigin.B(aWM) = 0;
  628. if ((NS_UNCONSTRAINEDSIZE == aInnerSize.ISize(aWM)) ||
  629. (NS_UNCONSTRAINEDSIZE == aInnerSize.BSize(aWM)) ||
  630. (NS_UNCONSTRAINEDSIZE == aCaptionSize.ISize(aWM)) ||
  631. (NS_UNCONSTRAINEDSIZE == aCaptionSize.BSize(aWM))) {
  632. return NS_OK;
  633. }
  634. nscoord minCapISize =
  635. aCaptionSize.ISize(aWM) + aCaptionMargin.IStartEnd(aWM);
  636. // inline-dir computation
  637. switch (aCaptionSide) {
  638. case NS_STYLE_CAPTION_SIDE_LEFT:
  639. case NS_STYLE_CAPTION_SIDE_RIGHT:
  640. if (aWM.IsBidiLTR() == (aCaptionSide == NS_STYLE_CAPTION_SIDE_LEFT)) {
  641. if (aInnerMargin.IStart(aWM) < minCapISize) {
  642. // shift the inner table to get some place for the caption
  643. aInnerMargin.IEnd(aWM) += aInnerMargin.IStart(aWM) - minCapISize;
  644. aInnerMargin.IEnd(aWM) = std::max(0, aInnerMargin.IEnd(aWM));
  645. aInnerMargin.IStart(aWM) = minCapISize;
  646. }
  647. }
  648. aOrigin.I(aWM) = aInnerMargin.IStart(aWM);
  649. break;
  650. default:
  651. NS_ASSERTION(aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP ||
  652. aCaptionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE ||
  653. aCaptionSide == NS_STYLE_CAPTION_SIDE_BOTTOM ||
  654. aCaptionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE ||
  655. aCaptionSide == NO_SIDE,
  656. "unexpected caption side");
  657. aOrigin.I(aWM) = aInnerMargin.IStart(aWM);
  658. break;
  659. }
  660. // block-dir computation
  661. switch (aCaptionSide) {
  662. case NS_STYLE_CAPTION_SIDE_BOTTOM:
  663. case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE:
  664. aOrigin.B(aWM) = aInnerMargin.BStart(aWM);
  665. break;
  666. case NS_STYLE_CAPTION_SIDE_LEFT:
  667. case NS_STYLE_CAPTION_SIDE_RIGHT:
  668. aOrigin.B(aWM) = aInnerMargin.BStart(aWM);
  669. switch (GetCaptionVerticalAlign()) {
  670. case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
  671. aOrigin.B(aWM) =
  672. std::max(aInnerMargin.BStart(aWM),
  673. (aCaptionSize.BSize(aWM) - aInnerSize.BSize(aWM)) / 2);
  674. break;
  675. case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
  676. aOrigin.B(aWM) =
  677. std::max(aInnerMargin.BStart(aWM),
  678. aCaptionSize.BSize(aWM) - aInnerSize.BSize(aWM));
  679. break;
  680. default:
  681. break;
  682. }
  683. break;
  684. case NO_SIDE:
  685. case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE:
  686. case NS_STYLE_CAPTION_SIDE_TOP:
  687. aOrigin.B(aWM) = aInnerMargin.BStart(aWM) + aCaptionSize.BSize(aWM) +
  688. aCaptionMargin.BStartEnd(aWM);
  689. break;
  690. default:
  691. NS_NOTREACHED("Unknown caption alignment type");
  692. break;
  693. }
  694. return NS_OK;
  695. }
  696. void
  697. nsTableWrapperFrame::OuterBeginReflowChild(nsPresContext* aPresContext,
  698. nsIFrame* aChildFrame,
  699. const ReflowInput& aOuterRI,
  700. Maybe<ReflowInput>& aChildRI,
  701. nscoord aAvailISize)
  702. {
  703. // work around pixel rounding errors, round down to ensure we don't exceed the avail height in
  704. WritingMode wm = aChildFrame->GetWritingMode();
  705. LogicalSize outerSize = aOuterRI.AvailableSize(wm);
  706. nscoord availBSize = outerSize.BSize(wm);
  707. if (NS_UNCONSTRAINEDSIZE != availBSize) {
  708. if (mCaptionFrames.FirstChild() == aChildFrame) {
  709. availBSize = NS_UNCONSTRAINEDSIZE;
  710. } else {
  711. LogicalMargin margin(wm);
  712. GetChildMargin(aPresContext, aOuterRI, aChildFrame,
  713. outerSize.ISize(wm), margin);
  714. NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.BStart(wm),
  715. "No unconstrainedsize arithmetic, please");
  716. availBSize -= margin.BStart(wm);
  717. NS_ASSERTION(NS_UNCONSTRAINEDSIZE != margin.BEnd(wm),
  718. "No unconstrainedsize arithmetic, please");
  719. availBSize -= margin.BEnd(wm);
  720. }
  721. }
  722. LogicalSize availSize(wm, aAvailISize, availBSize);
  723. // create and init the child reflow state, using passed-in Maybe<>,
  724. // so that caller can use it after we return.
  725. aChildRI.emplace(aPresContext, aOuterRI, aChildFrame, availSize,
  726. nullptr, ReflowInput::CALLER_WILL_INIT);
  727. InitChildReflowInput(*aPresContext, *aChildRI);
  728. // see if we need to reset top-of-page due to a caption
  729. if (aChildRI->mFlags.mIsTopOfPage &&
  730. mCaptionFrames.FirstChild() == aChildFrame) {
  731. uint8_t captionSide = GetCaptionSide();
  732. if (captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM ||
  733. captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE) {
  734. aChildRI->mFlags.mIsTopOfPage = false;
  735. }
  736. }
  737. }
  738. void
  739. nsTableWrapperFrame::OuterDoReflowChild(nsPresContext* aPresContext,
  740. nsIFrame* aChildFrame,
  741. const ReflowInput& aChildRI,
  742. ReflowOutput& aMetrics,
  743. nsReflowStatus& aStatus)
  744. {
  745. // Using zero as containerSize here because we want consistency between
  746. // the GetLogicalPosition and ReflowChild calls, to avoid unnecessarily
  747. // changing the frame's coordinates; but we don't yet know its final
  748. // position anyway so the actual value is unimportant.
  749. const nsSize zeroCSize;
  750. WritingMode wm = aChildRI.GetWritingMode();
  751. // Use the current position as a best guess for placement.
  752. LogicalPoint childPt = aChildFrame->GetLogicalPosition(wm, zeroCSize);
  753. uint32_t flags = NS_FRAME_NO_MOVE_FRAME;
  754. // We don't want to delete our next-in-flow's child if it's an inner table
  755. // frame, because table wrapper frames always assume that their inner table
  756. // frames don't go away. If a table wrapper frame is removed because it is
  757. // a next-in-flow of an already complete table wrapper frame, then it will
  758. // take care of removing it's inner table frame.
  759. if (aChildFrame == InnerTableFrame()) {
  760. flags |= NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD;
  761. }
  762. ReflowChild(aChildFrame, aPresContext, aMetrics, aChildRI,
  763. wm, childPt, zeroCSize, flags, aStatus);
  764. }
  765. void
  766. nsTableWrapperFrame::UpdateOverflowAreas(ReflowOutput& aMet)
  767. {
  768. aMet.SetOverflowAreasToDesiredBounds();
  769. ConsiderChildOverflow(aMet.mOverflowAreas, InnerTableFrame());
  770. if (mCaptionFrames.NotEmpty()) {
  771. ConsiderChildOverflow(aMet.mOverflowAreas, mCaptionFrames.FirstChild());
  772. }
  773. }
  774. void
  775. nsTableWrapperFrame::Reflow(nsPresContext* aPresContext,
  776. ReflowOutput& aDesiredSize,
  777. const ReflowInput& aOuterRI,
  778. nsReflowStatus& aStatus)
  779. {
  780. MarkInReflow();
  781. DO_GLOBAL_REFLOW_COUNT("nsTableWrapperFrame");
  782. DISPLAY_REFLOW(aPresContext, this, aOuterRI, aDesiredSize, aStatus);
  783. // Initialize out parameters
  784. aDesiredSize.ClearSize();
  785. aStatus = NS_FRAME_COMPLETE;
  786. if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
  787. // Set up our kids. They're already present, on an overflow list,
  788. // or there are none so we'll create them now
  789. MoveOverflowToChildList();
  790. }
  791. Maybe<ReflowInput> captionRI;
  792. Maybe<ReflowInput> innerRI;
  793. nsRect origInnerRect = InnerTableFrame()->GetRect();
  794. nsRect origInnerVisualOverflow = InnerTableFrame()->GetVisualOverflowRect();
  795. bool innerFirstReflow =
  796. InnerTableFrame()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
  797. nsRect origCaptionRect;
  798. nsRect origCaptionVisualOverflow;
  799. bool captionFirstReflow = false;
  800. if (mCaptionFrames.NotEmpty()) {
  801. origCaptionRect = mCaptionFrames.FirstChild()->GetRect();
  802. origCaptionVisualOverflow =
  803. mCaptionFrames.FirstChild()->GetVisualOverflowRect();
  804. captionFirstReflow =
  805. mCaptionFrames.FirstChild()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
  806. }
  807. // ComputeAutoSize has to match this logic.
  808. WritingMode wm = aOuterRI.GetWritingMode();
  809. uint8_t captionSide = GetCaptionSide();
  810. WritingMode captionWM = wm; // will be changed below if necessary
  811. if (captionSide == NO_SIDE) {
  812. // We don't have a caption.
  813. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI,
  814. innerRI, aOuterRI.ComputedSize(wm).ISize(wm));
  815. } else if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
  816. captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) {
  817. // ComputeAutoSize takes care of making side captions small. Compute
  818. // the caption's size first, and tell the table to fit in what's left.
  819. OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRI,
  820. captionRI, aOuterRI.ComputedSize(wm).ISize(wm));
  821. captionWM = captionRI->GetWritingMode();
  822. nscoord innerAvailISize = aOuterRI.ComputedSize(wm).ISize(wm) -
  823. captionRI->ComputedSizeWithMarginBorderPadding(wm).ISize(wm);
  824. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI,
  825. innerRI, innerAvailISize);
  826. } else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP ||
  827. captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) {
  828. // Compute the table's size first, and then prevent the caption from
  829. // being larger in the inline dir unless it has to be.
  830. //
  831. // Note that CSS 2.1 (but not 2.0) says:
  832. // The width of the anonymous box is the border-edge width of the
  833. // table box inside it
  834. // We don't actually make our anonymous box that isize (if we did,
  835. // it would break 'auto' margins), but this effectively does that.
  836. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI,
  837. innerRI, aOuterRI.ComputedSize(wm).ISize(wm));
  838. // It's good that CSS 2.1 says not to include margins, since we
  839. // can't, since they already been converted so they exactly
  840. // fill the available isize (ignoring the margin on one side if
  841. // neither are auto). (We take advantage of that later when we call
  842. // GetCaptionOrigin, though.)
  843. nscoord innerBorderISize =
  844. innerRI->ComputedSizeWithBorderPadding(wm).ISize(wm);
  845. OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(), aOuterRI,
  846. captionRI, innerBorderISize);
  847. captionWM = captionRI->GetWritingMode();
  848. } else {
  849. NS_ASSERTION(captionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE ||
  850. captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE,
  851. "unexpected caption-side");
  852. // Size the table and the caption independently.
  853. captionWM = mCaptionFrames.FirstChild()->GetWritingMode();
  854. OuterBeginReflowChild(aPresContext, mCaptionFrames.FirstChild(),
  855. aOuterRI, captionRI,
  856. aOuterRI.ComputedSize(captionWM).ISize(captionWM));
  857. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI,
  858. innerRI, aOuterRI.ComputedSize(wm).ISize(wm));
  859. }
  860. // First reflow the caption.
  861. Maybe<ReflowOutput> captionMet;
  862. LogicalSize captionSize(wm);
  863. LogicalMargin captionMargin(wm);
  864. if (mCaptionFrames.NotEmpty()) {
  865. captionMet.emplace(wm);
  866. nsReflowStatus capStatus; // don't let the caption cause incomplete
  867. OuterDoReflowChild(aPresContext, mCaptionFrames.FirstChild(),
  868. *captionRI, *captionMet, capStatus);
  869. captionSize.ISize(wm) = captionMet->ISize(wm);
  870. captionSize.BSize(wm) = captionMet->BSize(wm);
  871. captionMargin =
  872. captionRI->ComputedLogicalMargin().ConvertTo(wm, captionWM);
  873. // Now that we know the bsize of the caption, reduce the available bsize
  874. // for the table frame if we are bsize constrained and the caption is above
  875. // or below the inner table. Also reduce the CB size that we store for
  876. // our children in case we're a grid item, by the same amount.
  877. LogicalSize* cbSize = GetProperty(GridItemCBSizeProperty());
  878. if (NS_UNCONSTRAINEDSIZE != aOuterRI.AvailableBSize() || cbSize) {
  879. nscoord captionBSize = 0;
  880. nscoord captionISize = 0;
  881. switch (captionSide) {
  882. case NS_STYLE_CAPTION_SIDE_TOP:
  883. case NS_STYLE_CAPTION_SIDE_BOTTOM:
  884. case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE:
  885. case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE:
  886. captionBSize = captionSize.BSize(wm) + captionMargin.BStartEnd(wm);
  887. break;
  888. case NS_STYLE_CAPTION_SIDE_LEFT:
  889. case NS_STYLE_CAPTION_SIDE_RIGHT:
  890. captionISize = captionSize.ISize(wm) + captionMargin.IStartEnd(wm);
  891. break;
  892. }
  893. if (NS_UNCONSTRAINEDSIZE != aOuterRI.AvailableBSize()) {
  894. innerRI->AvailableBSize() =
  895. std::max(0, innerRI->AvailableBSize() - captionBSize);
  896. }
  897. if (cbSize) {
  898. // Shrink the CB size by the size reserved for the caption.
  899. LogicalSize oldCBSize = *cbSize;
  900. cbSize->ISize(wm) = std::max(0, cbSize->ISize(wm) - captionISize);
  901. cbSize->BSize(wm) = std::max(0, cbSize->BSize(wm) - captionBSize);
  902. if (oldCBSize != *cbSize) {
  903. // Reset the inner table's ReflowInput to stretch it to the new size.
  904. innerRI.reset();
  905. OuterBeginReflowChild(aPresContext, InnerTableFrame(), aOuterRI,
  906. innerRI, aOuterRI.ComputedSize(wm).ISize(wm));
  907. }
  908. }
  909. }
  910. }
  911. // Then, now that we know how much to reduce the isize of the inner
  912. // table to account for side captions, reflow the inner table.
  913. ReflowOutput innerMet(innerRI->GetWritingMode());
  914. OuterDoReflowChild(aPresContext, InnerTableFrame(), *innerRI,
  915. innerMet, aStatus);
  916. LogicalSize innerSize(wm, innerMet.ISize(wm), innerMet.BSize(wm));
  917. LogicalMargin innerMargin = innerRI->ComputedLogicalMargin();
  918. LogicalSize containSize(wm, GetContainingBlockSize(aOuterRI));
  919. // Now that we've reflowed both we can place them.
  920. // XXXldb Most of the input variables here are now uninitialized!
  921. // XXX Need to recompute inner table's auto margins for the case of side
  922. // captions. (Caption's are broken too, but that should be fixed earlier.)
  923. // Compute the desiredSize so that we can use it as the containerSize
  924. // for the FinishReflowChild calls below.
  925. LogicalSize desiredSize(wm);
  926. SetDesiredSize(captionSide, innerSize, captionSize,
  927. innerMargin, captionMargin,
  928. desiredSize.ISize(wm), desiredSize.BSize(wm), wm);
  929. aDesiredSize.SetSize(wm, desiredSize);
  930. nsSize containerSize = aDesiredSize.PhysicalSize();
  931. // XXX It's possible for this to be NS_UNCONSTRAINEDSIZE, which will result
  932. // in assertions from FinishReflowChild.
  933. if (mCaptionFrames.NotEmpty()) {
  934. LogicalPoint captionOrigin(wm);
  935. GetCaptionOrigin(captionSide, containSize, innerSize, innerMargin,
  936. captionSize, captionMargin, captionOrigin, wm);
  937. FinishReflowChild(mCaptionFrames.FirstChild(), aPresContext, *captionMet,
  938. captionRI.ptr(), wm, captionOrigin, containerSize, 0);
  939. captionRI.reset();
  940. }
  941. // XXX If the bsize is constrained then we need to check whether
  942. // everything still fits...
  943. LogicalPoint innerOrigin(wm);
  944. GetInnerOrigin(captionSide, containSize, captionSize, captionMargin,
  945. innerSize, innerMargin, innerOrigin, wm);
  946. FinishReflowChild(InnerTableFrame(), aPresContext, innerMet, innerRI.ptr(),
  947. wm, innerOrigin, containerSize, 0);
  948. innerRI.reset();
  949. nsTableFrame::InvalidateTableFrame(InnerTableFrame(), origInnerRect,
  950. origInnerVisualOverflow,
  951. innerFirstReflow);
  952. if (mCaptionFrames.NotEmpty()) {
  953. nsTableFrame::InvalidateTableFrame(mCaptionFrames.FirstChild(),
  954. origCaptionRect,
  955. origCaptionVisualOverflow,
  956. captionFirstReflow);
  957. }
  958. UpdateOverflowAreas(aDesiredSize);
  959. if (GetPrevInFlow()) {
  960. ReflowOverflowContainerChildren(aPresContext, aOuterRI,
  961. aDesiredSize.mOverflowAreas, 0,
  962. aStatus);
  963. }
  964. FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aOuterRI, aStatus);
  965. // Return our desired rect
  966. NS_FRAME_SET_TRUNCATION(aStatus, aOuterRI, aDesiredSize);
  967. }
  968. nsIAtom*
  969. nsTableWrapperFrame::GetType() const
  970. {
  971. return nsGkAtoms::tableWrapperFrame;
  972. }
  973. /* ----- global methods ----- */
  974. nsIContent*
  975. nsTableWrapperFrame::GetCellAt(uint32_t aRowIdx, uint32_t aColIdx) const
  976. {
  977. nsTableCellMap* cellMap = InnerTableFrame()->GetCellMap();
  978. if (!cellMap) {
  979. return nullptr;
  980. }
  981. nsTableCellFrame* cell = cellMap->GetCellInfoAt(aRowIdx, aColIdx);
  982. if (!cell) {
  983. return nullptr;
  984. }
  985. return cell->GetContent();
  986. }
  987. nsTableWrapperFrame*
  988. NS_NewTableWrapperFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  989. {
  990. return new (aPresShell) nsTableWrapperFrame(aContext);
  991. }
  992. NS_IMPL_FRAMEARENA_HELPERS(nsTableWrapperFrame)
  993. #ifdef DEBUG_FRAME_DUMP
  994. nsresult
  995. nsTableWrapperFrame::GetFrameName(nsAString& aResult) const
  996. {
  997. return MakeFrameName(NS_LITERAL_STRING("TableWrapper"), aResult);
  998. }
  999. #endif