Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(118)

Side by Side Diff: sky/engine/core/rendering/RenderBlockFlow.cpp

Issue 700743002: Remove margin collapsing. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/engine/core/rendering/RenderBlockFlow.h ('k') | sky/engine/core/rendering/RenderBox.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 25 matching lines...) Expand all
36 #include "core/frame/Settings.h" 36 #include "core/frame/Settings.h"
37 #include "core/rendering/HitTestLocation.h" 37 #include "core/rendering/HitTestLocation.h"
38 #include "core/rendering/RenderLayer.h" 38 #include "core/rendering/RenderLayer.h"
39 #include "core/rendering/RenderText.h" 39 #include "core/rendering/RenderText.h"
40 #include "core/rendering/RenderView.h" 40 #include "core/rendering/RenderView.h"
41 #include "core/rendering/line/LineWidth.h" 41 #include "core/rendering/line/LineWidth.h"
42 #include "platform/text/BidiTextRun.h" 42 #include "platform/text/BidiTextRun.h"
43 43
44 namespace blink { 44 namespace blink {
45 45
46 struct SameSizeAsMarginInfo {
47 uint16_t bitfields;
48 LayoutUnit margins[2];
49 };
50
51 COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), M arginValues_should_stay_small);
52
53 class MarginInfo {
54 // Collapsing flags for whether we can collapse our margins with our childre n's margins.
55 bool m_canCollapseWithChildren : 1;
56 bool m_canCollapseMarginBeforeWithChildren : 1;
57 bool m_canCollapseMarginAfterWithChildren : 1;
58 bool m_canCollapseMarginAfterWithLastChild: 1;
59
60 // This flag tracks whether we are still looking at child margins that can a ll collapse together at the beginning of a block.
61 // They may or may not collapse with the top margin of the block (|m_canColl apseTopWithChildren| tells us that), but they will
62 // always be collapsing with one another. This variable can remain set to tr ue through multiple iterations
63 // as long as we keep encountering self-collapsing blocks.
64 bool m_atBeforeSideOfBlock : 1;
65
66 // This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block.
67 bool m_atAfterSideOfBlock : 1;
68
69 // These variables are used to detect quirky margins that we need to collaps e away (in table cells
70 // and in the body element).
71 bool m_hasMarginBeforeQuirk : 1;
72 bool m_hasMarginAfterQuirk : 1;
73 bool m_determinedMarginBeforeQuirk : 1;
74
75 bool m_discardMargin : 1;
76
77 // These flags track the previous maximal positive and negative margins.
78 LayoutUnit m_positiveMargin;
79 LayoutUnit m_negativeMargin;
80
81 public:
82 MarginInfo(RenderBlockFlow*, LayoutUnit beforeBorderPadding, LayoutUnit afte rBorderPadding);
83
84 void setAtBeforeSideOfBlock(bool b) { m_atBeforeSideOfBlock = b; }
85 void setAtAfterSideOfBlock(bool b) { m_atAfterSideOfBlock = b; }
86 void clearMargin()
87 {
88 m_positiveMargin = 0;
89 m_negativeMargin = 0;
90 }
91 void setHasMarginBeforeQuirk(bool b) { m_hasMarginBeforeQuirk = b; }
92 void setHasMarginAfterQuirk(bool b) { m_hasMarginAfterQuirk = b; }
93 void setDeterminedMarginBeforeQuirk(bool b) { m_determinedMarginBeforeQuirk = b; }
94 void setPositiveMargin(LayoutUnit p) { ASSERT(!m_discardMargin); m_positiveM argin = p; }
95 void setNegativeMargin(LayoutUnit n) { ASSERT(!m_discardMargin); m_negativeM argin = n; }
96 void setPositiveMarginIfLarger(LayoutUnit p)
97 {
98 ASSERT(!m_discardMargin);
99 if (p > m_positiveMargin)
100 m_positiveMargin = p;
101 }
102 void setNegativeMarginIfLarger(LayoutUnit n)
103 {
104 ASSERT(!m_discardMargin);
105 if (n > m_negativeMargin)
106 m_negativeMargin = n;
107 }
108
109 void setMargin(LayoutUnit p, LayoutUnit n) { ASSERT(!m_discardMargin); m_pos itiveMargin = p; m_negativeMargin = n; }
110 void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMar ginAfterWithChildren = collapse; }
111 void setCanCollapseMarginAfterWithLastChild(bool collapse) { m_canCollapseMa rginAfterWithLastChild = collapse; }
112 void setDiscardMargin(bool value) { m_discardMargin = value; }
113
114 bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; }
115 bool canCollapseWithMarginBefore() const { return m_atBeforeSideOfBlock && m _canCollapseMarginBeforeWithChildren; }
116 bool canCollapseWithMarginAfter() const { return m_atAfterSideOfBlock && m_c anCollapseMarginAfterWithChildren; }
117 bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMargi nBeforeWithChildren; }
118 bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMargin AfterWithChildren; }
119 bool canCollapseMarginAfterWithLastChild() const { return m_canCollapseMargi nAfterWithLastChild; }
120 bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQu irk; }
121 bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; }
122 bool hasMarginAfterQuirk() const { return m_hasMarginAfterQuirk; }
123 LayoutUnit positiveMargin() const { return m_positiveMargin; }
124 LayoutUnit negativeMargin() const { return m_negativeMargin; }
125 bool discardMargin() const { return m_discardMargin; }
126 LayoutUnit margin() const { return m_positiveMargin - m_negativeMargin; }
127 };
128
129 void RenderBlockFlow::RenderBlockFlowRareData::trace(Visitor* visitor)
130 {
131 }
132
133 RenderBlockFlow::RenderBlockFlow(ContainerNode* node) 46 RenderBlockFlow::RenderBlockFlow(ContainerNode* node)
134 : RenderBlock(node) 47 : RenderBlock(node)
135 { 48 {
136 COMPILE_ASSERT(sizeof(MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInf o_should_stay_small);
137 setChildrenInline(true); 49 setChildrenInline(true);
138 } 50 }
139 51
140 RenderBlockFlow::~RenderBlockFlow() 52 RenderBlockFlow::~RenderBlockFlow()
141 { 53 {
142 } 54 }
143 55
144 void RenderBlockFlow::trace(Visitor* visitor)
145 {
146 visitor->trace(m_rareData);
147 RenderBlock::trace(visitor);
148 }
149
150 RenderBlockFlow* RenderBlockFlow::createAnonymous(Document* document) 56 RenderBlockFlow* RenderBlockFlow::createAnonymous(Document* document)
151 { 57 {
152 RenderBlockFlow* renderer = new RenderBlockFlow(0); 58 RenderBlockFlow* renderer = new RenderBlockFlow(0);
153 renderer->setDocumentForAnonymous(document); 59 renderer->setDocumentForAnonymous(document);
154 return renderer; 60 return renderer;
155 } 61 }
156 62
157 bool RenderBlockFlow::updateLogicalWidthAndColumnWidth() 63 bool RenderBlockFlow::updateLogicalWidthAndColumnWidth()
158 { 64 {
159 return RenderBlock::updateLogicalWidthAndColumnWidth(); 65 return RenderBlock::updateLogicalWidthAndColumnWidth();
160 } 66 }
161 67
162 bool RenderBlockFlow::isSelfCollapsingBlock() const
163 {
164 m_hasOnlySelfCollapsingChildren = RenderBlock::isSelfCollapsingBlock();
165 return m_hasOnlySelfCollapsingChildren;
166 }
167
168 void RenderBlockFlow::layoutBlock(bool relayoutChildren) 68 void RenderBlockFlow::layoutBlock(bool relayoutChildren)
169 { 69 {
170 ASSERT(needsLayout()); 70 ASSERT(needsLayout());
171 ASSERT(isInlineBlock() || !isInline()); 71 ASSERT(isInlineBlock() || !isInline());
172 72
173 // If we are self-collapsing with self-collapsing descendants this will get set to save us burrowing through our
174 // descendants every time in |isSelfCollapsingBlock|. We reset it here so th at |isSelfCollapsingBlock| attempts to burrow
175 // at least once and so that it always gives a reliable result reflecting th e latest layout.
176 m_hasOnlySelfCollapsingChildren = false;
177
178 if (!relayoutChildren && simplifiedLayout()) 73 if (!relayoutChildren && simplifiedLayout())
179 return; 74 return;
180 75
181 SubtreeLayoutScope layoutScope(*this); 76 SubtreeLayoutScope layoutScope(*this);
182 77
183 layoutBlockFlow(relayoutChildren, layoutScope); 78 layoutBlockFlow(relayoutChildren, layoutScope);
184 79
185 updateLayerTransformAfterLayout(); 80 updateLayerTransformAfterLayout();
186 81
187 // Update our scroll information if we're overflow:auto/scroll/hidden now th at we know if 82 // Update our scroll information if we're overflow:auto/scroll/hidden now th at we know if
188 // we overflow or not. 83 // we overflow or not.
189 updateScrollInfoAfterLayout(); 84 updateScrollInfoAfterLayout();
190 85
191 if (m_paintInvalidationLogicalTop != m_paintInvalidationLogicalBottom) 86 if (m_paintInvalidationLogicalTop != m_paintInvalidationLogicalBottom)
192 setShouldInvalidateOverflowForPaint(true); 87 setShouldInvalidateOverflowForPaint(true);
193 88
194 clearNeedsLayout(); 89 clearNeedsLayout();
195 } 90 }
196 91
197 inline void RenderBlockFlow::layoutBlockFlow(bool relayoutChildren, SubtreeLayou tScope& layoutScope) 92 inline void RenderBlockFlow::layoutBlockFlow(bool relayoutChildren, SubtreeLayou tScope& layoutScope)
198 { 93 {
199 LayoutUnit oldLeft = logicalLeft(); 94 LayoutUnit oldLeft = logicalLeft();
200 bool logicalWidthChanged = updateLogicalWidthAndColumnWidth(); 95 bool logicalWidthChanged = updateLogicalWidthAndColumnWidth();
201 relayoutChildren |= logicalWidthChanged; 96 relayoutChildren |= logicalWidthChanged;
202 97
203 LayoutState state(*this, locationOffset(), logicalWidthChanged); 98 LayoutState state(*this, locationOffset(), logicalWidthChanged);
204 99
205 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
206 // our current maximal positive and negative margins. These values are used when we
207 // are collapsed with adjacent blocks, so for example, if you have block A a nd B
208 // collapsing together, then you'd take the maximal positive margin from bot h A and B
209 // and subtract it from the maximal negative margin from both A and B to get the
210 // true collapsed margin. This algorithm is recursive, so when we finish lay out()
211 // our block knows its current maximal positive/negative values.
212 initMaxMarginValues();
213 setHasMarginBeforeQuirk(style()->hasMarginBeforeQuirk());
214 setHasMarginAfterQuirk(style()->hasMarginAfterQuirk());
215
216 LayoutUnit beforeEdge = borderBefore() + paddingBefore(); 100 LayoutUnit beforeEdge = borderBefore() + paddingBefore();
217 LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeig ht(); 101 LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeig ht();
218 LayoutUnit previousHeight = logicalHeight(); 102 LayoutUnit previousHeight = logicalHeight();
219 setLogicalHeight(beforeEdge); 103 setLogicalHeight(beforeEdge);
220 104
221 m_paintInvalidationLogicalTop = 0; 105 m_paintInvalidationLogicalTop = 0;
222 m_paintInvalidationLogicalBottom = 0; 106 m_paintInvalidationLogicalBottom = 0;
223 if (!firstChild() && !isAnonymousBlock()) 107 if (!firstChild() && !isAnonymousBlock())
224 setChildrenInline(true); 108 setChildrenInline(true);
225 109
(...skipping 28 matching lines...) Expand all
254 // If the child has an offset from the content edge to avoid floats then use that, otherwise let any negative 138 // If the child has an offset from the content edge to avoid floats then use that, otherwise let any negative
255 // margin pull it back over the content edge or any positive margin push it out. 139 // margin pull it back over the content edge or any positive margin push it out.
256 // If the child is being centred then the margin calculated to do that has f actored in any offset required to 140 // If the child is being centred then the margin calculated to do that has f actored in any offset required to
257 // avoid floats, so use it if necessary. 141 // avoid floats, so use it if necessary.
258 if (style()->textAlign() == WEBKIT_CENTER || child->style()->marginStartUsin g(style()).isAuto()) 142 if (style()->textAlign() == WEBKIT_CENTER || child->style()->marginStartUsin g(style()).isAuto())
259 newPosition = std::max(newPosition, childMarginStart); 143 newPosition = std::max(newPosition, childMarginStart);
260 144
261 child->setX(style()->isLeftToRightDirection() ? newPosition : totalAvailable LogicalWidth - newPosition - logicalWidthForChild(child)); 145 child->setX(style()->isLeftToRightDirection() ? newPosition : totalAvailable LogicalWidth - newPosition - logicalWidthForChild(child));
262 } 146 }
263 147
264 void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo) 148 void RenderBlockFlow::layoutBlockChild(RenderBox* child)
265 { 149 {
266 // The child is a normal flow object. Compute the margins we will use for co llapsing now.
267 child->computeAndSetBlockDirectionMargins(this); 150 child->computeAndSetBlockDirectionMargins(this);
268 151 LayoutUnit marginBefore = marginBeforeForChild(child);
269 // Try to guess our correct logical top position. In most cases this guess w ill 152 child->setY(logicalHeight() + marginBefore);
270 // be correct. Only if we're wrong (when we compute the real logical top pos ition)
271 // will we have to potentially relayout.
272 // Go ahead and position the child as though it didn't collapse with the top .
273 child->setY(estimateLogicalTopPosition(child, marginInfo));
274
275 child->layoutIfNeeded(); 153 child->layoutIfNeeded();
276
277 // Cache if we are at the top of the block right now.
278 bool childIsSelfCollapsing = child->isSelfCollapsingBlock();
279
280 // Now determine the correct ypos based off examination of collapsing margin
281 // values.
282 child->setY(collapseMargins(child, marginInfo, childIsSelfCollapsing));
283
284 // FIXME(sky): Is it still actually possible for the child to need layout he re?
285 // This used to be needed for floats and/or margin collapsing.
286 child->layoutIfNeeded();
287
288 // If we previously encountered a self-collapsing sibling of this child that had clearance then
289 // we set this bit to ensure we would not collapse the child's margins, and those of any subsequent
290 // self-collapsing siblings, with our parent. If this child is not self-coll apsing then it can
291 // collapse its margins with the parent so reset the bit.
292 if (!marginInfo.canCollapseMarginAfterWithLastChild() && !childIsSelfCollaps ing)
293 marginInfo.setCanCollapseMarginAfterWithLastChild(true);
294
295 // We are no longer at the top of the block if we encounter a non-empty chil d.
296 // This has to be done after checking for clear, so that margins can be rese t if a clear occurred.
297 if (marginInfo.atBeforeSideOfBlock() && !childIsSelfCollapsing)
298 marginInfo.setAtBeforeSideOfBlock(false);
299
300 // Now place the child in the correct left position
301 determineLogicalLeftPositionForChild(child); 154 determineLogicalLeftPositionForChild(child);
302 155 setLogicalHeight(logicalHeight() + marginBefore + logicalHeightForChild(chil d) + marginAfterForChild(child));
303 // Update our height now that the child has been placed in the correct posit ion.
304 setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
305 if (mustSeparateMarginAfterForChild(child)) {
306 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
307 marginInfo.clearMargin();
308 }
309 } 156 }
310 157
311 void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, SubtreeLayoutSc ope& layoutScope, LayoutUnit beforeEdge, LayoutUnit afterEdge) 158 void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, SubtreeLayoutSc ope& layoutScope, LayoutUnit beforeEdge, LayoutUnit afterEdge)
312 { 159 {
313 dirtyForLayoutFromPercentageHeightDescendants(layoutScope); 160 dirtyForLayoutFromPercentageHeightDescendants(layoutScope);
314 161
315 // The margin struct caches all our current margin collapsing state. The com pact struct caches state when we encounter compacts,
316 MarginInfo marginInfo(this, beforeEdge, afterEdge);
317
318 RenderBox* next = firstChildBox(); 162 RenderBox* next = firstChildBox();
319 RenderBox* lastNormalFlowChild = 0; 163 RenderBox* lastNormalFlowChild = 0;
320 164
321 while (next) { 165 while (next) {
322 RenderBox* child = next; 166 RenderBox* child = next;
323 next = child->nextSiblingBox(); 167 next = child->nextSiblingBox();
324 168
325 // FIXME: this should only be set from clearNeedsLayout crbug.com/361250 169 // FIXME: this should only be set from clearNeedsLayout crbug.com/361250
326 child->setLayoutDidGetCalled(true); 170 child->setLayoutDidGetCalled(true);
327 171
328 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child); 172 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
329 173
330 if (child->isOutOfFlowPositioned()) { 174 if (child->isOutOfFlowPositioned()) {
331 child->containingBlock()->insertPositionedObject(child); 175 child->containingBlock()->insertPositionedObject(child);
332 adjustPositionedBlock(child, marginInfo); 176 adjustPositionedBlock(child);
333 continue; 177 continue;
334 } 178 }
335 179
336 // Lay out the child. 180 // Lay out the child.
337 layoutBlockChild(child, marginInfo); 181 layoutBlockChild(child);
338 lastNormalFlowChild = child; 182 lastNormalFlowChild = child;
339 } 183 }
340 184
341 // Now do the handling of the bottom of the block, adding in our bottom bord er/padding and 185 // Negative margins can cause our height to shrink below our minimal height (border/padding).
342 // determining the correct collapsed bottom margin information. 186 // If this happens, ensure that the computed height is increased to the mini mal height.
343 handleAfterSideOfBlock(lastNormalFlowChild, beforeEdge, afterEdge, marginInf o); 187 setLogicalHeight(std::max(logicalHeight() + afterEdge, beforeEdge + afterEdg e));
344 } 188 }
345 189
346 // Our MarginInfo state used when laying out block children. 190 void RenderBlockFlow::adjustPositionedBlock(RenderBox* child)
347 MarginInfo::MarginInfo(RenderBlockFlow* blockFlow, LayoutUnit beforeBorderPaddin g, LayoutUnit afterBorderPadding)
348 : m_canCollapseMarginAfterWithLastChild(true)
349 , m_atBeforeSideOfBlock(true)
350 , m_atAfterSideOfBlock(false)
351 , m_hasMarginBeforeQuirk(false)
352 , m_hasMarginAfterQuirk(false)
353 , m_determinedMarginBeforeQuirk(false)
354 , m_discardMargin(false)
355 {
356 RenderStyle* blockStyle = blockFlow->style();
357 ASSERT(blockFlow->isRenderView() || blockFlow->parent());
358 m_canCollapseWithChildren = !blockFlow->createsBlockFormattingContext() && ! blockFlow->isRenderView();
359
360 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !before BorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
361
362 // If any height other than auto is specified in CSS, then we don't collapse our bottom
363 // margins with our children's margins. To do otherwise would be to risk odd visual
364 // effects when the children overflow out of the parent block and yet still collapse
365 // with it. We also don't collapse if we have any bottom border/padding.
366 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBo rderPadding
367 && (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight() .value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
368
369 m_discardMargin = m_canCollapseMarginBeforeWithChildren && blockFlow->mustDi scardMarginBefore();
370
371 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !blockFlow->mus tDiscardMarginBefore()) ? blockFlow->maxPositiveMarginBefore() : LayoutUnit();
372 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !blockFlow->mus tDiscardMarginBefore()) ? blockFlow->maxNegativeMarginBefore() : LayoutUnit();
373 }
374
375 RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox* c hild) const
376 {
377 LayoutUnit childBeforePositive = 0;
378 LayoutUnit childBeforeNegative = 0;
379 LayoutUnit childAfterPositive = 0;
380 LayoutUnit childAfterNegative = 0;
381
382 LayoutUnit beforeMargin = 0;
383 LayoutUnit afterMargin = 0;
384
385 RenderBlockFlow* childRenderBlockFlow = child->isRenderBlockFlow() ? toRende rBlockFlow(child) : 0;
386
387 if (childRenderBlockFlow) {
388 childBeforePositive = childRenderBlockFlow->maxPositiveMarginBefore();
389 childBeforeNegative = childRenderBlockFlow->maxNegativeMarginBefore();
390 childAfterPositive = childRenderBlockFlow->maxPositiveMarginAfter();
391 childAfterNegative = childRenderBlockFlow->maxNegativeMarginAfter();
392 } else {
393 beforeMargin = child->marginBefore();
394 afterMargin = child->marginAfter();
395 }
396
397 // Resolve uncollapsing margins into their positive/negative buckets.
398 if (beforeMargin) {
399 if (beforeMargin > 0)
400 childBeforePositive = beforeMargin;
401 else
402 childBeforeNegative = -beforeMargin;
403 }
404 if (afterMargin) {
405 if (afterMargin > 0)
406 childAfterPositive = afterMargin;
407 else
408 childAfterNegative = -afterMargin;
409 }
410
411 return RenderBlockFlow::MarginValues(childBeforePositive, childBeforeNegativ e, childAfterPositive, childAfterNegative);
412 }
413
414 LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& margin Info, bool childIsSelfCollapsing)
415 {
416 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
417 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
418
419 // The child discards the before margin when the the after margin has discar d in the case of a self collapsing block.
420 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAf ter && childIsSelfCollapsing);
421
422 // Get the four margin values for the child and cache them.
423 const RenderBlockFlow::MarginValues childMargins = marginValuesForChild(chil d);
424
425 // Get our max pos and neg top margins.
426 LayoutUnit posTop = childMargins.positiveMarginBefore();
427 LayoutUnit negTop = childMargins.negativeMarginBefore();
428
429 // For self-collapsing blocks, collapse our bottom margins into our
430 // top to get new posTop and negTop values.
431 if (childIsSelfCollapsing) {
432 posTop = std::max(posTop, childMargins.positiveMarginAfter());
433 negTop = std::max(negTop, childMargins.negativeMarginAfter());
434 }
435
436 // See if the top margin is quirky. We only care if this child has
437 // margins that will collapse with us.
438 bool topQuirk = hasMarginBeforeQuirk(child);
439
440 if (marginInfo.canCollapseWithMarginBefore()) {
441 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
442 // This child is collapsing with the top of the
443 // block. If it has larger margin values, then we need to update
444 // our own maximal values.
445 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()) , std::max(negTop, maxNegativeMarginBefore()));
446
447 // The minute any of the margins involved isn't a quirk, don't
448 // collapse it away, even if the margin is smaller (www.webreference .com
449 // has an example of this, a <dt> with 0.8em author-specified inside
450 // a <dl> inside a <td>.
451 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTo p - negTop)) {
452 setHasMarginBeforeQuirk(false);
453 marginInfo.setDeterminedMarginBeforeQuirk(true);
454 }
455
456 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !margin Before()) {
457 // We have no top margin and our top child has a quirky margin.
458 // We will pick up this quirky margin and pass it through.
459 // This deals with the <td><div><p> case.
460 // Don't do this for a block that split two inlines though. You do
461 // still apply margins in this case.
462 setHasMarginBeforeQuirk(true);
463 }
464 } else {
465 // The before margin of the container will also discard all the marg ins it is collapsing with.
466 setMustDiscardMarginBefore();
467 }
468 }
469
470 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
471 if (childDiscardMarginBefore) {
472 marginInfo.setDiscardMargin(true);
473 marginInfo.clearMargin();
474 }
475
476 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
477 LayoutUnit logicalTop = beforeCollapseLogicalTop;
478
479 LayoutUnit clearanceForSelfCollapsingBlock;
480 RenderObject* prev = child->previousSibling();
481 RenderBlockFlow* previousBlockFlow = prev && prev->isRenderBlockFlow() && ! prev->isFloatingOrOutOfFlowPositioned() ? toRenderBlockFlow(prev) : 0;
482 // If the child's previous sibling is a self-collapsing block that cleared a float then its top border edge has been set at the bottom border edge
483 // of the float. Since we want to collapse the child's top margin with the s elf-collapsing block's top and bottom margins we need to adjust our parent's hei ght to match the
484 // margin top of the self-collapsing block. If the resulting collapsed margi n leaves the child still intruding into the float then we will want to clear it.
485 if (!marginInfo.canCollapseWithMarginBefore() && previousBlockFlow && previo usBlockFlow->isSelfCollapsingBlock()) {
486 clearanceForSelfCollapsingBlock = previousBlockFlow->marginOffsetForSelf CollapsingBlock();
487 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
488 }
489
490 if (childIsSelfCollapsing) {
491 // For a self collapsing block both the before and after margins get dis carded. The block doesn't contribute anything to the height of the block.
492 // Also, the child's top position equals the logical height of the conta iner.
493 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
494 // This child has no height. We need to compute our
495 // position before we collapse the child's margins together,
496 // so that we can get an accurate position for the zero-height block .
497 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin() , childMargins.positiveMarginBefore());
498 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin() , childMargins.negativeMarginBefore());
499 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
500
501 // Now collapse the child's margins together, which means examining our
502 // bottom margin values as well.
503 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfte r());
504 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfte r());
505
506 if (!marginInfo.canCollapseWithMarginBefore()) {
507 // We need to make sure that the position of the self-collapsing block
508 // is correct, since it could have overflowing content
509 // that needs to be positioned correctly (e.g., a block that
510 // had a specified height of 0 but that actually had subcontent) .
511 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBef oreNeg;
512 }
513 }
514 } else {
515 if (mustSeparateMarginBeforeForChild(child)) {
516 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
517 // If we are at the before side of the block and we collapse, ignore the computed margin
518 // and just add the child margin to the container height. This will correctly position
519 // the child inside the container.
520 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore( ) ? marginInfo.margin() : LayoutUnit(0);
521 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForC hild(child));
522 logicalTop = logicalHeight();
523 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlo ck()
524 || (!marginInfo.canCollapseMarginBeforeWithChildren()))) {
525 // We're collapsing with a previous sibling's margins and not
526 // with the top of the block.
527 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargi n(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
528 logicalTop = logicalHeight();
529 }
530
531 marginInfo.setDiscardMargin(childDiscardMarginAfter);
532
533 if (!marginInfo.discardMargin()) {
534 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
535 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
536 } else {
537 marginInfo.clearMargin();
538 }
539
540 if (marginInfo.margin())
541 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
542 }
543
544 return logicalTop;
545 }
546
547 void RenderBlockFlow::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
548 { 191 {
549 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(); 192 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition();
550 193
551 LayoutUnit logicalTop = logicalHeight(); 194 LayoutUnit logicalTop = logicalHeight();
552 updateStaticInlinePositionForChild(child, logicalTop); 195 updateStaticInlinePositionForChild(child, logicalTop);
553 196
554 if (!marginInfo.canCollapseWithMarginBefore()) {
555 // Positioned blocks don't collapse margins, so add the margin provided by
556 // the container now. The child's own margin is added later when calcula ting its logical top.
557 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
558 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
559 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
560 }
561
562 RenderLayer* childLayer = child->layer(); 197 RenderLayer* childLayer = child->layer();
563 if (childLayer->staticBlockPosition() != logicalTop) { 198 if (childLayer->staticBlockPosition() != logicalTop) {
564 childLayer->setStaticBlockPosition(logicalTop); 199 childLayer->setStaticBlockPosition(logicalTop);
565 if (hasStaticBlockPosition) 200 if (hasStaticBlockPosition)
566 child->setChildNeedsLayout(MarkOnlyThis); 201 child->setChildNeedsLayout(MarkOnlyThis);
567 } 202 }
568 } 203 }
569 204
570 void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
571 {
572 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMa rginBefore()) {
573 // Update the after side margin of the container to discard if the after margin of the last child also discards and we collapse with it.
574 // Don't update the max margin values because we won't need them anyway.
575 if (marginInfo.discardMargin()) {
576 setMustDiscardMarginAfter();
577 return;
578 }
579
580 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
581 // with our children.
582 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.po sitiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()) );
583
584 if (!marginInfo.hasMarginAfterQuirk())
585 setHasMarginAfterQuirk(false);
586
587 if (marginInfo.hasMarginAfterQuirk() && !marginAfter()) {
588 // We have no bottom margin and our last child has a quirky margin.
589 // We will pick up this quirky margin and pass it through.
590 // This deals with the <td><div><p> case.
591 setHasMarginAfterQuirk(true);
592 }
593 }
594 }
595
596 void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefo re) const
597 {
598 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
599 // Give up if the child specified -webkit-margin-collapse: separate that pre vents collapsing.
600 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
601 if (child->style()->marginBeforeCollapse() == MSEPARATE)
602 return;
603
604 // The margins are discarded by a child that specified -webkit-margin-collap se: discard.
605 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
606 if (child->style()->marginBeforeCollapse() == MDISCARD) {
607 positiveMarginBefore = 0;
608 negativeMarginBefore = 0;
609 discardMarginBefore = true;
610 return;
611 }
612
613 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
614 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
615 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
616
617 if (!child->isRenderBlockFlow())
618 return;
619
620 RenderBlockFlow* childBlockFlow = toRenderBlockFlow(child);
621 if (childBlockFlow->childrenInline())
622 return;
623
624 MarginInfo childMarginInfo(childBlockFlow, childBlockFlow->borderBefore() + childBlockFlow->paddingBefore(), childBlockFlow->borderAfter() + childBlockFlow- >paddingAfter());
625 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
626 return;
627
628 RenderBox* grandchildBox = childBlockFlow->firstChildBox();
629 for ( ; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
630 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
631 break;
632 }
633
634 if (!grandchildBox)
635 return;
636
637 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
638 if (grandchildBox->needsLayout()) {
639 grandchildBox->computeAndSetBlockDirectionMargins(this);
640 if (grandchildBox->isRenderBlock()) {
641 RenderBlock* grandchildBlock = toRenderBlock(grandchildBox);
642 grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style()->has MarginBeforeQuirk());
643 grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style()->hasM arginAfterQuirk());
644 }
645 }
646
647 // Collapse the margin of the grandchild box with our own to produce an esti mate.
648 childBlockFlow->marginBeforeEstimateForChild(grandchildBox, positiveMarginBe fore, negativeMarginBefore, discardMarginBefore);
649 }
650
651 LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox* child, const M arginInfo& marginInfo)
652 {
653 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
654 // relayout if there are intruding floats.
655 LayoutUnit logicalTopEstimate = logicalHeight();
656 if (!marginInfo.canCollapseWithMarginBefore()) {
657 LayoutUnit positiveMarginBefore = 0;
658 LayoutUnit negativeMarginBefore = 0;
659 bool discardMarginBefore = false;
660 if (child->selfNeedsLayout()) {
661 // Try to do a basic estimation of how the collapse is going to go.
662 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMa rginBefore, discardMarginBefore);
663 } else {
664 // Use the cached collapsed margin values from a previous layout. Mo st of the time they
665 // will be right.
666 RenderBlockFlow::MarginValues marginValues = marginValuesForChild(ch ild);
667 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.p ositiveMarginBefore());
668 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.n egativeMarginBefore());
669 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
670 }
671
672 // Collapse the result with our current margins.
673 if (!discardMarginBefore)
674 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positive MarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
675 }
676
677 return logicalTopEstimate;
678 }
679
680 LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
681 {
682 // FIXME(sky): Remove
683 ASSERT(isSelfCollapsingBlock());
684 return LayoutUnit();
685 }
686
687 void RenderBlockFlow::handleAfterSideOfBlock(RenderBox* lastChild, LayoutUnit be foreSide, LayoutUnit afterSide, MarginInfo& marginInfo)
688 {
689 marginInfo.setAtAfterSideOfBlock(true);
690
691 // If our last child was a self-collapsing block with clearance then our log ical height is flush with the
692 // bottom edge of the float that the child clears. The correct vertical posi tion for the margin-collapsing we want
693 // to perform now is at the child's margin-top - so adjust our height to tha t position.
694 if (lastChild && lastChild->isRenderBlockFlow() && lastChild->isSelfCollapsi ngBlock())
695 setLogicalHeight(logicalHeight() - toRenderBlockFlow(lastChild)->marginO ffsetForSelfCollapsingBlock());
696
697 if (marginInfo.canCollapseMarginAfterWithChildren() && !marginInfo.canCollap seMarginAfterWithLastChild())
698 marginInfo.setCanCollapseMarginAfterWithChildren(false);
699
700 // If we can't collapse with children then go ahead and add in the bottom ma rgin.
701 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()))
702 setLogicalHeight(logicalHeight() + marginInfo.margin());
703
704 // Now add in our bottom border/padding.
705 setLogicalHeight(logicalHeight() + afterSide);
706
707 // Negative margins can cause our height to shrink below our minimal height (border/padding).
708 // If this happens, ensure that the computed height is increased to the mini mal height.
709 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
710
711 // Update our bottom collapsed margin info.
712 setCollapsedBottomMargin(marginInfo);
713 }
714
715 void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
716 {
717 if (style()->marginBeforeCollapse() == MDISCARD) {
718 ASSERT(value);
719 return;
720 }
721
722 if (!m_rareData && !value)
723 return;
724
725 if (!m_rareData)
726 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
727
728 m_rareData->m_discardMarginBefore = value;
729 }
730
731 void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
732 {
733 if (style()->marginAfterCollapse() == MDISCARD) {
734 ASSERT(value);
735 return;
736 }
737
738 if (!m_rareData && !value)
739 return;
740
741 if (!m_rareData)
742 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
743
744 m_rareData->m_discardMarginAfter = value;
745 }
746
747 bool RenderBlockFlow::mustDiscardMarginBefore() const
748 {
749 return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareD ata->m_discardMarginBefore);
750 }
751
752 bool RenderBlockFlow::mustDiscardMarginAfter() const
753 {
754 return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareDa ta->m_discardMarginAfter);
755 }
756
757 bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox* child) co nst
758 {
759 ASSERT(!child->selfNeedsLayout());
760 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMar ginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
761 }
762
763 bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox* child) con st
764 {
765 ASSERT(!child->selfNeedsLayout());
766 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMar ginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
767 }
768
769 void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
770 {
771 if (!m_rareData) {
772 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(this))
773 return;
774 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
775 }
776 m_rareData->m_margins.setPositiveMarginBefore(pos);
777 m_rareData->m_margins.setNegativeMarginBefore(neg);
778 }
779
780 void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
781 {
782 if (!m_rareData) {
783 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(this))
784 return;
785 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
786 }
787 m_rareData->m_margins.setPositiveMarginAfter(pos);
788 m_rareData->m_margins.setNegativeMarginAfter(neg);
789 }
790
791 bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox* child) c onst
792 {
793 ASSERT(!child->selfNeedsLayout());
794 const RenderStyle* childStyle = child->style();
795 return childStyle->marginBeforeCollapse() == MSEPARATE;
796 }
797
798 bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox* child) co nst
799 {
800 ASSERT(!child->selfNeedsLayout());
801 const RenderStyle* childStyle = child->style();
802 return childStyle->marginAfterCollapse() == MSEPARATE;
803 }
804
805 RootInlineBox* RenderBlockFlow::createAndAppendRootInlineBox() 205 RootInlineBox* RenderBlockFlow::createAndAppendRootInlineBox()
806 { 206 {
807 RootInlineBox* rootBox = createRootInlineBox(); 207 RootInlineBox* rootBox = createRootInlineBox();
808 m_lineBoxes.appendLineBox(rootBox); 208 m_lineBoxes.appendLineBox(rootBox);
809 209
810 return rootBox; 210 return rootBox;
811 } 211 }
812 212
813 void RenderBlockFlow::deleteLineBoxTree() 213 void RenderBlockFlow::deleteLineBoxTree()
814 { 214 {
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
1014 cb = cb->containingBlock(); 414 cb = cb->containingBlock();
1015 } 415 }
1016 return logicalRight; 416 return logicalRight;
1017 } 417 }
1018 418
1019 RootInlineBox* RenderBlockFlow::createRootInlineBox() 419 RootInlineBox* RenderBlockFlow::createRootInlineBox()
1020 { 420 {
1021 return new RootInlineBox(*this); 421 return new RootInlineBox(*this);
1022 } 422 }
1023 423
1024 RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareData()
1025 {
1026 if (m_rareData)
1027 return *m_rareData;
1028
1029 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
1030 return *m_rareData;
1031 }
1032
1033 } // namespace blink 424 } // namespace blink
OLDNEW
« no previous file with comments | « sky/engine/core/rendering/RenderBlockFlow.h ('k') | sky/engine/core/rendering/RenderBox.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698