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/. */
6 #include "nsTableWrapperFrame.h"
8 #include "mozilla/ComputedStyle.h"
9 #include "mozilla/PresShell.h"
10 #include "nsFrameManager.h"
11 #include "nsTableFrame.h"
12 #include "nsTableCellFrame.h"
13 #include "nsStyleConsts.h"
14 #include "nsPresContext.h"
15 #include "nsCSSRendering.h"
16 #include "nsIContent.h"
18 #include "nsGkAtoms.h"
19 #include "nsHTMLParts.h"
20 #include "nsDisplayList.h"
21 #include "nsLayoutUtils.h"
22 #include "nsIFrameInlines.h"
25 using namespace mozilla
;
26 using namespace mozilla::layout
;
31 nscoord
nsTableWrapperFrame::GetLogicalBaseline(
32 WritingMode aWritingMode
) const {
33 if (StyleDisplay()->IsContainLayout()) {
34 // We have no baseline. Fall back to the inherited impl which is
35 // appropriate for this situation.
36 return nsContainerFrame::GetLogicalBaseline(aWritingMode
);
39 nsIFrame
* kid
= mFrames
.FirstChild();
41 MOZ_ASSERT_UNREACHABLE("no inner table");
42 return nsContainerFrame::GetLogicalBaseline(aWritingMode
);
45 return kid
->GetLogicalBaseline(aWritingMode
) +
46 kid
->BStart(aWritingMode
, mRect
.Size());
49 nsTableWrapperFrame::nsTableWrapperFrame(ComputedStyle
* aStyle
,
50 nsPresContext
* aPresContext
,
52 : nsContainerFrame(aStyle
, aPresContext
, aID
) {}
54 nsTableWrapperFrame::~nsTableWrapperFrame() = default;
56 NS_QUERYFRAME_HEAD(nsTableWrapperFrame
)
57 NS_QUERYFRAME_ENTRY(nsTableWrapperFrame
)
58 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame
)
61 a11y::AccType
nsTableWrapperFrame::AccessibleType() {
62 return a11y::eHTMLTableType
;
66 void nsTableWrapperFrame::DestroyFrom(nsIFrame
* aDestructRoot
,
67 PostDestroyData
& aPostDestroyData
) {
68 DestroyAbsoluteFrames(aDestructRoot
, aPostDestroyData
);
69 mCaptionFrames
.DestroyFramesFrom(aDestructRoot
, aPostDestroyData
);
70 nsContainerFrame::DestroyFrom(aDestructRoot
, aPostDestroyData
);
73 const nsFrameList
& nsTableWrapperFrame::GetChildList(
74 ChildListID aListID
) const {
75 if (aListID
== kCaptionList
) {
76 return mCaptionFrames
;
79 return nsContainerFrame::GetChildList(aListID
);
82 void nsTableWrapperFrame::GetChildLists(nsTArray
<ChildList
>* aLists
) const {
83 nsContainerFrame::GetChildLists(aLists
);
84 mCaptionFrames
.AppendIfNonempty(aLists
, kCaptionList
);
87 void nsTableWrapperFrame::SetInitialChildList(ChildListID aListID
,
88 nsFrameList
& aChildList
) {
89 if (kCaptionList
== aListID
) {
91 nsFrame::VerifyDirtyBitSet(aChildList
);
92 for (nsIFrame
* f
: aChildList
) {
93 MOZ_ASSERT(f
->GetParent() == this, "Unexpected parent");
96 // the frame constructor already checked for table-caption display type
97 MOZ_ASSERT(mCaptionFrames
.IsEmpty(),
98 "already have child frames in CaptionList");
99 mCaptionFrames
.SetFrames(aChildList
);
101 MOZ_ASSERT(kPrincipalList
!= aListID
||
102 (aChildList
.FirstChild() &&
103 aChildList
.FirstChild() == aChildList
.LastChild() &&
104 aChildList
.FirstChild()->IsTableFrame()),
105 "expected a single table frame in principal child list");
106 nsContainerFrame::SetInitialChildList(aListID
, aChildList
);
110 void nsTableWrapperFrame::AppendFrames(ChildListID aListID
,
111 nsFrameList
& aFrameList
) {
112 // We only have two child frames: the inner table and a caption frame.
113 // The inner frame is provided when we're initialized, and it cannot change
114 MOZ_ASSERT(kCaptionList
== aListID
, "unexpected child list");
115 MOZ_ASSERT(aFrameList
.IsEmpty() || aFrameList
.FirstChild()->IsTableCaption(),
116 "appending non-caption frame to captionList");
117 mCaptionFrames
.AppendFrames(nullptr, aFrameList
);
119 // Reflow the new caption frame. It's already marked dirty, so
120 // just tell the pres shell.
121 PresShell()->FrameNeedsReflow(this, IntrinsicDirty::TreeChange
,
122 NS_FRAME_HAS_DIRTY_CHILDREN
);
123 // The presence of caption frames makes us sort our display
124 // list differently, so mark us as changed for the new
126 MarkNeedsDisplayItemRebuild();
129 void nsTableWrapperFrame::InsertFrames(
130 ChildListID aListID
, nsIFrame
* aPrevFrame
,
131 const nsLineList::iterator
* aPrevFrameLine
, nsFrameList
& aFrameList
) {
132 MOZ_ASSERT(kCaptionList
== aListID
, "unexpected child list");
133 MOZ_ASSERT(aFrameList
.IsEmpty() || aFrameList
.FirstChild()->IsTableCaption(),
134 "inserting non-caption frame into captionList");
135 MOZ_ASSERT(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
136 "inserting after sibling frame with different parent");
137 mCaptionFrames
.InsertFrames(nullptr, aPrevFrame
, aFrameList
);
139 // Reflow the new caption frame. It's already marked dirty, so
140 // just tell the pres shell.
141 PresShell()->FrameNeedsReflow(this, IntrinsicDirty::TreeChange
,
142 NS_FRAME_HAS_DIRTY_CHILDREN
);
143 MarkNeedsDisplayItemRebuild();
146 void nsTableWrapperFrame::RemoveFrame(ChildListID aListID
,
147 nsIFrame
* aOldFrame
) {
148 // We only have two child frames: the inner table and one caption frame.
149 // The inner frame can't be removed so this should be the caption
150 MOZ_ASSERT(kCaptionList
== aListID
, "can't remove inner frame");
152 if (HasSideCaption()) {
153 // The old caption isize had an effect on the inner table isize, so
154 // we're going to need to reflow it. Mark it dirty
155 InnerTableFrame()->MarkSubtreeDirty();
158 // Remove the frame and destroy it
159 mCaptionFrames
.DestroyFrame(aOldFrame
);
161 PresShell()->FrameNeedsReflow(this, IntrinsicDirty::TreeChange
,
162 NS_FRAME_HAS_DIRTY_CHILDREN
);
163 MarkNeedsDisplayItemRebuild();
166 void nsTableWrapperFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
167 const nsDisplayListSet
& aLists
) {
168 // No border or background is painted because they belong to the inner table.
169 // The outline belongs to the wrapper frame so it can contain the caption.
171 // If there's no caption, take a short cut to avoid having to create
172 // the special display list set and then sort it.
173 if (mCaptionFrames
.IsEmpty()) {
174 BuildDisplayListForInnerTable(aBuilder
, aLists
);
175 DisplayOutline(aBuilder
, aLists
);
179 nsDisplayListCollection
set(aBuilder
);
180 BuildDisplayListForInnerTable(aBuilder
, set
);
182 nsDisplayListSet
captionSet(set
, set
.BlockBorderBackgrounds());
183 BuildDisplayListForChild(aBuilder
, mCaptionFrames
.FirstChild(), captionSet
);
185 // Now we have to sort everything by content order, since the caption
186 // may be somewhere inside the table.
187 // We don't sort BlockBorderBackgrounds and BorderBackgrounds because the
188 // display items in those lists should stay out of content order in order to
189 // follow the rules in https://www.w3.org/TR/CSS21/zindex.html#painting-order
190 // and paint the caption background after all of the rest.
191 set
.Floats()->SortByContentOrder(GetContent());
192 set
.Content()->SortByContentOrder(GetContent());
193 set
.PositionedDescendants()->SortByContentOrder(GetContent());
194 set
.Outlines()->SortByContentOrder(GetContent());
197 DisplayOutline(aBuilder
, aLists
);
200 void nsTableWrapperFrame::BuildDisplayListForInnerTable(
201 nsDisplayListBuilder
* aBuilder
, const nsDisplayListSet
& aLists
) {
202 // Just paint the regular children, but the children's background is our
203 // true background (there should only be one, the real table)
204 nsIFrame
* kid
= mFrames
.FirstChild();
205 // The children should be in content order
207 BuildDisplayListForChild(aBuilder
, kid
, aLists
);
208 kid
= kid
->GetNextSibling();
212 ComputedStyle
* nsTableWrapperFrame::GetParentComputedStyle(
213 nsIFrame
** aProviderFrame
) const {
214 // The table wrapper frame and the (inner) table frame split the style
215 // data by giving the table frame the ComputedStyle associated with
216 // the table content node and creating a ComputedStyle for the wrapper
217 // frame that is a *child* of the table frame's ComputedStyle,
218 // matching the ::-moz-table-wrapper pseudo-element. html.css has a
219 // rule that causes that pseudo-element (and thus the wrapper table)
220 // to inherit *some* style properties from the table frame. The
221 // children of the table inherit directly from the inner table, and
222 // the table wrapper's ComputedStyle is a leaf.
224 return (*aProviderFrame
= InnerTableFrame())->Style();
227 // INCREMENTAL REFLOW HELPER FUNCTIONS
229 void nsTableWrapperFrame::InitChildReflowInput(nsPresContext
& aPresContext
,
230 const ReflowInput
& aOuterRI
,
231 ReflowInput
& aReflowInput
) {
232 nsMargin collapseBorder
;
233 nsMargin
collapsePadding(0, 0, 0, 0);
234 nsMargin
* pCollapseBorder
= nullptr;
235 nsMargin
* pCollapsePadding
= nullptr;
236 Maybe
<LogicalSize
> cbSize
;
237 if (aReflowInput
.mFrame
== InnerTableFrame()) {
238 WritingMode wm
= aReflowInput
.GetWritingMode();
239 if (InnerTableFrame()->IsBorderCollapse()) {
240 LogicalMargin border
= InnerTableFrame()->GetIncludedOuterBCBorder(wm
);
241 collapseBorder
= border
.GetPhysicalMargin(wm
);
242 pCollapseBorder
= &collapseBorder
;
243 pCollapsePadding
= &collapsePadding
;
245 // Propagate our stored CB size if present, minus any margins.
247 // Note that inner table computed margins are always zero, they're inherited
248 // by the table wrapper, so we need to get our margin from aOuterRI.
249 if (!HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
)) {
250 if (LogicalSize
* cb
= GetProperty(GridItemCBSizeProperty())) {
252 *cbSize
-= aOuterRI
.ComputedLogicalMargin().Size(wm
);
256 // For inner table frames, the containing block is the same as for
257 // the outer table frame.
258 cbSize
.emplace(aOuterRI
.mContainingBlockSize
);
261 aReflowInput
.Init(&aPresContext
, cbSize
, pCollapseBorder
, pCollapsePadding
);
264 // get the margin and padding data. ReflowInput doesn't handle the
265 // case of auto margins
266 void nsTableWrapperFrame::GetChildMargin(nsPresContext
* aPresContext
,
267 const ReflowInput
& aOuterRI
,
268 nsIFrame
* aChildFrame
,
270 LogicalMargin
& aMargin
) {
271 NS_ASSERTION(!aChildFrame
->IsTableCaption(),
272 "didn't expect caption frame; writing-mode may be wrong!");
274 // construct a reflow input to compute margin and padding. Auto margins
275 // will not be computed at this time.
277 // create and init the child reflow input
278 // XXX We really shouldn't construct a reflow input to do this.
279 WritingMode wm
= aOuterRI
.GetWritingMode();
280 LogicalSize
availSize(wm
, aAvailISize
, aOuterRI
.AvailableSize(wm
).BSize(wm
));
281 ReflowInput
childRI(aPresContext
, aOuterRI
, aChildFrame
, availSize
, Nothing(),
282 ReflowInput::CALLER_WILL_INIT
);
283 InitChildReflowInput(*aPresContext
, aOuterRI
, childRI
);
285 aMargin
= childRI
.ComputedLogicalMargin();
288 static nsSize
GetContainingBlockSize(const ReflowInput
& aOuterRI
) {
290 const ReflowInput
* containRS
= aOuterRI
.mCBReflowInput
;
293 size
.width
= containRS
->ComputedWidth();
294 if (NS_UNCONSTRAINEDSIZE
== size
.width
) {
297 size
.height
= containRS
->ComputedHeight();
298 if (NS_UNCONSTRAINEDSIZE
== size
.height
) {
306 nscoord
nsTableWrapperFrame::GetMinISize(gfxContext
* aRenderingContext
) {
307 nscoord iSize
= nsLayoutUtils::IntrinsicForContainer(
308 aRenderingContext
, InnerTableFrame(), nsLayoutUtils::MIN_ISIZE
);
309 DISPLAY_MIN_INLINE_SIZE(this, iSize
);
310 if (mCaptionFrames
.NotEmpty()) {
311 nscoord capISize
= nsLayoutUtils::IntrinsicForContainer(
312 aRenderingContext
, mCaptionFrames
.FirstChild(),
313 nsLayoutUtils::MIN_ISIZE
);
314 if (HasSideCaption()) {
317 if (capISize
> iSize
) {
326 nscoord
nsTableWrapperFrame::GetPrefISize(gfxContext
* aRenderingContext
) {
328 DISPLAY_PREF_INLINE_SIZE(this, maxISize
);
330 maxISize
= nsLayoutUtils::IntrinsicForContainer(
331 aRenderingContext
, InnerTableFrame(), nsLayoutUtils::PREF_ISIZE
);
332 if (mCaptionFrames
.NotEmpty()) {
333 uint8_t captionSide
= GetCaptionSide();
334 switch (captionSide
) {
335 case NS_STYLE_CAPTION_SIDE_LEFT
:
336 case NS_STYLE_CAPTION_SIDE_RIGHT
: {
337 nscoord capMin
= nsLayoutUtils::IntrinsicForContainer(
338 aRenderingContext
, mCaptionFrames
.FirstChild(),
339 nsLayoutUtils::MIN_ISIZE
);
343 nsLayoutUtils::IntrinsicISizeType iwt
;
344 if (captionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
345 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
346 // Don't let the caption's pref isize expand the table's pref
348 iwt
= nsLayoutUtils::MIN_ISIZE
;
350 NS_ASSERTION(captionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
||
351 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
,
352 "unexpected caption side");
353 iwt
= nsLayoutUtils::PREF_ISIZE
;
355 nscoord capPref
= nsLayoutUtils::IntrinsicForContainer(
356 aRenderingContext
, mCaptionFrames
.FirstChild(), iwt
);
357 maxISize
= std::max(maxISize
, capPref
);
364 nscoord
nsTableWrapperFrame::ChildShrinkWrapISize(
365 gfxContext
* aRenderingContext
, nsIFrame
* aChildFrame
, WritingMode aWM
,
366 LogicalSize aCBSize
, nscoord aAvailableISize
,
367 nscoord
* aMarginResult
) const {
368 AutoMaybeDisableFontInflation
an(aChildFrame
);
370 // For the caption frame, child's WM may differ from the table's main WM.
371 WritingMode childWM
= aChildFrame
->GetWritingMode();
373 SizeComputationInput
offsets(aChildFrame
, aRenderingContext
, aWM
,
375 LogicalSize marginSize
=
376 offsets
.ComputedLogicalMargin().Size(childWM
).ConvertTo(aWM
, childWM
);
377 LogicalSize paddingSize
=
378 offsets
.ComputedLogicalPadding().Size(childWM
).ConvertTo(aWM
, childWM
);
380 offsets
.ComputedLogicalBorderPadding().Size(childWM
).ConvertTo(aWM
,
383 // Shrink-wrap aChildFrame by default, except if we're a stretched grid item.
384 auto flags
= ComputeSizeFlags::eShrinkWrap
;
385 auto parent
= GetParent();
386 bool isGridItem
= parent
&& parent
->IsGridContainerFrame() &&
387 !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW
);
388 if (MOZ_UNLIKELY(isGridItem
) && !StyleMargin()->HasInlineAxisAuto(aWM
)) {
389 auto inlineAxisAlignment
=
390 aWM
.IsOrthogonalTo(parent
->GetWritingMode())
391 ? StylePosition()->UsedAlignSelf(parent
->Style())._0
392 : StylePosition()->UsedJustifySelf(parent
->Style())._0
;
393 if (inlineAxisAlignment
== StyleAlignFlags::NORMAL
||
394 inlineAxisAlignment
== StyleAlignFlags::STRETCH
) {
395 flags
= nsIFrame::ComputeSizeFlags::eDefault
;
399 LogicalSize size
= aChildFrame
->ComputeSize(
400 aRenderingContext
, aWM
, aCBSize
, aAvailableISize
, marginSize
,
401 bpSize
- paddingSize
, paddingSize
, flags
);
403 *aMarginResult
= offsets
.ComputedLogicalMargin().IStartEnd(aWM
);
405 return size
.ISize(aWM
) + marginSize
.ISize(aWM
) + bpSize
.ISize(aWM
);
409 LogicalSize
nsTableWrapperFrame::ComputeAutoSize(
410 gfxContext
* aRenderingContext
, WritingMode aWM
, const LogicalSize
& aCBSize
,
411 nscoord aAvailableISize
, const LogicalSize
& aMargin
,
412 const LogicalSize
& aBorder
, const LogicalSize
& aPadding
,
413 ComputeSizeFlags aFlags
) {
414 nscoord kidAvailableISize
= aAvailableISize
- aMargin
.ISize(aWM
);
415 NS_ASSERTION(aBorder
.IsAllZero() && aPadding
.IsAllZero(),
416 "Table wrapper frames cannot have borders or paddings");
418 // When we're shrink-wrapping, our auto size needs to wrap around the
419 // actual size of the table, which (if it is specified as a percent)
420 // could be something that is not reflected in our GetMinISize and
421 // GetPrefISize. See bug 349457 for an example.
423 // Match the availableISize logic in Reflow.
424 uint8_t captionSide
= GetCaptionSide();
426 if (captionSide
== NO_SIDE
) {
427 inlineSize
= ChildShrinkWrapISize(aRenderingContext
, InnerTableFrame(), aWM
,
428 aCBSize
, kidAvailableISize
);
429 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_LEFT
||
430 captionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
) {
432 ChildShrinkWrapISize(aRenderingContext
, mCaptionFrames
.FirstChild(),
433 aWM
, aCBSize
, kidAvailableISize
);
434 inlineSize
= capISize
+
435 ChildShrinkWrapISize(aRenderingContext
, InnerTableFrame(), aWM
,
436 aCBSize
, kidAvailableISize
- capISize
);
437 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
438 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
440 inlineSize
= ChildShrinkWrapISize(aRenderingContext
, InnerTableFrame(), aWM
,
441 aCBSize
, kidAvailableISize
, &margin
);
443 ChildShrinkWrapISize(aRenderingContext
, mCaptionFrames
.FirstChild(),
444 aWM
, aCBSize
, inlineSize
- margin
);
445 if (capISize
> inlineSize
) {
446 inlineSize
= capISize
;
449 NS_ASSERTION(captionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
||
450 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
,
451 "unexpected caption-side");
452 inlineSize
= ChildShrinkWrapISize(aRenderingContext
, InnerTableFrame(), aWM
,
453 aCBSize
, kidAvailableISize
);
455 ChildShrinkWrapISize(aRenderingContext
, mCaptionFrames
.FirstChild(),
456 aWM
, aCBSize
, kidAvailableISize
);
457 if (capISize
> inlineSize
) {
458 inlineSize
= capISize
;
462 return LogicalSize(aWM
, inlineSize
, NS_UNCONSTRAINEDSIZE
);
465 uint8_t nsTableWrapperFrame::GetCaptionSide() {
466 if (mCaptionFrames
.NotEmpty()) {
467 return mCaptionFrames
.FirstChild()->StyleTableBorder()->mCaptionSide
;
469 return NO_SIDE
; // no caption
473 StyleVerticalAlignKeyword
nsTableWrapperFrame::GetCaptionVerticalAlign() const {
474 const auto& va
= mCaptionFrames
.FirstChild()->StyleDisplay()->mVerticalAlign
;
475 return va
.IsKeyword() ? va
.AsKeyword() : StyleVerticalAlignKeyword::Top
;
478 void nsTableWrapperFrame::SetDesiredSize(uint8_t aCaptionSide
,
479 const LogicalSize
& aInnerSize
,
480 const LogicalSize
& aCaptionSize
,
481 const LogicalMargin
& aInnerMargin
,
482 const LogicalMargin
& aCaptionMargin
,
483 nscoord
& aISize
, nscoord
& aBSize
,
487 // compute the overall inline-size
488 switch (aCaptionSide
) {
489 case NS_STYLE_CAPTION_SIDE_LEFT
:
491 std::max(aInnerMargin
.LineLeft(aWM
),
492 aCaptionMargin
.IStartEnd(aWM
) + aCaptionSize
.ISize(aWM
)) +
493 aInnerSize
.ISize(aWM
) + aInnerMargin
.LineRight(aWM
);
495 case NS_STYLE_CAPTION_SIDE_RIGHT
:
497 std::max(aInnerMargin
.LineRight(aWM
),
498 aCaptionMargin
.IStartEnd(aWM
) + aCaptionSize
.ISize(aWM
)) +
499 aInnerSize
.ISize(aWM
) + aInnerMargin
.LineLeft(aWM
);
503 std::max(aInnerMargin
.IStartEnd(aWM
) + aInnerSize
.ISize(aWM
),
504 aCaptionMargin
.IStartEnd(aWM
) + aCaptionSize
.ISize(aWM
));
508 // compute the overall block-size
509 switch (aCaptionSide
) {
510 case NS_STYLE_CAPTION_SIDE_TOP
:
511 case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
:
512 aBSize
= aInnerSize
.BSize(aWM
) + aInnerMargin
.BEnd(aWM
);
514 std::max(aInnerMargin
.BStart(aWM
),
515 aCaptionSize
.BSize(aWM
) + aCaptionMargin
.BStartEnd(aWM
));
517 case NS_STYLE_CAPTION_SIDE_BOTTOM
:
518 case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
:
519 aBSize
= aInnerSize
.BSize(aWM
) + aInnerMargin
.BStart(aWM
);
521 std::max(aInnerMargin
.BEnd(aWM
),
522 aCaptionSize
.BSize(aWM
) + aCaptionMargin
.BStartEnd(aWM
));
524 case NS_STYLE_CAPTION_SIDE_LEFT
:
525 case NS_STYLE_CAPTION_SIDE_RIGHT
:
526 aBSize
= aInnerMargin
.BStart(aWM
);
527 aBSize
+= std::max(aInnerSize
.BSize(aWM
) + aInnerMargin
.BEnd(aWM
),
528 aCaptionSize
.BSize(aWM
) + aCaptionMargin
.BEnd(aWM
));
531 NS_ASSERTION(aCaptionSide
== NO_SIDE
, "unexpected caption side");
532 aBSize
= aInnerSize
.BSize(aWM
) + aInnerMargin
.BStartEnd(aWM
);
536 // negative sizes can upset overflow-area code
537 aISize
= std::max(aISize
, 0);
538 aBSize
= std::max(aBSize
, 0);
541 nsresult
nsTableWrapperFrame::GetCaptionOrigin(
542 uint32_t aCaptionSide
, const LogicalSize
& aContainBlockSize
,
543 const LogicalSize
& aInnerSize
, const LogicalMargin
& aInnerMargin
,
544 const LogicalSize
& aCaptionSize
, LogicalMargin
& aCaptionMargin
,
545 LogicalPoint
& aOrigin
, WritingMode aWM
) {
546 aOrigin
.I(aWM
) = aOrigin
.B(aWM
) = 0;
547 if ((NS_UNCONSTRAINEDSIZE
== aInnerSize
.ISize(aWM
)) ||
548 (NS_UNCONSTRAINEDSIZE
== aInnerSize
.BSize(aWM
)) ||
549 (NS_UNCONSTRAINEDSIZE
== aCaptionSize
.ISize(aWM
)) ||
550 (NS_UNCONSTRAINEDSIZE
== aCaptionSize
.BSize(aWM
))) {
553 if (mCaptionFrames
.IsEmpty()) {
557 NS_ASSERTION(NS_AUTOMARGIN
!= aCaptionMargin
.IStart(aWM
) &&
558 NS_AUTOMARGIN
!= aCaptionMargin
.BStart(aWM
) &&
559 NS_AUTOMARGIN
!= aCaptionMargin
.BEnd(aWM
),
560 "The computed caption margin is auto?");
562 // inline-dir computation
563 switch (aCaptionSide
) {
564 case NS_STYLE_CAPTION_SIDE_BOTTOM
:
565 case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
:
566 aOrigin
.I(aWM
) = aCaptionMargin
.IStart(aWM
);
567 if (aCaptionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
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
);
573 case NS_STYLE_CAPTION_SIDE_LEFT
:
574 case NS_STYLE_CAPTION_SIDE_RIGHT
:
575 aOrigin
.I(aWM
) = aCaptionMargin
.IStart(aWM
);
576 if (aWM
.IsBidiLTR() == (aCaptionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
)) {
577 aOrigin
.I(aWM
) += aInnerMargin
.IStart(aWM
) + aInnerSize
.ISize(aWM
);
580 default: // block-start
581 NS_ASSERTION(aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
582 aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
,
583 "unexpected caption side");
584 aOrigin
.I(aWM
) = aCaptionMargin
.IStart(aWM
);
585 if (aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP
) {
586 // We placed the caption using only the table's isize as available
587 // isize, and we should position it this way as well.
588 aOrigin
.I(aWM
) += aInnerMargin
.IStart(aWM
);
592 // block-dir computation
593 switch (aCaptionSide
) {
594 case NS_STYLE_CAPTION_SIDE_RIGHT
:
595 case NS_STYLE_CAPTION_SIDE_LEFT
:
596 aOrigin
.B(aWM
) = aInnerMargin
.BStart(aWM
);
597 switch (GetCaptionVerticalAlign()) {
598 case StyleVerticalAlignKeyword::Middle
:
599 aOrigin
.B(aWM
) = std::max(
600 0, aInnerMargin
.BStart(aWM
) +
601 ((aInnerSize
.BSize(aWM
) - aCaptionSize
.BSize(aWM
)) / 2));
603 case StyleVerticalAlignKeyword::Bottom
:
605 std::max(0, aInnerMargin
.BStart(aWM
) + aInnerSize
.BSize(aWM
) -
606 aCaptionSize
.BSize(aWM
));
612 case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
:
613 case NS_STYLE_CAPTION_SIDE_BOTTOM
:
614 aOrigin
.B(aWM
) = aInnerMargin
.BStart(aWM
) + aInnerSize
.BSize(aWM
) +
615 aCaptionMargin
.BStart(aWM
);
617 case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
:
618 case NS_STYLE_CAPTION_SIDE_TOP
:
619 aOrigin
.B(aWM
) = aInnerMargin
.BStart(aWM
) + aCaptionMargin
.BStart(aWM
);
622 MOZ_ASSERT_UNREACHABLE("Unknown caption alignment type");
628 nsresult
nsTableWrapperFrame::GetInnerOrigin(
629 uint32_t aCaptionSide
, const LogicalSize
& aContainBlockSize
,
630 const LogicalSize
& aCaptionSize
, const LogicalMargin
& aCaptionMargin
,
631 const LogicalSize
& aInnerSize
, LogicalMargin
& aInnerMargin
,
632 LogicalPoint
& aOrigin
, WritingMode aWM
) {
633 NS_ASSERTION(NS_AUTOMARGIN
!= aCaptionMargin
.IStart(aWM
) &&
634 NS_AUTOMARGIN
!= aCaptionMargin
.IEnd(aWM
),
635 "The computed caption margin is auto?");
636 NS_ASSERTION(NS_AUTOMARGIN
!= aInnerMargin
.IStart(aWM
) &&
637 NS_AUTOMARGIN
!= aInnerMargin
.IEnd(aWM
) &&
638 NS_AUTOMARGIN
!= aInnerMargin
.BStart(aWM
) &&
639 NS_AUTOMARGIN
!= aInnerMargin
.BEnd(aWM
),
640 "The computed inner margin is auto?");
642 aOrigin
.I(aWM
) = aOrigin
.B(aWM
) = 0;
643 if ((NS_UNCONSTRAINEDSIZE
== aInnerSize
.ISize(aWM
)) ||
644 (NS_UNCONSTRAINEDSIZE
== aInnerSize
.BSize(aWM
)) ||
645 (NS_UNCONSTRAINEDSIZE
== aCaptionSize
.ISize(aWM
)) ||
646 (NS_UNCONSTRAINEDSIZE
== aCaptionSize
.BSize(aWM
))) {
650 nscoord minCapISize
= aCaptionSize
.ISize(aWM
) + aCaptionMargin
.IStartEnd(aWM
);
652 // inline-dir computation
653 switch (aCaptionSide
) {
654 case NS_STYLE_CAPTION_SIDE_LEFT
:
655 case NS_STYLE_CAPTION_SIDE_RIGHT
:
656 if (aWM
.IsBidiLTR() == (aCaptionSide
== NS_STYLE_CAPTION_SIDE_LEFT
)) {
657 if (aInnerMargin
.IStart(aWM
) < minCapISize
) {
658 // shift the inner table to get some place for the caption
659 aInnerMargin
.IEnd(aWM
) += aInnerMargin
.IStart(aWM
) - minCapISize
;
660 aInnerMargin
.IEnd(aWM
) = std::max(0, aInnerMargin
.IEnd(aWM
));
661 aInnerMargin
.IStart(aWM
) = minCapISize
;
664 aOrigin
.I(aWM
) = aInnerMargin
.IStart(aWM
);
667 NS_ASSERTION(aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
668 aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
||
669 aCaptionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
||
670 aCaptionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
||
671 aCaptionSide
== NO_SIDE
,
672 "unexpected caption side");
673 aOrigin
.I(aWM
) = aInnerMargin
.IStart(aWM
);
677 // block-dir computation
678 switch (aCaptionSide
) {
679 case NS_STYLE_CAPTION_SIDE_BOTTOM
:
680 case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
:
681 aOrigin
.B(aWM
) = aInnerMargin
.BStart(aWM
);
683 case NS_STYLE_CAPTION_SIDE_LEFT
:
684 case NS_STYLE_CAPTION_SIDE_RIGHT
:
685 aOrigin
.B(aWM
) = aInnerMargin
.BStart(aWM
);
686 switch (GetCaptionVerticalAlign()) {
687 case StyleVerticalAlignKeyword::Middle
:
689 std::max(aInnerMargin
.BStart(aWM
),
690 (aCaptionSize
.BSize(aWM
) - aInnerSize
.BSize(aWM
)) / 2);
692 case StyleVerticalAlignKeyword::Bottom
:
694 std::max(aInnerMargin
.BStart(aWM
),
695 aCaptionSize
.BSize(aWM
) - aInnerSize
.BSize(aWM
));
702 case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
:
703 case NS_STYLE_CAPTION_SIDE_TOP
:
704 aOrigin
.B(aWM
) = aInnerMargin
.BStart(aWM
) + aCaptionSize
.BSize(aWM
) +
705 aCaptionMargin
.BStartEnd(aWM
);
708 MOZ_ASSERT_UNREACHABLE("Unknown caption alignment type");
714 void nsTableWrapperFrame::OuterBeginReflowChild(nsPresContext
* aPresContext
,
715 nsIFrame
* aChildFrame
,
716 const ReflowInput
& aOuterRI
,
717 Maybe
<ReflowInput
>& aChildRI
,
718 nscoord aAvailISize
) {
719 // work around pixel rounding errors, round down to ensure we don't exceed the
721 WritingMode wm
= aChildFrame
->GetWritingMode();
722 LogicalSize outerSize
= aOuterRI
.AvailableSize(wm
);
723 nscoord availBSize
= outerSize
.BSize(wm
);
724 if (NS_UNCONSTRAINEDSIZE
!= availBSize
) {
725 if (mCaptionFrames
.FirstChild() == aChildFrame
) {
726 availBSize
= NS_UNCONSTRAINEDSIZE
;
728 LogicalMargin
margin(wm
);
729 GetChildMargin(aPresContext
, aOuterRI
, aChildFrame
, outerSize
.ISize(wm
),
732 NS_ASSERTION(NS_UNCONSTRAINEDSIZE
!= margin
.BStart(wm
),
733 "No unconstrainedsize arithmetic, please");
734 availBSize
-= margin
.BStart(wm
);
736 NS_ASSERTION(NS_UNCONSTRAINEDSIZE
!= margin
.BEnd(wm
),
737 "No unconstrainedsize arithmetic, please");
738 availBSize
-= margin
.BEnd(wm
);
741 LogicalSize
availSize(wm
, aAvailISize
, availBSize
);
742 // create and init the child reflow input, using passed-in Maybe<>,
743 // so that caller can use it after we return.
744 aChildRI
.emplace(aPresContext
, aOuterRI
, aChildFrame
, availSize
, Nothing(),
745 ReflowInput::CALLER_WILL_INIT
);
746 InitChildReflowInput(*aPresContext
, aOuterRI
, *aChildRI
);
748 // see if we need to reset top-of-page due to a caption
749 if (aChildRI
->mFlags
.mIsTopOfPage
&&
750 mCaptionFrames
.FirstChild() == aChildFrame
) {
751 uint8_t captionSide
= GetCaptionSide();
752 if (captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
||
753 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
) {
754 aChildRI
->mFlags
.mIsTopOfPage
= false;
759 void nsTableWrapperFrame::OuterDoReflowChild(nsPresContext
* aPresContext
,
760 nsIFrame
* aChildFrame
,
761 const ReflowInput
& aChildRI
,
762 ReflowOutput
& aMetrics
,
763 nsReflowStatus
& aStatus
) {
764 // Using zero as containerSize here because we want consistency between
765 // the GetLogicalPosition and ReflowChild calls, to avoid unnecessarily
766 // changing the frame's coordinates; but we don't yet know its final
767 // position anyway so the actual value is unimportant.
768 const nsSize zeroCSize
;
769 WritingMode wm
= aChildRI
.GetWritingMode();
771 // Use the current position as a best guess for placement.
772 LogicalPoint childPt
= aChildFrame
->GetLogicalPosition(wm
, zeroCSize
);
773 ReflowChildFlags flags
= ReflowChildFlags::NoMoveFrame
;
775 // We don't want to delete our next-in-flow's child if it's an inner table
776 // frame, because table wrapper frames always assume that their inner table
777 // frames don't go away. If a table wrapper frame is removed because it is
778 // a next-in-flow of an already complete table wrapper frame, then it will
779 // take care of removing it's inner table frame.
780 if (aChildFrame
== InnerTableFrame()) {
781 flags
|= ReflowChildFlags::NoDeleteNextInFlowChild
;
784 ReflowChild(aChildFrame
, aPresContext
, aMetrics
, aChildRI
, wm
, childPt
,
785 zeroCSize
, flags
, aStatus
);
788 void nsTableWrapperFrame::UpdateOverflowAreas(ReflowOutput
& aMet
) {
789 aMet
.SetOverflowAreasToDesiredBounds();
790 ConsiderChildOverflow(aMet
.mOverflowAreas
, InnerTableFrame());
791 if (mCaptionFrames
.NotEmpty()) {
792 ConsiderChildOverflow(aMet
.mOverflowAreas
, mCaptionFrames
.FirstChild());
796 void nsTableWrapperFrame::Reflow(nsPresContext
* aPresContext
,
797 ReflowOutput
& aDesiredSize
,
798 const ReflowInput
& aOuterRI
,
799 nsReflowStatus
& aStatus
) {
801 DO_GLOBAL_REFLOW_COUNT("nsTableWrapperFrame");
802 DISPLAY_REFLOW(aPresContext
, this, aOuterRI
, aDesiredSize
, aStatus
);
803 MOZ_ASSERT(aStatus
.IsEmpty(), "Caller should pass a fresh reflow status!");
805 // Initialize out parameters
806 aDesiredSize
.ClearSize();
808 if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW
)) {
809 // Set up our kids. They're already present, on an overflow list,
810 // or there are none so we'll create them now
811 MoveOverflowToChildList();
814 Maybe
<ReflowInput
> captionRI
;
815 Maybe
<ReflowInput
> innerRI
;
817 nsRect origCaptionRect
;
818 nsRect origCaptionVisualOverflow
;
819 bool captionFirstReflow
= false;
820 if (mCaptionFrames
.NotEmpty()) {
821 origCaptionRect
= mCaptionFrames
.FirstChild()->GetRect();
822 origCaptionVisualOverflow
=
823 mCaptionFrames
.FirstChild()->GetVisualOverflowRect();
825 mCaptionFrames
.FirstChild()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW
);
828 // ComputeAutoSize has to match this logic.
829 WritingMode wm
= aOuterRI
.GetWritingMode();
830 uint8_t captionSide
= GetCaptionSide();
831 WritingMode captionWM
= wm
; // will be changed below if necessary
833 if (captionSide
== NO_SIDE
) {
834 // We don't have a caption.
835 OuterBeginReflowChild(aPresContext
, InnerTableFrame(), aOuterRI
, innerRI
,
836 aOuterRI
.ComputedSize(wm
).ISize(wm
));
837 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_LEFT
||
838 captionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
) {
839 // ComputeAutoSize takes care of making side captions small. Compute
840 // the caption's size first, and tell the table to fit in what's left.
841 OuterBeginReflowChild(aPresContext
, mCaptionFrames
.FirstChild(), aOuterRI
,
842 captionRI
, aOuterRI
.ComputedSize(wm
).ISize(wm
));
843 captionWM
= captionRI
->GetWritingMode();
844 nscoord innerAvailISize
=
845 aOuterRI
.ComputedSize(wm
).ISize(wm
) -
846 captionRI
->ComputedSizeWithMarginBorderPadding(wm
).ISize(wm
);
847 OuterBeginReflowChild(aPresContext
, InnerTableFrame(), aOuterRI
, innerRI
,
849 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
850 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
851 // Compute the table's size first, and then prevent the caption from
852 // being larger in the inline dir unless it has to be.
854 // Note that CSS 2.1 (but not 2.0) says:
855 // The width of the anonymous box is the border-edge width of the
856 // table box inside it
857 // We don't actually make our anonymous box that isize (if we did,
858 // it would break 'auto' margins), but this effectively does that.
859 OuterBeginReflowChild(aPresContext
, InnerTableFrame(), aOuterRI
, innerRI
,
860 aOuterRI
.ComputedSize(wm
).ISize(wm
));
861 // It's good that CSS 2.1 says not to include margins, since we
862 // can't, since they already been converted so they exactly
863 // fill the available isize (ignoring the margin on one side if
864 // neither are auto). (We take advantage of that later when we call
865 // GetCaptionOrigin, though.)
866 nscoord innerBorderISize
=
867 innerRI
->ComputedSizeWithBorderPadding(wm
).ISize(wm
);
868 OuterBeginReflowChild(aPresContext
, mCaptionFrames
.FirstChild(), aOuterRI
,
869 captionRI
, innerBorderISize
);
870 captionWM
= captionRI
->GetWritingMode();
872 NS_ASSERTION(captionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
||
873 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
,
874 "unexpected caption-side");
875 // Size the table and the caption independently.
876 captionWM
= mCaptionFrames
.FirstChild()->GetWritingMode();
877 OuterBeginReflowChild(aPresContext
, mCaptionFrames
.FirstChild(), aOuterRI
,
879 aOuterRI
.ComputedSize(captionWM
).ISize(captionWM
));
880 OuterBeginReflowChild(aPresContext
, InnerTableFrame(), aOuterRI
, innerRI
,
881 aOuterRI
.ComputedSize(wm
).ISize(wm
));
884 // First reflow the caption.
885 Maybe
<ReflowOutput
> captionMet
;
886 LogicalSize
captionSize(wm
);
887 LogicalMargin
captionMargin(wm
);
888 if (mCaptionFrames
.NotEmpty()) {
889 captionMet
.emplace(wm
);
890 nsReflowStatus capStatus
; // don't let the caption cause incomplete
891 OuterDoReflowChild(aPresContext
, mCaptionFrames
.FirstChild(), *captionRI
,
892 *captionMet
, capStatus
);
893 captionSize
.ISize(wm
) = captionMet
->ISize(wm
);
894 captionSize
.BSize(wm
) = captionMet
->BSize(wm
);
895 captionMargin
= captionRI
->ComputedLogicalMargin().ConvertTo(wm
, captionWM
);
896 // Now that we know the bsize of the caption, reduce the available bsize
897 // for the table frame if we are bsize constrained and the caption is above
898 // or below the inner table. Also reduce the CB size that we store for
899 // our children in case we're a grid item, by the same amount.
900 LogicalSize
* cbSize
= GetProperty(GridItemCBSizeProperty());
901 if (NS_UNCONSTRAINEDSIZE
!= aOuterRI
.AvailableBSize() || cbSize
) {
902 nscoord captionBSize
= 0;
903 nscoord captionISize
= 0;
904 switch (captionSide
) {
905 case NS_STYLE_CAPTION_SIDE_TOP
:
906 case NS_STYLE_CAPTION_SIDE_BOTTOM
:
907 case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
:
908 case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
:
909 captionBSize
= captionSize
.BSize(wm
) + captionMargin
.BStartEnd(wm
);
911 case NS_STYLE_CAPTION_SIDE_LEFT
:
912 case NS_STYLE_CAPTION_SIDE_RIGHT
:
913 captionISize
= captionSize
.ISize(wm
) + captionMargin
.IStartEnd(wm
);
916 if (NS_UNCONSTRAINEDSIZE
!= aOuterRI
.AvailableBSize()) {
917 innerRI
->AvailableBSize() =
918 std::max(0, innerRI
->AvailableBSize() - captionBSize
);
921 // Shrink the CB size by the size reserved for the caption.
922 LogicalSize oldCBSize
= *cbSize
;
923 cbSize
->ISize(wm
) = std::max(0, cbSize
->ISize(wm
) - captionISize
);
924 cbSize
->BSize(wm
) = std::max(0, cbSize
->BSize(wm
) - captionBSize
);
925 if (oldCBSize
!= *cbSize
) {
926 // Reset the inner table's ReflowInput to stretch it to the new size.
928 OuterBeginReflowChild(aPresContext
, InnerTableFrame(), aOuterRI
,
929 innerRI
, aOuterRI
.ComputedSize(wm
).ISize(wm
));
935 // Then, now that we know how much to reduce the isize of the inner
936 // table to account for side captions, reflow the inner table.
937 ReflowOutput
innerMet(innerRI
->GetWritingMode());
938 OuterDoReflowChild(aPresContext
, InnerTableFrame(), *innerRI
, innerMet
,
940 LogicalSize
innerSize(wm
, innerMet
.ISize(wm
), innerMet
.BSize(wm
));
941 LogicalMargin innerMargin
= innerRI
->ComputedLogicalMargin();
943 LogicalSize
containSize(wm
, GetContainingBlockSize(aOuterRI
));
945 // Now that we've reflowed both we can place them.
946 // XXXldb Most of the input variables here are now uninitialized!
948 // XXX Need to recompute inner table's auto margins for the case of side
949 // captions. (Caption's are broken too, but that should be fixed earlier.)
951 // Compute the desiredSize so that we can use it as the containerSize
952 // for the FinishReflowChild calls below.
953 LogicalSize
desiredSize(wm
);
954 SetDesiredSize(captionSide
, innerSize
, captionSize
, innerMargin
,
955 captionMargin
, desiredSize
.ISize(wm
), desiredSize
.BSize(wm
),
957 aDesiredSize
.SetSize(wm
, desiredSize
);
958 nsSize containerSize
= aDesiredSize
.PhysicalSize();
959 // XXX It's possible for this to be NS_UNCONSTRAINEDSIZE, which will result
960 // in assertions from FinishReflowChild.
962 if (mCaptionFrames
.NotEmpty()) {
963 LogicalPoint
captionOrigin(wm
);
964 GetCaptionOrigin(captionSide
, containSize
, innerSize
, innerMargin
,
965 captionSize
, captionMargin
, captionOrigin
, wm
);
966 FinishReflowChild(mCaptionFrames
.FirstChild(), aPresContext
, *captionMet
,
967 captionRI
.ptr(), wm
, captionOrigin
, containerSize
,
968 ReflowChildFlags::Default
);
971 // XXX If the bsize is constrained then we need to check whether
972 // everything still fits...
974 LogicalPoint
innerOrigin(wm
);
975 GetInnerOrigin(captionSide
, containSize
, captionSize
, captionMargin
,
976 innerSize
, innerMargin
, innerOrigin
, wm
);
977 FinishReflowChild(InnerTableFrame(), aPresContext
, innerMet
, innerRI
.ptr(),
978 wm
, innerOrigin
, containerSize
, ReflowChildFlags::Default
);
981 if (mCaptionFrames
.NotEmpty()) {
982 nsTableFrame::InvalidateTableFrame(
983 mCaptionFrames
.FirstChild(), origCaptionRect
, origCaptionVisualOverflow
,
987 UpdateOverflowAreas(aDesiredSize
);
989 if (GetPrevInFlow()) {
990 ReflowOverflowContainerChildren(aPresContext
, aOuterRI
,
991 aDesiredSize
.mOverflowAreas
,
992 ReflowChildFlags::Default
, aStatus
);
995 FinishReflowWithAbsoluteFrames(aPresContext
, aDesiredSize
, aOuterRI
, aStatus
);
997 // Return our desired rect
999 NS_FRAME_SET_TRUNCATION(aStatus
, aOuterRI
, aDesiredSize
);
1002 /* ----- global methods ----- */
1004 nsIContent
* nsTableWrapperFrame::GetCellAt(uint32_t aRowIdx
,
1005 uint32_t aColIdx
) const {
1006 nsTableCellMap
* cellMap
= InnerTableFrame()->GetCellMap();
1011 nsTableCellFrame
* cell
= cellMap
->GetCellInfoAt(aRowIdx
, aColIdx
);
1016 return cell
->GetContent();
1019 nsTableWrapperFrame
* NS_NewTableWrapperFrame(PresShell
* aPresShell
,
1020 ComputedStyle
* aStyle
) {
1021 return new (aPresShell
)
1022 nsTableWrapperFrame(aStyle
, aPresShell
->GetPresContext());
1025 NS_IMPL_FRAMEARENA_HELPERS(nsTableWrapperFrame
)
1027 #ifdef DEBUG_FRAME_DUMP
1028 nsresult
nsTableWrapperFrame::GetFrameName(nsAString
& aResult
) const {
1029 return MakeFrameName(NS_LITERAL_STRING("TableWrapper"), aResult
);