Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/layout/tables/nsTableRowGroupFrame.cpp
Warning:line 1234, column 11
Value stored to 'isTopOfPage' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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