OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |