/src/mozilla-central/layout/generic/nsBlockReflowContext.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* class that a parent frame uses to reflow a block frame */ |
8 | | |
9 | | #include "nsBlockReflowContext.h" |
10 | | #include "BlockReflowInput.h" |
11 | | #include "nsFloatManager.h" |
12 | | #include "nsColumnSetFrame.h" |
13 | | #include "nsContainerFrame.h" |
14 | | #include "nsBlockFrame.h" |
15 | | #include "nsLineBox.h" |
16 | | #include "nsLayoutUtils.h" |
17 | | |
18 | | using namespace mozilla; |
19 | | |
20 | | #ifdef DEBUG |
21 | | #undef NOISY_MAX_ELEMENT_SIZE |
22 | | #undef REALLY_NOISY_MAX_ELEMENT_SIZE |
23 | | #undef NOISY_BLOCK_DIR_MARGINS |
24 | | #else |
25 | | #undef NOISY_MAX_ELEMENT_SIZE |
26 | | #undef REALLY_NOISY_MAX_ELEMENT_SIZE |
27 | | #undef NOISY_BLOCK_DIR_MARGINS |
28 | | #endif |
29 | | |
30 | | nsBlockReflowContext::nsBlockReflowContext(nsPresContext* aPresContext, |
31 | | const ReflowInput& aParentRI) |
32 | | : mPresContext(aPresContext), |
33 | | mOuterReflowInput(aParentRI), |
34 | | mFrame(nullptr), |
35 | | mSpace(aParentRI.GetWritingMode()), |
36 | | mICoord(0), |
37 | | mBCoord(0), |
38 | | mMetrics(aParentRI) |
39 | 0 | { |
40 | 0 | } |
41 | | |
42 | | static nsIFrame* DescendIntoBlockLevelFrame(nsIFrame* aFrame) |
43 | 0 | { |
44 | 0 | LayoutFrameType type = aFrame->Type(); |
45 | 0 | if (type == LayoutFrameType::ColumnSet) { |
46 | 0 | static_cast<nsColumnSetFrame*>(aFrame)->DrainOverflowColumns(); |
47 | 0 | nsIFrame* child = aFrame->PrincipalChildList().FirstChild(); |
48 | 0 | if (child) { |
49 | 0 | return DescendIntoBlockLevelFrame(child); |
50 | 0 | } |
51 | 0 | } |
52 | 0 | return aFrame; |
53 | 0 | } |
54 | | |
55 | | bool |
56 | | nsBlockReflowContext::ComputeCollapsedBStartMargin(const ReflowInput& aRI, |
57 | | nsCollapsingMargin* aMargin, |
58 | | nsIFrame* aClearanceFrame, |
59 | | bool* aMayNeedRetry, |
60 | | bool* aBlockIsEmpty) |
61 | 0 | { |
62 | 0 | WritingMode wm = aRI.GetWritingMode(); |
63 | 0 | WritingMode parentWM = mMetrics.GetWritingMode(); |
64 | 0 |
|
65 | 0 | // Include block-start element of frame's margin |
66 | 0 | aMargin->Include(aRI.ComputedLogicalMargin().ConvertTo(parentWM, wm).BStart(parentWM)); |
67 | 0 |
|
68 | 0 | // The inclusion of the block-end margin when empty is done by the caller |
69 | 0 | // since it doesn't need to be done by the top-level (non-recursive) |
70 | 0 | // caller. |
71 | 0 |
|
72 | | #ifdef NOISY_BLOCKDIR_MARGINS |
73 | | nsFrame::ListTag(stdout, aRI.mFrame); |
74 | | printf(": %d => %d\n", aRI.ComputedLogicalMargin().BStart(wm), aMargin->get()); |
75 | | #endif |
76 | |
|
77 | 0 | bool dirtiedLine = false; |
78 | 0 | bool setBlockIsEmpty = false; |
79 | 0 |
|
80 | 0 | // Calculate the frame's generational block-start-margin from its child |
81 | 0 | // blocks. Note that if the frame has a non-zero block-start-border or |
82 | 0 | // block-start-padding then this step is skipped because it will be a margin |
83 | 0 | // root. It is also skipped if the frame is a margin root for other |
84 | 0 | // reasons. |
85 | 0 | nsIFrame* frame = DescendIntoBlockLevelFrame(aRI.mFrame); |
86 | 0 | nsPresContext* prescontext = frame->PresContext(); |
87 | 0 | nsBlockFrame* block = nullptr; |
88 | 0 | if (0 == aRI.ComputedLogicalBorderPadding().BStart(wm)) { |
89 | 0 | block = nsLayoutUtils::GetAsBlock(frame); |
90 | 0 | if (block) { |
91 | 0 | bool bStartMarginRoot, unused; |
92 | 0 | block->IsMarginRoot(&bStartMarginRoot, &unused); |
93 | 0 | if (bStartMarginRoot) { |
94 | 0 | block = nullptr; |
95 | 0 | } |
96 | 0 | } |
97 | 0 | } |
98 | 0 |
|
99 | 0 | // iterate not just through the lines of 'block' but also its |
100 | 0 | // overflow lines and the normal and overflow lines of its next in |
101 | 0 | // flows. Note that this will traverse some frames more than once: |
102 | 0 | // for example, if A contains B and A->nextinflow contains |
103 | 0 | // B->nextinflow, we'll traverse B->nextinflow twice. But this is |
104 | 0 | // OK because our traversal is idempotent. |
105 | 0 | for ( ;block; block = static_cast<nsBlockFrame*>(block->GetNextInFlow())) { |
106 | 0 | for (int overflowLines = 0; overflowLines <= 1; ++overflowLines) { |
107 | 0 | nsBlockFrame::LineIterator line; |
108 | 0 | nsBlockFrame::LineIterator line_end; |
109 | 0 | bool anyLines = true; |
110 | 0 | if (overflowLines) { |
111 | 0 | nsBlockFrame::FrameLines* frames = block->GetOverflowLines(); |
112 | 0 | nsLineList* lines = frames ? &frames->mLines : nullptr; |
113 | 0 | if (!lines) { |
114 | 0 | anyLines = false; |
115 | 0 | } else { |
116 | 0 | line = lines->begin(); |
117 | 0 | line_end = lines->end(); |
118 | 0 | } |
119 | 0 | } else { |
120 | 0 | line = block->LinesBegin(); |
121 | 0 | line_end = block->LinesEnd(); |
122 | 0 | } |
123 | 0 | for (; anyLines && line != line_end; ++line) { |
124 | 0 | if (!aClearanceFrame && line->HasClearance()) { |
125 | 0 | // If we don't have a clearance frame, then we're computing |
126 | 0 | // the collapsed margin in the first pass, assuming that all |
127 | 0 | // lines have no clearance. So clear their clearance flags. |
128 | 0 | line->ClearHasClearance(); |
129 | 0 | line->MarkDirty(); |
130 | 0 | dirtiedLine = true; |
131 | 0 | } |
132 | 0 |
|
133 | 0 | bool isEmpty; |
134 | 0 | if (line->IsInline()) { |
135 | 0 | isEmpty = line->IsEmpty(); |
136 | 0 | } else { |
137 | 0 | nsIFrame* kid = line->mFirstChild; |
138 | 0 | if (kid == aClearanceFrame) { |
139 | 0 | line->SetHasClearance(); |
140 | 0 | line->MarkDirty(); |
141 | 0 | dirtiedLine = true; |
142 | 0 | if (!setBlockIsEmpty && aBlockIsEmpty) { |
143 | 0 | setBlockIsEmpty = true; |
144 | 0 | *aBlockIsEmpty = false; |
145 | 0 | } |
146 | 0 | goto done; |
147 | 0 | } |
148 | 0 | // Here is where we recur. Now that we have determined that a |
149 | 0 | // generational collapse is required we need to compute the |
150 | 0 | // child blocks margin and so in so that we can look into |
151 | 0 | // it. For its margins to be computed we need to have a reflow |
152 | 0 | // state for it. |
153 | 0 |
|
154 | 0 | // We may have to construct an extra reflow state here if |
155 | 0 | // we drilled down through a block wrapper. At the moment |
156 | 0 | // we can only drill down one level so we only have to support |
157 | 0 | // one extra reflow state. |
158 | 0 | const ReflowInput* outerReflowInput = &aRI; |
159 | 0 | if (frame != aRI.mFrame) { |
160 | 0 | NS_ASSERTION(frame->GetParent() == aRI.mFrame, |
161 | 0 | "Can only drill through one level of block wrapper"); |
162 | 0 | LogicalSize availSpace = aRI.ComputedSize(frame->GetWritingMode()); |
163 | 0 | outerReflowInput = new ReflowInput(prescontext, |
164 | 0 | aRI, frame, availSpace); |
165 | 0 | } |
166 | 0 | { |
167 | 0 | LogicalSize availSpace = |
168 | 0 | outerReflowInput->ComputedSize(kid->GetWritingMode()); |
169 | 0 | ReflowInput innerReflowInput(prescontext, |
170 | 0 | *outerReflowInput, kid, |
171 | 0 | availSpace); |
172 | 0 | // Record that we're being optimistic by assuming the kid |
173 | 0 | // has no clearance |
174 | 0 | if (kid->StyleDisplay()->mBreakType != StyleClear::None || |
175 | 0 | !nsBlockFrame::BlockCanIntersectFloats(kid)) { |
176 | 0 | *aMayNeedRetry = true; |
177 | 0 | } |
178 | 0 | if (ComputeCollapsedBStartMargin(innerReflowInput, aMargin, |
179 | 0 | aClearanceFrame, aMayNeedRetry, |
180 | 0 | &isEmpty)) { |
181 | 0 | line->MarkDirty(); |
182 | 0 | dirtiedLine = true; |
183 | 0 | } |
184 | 0 | if (isEmpty) { |
185 | 0 | WritingMode innerWM = innerReflowInput.GetWritingMode(); |
186 | 0 | LogicalMargin innerMargin = |
187 | 0 | innerReflowInput.ComputedLogicalMargin().ConvertTo(parentWM, innerWM); |
188 | 0 | aMargin->Include(innerMargin.BEnd(parentWM)); |
189 | 0 | } |
190 | 0 | } |
191 | 0 | if (outerReflowInput != &aRI) { |
192 | 0 | delete const_cast<ReflowInput*>(outerReflowInput); |
193 | 0 | } |
194 | 0 | } |
195 | 0 | if (!isEmpty) { |
196 | 0 | if (!setBlockIsEmpty && aBlockIsEmpty) { |
197 | 0 | setBlockIsEmpty = true; |
198 | 0 | *aBlockIsEmpty = false; |
199 | 0 | } |
200 | 0 | goto done; |
201 | 0 | } |
202 | 0 | } |
203 | 0 | if (!setBlockIsEmpty && aBlockIsEmpty) { |
204 | 0 | // The first time we reach here is when this is the first block |
205 | 0 | // and we have processed all its normal lines. |
206 | 0 | setBlockIsEmpty = true; |
207 | 0 | // All lines are empty, or we wouldn't be here! |
208 | 0 | *aBlockIsEmpty = aRI.mFrame->IsSelfEmpty(); |
209 | 0 | } |
210 | 0 | } |
211 | 0 | } |
212 | 0 | done: |
213 | 0 |
|
214 | 0 | if (!setBlockIsEmpty && aBlockIsEmpty) { |
215 | 0 | *aBlockIsEmpty = aRI.mFrame->IsEmpty(); |
216 | 0 | } |
217 | 0 |
|
218 | | #ifdef NOISY_BLOCKDIR_MARGINS |
219 | | nsFrame::ListTag(stdout, aRI.mFrame); |
220 | | printf(": => %d\n", aMargin->get()); |
221 | | #endif |
222 | |
|
223 | 0 | return dirtiedLine; |
224 | 0 | } |
225 | | |
226 | | void |
227 | | nsBlockReflowContext::ReflowBlock(const LogicalRect& aSpace, |
228 | | bool aApplyBStartMargin, |
229 | | nsCollapsingMargin& aPrevMargin, |
230 | | nscoord aClearance, |
231 | | bool aIsAdjacentWithBStart, |
232 | | nsLineBox* aLine, |
233 | | ReflowInput& aFrameRI, |
234 | | nsReflowStatus& aFrameReflowStatus, |
235 | | BlockReflowInput& aState) |
236 | 0 | { |
237 | 0 | mFrame = aFrameRI.mFrame; |
238 | 0 | mWritingMode = aState.mReflowInput.GetWritingMode(); |
239 | 0 | mContainerSize = aState.ContainerSize(); |
240 | 0 | mSpace = aSpace; |
241 | 0 |
|
242 | 0 | if (!aIsAdjacentWithBStart) { |
243 | 0 | aFrameRI.mFlags.mIsTopOfPage = false; // make sure this is cleared |
244 | 0 | } |
245 | 0 |
|
246 | 0 | if (aApplyBStartMargin) { |
247 | 0 | mBStartMargin = aPrevMargin; |
248 | 0 |
|
249 | | #ifdef NOISY_BLOCKDIR_MARGINS |
250 | | nsFrame::ListTag(stdout, mOuterReflowInput.mFrame); |
251 | | printf(": reflowing "); |
252 | | nsFrame::ListTag(stdout, mFrame); |
253 | | printf(" margin => %d, clearance => %d\n", mBStartMargin.get(), aClearance); |
254 | | #endif |
255 | |
|
256 | 0 | // Adjust the available size if it's constrained so that the |
257 | 0 | // child frame doesn't think it can reflow into its margin area. |
258 | 0 | if (mWritingMode.IsOrthogonalTo(mFrame->GetWritingMode())) { |
259 | 0 | if (NS_UNCONSTRAINEDSIZE != aFrameRI.AvailableISize()) { |
260 | 0 | aFrameRI.AvailableISize() -= mBStartMargin.get() + aClearance; |
261 | 0 | } |
262 | 0 | } else { |
263 | 0 | if (NS_UNCONSTRAINEDSIZE != aFrameRI.AvailableBSize()) { |
264 | 0 | aFrameRI.AvailableBSize() -= mBStartMargin.get() + aClearance; |
265 | 0 | } |
266 | 0 | } |
267 | 0 | } else { |
268 | 0 | // nsBlockFrame::ReflowBlock might call us multiple times with |
269 | 0 | // *different* values of aApplyBStartMargin. |
270 | 0 | mBStartMargin.Zero(); |
271 | 0 | } |
272 | 0 |
|
273 | 0 | nscoord tI = 0, tB = 0; |
274 | 0 | // The values of x and y do not matter for floats, so don't bother |
275 | 0 | // calculating them. Floats are guaranteed to have their own float |
276 | 0 | // manager, so tI and tB don't matter. mICoord and mBCoord don't |
277 | 0 | // matter becacuse they are only used in PlaceBlock, which is not used |
278 | 0 | // for floats. |
279 | 0 | if (aLine) { |
280 | 0 | // Compute inline/block coordinate where reflow will begin. Use the |
281 | 0 | // rules from 10.3.3 to determine what to apply. At this point in the |
282 | 0 | // reflow auto inline-start/end margins will have a zero value. |
283 | 0 |
|
284 | 0 | WritingMode frameWM = aFrameRI.GetWritingMode(); |
285 | 0 | LogicalMargin usedMargin = |
286 | 0 | aFrameRI.ComputedLogicalMargin().ConvertTo(mWritingMode, frameWM); |
287 | 0 | mICoord = mSpace.IStart(mWritingMode) + usedMargin.IStart(mWritingMode); |
288 | 0 | mBCoord = mSpace.BStart(mWritingMode) + mBStartMargin.get() + aClearance; |
289 | 0 |
|
290 | 0 | LogicalRect space(mWritingMode, mICoord, mBCoord, |
291 | 0 | mSpace.ISize(mWritingMode) - |
292 | 0 | usedMargin.IStartEnd(mWritingMode), |
293 | 0 | mSpace.BSize(mWritingMode) - |
294 | 0 | usedMargin.BStartEnd(mWritingMode)); |
295 | 0 | tI = space.LineLeft(mWritingMode, mContainerSize); |
296 | 0 | tB = mBCoord; |
297 | 0 |
|
298 | 0 | if ((mFrame->GetStateBits() & NS_BLOCK_FLOAT_MGR) == 0) |
299 | 0 | aFrameRI.mBlockDelta = |
300 | 0 | mOuterReflowInput.mBlockDelta + mBCoord - aLine->BStart(); |
301 | 0 | } |
302 | 0 |
|
303 | | #ifdef DEBUG |
304 | | mMetrics.ISize(mWritingMode) = nscoord(0xdeadbeef); |
305 | | mMetrics.BSize(mWritingMode) = nscoord(0xdeadbeef); |
306 | | #endif |
307 | |
|
308 | 0 | mOuterReflowInput.mFloatManager->Translate(tI, tB); |
309 | 0 | mFrame->Reflow(mPresContext, mMetrics, aFrameRI, aFrameReflowStatus); |
310 | 0 | mOuterReflowInput.mFloatManager->Translate(-tI, -tB); |
311 | 0 |
|
312 | | #ifdef DEBUG |
313 | | if (!aFrameReflowStatus.IsInlineBreakBefore()) { |
314 | | if ((CRAZY_SIZE(mMetrics.ISize(mWritingMode)) || |
315 | | CRAZY_SIZE(mMetrics.BSize(mWritingMode))) && |
316 | | !mFrame->GetParent()->IsCrazySizeAssertSuppressed()) { |
317 | | printf("nsBlockReflowContext: "); |
318 | | nsFrame::ListTag(stdout, mFrame); |
319 | | printf(" metrics=%d,%d!\n", |
320 | | mMetrics.ISize(mWritingMode), mMetrics.BSize(mWritingMode)); |
321 | | } |
322 | | if ((mMetrics.ISize(mWritingMode) == nscoord(0xdeadbeef)) || |
323 | | (mMetrics.BSize(mWritingMode) == nscoord(0xdeadbeef))) { |
324 | | printf("nsBlockReflowContext: "); |
325 | | nsFrame::ListTag(stdout, mFrame); |
326 | | printf(" didn't set i/b %d,%d!\n", |
327 | | mMetrics.ISize(mWritingMode), mMetrics.BSize(mWritingMode)); |
328 | | } |
329 | | } |
330 | | #endif |
331 | |
|
332 | 0 | if (!mFrame->HasOverflowAreas()) { |
333 | 0 | mMetrics.SetOverflowAreasToDesiredBounds(); |
334 | 0 | } |
335 | 0 |
|
336 | 0 | if (!aFrameReflowStatus.IsInlineBreakBefore() && |
337 | 0 | aFrameReflowStatus.IsFullyComplete()) { |
338 | 0 | // If frame is complete and has a next-in-flow, we need to delete |
339 | 0 | // them now. Do not do this when a break-before is signaled because |
340 | 0 | // the frame is going to get reflowed again (whether the frame is |
341 | 0 | // (in)complete is undefined in that case anyway). |
342 | 0 | if (nsIFrame* kidNextInFlow = mFrame->GetNextInFlow()) { |
343 | 0 | // Remove all of the childs next-in-flows. Make sure that we ask |
344 | 0 | // the right parent to do the removal (it's possible that the |
345 | 0 | // parent is not this because we are executing pullup code). |
346 | 0 | // Floats will eventually be removed via nsBlockFrame::RemoveFloat |
347 | 0 | // which detaches the placeholder from the float. |
348 | 0 | nsOverflowContinuationTracker::AutoFinish fini(aState.mOverflowTracker, mFrame); |
349 | 0 | kidNextInFlow->GetParent()->DeleteNextInFlowChild(kidNextInFlow, true); |
350 | 0 | } |
351 | 0 | } |
352 | 0 | } |
353 | | |
354 | | /** |
355 | | * Attempt to place the block frame within the available space. If |
356 | | * it fits, apply inline-dir ("horizontal") positioning (CSS 10.3.3), |
357 | | * collapse margins (CSS2 8.3.1). Also apply relative positioning. |
358 | | */ |
359 | | bool |
360 | | nsBlockReflowContext::PlaceBlock(const ReflowInput& aReflowInput, |
361 | | bool aForceFit, |
362 | | nsLineBox* aLine, |
363 | | nsCollapsingMargin& aBEndMarginResult, |
364 | | nsOverflowAreas& aOverflowAreas, |
365 | | const nsReflowStatus& aReflowStatus) |
366 | 0 | { |
367 | 0 | // Compute collapsed block-end margin value. |
368 | 0 | WritingMode wm = aReflowInput.GetWritingMode(); |
369 | 0 | WritingMode parentWM = mMetrics.GetWritingMode(); |
370 | 0 | if (aReflowStatus.IsComplete()) { |
371 | 0 | aBEndMarginResult = mMetrics.mCarriedOutBEndMargin; |
372 | 0 | aBEndMarginResult.Include(aReflowInput.ComputedLogicalMargin(). |
373 | 0 | ConvertTo(parentWM, wm).BEnd(parentWM)); |
374 | 0 | } else { |
375 | 0 | // The used block-end-margin is set to zero before a break. |
376 | 0 | aBEndMarginResult.Zero(); |
377 | 0 | } |
378 | 0 |
|
379 | 0 | nscoord backupContainingBlockAdvance = 0; |
380 | 0 |
|
381 | 0 | // Check whether the block's block-end margin collapses with its block-start |
382 | 0 | // margin. See CSS 2.1 section 8.3.1; those rules seem to match |
383 | 0 | // nsBlockFrame::IsEmpty(). Any such block must have zero block-size so |
384 | 0 | // check that first. Note that a block can have clearance and still |
385 | 0 | // have adjoining block-start/end margins, because the clearance goes |
386 | 0 | // above the block-start margin. |
387 | 0 | // Mark the frame as non-dirty; it has been reflowed (or we wouldn't |
388 | 0 | // be here), and we don't want to assert in CachedIsEmpty() |
389 | 0 | mFrame->RemoveStateBits(NS_FRAME_IS_DIRTY); |
390 | 0 | bool empty = 0 == mMetrics.BSize(parentWM) && aLine->CachedIsEmpty(); |
391 | 0 | if (empty) { |
392 | 0 | // Collapse the block-end margin with the block-start margin that was |
393 | 0 | // already applied. |
394 | 0 | aBEndMarginResult.Include(mBStartMargin); |
395 | 0 |
|
396 | | #ifdef NOISY_BLOCKDIR_MARGINS |
397 | | printf(" "); |
398 | | nsFrame::ListTag(stdout, mOuterReflowInput.mFrame); |
399 | | printf(": "); |
400 | | nsFrame::ListTag(stdout, mFrame); |
401 | | printf(" -- collapsing block start & end margin together; BStart=%d spaceBStart=%d\n", |
402 | | mBCoord, mSpace.BStart(mWritingMode)); |
403 | | #endif |
404 | | // Section 8.3.1 of CSS 2.1 says that blocks with adjoining |
405 | 0 | // "top/bottom" (i.e. block-start/end) margins whose top margin collapses |
406 | 0 | // with their parent's top margin should have their top border-edge at the |
407 | 0 | // top border-edge of their parent. We actually don't have to do |
408 | 0 | // anything special to make this happen. In that situation, |
409 | 0 | // nsBlockFrame::ShouldApplyBStartMargin will have returned false, |
410 | 0 | // and mBStartMargin and aClearance will have been zero in |
411 | 0 | // ReflowBlock. |
412 | 0 |
|
413 | 0 | // If we did apply our block-start margin, but now we're collapsing it |
414 | 0 | // into the block-end margin, we need to back up the containing |
415 | 0 | // block's bCoord-advance by our block-start margin so that it doesn't get |
416 | 0 | // counted twice. Note that here we're allowing the line's bounds |
417 | 0 | // to become different from the block's position; we do this |
418 | 0 | // because the containing block will place the next line at the |
419 | 0 | // line's BEnd, and it must place the next line at a different |
420 | 0 | // point from where this empty block will be. |
421 | 0 | backupContainingBlockAdvance = mBStartMargin.get(); |
422 | 0 | } |
423 | 0 |
|
424 | 0 | // See if the frame fit. If it's the first frame or empty then it |
425 | 0 | // always fits. If the block-size is unconstrained then it always fits, |
426 | 0 | // even if there's some sort of integer overflow that makes bCoord + |
427 | 0 | // mMetrics.BSize() appear to go beyond the available block size. |
428 | 0 | if (!empty && !aForceFit && |
429 | 0 | mSpace.BSize(mWritingMode) != NS_UNCONSTRAINEDSIZE) { |
430 | 0 | nscoord bEnd = mBCoord - |
431 | 0 | backupContainingBlockAdvance + mMetrics.BSize(mWritingMode); |
432 | 0 | if (bEnd > mSpace.BEnd(mWritingMode)) { |
433 | 0 | // didn't fit, we must acquit. |
434 | 0 | mFrame->DidReflow(mPresContext, &aReflowInput); |
435 | 0 | return false; |
436 | 0 | } |
437 | 0 | } |
438 | 0 | |
439 | 0 | aLine->SetBounds(mWritingMode, |
440 | 0 | mICoord, mBCoord - backupContainingBlockAdvance, |
441 | 0 | mMetrics.ISize(mWritingMode), mMetrics.BSize(mWritingMode), |
442 | 0 | mContainerSize); |
443 | 0 |
|
444 | 0 | WritingMode frameWM = mFrame->GetWritingMode(); |
445 | 0 | LogicalPoint logPos = |
446 | 0 | LogicalPoint(mWritingMode, mICoord, mBCoord). |
447 | 0 | ConvertTo(frameWM, mWritingMode, |
448 | 0 | mContainerSize - mMetrics.PhysicalSize()); |
449 | 0 |
|
450 | 0 | // ApplyRelativePositioning in right-to-left writing modes needs to |
451 | 0 | // know the updated frame width |
452 | 0 | mFrame->SetSize(mWritingMode, mMetrics.Size(mWritingMode)); |
453 | 0 | aReflowInput.ApplyRelativePositioning(&logPos, mContainerSize); |
454 | 0 |
|
455 | 0 | // Now place the frame and complete the reflow process |
456 | 0 | nsContainerFrame::FinishReflowChild(mFrame, mPresContext, mMetrics, |
457 | 0 | &aReflowInput, frameWM, logPos, |
458 | 0 | mContainerSize, 0); |
459 | 0 |
|
460 | 0 | aOverflowAreas = mMetrics.mOverflowAreas + mFrame->GetPosition(); |
461 | 0 |
|
462 | 0 | return true; |
463 | 0 | } |