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